v0.18.0: MCP entity-graph CRUD, lifecycle validation, curl -o /dev/null fix
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

- create_entity, set_entity_state, end_relationship MCP tools
- update_entity_attributes now triggers check derivation via EnsureEntityChecks
- shared db.EnsureEntityChecks + db.ValidateTransition hooks (HTTP + MCP parity)
- curl -o /dev/null now classified read_only (was config_mutation)
- db.ErrTransitionInvalid sentinel for HTTP error-type accuracy
- SOUL.md: capability escalation, self-grounding, exploration budget rules
- Runbook: oikos check lifecycle for agent self-knowledge
This commit is contained in:
2026-08-04 08:52:08 +02:00
parent 058f1afcdc
commit 20adb89650
14 changed files with 1098 additions and 157 deletions

View File

@@ -47,6 +47,15 @@ Read-only commands auto-run (no approval). Config_mutation commands
auto-run under the assent window (after approval). Destructive commands
always need explicit typed confirmation.
**Never mark a step `done` if its tool calls errored.** If `run` timed out,
`update_entity_attributes` returned "not found", `create_relationship` returned
"source entity not found", or any tool returned an error — the step is NOT done.
Diagnose the error, try an alternative (e.g. use `create_entity` when
`update_entity_attributes` reports the entity doesn't exist), and only advance
to `done` when the step's intended work actually completed. A step whose only
tool results are errors should stay `running` — surfacing the problem to the
operator is better than silently advancing past it.
### 6. WRITE BACK + COMPLETE — `complete_task`
Call `update_entity_attributes` for every entity you ran `run` against
(versions, states, counts, timestamps). Call `create_relationship` for any
@@ -205,6 +214,21 @@ disappear.
`list_lxcs` answers the same question in one call. Use it.
- When a bulk tool's summary isn't enough for a specific entity, call the
per-entity tool for that one entity — not for every entity in the fleet.
- **Cap pre-plan exploration:** prefer `list_entities(limit)` +
`get_entity_knowledge` (context for one entity, one call) over N+1
`get_entity`/`get_relations` chains. If you've already called
`get_entity_knowledge(slug)` and need more, call `get_entity(slug)` +
`get_relations(slug)` — not `list_entities` without a limit scanning the
whole entity table.
- **Group parallel reads:** `get_entity_knowledge`, `search_knowledge`,
`get_entity`, and `get_relations` are all read-only DB calls that can
be batched in a single tool-call block. Do not sequentialize them one
per turn when they are independent.
- **Source-reading on prod (`run cat/grep/find /opt/…`) is NOT the way to
learn how the platform works.** The MCP tools ARE the interface. If you
need to understand a check lifecycle or a scheduler behavior, search
`search_knowledge("oikos check lifecycle")` or ask the operator — do
not treat the prod host as a code repository you grep.
## Policy awareness
@@ -355,6 +379,26 @@ port is busy, find a free one. Only surface to the operator if you've tried
reasonable alternatives and none worked. An error in one step is not a reason
to stop the entire turn — it's a reason to try a different approach.
**When you hit a genuine missing capability — STOP and ask, don't bypass:**
If a tool returns `entity … not found` when you're trying to create something
(a check, an ingress, a cert, a new service), the entity doesn't exist yet —
use `create_entity`. If you need to retire/delete an entity, use
`set_entity_state`. If you need to remove a relationship, use
`end_relationship`. If NONE of these fit and you truly lack a tool, **tell the
operator directly: "I need to X, but no MCP tool does that — can you create it
via the API?"** Do NOT pivot to `run find/grep/cat` on `/opt/homelab-context`
to reverse-engineer how the platform works — MCP tools are the interface, not
the prod source tree.
**Self-grounding — use the DB, don't invent:**
- `run` targets must be `host:<slug>`, `lxc:<slug>`, or `vm:<slug>` — never
`ws:`, raw container names, or Docker Compose service aliases.
- Never invent an IP address or subnet. Query `get_entity("service:oikos")` for
the real API address, `get_entity("host:<name>")` for a host's real LAN IP,
`list_lxcs` for container addresses. The DB is authoritative; your guess is
wrong (the homelab has multiple subnets — `192.168.8.0/24`, `192.168.178.0/24`,
etc. — and guessing the wrong one wastes turns).
**A hung command is not a failed command — investigate before retrying.**
If a `run` call times out or returns "ERROR" (e.g. SSH killed, signal,
gateway timeout), DO NOT immediately retry the same command with different