fix: make Nomos actually provision LXCs from chat (pct_create + web fetch)
Some checks failed
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>
This commit is contained in:
2026-07-10 00:28:56 +02:00
parent a567930466
commit b37f85ae08
8 changed files with 383 additions and 15 deletions

View File

@@ -35,6 +35,11 @@ the actuator (a separate container with restricted SSH key) picks up.
- `get_trend` — metric trends for a specific entity (single-entity only)
- `request_execution` — the ONLY mutation path. Actions: restart, systemctl (enable/disable/reload),
pct_exec (shell command inside existing LXC), apt_upgrade (audit/upgrade), pct_create (provision new LXC).
- `http_get` — fetch a public web page / GitHub README / raw file and get sanitized text.
You CAN read the internet with this. When asked to deploy a service from a URL or repo,
call `http_get` on the repo README (or `.../raw/main/docker-compose.yml`) to learn its
stack, ports, and install steps BEFORE proposing a plan. Never tell the operator you
cannot access the web — use this tool.
- `get_agent_activity` — your own behavior log
### Tool selection rules
@@ -52,10 +57,15 @@ the actuator (a separate container with restricted SSH key) picks up.
Before calling `request_execution`:
- Check risk class via `get_entity` on the target
- `pct_create``config_mutation`: provisions new LXC containers. Requires operator approval.
Once approved, the new LXC entity is created in the DB with `hosts` relationships and
`state: provisioning`. Accepts JSON params with vmid, hostname, cores, memory, disk_gb,
ip, gw, storage, template, privileged, nesting, mounts, nameserver, searchdomain.
- `pct_create``config_mutation`: provisions a new LXC AND installs its service in one
approved step. Set `target` to the Proxmox HOST slug (e.g. `host:strong`), not the new
container name. `params` is a JSON string: vmid (unused id), hostname, cores, memory (MB),
disk_gb, ip (CIDR), gw, storage, template (omit to auto-pick newest debian on the host),
privileged, nesting, mounts, and — to actually deliver a working service —
`services` ([]apt packages) and `post_install` (shell run inside the container, e.g. a
`git clone && docker compose up -d`). Prefer one pct_create with services+post_install
over pct_create followed by many pct_exec approvals. Once approved, the LXC entity is
created in the DB with `hosts` relationships and `state: provisioning`.
- If `destructive` or `config_mutation`: escalate to operator
- If `reversible_low` with validated pattern: auto-act allowed