A governor is a device that sits on a powerful engine and keeps it from running away — restraint built into the mechanism. That is what guv adds to autonomous Claude Code sessions: a machine-readable project manifest, ceremony tiers, calibrated QA reviewers, deterministic safety hooks, a committed team-visible session record, and two-tier sandboxed isolation — native sandbox by default, Docker opt-in.
Installs as the versioned guv plugin from this repo's marketplace; cloning the repo as a template remains the fallback path.
Based on patterns from Anthropic's harness design research and Simon Willison's Agentic Engineering Patterns.
guv treats software engineering as a data engineering problem.
When a model writes the code, the code stops being the source. It is one of many codebases the model could have written from the spec: regenerate it and you get a different one, with different bugs. Git keeps the version that passed its checks because that is where verification is banked, not where truth lives. The truth is everything upstream of the code: what you asked for, what depends on what, what has been done, and what counts as good. Keeping that reliable is a pipeline problem, and data engineering already knows how to run pipelines on unreliable compute.
A model is not reliable the way a compiler is reliable, so guv divides the work accordingly: machines check, people decide. Anything that can be checked against the same standard every time gets built into the machinery. Everything that can't is a decision, and decisions stay with a person. The line between the two moves in one direction: once a decision becomes precise enough to check, it crosses over and does not come back.
The name says the rest. Watt's governor held an engine at the speed a person chose. Choosing the speed was never its job.
Claude Code is the platform — the runtime where the work happens. That work is the data plane, and it is the model's.
guv is a control plane for Claude Code: it decides what may run, holds what counts as good, and records what happened. guv governs the work and never touches it.
The core is the installed machinery — the manifest, rules, hooks, resolver, skills, and reviewers. Sync replaces the core.
The record is the governed state — plans, sessions, the cost ledger, the calibration record. Sync never touches the record.
A project's guv, named -guv, is one project's instance: the core plus the record. guv-guv is the instance where the governed project is guv itself.
Entry points — four ways in, scaled to the work:
/init <spec>— greenfield: generate phase docs + manifest, renderCLAUDE.md/onboard— adopt an existing repo: detect the stack, infer conventions, renderCLAUDE.md, no phase ceremony/task "<description>"— scoped change: understand → red/green TDD → evaluate → done/plan <spec>— multi-phase initiative on an existing project: archive the prior initiative, generate fresh phase docs with continuous numbering, flip ceremony tophased
Session workflow — commands that encode a Planner → Generator → Evaluator loop (phased projects):
/phase N— Phase-boundary entry: branch, deep-read, full context + spec-alignment, present a plan (crossing into a phase)/next— Light daily/mid-phase resume: read the resolver's ready-frontier and present the next pick with a plan, no boundary ritual/replan— Mutate the live plan through the one sanctioned door: classify, confirm, apply atomically with an amendment record/eval— Run the review gate on recent work mid-session/handoff— End session with review accounting + handoff artifact for continuity/status— Quick 10-line project orientation
Dynamic workflows — Saved workflows in .claude/workflows/ register as slash commands. The planning layer is the phase docs and the commands; the execution layer is the model, subagents, and — for wide mechanical fan-out — workflows you author per project (.claude/rules/guv-workflows.md: QA gates use the platform review plus the reviewer by name; ultracode is fan-out-only, dropped back after). None ship with guv — the build-fanout workflow retired at [32.3] in favor of native worktree agents, should evidence ever demand fan-out again.
Manifest-driven — .claude/project.json is the single source of truth for stack, commands, repo topology (roots), and ceremony. Hooks, commands, the sandbox, and the firewall all read from it, so there's nothing to drift. Behavioral rules live in .claude/rules/ (guv-*.md, loaded natively).
Repo topology — two shapes, chosen per project. Single-repo (roots both ".") is the default for internal apps, where plan and product share one tree and every root-aware operation collapses to a no-op. Split — a control plane plus a sibling code repo — is the default for standalone or publishable products: it keeps the plan, sessions, and governance (.claude/) cleanly separate from the shippable code, and the scaffold proactively proposes it for that class. A control plane can orchestrate N code repos through a named-map roots.code, each command self-locating into the right repo. In a split, Claude launches in the control plane and the product is a sibling repo. Convention: the code repo keeps the plain product name, the control plane is its sibling named per the <project>-guv convention (here <product>-guv — a possessive suffix, the product's guv; human-facing only, never used for discovery: the manifest is the sole machine pointer), and the manifest's name stays the product name (it feeds image/container labels):
~/dev/
├── <product>/ # code repo → roots.code: "../<product>"
└── <product>-guv/ # control plane (cwd) → roots.control: "."
Review gate — Technical review belongs to the platform (/code-review, session-invoked with an explicit target and level); guv adds the one dimension the platform cannot: the alignment reviewer subagent, which grades work against the spec, vision, and user experience — findings, not scores. It runs in its own context window, worktree-isolated, with read-only enforcement and per-project memory.
Two isolation tiers — Default: Claude Code's native sandbox (OS-enforced filesystem/network limits, zero Docker steps — recommended settings ship in .claude/settings.sandbox-example.json). Opt-in: a Docker sandbox with iptables firewall for full environment reproducibility, --dangerously-skip-permissions autonomy, or platforms without native support. Pick one tier per project — see Security Model.
Safety hooks — Deterministic enforcement of dangerous command blocking (bash-guard), auto-formatting (auto-format), and session reminder (stop-check).
Session continuity — Handoff artifacts and phase status tracking that carry context across sessions and context resets.
Default — the guv plugin (versioned; updates ride releases, see CHANGELOG.md):
claude plugin marketplace add ijpatter1/guv
claude plugin install guv@guv
# then, inside your project directory:
claude
/guv:scaffold # deploys the project shell: manifest scaffolding, rules, docs skeletons, .gitignore blockUnder a plugin install every guv command carries the guv: prefix —
/guv:init, /guv:status, /guv:handoff — and the reviewer agent
resolves as guv:reviewer. /guv:init is the canonical
form of the greenfield door (the short name was deliberately not re-picked):
in a source-clone install the bare /init shadows Claude Code's built-in
/init and is the documented non-canonical surface — under the plugin install
only the namespaced form resolves, so no shadowing occurs.
Fallback — template-clone (unversioned): for forks that customize core-owned
files (a plugin's surfaces aren't editable; a clone's are) or environments without
plugin support. Updates arrive via maintainers/setup-control-plane.sh --sync —
supported indefinitely, though new surface ships plugin-first.
Already on a template clone? The decided disposition: migrate to the plugin if you haven't customized core-owned files. In order:
- Install the plugin (marketplace add + install, as above).
- Delete the copied surfaces the plugin now supplies at runtime, so the two
copies don't double-load:
.claude/skills/,.claude/agents/,.claude/hooks/, the loose helper scripts (resolve-stack.shand friends), and guv-shipped workflows. If you've added files of your own inside those directories (a custom skill or agent), move them aside first — the directories have no ownership convention, so the deletion takes everything. - Remove the
hooksblock from.claude/settings.json— it registers the just-deleted hook scripts by path, so every tool call would invoke a missing file. The plugin's ownhooks.jsontakes over. This is a hand edit:/guv:scaffoldnever touches an existing settings file. - Keep everything else. Keep
.claude/rules/guv-*.mdin particular: rules load from the project, not from the plugin — the plugin only re-deploys them via/guv:scaffold— so deleting them strips the engineering-rules layer with nothing taking over. Your manifest (and its schema file), docs, feedback log, unprefixed rules, and consumer-saved workflows are consumer-owned and stay.
If you have customized core-owned surfaces, keep the clone — but update
deliberately: --sync replaces core-owned surfaces wholesale (commands,
skills, agents, hooks, settings, helper scripts — only unprefixed rules files and
consumer-saved workflows are ownership-protected), so a blind sync reverts exactly
the customizations this path exists for. Re-apply your edits after a sync, pull
upstream changes selectively, or move the customizations into consumer-owned
surfaces (unprefixed rules, your own workflows) and then migrate.
Click "Use this template" on GitHub, or:
git clone https://github.com/ijpatter1/guv.git my-project
cd my-project
rm -rf .git && git initThe fastest path — give Claude Code your spec:
# Start Claude Code (default tier; or `make sandbox` for the Docker tier)
claude
# or: make sandbox
# Point it at your PRD/spec
/init path/to/your-spec.mdThis reads your spec and generates the project-specific artifacts:
.claude/project.json— the manifest: language, package manager, commands, roots, ceremonyCLAUDE.md— rendered fromCLAUDE.template.md, holding only the facts Claude can't infer (behavioral rules load natively from.claude/rules/; it points at the manifest for commands)README.md— rendered fromREADME.template.mdinto a project-facing README (with a status block/handoffkeeps current), replacing this guv READMEdocs/REQUIREMENTS.md— phases and deliverables extracted from your specdocs/ARCHITECTURE.md— Phase 1 detailed architecture, later phases stubbeddocs/PHASE_STATUS.md— deliverable tracker matching REQUIREMENTS.md
The tracker has a rendered view: a single self-contained status.html (DAG of
deliverables, ready frontier ringed, blocked chains traceable) produced by
bash .claude/resolve-ready.sh docs/PHASE_STATUS.md --json > status.json
bash .claude/render-status.sh status.json > status.html— it opens from disk, and committing it as a derived artifact is permitted (the
optional views manifest entry declares it; rebuilt, never line-merged). Before
serving it with GitHub Pages, mind that Pages sites from private repos are
public on non-Enterprise plans.
For an existing codebase, run /onboard instead — it detects the stack, infers the repo's conventions, writes the manifest, and renders CLAUDE.md without imposing phase structure.
Don't run Claude Code's built-in
/initin a guv-governed repo. The built-in/initinlines commands intoCLAUDE.md, violating the manifest contract (.claude/project.jsonowns commands;CLAUDE.mdnever restates them)./onboardis guv's equivalent and supersedes it — and the built-in is distinct from guv's own/init, the greenfield door used above, whose bare surface shadows it in a source-clone install.
Review the generated files, adjust anything that needs it, then commit and start building.
The template ships no
CLAUDE.md— that's intentional.CLAUDE.mdauto-loads every session, so shipping one would govern the meta-work of using the template. Instead the repo ships the inertCLAUDE.template.md(never auto-loaded) plus the.claude/rules/behavioral core;/initor/onboardrendersCLAUDE.template.md→CLAUDE.md. Consumers must commit their renderedCLAUDE.md— it is deliberately not gitignored.
Manual alternative — render the template by hand:
- Copy
CLAUDE.template.mdtoCLAUDE.md(leave the template in place — it's the reusable source), then in the copy fill the project identity and the "Project facts Claude can't infer" section (for greenfield, keep "Bootstrapping") and strip the leading<!-- TEMPLATE … -->comment. Leave the manifest pointers as-is (rules load natively from.claude/rules/). - Copy
README.template.mdtoREADME.md(overwriting this guv README), fill the[bracketed]placeholders, keep the<!-- STATUS:START/END -->markers, and strip the<!-- TEMPLATE … -->comment. - Edit
.claude/project.jsonto declare your stack, commands,roots,guards, andceremony. - For phased projects, define
docs/REQUIREMENTS.md,docs/ARCHITECTURE.md, anddocs/PHASE_STATUS.md.
If you opt into the Docker tier, also update:
Makefile— ChangeIMAGE_NAMEandCONTAINER_NAMEat the top (two lines). The sandbox base image is derived from the manifest'slanguage; override withmake build BASE_IMAGE=.... (Default-tier projects can skip this — the Makefile is only used bymake sandboxand friends.)
Optionally customize:
sandbox/init-firewall.sh— Add project-specific domains toPROJECT_DOMAINS(the package registry is selected automatically from the manifest'slanguage)..claude/project.json— Add stack-specificguards(e.g."gcp","cargo-publish"); the universal danger blocks are always on. Permissions in.claude/settings.jsonare now a broad convenience layer, not a per-project edit point.
echo 'export ANTHROPIC_API_KEY=sk-ant-...' >> ~/.zshrc
source ~/.zshrc# Option A (default tier): native Claude Code + native sandbox
# (enable via .claude/settings.sandbox-example.json or /sandbox in-session;
# Linux/WSL2: install bubblewrap + socat first — see Security Model below)
claude
# Option B (opt-in tier): Docker sandbox — reproducible env,
# --dangerously-skip-permissions autonomy, or no native sandbox support
make sandboxThen inside Claude Code:
/phase 1
# Terminal 1: Claude Code (or `make sandbox` for the Docker tier)
claude
# /next (or /phase N when crossing into a new phase)
# Terminal 2: Dev server on the host
make dev
# Terminal 3: Your tools (VS Code, git, tests)
code .├── CLAUDE.template.md # Inert source for CLAUDE.md (rendered, not auto-loaded)
├── README.template.md # Inert source for the PROJECT README (rendered on scaffold/onboard)
├── CHANGELOG.md # Plugin release notes (a version bump IS a release)
├── Makefile # Container lifecycle (base image from manifest)
├── .gitignore # Git exclusions
├── .claude-plugin/
│ └── marketplace.json # Public marketplace serving plugin/ (distribution machinery —
│ # template-clone forks can delete it along with plugin/)
├── .claude/
│ ├── project.json # MANIFEST — single source of truth (stack/commands/roots/ceremony)
│ ├── project.schema.json # Manifest schema (validation + self-docs)
│ ├── rules/ # Behavioral core (guv-*.md core-owned; unprefixed = yours)
│ ├── resolve-stack.sh # Detect-to-propose stack manifest (onboard/init)
│ ├── resolve-ready.sh # Deterministic ready-frontier resolver (DAG tracker)
│ ├── render-status.sh # Renders status.json as one self-contained status.html (a view, never a source)
│ ├── replan.sh # /replan's deterministic engine (guards, ordinals, atomic writes)
│ ├── update-readme-status.sh # Maintains the README STATUS block in place
│ ├── archive-initiative.sh # Freeze a finished initiative's phase docs (plan)
│ ├── guv-git.sh # Git against roots.code, once (the retired inline incantation)
│ ├── guv-cmd.sh # Manifest command + loud null-skip, once
│ ├── settings.json # Permissions (convenience layer) + hooks
│ ├── settings.sandbox-example.json # Recommended native-sandbox fragment (default tier)
│ ├── settings.local.json # Personal overrides (gitignored)
│ ├── agents/
│ │ └── reviewer.md # Alignment reviewer subagent
│ ├── hooks/
│ │ ├── bash-guard.sh # Blocks dangerous commands (universal + opt-in guards)
│ │ ├── auto-format.sh # Formats on write (formatter from manifest)
│ │ └── stop-check.sh # Reminds about evaluation
│ ├── skills/ # All process verbs are skills (commands flattened in at [8.3])
│ │ ├── task/ # /task — scoped change entry point
│ │ ├── next/ # /next — light daily/mid-phase re-entry (resolver frontier)
│ │ ├── phase/ # /phase — phase-boundary entry (full ritual + spec alignment)
│ │ ├── plan/ # /plan — phased initiative on an existing project
│ │ ├── init/ # /init — greenfield: scaffold + render CLAUDE.md
│ │ ├── onboard/ # /onboard — adopt an existing repo (no phase ceremony)
│ │ ├── replan/ # /replan — plan mutation: the one sanctioned door (engine: replan.sh)
│ │ ├── eval/ # /eval — the review gate
│ │ ├── feedback/ # /feedback — record guv friction
│ │ ├── handoff/ # /handoff — session end + review accounting
│ │ ├── status/ # /status — quick status check
│ │ ├── manual/ # /manual — out-of-sandbox task artifacts
│ │ ├── phase-docs/ # Shared phase-doc templates (init + plan)
│ │ └── session-management/ # Context continuity conventions
│ ├── tests/ # Bash test suites for the guv scripts/skills
│ └── feedback/ # guv-friction log — local-only, never phones home (submit is opt-in; created on first /feedback)
├── maintainers/ # Maintainer-only — developing guv (consumers can delete)
│ ├── DOGFOODING.md # How to dogfood guv via a control-plane split
│ ├── RELEASING.md # Release flow: bump policy, checklist, feedback drain
│ ├── setup-control-plane.sh # Scaffold/sync a dogfooding control plane (also the
│ │ # template-clone fallback's --sync update path)
│ ├── build-plugin.sh # Generates plugin/ from .claude/ + plugin-src/ (Phase 5)
│ ├── render-smoke.js # Dev-only DOM-stub execution check for render-status.sh's in-page JS
│ └── plugin-src/ # Authored plugin-only sources (manifest, hooks.json, guv-only skills)
├── plugin/ # GENERATED — the RELEASE ARTIFACT the marketplace serves.
│ # Never hand-edit; rebuilt by the release flow only
│ # (maintainers/RELEASING.md), so between releases it holds
│ # the last release and source legitimately runs ahead of it.
├── docs/
│ ├── REQUIREMENTS.md # Development plan (phased; YOU EDIT THIS)
│ ├── ARCHITECTURE.md # Technical architecture (phased; YOU EDIT THIS)
│ ├── PHASE_STATUS.md # Phase tracker (phased; YOU EDIT THIS)
│ └── sessions/
│ └── .gitkeep
└── sandbox/ # Docker isolation tier (opt-in; default is native)
├── Dockerfile # Sandbox image (BASE_IMAGE build arg)
├── init-firewall.sh # Per-language registry allowlist firewall
├── entrypoint.sh # Privilege drop + Claude start
└── README.md # Sandbox documentation
A rendered
CLAUDE.md(the live file) and.claude/project.jsonare created/filled per project by/initor/onboard. The template repo ships noCLAUDE.md.
The durable core — the guv-* rules in .claude/rules/, the manifest, the reviewer, the universal hooks — is never edited per project. The project shell — the rendered CLAUDE.md, the manifest's values, phase docs (YOU EDIT THIS), and stack-specific guards/firewall additions — is filled per project. Same core, different shell.
Isolation is three layers with distinct jobs:
- Native sandbox — the spatial boundary (default tier). OS-enforced limits (macOS
Seatbelt; bubblewrap on Linux/WSL2) on every Bash command and its child processes:
writes confined to the working directory, network confined to allowlisted domains.
Enable it with the shipped fragment
.claude/settings.sandbox-example.json— copy itssandboxblock into.claude/settings.json, or run/sandboxin-session. The fragment's starter domain allowlist mirrors the firewall's core set (Anthropic + GitHub) and its comments carry the per-language registry table for your stack. macOS needs nothing installed; on Linux/WSL2 installbubblewrapandsocatfirst (see the official sandboxing docs). - bash-guard — the semantic boundary within it. The native sandbox permits writes
anywhere in the working directory, so destructive patterns inside the boundary —
rm -rf ., hard resets, publishes — remain bash-guard's job in both tiers (deterministic PreToolUse hook; universal blocks plus manifest-keyed optional guards). - Permissions — the convenience layer. The allow/deny rules in
.claude/settings.jsondecide what runs without prompting. They reduce friction; they are not the enforcement boundary.
The Docker sandbox (make sandbox) is the opt-in tier that replaces layer 1 with
a container + iptables firewall — see sandbox/README.md for when
to choose it. Pick one tier per project: running the native sandbox inside the
container requires a weakened mode (enableWeakerNestedSandbox) and should not be
combined.
If your project uses Google Cloud:
make gcp-setup # Prints step-by-step instructions| Command | Description |
|---|---|
make sandbox |
Build + start Claude Code in Docker |
make attach |
Reattach to running sandbox after crash |
make shell |
Bash shell in sandbox for debugging |
make prompt P="..." |
Run a one-shot headless prompt |
make resume S="name" |
Resume a named session |
make dev |
Run dev server on host |
make stop |
Stop the sandbox container |
make clean |
Remove container + image (keeps volumes) |
make clean-all |
Full reset including auth and sessions |
make gcp-setup |
Print GCP service account instructions |
make test-fw |
Verify firewall blocks correctly |
This environment encodes three key patterns:
-
Separated evaluation (from Anthropic's harness research) — Review runs outside the authoring context: the platform review gate plus the alignment reviewer subagent in its own read-only context, preventing the self-praise problem where agents rate their own work too generously.
-
Test-first anchoring (from Simon Willison's Agentic Engineering Patterns) — Every session starts by running the test suite. Every feature uses red/green TDD. Tests are the regression safety net across phases.
-
Structured handoffs (from both sources) — Session artifacts carry enough context for a clean restart, avoiding the quality degradation that comes from context window growth and compaction.
The guv plugin ships its consumer-meaningful test suites alongside a layout-reconstructing runner, so you can verify an install actually resolves and exercises the plugin's own script bytes (not a source checkout). From the plugin install directory:
bash tests/run-plugin-tests.shThe runner rebuilds a .claude/-shaped tree from the flattened scripts/
(scripts at the top level, hooks recovered into hooks/ from hooks.json, the
shipped suites in tests/) and runs every shipped suite against it. A green run
means the location-relative guv suites resolve and pass in plugin layout; a
suite that cannot find its script turns the run red and names the offender.
To run a single suite — say, while chasing one failure — filter by basename
glob: bash tests/run-plugin-tests.sh --only 'resolve-ready*'. The rebuild is
always complete (the filter gates which suites run, not what is placed), and
a pattern that matches no shipped suite fails loud (exit 2, naming the pattern)
rather than reporting a vacuous green.