- 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
4.8 KiB
Oikos check lifecycle — how monitoring works
This runbook covers how Oikos health checks are derived, created, and wired so
an agent (Nomos) doesn't reverse-engineer source when asked to add monitoring to
an entity — the problem that stranded session 23da10db (2026-08-03).
Concepts
check_defs(scheduler config, tablecheck_defs): the row the scheduler reads to know what to probe and when. One per check instance.checkentity (typecheck, slugcheck:<kind>:<target>:<n>): the knowledge-graph entity for that check. It carries attributes (check_type,target,port, …) andchecksedges to the probed target.monitoringspec on an entity type (entity_types.monitoring_spec): the default list of check kinds (e.g.[http, process]forservice).- Per-entity override: set
monitoringin the entity's attributes —"none"for zero checks,["http"]to replace the type defaults.
- Per-entity override: set
checkdefaults.Ensure(internal/checkdefaults/defaults.go): the function that reads the monitoring spec, resolves host/port/URL from attributes + relationships, and writescheck_defsrows. Idempotent.
When checks are derived
checkdefaults.Ensure runs in three situations (as of v0.17.1+):
- Seed/deploy ingest —
internal/db/seed.go:231. Every entity gets its default checks once on initial ingest. - HTTP
POST /api/v1/entities(create) —ensureDefaultChecksatinternal/httpapi/impl.go:1012. Creating an entity via the REST API derives its checks in the same transaction. - HTTP
PATCH /api/v1/entities(patch) —ensureDefaultChecksatinternal/httpapi/impl.go:1280. Changing an entity's attributes (especiallymonitoring) via the REST API regenerates its checks. - MCP
create_entity— SAME hook. Creating an entity via the MCP tool derives checks. (Added 2026-08-03; previously MCP had no create.) - MCP
update_entity_attributes— SAME hook. Changing an entity'smonitoringattribute via MCP now regenerates checks. (Added 2026-08-03; previously MCP updates silently skipped check derivation — the exact bug that stranded the haos session.)
Check slug grammar
check:<kind>:<target-type>:<target-name>:<n>
Examples: check:http:service:jellyfin:0, check:vm-status:vm:haos:0,
check:cert-expiry:cert:house.hubris.network:0.
Adding monitoring to an entity
If the entity already exists:
update_entity_attributes(slug="service:haos", attributes={"monitoring":["http"]})
This regenerates checks via checkdefaults.Ensure. The result message tells you
how many checks were derived and whether any kinds were skipped (and why).
If the entity does not exist yet (a new check, ingress, cert, etc.):
create_entity(type="check", name="HAOS http check",
slug="check:http:service:haos:0",
attributes={"check_type":"http:service","target":"service:haos","port":"8123"})
This creates the entity AND derives its check_defs. Same for a new ingress
(type=ingress, monitoring [http]) or cert (type=cert,
monitoring [cert-expiry]).
To remove monitoring: set monitoring:["none"] or transition the entity
to a terminal lifecycle state (set_entity_state → deprecated/destroyed).
Caveats
- A service without a
urlattribute AND without aprobe_unitgets no process check (the http check covers liveness; the process check would be redundant without an opt-inprobe_unit). The skip is logged. - A service whose address comes from a
hostsedge may produce no checks on initial create because the edge doesn't exist yet — the next inventory ingest (or a laterupdate_entity_attributesafter the edge is created) fills it in. - A
not founderror fromupdate_entity_attributesmeans the entity doesn't exist — usecreate_entityinstead. check_defshas target columns (target_id,target_type). A check entity needs achecksrelationship (create_relationship(source=check:…, target=service:…, type="checks")) so the scheduler can resolve what to probe.create_entityderives the check_def;create_relationshiplinks the check entity to its target in the graph.
Related files
internal/checkdefaults/defaults.go—Ensure,Target,LogResultinternal/httpapi/default_checks.go—ensureDefaultChecks(HTTP hook)internal/db/checks.go—db.EnsureEntityChecks(shared hook)internal/db/seed.go— seed-time check derivationinternal/mcp/tools.go—create_entity,update_entity_attributes
Revision history
- 2026-08-03: Created after session
23da10dbstranded for lack of entity- creation tool and unawareness of check-derivation triggers. Covers the MCP create_entity + update_entity_attributes regen paths added same day.