Brigade Master Class

Brigade, end to end

One canonical source for the MCP servers, tools, skills, and memory your AI coding agents share across 18 writer harnesses, merged into each tool’s native config with a review gate and a receipt for every change. A local operator-system CLI — not a runner, not a daemon, not a hosted service. Memory is one pillar of it, not the whole story. This is how every piece works, from the decide() memory guardrail to the MCP merge engine to the cross-model run loop.

brigade-cli v0.25.1Python 3.10+MITzero runtime deps
01

What Brigade Is — and Is Not

Brigade’s own one-liner: "Your agents run loops. Brigade keeps the receipts." It is one canonical source for the MCP servers, tools, skills, and memory your agents share across Codex, Claude Code, OpenCode, and over a dozen other harnesses — merged into each tool’s native config with a review gate and a receipt for every change. Shared memory is where it started and is one pillar of it, not the whole surface. It runs on the machine you control: local by default, loud about the exceptions. Holding both halves of this panel in your head is the whole mental model.

What it is

  • A shared MCP catalogOne catalog of MCP servers merged by key into every tool’s native config. Dry-run by default; servers you added by hand are never touched.
  • A shared tool + skill catalogReviewed portable tools and SKILL.md packs, installed across the harness fleet with per-harness receipts and rollback.
  • Shared memory across harnessesOne handoff note format every tool writes; one canonical owner files the good notes into durable memory.
  • Local guardrailsLints handoffs, scrubs content, and security-scans agent workspaces before anything leaves the machine.
  • A receipt for everythingEvery consequential action lands a plain-file receipt you can grep, diff, and prune.
  • File-firstYour memory and catalogs are files in your repo, reviewable in git, readable without Brigade installed.
  • Deliberately boundedSafe, targeted changes apply; ambiguous or risky ones wait for your review.

What it is not

  • A hosted service or daemonDoes not run in the background or install schedulers.
  • A publisherNever pushes to GitHub or publishes packages.
  • NoisySends no notifications by default.
  • Blindly automaticDoes not save every note or write tool configs without your yes.
  • A silent ingesterNever turns ingest into a background process, and never skips review for risky or failed notes.
02

Why It Exists: Two Incidents

Brigade was hand-rolled one incident at a time around an always-on OpenClaw agent plus daily Codex and Claude Code sessions. Two failures shaped the design more than anything planned. First, a nightly "dreaming" job promoted raw session fragments straight into memory and bloated MEMORY.md past the bootstrap budget; every session then started with truncated memory and nobody noticed for weeks. Blind auto-promotion died that day. Second, 195 handoff notes sat unread across 35 repos because the ingester had a hardcoded three-repo allowlist and nothing warned about the gap. Silence is the failure mode. Every part of Brigade that lints, warns, or writes a receipt exists because something once failed in silence.

41KB
MEMORY.md bloat
Blew past the 12KB bootstrap budget. Truncated memory, unnoticed for weeks. The end of blind auto-promotion.
195
Handoffs unread
Across 35 repos, behind a hardcoded 3-repo allowlist. No warning fired. Silence is the failure mode.
12KB
Bootstrap budget
The slim-index ceiling Brigade now guards on every route into memory.
482
Cards in production
The system Brigade packages, surviving daily multi-agent work. The cookbook is where it came from.
03

Brigade’s Surface Area

Memory is where Brigade started, but it is one capability among several the CLI keeps in one reviewed source: MCP servers, tools, skills, and memory. Each is its own command family with its own review gate and receipts; none of them publishes, runs a daemon, or changes anything without your explicit command. Here is the whole surface before we go deep on each piece — keep it in mind, because the rest of this dive is one chapter per card.

Shared memorybrigade ingest
Handoff notes from every harness, linted and filed into a budget-guarded index plus knowledge cards.
MCP catalogbrigade mcp
One canonical server catalog merged by key into each tool’s native config. Dry-run by default, secrets as references.
Shared toolsbrigade tools
A portable catalog of tools, scripts, and contracts with call planning, approval queues, run receipts, and parity tracking.
Shared skillsbrigade skills
Reviewed SKILL.md packs, linted for injection, installed across 20 targets with per-harness receipts and rollback.
Friction logsbrigade friction
Mines recent work, handoffs, and learnings for workflow pain and turns it into reviewable candidates. Never auto-files issues.
Repo fleetbrigade repos
Health evidence and release trains across your local repos. Builds a manual publish plan; never publishes.
Cross-model runbrigade run
A bounded aboyeur that plans a task into stages and dispatches workers across your own authenticated CLIs.
Guardsscrub · security
Content scrub, workspace security scans, and prompt-injection checks before anything becomes memory or leaves the machine.
04

The Kitchen Glossary

Brigade borrows the vocabulary of a professional kitchen brigade (a brigade de cuisine). The terms are load-bearing, not decoration: internalize them and the rest of the system reads cleanly. Definitions are verbatim from docs/technical-guide.md.

harnessthe line cook
An AI agent program: Claude Code, Codex, OpenCode, Antigravity, Pi, Cursor, OpenClaw, Hermes, and more.docs/technical-guide.md
operatorthe chef
You, the human running the agents and making the explicit decisions about what gets saved, run, or published.
handoffthe ticket
A memory note an agent writes to be saved long-term, held in its own inbox until linted and classified.
ingest / ingesterexpediting to the pass
Reading handoff notes from every inbox and filing them into permanent memory. Conservative by design.
stationa kitchen station
A subsystem of Brigade (memory, security, tokens, pantry, ...) with its own commands and a health check.
mise en placeeverything in its place
Rules, memory, tools, inboxes, and guards laid out before the session gets expensive. The core idea.
aboyeurthe expediter
The kitchen expediter who calls out orders. In Brigade, the orchestrator behind a cross-model `brigade run`.
receiptthe docket
A local file logging that something happened, kept for audit and proof. Brigade writes them but never acts on them.
gatethe chef’s yes
A manual approval checkpoint; nothing risky happens without your yes.
dogfoodstaff meal
Brigade used on itself or another trusted repo.
05

The Memory Loop

The memory loop is the original core; the rest of the surface orbits it. In five steps: (1) each writer harness drops a handoff note into its own inbox (e.g. .claude/memory-handoffs/) as it works; (2) Brigade lints, guards, and classifies every note before it can become memory; (3) safe, targeted notes file themselves into durable memory automatically; (4) anything ambiguous, unsafe, or failed is kicked to a review inbox for the memory owner to decide; (5) future sessions start with better context and a plain-file receipt records exactly what happened. Drawn, it looks like this — writer harnesses hand off, Brigade lints and classifies, safe notes reach durable memory through the owner, the risky few branch to review, and memory feeds the next session.

Writer harnessesCodex · Claude Code · OpenCode · …
Brigadelint · guard · classify
Memory ownerOpenClaw / Hermes / you
Durable memoryMEMORY.md index + cards
↓ ambiguous or risky
Review inboxwaits for your yes
06

Mise en Place: Two-Layer Memory

The 41KB incident produced the central design decision: memory has two layers. Knowledge cards under memory/cards/ hold the detail; MEMORY.md stays a slim, one-line-per-card index that loads every session and is guarded against the 12KB budget. Brigade never edits canonical memory itself — the owner does the writing.

Bootstrap layer (loads every session, budget-guarded)
MEMORY.md
Slim one-line-per-card index. Guarded against the 12KB bootstrap budget on every route.
AGENTS.md / rules
Operator rules and conventions projected into each harness’s native format.
TOOLS.md
The reviewed tool + endpoint catalog. A safe special target for routed notes.
Detail layer (loaded on demand)
memory/cards/*.md
Knowledge cards with YAML frontmatter. Where promoted handoffs land. 482 in the production system.
.learnings/*
LEARNINGS.md, ERRORS.md, FEATURE_REQUESTS.md — routed append targets.
memory care scan
Flags stale, contradictory, or undersourced cards for review instead of trusting them forever.
07

The decide() Guardrail

This is the single most important piece of Brigade’s memory loop. decide() (ingest.py) is the pure function that turns a parsed handoff into one of four outcomes: promoted, routed, inboxed, or skipped. Every branch that cannot prove a note is safe routes it to the review inbox. Conservative by default — that pause is the point.

Parsed handoff note
Sections parsed from the markdown by SECTION_RE (^##\s+name).
  • any unknown ## section?
    inboxedoutcome
    A section key not in KNOWN_SECTIONS means the parser may have split on internal text. Bail to review.
  • action = create/update-card AND promote_cards
    Card safety checks
    SAFE_CARD_NAME_RE filename allowlist → YAML frontmatter present → scan_untrusted for injection.
    • any check fails
      inboxedoutcome
      Unsafe name, missing frontmatter, or injection signal.
    • all pass
      promotedoutcome
      Written to memory/cards/<card>.md.
  • action names a target document AND route_documents
    Document safety checks
    Target in SAFE_SPECIAL_TARGETS or matching SAFE_RULE_PATH_RE → non-empty → no ## headings → dedupe → budget guard → injection scan.
    • any check fails
      inboxedoutcome
      Unsafe target, dup, over-budget, or injection signal.
    • all pass
      routedoutcome
      Appended to the target document (TOOLS.md, rules/*, .learnings/*).
  • no recommended action
    inboxedoutcome
    Missing "Recommended memory action".
  • anything else
    skippedoutcome
    Action not auto-handled; left for a human.
08

decide(), in the Source

The same guardrail in code. Notice that every failure path constructs an Outcome("inboxed", ...) instead of writing — the safe default is always review.

src/brigade/ingest.py:209python

The card-promotion branch of decide(). The document-routing branch below it follows the same shape.

def decide(sections, target, promote_cards, route_documents) -> Outcome:
    action = sections.get("recommended memory action", "").strip().lower()

    stray = [s for s in sections if s not in KNOWN_SECTIONS]
    if stray:
        return Outcome("inboxed",
            reason=f"unknown sections present (parser may have split content): {stray}")

    if action in ("create-card", "update-card") and promote_cards:
        card = sections.get("target card", "").strip()
        content = sections.get("suggested card content", "")
        if not SAFE_CARD_NAME_RE.match(card):
            return Outcome("inboxed", reason=f"target card name unsafe: {card!r}")
        if not content.lstrip().startswith("---"):
            return Outcome("inboxed", reason="card content missing YAML frontmatter")
        if scan_untrusted(content).flagged:
            return Outcome("inboxed", reason="injection signal in card content ...")
        return Outcome("promoted", dest=target / "memory" / "cards" / card)
  • stray = [s for s in sections if s not in KNOWN_SECTIONS]An unrecognized ## heading means the parser likely split the note wrong. Refuse to guess; inbox it.
  • and promote_cardsAuto-promotion is opt-in. Off by default, you choose to enable it per ingest.
  • SAFE_CARD_NAME_RE.match(card)A strict filename allowlist (^[A-Za-z0-9._-]+\.md$) blocks path traversal into other dirs.
  • scan_untrusted(content).flaggedPrompt-injection scan runs before anything is allowed to become durable memory.
09

The Eleven Stations

Under the command families, Brigade is partitioned into eleven builtin stations (the _BUILTIN tuple in registry.py). Each is a frozen Station dataclass with a name, a summary, kitchen aliases, an optional doctor() health check, and the managed tools attached to it. Each managed tool now also declares machine-readable surfaces — a live doctor JSON, a bounded brief, a verify command — that brigade stations list --json and brigade profiles surface before you install a sidecar. The station is the unit of the system, and the bridge from the memory loop to everything else.

coremise
Workspace bootstrap and harness adapters — the setup station.
skillsskillet
Reviewed SKILL.md packs, linted for injection and installed across the harness fleet with receipts and rollback.
memorygarde
Handoff inbox, ingest, and memory-care.
memory-doctor · bootstrap-doctor
guardpass
Publish safety and content scrub.
content-guard
tokens
Output compaction.
Token Glace
searchcode-search
Local semantic code search.
code-search-api · code-search-mcp
securitysec
Agent workspace security scanning.
pantrylarder
Agent session auth sync.
agentpantry
notificationsnotify
Operator notification wiring.
agent-notify
evidenceledger
Local-first evidence ledger with built-in crawlers and receipt export.
miseledger
mcpbrigadier
One canonical MCP server catalog merged by key into each tool’s native config.
10

One MCP Catalog, Every Tool

Every agent tool reads its MCP servers from a different file in a different shape. Brigade keeps one canonical catalog at .brigade/mcp.json and merges it into each tool’s native config for you. It is dry-run by default and never runs from doctor or brief; it merges by server key, so servers you added by hand are never touched; and secrets are written as ${VAR} references (or VS Code ${input:VAR}), never inlined. brigade mcp plan previews; brigade mcp sync --write actually merges.

ToolNative config it writesShape
Claude Code.mcp.jsonJSON · mcpServers
Cursor.cursor/mcp.jsonJSON · mcpServers
Codex CLI.codex/config.tomlTOML · [mcp_servers.*], merged surgically
VS Code.vscode/mcp.jsonJSON · servers + inputs[]
OpenCodeopencode.jsonJSON · mcp
Antigravity~/.gemini/config/mcp_config.jsonJSON · user-global
OpenClaw~/.openclaw/openclaw.jsonJSON · mcp.servers
11

The Merge State Machine

Brigade owns only the server keys recorded in the sidecar .brigade/mcp/state.json. For each (tool, server) it compares the canonical definition, what it last wrote, and the live value in the file, then picks one of seven outcomes. A server you added yourself is foreign and never modified; one Brigade manages but you then edited is a conflict, left alone unless you pass --force. This is what makes the sync safe to run on a config you also hand-edit. (Verbatim from docs/mcp-sync.md.)

StateSituationDefault action
missingNot in the filecreate
foreignIn the file, not owned by Brigadeskip (--adopt to take over)
currentOwned, matches the catalogskip
staleOwned, canonical changedupdate
conflictedOwned, edited outside Brigadeskip (--force to overwrite)
orphanDropped from the catalog, still pristineskip (--prune to remove)
orphan-editedDropped from the catalog, edited in placeleave untouched
12

Shared Tools: The Portable Catalog

brigade tools describes local callable tools, slash commands, skills, superpowers, scripts, and MCP configs across every harness. It inspects local files, reports health, and can explicitly write reviewed projections or supervise approved runtimes. It does not start servers, fetch schemas, store auth, or auto-run anything. A tool call walks a gated path before it ever executes, and projection parity tracks every harness file so config drift surfaces as a reviewable issue rather than a surprise.

  1. Discover & contracttools list / search / describe surface portable entries and their JSON-Schema call contracts.
  2. Plantools call plan validates arguments and renders a safe execution plan without invoking anything.
  3. Queue & approvePlans wait in an approval queue; approve / reject / hold change status only, never run code.
  4. Run & receipttools call run executes one approved call and writes a local receipt with args, exit code, and fingerprints.
  5. ParityProjection fingerprints track each harness file; a parity closeout quiets unchanged issues, but a changed fingerprint resurfaces as drift to review.
13

Shared Skills: One Pack, Twenty Targets

Skills are treated as versioned workflow code: a reviewed SKILL.md pack with metadata, provenance, a trust level, and a stable fingerprint. One import lands it in a local registry; one install materializes it into every harness’s native skills folder with a receipt and a rollback snapshot. The supported targets are twenty in all — nineteen harnesses (Codex, Claude, OpenCode, Antigravity, Pi, Cursor, Aider, Goose, Continue, GitHub Copilot CLI, Qwen, Kimi, AdaL, OpenHands, Grok, Amp, Crush, OpenClaw, Hermes) plus a read-only MCP resource.

Importinto .brigade/skills/registry/ with metadata, provenance, trust, fingerprint
LintSKILL.md, trust level, bundled tests, and a prompt-injection scan
Install --target allrender per harness, write the native file, log a per-harness receipt
Compatibilitysupported / installed / planned / blocked, plus version drift and history
Diff & rollbackcompare installed vs current, or restore the pre-update snapshot
14

Friction Logs: Mining Pain Into Work

brigade friction scan reads recent work artifacts, notes, handoffs, and .learnings (optionally local Codex and Claude Code session logs) for buried workflow pain, and writes .brigade/friction/latest.json and latest.md. It is review-first: it does not create GitHub issues, edit memory, publish reports, or promote findings. Candidates only become tasks when you say so. It pattern-matches nine kinds of friction:

auth
Auth or permission friction: 401/403, permission denied, expired session.
quota
Quota or rate-limit friction: 429, usage limit, credits depleted.
tool_failure
A tool or command failed: nonzero exit, command not found, a panic.
network_timeout
A network call refused or timed out.
blocked
A blocked workflow: blocker, could not, failed, cannot.
workaround
A workaround was required: fallback, manual fix, had to route around.
missing_context
Missing, stale, or outdated context.
workflow_correction
A correction captured: a gotcha, a lesson learned.
latency
Latency or effort friction: slow, took ages, too long, expensive.
15

The Repo Fleet and Release Trains

brigade repos inspects the local repositories listed in a gitignored .brigade/repos.toml. It never clones, pushes, or mutates a remote: it collects safe health evidence, redacts private paths, and turns reviewed reports into a release train. A train classifies each repo as ready, blocked, needs-review, needs-dispatch, in-progress, stale-evidence, no-release-candidate, or deferred, then writes FLEET_RELEASE_TRAIN.md, FLEET_RELEASE_EVIDENCE.json, and a MANUAL_PUBLISH_PLAN.md of checklist steps. Brigade does not execute any publish step.

Discoverdry-run under configured roots; safe labels; never clones
Scanbranch, dirty counts, guidance files, docs as health evidence
Sweepoptional read-only refresh; per-repo summaries + fingerprints
Reportfleet operator report: safe ids, counts, blockers, warnings
Actionsreviewed action queue: start / done / defer / dispatch
Releaserelease train + manual publish plan; no publish executed
16

Execution: brigade run & the Aboyeur

brigade run "<task>" is a bounded cross-model orchestration. The aboyeur (the kitchen expediter) plans the task into staged JSON assignments; workers run in parallel within a stage through their own CLIs; later stages receive earlier results; the orchestrator synthesizes. It is intentionally bounded: two orchestrator calls plus the planned worker calls. No infinite loop. Each run also carries brigade-computed ground truth — a git diff --stat, the changed-file list, and parsed verify exit codes folded into synthesis, so the aboyeur reasons over facts, not worker narration — plus fail-open code-graph and upstream-drift briefs, ranked and clipped by a run-level brief budget, that hand workers blast-radius context before they edit.

Phase 1 · PLANorchestrator (aboyeur)
build_plan_promptEmit one strict JSON object of staged assignments, capped at roster.max_workers per stage.orchestrator
Phase 2 · DISPATCHworkers run their own CLIsparallel
Stage 1 workersRun concurrently via ThreadPoolExecutor. A crash becomes ok=False, never a hard failure.cli=codex
Stage 2 workersReceive all prior-stage results as context, then run concurrently too.cli=claude
...later stagesSerial across stages, parallel within. Pool never over-provisions.cli=...
Phase 3 · SYNTHESISorchestrator (aboyeur)
Synthesize final answerFold worker results into one answer, then write a run handoff into the ingester inbox.orchestrator
17

The Dispatch Loop

How "serial across stages, parallel within a stage, later stages see earlier results" is actually implemented.

src/brigade/aboyeur.py:756python
all_results: list[WorkerResult] = []
stages = sorted({a.stage for a in assignments})
for stage in stages:
    stage_assignments = [a for a in assignments if a.stage == stage]
    prior_results = list(all_results)
    max_workers = min(roster.max_workers, len(stage_assignments))
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_index = {
            executor.submit(run_one, a, prior_results): i
            for i, a in enumerate(stage_assignments)
        }
        for future in as_completed(future_to_index):
            i = future_to_index[future]
            try:
                stage_results_by_index[i] = future.result()
            except Exception as exc:
                a = stage_assignments[i]
                stage_results_by_index[i] = WorkerResult(
                    worker=a.worker, task=a.task, text="", ok=False, detail=str(exc)[:200])
    all_results.extend(stage_results_by_index[i] for i in range(len(stage_assignments)))
  • for stage in stages:Stages are serial; ordering is preserved so dependent work runs after its inputs.
  • prior_results = list(all_results)Each stage receives a snapshot of every earlier worker’s output as context.
  • min(roster.max_workers, len(stage_assignments))The pool never over-provisions: cap is the smaller of the roster limit and the stage size.
  • except Exception ... ok=FalseA worker that crashes becomes a failed result, not an exception that kills the run.
18

The CLI Adapter Ring & Sandbox Enforcement

Brigade reaches models with no SDKs and no API keys: it builds subprocess argv for the user’s own authenticated CLIs. Because not every CLI can truly enforce read-only, Brigade is honest about it. hard = a native sandbox the model cannot escape; soft = read-only is only a prompt instruction; none = read_only is not applied at all. A writable --sandbox override downgrades even a hard CLI to prompt-only, with a loud advisory.

hardsoftnone
codex
antigravity
pi / cursor / aider
continue / qwen / kimi
goose / copilot / adal
openhands / grok
amp / crush
claudeargv ignores read_only entirely
opencode

8 hard · 7 soft · 2 none. From READ_ONLY_ENFORCEMENT in agents.py. ollama:<model> refs always resolve to "none".

19

How read-only Is Enforced

The codex adapter is the cleanest example of the "build argv, no shell" pattern. Every external command is an argv list run through proc.run, which captures output and normalizes failure to exit codes.

src/brigade/agents.py:22 · src/brigade/proc.py:30python
def _codex_argv(prompt, read_only, sandbox):
    if sandbox:
        return ["codex", "exec", "--sandbox", sandbox, prompt]   # writable override
    if read_only:
        return ["codex", "exec", "--sandbox", "read-only", prompt]  # hard sandbox
    return ["codex", "exec", prompt]

# proc.run: no shell, bounded, failures become exit codes
cp = subprocess.run(args, capture_output=True, text=True,
                    timeout=timeout, check=False, stdin=subprocess.DEVNULL)
# FileNotFoundError -> Result(code=127, ...)   # missing tool, not a raise
# TimeoutExpired    -> Result(code=124, ...)   # hung tool, bounded
  • ["codex", "exec", "--sandbox", "read-only", prompt]codex gets a real OS sandbox flag, which is why its enforcement is "hard".
  • sandbox: ... return [..., "--sandbox", sandbox, ...]A writable --sandbox override is honored, downgrading enforcement to prompt-only with a loud advisory.
  • subprocess.run(args, ... ) # no shell=Trueargv list, never a shell string: there is no shell-injection surface.
  • stdin=subprocess.DEVNULLTools can never block waiting on input; a hung tool is killed by timeout (code 124).
20

Installation as Declarative Composition

brigade init does not run a script of imperative steps. It composes manifests (a depth manifest + one per selected harness + includes), dedupes them by destination so a harness can override a baseline file, renders the templates, and atomically rewrites a marker-delimited block in .gitignore. A repo-depth install now writes only AGENTS.md and SAFETY_RULES.md plus gitignored state by default; the full kit — workflow rules, the inactive pre-push hook, the default tool packs — moves behind --full.

src/brigade/install.py:265python
# Dedupe files by dst (last-wins): a harness manifest can override a baseline file.
seen: dict[str, dict] = {}
for entry in files:
    seen[entry["dst"]] = entry
deduped_files = list(seen.values())

# Per selected harness, write a managed, marker-delimited gitignore block:
for h in selection.harnesses:
    inbox = WRITER_INBOXES.get(h)
    if inbox:
        lines += [f"{inbox}/*",            # ignore session-local handoffs
                  f"!{inbox}/TEMPLATE.md",  # but keep the template
                  f"!{inbox}/.gitkeep"]
  • seen[entry["dst"]] = entryLast-wins by destination path: later (harness-specific) manifests override earlier (baseline) files.
  • GITIGNORE_BEGIN ... markersRe-running brigade init only rewrites the content between the markers, never your edits outside them.
  • f"{inbox}/*" + f"!{inbox}/TEMPLATE.md"Handoffs are private session context, so they are gitignored — but the shared template is kept.
21

Brigade as a Read-only MCP Server

Distinct from the MCP catalog sync above (brigade mcp, which writes server config into your tools), this is Brigade serving its own skills and memory cards back to agents over a zero-dependency, read-only MCP server: a single line-oriented JSON-RPC loop on stdin/stdout that only ever initializes, lists resources, and calls read tools. Managed tools follow the same humility: an absent or unconfigured fleet tool is advisory (WARN/MANUAL), never a hard failure of the workspace doctor.

src/brigade/mcp_server.py:50python
for line in sys.stdin:
    request = json.loads(line)               # newline-delimited JSON-RPC 2.0
    method = str(request.get("method") or "")
    if method == "initialize":
        _emit(response(id, result={"protocolVersion": "2024-11-05",
            "capabilities": {"resources": {}, "tools": {}}}))
    elif method == "resources/list":
        _emit(response(id, result={"resources": list_resources()}))
    elif method == "tools/call":
        payload, failed = call_tool(name, arguments)   # station-supplied callback
        _emit(response(id, result={"content": [{"type": "text", "text": text}],
                                   "isError": failed}))
  • for line in sys.stdin:No framework: a plain newline-delimited JSON-RPC loop, which is why it has zero dependencies.
  • initialize / resources/list / tools/callThe only methods it answers. There is no mutating method — the server is read-only by construction.
  • call_tool(name, arguments)Each station supplies a read callback; the loop owns the JSON-RPC envelope.
22

The CLI Surface: 43 Commands, 5 Families

Everything above is reachable through one CLI. COMMAND_GROUPS (cli/_common.py) organizes all 43 top-level commands into five families; a test enforces that every command appears in exactly one group, so nothing can be silently un-grouped. Eighteen of the groups are an operator extras surface that registers only after brigade extras on (or BRIGADE_EXTRAS=1); the core stays twenty-five. The daily operator loop now centers on a verified work loop — work brief, then work verify run --capture <id>, then a handoff — so outcomes are recorded, not narrated. This is the map of where each capability lives.

Core memory loop
  • init
  • handoff
  • handoff-template
  • ingest
  • memory
  • doctor
  • status
  • profiles
Daily operator loop
  • operator
  • daily
  • work
  • friction
  • center
  • runbook
  • budgets
  • notifications
Stations and tools
  • add
  • stations
  • skills
  • tools
  • mcp
  • pantry
  • roster
  • run
  • runs
  • dogfood
Review, security, and research
  • security
  • scrub
  • untrusted
  • research
  • learn
  • outcome
  • chat
  • context
  • projects
Wiring and advanced
  • release
  • roadmap
  • repos
  • reconfigure
  • completions
  • extras
  • openclaw-fragments
  • hermes-fragments
23

From the Brigade to the Whole Kitchen

Brigade is the brigade de cuisine itself — the executive chef and the line — but it does not work alone. The stations you saw attach to managed tools (agentpantry, code-search, miseledger, and more) and the embedded content guard, each owning one job and handing off cleanly to the next, while the catalogs, friction lane, and fleet keep the whole line in sync.

Escoffier Labs Academy. Generated from the deep-dive source of record.