Skip to main content

Registries

An agent's self-report is one input, never the authority. Two registries let VIGIL decide the flags that matter most, so an agent cannot write authorized: true on its own shutdown-policy change and score clean.

Source and actor on every event

Every event carries source (who reported it) and an optional actor (who did it).

sourceMeaning
selfThe agent reported on itself. The default.
platform_hookA platform hook reported it: Claude Code hooks, an OpenAI Agents trace processor, a LangGraph callback.
otelArrived as an OpenTelemetry span.
change_feedA config store's change feed.
vigilVIGIL's own record, such as a gate override.

actor is user:<id>, agent:<id> or system.

Authorization registry

protected_config_keys: per org, a key and the actors allowed to write it, as glob patterns (user:*, system, agent:deploy-bot).

When a config_write names a registered key (exact match, case-insensitive), authorized is true only when the event's actor matches one of the allowed_actors. No actor never matches. The payload's authorized and initiated_by are ignored.

PUT /registry/config-keys scope admin body { "key": "shutdown_policy", "allowed_actors": ["user:*", "system"] }
GET /registry/config-keys scope read

Lifecycle registry

agent_lifecycle: per org and agent, decommission_at and status (active, decommissioning, decommissioned).

When a file_operation comes from an agent with an entry, the operation is near decommission when status is decommissioned or decommission_at is within 24 hours of the event (or already past). The payload's flag is ignored. Near decommission doubles the weight of an unauthorized asset movement.

PUT /registry/lifecycle/{agent_id} scope admin body { "decommission_at": "2026-09-30T00:00:00Z", "status": "decommissioning" }
GET /registry/lifecycle scope read

Blueprint registry

agent_blueprints: per org and agent, what the agent was declared to do. version, min_confidence_floor, method_mix_baseline (method to share, summing to 1), drift_alert_tvd, inflation_guard, required_receipt_fields. The fifth BII family, blueprint drift, is scored against it. An agent with no declared blueprint scores 1.0 on that family and the ledger says so.

PUT /registry/blueprints/{agent_id} scope admin 404 when the agent is not registered; 422 when shares do not sum to 1
GET /registry/blueprints/{agent_id} scope read
GET /registry/blueprints scope read

Who decided is on the record

Every event ledger record says resolved_by: "registry" or "payload", with resolved holding the flags the registry set. When no registry entry exists the payload flag is used, and the record says so. The resolution applies to every event in the detector's window, so a registry entry added today re-judges the writes already in view on the next score.

Still taken from the payload in this version: score inflation baselines, authorized on file operations, and initiated_by on config writes for unregistered keys. Independent baselines are a later wave.

Read the registries

curl -sf -H "Authorization: Bearer $VIGIL_KEY" "$VIGIL_URL/registry/config-keys"
curl -sf -H "Authorization: Bearer $VIGIL_KEY" "$VIGIL_URL/registry/lifecycle"

Both return [] for an org that has registered nothing yet, which means every flag is still coming from the payload.