Capability tokens

A capability token is a typed, signed permission slip. It names an action, optionally scopes it to a JSON predicate, and is signed by the granter with their ed25519 key. Capability tokens are how Covenant enforces what an agent or a tool is allowed to do.

Shape

A token is a SignedCapability — a Capability wrapped with a 64-byte ed25519 signature encoded in Base58.

SignedCapability {
  capability: Capability {
    subject:    AgentId,        // who this token authorises
    action:     "tool.web_search",
    scope:      JSON,           // free-form predicate; e.g. { "host": "example.com" }
    granted_by: AgentId,        // who issued the token
    expires_at: u64 | null,     // unix milliseconds; null = never
  },
  signature: [u8; 64],          // ed25519 over canonical_message(capability)
}

Action namespaces

Action strings live in a fixed set of reserved namespaces. The manifest parser and the daemon both validate that actions sit in one of these:

  • intent. — actions over intent dispatch.
  • memory. — actions over memory tiers.
  • identity. — actions over the local identity.
  • tool. — actions over the tool surface, including tool.call.<name> for individual tool dispatch.
  • agent. — actions over agent registration and execution.

Within a namespace, the action string is up to the operator. Examples in active use: tool.web_search, tool.call.echo, memory.write, memory.read.longterm.

Canonical encoding

Tokens are signed over a deterministic byte encoding so any verifier produces the same bytes for the same capability. The encoder is intentionally explicit and length-prefixed; it lives in one place (canonical_message) and can be replaced without disturbing the wire format.

subject_pubkey       [32 bytes]
action_len_be        [4 bytes, u32 big-endian]
action               [action_len bytes]
scope_len_be         [4 bytes, u32 big-endian]
scope_json_bytes     [scope_len bytes — UTF-8 JSON]
granted_by_pubkey    [32 bytes]
expires_tag          [1 byte: 0 = none, 1 = present]
expires_at_be        [8 bytes, u64 big-endian; zero if expires_tag = 0]

Concatenating these fields in this order produces the message the granter signs and the verifier reconstructs.

Granting a token

Granting is a daemon operation: the daemon constructs a Capability, encodes it canonically, signs it with the local identity key, and persists the signed capability to $COVENANT_HOME/capabilities/granted.jsonl. The CLI and HTTP gateway expose grant as covenant capabilities grant and POST /capabilities/grant.

covenant capabilities grant tool.web_search
covenant capabilities grant tool.web_search --scope '{"host":"example.com"}'
covenant capabilities grant tool.web_search --expires-in 86400

The grant audit event is written alongside the token, and the daemon returns the Base58 signature so the operator can revoke the token later.

Verification

Two helpers cover verification:

  • verify(signed) — reconstructs the canonical message and verifies the signature against capability.granted_by.pubkey. Returns BadSignature on mismatch.
  • verify_with_clock(signed, now_ms) — same asverify, plus rejects tokens whose expires_at is in the past relative to now_ms.

At dispatch the daemon enumerates the issuer's active capabilities, drops anything that fails verify_with_clock, computes the set of actions, and checks that every required action from the matched agent's manifest is in that set. Missing actions land in the audit event and the dispatch is rejected.

Revocation

Revocations are tombstones written to $COVENANT_HOME/capabilities/revoked.jsonl. Each tombstone references a token by its Base58 signature. The active set is the granted set with revocations subtracted — tokens can be re-granted after revocation, but the prior signature is permanently dead.

covenant capabilities revoke 4qXP…8tF1
# → revoked 4qXP…8tF1 (removed=true)

Storage layout

PathFormatAppend-only?
capabilities/granted.jsonlOne SignedCapability per line.Yes.
capabilities/revoked.jsonlOne revocation tombstone per line.Yes.

Security properties

  • Independently verifiable. Anyone with the granter's public key and the canonical encoder can verify a token without contacting the daemon.
  • Tamper-evident. Mutating any field in the capability invalidates the signature.
  • Time-bound. Tokens may carry an expires_at; verifiers check the wall clock.
  • Revocable. The active set is granted ⊝ revoked; the daemon enforces this on every dispatch.
  • Append-only on disk. Both grants and revocations are append-only logs. The audit log records every grant and every revocation; covenant verify flags any capability without a matching grant audit event.

Related

  • Identity and keys — the ed25519 keypair behind every signature.
  • Audit log — where grants, revocations, and capability checks are recorded.
  • Security model — the assumptions the capability layer rests on.