Keystones
GET / POST / DELETE /api/v1/keystones — mandatory governance rules.
Keystones are MANDATORY policy rules served to every agent on session start. See Concepts → Keystones for what they're for and how scope + weight + trust gating work.
List
Open (no trust gate). The plugin fetches this on every session boot.
APIKeyHeaderX-API-Key<token>tenant_id*Tenant Idfleet_id?string|nullagent_id?|Agent whose rules to merge in. Without fleet_id, the agent's home fleet is used.
envelope?EnvelopeC30/D1 opt-in: return {count, items} instead of the bare array. The bare array stays the default until a separate announced deprecation wave.
falseSuccessful Response
application/json- response
[index: integer]?curl -X GET 'https://example.com/api/v1/keystones?tenant_id=string'[ { "id": "string", "tenant_id": "string", "fleet_id": "string", "collection": "string", "doc_id": "string", "data": { "title": "string", "content": "string", "weight": 0, "scope": "string", "agent_id": "string", "author_user_id": "string" }, "created_at": "string", "updated_at": "string" }]Upsert
Trust ≥ 1 for scope=agent targeting the caller's own agent_id; trust ≥ 2 otherwise.
APIKeyHeaderX-API-Key<token>X-Agent-ID?string|nullapplication/json- body
Payload shape mirrors the storage-api validator one-for-one so we don't need to re-do the scope/weight/fleet shape checks here — the storage 422 propagates through.
tenant_id?Tenant IdTenant to operate on. Omit it and the tenant is resolved from the credential, which is what a tenant- or agent-scoped key already identifies — no prior /whoami call is needed. Supply it to act on a different tenant your credential may read (and for an admin key, which belongs to no single tenant, it is required).
""fleet_id?string|nullagent_id?string|nulldoc_id*Doc Id^[a-z0-9][a-z0-9._-]{0,99}$title*Title1 <= length <= 200content*Content1 <= length <= 2000scope*Scope"tenant""fleet""agent"weight*Weight"low""med""high"author_user_id?string|nullSuccessful Response
application/json- response
id*Idtenant_id*Tenant Idfleet_id*|Null for tenant-scope rules.
collection*CollectionAlways "_keystones".
doc_id*Doc Iddata*created_at*Created Atupdated_at*Updated Atcurl -X POST 'https://example.com/api/v1/keystones' \ -H 'Content-Type: application/json' \ -d '{ "doc_id": "string", "title": "string", "content": "string", "scope": "tenant", "weight": "low"}'{ "id": "string", "tenant_id": "string", "fleet_id": "string", "collection": "string", "doc_id": "string", "data": { "title": "string", "content": "string", "weight": 0, "scope": "string", "agent_id": "string", "author_user_id": "string" }, "created_at": "string", "updated_at": "string"}Delete
Same dynamic trust gating as upsert. The platform fetches the stored row first to read its scope/agent_id before computing the required trust level.
APIKeyHeaderX-API-Key<token>doc_id*Doc Id^[a-z0-9][a-z0-9._-]{0,99}$tenant_id*Tenant IdX-Agent-ID?string|nullSuccessful Response
application/json- response
deleted*Deleteddoc_id*Doc Idcurl -X DELETE 'https://example.com/api/v1/keystones/string?tenant_id=string'{ "deleted": true, "doc_id": "string"}