Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `brigade work brief` and `brigade work brief --json` as a start-of-day entrypoint with git state, latest sessions, latest dogfood run, resolved next task, and suggested command.
- `brigade work tasks` plus `brigade work task add/show/done` to manage a gitignored local task ledger under `.brigade/work/tasks.json`.
- `brigade work run --queue-next` to queue the successful run's extracted next step, with duplicate pending task protection.
- `brigade work import add/list/show/promote` to manage a gitignored local import inbox for scanner-discovered candidate work.
- `ROADMAP.md` covering the daily-driver path, scanner-ready inbox, chat-surface scanners, memory-card decay refresh, and portable operator setup.
- `brigade work note` to append timestamped checkpoints to the active work session without ending it.
- `brigade work doctor` to check dogfood config, Codex availability, local artifact paths, handoff inbox, ignore coverage, and latest run context for the daily work loop.
- Workspace installs now include `.brigade/memory-care.example.json` as a scanner wiring contract for memory-care decay output.
Expand All @@ -59,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dogfood next-step extraction now handles markdown `## Next` sections and can fall back to `summary.md` when `final.txt` does not contain a next-step label.
- `brigade work run` now consumes the oldest pending ledger task before falling back to the latest extracted dogfood next step, and marks consumed tasks done after successful runs.
- `brigade work task add --from-next` now reuses an equivalent pending task instead of adding duplicates.
- `brigade work brief` now includes pending local work imports in both text and JSON output.
- The managed gitignore block now treats `.brigade/dogfood.toml` and `.brigade/runs/` as local state.
- Live smoke docs now keep Codex agent execution in a trusted repo cwd while writing temporary roster, artifacts, and handoff output under `/tmp`.
- Handoff write failures now preserve final run artifacts, print the final answer, return nonzero, and mark `run.json` as `handoff-failed`.
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ The cookbook explains the why. This package gives you the kitchen.

Browse the public template index in [`templates/`](templates/). The installable source files live under `src/brigade/templates/`; root workspace files are local dogfood state and stay ignored.

See [`ROADMAP.md`](ROADMAP.md) for the daily-driver, scanner inbox, chat-surface scanner, and memory-card decay roadmap.

## What you do not get

- private hostnames, IPs, account IDs, or personal details
Expand Down Expand Up @@ -148,6 +150,9 @@ brigade work tasks
brigade work task add "build the next slice"
brigade work task add --from-next
brigade work task done <task-id>
brigade work import add --kind task --source slack "refresh the stale memory card"
brigade work import list
brigade work import promote <import-id>
brigade work run
brigade work run --queue-next
brigade work run "review today's changes"
Expand Down Expand Up @@ -178,7 +183,7 @@ CLI runs write artifacts by default under `.brigade/runs/<id>` below `--cwd`; do

Use `--output-dir <path>` to pick the artifact directory, or `--no-artifacts` for a throwaway run.

Use `brigade work bootstrap` once in a repo to initialize the daily loop: it writes or verifies `.brigade/dogfood.toml`, creates local run and work artifact directories, creates the configured handoff inbox, updates the managed `.gitignore` block, and reports whether the repo is ready to run. Use `brigade work brief` as the normal start-of-day command. It shows branch and dirty-file state, active and latest work sessions, pending local tasks, latest dogfood run, extracted next task, recent sessions, and the command to continue; add `--json` for wrappers. Use `brigade work tasks` to list the local task ledger stored in `.brigade/work/tasks.json`, `brigade work task add "..."` to queue work manually, `brigade work task add --from-next` to promote the latest extracted dogfood next step, and `brigade work task done <task-id>` to close queued work. Use `brigade work status` as the quick daily dashboard for a repo. It reports the current branch, dirty files, dogfood readiness, configured dogfood paths, latest dogfood run, and extracted next step without starting a new orchestration. Use `brigade work doctor` to check whether the repo is ready for the daily loop: dogfood config, Codex CLI, local artifact paths, handoff inbox, ignore coverage, and latest run context. Use `brigade work resume` when returning to a repo; it shows the active or latest work session, latest dogfood run, extracted next step, and the suggested command to continue. Use `brigade work next` when you only need the task Brigade would run next, or `brigade work next --json` for wrappers that want the active session, dogfood snapshot, resolved task, and suggested command as structured output. `brigade work run` is the one-command daily loop: it starts a work session, consumes the oldest pending ledger task when no task is passed, otherwise uses the latest extracted dogfood next step, runs `brigade dogfood`, marks consumed ledger tasks done after successful runs, ends the session, writes a work-session Memory Handoff by default, and prints a compact recap. Add `--queue-next` to queue the successful run's extracted next step for the next session; duplicate pending task text is reused instead of added again. Pass a task to override the resolved next step, `--title` to name the session, `--no-handoff` to skip the work handoff, or `--dogfood-handoff` to also let the underlying dogfood run write its own handoff. `brigade work start "title"` opens a local work session under `.brigade/work/<id>/`, records the starting git and dogfood context, and writes `start.md`. `brigade work note "checkpoint"` appends a timestamped note to the active session without ending it. `brigade work end --note "what happened"` closes the active session, records ending context, and writes `end.md`. Add `--handoff` to also write a Memory Handoff for the closed session; it defaults to the configured dogfood handoff inbox or `.codex/memory-handoffs`.
Use `brigade work bootstrap` once in a repo to initialize the daily loop: it writes or verifies `.brigade/dogfood.toml`, creates local run and work artifact directories, creates the configured handoff inbox, updates the managed `.gitignore` block, and reports whether the repo is ready to run. Use `brigade work brief` as the normal start-of-day command. It shows branch and dirty-file state, active and latest work sessions, pending local tasks, pending local imports, latest dogfood run, extracted next task, recent sessions, and the command to continue; add `--json` for wrappers. Use `brigade work tasks` to list the local task ledger stored in `.brigade/work/tasks.json`, `brigade work task add "..."` to queue work manually, `brigade work task add --from-next` to promote the latest extracted dogfood next step, and `brigade work task done <task-id>` to close queued work. Use `brigade work import add "..."` as a scanner-ready local inbox for candidate tasks, findings, decisions, preferences, incidents, links, and commands from systems such as chat crawlers or memory-care decay scans; imports are stored under `.brigade/work/imports/inbox.jsonl`, stay gitignored, and do not write memory directly. Use `brigade work import list`, `brigade work import show <import-id>`, and `brigade work import promote <import-id>` to review and promote an import into the task ledger with source metadata preserved. Use `brigade work status` as the quick daily dashboard for a repo. It reports the current branch, dirty files, dogfood readiness, configured dogfood paths, latest dogfood run, and extracted next step without starting a new orchestration. Use `brigade work doctor` to check whether the repo is ready for the daily loop: dogfood config, Codex CLI, local artifact paths, handoff inbox, ignore coverage, and latest run context. Use `brigade work resume` when returning to a repo; it shows the active or latest work session, latest dogfood run, extracted next step, and the suggested command to continue. Use `brigade work next` when you only need the task Brigade would run next, or `brigade work next --json` for wrappers that want the active session, dogfood snapshot, resolved task, and suggested command as structured output. `brigade work run` is the one-command daily loop: it starts a work session, consumes the oldest pending ledger task when no task is passed, otherwise uses the latest extracted dogfood next step, runs `brigade dogfood`, marks consumed ledger tasks done after successful runs, ends the session, writes a work-session Memory Handoff by default, and prints a compact recap. Add `--queue-next` to queue the successful run's extracted next step for the next session; duplicate pending task text is reused instead of added again. Pass a task to override the resolved next step, `--title` to name the session, `--no-handoff` to skip the work handoff, or `--dogfood-handoff` to also let the underlying dogfood run write its own handoff. `brigade work start "title"` opens a local work session under `.brigade/work/<id>/`, records the starting git and dogfood context, and writes `start.md`. `brigade work note "checkpoint"` appends a timestamped note to the active session without ending it. `brigade work end --note "what happened"` closes the active session, records ending context, and writes `end.md`. Add `--handoff` to also write a Memory Handoff for the closed session; it defaults to the configured dogfood handoff inbox or `.codex/memory-handoffs`.

Memory and bootstrap readiness are part of the same operating-system health story. `brigade doctor` checks installed bootstrap files against built-in hard byte budgets so overgrown files fail before agents load truncated context. It also checks `memory/cards/*.md` budgets, verifies that `MEMORY.md` card links resolve under `memory/cards/`, and reports memory-care freshness from `memory/cards/decay/scan-latest.json`. Workspace installs include `.brigade/memory-care.example.json` as a scanner wiring contract for whatever scheduler or memory owner produces the decay files. Missing memory-care decay state is advisory for fresh installs, but corrupt scan or refresh-queue JSON fails once the loop is wired. Bootstrap truncation is treated as a hard failure to prevent, not a cosmetic warning; keep cards atomic and bootstrap files as slim indexes.

Expand Down
56 changes: 56 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Brigade Roadmap

Brigade is being built as a practical daily workflow first, then a portable setup other people can adapt. The core direction is an organized version of real agent work: one command to start, predictable local artifacts, reviewable memory handoffs, and enough inspection to trust the loop during normal work.

## Current Phase: Daily Driver

Status: in progress.

- Local dogfood defaults live in gitignored `.brigade/dogfood.toml`.
- `brigade work bootstrap` prepares a repo for the daily loop.
- `brigade work brief` is the start-of-day entrypoint.
- `brigade work run` wraps a dogfood run in local work-session artifacts and handoffs.
- `brigade work tasks` plus `brigade work task add/show/done` provide a gitignored local task ledger.
- `brigade work run --queue-next` queues extracted follow-up work without duplicating equivalent pending tasks.
- `brigade work import add/list/show/promote` gives scanners and wrappers a stable local inbox for candidate work.

## Next Phase: Scanner-Ready Inbox

Goal: make Brigade a safe target for local automations that discover useful work.

- Keep raw scanner output private and gitignored under `.brigade/work/imports/`.
- Normalize imports into small records with `kind`, `source`, text, timestamps, and metadata.
- Let wrappers import candidate tasks, findings, decisions, preferences, incidents, links, and commands without knowing Brigade internals.
- Promote selected imports into the work task ledger, with source metadata preserved.
- Surface pending imports in `brigade work brief` so discovered work appears in the daily flow.

## Later Phase: Chat Surface Scanners

Goal: support the common places agent work happens without making any one chat product mandatory.

- Build adapters for Discord, Slack, Telegram, and export-based chat archives as separate scanner layers.
- Convert surface-specific events into the local import inbox instead of writing memory directly.
- Summarize private chat evidence, do not quote raw third-party messages into public docs or handoffs.
- Use promotion gates so only reviewed, durable, or actionable items become tasks or memory handoffs.
- Keep source metadata such as workspace, channel, thread, message range, and confidence local unless explicitly exported.

## Later Phase: Memory Card Decay And Refresh

Goal: prevent durable memory from silently rotting.

- Track freshness metadata, confidence, evidence, and review dates for memory cards.
- Run memory-care scanners that detect expired, stale, contradictory, or undersourced cards.
- Import refresh candidates into Brigade as local work imports.
- Promote refresh candidates into tasks or memory handoffs after review.
- Auto-fix only within safe gates where source evidence is current, low-risk, and locally reviewable.
- Treat bootstrap truncation as a hard failure. Bootstrap files stay slim, cards hold durable detail, and doctor checks enforce the boundary.

## Later Phase: Portable Operator Setup

Goal: keep the system usable by the original operator while making it adaptable by others.

- Keep Codex-first defaults, with Claude Code, OpenCode, Hermes, OpenClaw, and generic harness paths supported through writer-specific inboxes.
- Make local paths configurable and gitignored.
- Provide templates for fresh-start users without publishing private workspace state.
- Keep public repo docs focused on patterns, commands, and safety contracts.
- Leave release, tag, push-to-main, and production-impacting actions behind explicit approval gates.
52 changes: 52 additions & 0 deletions src/brigade/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,36 @@ def _build_parser() -> argparse.ArgumentParser:
p_work_task_done = task_sub.add_parser("done", help="Mark one work task done.")
p_work_task_done.add_argument("task_id", help="Task id or unique prefix.")
p_work_task_done.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
p_work_import = work_sub.add_parser("import", help="Add, list, show, or promote scanner-ready work imports.")
import_sub = p_work_import.add_subparsers(dest="import_command", metavar="<import-command>")
import_sub.required = True
p_work_import_add = import_sub.add_parser("add", help="Add a local work import.")
p_work_import_add.add_argument("text", nargs="+", help="Import text.")
p_work_import_add.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
p_work_import_add.add_argument(
"--kind",
choices=["task", "finding", "decision", "preference", "incident", "link", "command"],
default="task",
help="Import kind.",
)
p_work_import_add.add_argument("--source", default="manual", help="Import source such as slack, discord, or memory-care.")
p_work_import_add.add_argument(
"--metadata",
action="append",
default=[],
help="Metadata as key=value. May be repeated.",
)
p_work_import_list = import_sub.add_parser("list", help="List local work imports.")
p_work_import_list.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to inspect.")
p_work_import_list.add_argument("--all", action="store_true", help="Include promoted imports.")
p_work_import_list.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
p_work_import_list.add_argument("--limit", type=int, default=20, help="Maximum imports to show.")
p_work_import_show = import_sub.add_parser("show", help="Show one work import.")
p_work_import_show.add_argument("import_id", help="Import id or unique prefix.")
p_work_import_show.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to inspect.")
p_work_import_promote = import_sub.add_parser("promote", help="Promote one work import into the task ledger.")
p_work_import_promote.add_argument("import_id", help="Import id or unique prefix.")
p_work_import_promote.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
p_work_list = work_sub.add_parser("list", help="List recent Brigade work sessions.")
p_work_list.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to inspect.")
p_work_list.add_argument("--limit", type=int, default=10, help="Maximum sessions to show.")
Expand Down Expand Up @@ -510,6 +540,28 @@ def main(argv=None) -> int:
return work_cmd.task_done(target=args.target, task_id=args.task_id)
parser.error(f"unknown task command: {args.task_command}")
return 2
if args.work_command == "import":
if args.import_command == "add":
return work_cmd.import_add(
target=args.target,
text=" ".join(args.text),
kind=args.kind,
source=args.source,
metadata=args.metadata,
)
if args.import_command == "list":
return work_cmd.import_list(
target=args.target,
all_imports=args.all,
json_output=args.json,
limit=args.limit,
)
if args.import_command == "show":
return work_cmd.import_show(target=args.target, import_id=args.import_id)
if args.import_command == "promote":
return work_cmd.import_promote(target=args.target, import_id=args.import_id)
parser.error(f"unknown import command: {args.import_command}")
return 2
if args.work_command == "list":
return work_cmd.list_sessions(target=args.target, limit=args.limit)
if args.work_command == "latest":
Expand Down
Loading
Loading