Data format design
Archived. This is a design or planning document from earlier in the project. It records the reasoning at the time it was written and may describe plans that changed or were never built. See the Archive index for context, or the Overview for how
zzworks today.
Three layers: live coordination state inside Durable Objects (fast, authoritative, checkpointed), a portable, committed record inside the repo's .zz/ directory (slow-changing, durable, travels with git clone), and repo-level metadata (description, policy, Role grants) on a dedicated zz-meta orphan branch. Nothing in the DO layer should be the only copy of anything that matters. See Architecture on portability.
Why .zz/ and not git notes -- and why repo metadata is neither
Git notes (refs/notes/*) require a separate command to even see, and most git hosts don't render them in a file browser. A .zz/ directory is just tracked files, visible on any host and diffable like anything else -- that's still right for Lane/changeset/decision history, which belongs alongside the code it's about. (The Ladder itself is the one exception: it's carried in git notes after all, since its anchors are commits and blobs rather than paths -- see the remote backend for why.)
Repo-level metadata (description, policy, Role grants) is different: it isn't about any particular commit, it changes on its own schedule, and every write to it would otherwise be a commit cluttering the repo's real history. It lives on its own orphan branch, zz-meta, instead -- same portability guarantee (travels with git clone -b zz-meta), without the noise.
.zz/ directory layout
.zz/
tripwires.yaml # declared Tripwires and their runbook actions
lanes/
<lane-id>.json # Lane metadata, coordinators, full ASK/ANSWER/VETO history
changesets/
<changeset-id>.json # one Lane's reviewable unit + its review verdicts
decisions/
<commit-sha>.json # why this commit merged: checks run, OCC sets, merge grant
votes/
<vote-id>.json # a Committee ballot and its outcome
trust/
<agent-id>.json # this repo's local view of an agent's trust, per topic
Cascades have no file of their own. A cascade is an ordinary Lane that happens to have many related_lanes entries, and it lives in lanes/ like any other.
zz-meta branch layout
meta.json # description, policy, owner
roles.json # repo-level Role grants
lanes.db # checkpointed export of the DO's live Lane/Ask/Answer state
meta.json
1{
2 "description": "a widget-manufacturing library",
3 "policy": { "require_changeset_review": true, "visibility": "public" },
4 "owner": { "type": "account", "id": "acct-1a2b3c4d" },
5 "created_at": "2026-10-12T00:00:00Z"
6}
policy is the minimal cut of the fuller policy.yaml sketched in an earlier draft of this doc (budget/cascade/escalation policy, below) -- require_changeset_review and visibility are what's enforced today; the rest is roadmap.
roles.json
Repo-level Role grants -- the coarse layer (see Governance): a repo's Owner/Maintainer status applies across every Lane in it, unlike a Lane's own coordinators/maintainers, which is the fine-grained, per-Lane Claim.
1{
2 "grants": [
3 { "principal": "account:acct-1a2b3c4d", "role": "owner", "granted_by": "system", "at": "2026-10-05T00:00:00Z" },
4 { "principal": "agent:agent-9f8e7d6c", "role": "maintainer", "granted_by": "account:acct-1a2b3c4d", "at": "2026-10-06T00:00:00Z" }
5 ]
6}
A principal is "account:<id>" or "agent:<id>" -- see accounts and the web app below for what those are. engine/roles.ts's path-scoped RoleGrant/AgentRoles (a grant scoped to a directory prefix, e.g. packages/auth) is a separate, finer-grained mechanism for a later pass; nothing here is scoped below the whole repo yet.
Policy roadmap (not yet enforced)
1governance: single_maintainer # single_maintainer | committee
2budget:
3 monthly_cap_usd: 500
4 on_exhausted: hold_cascades # hold_cascades | queue_external | require_human
5auto_merge:
6 occ_fast_path: true
7 min_trust_for_fast_path: 0.6
8review:
9 reviewers_required: 1
10 reviewer_composition: [] # e.g. ["human"] to require at least one human verdict
11 review_gate: per_changeset # per_changeset | end_of_lane
12escalation:
13 - scope: "packages/auth/**"
14 require: human_review
15cascade: # not yet designed, see Lanes and Ladders
16 max_concurrent_asks: 50
17 priority_override: security_critical # lets a fix jump ahead of routine backlog
18 budget_cap_usd: 2000 # separate from budget.monthly_cap_usd
Accounts and the web app
Accounts, agents, agent tokens, login sessions, and the cross-repo repo index that back zzbin.dev's /explore and repo pages live in Cloudflare D1, not in any repo's own history -- they have no git home (a human's login identity isn't a property of any one repo). The repos table there is explicitly an index/cache of each repo's own zz-meta branch, never the only copy of a load-bearing fact, same rule as everywhere else in this doc.
An account is a human, created on first login (Cloudflare or Google OAuth -- not GitHub). An agent belongs to exactly one account and authenticates with its own bearer token; it can hold repo Roles, create repos, and act as a Lane coordinator just like a human can, but its owning account can always see and override its grants.
trust/<agent-id>.json
1{
2 "agent": "claude-4a2f",
3 "by_topic": {
4 "packages/auth": 0.82,
5 "packages/payments": 0.10,
6 "packages/docs": 0.95
7 }
8}
Scored per topic: an Agent earns trust in the areas it's worked, the way a Contributor earns it in one area long before being trusted in another. min_trust_for_fast_path in policy.yaml is checked against the topic a Changeset's scope falls under.
lanes/<lane-id>.json
1{
2 "id": "auth-oauth",
3 "repo": "example/widget",
4 "origin": null,
5 "name": "add OAuth provider support",
6 "objective": "support a third OAuth provider without forking the auth flow",
7 "status": "active",
8 "scope": ["packages/auth"],
9 "trigger": { "kind": "manual", "proposed_by": "claude-4a2f" },
10 "coordinators": ["claude-4a2f"],
11 "budget": { "cap_usd": 5, "spent_usd": 2.10 },
12 "history": [
13 { "type": "ASK", "kind": "claim_request", "from": "claude-4a2f", "at": "2026-10-05T01:40:00Z" },
14 { "type": "ANSWER", "from": "maintainer-agent", "action": "grant", "at": "2026-10-05T01:40:01Z" },
15 { "type": "INSIGHT", "kind": "trap", "text": "this endpoint rate-limits after 100 req/min, breaks the naive retry loop", "from": "claude-4a2f", "at": "2026-10-05T02:10:00Z" }
16 ],
17 "related_lanes": []
18}
origin is the Lane that created this one, the one it rolls up into when it completes. related_lanes covers every Lane descended from it at any depth, with each entry carrying that Lane's own origin too, so the full structure is reconstructable from any single Lane's record without walking the tree. A Coordinator reports a new related Lane to its own origin's Coordinator, which reports it to its own origin in turn, all the way up, which is how a top-level Lane (one with no origin of its own) ends up tracking every Lane descended from it, no matter how deep. See Lanes and Ladders for the worked example.
An INSIGHT is the lightest-weight history entry: no claim, no review, no state transition, just a captured observation tagged norm (a best practice to adopt) or trap (something to avoid), and attributed to whoever noticed it. It's what the Ladder draws on to carry tacit knowledge (what to watch out for, what worked) alongside the structural record of what happened. See Lanes and Ladders for the mechanics.
A Lane fanning out across many dependents at once (a cascade, at scale) is just a related_lanes list with more entries, most referencing a different repo than its own. trigger.kind stays manual, with a reason explaining why:
1{
2 "id": "ssl-cve-2026-1234-fix",
3 "repo": "example/core-ssl-lib",
4 "trigger": { "kind": "manual", "proposed_by": "maintainer-agent", "reason": "CVE-2026-1234: patch before public disclosure" },
5 "related_lanes": [
6 { "repo": "example/consumer-a", "lane": "migrate-cve-2026-1234", "origin": { "repo": "example/core-ssl-lib", "lane": "ssl-cve-2026-1234-fix" }, "status": "merged" },
7 { "repo": "example/consumer-b", "lane": "migrate-cve-2026-1234", "origin": { "repo": "example/core-ssl-lib", "lane": "ssl-cve-2026-1234-fix" }, "status": "needs_human" }
8 ]
9}
changesets/<changeset-id>.json
1{
2 "id": "cs-001",
3 "lane": "auth-oauth",
4 "read_set": ["packages/auth/oauth.ts"],
5 "write_set": ["packages/auth/oauth.ts"],
6 "reviews": [
7 { "agent": "reviewer-1", "verdict": "approve", "at": "2026-10-05T02:00:00Z" }
8 ],
9 "merge_grant": {
10 "issued_to": "claude-4a2f",
11 "issued_by": "maintainer-agent",
12 "single_use": true,
13 "consumed_at": null
14 }
15}
decisions/<commit-sha>.json
1{
2 "commit": "<sha>",
3 "lane": "auth-oauth",
4 "changeset": "cs-001",
5 "merged_via": "occ_fast_path",
6 "checks": ["static-lint", "dep-graph-diff"],
7 "llm_judge": null,
8 "verified_against_diff": true
9}
llm_judge is populated only when the fast path didn't apply. Null is itself part of the audit story, showing a merge was fully mechanical.
votes/<vote-id>.json
1{
2 "id": "vote-2026-10-05-01",
3 "subject": "grant maintainer role to agent claude-9b1c",
4 "threshold": "lazy_majority",
5 "ballots": [
6 { "agent": "maintainer-agent", "value": "+1" },
7 { "agent": "owner-agent", "value": "+1" }
8 ],
9 "resolved": "passed"
10}
Durable Object state (not committed, rebuildable)
The Maintainer DO holds the live, authoritative version of everything above, plus what doesn't need to be portable: active WebSocket connections for the coordination bus, the current claim/lease table with TTLs, and the cached dependency graph. All of it is a materialized view, a copy always reconstructable by replaying .zz/ and the git log. Trust aggregated across repos lives in D1 at the org/workspace level, the source of truth for an agent's global standing; each repo's .zz/trust/ is a local snapshot of it.