v0.26.0
Brigade's first stable release. Install with pipx install brigade-cli==0.26.0 (or uv tool install brigade-cli), or move an existing install with brigade update --channel stable. Stable is the immutable pinned channel; beta tracks CI-green main for development machines - see docs/update-channels.md.
Added
-
Roster resolution now understands linked git worktrees: when a worktree has
no.brigade/roster.tomlof its own,brigade runandroster doctorfall
back to the parent clone's roster (newworktree-parentsource, reported in
the run provenance line) before the user roster at~/.brigade/roster.toml.
A fresh worktree of a wired repo keeps the repo's seats instead of silently
downgrading to whatever the user roster or a scaffold provides. (#741) -
brigade roster initrefuses to scaffold a starter roster when a fallback
roster already applies to the target (the parent clone's roster in a linked
worktree, or~/.brigade/roster.toml), since the codex+ollama-only starter
would shadow every seat configured there. Pass--forceto scaffold a
workspace roster anyway.brigade researchnow resolves its roster through
the same fallback chain instead of requiring a workspace roster. (#741) -
One-and-done onboarding:
brigade work hooks install|update|status|uninstall
gain--scope user(defaultproject, prior behavior unchanged), installing
the managed Claude work-loop hooks once at user scope so every repo the agent
opens gets the work brief injected and an unwired git repo gets the exact
brigade initcommand printed at session start. User settings merge
non-destructively, Brigade-owned entries are tagged so uninstall removes
only them, and status detects a stale script by hash.operator quickstart
now suggests the user-scope install once when wiring the claude harness, and
the README documents the flow. (#740, #743) -
brigade status --jsoncarries the sameavailable_updatefield the work
brief gained, so machine consumers can watch for releases without parsing the
brief. Cache-read only; never touches the network. (#717) -
The publish workflow verifies https://check.brigade.tools/v1/version reports
the just-published release after the PyPI upload and fails loudly with
update-and-rerun instructions on drift, andrelease doctorwarns when
pyproject declares a version with no matching git tag, catching
version-bump-without-release before it ships. (#719) -
docs/outcome-scoring.mddocuments read-time re-scoring and the full failure
kind-to-verdict table. (#718) -
brigade runs auditprovides a read-only audit of recorded lifecycle evidence
for coordinator decisions. (#649) -
Verify-run retention now archives receipt evidence before pruning (#598).
When.brigade/work/verify-runs/grows past the retention cap, each run
directory is copied into the verify archive (default
.brigade/work/verify-archive/<run-id>/) and an append-only
index.jsonlentry (brigade.verify_archive_index.v1) records the
receipt's digest, signature, key id, and schema version before the local
copy is deleted. Archival re-verifies the copied receipt bytes and the
receipt's self-declareddigests.receipt_sha256; a run directory whose
archival fails or whose receipt no longer re-hashes is kept locally, so
pruning never destroys unpreserved evidence. Archive paths that overlap the
local run root, partial or symlinked archive destinations, and source trees
containing symlinks or special files are rejected without pruning. New
.brigade/config.json
keys:verify_runs_keep(default 50),verify_archive_enabled(default
true), andverify_archive_dir(default.brigade/work/verify-archive). -
brigade work resolve-target --cwd PATH [--harness NAME]prints the
Brigade-wired project root (requires.brigade/config.json) so shell hooks
share Claude's discovery contract instead of matching any.brigade/dir. -
Shared
brigade.wiring.resolve_wired_targethelper used by Claude hooks and
the new resolver CLI; optional harness filter. -
Grok work-loop hook templates under
src/brigade/templates/grok/hooks/that
useresolve-target, timeout the session brief, and do not deny edits while
a brief is running (#537). -
Imported
stations/notifyGo module into the Brigade monorepo. Unified release
manifests now enumerate five native components (25 platform assets plus
component-manifest-v1.jsonandchecksums.txt) with managed resolution
throughbrigade setup. -
Beta pre-pin compatibility: beta installs the CI-green
mainBrigade wheel but
reuses the last verified stable component manifest;agent-notifyis omitted
from setup until a stable manifest publishes its assets. Stable validation
stays strict. -
Public update-channel and component-manifest policy docs.
-
Agent Pantry compatibility probe:
brigade pantryrequiresagentpantry version --json>=0.5.0before invoking doctor, status, or inventory
surfaces. Pantry remains an external Go binary. -
The append-only lifecycle journal now defines the canonical
brigade.run_event.v1event contract, closed payload allowlists, deterministic digest chains, idempotent appends, partial-tail quarantine and recovery, and private journal artifacts. (#607) -
Enrolled runs record lifecycle transitions before their compatibility
run.jsonsnapshots advance, while legacy and opt-out runs remain snapshot-only. (#608) -
A pure, deterministic run snapshot projector derives journal-backed fields while preserving the existing
run.jsoncontract. (#609) -
Shadow projection comparison records bounded digest-only evidence of whether each snapshot matches its lifecycle-journal projection, including lag, mismatch, error, and crash-gap states. (#610)
-
Crash-safe recovery checkpoints cover lifecycle events and
run.jsonreplacements, let recovery restore a verified record after interruption, and add read-only Doctor checks for repairable and unsafe states. (#615) -
Lifecycle events now pair every worker dispatch request with its observed completion or failure, carrying the selected seat and attempt identity and surfacing unobserved requests as recovery work. (#625)
-
Enrolled runs can pause at Daily and Tool approval boundaries, then resume and redeem the approved action exactly once with redacted, bound approval facts. (#626)
-
brigade runs redactprovides an operator-confirmed, fail-closed procedure to redact terminal lifecycle journals, reproject their snapshots, and retain chained anchors for overlapping rewrite history. (#627) -
brigade runs eventsexposes lifecycle-only NDJSON with opaque durable cursors, andruns steerandruns interruptaccept idempotent request IDs with journaled requested and observed control facts. (#641) -
Runs probe declared seat health after writing the initial run receipt and before planning, recording
seat-health.jsonbeside the receipt; a probe that fails, hangs, or raises is itself receipted as a failed result for every declared seat, so probe trouble cannot take down an already-recorded run. (#685) -
A failed orchestrator seat now selects a healthy declared fallback, or aborts
with its typed cause, before planning begins. (#688) -
Four packaged roster presets (
minimal-single-cli,budget-open-weight,full-multi-lane,review-heavy) and optional per-seatpurpose,requires,fallback,stats, andcaveatsmetadata, with one-hop capability-based fallback resolution when host requirements are not met. (#454) -
brigade roster suggest --preset NAMEassembles a preset roster from installed host capabilities, emitting per-seat resolution lines and substituting local receipt stats when available, andbrigade roster statssummarizes per-seat median duration and failure rate from local worker receipts. (#463) -
brigade model trial regrade OUTPUT_DIRre-runs graders from stored trial output without re-running seats. Trial summaries recordmeasurement_failuresandpartial_scores, cells carryfailure_reason, and trial processes exit3when measurement failures are present,1for rejected or execution errors, and0otherwise. (#457) -
The
oracleCLI adapter (cli = "oracle") runs browser research viaoracle --engine browser, reports stale cookie auth with abrigade pantrynext step instead ofworkspace-trust, and lets a researcher seat'stimeout_secondsraise the research engine LLM timeout floor. (#535) -
run.jsonrecords aschedulerblock withrequested,used, andfallback_reason, written at run start and filled when dispatch resolves the effective scheduler (--scheduler, thenlimits.scheduler, thenwaves), so a receipt distinguishes a real DAG dispatch from a silent degrade to waves. (#543) -
Failed worker results and per-attempt records in run receipts include a typed
failureobject (brigade.worker_failure.v1) withfailure_class,phase, andretry_disposition, mapped from the legacyfailure_kindandfailure_phasefields. (#589) -
brigade roster doctorruns a shared seat health probe per declared seat, covering declaration, executable identity, authentication, transport liveness, version gates, model reachability, and isolation compatibility, without model smoke prompts. (#590) -
brigade mcp pi-bridgeexposesdiscover,call,install, anduninstallto project the canonical.brigade/mcp.jsoncatalog into Pi's managed extension at~/.pi/agent, names toolsserver__tool, rejects catalog server names containing the reserved__separator, preserves server and tool identity on MCP failures, and tracks the generated extension and catalog projection through install receipts. (#438, #453) -
brigade harness installaccepts--surface cursor-cli|cursor-guito select a vendor surface explicitly, and--projection-only(which requires--surface) to let a runtime-absent surface receive Brigade projections without claiming a native runtime; install records the decision in.brigade/surface-evidence.json. (#464) -
brigade harness sync,brigade harness uninstall, andbrigade harness doctorsupport Claude Code and Codex user-scope profiles (--target claude|codex|all --scope user), dry-run by default, with receipt-based ownership, idempotent sync, and uninstall that removes only Brigade-owned artifacts. (#465) -
User-scope harness profiles extend to OpenClaw, Kimi, Grok, Cursor, and OpenCode under the same sync, doctor, and uninstall contract, so
brigade harness sync --target all --scope usercovers all seven harnesses. (#467) -
brigade evidence show,brigade evidence explain, andbrigade evidence statsquery the evidence ledger without invoking the engine binary directly; help, status, doctor, and plan text use the evidence engine branding, timeouts honorBRIGADE_EVIDENCE_TIMEOUT_SECONDSandBRIGADE_EVIDENCE_STATUS_TIMEOUT_SECONDS, and exit124prints a retry hint that doubles the current timeout. (#430) -
brigade mcp sync --user-scopeandbrigade operator sync-mcp --user-scopeno longer write stdio MCP servers into a user-wide client config silently: interactive runs show the destination, the stdio count, and the servers-times-sessions process formula before asking for confirmation, non-interactive and--jsonruns require--allow-global-stdio, and plan and sync items now carrytransportandscope. (#425) -
After a successful command, Brigade prints a one-line stderr notice at most once per 24 hours when a newer release is on PyPI. It is anonymous, TTY-only, skipped in CI, and disabled with
BRIGADE_NO_UPDATE_CHECK=1. (#426) -
brigade codeexposes the full GraphTrail verb set (callers,callees,affected,search,neighbors,dead-code,cycles,evaluate,explain,export,stats,doctor,diff) and accepts--target <dir>on every verb, so engine paths resolve against the wired project root. (#427) -
agent-notifyships inside the Brigade monorepo understations/notify/with its standalone history preserved and monorepo CI coverage, and installs as a native component throughbrigade setup. (#433, #439) -
brigade model trial execute --resumefreezes eval cell identity (cell_id,manifest_digest, attempt numbering) so resumed cells keep stable identity, reports stale cells on stderr, and allocates the next attempt from both the attempt directories andcell.jsoninstead of reusing deleted numbers. (#436) -
brigade handoff lint --content-guardflags prompt-injection heuristics with line numbers alongside the existing leak scan. (#477, #515) -
The default scanner registry schedules
brigade friction scan --jsonweekly (weekly@05:00) with cadence-aware stale thresholds for seven-day freshness. (#526) -
brigade handoff lintaccepts synonym section headings (for exampleTL;DRforSummary,KindforType) and resolves them in draft summaries. (#527) -
agent-notifyresolves the per-turn Codex model from notify metadata or the matching local rollout and includes provider identity in Discord, Telegram, and Signal messages. (#533) -
brigade rungains--scheduler {waves,dag}, a ready-queue DAG scheduler that keeps independent branches moving and skips transitive dependents of failed workers. Fail-fast stage gating is now the default and--keep-goingrestores the old run-everything behavior; a run with any failed or skipped worker recordsstatus: "incomplete"inrun.jsonand exits3.brigade work verify runreuses the newest completed receipt when the tree fingerprint and planned commands match, recordingreused_from, unless--no-reuseis passed. (#447) -
Verifier-bound skill scorecards:
brigade work verify planandbrigade work verify runaccept--manifest <id>to run tracked verifier manifests (brigade.verify_manifest.v1underverify/manifests/*.json) with effectiveness and utility-guardrail check roles, receipts stamp the manifest and patch binding plus per-command check identity, skill promotion inbrigade outcome reconcileandbrigade outcome forkis decided by a receipt-only scorecard (scorecard.v1) withroute-policy.v1bands fromunseentopromoted, and the newbrigade outcome backfill scorecardverb audits receipt eligibility read-only. (#591) -
brigade runwrites aroute-decision.jsonartifact (brigade.route-decision.v1) into every run output directory recording the chosen route, confidence, template version, and the admissible worker seats, and therouteobject inrun.jsongainsconfidenceandtemplate_version. (#547) -
brigade work verify runreceipts are bound to patch identity: each run directory gains achanges.patchartifact andreceipt.json(schema version 2) recordsbaseline_commit,tree_fingerprint(the real git tree hash, computed without touching.git/index), andchanges_patch_sha256. All three degrade tonullrather than failing the run, andbrigade work verify showprints the verified-tree binding line. (#563) -
New
.brigade/config.jsonkeycapture_before_retry(warndefault,block,off) gatesbrigade work verify run: retrying a plan whose newest matching receipt failed without a capturedbrigade outcomerecord prints a warning naming the capture command,blockexits1instead,offskips the check, and an invalid value exits2. (#560) -
brigade receipts exporttelemetry projects verify receipts asbrigade.work.verifytool spans (executable name only, never the full command text) and outcome records asbrigade.outcome.capturespans carrying artifact, signal, and cohort-scored attributes, both attached to the owning run's trace with a synthetic trace id for orphans. Run-span output is unchanged. (#569) -
brigade work briefreports anupdate_availableline when the cached update check knows of a newer release, and the brief's JSON payload carries the same data under anupdatekey (nullwhen none). The read is cache-only, never touches the network, and honorsBRIGADE_NO_UPDATE_CHECK. (#699)
Changed
- Outcome scoring counts model-quality failures against seats instead of
neutralizing them:FailureDomaingainsMODEL_OUTPUT(empty-output,
malformed-final-output, tool-only-output, non-final-output), the blanket
FailureClass-to-infrastructure fallthrough becomes an explicit allowlist,
run-level and worker-level verdicts agree for the same kind, unknown kinds
fail closed to negative, and a suspected no-op run scores negative. Scores
recompute from stored receipts at read time, so rankings can shift after
upgrading; re-read them rather than comparing across the upgrade. (#718) - Newly journal-authoritative runs derive their
run.jsoncompatibility snapshots from validated lifecycle events and recovery checkpoints, with strict projector readiness and recovery gates. (#622) - Lifecycle journals are now authoritative for every new run; existing snapshot-only directories retain their prior behavior, and compatibility snapshots remain readable by the previous v1 reader contract. (#630)
- The previous-v1-reader compatibility check now uses a versioned fixture derived from
v0.25.0, covering authoritative, paused, and legacy run snapshots. (#640) - The lifecycle journal ceiling is measured for real, representative, and configurable worst-case runs, with the current decision to raise the bound rather than segment journals. (#642)
- Worker infrastructure failures no longer lower skill scores. Friction records
carryfailure.classaserror_classwith an optional adaptercause_code,
and a run that failed only for infrastructure reasons produces neutral
artifact evidence while retaining its evidence reference. Verifier failures
remain negative evidence and verifier success remains positive. (#682) - Outcome scores are recomputed from stored receipts at read time, so the two
classifier changes below re-score existing evidence with no new runs. Two
vocabularies now feed one classifier: run-owned failure kinds and typed
FailureClasscauses. Most visibly,timeoutexists in both, so historical
timeout failures that previously scored negative now score neutral. Rankings
produced before upgrading will differ afterward; re-read them rather than
comparing across the upgrade. (#686, #689) - Outcome capture reads the nested
failure.kindtaxonomy, retaining the legacy
top-levelfailure_kindas a fallback. Of 56 recorded failed runs, 19 carried
only the nested field and 16 carried both, which is why the fallback stays.
Classification also consults the failure phase:agent-errorand
orchestrator-errorare catch-all else-branches rather than infrastructure
evidence, so kind alone would have forgiven real model failures. (#686) - Typed
FailureClasscauses are classified as infrastructure, so a run aborted
with a typed cause is no longer scored as a skill failure. Unknown kinds still
resolve to a real failure, and model-contract kinds are matched before the
typed parse sonon-final-outputstays a model failure. (#689) - The
kimiadapter targets Kimi Code 0.28 prompt mode (kimi -p), dropping--print,--final-message-only, and the interactive--planand--yoloflags that cannot combine with-p. Read-only kimi dispatches now rely on prompt-based enforcement, andREAD_ONLY_ENFORCEMENTforkimiissoftrather thanhard. (#401) brigade doctorscopes default output to--target, hiding host-global operator checks (components, managed tools, OpenClaw, content guard) unless--operatoris passed, and prefixes target-scoped finding detail withtarget=. (#478)brigade doctorno longer assumes Claude for targets without Brigade config or an explicit--harness. Harness-native checks run only when a harness is declared, and handoff, skills, and orphan projection checks are labeled with anadapter:prefix. (#449)brigade frictionregex scans skip default denylisted suggestion and skill paths, damp prose hits in markdown outside run artifacts, and collapse identical snippets into one candidate with occurrence counts and source paths. (#473, #513)brigade receipts export miseledgernow carries stableprojectandworkspace_dirmetadata so MiseLedger project filters work across generated worktree paths. (#540)brigade releasereadiness treats open security findings and unreadable security evidence as blockers rather than warnings, naming the top finding with severity, location, and remediation. (#670)brigade skills diffdefaults to the bundled package template so a stale registry copy cannot mask drift from newer bundled skills; pass--against registryfor the previous baseline. (#514)miseledger initno longer writes an unusedconfig.toml; it creates only the private data and cache directories and opens the archive database. (#538)agent-notifyvalidatesdefaults.timeout_secondsat config load with stable field-scoped errors, and Claude Code Stop-hookcwdandsession_iddisclosures are now opt-in through[claude_code_stop](include_cwd,include_session_id, both default false). (#671)brigade security scanexcludes.brigade/**, Brigade's own state directory, by default, including whensecurity.tomlomitsexclude_paths. Writingexclude_paths = []opts back in,brigade security initwrites the exclusion into generated configs, and unknown keys insecurity.tomlare rejected instead of ignored. (#544)brigade handoff lint --content-guardfails the lint with exit1on any warning-severity injection heuristic hit instead of passing with a printed warning, and reports splitcontent_guard_egressandcontent_guard_injectionverdicts in both text and JSON output. Info-only hits still pass. (#559)
Fixed
- The security scanner's secrets detectors no longer flag their own regex
literals (the old guard pointed at a file path retired by the package split),
runtime reads (os.environ,os.getenv,secrets.*,*_from_env),
attribute reads, or guard example fixtures, and one ranked finding is emitted
per line instead of duplicates. Committed credentials still report: quoted
literals are never exempted, dotted JWT-shaped values stay flagged, and
regression tests pin both directions. (#701) - The passive update check's background version refresh runs even when stderr
is piped, so agent-only installs populate the version cache and the work
brief'supdate_availableline can actually fire; the printed notice stays
TTY-only. (#716) - A bare
brigadeinvocation prints the start-here command block before the
usage error instead of a dead end. (#720) agent-notify initnow refuses a symlinked parent before it creates or publishes its config file, publishes by hard link so an existing path is never followed, and applies permissions and fsync through the open descriptor rather than by path, closing symlink and TOCTOU write races. (#643)- Dispatch outcome writes are now bound to configured targets and report a
bounded error naming the resolved root. Missing Python interpreters suggest
python3, stale command inventory names its regeneration command, and
coverless root assignments no longer fall back to the wave scheduler. (#662) brigade outcome repairdiagnoses and repairs completed-ledger digest-chain
breaks, preserving and re-signing self-consistent records after a break
instead of discarding them. Repairs quarantine first and use binary
O_EXCLwrites. (#645)- A failed run that holds uncommitted work retains its worktree, reports the
retained path and patch-file count, and prunes that retained entry after the
next successful run for the same target. (#663) - Outcome capture now attributes receipts to the exercised skill instead of the
genericbrigade-workbucket, preferring a failed receipt's own stamp over
the current capture value. (#647) - Grok/T3 work-loop discovery no longer treats
~/.brigade(user-level aboyeur
roster) as a project work root. Hooks andwork resolve-targetrequire
.brigade/config.json, so sessions under$HOMEor unwired dirs do not
backgroundbrigade work brief --target $HOME(#537). brigade runno longer dies on the first unparsable plan when the chef's final
message is prose. The corrective plan turn now restates the output contract
("reply with the JSON plan object and nothing else") alongside the parse error,
and orchestrator seats that launch in a harness plan mode (claude, cursor, grok
under read-only) are told not to write a plan, design, or context file: the
failed write is what let user-level hooks replace the plan JSON with hook
rebuttal prose. Retries stay bounded at one correction. (#520)- Agent Pantry version parsing stays non-throwing and bounded for arbitrarily
long numeric segments: the parser accepts ASCII-numeric semver triples only,
enforces a conservative per-segment digit bound, catchesint()conversion
ValueError, and surfaces the fixedinvalid-versionlabel for oversized or
non-ASCII-digit input without ever echoing raw content. Added huge-segment and
non-ASCII-digit regressions covering observed/detail and adjacent stdout. docs/component-manifest-policy.mdno longer presents the five-component /
25-asset contract as a current stable release. It is now stated as the future
first stable manifest contract afteragent-notifypublication, with current
bundledagent-notifyassets empty/unpublished and no stable release claimed.- Lifecycle journal append, recovery, checkpoint, and shadow paths now serialize their critical sections, persist directory updates, enforce event and byte limits, and retain locks when durable enrollment state cannot be safely classified. (#624)
- Journal enrollment, partial-tail recovery, atomic writes, and redaction anchors are hardened against mid-run enrollment loss, interrupted writes, symlink races, and overlapping redaction histories. (#633)
- Recovery-checkpoint bodies are stripped from exported verification archives and replaced with privacy-safe artifact references; local recovery retains the private bodies it needs. (#646)
- Candidate outcome artifacts can recover from earlier regressions when later verified clears outnumber them in the same unchanged content-fingerprint cohort. (#648)
- Outcome scoring treats receipts linked by
reused_fromas one verification signal while retaining the append-only ledger rows. (#650) - Redaction anchor refresh is idempotent, validates split-retirement digests, and safely resumes if cleanup stops between parent retirement and child realignment. (#644)
- Outcome-ledger writers serialize digest-chain appends and preserve completed rows while recovering interrupted writes. (#612)
- Journal redaction cleanup remains retryable across the parent-retirement and child-realignment crash window. (#655)
brigade handoff lint --content-guardno longer reports a clean injection
verdict for a handoff whose text could not be read. An unreadable path now
reportsunscannedand fails that check, so neither the printed line nor the
content_guard_injectionfield can be mistaken for a passing security scan.
Readable handoffs are unaffected. (#679)- Proxy seat
_REFoverrides acceptenv-file:/absolute/path#VARIABLEreferences to load secrets from systemd-style env files. Roster validation and runtime resolution share one classifier, so a malformedenv-file:reference fails dispatch instead of silently falling through to a parent environment variable. (#411) - Branch and HEAD drift detection compares against a snapshot from the resolved
lock_workspace(the canonical checkout) rather than the assigned worktreecwdwhen the two differ, so canonical-checkout movement is detected without false positives from an isolated worktree. (#599) - Cursor model inventory captures the full
cursor-agent modelslist through a tempfile, since piped output truncates at 8 KiB, and treats the list as complete only after theTip: use --model <id>trailer, sobrigade roster doctorallow_modelschecks see every installed model. (#601) - Read-only Claude workers insert
--between the--disallowedToolsdeny list and the positional prompt, so plan text is no longer parsed as additional deny rules. (#451) - Read-only Claude workers deny
WebSearchandWebFetch, so non-interactive runs under--permission-mode planno longer stall on an approval prompt. (#461) brigade operatoradopt plans count guidance inventory entries by filesystem type, so directories such asmemory/cardsno longer inflate theguidance_filescount. (#479, #509)- Agent Pantry health messages report dev and prerelease builds as a deliberate version-policy rejection rather than a parse failure, keeping the fixed
invalid-versionlabel and never echoing raw version strings. (#480, #511) - The Claude work-loop closeout gate no longer treats detached
brigade runoutput under.brigade/orbrigade runbash commands as verification writes that bumplast_verification_write_at. (#483, #516) brigade harness syncupgrades a legacy version-1~/.cursor/brigade/install-state.jsonto profile schema v2 instead of deadlocking, preserving files, hooks, and MCP attestations so uninstall still works. (#510)brigade work hooks installadopts legacybrigade-work-loop.pyhandlers found in an unwired~/.claude/settings.json, and refuses when.brigade/config.jsonis present but unreadable. (#525)- The Claude work-loop closeout gate treats an unavailable worktree fingerprint as a pending write and records the unavailable sentinel on every
Bashpre-hook, so mutations are not missed when git state cannot be read at bash start. (#600) brigade work verify runnames the supported fix when it rejects a shell interpreter as the verification executable. (#416)brigade outcome reconcilepreserves colliding decision receipts by writing each one exclusively with microsecond timestamps and a random token instead of overwriting the prior file. (#603)- Run sidecar files such as
worker-results.jsonandsynthesis.jsonappend immutable revisions underrevisions/instead of replacing prior evidence when updated mid-run. (#605) - The content-guard
pre-pushhook derives the exclusion set for brand-new branches fromgit ls-remoterather than stale local tracking refs, scans only commits not advertised on the remote, and batches them through--revs-stdin. (#606) - Content guard rejects unsafe
--rangeoperands for history scans while preserving valid Git revision grammar, and fails closed ongit rev-listerrors. (#677) - Component reports and install checks honor the verified exact-release manifest from
brigade setupinstead of falling back to the bundled compatibility manifest wheneverinstalled.jsondisagrees. (#408) - GraphTrail, MiseLedger, and other managed engine consumers resolve binaries through a shared
component_binsresolver (GRAPHTRAIL_BIN,MISELEDGER_BIN, theninstalled.json, thenPATH, then legacy locations) and emit absolute paths in generated Cursor MCP config and search plans. (#419) brigade work verifycatches Ctrl-C, terminates the child process group, and writes acanceledreceipt with preserved evidence instead of leaving a running receipt or printing a traceback; a repeated interrupt retries termination with zero grace. (#448)brigade work verifyarchive export validates recovery-checkpoint references, omits crashed.checkpoint.*.tmpbodies without decoding them, keeps existing archive trees immutable, and records privacy-safecheckpoint_errorsin the verify archive index when a checkpoint cannot be exported truthfully. (#668)- Lifecycle journal appends serialize across processes through
lifecycle.jsonl.lock(fcntl.flock),brigade runs steerandbrigade runs interruptrefuse completed runs instead of appending into a terminal chain, andcontrol.failedpayloads carry a bounded error class plus digest reference rather than free transport text. (#651) - The lifecycle journal event ceiling rises from 512 to 2048 with bounded runtime reads that enforce byte and event limits before allocation, and authoritative dispatch recovery reuses a stranded dispatch checkpoint instead of duplicating journal events after a crash between checkpoint write and event append. (#672)
agent-notifycaps hook and stdin reads at 256 KiB and truncates or refuses Discord, Telegram, and Signal payloads against documented ceilings, returning a boundedpayload_limitdiagnostic instead of failing delivery silently. (#618, #666)agent-notifychannel transport failures return bounded provider, stage, status, and cause fields instead of wrapped transport errors that could carry webhook URLs or bot tokens into stderr. (upstream agent-notify #8, imported via #433)brigade runrecords apre-run-snapshot.jsonof branch, HEAD, and content fingerprints, aborts with exit2andfailure_kind: "branch-head-drift"when git state drifts mid-run, rejects--allow-dirtywrite runs in a dirty primary checkout unless--worktreeis passed, and refuses Claude sandbox modes it cannot enforce:workspace-writeand implicit sandboxes now fail dispatch asunsupported-sandboxinstead of launching unsandboxed. (#440)- Security finding fingerprints are content-addressed by rule, path, normalized excerpt, and occurrence index, so suppressions survive edits above a finding. Legacy line-based fingerprints are kept as aliases and auto-migrated through
.brigade/security/fingerprint-migration-map.json, andexclude_pathspatterns with a trailing/**now exclude the prefix and all of its descendants. (#539) brigade work verify run --captureauto-exports pending receipts and imports them into MiseLedger after capture, fail-open and never changing the verify exit code, and thebrigade receipts export miseledgercursor advances only after a successful import, so a failed or missingmiseledgerbinary no longer silently drops receipts from later exports. (#552)brigade handoff lintaccepts near-miss section headings such as## TYPEor## Summary:and recognized synonyms, resolving them to the canonical section with a warning and ause ## <canonical>hint instead of failing, and warns when sections appear out of canonical order. (#558)- Reused
brigade work verify runreceipts stampharness_sessionfrom the caller'sBRIGADE_CLAUDE_SESSION, so a receipt-reuse cache hit no longer drops the session fingerprint that a fresh run records. (#551) - Research config loading no longer fails under a no-site Python 3.10 where the third-party
tomlifallback is unavailable;brigade.research.confignow reads through the bundledtoml_compatparser. (#549) - Evidence-ledger search with a
--projectfilter no longer scans the whole archive: the FTS query pins the materialized candidate set as the outer loop, so project and other correlated metadata filters are evaluated only against FTS candidates. (#548) brigade repossweep subprocesses put the source root rather than the package directory onPYTHONPATH, so built-in sweep commands can importbrigadefrom a source checkout without installation. (#545)
Removed
- Removed the opt-in
brigade run --deliberategrounded-deliberation mode
(planner,brigade.deliberation.v1artifact emission, and related runs
show/watch/resume surfaces). Recoverable from git history; see #442 / #471. - The
BRIGADE_RUN_JOURNAL_AUTHORITYenvironment flag is no longer needed or read at runtime because journal authority is the default for new runs. (#630)