b37f85ae08
fix: make Nomos actually provision LXCs from chat (pct_create + web fetch)
...
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Root cause of "asks permission but never acts": the approved pct_create
execution failed to parse because the LLM emitted `"privileged":0` /
`"nesting":1` (numbers) into strict `bool` fields, so the container was
never created. Compounded by a hardcoded template name (debian-13.0-1)
that no longer exists on the host, and no way for the agent to read the web.
- flexBool: accept 0/1, "true", bool for privileged/nesting (the exact prod failure)
- pct_create template pre-flight: list host cache, validate/auto-pick newest debian
- pct_create services[] + post_install: one approval provisions a working service
- new http_get MCP tool (sanitized, size-capped, SSRF-guarded) — agent can read repos/sites
- request_execution description: target=host, full JSON schema + example
- SOUL.md: agent CAN fetch the web; prefer one-step provisioning
- default model deepseek-v4-flash -> v4-pro; maxIterations 15 -> 25
- unit tests for flexBool, template resolve, pkg sanitize, HTML sanitize + SSRF block
Verified live on host:strong with a throwaway VMID 999: template auto-resolved,
container created + booted, services installed, post_install ran, then destroyed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-10 00:28:56 +02:00
4bf811a383
docker: alpine base with openssh-client, mount SSH key + NET_RAW for scheduler
...
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
- Switch Dockerfile from distroless/static to alpine:3.21
- Install openssh-client-default in runtime image
- Mount SSH key in scheduler service (docker-compose)
- Add NET_RAW capability for ping checks
- Wire OIKOS_SSH_KEY_PATH and OIKOS_SSH_USER env vars in scheduler
- sshExec uses configured key path with StrictHostKeyChecking=no
2026-07-08 21:15:02 +02:00
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
f07668c1c3
caddy: update Caddyfile.oikos snippet to match deployed config with enrollment bypass
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
2026-07-08 12:00:20 +02:00
dcd35b6315
phase 6: deploy pipeline — CI, cutover checklist, watchdog, verification, rollback
...
- scripts/deploy.sh: Gitea webhook-triggered deploy (git pull → docker build
→ compose up → health check). SHA-tagged images, rolling restart.
- scripts/watchdog.sh: cron health check every 2min, pages operator via
Matrix after 3 consecutive failures. Reset on recovery.
- scripts/verify-phase6.sh: 14 end-to-end verification checks against
plan V1–V14 (ontology, DB, API, scheduler, actuator, learning, classifier,
hermes, secrets, deploy, knowledge, observability, correlation, cutover).
- scripts/rollback.sh: re-deploy previous SHA tag + pg_restore from
pre-deploy dump. Health check loop, returns to main branch after.
- scripts/cutover-checklist.md: pre/post-cutover steps — backup, CI gate,
Caddy re-point, DNS, apps/105 disable, cleanup.
- compose/caddy/Caddyfile.oikos: reverse-proxy config for
oikos/mcp/hermes.hubris.network → mac-mini mesh IP.
- .gitignore: added bin/ to exclude compiled binaries.
14/14 verification checks pass against running Docker stack.
2026-07-07 17:37: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
aa2ca0ae6f
phase 1: Go foundation — module, migrations, domain, seed ingest
...
Core deliverables:
- Go module github.com/dtoro/oikos (Go 1.26.3)
- cmd/oikos: single binary with role subcommands (migrate, seed, export)
- 6 SQL migrations: ontology meta-schema, entity instances (UUID+slug,
blast_radius recursive function), operations (signals/checks/approvals),
cognition (classifications/executions/feedback/patterns/skills), policy,
observability (TimescaleDB hypertables + CAGGs + retention)
- Domain layer: entity, signal, execution, classification, pattern, skill,
approval, check types + 11 sentinel errors + lifecycle state machines
- DB layer: pgx pool, SQL splitter (handles 94436 and -- comments), migration
runner, seed ingest (ontology+inventory+policy) with content-hash dedup
- Config: env-based with defaults, secrets redaction
- Observability: slog JSON logger with debug mode
- Infrastructure: Makefile, docker-compose.yml, multi-stage Dockerfile
(distroless, CGO_ENABLED=0)
Verified end-to-end against timescale/timescaledb:2.17.2-pg16:
- 6 migrations applied (65 SQL statements)
- Seeds ingested: 6 lifecycles, 59 entity types, 46 relationship types,
111 entities, 144 relationships, 4 risk classes, 27 approval rules,
9 autonomy settings
- Idempotent: second seed run is a no-op (content hash matches)
Bugs fixed during implementation:
- TimescaleDB CAGGs can't run in a transaction -> splitSQL() executes
statements individually
- Semicolons in -- comments treated as separators -> comment handling
- YAML keys source/target didn't match code's source_type/target_type
- yaml.Marshal produced YAML for JSONB columns -> json.Marshal
2026-07-07 01:07:26 +02:00