Skip to content

v0.26.0

Choose a tag to compare

@github-actions github-actions released this 06 Aug 02:26
· 213 commits to main since this release
658ce9c

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.toml of its own, brigade run and roster doctor fall
    back to the parent clone's roster (new worktree-parent source, 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 init refuses 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 --force to scaffold a
    workspace roster anyway. brigade research now 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 (default project, 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 init command 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 --json carries the same available_update field 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, and release doctor warns when
    pyproject declares a version with no matching git tag, catching
    version-bump-without-release before it ships. (#719)

  • docs/outcome-scoring.md documents read-time re-scoring and the full failure
    kind-to-verdict table. (#718)

  • brigade runs audit provides 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.jsonl entry (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-declared digests.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), and verify_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_target helper used by Claude hooks and
    the new resolver CLI; optional harness filter.

  • Grok work-loop hook templates under src/brigade/templates/grok/hooks/ that
    use resolve-target, timeout the session brief, and do not deny edits while
    a brief is running (#537).

  • Imported stations/notify Go module into the Brigade monorepo. Unified release
    manifests now enumerate five native components (25 platform assets plus
    component-manifest-v1.json and checksums.txt) with managed resolution
    through brigade setup.

  • Beta pre-pin compatibility: beta installs the CI-green main Brigade wheel but
    reuses the last verified stable component manifest; agent-notify is 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 pantry requires agentpantry version --json >=0.5.0 before invoking doctor, status, or inventory
    surfaces. Pantry remains an external Go binary.

  • The append-only lifecycle journal now defines the canonical brigade.run_event.v1 event 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.json snapshots 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.json contract. (#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.json replacements, 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 redact provides 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 events exposes lifecycle-only NDJSON with opaque durable cursors, and runs steer and runs interrupt accept 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.json beside 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-seat purpose, requires, fallback, stats, and caveats metadata, with one-hop capability-based fallback resolution when host requirements are not met. (#454)

  • brigade roster suggest --preset NAME assembles a preset roster from installed host capabilities, emitting per-seat resolution lines and substituting local receipt stats when available, and brigade roster stats summarizes per-seat median duration and failure rate from local worker receipts. (#463)

  • brigade model trial regrade OUTPUT_DIR re-runs graders from stored trial output without re-running seats. Trial summaries record measurement_failures and partial_scores, cells carry failure_reason, and trial processes exit 3 when measurement failures are present, 1 for rejected or execution errors, and 0 otherwise. (#457)

  • The oracle CLI adapter (cli = "oracle") runs browser research via oracle --engine browser, reports stale cookie auth with a brigade pantry next step instead of workspace-trust, and lets a researcher seat's timeout_seconds raise the research engine LLM timeout floor. (#535)

  • run.json records a scheduler block with requested, used, and fallback_reason, written at run start and filled when dispatch resolves the effective scheduler (--scheduler, then limits.scheduler, then waves), 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 failure object (brigade.worker_failure.v1) with failure_class, phase, and retry_disposition, mapped from the legacy failure_kind and failure_phase fields. (#589)

  • brigade roster doctor runs 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-bridge exposes discover, call, install, and uninstall to project the canonical .brigade/mcp.json catalog into Pi's managed extension at ~/.pi/agent, names tools server__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 install accepts --surface cursor-cli|cursor-gui to 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, and brigade harness doctor support 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 user covers all seven harnesses. (#467)

  • brigade evidence show, brigade evidence explain, and brigade evidence stats query the evidence ledger without invoking the engine binary directly; help, status, doctor, and plan text use the evidence engine branding, timeouts honor BRIGADE_EVIDENCE_TIMEOUT_SECONDS and BRIGADE_EVIDENCE_STATUS_TIMEOUT_SECONDS, and exit 124 prints a retry hint that doubles the current timeout. (#430)

  • brigade mcp sync --user-scope and brigade operator sync-mcp --user-scope no 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 --json runs require --allow-global-stdio, and plan and sync items now carry transport and scope. (#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 code exposes 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-notify ships inside the Brigade monorepo under stations/notify/ with its standalone history preserved and monorepo CI coverage, and installs as a native component through brigade setup. (#433, #439)

  • brigade model trial execute --resume freezes 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 and cell.json instead of reusing deleted numbers. (#436)

  • brigade handoff lint --content-guard flags prompt-injection heuristics with line numbers alongside the existing leak scan. (#477, #515)

  • The default scanner registry schedules brigade friction scan --json weekly (weekly@05:00) with cadence-aware stale thresholds for seven-day freshness. (#526)

  • brigade handoff lint accepts synonym section headings (for example TL;DR for Summary, Kind for Type) and resolves them in draft summaries. (#527)

  • agent-notify resolves 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 run gains --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-going restores the old run-everything behavior; a run with any failed or skipped worker records status: "incomplete" in run.json and exits 3. brigade work verify run reuses the newest completed receipt when the tree fingerprint and planned commands match, recording reused_from, unless --no-reuse is passed. (#447)

  • Verifier-bound skill scorecards: brigade work verify plan and brigade work verify run accept --manifest <id> to run tracked verifier manifests (brigade.verify_manifest.v1 under verify/manifests/*.json) with effectiveness and utility-guardrail check roles, receipts stamp the manifest and patch binding plus per-command check identity, skill promotion in brigade outcome reconcile and brigade outcome fork is decided by a receipt-only scorecard (scorecard.v1) with route-policy.v1 bands from unseen to promoted, and the new brigade outcome backfill scorecard verb audits receipt eligibility read-only. (#591)

  • brigade run writes a route-decision.json artifact (brigade.route-decision.v1) into every run output directory recording the chosen route, confidence, template version, and the admissible worker seats, and the route object in run.json gains confidence and template_version. (#547)

  • brigade work verify run receipts are bound to patch identity: each run directory gains a changes.patch artifact and receipt.json (schema version 2) records baseline_commit, tree_fingerprint (the real git tree hash, computed without touching .git/index), and changes_patch_sha256. All three degrade to null rather than failing the run, and brigade work verify show prints the verified-tree binding line. (#563)

  • New .brigade/config.json key capture_before_retry (warn default, block, off) gates brigade work verify run: retrying a plan whose newest matching receipt failed without a captured brigade outcome record prints a warning naming the capture command, block exits 1 instead, off skips the check, and an invalid value exits 2. (#560)

  • brigade receipts export telemetry projects verify receipts as brigade.work.verify tool spans (executable name only, never the full command text) and outcome records as brigade.outcome.capture spans 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 brief reports an update_available line when the cached update check knows of a newer release, and the brief's JSON payload carries the same data under an update key (null when none). The read is cache-only, never touches the network, and honors BRIGADE_NO_UPDATE_CHECK. (#699)

Changed

  • Outcome scoring counts model-quality failures against seats instead of
    neutralizing them: FailureDomain gains MODEL_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.json compatibility 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
    carry failure.class as error_class with an optional adapter cause_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
    FailureClass causes. Most visibly, timeout exists 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.kind taxonomy, retaining the legacy
    top-level failure_kind as 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-error and
    orchestrator-error are catch-all else-branches rather than infrastructure
    evidence, so kind alone would have forgiven real model failures. (#686)
  • Typed FailureClass causes 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 so non-final-output stays a model failure. (#689)
  • The kimi adapter targets Kimi Code 0.28 prompt mode (kimi -p), dropping --print, --final-message-only, and the interactive --plan and --yolo flags that cannot combine with -p. Read-only kimi dispatches now rely on prompt-based enforcement, and READ_ONLY_ENFORCEMENT for kimi is soft rather than hard. (#401)
  • brigade doctor scopes default output to --target, hiding host-global operator checks (components, managed tools, OpenClaw, content guard) unless --operator is passed, and prefixes target-scoped finding detail with target=. (#478)
  • brigade doctor no 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 an adapter: prefix. (#449)
  • brigade friction regex 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 miseledger now carries stable project and workspace_dir metadata so MiseLedger project filters work across generated worktree paths. (#540)
  • brigade release readiness 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 diff defaults to the bundled package template so a stale registry copy cannot mask drift from newer bundled skills; pass --against registry for the previous baseline. (#514)
  • miseledger init no longer writes an unused config.toml; it creates only the private data and cache directories and opens the archive database. (#538)
  • agent-notify validates defaults.timeout_seconds at config load with stable field-scoped errors, and Claude Code Stop-hook cwd and session_id disclosures are now opt-in through [claude_code_stop] (include_cwd, include_session_id, both default false). (#671)
  • brigade security scan excludes .brigade/**, Brigade's own state directory, by default, including when security.toml omits exclude_paths. Writing exclude_paths = [] opts back in, brigade security init writes the exclusion into generated configs, and unknown keys in security.toml are rejected instead of ignored. (#544)
  • brigade handoff lint --content-guard fails the lint with exit 1 on any warning-severity injection heuristic hit instead of passing with a printed warning, and reports split content_guard_egress and content_guard_injection verdicts 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's update_available line can actually fire; the printed notice stays
    TTY-only. (#716)
  • A bare brigade invocation prints the start-here command block before the
    usage error instead of a dead end. (#720)
  • agent-notify init now 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 repair diagnoses 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_EXCL writes. (#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
    generic brigade-work bucket, 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 and work resolve-target require
    .brigade/config.json, so sessions under $HOME or unwired dirs do not
    background brigade work brief --target $HOME (#537).
  • brigade run no 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, catches int() conversion
    ValueError, and surfaces the fixed invalid-version label 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.md no longer presents the five-component /
    25-asset contract as a current stable release. It is now stated as the future
    first stable manifest contract after agent-notify publication, with current
    bundled agent-notify assets 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_from as 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-guard no longer reports a clean injection
    verdict for a handoff whose text could not be read. An unreadable path now
    reports unscanned and fails that check, so neither the printed line nor the
    content_guard_injection field can be mistaken for a passing security scan.
    Readable handoffs are unaffected. (#679)
  • Proxy seat _REF overrides accept env-file:/absolute/path#VARIABLE references to load secrets from systemd-style env files. Roster validation and runtime resolution share one classifier, so a malformed env-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 worktree cwd when 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 models list through a tempfile, since piped output truncates at 8 KiB, and treats the list as complete only after the Tip: use --model <id> trailer, so brigade roster doctor allow_models checks see every installed model. (#601)
  • Read-only Claude workers insert -- between the --disallowedTools deny list and the positional prompt, so plan text is no longer parsed as additional deny rules. (#451)
  • Read-only Claude workers deny WebSearch and WebFetch, so non-interactive runs under --permission-mode plan no longer stall on an approval prompt. (#461)
  • brigade operator adopt plans count guidance inventory entries by filesystem type, so directories such as memory/cards no longer inflate the guidance_files count. (#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-version label and never echoing raw version strings. (#480, #511)
  • The Claude work-loop closeout gate no longer treats detached brigade run output under .brigade/ or brigade run bash commands as verification writes that bump last_verification_write_at. (#483, #516)
  • brigade harness sync upgrades a legacy version-1 ~/.cursor/brigade/install-state.json to profile schema v2 instead of deadlocking, preserving files, hooks, and MCP attestations so uninstall still works. (#510)
  • brigade work hooks install adopts legacy brigade-work-loop.py handlers found in an unwired ~/.claude/settings.json, and refuses when .brigade/config.json is 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 Bash pre-hook, so mutations are not missed when git state cannot be read at bash start. (#600)
  • brigade work verify run names the supported fix when it rejects a shell interpreter as the verification executable. (#416)
  • brigade outcome reconcile preserves 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.json and synthesis.json append immutable revisions under revisions/ instead of replacing prior evidence when updated mid-run. (#605)
  • The content-guard pre-push hook derives the exclusion set for brand-new branches from git ls-remote rather than stale local tracking refs, scans only commits not advertised on the remote, and batches them through --revs-stdin. (#606)
  • Content guard rejects unsafe --range operands for history scans while preserving valid Git revision grammar, and fails closed on git rev-list errors. (#677)
  • Component reports and install checks honor the verified exact-release manifest from brigade setup instead of falling back to the bundled compatibility manifest whenever installed.json disagrees. (#408)
  • GraphTrail, MiseLedger, and other managed engine consumers resolve binaries through a shared component_bins resolver (GRAPHTRAIL_BIN, MISELEDGER_BIN, then installed.json, then PATH, then legacy locations) and emit absolute paths in generated Cursor MCP config and search plans. (#419)
  • brigade work verify catches Ctrl-C, terminates the child process group, and writes a canceled receipt with preserved evidence instead of leaving a running receipt or printing a traceback; a repeated interrupt retries termination with zero grace. (#448)
  • brigade work verify archive export validates recovery-checkpoint references, omits crashed .checkpoint.*.tmp bodies without decoding them, keeps existing archive trees immutable, and records privacy-safe checkpoint_errors in 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 steer and brigade runs interrupt refuse completed runs instead of appending into a terminal chain, and control.failed payloads 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-notify caps hook and stdin reads at 256 KiB and truncates or refuses Discord, Telegram, and Signal payloads against documented ceilings, returning a bounded payload_limit diagnostic instead of failing delivery silently. (#618, #666)
  • agent-notify channel 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 run records a pre-run-snapshot.json of branch, HEAD, and content fingerprints, aborts with exit 2 and failure_kind: "branch-head-drift" when git state drifts mid-run, rejects --allow-dirty write runs in a dirty primary checkout unless --worktree is passed, and refuses Claude sandbox modes it cannot enforce: workspace-write and implicit sandboxes now fail dispatch as unsupported-sandbox instead 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, and exclude_paths patterns with a trailing /** now exclude the prefix and all of its descendants. (#539)
  • brigade work verify run --capture auto-exports pending receipts and imports them into MiseLedger after capture, fail-open and never changing the verify exit code, and the brigade receipts export miseledger cursor advances only after a successful import, so a failed or missing miseledger binary no longer silently drops receipts from later exports. (#552)
  • brigade handoff lint accepts near-miss section headings such as ## TYPE or ## Summary: and recognized synonyms, resolving them to the canonical section with a warning and a use ## <canonical> hint instead of failing, and warns when sections appear out of canonical order. (#558)
  • Reused brigade work verify run receipts stamp harness_session from the caller's BRIGADE_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 tomli fallback is unavailable; brigade.research.config now reads through the bundled toml_compat parser. (#549)
  • Evidence-ledger search with a --project filter 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 repos sweep subprocesses put the source root rather than the package directory on PYTHONPATH, so built-in sweep commands can import brigade from a source checkout without installation. (#545)

Removed

  • Removed the opt-in brigade run --deliberate grounded-deliberation mode
    (planner, brigade.deliberation.v1 artifact emission, and related runs
    show/watch/resume surfaces). Recoverable from git history; see #442 / #471.
  • The BRIGADE_RUN_JOURNAL_AUTHORITY environment flag is no longer needed or read at runtime because journal authority is the default for new runs. (#630)