Scope manifests
The per-task grant that says which tokens an agent currently holds — and the reason the default answer is “no”.
A protected path only opens for an agent that holds the right token. A scope manifest is where those tokens live: a small operator-issued file, one per work area, that lists exactly what the current task is allowed to do. The gate reads it on every write.
One manifest per worktree
Section titled “One manifest per worktree”Each WIP worktree gets its own manifest, stored at
/var/lib/operator-authority/scopes/<worktree-hash>.json. The hash binds the grant to a
specific directory: it is the first twelve hex characters of the SHA-256 of the worktree’s resolved
absolute path. Move to a different worktree and you get a different hash, hence a different (or absent)
manifest. A grant for one task’s directory cannot be reused from another.
What a manifest holds
Section titled “What a manifest holds”| Field | Meaning |
|---|---|
scope_tokens |
The tokens this task holds (e.g. task-approved, migration). |
allowed_paths |
Specific path globs granted outright, regardless of the policy. |
expires_at |
When the grant lapses. After this, it counts as no grant at all. |
task_id |
The task this grant belongs to. |
agent_identity |
Which agent the grant was issued for. |
worktree_path |
The directory the grant is bound to. |
issued_by |
The operator who granted it. |
Operator-owned, agent-readable
Section titled “Operator-owned, agent-readable”The crucial property: an agent can read its manifest but cannot
write it. The scopes directory is operator-owned (restrictive permissions, an
operator-authority group); grants are issued through the runtime’s admin surface — the
dashboard’s Agent Authority view — never through the gate or by the agent itself. An agent therefore
cannot grant itself a token. That one-way relationship is what makes the token meaningful: it can only
come from the operator.
How a token gets there
Section titled “How a token gets there”The usual path: the agent hits a protected action, the gate routes it to the
approval queue, the operator approves a plan, and that approval writes
the task-approved token into this worktree’s manifest — atomically with the approval record.
On the agent’s next attempt, the gate reads the now-present token and allows the write. The manifest is
the durable memory of the operator’s “yes,” with a built-in expiry so a yes doesn’t last forever.
From dashboard to gate — the projector
Section titled “From dashboard to gate — the projector”There is a subtlety the design hides: the gate reads files, but the dashboard and runtime
write a Postgres table (operator_authority.scope_manifests). For a long time
nothing connected the two — the runtime container had no mount of the host scopes directory — so a grant
issued in the dashboard never actually reached the gate; only manifests hand-written on the host did.
A small host daemon now bridges them (operator-authority-scope-projector, a systemd service
running as the scopes-dir owner). Each cycle it does a read-only SELECT of the
scope_manifests table and materialises every row into the gate’s JSON file, atomically, within a
few seconds. It only reaps files it projected (marked _projected_from_db), so hand-written
manifests are left untouched. With it in place, the dashboard’s Agent Authority → Scope Manifests form
(issue / edit / revoke a grant with a TTL) is finally authoritative for the gate: write a grant, and the
agent’s next attempt sees it within ~5 seconds. (Added 2026-06-19.)

