barony 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- barony-0.5.1/.gitignore +6 -0
- barony-0.5.1/PKG-INFO +382 -0
- barony-0.5.1/README.md +365 -0
- barony-0.5.1/pyproject.toml +64 -0
- barony-0.5.1/scripts/sync_templates.py +62 -0
- barony-0.5.1/src/baron/__init__.py +10 -0
- barony-0.5.1/src/baron/cli.py +751 -0
- barony-0.5.1/src/baron/clock.py +40 -0
- barony-0.5.1/src/baron/data/capability-rules.v1.yaml +150 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/.github/workflows/lock-guard.yml +80 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/BOOTSTRAP-ADMIN.md +121 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/BOOTSTRAP.md +156 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/CLAUDE.md +36 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/CONVENTIONS.md +146 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/COORDINATION.md +201 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/ORCHESTRATE.md +87 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/PARTICIPATE.md +46 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/QUICKSTART.md +48 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/README.md +27 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/START.md +44 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/_failover-cron-sections/cloud-routine.md +23 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/_failover-cron-sections/gh-actions-cron.md +34 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/_failover-cron-sections/launchd-cron.md +28 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/_failover-cron-sections/systemd-timer.md +33 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/_handoff/README.md +38 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/_handoff/{{DATE}}-bootstrap-to-librarian-genesis.md +38 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/adapters/claude/HYDRATE.md +286 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/adapters/code-puppy/HYDRATE.md +251 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/adapters/generic/HYDRATE.md +181 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/adapters/pydantic-ai/HYDRATE.md +176 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__AUTONOMOUS_CRON__/AGENT.md +83 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__AUTONOMOUS_CRON__/persona.yaml +45 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__AUTONOMOUS_EVENT__/AGENT.md +88 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__AUTONOMOUS_EVENT__/persona.yaml +43 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__DEV__/AGENT.md +117 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__DEV__/persona.yaml +42 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__MERGER__/AGENT.md +49 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__MERGER__/persona.yaml +49 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__REVIEWER__/AGENT.md +49 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/__REVIEWER__/persona.yaml +50 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/librarian/AGENT.md +138 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/librarian/FAILOVER.md +104 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/agents/librarian/persona.yaml +47 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/decisions/README.md +56 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/findings/README.md +32 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/manifest.example.yaml +41 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/wiki/README.md +30 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/wiki/index.md +26 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/wiki/log.md +7 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/workspace-template/AGENTS.md +32 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/workspace-template/CLAUDE.md +30 -0
- barony-0.5.1/src/baron/data/templates/collab-repo/workspace-template/setup.sh +280 -0
- barony-0.5.1/src/baron/data/templates/references/capability-rules.md +52 -0
- barony-0.5.1/src/baron/data/templates/references/capability-vocab.v1.md +101 -0
- barony-0.5.1/src/baron/data/templates/references/manifest.schema.md +128 -0
- barony-0.5.1/src/baron/data/templates/references/persona.schema.md +132 -0
- barony-0.5.1/src/baron/forge/__init__.py +38 -0
- barony-0.5.1/src/baron/forge/base.py +64 -0
- barony-0.5.1/src/baron/forge/github.py +107 -0
- barony-0.5.1/src/baron/frontmatter.py +53 -0
- barony-0.5.1/src/baron/gitutil.py +117 -0
- barony-0.5.1/src/baron/guard.py +573 -0
- barony-0.5.1/src/baron/handoff.py +161 -0
- barony-0.5.1/src/baron/indexer.py +111 -0
- barony-0.5.1/src/baron/ledger.py +120 -0
- barony-0.5.1/src/baron/lock.py +184 -0
- barony-0.5.1/src/baron/rules.py +160 -0
- barony-0.5.1/src/baron/runtimes/__init__.py +54 -0
- barony-0.5.1/src/baron/runtimes/pydantic_ai.py +365 -0
- barony-0.5.1/src/baron/scaffold.py +742 -0
- barony-0.5.1/src/baron/schemas.py +179 -0
- barony-0.5.1/src/baron/status.py +319 -0
- barony-0.5.1/src/baron/templates.py +36 -0
- barony-0.5.1/src/baron/validate.py +268 -0
- barony-0.5.1/src/baron/waivers.py +148 -0
- barony-0.5.1/src/baron/worktree.py +194 -0
- barony-0.5.1/tests/conftest.py +96 -0
- barony-0.5.1/tests/test_cli.py +68 -0
- barony-0.5.1/tests/test_guard.py +409 -0
- barony-0.5.1/tests/test_handoff.py +71 -0
- barony-0.5.1/tests/test_indexer.py +63 -0
- barony-0.5.1/tests/test_ledger.py +117 -0
- barony-0.5.1/tests/test_lock.py +149 -0
- barony-0.5.1/tests/test_pydantic_ai.py +318 -0
- barony-0.5.1/tests/test_rules.py +100 -0
- barony-0.5.1/tests/test_scaffold.py +194 -0
- barony-0.5.1/tests/test_schemas.py +45 -0
- barony-0.5.1/tests/test_status.py +169 -0
- barony-0.5.1/tests/test_template_sync.py +68 -0
- barony-0.5.1/tests/test_validate.py +114 -0
- barony-0.5.1/tests/test_waivers.py +176 -0
- barony-0.5.1/tests/test_worktree.py +150 -0
- barony-0.5.1/uv.lock +659 -0
barony-0.5.1/.gitignore
ADDED
barony-0.5.1/PKG-INFO
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: barony
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: Git-native governance for teams of AI coding agents — the baron CLI over Barony's markdown/git collab substrate.
|
|
5
|
+
Project-URL: Homepage, https://github.com/vggg/barony
|
|
6
|
+
Project-URL: Repository, https://github.com/vggg/barony
|
|
7
|
+
Project-URL: Documentation, https://github.com/vggg/barony/blob/main/docs/concepts.md
|
|
8
|
+
Project-URL: Changelog, https://github.com/vggg/barony/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/vggg/barony/issues
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: pyyaml>=6.0
|
|
12
|
+
Requires-Dist: typer>=0.12
|
|
13
|
+
Provides-Extra: pydantic-ai
|
|
14
|
+
Requires-Dist: pydantic-ai-harness<0.11,>=0.10; extra == 'pydantic-ai'
|
|
15
|
+
Requires-Dist: pydantic-ai-slim<3,>=2.14.1; extra == 'pydantic-ai'
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# barony — git-native governance for teams of AI coding agents
|
|
19
|
+
|
|
20
|
+
> Install `barony`, run `baron`, import `baron`. Part of **Barony** —
|
|
21
|
+
> [github.com/vggg/barony](https://github.com/vggg/barony) — where the full
|
|
22
|
+
> framework, concepts, and adapters live. This page is the CLI reference.
|
|
23
|
+
|
|
24
|
+
`baron` is **Barony**'s CLI. It
|
|
25
|
+
turns the multi-agent coordination *conventions* that
|
|
26
|
+
Barony emits into *mechanisms*: a small CLI that scaffolds new projects
|
|
27
|
+
(`baron init`), validates the canonical specs, reports clone/branch/ledger
|
|
28
|
+
divergence, and performs the race-prone record-keeping operations
|
|
29
|
+
(finding/decision numbering, handoff lifecycle) safely.
|
|
30
|
+
|
|
31
|
+
**Design principle (ADR-003, `../docs/adr/ADR-003-baron-cli.md`): the
|
|
32
|
+
markdown/git substrate IS the database.** baron is a disciplined reader/writer
|
|
33
|
+
over the same human-legible collab-repo files the personas use
|
|
34
|
+
(`manifest.yaml`, `persona.yaml`, `findings/index.md`, `decisions/index.md`,
|
|
35
|
+
`_handoff/*.md`, `wiki/status.md`). It never introduces another store, and every
|
|
36
|
+
file it writes remains fully human/agent-legible.
|
|
37
|
+
|
|
38
|
+
Dependencies: **typer + pyyaml only**. `git` is driven via subprocess. `gh` is an
|
|
39
|
+
accepted prerequisite for forge features only (`baron lock`) — everything else
|
|
40
|
+
below works without `gh` installed. The pydantic-ai runtime adapter is an
|
|
41
|
+
**optional extra** (`barony[pydantic-ai]`, pinned) — see `baron hydrate` below.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
Once published to PyPI (distribution name `barony`):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv tool install barony # installs the `baron` console script
|
|
49
|
+
# or:
|
|
50
|
+
pip install barony
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Until then, install from a local clone:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# from the repo root, with uv:
|
|
57
|
+
uv tool install ./cli # installs the `baron` console script
|
|
58
|
+
uv tool install './cli[pydantic-ai]' # + the pydantic-ai runtime adapter
|
|
59
|
+
# or for development:
|
|
60
|
+
uv run --project cli baron --help
|
|
61
|
+
# or with plain pip (>= 3.10):
|
|
62
|
+
pip install ./cli
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quickstart
|
|
66
|
+
|
|
67
|
+
Verified end-to-end on a bare venv (`pip install` the wheel, no repo checkout):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
baron init gardenkit --dir gardenkit-collab --code-repo ./gardenkit \
|
|
71
|
+
--personas dev:fern,dev:moss,librarian:iris
|
|
72
|
+
cd gardenkit-collab
|
|
73
|
+
baron validate . # 0 errors
|
|
74
|
+
baron status # green when fresh
|
|
75
|
+
baron finding new --title "First finding" --author fern --no-push
|
|
76
|
+
HANDOFF=$(baron handoff create --for moss --from fern --title "Review the seam")
|
|
77
|
+
baron handoff close "$HANDOFF" --note "Done, see F1."
|
|
78
|
+
baron index # regenerates _handoff/README.md — commit it
|
|
79
|
+
baron worktree add fern # ../gardenkit-worktrees/fern, branch persona/fern
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Commands
|
|
83
|
+
|
|
84
|
+
### `baron init <project-name>` (ADR-006)
|
|
85
|
+
|
|
86
|
+
The deterministic, non-conversational scaffold — the mechanical subset of the
|
|
87
|
+
skill's `ORCHESTRATE.md` recipe.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
baron init gardenkit --dir gardenkit-collab --code-repo ./gardenkit \
|
|
91
|
+
--personas dev:fern,dev:moss,librarian:iris --runtime claude
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Flags: `--dir` (default `./<project-name>`), `--code-repo` (local path or git
|
|
95
|
+
URL, recorded in `manifest.yaml` with a relative path + `workspace.worktrees_root`),
|
|
96
|
+
`--personas archetype:slug,...` (archetypes: `dev`, `librarian`,
|
|
97
|
+
`autonomous-event`, `autonomous-cron`, `reviewer`, `merger`; a librarian is
|
|
98
|
+
appended when missing), `--runtime claude|generic|pydantic-ai|code-puppy`,
|
|
99
|
+
`--no-git`. Refuses a non-empty target directory.
|
|
100
|
+
|
|
101
|
+
Emits the canonical layout — `CONVENTIONS.md`/`COORDINATION.md` (filled),
|
|
102
|
+
`manifest.yaml`, `canon/` + `adapters/` copied verbatim from the **packaged
|
|
103
|
+
templates** (vendored from `skills/barony/assets/collab-repo/` per ADR-006;
|
|
104
|
+
drift-guarded byte-for-byte by `tests/test_template_sync.py`), hydrated
|
|
105
|
+
`agents/<slug>/persona.yaml` (identity `<slug>@<project>.local`, commit prefix,
|
|
106
|
+
routing label; generic edit-me scope), a genesis handoff, `findings/index.md` +
|
|
107
|
+
`decisions/index.md` ledger headers, the wiki stub, the lock-guard CI template,
|
|
108
|
+
and a per-persona **runtime kit** under `agents/<slug>/runtime/`:
|
|
109
|
+
|
|
110
|
+
| `--runtime` | Kit contents |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `claude` (default) | Tier-2 persona `CLAUDE.md` + `.claude/settings.json` wiring the `baron guard` PreToolUse hook |
|
|
113
|
+
| `generic`, `code-puppy` | Tier-1 `AGENTS.md` (instruction-only; code-puppy's documented fallback) |
|
|
114
|
+
| `pydantic-ai` | `agent_setup.py` bootstrap (running it needs `barony[pydantic-ai]`) |
|
|
115
|
+
|
|
116
|
+
The scaffold must pass `baron validate` with zero errors before init reports
|
|
117
|
+
success; then `git init -b main` + a first commit of exactly the files written
|
|
118
|
+
(never `git add -A`), unless `--no-git`. Dates come from the injectable clock.
|
|
119
|
+
Persona scope prose, `AGENT.md` manuals, and Tier-3 hydration (Claude
|
|
120
|
+
subagents, code-puppy JSON agents) stay on the conversational path — init
|
|
121
|
+
prints the pointers instead of pretending.
|
|
122
|
+
|
|
123
|
+
### `baron validate [PATH]` (M1)
|
|
124
|
+
|
|
125
|
+
Validate `persona.yaml` / `manifest.yaml` — a single file, or every one
|
|
126
|
+
discovered under `PATH`. Schemas are declarative Python data
|
|
127
|
+
(`src/baron/schemas.py`) formalized from the prose specs in
|
|
128
|
+
`../skills/barony/references/`; the FROZEN 10-verb capability
|
|
129
|
+
vocabulary is embedded and drift-guarded by a test that re-parses
|
|
130
|
+
`capability-vocab.v1.md`.
|
|
131
|
+
|
|
132
|
+
Checks: YAML parse, missing/unknown fields, types, verbs outside the vocabulary,
|
|
133
|
+
allow/deny overlap (including `write_path` scope overlap), unfilled
|
|
134
|
+
`{{PLACEHOLDER}}` tokens.
|
|
135
|
+
|
|
136
|
+
**Template rule:** directory discovery skips files whose path contains a
|
|
137
|
+
template marker directory (`assets/collab-repo/` or `legacy/`) — emit-time
|
|
138
|
+
templates legitimately carry placeholders and often aren't valid YAML at all.
|
|
139
|
+
Fixture paths (`tests/examples/`) are validated but exempt from the placeholder
|
|
140
|
+
check only. An explicitly named file is always validated.
|
|
141
|
+
|
|
142
|
+
Exit 0 = no errors (warnings allowed) / 1 = errors. `--json` for machines.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
baron validate tests/examples/tess/persona.yaml
|
|
146
|
+
baron validate . --json
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### `baron status [--fetch] [--sla N] [--json]` (M2)
|
|
150
|
+
|
|
151
|
+
Run from a collab repo (or `--collab PATH`). Reads `manifest.yaml` — including
|
|
152
|
+
the optional `workspace.clones` / `workspace.worktrees_root` fields (see
|
|
153
|
+
`../skills/barony/references/manifest.schema.md`) — and
|
|
154
|
+
reports, with severity:
|
|
155
|
+
|
|
156
|
+
| Check | Severity | Meaning |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `ahead` | red | commits never pushed to origin (stranded work) |
|
|
159
|
+
| `behind` | red | origin commits never pulled (stale canonical clone) |
|
|
160
|
+
| `unmerged-branch` | red | local branch not merged to origin default, with last-commit age |
|
|
161
|
+
| `handoff-overdue` | red | `status: open` handoff older than the SLA (default 14 days) |
|
|
162
|
+
| `dirty` | warn | uncommitted paths |
|
|
163
|
+
| `ledger-stale` | warn | newest F/D entry date older than the newest `docs/`/`src/` commit in the code repo (**heuristic**, labeled as such) |
|
|
164
|
+
| `wiki-stale` | warn | `wiki/status.md` `updated:` older than the newest finding entry |
|
|
165
|
+
|
|
166
|
+
Use `--fetch` to refresh each working copy's origin refs first — without it,
|
|
167
|
+
remote-side divergence (the `behind` class) is invisible. Exit 0 = green
|
|
168
|
+
(warnings allowed) / 1 = any red (CI-usable).
|
|
169
|
+
|
|
170
|
+
### `baron finding new` / `baron decision new` (M3)
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
baron finding new --title "Tracker-gated recall" --author carson
|
|
174
|
+
baron decision new --title "Adopt fps-aware segmentation" --author terrence --body-file body.md
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Parses the index for the max ID (both `### F<N>` headings and `| F<N> |` table
|
|
178
|
+
rows), allocates the next, appends a house-style entry
|
|
179
|
+
(`### F<N> — <title> (<date>, <author>)`), commits, and pushes. **On push
|
|
180
|
+
rejection** (someone else claimed the number first): roll back, `pull --rebase`,
|
|
181
|
+
re-parse, renumber, retry — bounded (`--retries`, default 3). git's push
|
|
182
|
+
atomicity is the lock; there is no other store. `--no-push` for offline work.
|
|
183
|
+
Dates come from a single injectable clock (`src/baron/clock.py`).
|
|
184
|
+
|
|
185
|
+
### `baron handoff create|close|list` (M3)
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
baron handoff create --for tess --from rex --title "Review the seam" --priority high
|
|
189
|
+
baron handoff close _handoff/2026-07-22-review-the-seam.md --note "Done, see F9."
|
|
190
|
+
baron handoff list --open
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`create` writes `_handoff/YYYY-MM-DD-<slug>.md` with the standard frontmatter
|
|
194
|
+
(`created` / `status: open` / `for` / `from` / `priority`). `close` flips
|
|
195
|
+
`status` to `done`, adds a `closed:` date and an optional blockquote note, then
|
|
196
|
+
`git mv`s the file to `_handoff/archive/YYYY/` — **archive, never delete**, with
|
|
197
|
+
history preserved. Status edits are textual so prose is never reflowed.
|
|
198
|
+
|
|
199
|
+
### `baron index` (M3)
|
|
200
|
+
|
|
201
|
+
Regenerates a marker-delimited summary block (`BEGIN/END BARON INDEX` HTML
|
|
202
|
+
comments) in `_handoff/README.md` (creating it if absent): open/done/archived
|
|
203
|
+
counts plus a table of open handoffs (file, for, from, age). Also verifies
|
|
204
|
+
finding/decision numbering: duplicates are errors (exit 1); gaps and
|
|
205
|
+
out-of-order headings are **report-only** warnings — baron never renumbers
|
|
206
|
+
history.
|
|
207
|
+
|
|
208
|
+
### `baron guard --persona-file <persona.yaml>` (M4)
|
|
209
|
+
|
|
210
|
+
Deterministic capability enforcement as a **Claude Code PreToolUse hook**
|
|
211
|
+
(ADR-004). Implements the documented hooks contract
|
|
212
|
+
(https://code.claude.com/docs/en/hooks — the canonical target of the old
|
|
213
|
+
docs.anthropic.com hooks URL): reads the hook JSON from stdin (`tool_name`,
|
|
214
|
+
`tool_input`, `cwd`), maps the call to the frozen v1 capability verbs, and
|
|
215
|
+
either stays silent (exit 0 — the normal permission flow applies) or blocks
|
|
216
|
+
(exit 2 with the reason on stderr, which the contract feeds to the model).
|
|
217
|
+
`--persona-file` may also come from env `BARON_PERSONA_FILE`.
|
|
218
|
+
|
|
219
|
+
What it decides:
|
|
220
|
+
|
|
221
|
+
- **Bash** — `git push` targeting the default branch → `push_main`;
|
|
222
|
+
`--force`/`-f`/`--force-with-lease`/`+refspec` → `force_push`;
|
|
223
|
+
`gh pr merge` → `merge_pr`; `git merge` while ON the default branch →
|
|
224
|
+
`push_main`. Parsing is **conservative**: an undeterminable push target
|
|
225
|
+
(e.g. bare `git push` outside a repo) is treated as the enforcement-relevant
|
|
226
|
+
verb and denied for personas lacking it, with stderr naming the inference;
|
|
227
|
+
personas holding the verb always pass. Non-git/gh commands pass — guard
|
|
228
|
+
governs capability verbs, not general shell.
|
|
229
|
+
- **Edit / Write / NotebookEdit** — `_handoff/` is universally writable;
|
|
230
|
+
`agents/<other-slug>/` needs `edit_other_personas` (a persona's own
|
|
231
|
+
`agents/<slug>/` dir is its own surface); denied `write_path` scopes always
|
|
232
|
+
block; otherwise `write_code` grants the write, and without it only the
|
|
233
|
+
persona's declared `write_path` scopes remain.
|
|
234
|
+
- **Unknown tools** — pass (a capability gate, not an allowlist).
|
|
235
|
+
|
|
236
|
+
**Policy source (since v0.3.0):** guard's rule table — the command patterns and
|
|
237
|
+
file-op scoping semantics above, plus the conservative-deny ambiguity policy —
|
|
238
|
+
is NOT hardcoded: it lives in the versioned artifact
|
|
239
|
+
`src/baron/data/capability-rules.v1.yaml` (package data, loaded by
|
|
240
|
+
`src/baron/rules.py`; `rules_version: 1`). It is THE single source for
|
|
241
|
+
enforcement rules; the pydantic-ai adapter below consumes the same table, so
|
|
242
|
+
decisions are identical across runtimes. A missing/unsupported artifact fails
|
|
243
|
+
CLOSED. Prose contract:
|
|
244
|
+
`../skills/barony/references/capability-rules.md`.
|
|
245
|
+
|
|
246
|
+
**Fail-closed but not brick:** unreadable persona file / malformed stdin →
|
|
247
|
+
DENY with actionable stderr. Escape hatch: `BARON_GUARD_OVERRIDE=<reason>`
|
|
248
|
+
allows the call BUT appends timestamp/tool/target/reason to
|
|
249
|
+
`.baron/guard-override.log` — a **tracked** file (deliberately not gitignored:
|
|
250
|
+
overrides are visible in diffs); each override is expected to become a
|
|
251
|
+
`_handoff/`. Wire-up (`.claude/settings.json`, matcher
|
|
252
|
+
`Bash|Edit|Write|NotebookEdit`): the Claude adapter's HYDRATE.md step 3c emits
|
|
253
|
+
it. Without baron installed the hook fails non-blocking and denials degrade to
|
|
254
|
+
instructed — honest degradation, never a bricked session.
|
|
255
|
+
|
|
256
|
+
### `baron lock claim|release|list` (M5)
|
|
257
|
+
|
|
258
|
+
PR-as-lock (ADR-002 §3), replacing the race-prone markdown LOCK-commit
|
|
259
|
+
protocol — **the open PR is the lock**, the forge's PR list is the only state.
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
baron lock claim contracts/models.py --reason "tightening the stage protocol"
|
|
263
|
+
baron lock list
|
|
264
|
+
baron lock release contracts/models.py
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`claim` creates branch `lock/<slug>` with one empty commit (via
|
|
268
|
+
`git commit-tree` — the local checkout is never touched; the empty commit is
|
|
269
|
+
load-bearing, GitHub refuses a PR whose head equals its base), opens a draft
|
|
270
|
+
PR titled `lock: <path>` labeled `lock:<path>` with the reason in the body,
|
|
271
|
+
and **refuses if an open lock PR for the path exists** (showing the holder).
|
|
272
|
+
`release` closes the lock PR and deletes the branch. `list` prints
|
|
273
|
+
path/holder/age/PR#. Requires `gh` (raises a clean `ForgeUnavailable`
|
|
274
|
+
otherwise); all forge calls go through the Forge Protocol, so tests run
|
|
275
|
+
against a fake. The CI side is the emitted
|
|
276
|
+
`.github/workflows/lock-guard.yml` template (bash + `gh`), which fails any
|
|
277
|
+
*other* PR touching a locked path.
|
|
278
|
+
|
|
279
|
+
### `baron worktree add|list|remove` (M6 tooling)
|
|
280
|
+
|
|
281
|
+
The branch-per-persona worktree topology (ADR-003 §2.7): one shared object
|
|
282
|
+
store, worktrees under the manifest's `workspace.worktrees_root`.
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
baron worktree add fern --collab . # <worktrees_root>/fern on branch persona/fern
|
|
286
|
+
baron worktree add fern --repo ../code --root ../worktrees # explicit paths
|
|
287
|
+
baron worktree list
|
|
288
|
+
baron worktree remove fern [--force]
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`add` creates `<root>/<persona>` on branch `persona/<persona>` (created from
|
|
292
|
+
the default branch if missing; an existing branch is reused). Defaults resolve
|
|
293
|
+
from the manifest (`workspace.worktrees_root`, `repos[role=code]`); `--root` /
|
|
294
|
+
`--repo` override. `list` shows each worktree's branch with ahead/behind vs
|
|
295
|
+
the default branch. `remove` refuses while the worktree is dirty or its branch
|
|
296
|
+
holds unmerged commits unless `--force` — and NEVER deletes the
|
|
297
|
+
`persona/<persona>` branch (removing a working copy must not destroy history).
|
|
298
|
+
`baron status` sweeps worktrees like clones (each reports its checked-out
|
|
299
|
+
HEAD's divergence; the repo-wide branch sweep runs once, on the shared repo).
|
|
300
|
+
Converting an existing clone-per-persona workspace:
|
|
301
|
+
`../docs/worktree-migration.md`.
|
|
302
|
+
|
|
303
|
+
### `baron waiver add|list` + `.baron-waivers.yaml`
|
|
304
|
+
|
|
305
|
+
Deliberately-parked `baron status` reds, with mandatory expiry.
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
baron waiver add "clone:rex *" --reason "kept for the vNext experiment" \
|
|
309
|
+
--handoff _handoff/2026-07-23-parked-branch.md --expires 2026-08-15
|
|
310
|
+
baron waiver list
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
`.baron-waivers.yaml` (collab root, human-legible, baron-managed via `waiver
|
|
314
|
+
add`) holds `{subject, reason, handoff, expires}` entries; `subject` is an
|
|
315
|
+
fnmatch pattern on the status SUBJECT column. A matching, unexpired waiver
|
|
316
|
+
downgrades a red to warn with `(waived: <reason>)` appended — parked work
|
|
317
|
+
stays visible, just not alarm-red. **Expiry keeps waivers honest:** an expired
|
|
318
|
+
waiver stops matching (the red resurfaces) and is itself reported as an
|
|
319
|
+
`expired-waiver` warn; malformed entries are reported, never silently dropped.
|
|
320
|
+
|
|
321
|
+
### `baron hydrate pydantic-ai --persona-file F [--out agent_setup.py]`
|
|
322
|
+
|
|
323
|
+
Emit a ready-to-edit bootstrap script hydrating one persona onto
|
|
324
|
+
**pydantic-ai** (the fourth runtime adapter,
|
|
325
|
+
`../skills/barony/assets/collab-repo/adapters/pydantic-ai/HYDRATE.md`).
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
baron hydrate pydantic-ai --persona-file agents/fern/persona.yaml --out agent_setup.py
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
The emitted script imports `baron.runtimes.pydantic_ai.build_agent` and
|
|
332
|
+
carries a model placeholder (`"test"` — pydantic-ai's offline TestModel —
|
|
333
|
+
until you pick a real model). Emission needs only baron; **running** it needs
|
|
334
|
+
the optional extra:
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
pip install 'barony[pydantic-ai]' # pins pydantic-ai-harness>=0.10,<0.11
|
|
338
|
+
# + pydantic-ai-slim>=2.14.1,<3
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
`build_agent(persona_file, collab_root=None, model=...)` returns a live
|
|
342
|
+
`pydantic_ai.Agent`: instructions composed from the persona spec; harness
|
|
343
|
+
`FileSystem` scoped per write verbs (natively read-only when the persona holds
|
|
344
|
+
no write verb); harness `Shell` only when a shell-granting verb is allowed
|
|
345
|
+
(with test runners denied when `run_tests` is denied); and an in-process guard
|
|
346
|
+
capability (`before_tool_execute` + `ModelRetry` veto — the documented
|
|
347
|
+
interception seam) consuming the same `capability-rules.v1.yaml` as
|
|
348
|
+
`baron guard`, which makes the five guard-covered sub-tool denials natively
|
|
349
|
+
**enforced** on this runtime. Without the extra, importing
|
|
350
|
+
`baron.runtimes.pydantic_ai` raises a clean ImportError with these install
|
|
351
|
+
instructions. Verified against pydantic-ai-harness 0.10.0 +
|
|
352
|
+
pydantic-ai-slim 2.16.0 (2026-07-23).
|
|
353
|
+
|
|
354
|
+
## Forges
|
|
355
|
+
|
|
356
|
+
`src/baron/forge/` holds a small `Protocol` (`base.py`) with one built-in
|
|
357
|
+
implementation, GitHub via `gh` subprocess (`github.py`) — first consumed by
|
|
358
|
+
`baron lock` (M5: `create_branch`, label-aware `open_pr`/`list_open_prs`,
|
|
359
|
+
`close_pr`). Other forges are plugins discovered through the `baron.forges`
|
|
360
|
+
entry-point group; GitLab is backlog — design sketch in `../docs/BACKLOG.md`.
|
|
361
|
+
|
|
362
|
+
## Development
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
uv run --project cli pytest cli/tests # from the repo root
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
The suite includes the capability-vocabulary drift guard, a synthetic divergent
|
|
369
|
+
git topology reproducing the 2026-07-22 triple-stranding incident classes, the
|
|
370
|
+
ledger push-rejection race test, subprocess-driven guard hook tests (synthetic
|
|
371
|
+
PreToolUse JSON on stdin), a recorded fake forge for the lock lifecycle, a real
|
|
372
|
+
two-persona worktree fixture, the waiver downgrade/expiry cases, the
|
|
373
|
+
capability-rules artifact tests (packaged + versioned, verb set ≡ the frozen
|
|
374
|
+
vocabulary, guard-consumes-the-data mutation test), and the pydantic-ai
|
|
375
|
+
adapter tests (offline TestModel/FunctionModel: capability omission, write
|
|
376
|
+
scoping, a scripted-and-vetoed `git push origin main`, the clean import-error
|
|
377
|
+
path), the `baron init` acceptance tests (layout + self-validation via the real
|
|
378
|
+
schemas + runtime kits + the non-empty-dir refusal), and the template drift
|
|
379
|
+
guard (`test_template_sync.py`: the vendored `src/baron/data/templates/` must
|
|
380
|
+
stay byte-identical to `skills/barony/assets/collab-repo/` — re-vendor with
|
|
381
|
+
`python cli/scripts/sync_templates.py`). The dev dependency group repeats the
|
|
382
|
+
pydantic-ai extra's pins so those tests run for real.
|