Skip to content

Commit 1d0a0b2

Browse files
authored
Merge pull request #37 from escoffier-labs/feat/work-import-inbox
feat: add work import inbox
2 parents 802b6b8 + 1895a58 commit 1d0a0b2

6 files changed

Lines changed: 554 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4545
- `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.
4646
- `brigade work tasks` plus `brigade work task add/show/done` to manage a gitignored local task ledger under `.brigade/work/tasks.json`.
4747
- `brigade work run --queue-next` to queue the successful run's extracted next step, with duplicate pending task protection.
48+
- `brigade work import add/list/show/promote` to manage a gitignored local import inbox for scanner-discovered candidate work.
49+
- `ROADMAP.md` covering the daily-driver path, scanner-ready inbox, chat-surface scanners, memory-card decay refresh, and portable operator setup.
4850
- `brigade work note` to append timestamped checkpoints to the active work session without ending it.
4951
- `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.
5052
- Workspace installs now include `.brigade/memory-care.example.json` as a scanner wiring contract for memory-care decay output.
@@ -59,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5961
- 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.
6062
- `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.
6163
- `brigade work task add --from-next` now reuses an equivalent pending task instead of adding duplicates.
64+
- `brigade work brief` now includes pending local work imports in both text and JSON output.
6265
- The managed gitignore block now treats `.brigade/dogfood.toml` and `.brigade/runs/` as local state.
6366
- Live smoke docs now keep Codex agent execution in a trusted repo cwd while writing temporary roster, artifacts, and handoff output under `/tmp`.
6467
- Handoff write failures now preserve final run artifacts, print the final answer, return nonzero, and mark `run.json` as `handoff-failed`.

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ The cookbook explains the why. This package gives you the kitchen.
4646

4747
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.
4848

49+
See [`ROADMAP.md`](ROADMAP.md) for the daily-driver, scanner inbox, chat-surface scanner, and memory-card decay roadmap.
50+
4951
## What you do not get
5052

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

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

181-
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`.
186+
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`.
182187

183188
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.
184189

ROADMAP.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Brigade Roadmap
2+
3+
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.
4+
5+
## Current Phase: Daily Driver
6+
7+
Status: in progress.
8+
9+
- Local dogfood defaults live in gitignored `.brigade/dogfood.toml`.
10+
- `brigade work bootstrap` prepares a repo for the daily loop.
11+
- `brigade work brief` is the start-of-day entrypoint.
12+
- `brigade work run` wraps a dogfood run in local work-session artifacts and handoffs.
13+
- `brigade work tasks` plus `brigade work task add/show/done` provide a gitignored local task ledger.
14+
- `brigade work run --queue-next` queues extracted follow-up work without duplicating equivalent pending tasks.
15+
- `brigade work import add/list/show/promote` gives scanners and wrappers a stable local inbox for candidate work.
16+
17+
## Next Phase: Scanner-Ready Inbox
18+
19+
Goal: make Brigade a safe target for local automations that discover useful work.
20+
21+
- Keep raw scanner output private and gitignored under `.brigade/work/imports/`.
22+
- Normalize imports into small records with `kind`, `source`, text, timestamps, and metadata.
23+
- Let wrappers import candidate tasks, findings, decisions, preferences, incidents, links, and commands without knowing Brigade internals.
24+
- Promote selected imports into the work task ledger, with source metadata preserved.
25+
- Surface pending imports in `brigade work brief` so discovered work appears in the daily flow.
26+
27+
## Later Phase: Chat Surface Scanners
28+
29+
Goal: support the common places agent work happens without making any one chat product mandatory.
30+
31+
- Build adapters for Discord, Slack, Telegram, and export-based chat archives as separate scanner layers.
32+
- Convert surface-specific events into the local import inbox instead of writing memory directly.
33+
- Summarize private chat evidence, do not quote raw third-party messages into public docs or handoffs.
34+
- Use promotion gates so only reviewed, durable, or actionable items become tasks or memory handoffs.
35+
- Keep source metadata such as workspace, channel, thread, message range, and confidence local unless explicitly exported.
36+
37+
## Later Phase: Memory Card Decay And Refresh
38+
39+
Goal: prevent durable memory from silently rotting.
40+
41+
- Track freshness metadata, confidence, evidence, and review dates for memory cards.
42+
- Run memory-care scanners that detect expired, stale, contradictory, or undersourced cards.
43+
- Import refresh candidates into Brigade as local work imports.
44+
- Promote refresh candidates into tasks or memory handoffs after review.
45+
- Auto-fix only within safe gates where source evidence is current, low-risk, and locally reviewable.
46+
- Treat bootstrap truncation as a hard failure. Bootstrap files stay slim, cards hold durable detail, and doctor checks enforce the boundary.
47+
48+
## Later Phase: Portable Operator Setup
49+
50+
Goal: keep the system usable by the original operator while making it adaptable by others.
51+
52+
- Keep Codex-first defaults, with Claude Code, OpenCode, Hermes, OpenClaw, and generic harness paths supported through writer-specific inboxes.
53+
- Make local paths configurable and gitignored.
54+
- Provide templates for fresh-start users without publishing private workspace state.
55+
- Keep public repo docs focused on patterns, commands, and safety contracts.
56+
- Leave release, tag, push-to-main, and production-impacting actions behind explicit approval gates.

src/brigade/cli.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,36 @@ def _build_parser() -> argparse.ArgumentParser:
156156
p_work_task_done = task_sub.add_parser("done", help="Mark one work task done.")
157157
p_work_task_done.add_argument("task_id", help="Task id or unique prefix.")
158158
p_work_task_done.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
159+
p_work_import = work_sub.add_parser("import", help="Add, list, show, or promote scanner-ready work imports.")
160+
import_sub = p_work_import.add_subparsers(dest="import_command", metavar="<import-command>")
161+
import_sub.required = True
162+
p_work_import_add = import_sub.add_parser("add", help="Add a local work import.")
163+
p_work_import_add.add_argument("text", nargs="+", help="Import text.")
164+
p_work_import_add.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
165+
p_work_import_add.add_argument(
166+
"--kind",
167+
choices=["task", "finding", "decision", "preference", "incident", "link", "command"],
168+
default="task",
169+
help="Import kind.",
170+
)
171+
p_work_import_add.add_argument("--source", default="manual", help="Import source such as slack, discord, or memory-care.")
172+
p_work_import_add.add_argument(
173+
"--metadata",
174+
action="append",
175+
default=[],
176+
help="Metadata as key=value. May be repeated.",
177+
)
178+
p_work_import_list = import_sub.add_parser("list", help="List local work imports.")
179+
p_work_import_list.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to inspect.")
180+
p_work_import_list.add_argument("--all", action="store_true", help="Include promoted imports.")
181+
p_work_import_list.add_argument("--json", action="store_true", help="Print machine-readable JSON.")
182+
p_work_import_list.add_argument("--limit", type=int, default=20, help="Maximum imports to show.")
183+
p_work_import_show = import_sub.add_parser("show", help="Show one work import.")
184+
p_work_import_show.add_argument("import_id", help="Import id or unique prefix.")
185+
p_work_import_show.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to inspect.")
186+
p_work_import_promote = import_sub.add_parser("promote", help="Promote one work import into the task ledger.")
187+
p_work_import_promote.add_argument("import_id", help="Import id or unique prefix.")
188+
p_work_import_promote.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to update.")
159189
p_work_list = work_sub.add_parser("list", help="List recent Brigade work sessions.")
160190
p_work_list.add_argument("--target", "-t", type=Path, default=Path("."), help="Repo or workspace to inspect.")
161191
p_work_list.add_argument("--limit", type=int, default=10, help="Maximum sessions to show.")
@@ -510,6 +540,28 @@ def main(argv=None) -> int:
510540
return work_cmd.task_done(target=args.target, task_id=args.task_id)
511541
parser.error(f"unknown task command: {args.task_command}")
512542
return 2
543+
if args.work_command == "import":
544+
if args.import_command == "add":
545+
return work_cmd.import_add(
546+
target=args.target,
547+
text=" ".join(args.text),
548+
kind=args.kind,
549+
source=args.source,
550+
metadata=args.metadata,
551+
)
552+
if args.import_command == "list":
553+
return work_cmd.import_list(
554+
target=args.target,
555+
all_imports=args.all,
556+
json_output=args.json,
557+
limit=args.limit,
558+
)
559+
if args.import_command == "show":
560+
return work_cmd.import_show(target=args.target, import_id=args.import_id)
561+
if args.import_command == "promote":
562+
return work_cmd.import_promote(target=args.target, import_id=args.import_id)
563+
parser.error(f"unknown import command: {args.import_command}")
564+
return 2
513565
if args.work_command == "list":
514566
return work_cmd.list_sessions(target=args.target, limit=args.limit)
515567
if args.work_command == "latest":

0 commit comments

Comments
 (0)