Skip to content
Back to skills

Verify Brigade

BSecurity

Prove a Brigade change works by driving the real `brigade` CLI against a throwaway temp target, then capture receipts as evidence. Use when you changed anything under src/brigade/ and need proof beyond pytest - init/doctor wiring, work-verify receipts, Grok Bot connector packs, feed manifests, handoff lint. Also use before claiming a CLI behavior in a PR body, handoff, or job report.

  • 73 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 6, 2026
ai-agentspythonrustgoshellbashnodegitsecurity

Works with

  • cli
  • mcp

Security analysis

B81/100
  • highPerforms destructive filesystem operations
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 8 files and shows the line behind each finding

Scanned October 6, 2026

npx -y skills add escoffier-labs/brigade --skill verify-brigade --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Verify Brigade?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Verify Brigade
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/escoffier-labs-verify-brigade/badge)](https://www.skillsdirectory.com/skills/escoffier-labs-verify-brigade)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: verify-brigade
description: "Prove a Brigade change works by driving the real `brigade` CLI against a throwaway temp target, then capture receipts as evidence. Use when you changed anything under src/brigade/ and need proof beyond pytest - init/doctor wiring, work-verify receipts, Grok Bot connector packs, feed manifests, handoff lint. Also use before claiming a CLI behavior in a PR body, handoff, or job report."
---

# Verify Brigade

Brigade has no server and no UI. The surface a user touches is the `brigade`
CLI, and the only honest way to prove a change is to run that CLI against a
target and read what it wrote. This skill drives it through one helper,
`control-brigade.py`, so a proof is a rerunnable command instead of a story.

Every drive happens in a temp target this skill creates. The helper enforces
that: `--target` is accepted only when it resolves *under* `<state-root>/targets`,
so the operator home, the Brigade checkout, and every other path are refused
before a command runs. The state root gets the same treatment whether it comes
from `--root` or from the default - resolved, refused if it resolves to or
contains the home directory or the checkout, and refused if it is a symlink at
the root or at `targets/`/`captures/`, so a link planted in a world-writable
temp dir cannot redirect a drive. `cleanup` removes only paths `new-target`
recorded. `AGENTS.md` forbids driving the real workspace anyway; here it is not
reachable.

What that paragraph does *not* claim:

- A path under the temp base is allowed even when `$TMPDIR` sits inside the
  home directory. That is the only carve-out, and it is exactly that narrow:
  the home and checkout refusals run *first*, so the allowance applies only
  when the temp base itself resolves inside the home directory and outside the
  checkout. A `$TMPDIR` inside the checkout is still refused, and a relative
  `$TMPDIR` is refused outright rather than resolved against the working
  directory. The temp base itself is refused - a state root there would chmod
  the shared scratch tree to `0700`.
- The default evidence root is `<checkout>/.brigade/verification-evidence`,
  which is inside the checkout. That is the one deliberate exception: it is
  gitignored, and it sits outside the state root on purpose so `cleanup` cannot
  reach the proof. The default and `--evidence-root` are both guarded like
  `--root`, symlink check included: a link planted at either is refused, not
  followed. `--label` names the directory under that root, so it must be a
  simple `[A-Za-z0-9._-]` name of 1-64 characters - no separators, no `..`.
- `grokbot-feed --manifest` is the one flag outside the target contract. It is
  a caller-supplied path, read for validation only and never written, so an
  operator can validate a real private feed manifest from wherever it lives.
  Everything the drive *writes* still lands in the target or the state root.

## Launch

There is no long-running process. "Launch" means: have a Brigade CLI, and have
a fresh target to drive it against.

```bash
# fresh checkout (this repo). Quote the extras so the shell does not glob them.
python3 -m venv .venv
.venv/bin/pip install -e ".[dev,grokbot]"
```

Observed on this checkout: that install printed
`Successfully installed ... brigade-cli-0.27.0 ... mcp-2.1.1 ...`, and
`.venv/bin/brigade --version` then printed `brigade 0.27.0`. The `grokbot`
extra pulls the optional `mcp` package (`pyproject.toml`:
`grokbot = ["mcp>=2,<3"]`). The `[dev]` extra alone is enough for pytest /
ruff / mypy; add `grokbot` when the change touches the listener.

Create the target:

```bash
registry/skills/verify-brigade/control-brigade.py new-target
```

That prints one JSON object. It ran `git init -q -b main` and
`brigade init --depth workspace --harnesses claude,codex` in a new directory
under the state root (`$TMPDIR/verify-brigade/targets/<stamp>-<rand>`), and
recorded the path so `cleanup` can find it later. Ready is
`"ok": true` plus the `"target"` path; export it:

```bash
TARGET=$(registry/skills/verify-brigade/control-brigade.py new-target \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["target"])')
```

`new-target` records the path before it runs `brigade init`, so `cleanup` can
reclaim it even when that init fails; a failed init also removes the directory
it made. `--dry-run` prints the two commands and creates nothing.

To drive an existing directory you already made under `<state-root>/targets`
(instead of letting `new-target` make one), `init` runs the same
`brigade init` against it:

```bash
registry/skills/verify-brigade/control-brigade.py init --target "$TARGET" \
  --depth workspace --harnesses claude,codex
```

Teardown is the `cleanup` section below. Run it after every attempt, including
failed ones, so broken runs do not leave targets behind.

## Doctor

One read-only check that answers "is this rig worth driving?" - before blaming
Brigade for a drive that fails:

```bash
registry/skills/verify-brigade/control-brigade.py doctor
```

It resolves the Brigade command (`--brigade`, then `$BRIGADE_BIN`, then
`.venv/bin/brigade`, then `PATH`, then `python -m brigade`), reports its
version, and checks git, the checkout, and a writable state root. `"ok": true`
means drive. Anything `"fail"` means fix that first.

Against a target that already exists, the equivalent question is:

```bash
registry/skills/verify-brigade/control-brigade.py doctor-target --target "$TARGET"
```

`"summary": {"failed": 0, ...}` is the success signal. `warn` counts above zero
are normal on a fresh target - memory-care, security, and backups are not
initialized yet.

Against this checkout itself (the development tree, not a temp target):

```bash
.venv/bin/brigade doctor --target .
.venv/bin/brigade status --target .
```

Observed here, both exit 0. Doctor printed
`summary: 43 checks, 0 failed, 0 manual` and a list of `warn` rows
(missing operator bootstrap files, unwired memory-care / security). Status
printed group rows (`core`, `skills`, `memory`, `guard`, ...) with `0 fail`
on every group; several groups were `[degraded]` or `[not-installed]` because
this tree is not an initialized operator workspace. Healthy for a Brigade
source checkout is **exit 0 and 0 failed**, not zero warnings.

## Drive

Real commands from this repo, one per mapped feature. The full map is in
[`features/README.md`](features/README.md); drive the feature your change
actually touched, not just the convenient one.

```bash
C=registry/skills/verify-brigade/control-brigade.py

# init + doctor wiring
$C doctor-target --target "$TARGET"

# work verification receipts (returns the receipt id and status)
$C work-verify --target "$TARGET" --capture verify-brigade

# Grok Bot connector pack lifecycle (implementation-worker is the worker pack)
$C grokbot-pack-setup  --target "$TARGET" --id implementation-worker
$C grokbot-pack-setup  --target "$TARGET" --id implementation-worker --apply
$C grokbot-pack-doctor --target "$TARGET" --id implementation-worker
$C grokbot-pack-canary --target "$TARGET" --id implementation-worker
$C grokbot-pack-remove --target "$TARGET" --id implementation-worker

# feed manifest validation and queue projection
$C grokbot-feed   --target "$TARGET" --sample
$C grokbot-status --target "$TARGET"

# handoff inbox lint
$C handoff-lint --target "$TARGET" --content-guard
```

Read the exit code, not the prose:

| exit | meaning |
|---|---|
| 0 | the drive ran and the observation is what a healthy rig produces |
| 1 | the helper itself failed (no Brigade, unsafe path, bad target) |
| 2 | usage error |
| 3 | the drive ran fine, but the observation is a failure |

Stable handles to assert on, in order of preference: the JSON keys the helper
normalizes (`run_id`, `status`, `summary.failed`, `checks[].status`, `valid`,
`reason`), then the receipt directory under
`$TARGET/.brigade/work/verify-runs/<run-id>/`. Do not grep the human prose;
it changes.

Checkout-level focused gates for a change in this repo (no full suite).
`./scripts/verify-focused` itself runs ruff, ruff format `--check`, mypy,
version-sync, the managed and template-profile snapshots, then the named
pytest selectors. The three lint/type pieces can also be run alone:

```bash
./scripts/verify-focused tests/test_skills_cmd.py tests/test_ci_workflow.py
.venv/bin/ruff check src/brigade
.venv/bin/ruff format --check src/brigade
.venv/bin/mypy
```

Receipted form — same focused command, recorded as a work-verify receipt
(`brigade work verify run --help` lists `--argv-json`, `--capture`, and
`--json`; `--help` itself exits 0):

```bash
.venv/bin/brigade work verify run --target . \
  --argv-json '["./scripts/verify-focused","tests/test_skills_cmd.py","tests/test_ci_workflow.py"]' \
  --capture brigade-work
```

`--command` and `--argv-json` receipts are audit-only. Do not pass
`--no-reuse` to the full `./scripts/verify` gate. Do not run
`./scripts/verify-fast` or the full suite from this skill.

## Evidence

```bash
registry/skills/verify-brigade/control-brigade.py evidence --target "$TARGET" --label <what-you-proved>
```

Writes `.brigade/verification-evidence/<stamp>-<label>/` in the checkout and
prints the path as `evidence_dir`. It contains `captures/` (every command the
helper ran, with argv, exit code, stdout, stderr, duration),
`target-brigade/work/verify-runs/` (the real receipts Brigade wrote), and
`manifest.json`. That directory is outside the state root, so `cleanup` cannot
reach it.

Proof standards for this repo:

- Drive the CLI path a user runs. Do not import `brigade.*` in Python and call
  the function; a passing unit test is not a proof that the command works.
- Capture the action and the resulting state. A `work-verify` proof is the
  command record **and** the receipt directory it names.
- Verify the side effect on disk, not just stdout. `grokbot-pack-setup --apply`
  claims it wrote `.brigade/grokbot/packs/<id>.json`; look at the file.
- Preview modes here are genuinely non-mutating, but check rather than trust:
  `grokbot-pack-setup` without `--apply` and `grokbot-pack-remove` without
  `--apply` print a `writes`/`paths` list and touch nothing, and
  `grokbot-feed` validates without enqueueing. Confirm by diffing
  `$TARGET/.brigade/` before and after.
- No mocks. Every command above hits the real CLI. The one boundary that is
  genuinely absent is a running Grok Bot listener, and the skill reads its
  absence as data rather than faking it.

Checkout `work verify` receipts live at
`.brigade/work/verify-runs/<run-id>/receipt.json`. Cite the `run_id` in the
PR body (`work-verify receipt: <run-id>`). A passing receipt has
`"status": "completed"` and `commands[].exit_code` of `0`. See
`docs/receipt-schemas.md` and the citation paragraph at the end of this
skill.

## Cleanup

```bash
registry/skills/verify-brigade/control-brigade.py cleanup --dry-run   # see it first
registry/skills/verify-brigade/control-brigade.py cleanup
```

Cleanup removes only paths recorded by `new-target` and only when they sit
under `<state-root>/targets/`; anything else is skipped with a reason. It never
kills processes by name, and it never removes an evidence directory. Use
`--target` to drop one target, `--keep-captures` to leave the raw command
records in the state root.

After cleanup, confirm the proof survived:

```bash
ls .brigade/verification-evidence/<stamp>-<label>/manifest.json
```

`.venv/` is gitignored (`.gitignore` line `.venv/`). Never commit `.brigade/`
— the root `.gitignore` lists `.brigade/` and `.brigade/work/` among the
ignored paths. Evidence under `.brigade/verification-evidence/` is also
gitignored; copy a receipt id into the PR body instead of adding the
directory. After a checkout-level verify, leave `.venv/` in place for the
next drive; remove it only when you are done with the tree
(`rm -rf .venv`). Do not `git add` either tree.

## Feature map

CLI surfaces in this repo and the tests that cover them. Drive the helper
feature your change actually touched (`features/README.md`); use the
pytest selectors here when the proof is a focused gate. Names confirmed
present under `tests/` on this checkout.

| Surface | Command | Tests |
|---|---|---|
| run | `brigade run` | `tests/test_run_cli.py`, `tests/test_run_lifecycle.py`, `tests/test_run_events.py`, `tests/test_run_control.py`, `tests/test_run_resume.py`, `tests/test_run_receipts.py` (32 `tests/test_run_*.py` / `tests/test_runs_*.py` files) |
| work verify | `brigade work verify` | `tests/test_work_cmd_verification.py`, `tests/test_work_cmd_verify_ranking.py`, `tests/test_verify_trial.py`, `tests/test_verification_contract.py`, `tests/test_verify_brigade_skill.py` |
| fleet | `brigade fleet` | `tests/test_fleet_claims.py`, `tests/test_fleet_claim_release.py`, `tests/test_fleet_nodes.py`, `tests/test_fleet_sync.py`, `tests/test_fleet_cloud.py`, `tests/test_fleet_command_deck.py` (14 `tests/test_fleet_*.py` files) |
| grokbot listener | `brigade run cloud grokbot` (`serve`, `setup`, `doctor`, `canary`, queue verbs) | `tests/test_grokbot_ops.py`, `tests/test_grokbot_jobs.py`, `tests/test_grokbot_mcp.py`, `tests/test_grokbot_feed.py`, `tests/test_grokbot_packs.py` |
| guard | `brigade guard` / `brigade scrub` | `tests/guard/test_cli.py`, `tests/guard/test_engine.py`, `tests/guard/test_rules.py`, `tests/test_scrub.py`, `tests/test_runguard.py` |

Doctor and status for the checkout itself: `tests/test_doctor.py`,
`tests/test_status.py`.

## Helpers

`control-brigade.py` is the only helper. It is executable, stdlib-only, and
prints one JSON object per call.

```bash
registry/skills/verify-brigade/control-brigade.py --help
```

Subcommands: `doctor`, `new-target`, `init`, `doctor-target`, `work-verify`,
`grokbot-pack-setup`, `grokbot-pack-doctor`, `grokbot-pack-canary`,
`grokbot-pack-remove`, `grokbot-feed`, `grokbot-status`, `handoff-lint`,
`evidence`, `cleanup`.

Global flags: `--brigade "<command>"` to drive a different Brigade build (for
example `--brigade "$(command -v python3) -m brigade"`), `--root <dir>` to
isolate the state root when two runs go at once (a directory under `$TMPDIR`,
not `$TMPDIR` itself), `--timeout <s>` per call.

Every subcommand that writes accepts `--dry-run`, which reports the command it
skipped and mutates nothing: `new-target`, `init`, `work-verify`,
`grokbot-feed --sample`, `evidence`, `cleanup`, and
`grokbot-pack-setup`/`grokbot-pack-remove` (there it forces preview even with
`--apply`). The dry-run envelope carries `"dry_run": true` and a `would_run`,
`would_remove`, or `would_copy` list.

`tests/test_verify_brigade_skill.py` runs `new-target`, `doctor-target`,
`work-verify`, and `cleanup` in a pytest `tmp_path`, and asserts the path
refusals (including a symlink planted at the default state root), the
unwritable-root JSON envelope, and the `0600`/`0700` permissions, so CI fails
if this helper stops working or stops guarding.

## Reporting the proof

Do not claim a Brigade behavior without the receipt. When a change is done,
route the repo's own gate through Brigade once:

```bash
brigade work verify run --target . \
  --argv-json '["./scripts/verify-focused","<pytest-selector>"]' \
  --capture brigade-work
```

Then paste the `run_id`, the status, and the `evidence_dir` from this skill.

That receipt is proof for a human reader, not a scored trial. `--command` and
`--argv-json` receipts are audit-only; only `--manifest <id>` produces a receipt
the outcome ratchet can score. Each `--capture` run prints which one it was.
See `docs/outcome-scoring.md`.

Checkout receipts from `brigade work verify run --target .` land at:

```
.brigade/work/verify-runs/<run-id>/receipt.json
```

Cite the `run_id` in the PR body as a single line, for example
`work-verify receipt: <run-id>`. Read it back with
`brigade work verify show <run-id> --json`. A passing receipt
(`docs/receipt-schemas.md`, `brigade.work_verify_receipt` schema_version 2)
has `"status": "completed"`, a `run_id` shaped
`<YYYYMMDD>-<HHMMSS>-work-verify-<hex>`, `commands[].exit_code` of `0`,
and the identity tuple `baseline_commit` / `tree_fingerprint` /
`changes_patch_sha256`. Failures still write a receipt (`"status": "failed"`);
that is the ledger signal, not a missing file.

Files in this skill

  • SKILL.md15.9 KB
  • control-brigade.py42.4 KB
  • features/README.md2.8 KB
  • features/grokbot-pack-lifecycle.md5.1 KB
  • features/handoff-lint.md3.5 KB
  • features/init-and-doctor.md3.7 KB
  • features/run-cloud-grokbot-queue.md4 KB
  • features/work-verify-receipts.md4.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.