Zones
A zone is the unit of protection: path patterns + owner + risk level + default policy. This is CC’s own zone map, trimmed — the real file the product’s development runs under, not an idealised example:
# .zones/zones.yml — committed, reviewed like codeversion: 1
zones: - id: schema name: Database schema risk: high owner: paulo@commitcycle.com description: > D1 migrations and table structure. The only thing a git revert does not undo. paths: - "apps/api/migrations/**" - "apps/api/src/db/schema/**" default_policy: deny
- id: enforcement name: Enforcement layers risk: high owner: paulo@commitcycle.com description: > The hook and the GitHub Action. A silent bug here means the gate is decorative while still reporting success. paths: - "packages/hook/**" - "packages/action/**" default_policy: deny
# Everything not listed here is unprotected, on purpose.The design bets
Section titled “The design bets”Undeclared paths are unprotected. Most of a repo is ordinary code where a mistaken agent edit costs one git revert. Reserving zones for the places where that isn’t true — migrations, contracts, the enforcement code itself — keeps the false-positive rate near zero, and the false-positive rate is what decides whether a gate survives contact with a real team.
deny is for the irreversible. The schema zone above is closed because a dropped table is the one thing a revert can’t restore. Zones whose risk is “review it before it merges” use read-only or stay open and rely on the closing gate instead.
The file is the interface. No dashboard toggle, no per-session exceptions. Changing a boundary is a diff with an author and a reviewer, which is precisely the audit trail a boundary change deserves.
Which tool surfaces the hook models
Section titled “Which tool surfaces the hook models”A zone is only as good as the set of tools it is applied to, so this is worth stating plainly.
Four tools are modelled by name. Edit, Write and Read are judged on the path they declare; Bash is contained rather than classified — commands run against a git snapshot and anything that lands outside the open zones is reverted, byte for byte.
Everything else — every MCP server, every browser tool, the harness’s own control plane — is judged on the evidence the call carries about itself. There is no list of servers, because a list of servers goes stale the week after it is written. There are two signals:
- A path under a path-shaped key.
{"target": "apps/api/migrations/003.sql"}is judged exactly as aWriteto that file would be — same zone map, same grant.target,dest,destination,output_path,filenameand their siblings all count;prompt,title,contentandurlnever do. - A database statement under a statement-shaped key.
{"query": "drop table orders"}is refused while the schema zone is closed, because an MCPapply_migrationis neither Bash nor a declared path, and a dropped table is the one thing a revert cannot restore.
The statement has to be anchored — the value starts with the verb, or the verb follows a ; — and it has to read as a statement rather than a sentence. {"query": "how do I drop a table in D1?"} is a documentation search and passes. So does {"prompt": "fix the classifier in packages/hook/src/tools.ts"}: prose under a prose key is prose, whatever paths and verbs are in it. That boundary is the point — a gate whose false-positive rate is not near zero does not survive contact with a real team.
A call that carries no evidence is still allowed, and that is deliberate: reading documentation, driving a preview and filing a board record are legitimate, and most of what an agent does through these surfaces is exactly that. What changed is that it is no longer silent. Every unmodelled call is recorded as unwatched with the surface it came from, and one that named a path leaves a mutation event carrying that path — so the closing gate can see that something outside the matrix ran, instead of reporting a clean picture of a task whose real work happened somewhere it never looked.
cycle doctor prints a tool surfaces row saying which surfaces this repository has actually seen and how many of its recorded events came from calls the matrix does not model. It reports a warning while any of those surfaces is bound to nothing — an allow-by-default that nobody has accounted for is a warning, not health.
What a zone is not
Section titled “What a zone is not”Not a sandbox (the agent still runs on your machine), not a network policy, and not secrets management — gitignored paths inside a zone are a known open question from Phase 0: .env files are both gitignored and the archetypal secret, so secrets zones need a different mechanism than the git-snapshot containment everything else gets.