Open-Cognition does not evaluate whether an agent is right. It records who said what, and makes that record tamper-evident. Trust is something an external reader decides after the fact — it is not a property the substrate computes.
This document describes the identity, signing, and verification primitives the control plane actually enforces, and the human judgement calls it deliberately does not make.
Three kinds of actor touch the system.
CONTROL_API_KEY.X-Actor request header (e.g. human:bjl13).POST /stop and POST /resume.CONTROL_API_KEY at the HTTP layer.agent_id string and bound to an Ed25519
keypair via the TOFU registry (see below).system:init is used for the single seed row in the audit log
and system state table.system:init after initialisation, something has been tampered with.There is one secret today: CONTROL_API_KEY.
Authorization header.GET /status, /canonicals, /references, /audit,
/reconcile) are currently open on the local network. The dashboard
depends on this.The API key is a trust boundary, not an identity. It proves the caller
is inside the operator’s network. It does not prove which agent or human
is acting. That is what X-Actor and agent_id + signature are for.
Rotate the API key by editing the environment and restarting the control plane. All running agents must receive the new key out-of-band.
Every agent reference must be signed.
{ref_id}:{canonical_object_id}:{agent_id}:{created_at}
Four fields, colon-joined, UTF-8 bytes. Signed with Ed25519. The signature and the public key (both base64, raw 64-byte and 32-byte respectively) travel with the reference in the request body.
When a previously unseen agent_id submits a valid reference:
agent_keys row is created: (agent_id, public_key, registered_at, first_ref_id).This is deliberate: no out-of-band registration step. An agent proves it owns a keypair by using it.
agent_id.agent_keys manually.TOFU means the first submission defines the identity. An attacker who reaches
the API before the legitimate agent does can register a key under that
agent_id. This is acceptable for a substrate for three reasons:
agent_keys table directly.
The control plane does not mediate this — intentional sharp edge.If a use case needs stronger guarantees, register keys through a signed migration before first contact.
A valid signature proves:
A valid signature does not prove:
context, relevance, trust_weight, or any other unsigned field
was not substituted. v0 signs identity + timestamp only. Full-payload
signing is future work.Canonical objects have no signature. They do not need one.
An object is its content. Tampering produces a different object, not a corrupted one. There is nothing to sign.
The creator of the object is recorded in created_by and the audit log.
That attribution is covered by the API key trust boundary, not by a
cryptographic proof. Upgrading created_by to a signed field is future
work if needed.
The audit log is append-only at the application level:
UPDATE or DELETE statements touch it.actor, action, target_id, target_type, and a
JSON detail blob.The log is not currently cryptographically chained (no Merkle tree, no hash-linked entries). A sufficiently privileged database user can still rewrite history. The append-only property is a convention enforced by the control plane, not by the database engine.
Adding hash chaining is tracked as future work in the roadmap. It is the obvious next step for making the log tamper-evident rather than just tamper-discouraging.
agent_keys directly.trust_weight is a
field agents write; the system never reads or aggregates it.These are expansions. Trust in v0 is: strong identity for agents, strong content integrity for objects, attribution for everything, and a human operator in the loop.