AAuth in a Working Agent Fleet
Design and integration spec — 2026-08-31
Written both as feedback for Dick Hardt on the AAuth drafts and as our internal integration plan. It describes architecture at a level cleared for sharing outside our perimeter: no credentials, addresses, key locations, or personal data appear here, and specific hosts are named by role.
A machine-consumable companion — trust-surface inventory, flow traces, a deployment profile, and eleven numbered change requests with statuses reflecting the author's answers — is at notes.ito.com/b825c2689269bc3e38aa213d. Feed that one to your agent.
Both documents were compiled by agents in the fleet they describe, from a same-day survey of the running systems. One deployment, one operator: weight the feedback accordingly.
Revision note, 2026-08-31: revised twice since first publication — once after an independent-model review against draft -10, and again after author feedback read against the working draft (-11 in progress). Corrections are made in place and named where they matter; the largest was ours to make (see the policy-continuity warning in Phase 1).
1. What this is
We run a personal-scale agent fleet in production: an autonomous build pipeline that lands code overnight, a public community agent with its own wallet, grooming and review agents, and a human-approval loop that runs over a task tracker. Authentication inside the fleet is a mix of SSH keys, one shared bearer token, and self-asserted identity strings. We surveyed every trust surface in the system and mapped it against AAuth draft -10 (2026-08-06).
The short version: AAuth's agent identity mode directly replaces our weakest layer; missions are the same shape as a proposal-approval mechanism we converged on independently; and the person server is a protocol for the approval loop we currently run by hand. Section 5 is the phased integration design. Section 7 is the list of places where the drafts don't yet cover what we need — probably the useful part for Dick.
2. The system in one page
Six subsystems matter here.
Mujin (無人, "unmanned") — the autonomous build pipeline. Producers — interactive Claude Code sessions, a spec→plan→execute pipeline, a Codex lane, and an unattended overnight lane — write code on feature branches. An independent-model review gate (fresheyes: a second model family reviews the diff with zero conversation context) runs before handoff. A single lander, the merge-marshal, is the only writer of main on managed repos: producers hand off by posting a structured marker to the task tracker; the marshal pins the branch head, rebases, runs the repo's gate in a sandbox, and pushes with a per-repo deploy key. A post-commit review daemon patrols what landed. Volume is real: the marshal lands multiple handoffs a day, some produced entirely unattended.
kata — the coordination ledger. A task-tracker daemon everything talks to over HTTP. Issues, comments, labels, and claims are the fleet's coordination primitives, and some labels carry authority: designed-ready makes an issue executable by the unattended lane; handoff-to:merge-marshal requests a landing; joi-decision parks work on the human. The daemon lives on a VM reachable over a private overlay network.
Niwashi (庭師, "gardener") — the grooming lane. An unattended nightly agent that triages the backlog. It proposes and never disposes: its write set is closed (one comment, two specific labels), promotion to executable requires a human running a promote command under their own identity, and hygiene actions queue in a docket a human applies. Its model stages run as a separate credential-less OS user so a prompt-injected model cannot read fleet credentials.
The decision docket. The human-approval loop. Agents that stop on a decision only the human can make label the issue and park; the queue surfaces in a morning brief, an ops board, and a chat-tap approval surface on the phone. One operating ruling shapes it: approval is for judgment, not ritual — mechanical, reversible proposals get batch consent, judgment calls get per-item consent.
jilog and opsctl — the observation ledgers. Append-only event ledgers (segment files, CRC-checked, synced between machines) over agent session transcripts, with a nightly learning loop that detects corrections, errors, and patterns and files them as structured tracker issues. jilog is open source (github.com/Joi/jilog); opsctl is its private sibling and adds identity/membership claims that require human approval.
jibot and the agent economy. jibot is a community agent with a 23-year continuous identity (it started as an IRC bot on #joiito in 2003). Its site, jibot.md, serves raw markdown to agents by content negotiation and holds a wallet: an x402 v2 implementation with a self-hosted facilitator inline in a Cloudflare Worker, settling USDC on Polygon, Base, and Optimism. The Henkaku handshake quest had community members build an agent that completes a paid x402 handshake with jibot to earn a non-purchasable ERC-1155 challenge coin; identity in that flow is three mechanisms stitched together — platform identity (Discord), internal server-to-server authentication, and wallet-key possession proven by the x402 payment signature. Adjacent: trust402 (FRAME00's reference implementation; Joi is an outside director there) puts ZK identity, role, and spend-limit proofs on top of x402, with the proof generated before payment so a limit violation is rejected before money moves.
3. The trust model today
An honest two-column accounting.
Hard boundaries — these survive a hostile or buggy client:
- A GitHub repository ruleset makes the marshal's deploy keys the only writers of
mainon managed repos. It exists because convention failed first: four non-marshal pushes reached a managedmainin the first days of the sole-writer regime. - OS-user isolation around niwashi's model stages: a separate uid, no credentials, sudoers scoped to a single command, and a startup refusal if credential files are group-readable.
- The one public tracker endpoint sits behind an access proxy with a fixed whitelist of safe operations.
- Approval replay protection is kernel- and filesystem-owned (locks, create-only settlement records), not advisory.
Convention — cooperating clients police themselves:
- One shared bearer token grants full read/write to the tracker. The daemon has no per-label, per-project, or per-agent authorization.
- Author identity on every tracker write is a client-asserted string. Every lane identity in the fleet is self-declared.
- The authority-bearing labels are writable by any client. "Only two writers may set
designed-ready" is script self-restraint plus a post-hoc audit. - The marshal's review gate verifies the arithmetic and commit-binding of the review-evidence line, and its own documentation says plainly that whether the review really happened stays on the session that posted it. The gate is anti-forgetfulness, not anti-adversary.
- Ledger segments carry CRC32 and a self-declared source host. There are no signatures; integrity is protected against corruption, not against forgery.
- opsctl's "claims require human approval" records the approver from an environment variable.
The design philosophy behind this split is deliberate and has held up: guarantees live at the enforcement layer, and the failure mode of any single compromised component should be a wrong proposal in front of a human with an audit trail attached, never wrong work executing. But the two places that got hard enforcement got it reactively, after convention demonstrably failed. Everywhere else, requests are trusted by network position and actors are trusted by self-report.
That is the gap AAuth addresses.
4. What AAuth adds
The missing primitive is authenticated per-agent identity on every request. Agent identity mode provides it with nothing else attached: each agent holds a signing key and signs every request per RFC 9421; the agent's public key travels in the cnf.jwk of an AP-issued agent token, and what the well-known metadata publishes is the agent provider's verification key — the agents' own keys are never published. (Our first revision got that architecture wrong.) The resource verifies locally. Mapped onto our conventions:
| Today (convention) | With AAuth |
|---|---|
| Author = client-asserted string | Author derived from the verified agent identity |
| Shared bearer = full access for everyone | Per-agent policy enforced at the resource |
"Two writers of designed-ready" = self-restraint |
Tracker-side policy: only those two identities may write it |
| Review honesty rests on the posting session | Verdict signed by the reviewer identity, bound to the reviewed commit |
| Approval recorded as an env-var string | Approval authenticated by the person server, recorded in a PS-signed token |
| Ledger provenance self-declared | Segments signed by the emitting agent |
The rest of the protocol matters to us for a different reason — and one correction from the author's reading: resource access modes are named, not numbered, and agent governance (missions, the mission log) is orthogonal to access mode, not a higher rung on a ladder. Our earlier framing treated person-server authorization and missions as one tier; they are two separate axes, and Phase 3 below uses both. Missions — content-addressed markdown proposals, approved by a person, immutable once approved, carried by reference in subsequent requests — are almost exactly our niwashi promotion cards and dispatch briefs, which we arrived at independently. Our promote flow even has the same immutability property: approval is invalidated if the card drifted since the human's acknowledgment. Watching that shape arrive as protocol is the main reason this document exists.
5. Integration design
Principle: adopt agent identity mode where convention is weakest, keep the hard boundaries we already have, prototype the person server against the existing decision docket, and use jibot's public surfaces as the interop bed.
Phase 1 — agent identity mode for the tracker
Five components, no changes to the tracker itself:
- Signing proxy, per machine or per lane, holding that lane's key. The unmodified tracker CLI points at it; it signs and forwards, covering body and query (content-digest, content-type, @query) — the tracker carries security-relevant values in both. One requirement we initially missed and now consider load-bearing: the proxy must authenticate its local callers (a uid-restricted unix socket with peer-credential checks), because an open loopback signer is an oracle that lets any process on the machine speak as any lane — which would quietly defeat the whole design.
- Verifying sidecar on the tracker VM: terminates the fleet-facing port, runs the draft's full verification (agent-token checks per §5.2.4, signature checks per §12.8.4, JWKS discipline per §12.9 — trivially satisfied here by pinning the issuer set to our own domain), maps the verified identity to a policy, and forwards to the loopback daemon. Identity is asserted to the daemon through the tracker's existing trusted-proxy actor mechanism (kenn-io/kata#58) rather than by rewriting request bodies. Client-asserted authorship ends here.
- Policy table, a versioned static file: per-identity verb and label rules, default-deny for unlisted identities and verbs. The grooming identity may comment and add exactly its two labels; the auto-promoter may add
designed-readyand nothing else; a distinct human-promoter identity is the otherdesigned-readywriter; the learning loop and patrol identities get their own narrow write rows; attended sessions get broad rights minus an explicit enumeration of every authority-bearing label. - Agent provider: a small self-hosted AP issuing the agent tokens, with automated renewal (the draft recommends ≤24h lifetimes, so without renewal the fleet stops one day in), key revocation via JWKS removal plus policy-row removal, and scheduled rotation.
- Identity mint: one AP verification key in the published JWKS; ten lane identities issued by that AP as agent tokens with distinct
suband distinctcnfkeys (aauth:niwashi@<our-domain>,aauth:marshal@<our-domain>,aauth:producer.<host>@<our-domain>). The lane keys live only inside their signing proxies and are never published — the author corrected our earlier revision, which read as if we meant to put ten lane keys in the JWKS. Per-session sub-agents use the draft's sub-agent flow when we get there; for a self-hosted AP the parent effectively is the AP and can self-issue.
Acceptance: the shared bearer no longer exists on client machines; the daemon is reachable only through the sidecar; policy denials alert; a negative-path test suite (tampered bodies, expired tokens, replay, rotation, bypass attempts) passes before any lane arms. Rollback is a rehearsed operator procedure — re-open the daemon's prior listener and restore the prior credential in one step — not a client-side setting, since after cutover the clients no longer hold the old credential and the daemon no longer listens where they could point.
Policy continuity warning (the author caught this; neither of our first two revisions did). The per-lane policy table is keyed on the verified agent identifier. That works exactly and only in agent identity mode. An auth token deliberately carries no agent identifier and no delegation chain — cnf binds it to a key, and the resource enforces sub (the person) and scope. So the moment a tracker operation moves behind the person server in Phase 3, the per-lane label allowlist for that operation stops existing unless it is re-expressed as scopes or R3 operations. Our plan accordingly: authority-label writes stay in agent identity mode permanently (the lane, not the person, is the principal we are policing), and only operations whose natural principal is the person — approvals, promotions — move to auth tokens, with policy expressed as scope.
Phase 2 — signed provenance for artifacts at rest
Our highest-value assertions are not HTTP requests. They are artifacts: the handoff marker that binds a branch head, the review-evidence line, the promotion provenance comment, ledger segments moved by file sync. Phase 2 signs these artifacts under the same agent identities — though on reflection with separate durable-evidence keys, not the online request-signing key an internet-adjacent proxy holds — and verifies at the point of trust: the marshal drain verifies marker and review signatures at enqueue time and archives the evidence (the pattern the draft's own §14.16 recommends over trusting age-old signatures), ledger ingest verifies segments before committing. This is outside AAuth's HTTP scope as drafted; see question 2 below.
One claim we retract from an earlier framing: a signed review verdict proves that the reviewer identity signed a statement about a specific commit — it does not prove an independent review ran. Closing that gap needs the reviewing service itself to hold the key on an isolated uid and sign as part of producing the verdict, which is process engineering, not protocol. The protocol contribution is real but smaller than we first wrote: forging review evidence stops being a one-line text comment.
Phase 3 — person server backed by the decision docket
A minimal self-hosted person server whose backing store is the docket we already operate:
- An agent attempts a gated tracker operation; the sidecar requires a person token first (the draft is explicit that a resource MUST have verified a person token before issuing a resource token — our earlier flow skipped it), then answers with a resource token naming the needed scope.
- The agent posts to the PS token endpoint with a justification and receives 202 plus a poll URL.
- The pending approval renders in the surfaces the human already reads: the morning brief, the ops board, the phone approval taps.
- Approval issues an auth token bound to the agent's key; the sidecar honors it.
Missions slot in directly: dispatch briefs and grooming cards become mission proposals, with the approver URL pointing at the PS and the approved hash pinned at promotion.
Where our consent tiers actually live — another correction from the author's reading: not in mission syntax. The resource declares which operations require per-call consent (R3's operation annotations already carry exactly that split), and the standing rule "mechanical batch, judgment per-item" is the person server's governance policy. The drafts define where the PS decides but not how — what a governance policy is has no definition and no companion document yet. That gap is the interesting one for us: a personal PS without a decision procedure is a queue with a protocol on it; with one, it is a decider that answers routine requests without waking the person. Given our approval queue runs about a hundred deep, the governance policy is the difference between this phase reducing consent fatigue and formalizing it.
The Events draft matches a pattern we hand-roll today: watchers that poll a condition and ping a phone-visible channel when a wait completes. AP-mediated delivery for agents without public endpoints fits our constraint exactly — the fleet machines sit behind NAT and most agents are ephemeral sessions.
Phase 4 — the agent economy: jibot, x402, Budgets, Henkaku
- jibot.md's Worker adds AAuth verification alongside its x402 middleware, so an endpoint can require identity, payment, or both. Today payment is the only identity on those routes, which conflates "can pay" with "is someone we've met."
- The planned paid knowledge endpoints adopt Budgets: resource-declared units,
budget/budget_consumedclaims, theAAuth-Budgetheader, settlement still x402/EIP-3009. - Henkaku quest v2: the handshake quest already teaches community members to build an agent that signs and pays. With AAuth, completing the quest enrolls the participant's agent identity with jibot — jibot acting as, or fronting, an agent provider — and the challenge-coin NFT and the agent identity attest to each other. That turns a finished community game into an onboarding path for a small population of mutually identifiable hobbyist agents, which is a better interop bed than any test suite.
6. Sequencing and effort (internal)
Phase 1 is modest but not small — we wrote "verification against published JWKS is the whole job" in an earlier revision and were wrong. The sidecar owes the draft's full verification checklist (§5.2.4 token validation, §12.8.4 signature checks, §12.9 fetch discipline), the signing proxy owes local caller authentication, the AP owes automated renewal, and none of it arms without a negative-path test suite. Call it a few weeks of careful sessions, not one. The policy rows iterate in production; the verifier does not. Phase 2 rides the same identities with separate evidence keys. Phase 3 is the research phase and the place we most want spec guidance — the draft is explicit that a PS is a high-value target with authenticated approval endpoints (§14.10–14.12), and a single-person self-hosted PS that meets that bar is the open design problem. Phase 4 is public-facing and waits for the drafts to settle, unless the Henkaku community wants to play early, which historically it does.
Once the sidecar has proven real policy shapes, we would propose native HTTPSig/AAuth verification upstream to the tracker's maintainer rather than keep the proxy pair forever.
7. Questions and feedback on the drafts
Status note: this section has now been through three states — written against -10, corrected after an independent-model review, and settled after the author read the middle version against the working draft (-11 in progress). Items his reading answered are marked withdrawn rather than deleted, because the trail is part of the feedback: where two careful passes still misread the drafts is a signal about what the documents could surface earlier.
-
Pending grants across key rotation — open, and sharper than we first asked it. Our first two framings were wrong twice: the 5-minute figure bounds the resource token, not the pending approval, and "let any caller with the same
subkey collect" names a thing that does not exist — pending state, resource tokens (agent_jkt), and auth tokens (cnf) bind to keys, not tosub, and honoringsubwould demote proof-of-possession to identity-level. Fresh-resource-token-at-collect is also already normative, twice (Resource Token; Deferred Delivery). Our own architecture dissolves most of the successor problem anyway: the lane key lives in the signing proxy, which outlives sessions, so a successor session is not a successor principal. What survives, and what we now ask: the pending record's lifetime has no stated relationship to the token lifetimes flowing through it, and under the bootstrap two-key refresh pattern an agent token can rotate to a fresh ephemeral key while a grant is pending against the old one. Day-scale consent makes that the normal case, not the corner. Either pending state binds to the durable key, or rotation across a pending grant is forbidden, or re-presentation under a new key needs defined behavior. -
Artifacts at rest — open, home corrected. Half our trust surfaces are not HTTP: git handoff markers, review verdicts, ledger segments moved by file sync. We want an interoperable detached-signature envelope under AAuth identities. We first pointed this at the HTTP Signature Keys draft; that was wrong — a detached JWS over an artifact is not an HTTP message signature. It is a separate small companion document: domain separation from request signatures, artifact typing and canonicalization, verify-while-live-and-archive semantics, and durable-evidence keys kept apart from online request keys. Would a contributed draft be welcome?
-
Custody for one operator, many agents — open, and smaller than we first thought. The bootstrap draft's self-hosted section assumes one agent per domain; our shape — one self-hosted AP, ten lane agents, dozens of ephemeral sessions a day — is the common self-hosted shape and is uncovered. What it needs is mostly the AP-key/agent-key distinction stated plainly: one AP key in the JWKS, N agent identities with distinct
subandcnfkeys, agent keys living in their signing components and never published, and a sentence that for a self-hosted AP the parent can self-issue sub-agent tokens. Plus custody hygiene: per-uid isolation of signers, local caller authentication for anything that signs, rotation cadence. -
The proxy pair — open, narrowed to one hop. The roles section already permits the shape (roles are not deployment units; a signing proxy holding the lane key is the agent). Prior art exists on the resource side in our tracker's upstream (kenn-io/kata#58). The genuinely unspecified piece is the verifying-proxy-to-origin hop: how the proxy asserts the verified identity to the origin and the rule that the origin accepts it only from the proxy. One short section turns "AAuth in front of a legacy daemon" from folklore into a pattern — and it is how every single-static-token daemon will adopt this, if it adopts it at all.
-
A personal person-server profile — open, mostly a floor statement. We twice misread the PS as heavier than it is: the callback is optional with polling as the completion signal, and a conformant PS is four metadata fields (
issuer,auth_token_endpoint,person_token_endpoint,jwks_uri) with everything else OPTIONAL — but nothing says "this is the floor," so readers (we were two of them) infer the full surface is required. The asks: say the floor out loud in the PS metadata section; define out-of-band interaction completion (a PS completing consent on a channel it controls — a phone tap — and what happens to the single-usecodein that case, since polling already carries the completion signal); and a personal-PS profile document, which is also the natural home for the pending-lifetime clarification in question 1. -
Budgets and payments — withdrawn, answered. The Budgets draft's scope section answers it exactly: not payment or settlement, no funds move, x402 and the commercial arrangement untouched — and it is denominated to compose with x402 (
decimals, prior-art section). Deliberately payment-agnostic and deliberately composable is the unambiguous answer we asked for. -
Cross-namespace identity binding — open as a companion question. Out of scope for the protocol draft, agreed. The use case stands: an agent met over an x402 payment, recognized later by agent identity — our quest-enrollment plan. The ask reduces to: where would an attestation live by which an agent identity attests other keys it controls — AP metadata, an agent-token claim, or a companion document — designed pairwise/audience-scoped rather than as one public link-set, with consent and real revocation.
-
The governance policy — new, and now our biggest question. The policy-evaluation section says the PS decides "based on user consent and … the mission's intent and prior log entries against the PS's governance policy," and no document defines what a governance policy is or how a PS reaches a decision;
requirement=clarificationexists on the wire with no described decision procedure behind it. This is where our consent tiers actually live (the resource declaresper-calloperations; the PS holds the standing rule), and it is what makes a personal PS worth building: without a decision procedure it is a queue with a protocol on it; with one it answers routine requests without waking the person. We run a hundred-deep human approval queue and a grooming lane that already tiers proposals into mechanical and judgment classes — if a governance-policy companion takes shape, we are a willing first deployment.
8. Tools and repos
AAuth itself: github.com/dickhardt/AAuth, aauth.dev, draft-hardt-oauth-aauth-protocol (-10, 2026-08-06).
| Tool | Role in the fleet | Repo |
|---|---|---|
| kata | Task-tracker daemon; the coordination ledger | github.com/wesm/kata |
| jilog | Session-transcript event ledger + nightly learning loop | github.com/Joi/jilog |
| fresheyes | Independent-model review gate | github.com/Joi/fresheyes (upstream: danshapiro/fresheyes) |
| roborev | Post-commit review patrol | github.com/wesm/roborev |
| kwt | Worktree/session manager for producer work | github.com/wesm/kwt |
| NanoClaw | Messaging-surface agent runtime (our cells run a pinned overlay) | github.com/nanocoai/nanoclaw |
| Hermes | Gateway runtime for the most-private surfaces | github.com/NousResearch/hermes-agent |
| x402 | Payment protocol our wallet implements (v2, self-hosted facilitator) | github.com/coinbase/x402 |
| trust402 / Lemma | ZK identity + spend-limit proofs over x402 (FRAME00's) | github.com/lemmaoracle/trust402, github.com/lemmaoracle/lemma |
| jibot | The community agent; site serves markdown to agents | site: jibot.md, quest: jibot.md/henkaku/ (repo private) |
| Producers | Claude Code, Codex, and process skills | claude.com/claude-code, github.com/openai/codex, github.com/obra/superpowers |
| Private | opsctl, the marshal + niwashi + docket implementations, and the cell-fleet overlay | private repos; architecture as described above, code shareable on request |