Zones

Name the paths that would hurt. Everything else stays open.

Most of a repository is safe for an agent to change. A few parts are not — the schema, the contracts, whatever your incident history says. A zone is how you say which is which, in a file you review like code, and it is the only thing CommitCycle actually enforces.

Four things, and one of them is a person

Path patterns say where. A risk level says how much care. A default policy says what happens when nothing has been granted. And an owner says who to ask — which is the attribute that turns a wall into a door.

  • Path patterns — the same glob shapes GitHub rulesets use, so nothing new to learn
  • Risk level — high, medium, low. High means the owner is asked before the work starts
  • Default policy — deny, read-only or open, applied when no grant names the zone
  • Owner — a real person, in a file, not in tribal memory
.zones/zones.yml · committed
# CommitCycle's own map, trimmed. Four zones in the real file, not thirty.
zones:
  - id: schema
    risk: high
    owner: paulo@commitcycle.com
    paths:
      - "apps/api/migrations/**"
      - "apps/api/src/db/schema/**"
    default_policy: deny

  - id: enforcement
    risk: high
    owner: paulo@commitcycle.com
    paths:
      - "packages/hook/**"
      - "packages/action/**"
    default_policy: deny

  - id: brand
    risk: medium
    default_policy: read-only

# Everything not listed here is unprotected, on purpose.

Access arrives as a grant, and leaves on its own

Moving a task to In Progress is what mints it. There is no command that opens a zone, so there is no back door to find — and nobody has to remember to close anything.

Bound to one task

It opens the zones that task declared, and nothing adjacent. The tempting neighbouring change is the one non-goals exist to name.

Bound to one branch

Two agents in one repository each answer to their own grant. This is the failure this product first hit itself, and the fix is recorded as D-43.

Expires in eight hours

A hundred micro-consents traded for one macro-consent with a clock on it. Per-call prompting is safety by fatigue.

Blocked14:02 · task CC-42

Write apps/api/migrations/0007_add_org_index.sql

Zone
schema · risk high
Task declared
api, web
Owner
paulo@commitcycle.com

The agent is told why in the same response that denies it, so it asks for access instead of trying a different way in. A block that only says no gets routed around.

Access requestwaiting · 2 min

CC-42 wants schema

Reason
The org index needs a migration
Scope
write · apps/api/migrations/**
Expires
4 hours after approval
Approve for 4hDeny

Just-in-time: the grant expires on its own. Nobody has to remember to close it, which is the step every access process actually fails at.

The blocking is commodity. The model underneath is not.

Worth saying before you find it out yourself: denying a tool call in flight ships in Claude Code, Codex, Cursor, Augment, Factory and Devin CLI, and it is free in whichever of those you are already using. If that were the product, you would not need this page.

What none of them has is the model the denial consults. Their rules are per-machine and permanent. There is no owner to ask, no approval moment, no expiry, and no notion of a task that permission could be scoped to.

Everyone's rules

A path list. Set once, true forever, the same for every piece of work, with nobody attached to it.

A zone plus a grant

Path × owner × risk × this task × this branch × eight hours, and a record of who opened it and why.

Against CODEOWNERS and branch rulesets the difference is when: same vocabulary, asked after the change exists, enforced on the host. A zone is checked at the write, on your laptop, offline — and CI still recomputes the whole diff afterwards.

What was measured, and what it does not prove

Every figure here carries its limit in the same breath. That is a house rule, not modesty.

  • 25/25 Bash escape vectors contained — shell writes run against a git snapshot and anything outside your zones is reverted byte-for-byte.The corpus was chosen by the author. The live false-positive eval has not run yet.
  • 0/20 false positives on that same guard.Same self-chosen corpus. Twenty commands is not twenty real tasks.
  • 8/20 false positives on the conservative allowlist — the approach we refused, and the reason containment won instead.A tool that blocks legitimate work gets uninstalled in week two. That was measured, not guessed.
  • 68–83 ms at p95 for the decision, against a 100 ms budget.p99 touched 102 ms in one case. The margin is thin and the levers are named.

Where zones stop

  • They confine each agent; they do not referee between them. Two agents that disagree still disagree — each is simply held to its own task and branch.
  • Unprotected is the default, and should be. An over-eager gate costs more than a missing one, so anything you do not declare is simply open.
  • Topics never gate. Zones enforce paths; the disciplines a task declares only advise. The two never merge.
  • The record outlives us. The map, the grants and the audit trail are files in your repository. Uninstall CommitCycle and you keep all of it.