Git-native governance for teams of AI coding agents: who may do what, who did what, what's true now — enforced by mechanism, measured by audit, on any runtime.
New here? Read
docs/user-guide.md. It takes a first-time user from install to a scaffolded project with the guard wired, proved bybaron doctor, and a real capability denial on screen — about fifteen minutes of reading. Every command in it was run; every output is real.
Running several AI coding agents on one long-lived project needs three separate things, which are routinely confused:
| Layer | Answers | What you'd use |
|---|---|---|
| Coordination | Who may do what · who did what · what is true now | Barony |
| Per-agent runtime | How one agent thinks and calls tools | Claude Code, code-puppy, a pydantic-ai harness |
| Control plane | Where agents run; routing, deploy, scheduling, secrets | something else |
Barony is the first row only. It is a spec, a CLI (baron), and per-runtime
adapters. Each persona is declared once in a runtime-neutral persona.yaml and
hydrated onto whatever runtime you have, at the highest enforcement fidelity
that runtime supports. The default substrate is plain markdown + git, and it is
the only one baron itself uses: no server, no database, nothing you or your
agents can't read with cat.
It is not a runtime, a control plane, or an agent framework. There is no scheduler, message bus, or agent-to-agent RPC — coordination happens at git tempo, which is the point: every coordination event leaves a reviewable record. It is also not an adversarial sandbox; it stops a cooperating agent from doing the wrong thing, not a hostile one with shell access.
What it costs you: a second repo (the collab repo) alongside your code repo,
a persona.yaml per agent, and the discipline of routing material work through
handoffs and ledgers. Plus one hook wired into each working copy, which
baron doctor will nag you about until you do it.
Skip it if you run one agent on one-shot tasks with no state that has to outlive the session. A plain session is simpler and this is real overhead.
Run several agent sessions on one project for a few weeks and these show up. Each receipt is first-party — from Barony's own pilot projects and audits, recorded in the ADRs:
- State chaos. On 2026-07-22 an estate-wide assessment of a pilot found its
two most recent results stranded three different ways at once — commits never
pushed, a pushed branch never merged, and the canonical clone never pulled —
leaving the status board stale for a week (ADR-003 §1).
baron statusturns each stranding class into a red exit code you can put in CI. - Enforcement theater. Rules that live in prose decay: a first-party audit of
a real multi-agent project measured operational fidelity 0.53 — roughly half
the documented coordination protocol was actually being followed (ADR-003 §1).
Barony labels every capability denial honestly as enforced or merely
instructed, and
baron guardblocks denied actions before the tool runs where the runtime allows it. - Knowledge rot. On the same pilot, 18 of 40 handoffs sat
status: openfor weeks, and finding numbers collided three separate times because allocation was a rule, not a mechanism (ADR-002 §2). Barony gives ledgers race-safe numbering (git push atomicity is the lock) and handoffs an SLA plus an archive-not-delete lifecycle. - Accountability vacuum. All personas commit under one human GitHub account, so the platform is structurally blind to who did what, and self-approval is refused outright (verified live; ADR-002 §1/§4). Barony moves accountability into the substrate: persona commit prefixes, SHA-sealed review verdicts (signets), and a read-only audit that measures the intervention tax.
The distinction the whole thing turns on, and the one baron prints at you:
enforced — baron mechanises it. Something inspects the pending call and refuses it before the tool runs.
instructed — it is declared in a file the persona reads, and nothing checks.
Both are legitimate; only one is a control. Calling an instruction "enforcement"
is the failure this product exists to catch, so baron refuses to round up and
CI fails an adapter that claims enforcement it cannot deliver. Six of the ten
capability verbs label enforced; the other four are instructions —
open_pr and run_tests because guard does not parse for them, read_code and
read_collab because baron emits no mechanism that would omit the read
tools, measured once per shipped adapter. baron rules list prints the table
with the measurements attached.
Requires Python ≥ 3.10 and git. Verified end to end from a clean virtualenv — 2.4 seconds of machine time, install included.
uv tool install barony # or: pip install barony (live on PyPI)
# The code repo you want to govern (skip if you already have one):
mkdir gardenkit && git -C gardenkit init -b main -q && \
git -C gardenkit commit --allow-empty -m "init" -q
# Scaffold a collab repo next to it — two devs + a librarian:
baron init gardenkit --dir gardenkit-collab --code-repo ./gardenkit \
--personas dev:fern,dev:moss,librarian:iris
cd gardenkit-collab
baron validate . # canonical specs — expect 0 errors
baron status # divergence/staleness — green when fresh
baron rules list # what the guard enforces, honestly labelled
# First coordination moves:
baron finding new --title "First finding" --author fern --no-push
HANDOFF=$(baron handoff create --for moss --from fern --title "Review the seam")
baron handoff close "$HANDOFF" --note "Done, see F1."
baron index # regenerates _handoff/README.md — commit it
# Per-persona working copies (worktrees of the code repo above):
baron worktree add fern # ../gardenkit-worktrees/fern, branch persona/fern
# Install fern's runtime kit where the runtime reads it, then PROVE it:
cp -R agents/fern/runtime/.claude ../gardenkit/
cp agents/fern/runtime/CLAUDE.md ../gardenkit/
baron doctor --dir ../gardenkit # guard wiring self-test — exit 1 if the hook is missing
# Deploy fern as a sidecar — sync, sweep her handoffs + labelled backlog, run one
# unit of work, commit and push. `baron init` emitted the launcher (ADR-026):
./agents/fern/sidecar.sh --dry-run # the plan and the brief, nothing invokedDrop --no-push once the collab repo has an origin remote. Generating a
runtime kit is not installing it — skipping the cp is how the
badminton-analyzer incident merged 15 PRs under a persona that was denied
merge_pr, silently. baron doctor exists so that skipping it is loud; it
verifies wiring, not invocation (ADR-017), and a green doctor means
"correctly wired", never "enforcement happened".
One collab repo per project is the default, and stays it — it is what buys
multi-tenant isolation (different access per project) and an independent
lifecycle. For a single owner running several fleets that default buys mostly
repo sprawl and no cross-project view, so --layout monorepo
(ADR-025) emits the other topology:
one collab repo whose projects are subdirs, each with its own manifest.yaml,
agents/, _handoff/, decisions/, findings/ and wiki/.
baron init fleet-coordination --layout monorepo # root + the `_meta` project
cd fleet-coordination
baron add-project gardenkit --code-repo ../gardenkit --personas dev:fern,librarian:iris
baron add-project badminton --code-repo git@github.com:you/badminton.git
baron status # PORTFOLIO-wide: every project, then a portfolio total
baron health # same, rolled up
baron validate . # every project's specs in one pass
cd gardenkit/ # inside a project, every command behaves exactly as above_meta/ is the portfolio project: no code repo, its work items are the
cross-project decisions. The recursion is the point — the portfolio is a project
that coordinates projects, governed by the same primitives one level up.
What it costs, stated: access is all-or-nothing (a monorepo cannot grant
per-project access), so this is a mode, not a replacement. Code repos stay
separate and per-project; only the coordination substrate is unified. CI lives
once at the root, and the wake (repository_dispatch) carries the project so the
gate resolves the handoff inside that subdir and nothing else.
The user guide walks all of that with real output,
including a live guard denial and the failure modes. Full command reference:
cli/README.md. The conversational setup path (an agent
interviews you, then scaffolds) routes through
skills/barony/assets/collab-repo/START.md — see
docs/concepts.md.
See a real one: vggg/barony-demo is
a seeded example — a week of a fictional project's findings, decisions, handoffs
(closed and open), a waiver, and a captured live guard refusal. The project is
fictional; every artifact was produced by the real tools.
One persona.yaml, four adapters, as claimed by each adapter's machine-readable
capability map (checked in CI by tests/bi_runtime_accept.py):
| Runtime | Tier | Whole-tool denials³ | Guard-covered sub-tool denials¹ | open_pr / run_tests |
|---|---|---|---|---|
| Claude Code | 3 (native subagents) or 2 (CLAUDE.md) |
write_code enforced-with-baron; read verbs instructed as shipped, enforced at Tier 3 |
enforced-with-baron (instructed otherwise) | instructed |
| pydantic-ai | 3 (in-process hydration) | write_code enforced (in-process guard); read verbs instructed — measured |
enforced (in-process interception — the hook cannot be absent) | instructed |
| code-puppy | 2.75 (native JSON agents)² | instructed as shipped; enforced at Tier 3, which is hand-authored | instructed (guard does not run here) | instructed |
| generic (any runtime) | 1 (in-prompt + AGENTS.md) |
instructed | instructed | instructed |
¹ The five denials the shared rules artifact (capability-rules.v1.yaml)
covers: push_main, force_push, merge_pr, write_path scoping,
edit_other_personas. Every enforcing consumer loads that same artifact, so
git push origin main is judged identically across runtimes. A persona runs at
the highest tier its runtime supports and degrades gracefully, with the honesty
label degrading alongside. Note baron init does not reach Tier 3 on any
runtime — it emits Tier 2 on Claude and Tier 1 elsewhere; Tier 3 needs the
in-session recipe in adapters/<runtime>/HYDRATE.md.
² code-puppy enforces whole-tool denials natively (JSON agent allow-list) but
its sub-tool denials stay instruction-only — a partial Tier 3, which its own
adapter labels "2.75" rather than round up. The allow-list is the runtime's
capability, not baron's output: baron init --runtime code-puppy emits a Tier-1
AGENTS.md that says of itself "nothing is enforced", and baron guard never
runs on code-puppy — it has no pre-tool seam and is deliberately absent from
guard.KNOWN_RUNTIMES. See
USING-WITH-CODE-PUPPY.md.
³ The whole-tool class is read_code, read_collab and write_code. They do
not share a fate, so the cells name them separately. write_code has file-op
detection and is adjudicated by baron guard wherever guard runs. The two read
verbs are the honest bound: baron emits no mechanism capable of omitting the
read tools — measured once per shipped adapter, including a live test that a
persona denying read_code keeps its read tools under the emitted pydantic-ai
bootstrap, which builds FileSystem unconditionally
(ADR-020).
The bound is exact: baron emits no mechanism, not that a runtime cannot
enforce these verbs — a hand-authored Tier-3 allow-list does. That is why the
claude and code-puppy HYDRATE.md tables print enforced for the read
verbs while baron rules list prints instructed: they describe a
hand-authored artifact, rules list describes what baron ships. The divergence
is recorded, not rounded away (ADR-020 §7).
Full list with what each means for you:
user guide §9, drawn from
docs/DECISIONS-FOR-REVIEW.md §E. The headline
five:
- No test drives a real Claude Code process against a scaffolded repo. Enforcement is proven by wiring, not by invocation.
- The
bash -c '…'guard bypass stands and is documented on purpose. Static parsing does not recurse into an inline program string. .baron/rules.yamlis parsed but never activated.baron rules validate --filechecks a candidate; baron still loads only the packaged artifact.baron doctorreads project-level settings only. A hook in~/.claude/settings.jsonis invisible to it.- Runtime neutrality is proved with two producers, not three. Claude Code and pydantic-ai emit into the same plane in the same wire shape. That falsifies "the plane is Claude-Code-shaped"; it is not proof the shape fits every runtime. code-puppy has no pre-tool seam and emits nothing.
Active development, not a finished product. Two version numbers, on purpose:
the plugin/skill version lives in .claude-plugin/plugin.json and the skill
frontmatter (currently 1.10.0, sync enforced by lint); the CLI package
version is separate (baron --version). See STATUS.md for
progress and CHANGELOG.md for release history.
- docs/user-guide.md — start here.
- docs/product-overview.md — the evaluator's page: the problem from first-party incidents, the git-native thesis, every capability in a paragraph, and the bounds stated in line rather than in a footnote.
- docs/capability-value-map.md — each capability → the outcome it delivers → the metric it moves, with how it's measured and whether anyone has measured it yet.
- docs/concepts.md — every concept at paragraph length:
emitted layout, capability + honesty ladders, adapters, PR-locks, signets,
worktree topology, the
baronsurface. - docs/adr/ — why, argued rather than asserted. ADR-001 (runtime-agnostic architecture) through ADR-022 (what a plugin may and may not be authoritative for).
- docs/DECISIONS-FOR-REVIEW.md — the current consolidation: decisions, §E honest bounds, §F deliberate non-goals.
cli/README.md— fullbaroncommand reference.skills/multi-agent-audit/— the read-only sister skill that grades any multi-agent project (not just Barony). Headline metric: the intervention tax, human touches per autonomous task.- docs/history.md — how a Claude-Code-only scaffolding skill became runtime-agnostic governance.
CONTRIBUTING.md— PR conventions, including the docs-land-with-code rule.- Installing as a Claude Code plugin:
/plugin install https://github.com/vggg/barony(or a local clone path). On code-puppy, invoke the neutral files by path — seeUSING-WITH-CODE-PUPPY.md.
Formerly
agent-project-bootstrap; renamed at v1.7.0 (ADR-005). Old GitHub URLs redirect.
MIT License · vggg