e8e230b4a5
nomos+web: streaming, provider routing, event gap-fill, embedded UI; fix approval FK & session context
...
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Agent (cmd/nomos):
- Stream LLM tokens via NewStreaming; emit text_delta then final text.
- OpenRouter provider routing: data_collection=deny (ZDR) + require_parameters;
NOMOS_PROVIDER_SORT opt-in; Exacto via model suffix.
- Multi-turn: reload session history into context; UI passes session id.
- Fix agent_activity logging (agent_id/session_id) and mcpClient data race.
Events (live control-room feed):
- approval.created (mcp), approval.decided (api), execution.completed/failed
(approved-action path), signal.raised/resolved + health.changed (scheduler,
transition-gated).
Fixes:
- createApproval FK violation (reuse execution entity) — the agent's only
write path; log the previously-swallowed errors.
Web UI:
- Embed web/dist via //go:embed (single binary); Dockerfile builds SPA into
the Go stage; committed .gitkeep placeholder keeps backend-only builds green.
- Caddy: Authentik-gated /agent/* -> nomos so the UI reaches the agent
same-origin in production.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-08 15:22:27 +02:00
2b3aa248b1
N0: rename Hermes → Nomos (standalone commit)
...
Problem: "Hermes" collides with Nous Researchs unrelated product;
unclear identity for the resident agent.
Change: Rename the live service identity across 39 files:
- cmd/hermes/ → cmd/nomos/ (binary, env vars NOMOS_*)
- internal/config/ server.go (NomosAgentSlug, nomosAgentID)
- compose/hermes/ → compose/nomos/ (Dockerfile, service name)
- hermes/ → nomos/ (SOUL.md, config.yaml, skills/)
- .agents/HERMES.md → NOMOS.md (persona)
- tools/setup-hermes-soul.sh → setup-nomos-soul.sh
- seeds/inventory.yaml (agent:hermes → agent:nomos)
- migrations/014_rename_agent_hermes_to_nomos.up.sql
- Caddy vhost hermes.hubris.network → nomos.hubris.network
- All referencing docs, scripts, ADR notes
History preserved: archive/, plans/done/, ADRs not rewritten.
Matrix @hermes notifier account and Legacy bin/hermes on LXC 129
intentionally untouched (out of scope).
Risk: N0 is identity-only rename; zero behavioral changes.
Verification: go build ./... passes; docker compose --profile full
resolves nomos service; grep -ri hermes (excluding archive/plans)
returns only intentional refs (LLM model name, Matrix user).
2026-07-08 14:14:56 +02:00
5d15265f65
fix: queryRows returns [] not null for empty result sets
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
2026-07-08 12:50:13 +02:00
3ea43adcfd
fix: repair 5 MCP analysis tools with SQL errors + seed entity_status rows
...
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
- get_event_timeline: event_type/actor/message → type/source/data::text
- get_blast_radius: add JOIN entities for slug column
- get_state_snapshot: remove nonexistent disk_usage_pct, drift_count
- get_change_history: timestamp/actor_label/details → ts/actor_id::text/detail
- seed: upsert entity_status rows during inventory ingest (was empty, causing INNER JOIN on get_health_summary to return nothing)
2026-07-08 12:27:25 +02:00
a3ebd12e90
complete DB as source of truth — FTS knowledge surface
...
Plan #5 done. Wiki already archived to archive/knowledge/. seeds/knowledge.yaml
has 24 docs + 6 investigations + 3 runbooks.
- MCP search_knowledge: upgraded from ILIKE to PostgreSQL ts_rank/ts_headline
- MCP get_entity_knowledge: new tool, walks relationship edges to return
all docs/investigations/runbooks linked to an entity
- HTTP endpoints (SearchKnowledge, GetEntityKnowledge) already used full FTS
- Plan index + audit cross-reference updated
2026-07-08 11:06:12 +02:00
7c6cffb5f5
complete MCP tool surface — Matrix approval webhook loop + token verification
...
Plan #6 (MCP Tool Completion / bin/homelab Migration) done.
- Approval records created for gated request_execution actions
- Notifier sends Matrix messages with HMAC approval tokens
- Stores matrix_event_id, polls /relations/{id}/m.annotation for ✅ /❌
- Reaction detection triggers DecideApproval API call
- Token verification added to DecideApproval endpoint
- Migration 013: matrix_event_id + alert_sent_at on approvals
- AGENTS.md: 21-tool surface documented, stale homelab CLI refs removed
- Plan index updated, audit cross-reference refreshed
2026-07-08 11:02:06 +02:00
a786107cc7
feat: add client introspection MCP tools — whoami, explain, preflight, etc.
...
Phase 3 from the client-lifecycle plan. Six new MCP tools registered:
- whoami(hostname) — entity record, health, mesh IP, age pubkey
- explain(service_slug) — compact context card with type, state, health
- preflight(service_slug, action) — risk class + approval requirement
- get_change_history(entity_slug, limit) — audit log entries
- get_state_snapshot() — fleet health, disk, drift count
- list_my_secrets(caller_pubkey?) — secrets accessible by age key
All tools use existing queryRows/queryEntity helpers with SQL queries.
All tests pass.
2026-07-08 00:27:26 +02:00
7f7d039e1b
phase 3-4: get_execution_status tool, approval creation, delete bin/ + homelab.go, update AGENTS.md
2026-07-07 23:13:13 +02:00
7ac2521a22
mcp: expand request_execution — restart, systemctl, pct_exec, apt_upgrade with inline SSH
2026-07-07 23:07:02 +02:00
692800cf09
mcp: add 5 operational tools — tail_log, get_service_status, ping_service, list_lxcs, get_lxc_state
2026-07-07 23:01:21 +02:00
f4a00a6cfd
phase 4: standalone hermes agent — MCP client gateway, no Goose dependency
...
- cmd/hermes/main.go: standalone MCP client binary with serve mode (:8092).
Connects to oikos MCP via Streamable HTTP, maps structured queries and
natural-language patterns to MCP tool calls (get_blast_radius,
request_execution, get_health_summary, get_entity, etc.).
- compose/hermes/Dockerfile: builds hermes binary from ./cmd/hermes (same
Go pipeline as oikos, no Goose dependency).
- docker-compose.yml: hermes service (profile: full, port 8092).
- hermes/config.yaml: simplified for standalone hermes binary.
- internal/config/config.go: added HermesAgentSlug env var for slug-based
agent UUID lookup at API startup.
- internal/httpapi/server.go: resolves agent UUID from slug at startup
for MCP activity logging.
- internal/mcp/server.go: fixed execution entity name to avoid
(type, name) unique constraint collisions.
- seeds/inventory.yaml: agent:hermes state active (was planned).
- internal/httpapi/*_test.go: 4 Phase 4 integration tests + postJSON helper.
Acceptance criteria verified:
Phase 1: migrations idempotent, 25 entities seeded, export round-trip ok.
Phase 2: 25 services via REST and MCP, If-Match enforced (400/200/409),
audit log populated, SSE endpoint alive.
Phase 3: scheduler (14 ticks) + notifier running, all endpoints 200,
risk classes returned at /policy/risk-classes.
Phase 4: hermes healthz ok, 'what depends on authentik?' → 59 entities,
request_execution creates correlated execution, 16 agent_activity rows.
Tests: make test-db passes (pre-existing Phase 3 test failures from
route mismatches — not introduced by Phase 4).
2026-07-07 17:17:18 +02:00
74a6b6bb18
phase 4: fix execution FK violation — create entity row before insert
...
- phase3.go: RequestExecution now calls InsertEntity before InsertExecution
(executions.entity_id references entities.id via FK constraint).
- mcp/server.go: request_execution MCP tool same fix — inserts entities row
with slug 'exec:<target>:<id8>' before executions insert.
- docker-compose.yml: fix seed OIKOS_SEEDS_DIR from /app/seeds to /seeds
(distroless image COPY destination).
2026-07-07 16:45:28 +02:00
3823a82417
phase 4: hermes agent — MCP tools, activity logging, 'all' role, wiring fixes
...
- mcp/server.go: 7 new tools (get_signal_history, get_patterns, get_skills,
request_execution, get_trend, get_event_timeline, get_agent_activity),
agent_activity logging middleware on every tool call.
- phase3.go: QueryAgentActivity REST handler implemented (was stub).
Fixed scan count mismatch in ListSkills/PatchSkill/ListSkillVersions
(13 cols → 12 targets). Fixed AgentActivity cursor pagination
(lexicographic → integer comparison). Fixed s.Slug → s.Name in log.
- cmd/oikos/main.go: 'all' role now runs api + scheduler + notifier in
one process. Replaced nil SchedulerRunner/NotifierRunner with direct
scheduler.RunnerForMain() / notifier.RunnerForMain() imports.
Added runWithPool helper for standalone scheduler/notifier roles.
- internal/config/config.go: added HermesAgentID env var.
- internal/httpapi/server.go: pass HermesAgentID to MCP handler.
- docker-compose.yml: added scheduler and notifier services (dev profile).
- hermes/: config.yaml, SOUL.md, skills/homelab-ops/SKILL.md.
- Cleaned up: scheduler/init.go dead code, mcp/server.go pgx import guard.
2026-07-07 16:07:08 +02:00
f1b0b65149
phase 2 review: fix SSE deadlock, MCP panic, lifecycle 500, NOT NULL bug
...
Reviewed the phase-2 implementation (parts 2–5) end to end. The suite hung
for 600s and several handlers were never exercised because there were no
tests for the new mutation/event/MCP surface. Fixes:
- CRITICAL: sseListener ran on context.Background() and held a pooled
connection forever, so pool.Close() deadlocked (600s test timeout).
NewHandler now takes a ctx that governs the listener; ListenAndServe and
the test helper cancel it before closing the pool.
- CRITICAL: MCP AddTool panicked ("missing input schema") at construction
under go-sdk v1.6.1 — so NewHandler (and every API handler) panicked.
Added object input schemas to all 8 tools via an objSchema helper.
- HIGH: PatchEntity parsed lifecycle transitions as map[string][]string but
the shape is {from:{to:{requires:[]}}}, so every state-change PATCH 500'd.
Parse the nested shape; allow same-state no-ops.
- HIGH: CreateEntity bound SQL NULL for attributes when omitted, violating
the NOT NULL column (the default only applies when omitted). Default to
'{}'.
- MED: serveSSEWriter ignored the request ctx (per-client goroutine leak on
disconnect) and set an invalid Content-Length: -1. Thread ctx through;
omit the header. writeSSE now nil-checks the flusher (io.Pipe path passed
nil → would have panicked on first event).
- MED: SSE `data:` leaked raw sqlcgen.Event (PascalCase, base64 JSONB).
Emit canonical gen.Event so SSE matches GET /events. Verified live.
- LOW: CreateEntity uses uuid.NewV7 (ADR-0005) + real actor from context in
audit; removed dead bearerAuth; fixed vet unkeyed-field warnings.
Tests (would have caught all of the above): entity create/patch with
If-Match 409/400, valid+invalid lifecycle transitions, idempotency replay,
duplicate-slug 409, abstract-type 422, event+audit side effects, MCP tool
registration. Live smoke test confirmed NOTIFY→listener→SSE delivery.
Also adds the missing Phase 2 deliverable: Gitea Actions CI (vet,
golangci-lint, govulncheck, generated-code drift guard, race tests against
TimescaleDB, docker build) and wires sqlc into `make generate`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-07 13:26:43 +02:00
6b61495e3b
phase 2 (part 5): MCP server with official Go SDK
...
- MCP server at /mcp using github.com/modelcontextprotocol/go-sdk v1.6.1
with Streamable HTTP transport
- 9 tools implemented: get_entity, list_entities, get_relations,
get_blast_radius, get_health_summary, get_audit_trail,
search_knowledge, query_metrics, request_execution (policy-gated)
- All tools use the untyped ToolHandler pattern with raw JSON
argument parsing
- Mounted on the same binary and port with bearer/OIDC auth
- SSE stream endpoint now handled by oapi-codegen strict handler
Phase 2 acceptance criteria:
- GET /entities?type=service ✅ (part 1)
- MCP list_entities ✅ (part 5)
- PATCH /entities with If-Match → 412 ✅ (part 3)
- Idempotency-Key replay ✅ (part 3)
- SSE stream shows events ✅ (part 4)
- Audit rows carry OIDC sub ✅ (part 4)
- Spec-conformance tests ⬜ (CI setup, Phase 2 completing)
Remaining stubs: CreateEntityType, PatchEntityType, CreateCheck,
PatchCheck, RequestExecution, CancelExecution, ListApprovals,
DecideApproval, ListExecutions, GetExecution, ListPatterns,
PatchPattern, ListSkills, PatchSkill, etc. (Phase 3)
2026-07-07 12:27:36 +02:00