brigade-cli 0.8.2__tar.gz → 0.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. brigade_cli-0.9.1/PKG-INFO +194 -0
  2. brigade_cli-0.9.1/README.md +165 -0
  3. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/pyproject.toml +1 -1
  4. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/__init__.py +1 -1
  5. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/cli.py +54 -3
  6. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/doctor.py +4 -1
  7. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/handoff_cmd.py +2 -0
  8. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/install.py +5 -1
  9. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/memory_cmd.py +22 -4
  10. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/operator_cmd.py +2 -1
  11. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/security_cmd.py +44 -1
  12. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/hermes/memory-handoff.harness.json +1 -1
  13. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/hermes/model-lanes.harness.json +1 -1
  14. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/hermes/workspace.harness.json +1 -1
  15. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/chat-memory-sweep.example.json +1 -1
  16. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/memory-care.example.json +4 -4
  17. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/policies/personal.json +1 -1
  18. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/policies/public-content.json +1 -1
  19. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/policies/public-repo.json +1 -1
  20. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/tools_cmd.py +18 -3
  21. brigade_cli-0.9.1/src/brigade_cli.egg-info/PKG-INFO +194 -0
  22. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade_cli.egg-info/SOURCES.txt +1 -0
  23. brigade_cli-0.9.1/tests/test_cli_help.py +55 -0
  24. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_memory_cmd.py +34 -1
  25. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_operator_cmd.py +8 -0
  26. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_security_cmd.py +23 -0
  27. brigade_cli-0.8.2/PKG-INFO +0 -778
  28. brigade_cli-0.8.2/README.md +0 -749
  29. brigade_cli-0.8.2/src/brigade_cli.egg-info/PKG-INFO +0 -778
  30. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/LICENSE +0 -0
  31. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/MANIFEST.in +0 -0
  32. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/QUICKSTART.md +0 -0
  33. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/setup.cfg +0 -0
  34. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/__main__.py +0 -0
  35. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/aboyeur.py +0 -0
  36. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/add.py +0 -0
  37. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/agents.py +0 -0
  38. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/budgets.py +0 -0
  39. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/budgets_cmd.py +0 -0
  40. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/center_cmd.py +0 -0
  41. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/chat_cmd.py +0 -0
  42. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/config.py +0 -0
  43. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/context_cmd.py +0 -0
  44. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/daily_cmd.py +0 -0
  45. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/dogfood_cmd.py +0 -0
  46. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/fragments.py +0 -0
  47. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/handoff.py +0 -0
  48. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/hermes_adapter.py +0 -0
  49. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/ingest.py +0 -0
  50. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/learn_cmd.py +0 -0
  51. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/managed.py +0 -0
  52. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/notifications_cmd.py +0 -0
  53. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/pantry_cmd.py +0 -0
  54. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/phases_cmd.py +0 -0
  55. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/proc.py +0 -0
  56. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/projects_cmd.py +0 -0
  57. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/prompt.py +0 -0
  58. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/py.typed +0 -0
  59. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/reconfigure.py +0 -0
  60. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/registry.py +0 -0
  61. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/release_cmd.py +0 -0
  62. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/repos_cmd.py +0 -0
  63. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/__init__.py +0 -0
  64. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/config.py +0 -0
  65. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/engine.py +0 -0
  66. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/extract.py +0 -0
  67. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/handoff.py +0 -0
  68. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/llm.py +0 -0
  69. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/registry.py +0 -0
  70. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/report.py +0 -0
  71. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/sources/__init__.py +0 -0
  72. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/sources/cli.py +0 -0
  73. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/sources/local.py +0 -0
  74. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/sources/web.py +0 -0
  75. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research/types.py +0 -0
  76. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/research_cmd.py +0 -0
  77. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/roadmap_cmd.py +0 -0
  78. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/roster.py +0 -0
  79. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/roster_cmd.py +0 -0
  80. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/runbook_cmd.py +0 -0
  81. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/runs_cmd.py +0 -0
  82. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/scrub.py +0 -0
  83. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/selection.py +0 -0
  84. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/skills_cmd.py +0 -0
  85. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/station.py +0 -0
  86. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/status.py +0 -0
  87. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/adal/memory-handoffs/TEMPLATE.md +0 -0
  88. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/aider/memory-handoffs/TEMPLATE.md +0 -0
  89. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/antigravity/memory-handoffs/TEMPLATE.md +0 -0
  90. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/claude/memory-handoffs/TEMPLATE.md +0 -0
  91. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/codex/memory-handoffs/TEMPLATE.md +0 -0
  92. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/continue/memory-handoffs/TEMPLATE.md +0 -0
  93. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/copilot/memory-handoffs/TEMPLATE.md +0 -0
  94. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/cursor/memory-handoffs/TEMPLATE.md +0 -0
  95. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/depth/repo.json +0 -0
  96. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/depth/workspace.json +0 -0
  97. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/generic/harness-adapter-checklist.md +0 -0
  98. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/generic/memory-contract.md +0 -0
  99. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/goose/memory-handoffs/TEMPLATE.md +0 -0
  100. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/handoff/handoff-sources.example.json +0 -0
  101. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/handoff/openclaw-ingest-receipt.example.json +0 -0
  102. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/adal.json +0 -0
  103. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/aider.json +0 -0
  104. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/antigravity.json +0 -0
  105. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/claude.json +0 -0
  106. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/codex.json +0 -0
  107. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/continue.json +0 -0
  108. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/copilot.json +0 -0
  109. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/cursor.json +0 -0
  110. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/goose.json +0 -0
  111. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/hermes.json +0 -0
  112. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/kimi.json +0 -0
  113. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/openclaw.json +0 -0
  114. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/opencode.json +0 -0
  115. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/openhands.json +0 -0
  116. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/pi.json +0 -0
  117. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/harnesses/qwen.json +0 -0
  118. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/hermes/README.md +0 -0
  119. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/hermes/memory-handoffs/TEMPLATE.md +0 -0
  120. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/hooks/pre-push +0 -0
  121. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/includes/publisher.json +0 -0
  122. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/kimi/memory-handoffs/TEMPLATE.md +0 -0
  123. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/backup-restic.md +0 -0
  124. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/chat-surface-crawlers.md +0 -0
  125. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/content-safety.md +0 -0
  126. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/handoff-flow.md +0 -0
  127. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/memory-architecture.md +0 -0
  128. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/memory-care-staleness.md +0 -0
  129. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/memory-scanner.md +0 -0
  130. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/multi-workspace-handoff-admin.md +0 -0
  131. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/obsidian-notes.md +0 -0
  132. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/pipeline-standups.md +0 -0
  133. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/memory/cards/tokenjuice-output-compaction.md +0 -0
  134. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/openclaw/README.md +0 -0
  135. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/openclaw/acp-escalation.openclaw.json +0 -0
  136. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/openclaw/memory-sweep-cron.openclaw.json +0 -0
  137. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/openclaw/model-aliases.openclaw.json +0 -0
  138. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/openclaw/ollama-memory-search.openclaw.json +0 -0
  139. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/opencode/memory-handoffs/TEMPLATE.md +0 -0
  140. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/openhands/memory-handoffs/TEMPLATE.md +0 -0
  141. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/pi/memory-handoffs/TEMPLATE.md +0 -0
  142. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/qwen/memory-handoffs/TEMPLATE.md +0 -0
  143. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/scripts/backup-restic.sh +0 -0
  144. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/skills/note/SKILL.md +0 -0
  145. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/AGENTS.md +0 -0
  146. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/CLAUDE.md +0 -0
  147. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/HEARTBEAT.md +0 -0
  148. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/IDENTITY.md +0 -0
  149. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/INSTALL_FOR_AGENTS.md +0 -0
  150. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/MEMORY.md +0 -0
  151. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/SAFETY_RULES.md +0 -0
  152. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/SOUL.md +0 -0
  153. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/TOOLS.md +0 -0
  154. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/USER.md +0 -0
  155. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/rules/acceptance-driven-work.md +0 -0
  156. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates/workspace/rules/issue-tdd-loop.md +0 -0
  157. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/templates.py +0 -0
  158. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/toml_compat.py +0 -0
  159. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/untrusted.py +0 -0
  160. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/untrusted_cmd.py +0 -0
  161. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade/work_cmd.py +0 -0
  162. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade_cli.egg-info/dependency_links.txt +0 -0
  163. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade_cli.egg-info/entry_points.txt +0 -0
  164. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade_cli.egg-info/requires.txt +0 -0
  165. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/src/brigade_cli.egg-info/top_level.txt +0 -0
  166. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_aboyeur.py +0 -0
  167. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_add.py +0 -0
  168. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_agents.py +0 -0
  169. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_budgets.py +0 -0
  170. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_cli_alias.py +0 -0
  171. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_config.py +0 -0
  172. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_doctor.py +0 -0
  173. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_dogfood_cmd.py +0 -0
  174. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_fragments.py +0 -0
  175. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_gitignore.py +0 -0
  176. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_handoff.py +0 -0
  177. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_handoff_cmd.py +0 -0
  178. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_ingest.py +0 -0
  179. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_init.py +0 -0
  180. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_install.py +0 -0
  181. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_managed.py +0 -0
  182. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_neutrality.py +0 -0
  183. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_notifications_cmd.py +0 -0
  184. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_pantry_cmd.py +0 -0
  185. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase100_cmd.py +0 -0
  186. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase101_cmd.py +0 -0
  187. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase165_cmd.py +0 -0
  188. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase36_cmd.py +0 -0
  189. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase37_cmd.py +0 -0
  190. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase38_cmd.py +0 -0
  191. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase39_cmd.py +0 -0
  192. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase40_cmd.py +0 -0
  193. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase41_cmd.py +0 -0
  194. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase42_cmd.py +0 -0
  195. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase43_cmd.py +0 -0
  196. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase44_cmd.py +0 -0
  197. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase45_cmd.py +0 -0
  198. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase46_50_cmd.py +0 -0
  199. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase51_55_cmd.py +0 -0
  200. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase56_60_cmd.py +0 -0
  201. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase96_cmd.py +0 -0
  202. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase97_cmd.py +0 -0
  203. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase98_cmd.py +0 -0
  204. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_phase99_cmd.py +0 -0
  205. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_privacy_regression.py +0 -0
  206. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_proc.py +0 -0
  207. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_prompt.py +0 -0
  208. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_reconfigure.py +0 -0
  209. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_registry.py +0 -0
  210. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_release_cmd.py +0 -0
  211. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_repos_cmd.py +0 -0
  212. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_cli_sources.py +0 -0
  213. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_cmd.py +0 -0
  214. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_config.py +0 -0
  215. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_engine.py +0 -0
  216. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_extract.py +0 -0
  217. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_handoff.py +0 -0
  218. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_llm.py +0 -0
  219. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_local_sources.py +0 -0
  220. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_registry.py +0 -0
  221. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_report.py +0 -0
  222. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_types.py +0 -0
  223. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_research_web.py +0 -0
  224. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_roadmap_cmd.py +0 -0
  225. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_roster.py +0 -0
  226. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_roster_cmd.py +0 -0
  227. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_run_cli.py +0 -0
  228. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_runbook_cmd.py +0 -0
  229. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_runs_cmd.py +0 -0
  230. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_scrub.py +0 -0
  231. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_selection.py +0 -0
  232. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_skills_cmd.py +0 -0
  233. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_station.py +0 -0
  234. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_status.py +0 -0
  235. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_toml_compat.py +0 -0
  236. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_untrusted.py +0 -0
  237. {brigade_cli-0.8.2 → brigade_cli-0.9.1}/tests/test_work_cmd.py +0 -0
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.4
2
+ Name: brigade-cli
3
+ Version: 0.9.1
4
+ Summary: AI agent memory, handoffs, and local guardrails for Codex, Claude Code, OpenCode, Hermes, and OpenClaw.
5
+ Author-email: Solomon Neas <srneas@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://brigade.tools
8
+ Project-URL: Repository, https://github.com/escoffier-labs/brigade
9
+ Project-URL: Cookbook, https://github.com/solomonneas/solos-cookbook
10
+ Project-URL: OpenClaw, https://github.com/solomonneas/openclaw
11
+ Project-URL: ContentGuard, https://github.com/solomonneas/content-guard
12
+ Project-URL: AgentPantry, https://github.com/escoffier-labs/agentpantry
13
+ Project-URL: Issues, https://github.com/escoffier-labs/brigade/issues
14
+ Keywords: agents,ai-agents,agent-memory,agent-handoffs,ai-memory,openclaw,claude-code,codex,opencode,memory,bootstrap,brigade,brigade-cli,operator,local-first,guardrails,agents-md
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=7; extra == "dev"
26
+ Provides-Extra: research
27
+ Requires-Dist: playwright>=1.40; extra == "research"
28
+ Dynamic: license-file
29
+
30
+ <p align="center">
31
+ <img src="docs/assets/brigade-social-preview.jpg" alt="Brigade" width="900">
32
+ </p>
33
+
34
+ <h1 align="center">Brigade CLI</h1>
35
+
36
+ <p align="center">
37
+ <strong>AI agent memory, handoffs, and local guardrails for Codex, Claude Code, OpenCode, and a dozen other harnesses.</strong>
38
+ </p>
39
+
40
+ <p align="center">
41
+ <img src="https://img.shields.io/github/actions/workflow/status/escoffier-labs/brigade/ci.yml?branch=main&style=for-the-badge&label=ci" alt="CI status">
42
+ <img src="https://img.shields.io/pypi/v/brigade-cli?style=for-the-badge&label=pypi" alt="PyPI version">
43
+ <img src="https://img.shields.io/badge/python-3.10%2B-blue?style=for-the-badge&logo=python&logoColor=white" alt="Python 3.10+">
44
+ <img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="MIT license">
45
+ </p>
46
+
47
+ Your agents run loops. Brigade keeps the receipts.
48
+
49
+ ## Why I built this
50
+
51
+ I run an always-on OpenClaw agent next to daily Codex and Claude Code sessions, and I have since January. Every one of those tools wakes up empty. Whatever a session learned about my machine, my rules, or yesterday's dead ends scattered across tool-specific folders and died there.
52
+
53
+ So I hand-rolled the fixes, one incident at a time: a slim `MEMORY.md` index pointing at small memory cards instead of one giant file, a handoff note format every harness could write, an ingest cron that filed the good notes into durable memory every 30 minutes, staleness checks so old cards stopped being trusted forever.
54
+
55
+ Two incidents shaped the design more than anything I planned. First, a nightly "dreaming" job that auto-promoted session fragments quietly bloated `MEMORY.md` to 41KB, way past the 12KB bootstrap budget, so every session started with truncated memory and nobody noticed for weeks. Auto-promotion died that day. Everything goes through review now. Second, I found 195 handoff notes sitting unread across 35 repos because the ingester had a hardcoded three-repo allowlist and nothing warned about the coverage gap. Silence is the failure mode. Every part of Brigade that lints, warns, or writes a receipt exists because something once failed quietly.
56
+
57
+ That system now runs 482 memory cards and survives daily multi-agent work. But explaining it to anyone meant: clone six repos, write these crons, keep your index slim, watch for staleness, and whatever you do, turn auto-promotion off. Brigade is that setup packaged as one installable CLI. The full production stack is documented in the [solos-cookbook](https://github.com/solomonneas/solos-cookbook) if you want to see where it came from.
58
+
59
+ ## The loop
60
+
61
+ Writer harnesses leave handoff notes as they work. A memory owner (OpenClaw, Hermes, or just you) ingests the ones worth keeping. Brigade lints, guards, and routes everything in between, and every consequential action lands a receipt in a plain file you can grep, diff, and prune.
62
+
63
+ 1. agents write handoff notes into their own local inboxes
64
+ 2. Brigade lints and scans them before they can become memory
65
+ 3. safe targeted notes get filed into durable memory by the owner
66
+ 4. ambiguous or risky notes wait for your review
67
+ 5. future sessions start with better context, and receipts show what happened
68
+
69
+ ```mermaid
70
+ flowchart LR
71
+ WRITERS["writer harnesses<br/>Codex · Claude Code · OpenCode · ..."]
72
+ BRIGADE["Brigade<br/>lint · guard · route · receipts"]
73
+ REVIEW["operator review<br/>safe · ambiguous · risky"]
74
+ OWNER["memory owner<br/>OpenClaw / Hermes / you"]
75
+ MEM["durable memory<br/>MEMORY.md index · memory cards"]
76
+
77
+ WRITERS -- handoff notes --> BRIGADE --> REVIEW
78
+ REVIEW -- safe targeted notes --> OWNER --> MEM
79
+ MEM -. context .-> WRITERS
80
+
81
+ classDef brigade fill:#2563eb,stroke:#1d4ed8,color:#fff;
82
+ classDef memory fill:#ecfdf5,stroke:#059669,color:#064e3b;
83
+ classDef gate fill:#fff7ed,stroke:#ea580c,color:#7c2d12;
84
+ class BRIGADE brigade;
85
+ class OWNER,MEM memory;
86
+ class REVIEW gate;
87
+ ```
88
+
89
+ Memory has two layers: knowledge cards under `memory/cards/` hold the detail, and `MEMORY.md` stays a slim one-line-per-card index that loads every session. `brigade memory care scan` flags stale, contradictory, or undersourced cards for review instead of letting them rot. Brigade never edits canonical memory itself; the owner does the writing.
90
+
91
+ It all runs on the machine you control: laptop, workstation, or VPS. Local by default, loud about the exceptions.
92
+
93
+ ## Install
94
+
95
+ ```bash
96
+ pipx install brigade-cli
97
+ brigade operator quickstart --target ./my-repo --harnesses codex
98
+ brigade operator doctor --target ./my-repo --profile local-operator
99
+ ```
100
+
101
+ For an OpenClaw or Hermes workspace instead of a code repo:
102
+
103
+ ```bash
104
+ brigade operator quickstart --target ~/agent-workspace --depth workspace --harnesses openclaw,hermes --owner openclaw
105
+ ```
106
+
107
+ Use `--dry-run` first to preview the planned steps without writing anything; `brigade init --target ./my-repo --harnesses codex --dry-run` shows the full file-by-file list. Pass more harnesses as a comma-separated list. Quickstart only wires the harnesses you select and leaves the rest alone.
108
+
109
+ Write a handoff and check the wiring:
110
+
111
+ ```bash
112
+ brigade handoff draft --target ./my-repo --inbox codex \
113
+ --title "What changed" \
114
+ --summary "Short note future agents should know." \
115
+ --content "The durable note itself goes here."
116
+ brigade handoff lint --target ./my-repo
117
+ brigade handoff doctor --target ./my-repo
118
+ ```
119
+
120
+ New here? Start with [docs/first-10-minutes.md](docs/first-10-minutes.md). Already have a homegrown setup with scripts, crons, and handoff folders? Brigade has an adoption path that inventories what you have before changing anything: start with `brigade operator adopt plan` and see the [technical guide](docs/technical-guide.md). Want an agent to set this up for you? Point it at this repo; [AGENTS.md](AGENTS.md) tells it exactly what to do and where to stop.
121
+
122
+ ## Harness support
123
+
124
+ Each writer gets its own local inbox; one canonical owner ingests. Brigade keeps the note format consistent so different tools can contribute without inventing their own styles.
125
+
126
+ | Writer | Harness id | Inbox |
127
+ |---|---|---|
128
+ | Codex CLI | `codex` | `.codex/memory-handoffs/` |
129
+ | Claude Code | `claude` | `.claude/memory-handoffs/` |
130
+ | OpenCode | `opencode` | `.opencode/memory-handoffs/` |
131
+ | Antigravity | `antigravity` | `.antigravity/memory-handoffs/` |
132
+ | Pi | `pi` | `.pi/memory-handoffs/` |
133
+ | Cursor | `cursor` | `.cursor/memory-handoffs/` |
134
+ | Aider | `aider` | `.aider/memory-handoffs/` |
135
+ | Goose | `goose` | `.goose/memory-handoffs/` |
136
+ | Continue | `continue` | `.continue/memory-handoffs/` |
137
+ | GitHub Copilot CLI | `copilot` | `.copilot/memory-handoffs/` |
138
+ | Qwen Code | `qwen` | `.qwen/memory-handoffs/` |
139
+ | Kimi Code | `kimi` | `.kimi/memory-handoffs/` |
140
+ | AdaL | `adal` | `.adal/memory-handoffs/` |
141
+ | OpenHands | `openhands` | `.openhands/memory-handoffs/` |
142
+ | Hermes | `hermes` | `.hermes/memory-handoffs/` |
143
+ | OpenClaw | `openclaw` | usually the memory owner, not a writer |
144
+
145
+ All of them get handoff templates, ingest source coverage, and projected tools/skills. Per-harness details are in the [technical guide](docs/technical-guide.md).
146
+
147
+ ## Beyond memory
148
+
149
+ The memory loop is the core. Around it, the same review-and-receipt pattern covers the rest of an operator's day, and you can ignore all of it until you need it:
150
+
151
+ - **Daily loop**: `brigade work brief` shows pending work, imports, and warnings; `brigade daily status` keeps it bounded and cheap.
152
+ - **Security**: `brigade security scan` is a local read-only scanner for agent workspaces (secrets, risky hooks, MCP configs, prompt-injection patterns); `brigade scrub` gates content before it leaves the machine.
153
+ - **Tools and skills**: one reviewed catalog projected into every harness's native format, with approval gates for anything that executes.
154
+ - **Research**: `brigade research run` turns a question into a cited local report and a reviewable memory handoff.
155
+ - **Fleet and release**: health evidence across your local repos and release-readiness receipts, with no publish step.
156
+
157
+ The full tour of every station lives in [docs/overview.md](docs/overview.md).
158
+
159
+ ## Why not something else?
160
+
161
+ - **mem0, Letta, and friends** are memory layers for apps you are building, usually behind an API or a server. Brigade is for the agent CLIs you already run, and it is file-first: your memory is markdown in your repo, reviewable in git, readable without Brigade.
162
+ - **Native harness memory** (each tool's own auto-memory) is a per-tool silo. It does not cross harnesses, and it writes without review. Brigade gives every tool one shared format and one canonical owner, with a review gate in between.
163
+ - **A plain CLAUDE.md / AGENTS.md** works great until it bloats past the context budget and goes stale. Brigade exists because mine hit 41KB. It keeps bootstrap files slim, moves detail into indexed cards, and flags staleness instead of trusting last month's facts forever.
164
+ - **A daemon or hosted service** would be simpler to demo and worse to trust. Brigade writes local files when you run a command, and that is all it does.
165
+
166
+ ## What Brigade is not
167
+
168
+ Brigade is not a hosted memory service, a daemon, or an automatic release bot.
169
+
170
+ It does not:
171
+
172
+ - run in the background or install schedulers
173
+ - push to GitHub or publish packages
174
+ - send notifications by default
175
+ - save every note automatically
176
+ - turn memory ingest into a silent background process
177
+ - skip review for ambiguous, risky, or failed notes
178
+
179
+ That pause is the point. Agent memory should be useful, not noisy.
180
+
181
+ ## Docs
182
+
183
+ - [First 10 minutes](docs/first-10-minutes.md): shortest path from install to healthy setup.
184
+ - [Overview](docs/overview.md): the full tour of every station and diagram.
185
+ - [Technical guide](docs/technical-guide.md): the detailed command walkthrough.
186
+ - [Security and Content Guard](docs/security.md): scanner policies, handoff guards, import flow.
187
+ - [Handoff promotion](docs/handoff-promotion.md): how notes move toward memory.
188
+ - [Repo fleet](docs/repo-fleet.md) and [Tool catalog](docs/tool-catalog.md).
189
+ - [Command inventory](docs/command-inventory.md): every public CLI command.
190
+ - [Roadmap](ROADMAP.md) and [roadmap archive](docs/roadmap-archive.md).
191
+
192
+ Project identity: GitHub [`escoffier-labs/brigade`](https://github.com/escoffier-labs/brigade), website [brigade.tools](https://brigade.tools), PyPI [`brigade-cli`](https://pypi.org/project/brigade-cli/), command `brigade`. The name comes from the kitchen: a *brigade de cuisine* runs the line, and *mise en place* means the station is prepped before service. Set up the rules, memory, tools, and receipts before the session gets expensive.
193
+
194
+ It is early-stage and moving fast. If you hit a broken workflow, a confusing command, or a setup issue, [open an issue](https://github.com/escoffier-labs/brigade/issues) and I will get it fixed.
@@ -0,0 +1,165 @@
1
+ <p align="center">
2
+ <img src="docs/assets/brigade-social-preview.jpg" alt="Brigade" width="900">
3
+ </p>
4
+
5
+ <h1 align="center">Brigade CLI</h1>
6
+
7
+ <p align="center">
8
+ <strong>AI agent memory, handoffs, and local guardrails for Codex, Claude Code, OpenCode, and a dozen other harnesses.</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <img src="https://img.shields.io/github/actions/workflow/status/escoffier-labs/brigade/ci.yml?branch=main&style=for-the-badge&label=ci" alt="CI status">
13
+ <img src="https://img.shields.io/pypi/v/brigade-cli?style=for-the-badge&label=pypi" alt="PyPI version">
14
+ <img src="https://img.shields.io/badge/python-3.10%2B-blue?style=for-the-badge&logo=python&logoColor=white" alt="Python 3.10+">
15
+ <img src="https://img.shields.io/badge/license-MIT-green?style=for-the-badge" alt="MIT license">
16
+ </p>
17
+
18
+ Your agents run loops. Brigade keeps the receipts.
19
+
20
+ ## Why I built this
21
+
22
+ I run an always-on OpenClaw agent next to daily Codex and Claude Code sessions, and I have since January. Every one of those tools wakes up empty. Whatever a session learned about my machine, my rules, or yesterday's dead ends scattered across tool-specific folders and died there.
23
+
24
+ So I hand-rolled the fixes, one incident at a time: a slim `MEMORY.md` index pointing at small memory cards instead of one giant file, a handoff note format every harness could write, an ingest cron that filed the good notes into durable memory every 30 minutes, staleness checks so old cards stopped being trusted forever.
25
+
26
+ Two incidents shaped the design more than anything I planned. First, a nightly "dreaming" job that auto-promoted session fragments quietly bloated `MEMORY.md` to 41KB, way past the 12KB bootstrap budget, so every session started with truncated memory and nobody noticed for weeks. Auto-promotion died that day. Everything goes through review now. Second, I found 195 handoff notes sitting unread across 35 repos because the ingester had a hardcoded three-repo allowlist and nothing warned about the coverage gap. Silence is the failure mode. Every part of Brigade that lints, warns, or writes a receipt exists because something once failed quietly.
27
+
28
+ That system now runs 482 memory cards and survives daily multi-agent work. But explaining it to anyone meant: clone six repos, write these crons, keep your index slim, watch for staleness, and whatever you do, turn auto-promotion off. Brigade is that setup packaged as one installable CLI. The full production stack is documented in the [solos-cookbook](https://github.com/solomonneas/solos-cookbook) if you want to see where it came from.
29
+
30
+ ## The loop
31
+
32
+ Writer harnesses leave handoff notes as they work. A memory owner (OpenClaw, Hermes, or just you) ingests the ones worth keeping. Brigade lints, guards, and routes everything in between, and every consequential action lands a receipt in a plain file you can grep, diff, and prune.
33
+
34
+ 1. agents write handoff notes into their own local inboxes
35
+ 2. Brigade lints and scans them before they can become memory
36
+ 3. safe targeted notes get filed into durable memory by the owner
37
+ 4. ambiguous or risky notes wait for your review
38
+ 5. future sessions start with better context, and receipts show what happened
39
+
40
+ ```mermaid
41
+ flowchart LR
42
+ WRITERS["writer harnesses<br/>Codex · Claude Code · OpenCode · ..."]
43
+ BRIGADE["Brigade<br/>lint · guard · route · receipts"]
44
+ REVIEW["operator review<br/>safe · ambiguous · risky"]
45
+ OWNER["memory owner<br/>OpenClaw / Hermes / you"]
46
+ MEM["durable memory<br/>MEMORY.md index · memory cards"]
47
+
48
+ WRITERS -- handoff notes --> BRIGADE --> REVIEW
49
+ REVIEW -- safe targeted notes --> OWNER --> MEM
50
+ MEM -. context .-> WRITERS
51
+
52
+ classDef brigade fill:#2563eb,stroke:#1d4ed8,color:#fff;
53
+ classDef memory fill:#ecfdf5,stroke:#059669,color:#064e3b;
54
+ classDef gate fill:#fff7ed,stroke:#ea580c,color:#7c2d12;
55
+ class BRIGADE brigade;
56
+ class OWNER,MEM memory;
57
+ class REVIEW gate;
58
+ ```
59
+
60
+ Memory has two layers: knowledge cards under `memory/cards/` hold the detail, and `MEMORY.md` stays a slim one-line-per-card index that loads every session. `brigade memory care scan` flags stale, contradictory, or undersourced cards for review instead of letting them rot. Brigade never edits canonical memory itself; the owner does the writing.
61
+
62
+ It all runs on the machine you control: laptop, workstation, or VPS. Local by default, loud about the exceptions.
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pipx install brigade-cli
68
+ brigade operator quickstart --target ./my-repo --harnesses codex
69
+ brigade operator doctor --target ./my-repo --profile local-operator
70
+ ```
71
+
72
+ For an OpenClaw or Hermes workspace instead of a code repo:
73
+
74
+ ```bash
75
+ brigade operator quickstart --target ~/agent-workspace --depth workspace --harnesses openclaw,hermes --owner openclaw
76
+ ```
77
+
78
+ Use `--dry-run` first to preview the planned steps without writing anything; `brigade init --target ./my-repo --harnesses codex --dry-run` shows the full file-by-file list. Pass more harnesses as a comma-separated list. Quickstart only wires the harnesses you select and leaves the rest alone.
79
+
80
+ Write a handoff and check the wiring:
81
+
82
+ ```bash
83
+ brigade handoff draft --target ./my-repo --inbox codex \
84
+ --title "What changed" \
85
+ --summary "Short note future agents should know." \
86
+ --content "The durable note itself goes here."
87
+ brigade handoff lint --target ./my-repo
88
+ brigade handoff doctor --target ./my-repo
89
+ ```
90
+
91
+ New here? Start with [docs/first-10-minutes.md](docs/first-10-minutes.md). Already have a homegrown setup with scripts, crons, and handoff folders? Brigade has an adoption path that inventories what you have before changing anything: start with `brigade operator adopt plan` and see the [technical guide](docs/technical-guide.md). Want an agent to set this up for you? Point it at this repo; [AGENTS.md](AGENTS.md) tells it exactly what to do and where to stop.
92
+
93
+ ## Harness support
94
+
95
+ Each writer gets its own local inbox; one canonical owner ingests. Brigade keeps the note format consistent so different tools can contribute without inventing their own styles.
96
+
97
+ | Writer | Harness id | Inbox |
98
+ |---|---|---|
99
+ | Codex CLI | `codex` | `.codex/memory-handoffs/` |
100
+ | Claude Code | `claude` | `.claude/memory-handoffs/` |
101
+ | OpenCode | `opencode` | `.opencode/memory-handoffs/` |
102
+ | Antigravity | `antigravity` | `.antigravity/memory-handoffs/` |
103
+ | Pi | `pi` | `.pi/memory-handoffs/` |
104
+ | Cursor | `cursor` | `.cursor/memory-handoffs/` |
105
+ | Aider | `aider` | `.aider/memory-handoffs/` |
106
+ | Goose | `goose` | `.goose/memory-handoffs/` |
107
+ | Continue | `continue` | `.continue/memory-handoffs/` |
108
+ | GitHub Copilot CLI | `copilot` | `.copilot/memory-handoffs/` |
109
+ | Qwen Code | `qwen` | `.qwen/memory-handoffs/` |
110
+ | Kimi Code | `kimi` | `.kimi/memory-handoffs/` |
111
+ | AdaL | `adal` | `.adal/memory-handoffs/` |
112
+ | OpenHands | `openhands` | `.openhands/memory-handoffs/` |
113
+ | Hermes | `hermes` | `.hermes/memory-handoffs/` |
114
+ | OpenClaw | `openclaw` | usually the memory owner, not a writer |
115
+
116
+ All of them get handoff templates, ingest source coverage, and projected tools/skills. Per-harness details are in the [technical guide](docs/technical-guide.md).
117
+
118
+ ## Beyond memory
119
+
120
+ The memory loop is the core. Around it, the same review-and-receipt pattern covers the rest of an operator's day, and you can ignore all of it until you need it:
121
+
122
+ - **Daily loop**: `brigade work brief` shows pending work, imports, and warnings; `brigade daily status` keeps it bounded and cheap.
123
+ - **Security**: `brigade security scan` is a local read-only scanner for agent workspaces (secrets, risky hooks, MCP configs, prompt-injection patterns); `brigade scrub` gates content before it leaves the machine.
124
+ - **Tools and skills**: one reviewed catalog projected into every harness's native format, with approval gates for anything that executes.
125
+ - **Research**: `brigade research run` turns a question into a cited local report and a reviewable memory handoff.
126
+ - **Fleet and release**: health evidence across your local repos and release-readiness receipts, with no publish step.
127
+
128
+ The full tour of every station lives in [docs/overview.md](docs/overview.md).
129
+
130
+ ## Why not something else?
131
+
132
+ - **mem0, Letta, and friends** are memory layers for apps you are building, usually behind an API or a server. Brigade is for the agent CLIs you already run, and it is file-first: your memory is markdown in your repo, reviewable in git, readable without Brigade.
133
+ - **Native harness memory** (each tool's own auto-memory) is a per-tool silo. It does not cross harnesses, and it writes without review. Brigade gives every tool one shared format and one canonical owner, with a review gate in between.
134
+ - **A plain CLAUDE.md / AGENTS.md** works great until it bloats past the context budget and goes stale. Brigade exists because mine hit 41KB. It keeps bootstrap files slim, moves detail into indexed cards, and flags staleness instead of trusting last month's facts forever.
135
+ - **A daemon or hosted service** would be simpler to demo and worse to trust. Brigade writes local files when you run a command, and that is all it does.
136
+
137
+ ## What Brigade is not
138
+
139
+ Brigade is not a hosted memory service, a daemon, or an automatic release bot.
140
+
141
+ It does not:
142
+
143
+ - run in the background or install schedulers
144
+ - push to GitHub or publish packages
145
+ - send notifications by default
146
+ - save every note automatically
147
+ - turn memory ingest into a silent background process
148
+ - skip review for ambiguous, risky, or failed notes
149
+
150
+ That pause is the point. Agent memory should be useful, not noisy.
151
+
152
+ ## Docs
153
+
154
+ - [First 10 minutes](docs/first-10-minutes.md): shortest path from install to healthy setup.
155
+ - [Overview](docs/overview.md): the full tour of every station and diagram.
156
+ - [Technical guide](docs/technical-guide.md): the detailed command walkthrough.
157
+ - [Security and Content Guard](docs/security.md): scanner policies, handoff guards, import flow.
158
+ - [Handoff promotion](docs/handoff-promotion.md): how notes move toward memory.
159
+ - [Repo fleet](docs/repo-fleet.md) and [Tool catalog](docs/tool-catalog.md).
160
+ - [Command inventory](docs/command-inventory.md): every public CLI command.
161
+ - [Roadmap](ROADMAP.md) and [roadmap archive](docs/roadmap-archive.md).
162
+
163
+ Project identity: GitHub [`escoffier-labs/brigade`](https://github.com/escoffier-labs/brigade), website [brigade.tools](https://brigade.tools), PyPI [`brigade-cli`](https://pypi.org/project/brigade-cli/), command `brigade`. The name comes from the kitchen: a *brigade de cuisine* runs the line, and *mise en place* means the station is prepped before service. Set up the rules, memory, tools, and receipts before the session gets expensive.
164
+
165
+ It is early-stage and moving fast. If you hit a broken workflow, a confusing command, or a setup issue, [open an issue](https://github.com/escoffier-labs/brigade/issues) and I will get it fixed.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "brigade-cli"
7
- version = "0.8.2"
7
+ version = "0.9.1"
8
8
  description = "AI agent memory, handoffs, and local guardrails for Codex, Claude Code, OpenCode, Hermes, and OpenClaw."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,3 +1,3 @@
1
1
  """Brigade: local operator-system CLI for agent workspaces."""
2
2
 
3
- __version__ = "0.8.2"
3
+ __version__ = "0.9.1"
@@ -11,12 +11,62 @@ from .work_cmd import TASK_PRIORITIES, TASK_TYPES
11
11
  from .prompt import prompt_for_selection # imported here so tests can monkeypatch cli.prompt_for_selection
12
12
 
13
13
 
14
+ # Top-level help groups. Every sub.add_parser command must appear in exactly
15
+ # one group; tests/test_cli_help.py enforces full coverage.
16
+ COMMAND_GROUPS: list[tuple[str, list[str]]] = [
17
+ ("Core memory loop",
18
+ ["init", "handoff", "handoff-template", "ingest", "memory", "doctor", "status"]),
19
+ ("Daily operator loop",
20
+ ["operator", "daily", "work", "center", "runbook", "budgets", "notifications"]),
21
+ ("Stations and tools",
22
+ ["add", "skills", "tools", "pantry", "roster", "run", "runs", "dogfood"]),
23
+ ("Review, security, and research",
24
+ ["security", "scrub", "untrusted", "research", "learn", "chat", "context", "projects"]),
25
+ ("Wiring and advanced",
26
+ ["release", "roadmap", "repos", "reconfigure", "openclaw-fragments", "hermes-fragments"]),
27
+ ]
28
+
29
+ _START_HERE = """Brigade: run your agent brigade. Operator-system CLI for agent workspaces.
30
+
31
+ Start here:
32
+ brigade operator quickstart --target <repo> --harnesses codex set up a repo or workspace
33
+ brigade operator doctor --target <repo> check the wiring
34
+ brigade handoff draft --target <repo> ... record a durable note
35
+ brigade ingest --target <workspace> route handoffs into memory"""
36
+
37
+
38
+ class _TopLevelHelpFormatter(argparse.RawDescriptionHelpFormatter):
39
+ """Suppress argparse's flat subcommand dump on the top-level parser.
40
+
41
+ The grouped epilog lists every command instead. Subparsers do not inherit
42
+ this formatter, so `brigade <command> --help` keeps the normal listing.
43
+ """
44
+
45
+ def _iter_indented_subactions(self, action):
46
+ if isinstance(action, argparse._SubParsersAction):
47
+ return iter(())
48
+ return super()._iter_indented_subactions(action)
49
+
50
+
51
+ def _grouped_epilog(sub: argparse._SubParsersAction) -> str:
52
+ helps = {action.dest: (action.help or "") for action in sub._choices_actions}
53
+ lines = ["commands:"]
54
+ for title, names in COMMAND_GROUPS:
55
+ lines.append("")
56
+ lines.append(f"{title}:")
57
+ lines.extend(f" {name:<22}{helps.get(name, '')}" for name in names)
58
+ lines.append("")
59
+ lines.append("Run 'brigade <command> --help' for details on any command.")
60
+ return "\n".join(lines)
61
+
62
+
14
63
  def _build_parser() -> argparse.ArgumentParser:
15
64
  from . import learn_cmd, projects_cmd, release_cmd, repos_cmd
16
65
 
17
66
  parser = argparse.ArgumentParser(
18
67
  prog="brigade",
19
- description="Brigade: run your agent brigade. Operator-system CLI for agent workspaces.",
68
+ description=_START_HERE,
69
+ formatter_class=_TopLevelHelpFormatter,
20
70
  )
21
71
  parser.add_argument(
22
72
  "--version", action="version", version=f"brigade {__version__}"
@@ -1046,8 +1096,8 @@ def _build_parser() -> argparse.ArgumentParser:
1046
1096
  p_handoff_draft.add_argument("--action", choices=["create-card", "update-card", "no-card"], default="no-card", help="Recommended memory action.")
1047
1097
  p_handoff_draft.add_argument("--target-card", default=None, help="Target card filename for card handoffs.")
1048
1098
  p_handoff_draft.add_argument("--target-document", default=".learnings/LEARNINGS.md", help="Target document for no-card handoffs.")
1049
- p_handoff_draft.add_argument("--content", default=None, help="Suggested card or document content.")
1050
- p_handoff_draft.add_argument("--content-file", type=Path, default=None, help="Read suggested content from a file.")
1099
+ p_handoff_draft.add_argument("--content", default=None, help="Suggested card or document content. One of --content/--content-file is required.")
1100
+ p_handoff_draft.add_argument("--content-file", type=Path, default=None, help="Read suggested content from a file. One of --content/--content-file is required.")
1051
1101
  p_handoff_draft.add_argument("--id", dest="draft_id", default=None, help="Stable id slug to use in the filename.")
1052
1102
  p_handoff_draft.add_argument("--force", action="store_true", help="Overwrite an existing generated draft path.")
1053
1103
  p_handoff_draft.add_argument("--guard", action="store_true", help="Scan the generated draft with content-guard before returning success.")
@@ -2817,6 +2867,7 @@ def _build_parser() -> argparse.ArgumentParser:
2817
2867
  p_recon.add_argument("--prune", action="store_true",
2818
2868
  help="Remove files for harnesses no longer selected.")
2819
2869
 
2870
+ parser.epilog = _grouped_epilog(sub)
2820
2871
  return parser
2821
2872
 
2822
2873
 
@@ -383,8 +383,11 @@ def _check_orphan_inboxes(
383
383
 
384
384
 
385
385
  def _check_memory_care(target: Path) -> List[CheckResult]:
386
+ from . import memory_cmd
387
+
386
388
  results: List[CheckResult] = []
387
- decay_dir = target / "memory" / "cards" / "decay"
389
+ config = memory_cmd.load_config(target) or memory_cmd.MemoryCareConfig()
390
+ decay_dir = memory_cmd._read_output_dir(target, config)
388
391
  scan = decay_dir / "scan-latest.json"
389
392
  queue = decay_dir / "refresh-queue.json"
390
393
 
@@ -1437,6 +1437,8 @@ def draft(
1437
1437
  print(f"content_guard_detail: {guard_result.get('detail')}")
1438
1438
  for error in lint_result.errors:
1439
1439
  print(f"error: {error}")
1440
+ if not lint_result.valid:
1441
+ print(f"note: invalid draft kept at {path}; repair or delete it, then rerun `brigade handoff lint`.")
1440
1442
  return 0 if payload["valid"] else 1
1441
1443
 
1442
1444
 
@@ -247,7 +247,11 @@ def install_selection(
247
247
  for d in dirs:
248
248
  print(f" dir {target / d}")
249
249
  for entry in files:
250
- print(f" file {target / entry['dst']}")
250
+ dst = target / entry["dst"]
251
+ if dst.exists():
252
+ print(f" file {dst} (exists; refused without --force)")
253
+ else:
254
+ print(f" file {dst}")
251
255
  return 0
252
256
 
253
257
  target.mkdir(parents=True, exist_ok=True)
@@ -16,7 +16,10 @@ from .install import apply_gitignore
16
16
  from .selection import Selection
17
17
 
18
18
  CONFIG_REL_PATH = ".brigade/memory-care.toml"
19
- DEFAULT_OUTPUT_PATH = "memory/cards/decay"
19
+ DEFAULT_OUTPUT_PATH = ".brigade/memory-care/decay"
20
+ # Pre-0.9.1 scans wrote into the user's card tree. Readers fall back to this
21
+ # location when the default is in effect and no new-style output exists yet.
22
+ LEGACY_OUTPUT_PATH = "memory/cards/decay"
20
23
  CHECKS = (
21
24
  "stale",
22
25
  "expired",
@@ -56,12 +59,27 @@ def _output_dir(target: Path, config: MemoryCareConfig) -> Path:
56
59
  return target.expanduser().resolve() / config.output_path
57
60
 
58
61
 
62
+ def _read_output_dir(target: Path, config: MemoryCareConfig) -> Path:
63
+ """Resolve the output dir for readers, honoring the legacy location.
64
+
65
+ Scans write to `config.output_path`. When the default path is in effect
66
+ and has no scan output yet, fall back to the pre-0.9.1 location so
67
+ existing workspaces keep their queue continuity.
68
+ """
69
+ output = _output_dir(target, config)
70
+ if config.output_path == DEFAULT_OUTPUT_PATH and not (output / "scan-latest.json").is_file():
71
+ legacy = target.expanduser().resolve() / LEGACY_OUTPUT_PATH
72
+ if (legacy / "scan-latest.json").is_file() or (legacy / "refresh-queue.json").is_file():
73
+ return legacy
74
+ return output
75
+
76
+
59
77
  def _scan_path(target: Path, config: MemoryCareConfig) -> Path:
60
- return _output_dir(target, config) / "scan-latest.json"
78
+ return _read_output_dir(target, config) / "scan-latest.json"
61
79
 
62
80
 
63
81
  def _queue_path(target: Path, config: MemoryCareConfig) -> Path:
64
- return _output_dir(target, config) / "refresh-queue.json"
82
+ return _read_output_dir(target, config) / "refresh-queue.json"
65
83
 
66
84
 
67
85
  def _today() -> date:
@@ -197,7 +215,7 @@ def init(*, target: Path, force: bool = False, update_gitignore: bool = True) ->
197
215
  if update_gitignore:
198
216
  apply_gitignore(target, Selection(depth="repo", harnesses=[], owner="this-repo", includes=[]))
199
217
  print(f"memory_care_config: {path}")
200
- print("output_path: memory/cards/decay")
218
+ print(f"output_path: {DEFAULT_OUTPUT_PATH}")
201
219
  print("next_command: brigade memory care scan")
202
220
  return 0
203
221
 
@@ -2787,7 +2787,8 @@ def quickstart(
2787
2787
  dry_run=dry_run,
2788
2788
  allow_home=False,
2789
2789
  )
2790
- steps.append({"id": "brigade-init", "status": "ok" if install_rc == 0 else "error", "return_code": install_rc, "output": install_output})
2790
+ install_status = "planned" if dry_run and install_rc == 0 else "ok" if install_rc == 0 else "error"
2791
+ steps.append({"id": "brigade-init", "status": install_status, "return_code": install_rc, "output": install_output})
2791
2792
  if install_rc != 0:
2792
2793
  payload = {
2793
2794
  "target": str(target),
@@ -16,7 +16,8 @@ from urllib import request as urlrequest
16
16
  from urllib.parse import urlparse
17
17
 
18
18
  from . import work_cmd
19
- from .untrusted import PROMPT_INJECTION_RE
19
+ from .selection import WRITER_INBOXES
20
+ from .untrusted import PROMPT_INJECTION_RE, scan_untrusted
20
21
 
21
22
  SEVERITY_ORDER = {
22
23
  "info": 0,
@@ -52,6 +53,7 @@ SCAN_PROFILES = {
52
53
  }
53
54
  SECURITY_CHECKS = (
54
55
  "automation",
56
+ "handoff-injection",
55
57
  "mcp",
56
58
  "permissions",
57
59
  "prompt-injection",
@@ -2123,6 +2125,8 @@ def _surface_for(path: Path, target: Path) -> str:
2123
2125
  parts = rel.parts
2124
2126
  if _is_session_chat_path(path, target):
2125
2127
  return "session-chat"
2128
+ if "memory-handoffs" in parts:
2129
+ return "handoff-inbox"
2126
2130
  if "skills" in parts and path.name == "SKILL.md":
2127
2131
  return "skill"
2128
2132
  if "commands" in parts and path.suffix.lower() == ".md":
@@ -2463,6 +2467,44 @@ def _filter_findings(
2463
2467
  return selected
2464
2468
 
2465
2469
 
2470
+ def _scan_handoff_inboxes(findings: list[dict[str, Any]], *, target: Path) -> list[str]:
2471
+ """Screen pending handoff notes for injection signals.
2472
+
2473
+ Handoff inboxes are excluded from the line scanner via SKIP_PREFIXES so
2474
+ untrusted note content is not attributed to the repo author. This pass
2475
+ reports the same content through the untrusted-context lens instead:
2476
+ a pending note carrying injection-style instructions should be reviewed
2477
+ before any ingester reads it. `processed/` and TEMPLATE.md are skipped.
2478
+ """
2479
+ scanned: list[str] = []
2480
+ for inbox_rel in sorted(set(WRITER_INBOXES.values())):
2481
+ inbox = target / inbox_rel
2482
+ if not inbox.is_dir():
2483
+ continue
2484
+ for path in sorted(inbox.glob("*.md")):
2485
+ if path.name == "TEMPLATE.md":
2486
+ continue
2487
+ try:
2488
+ text = path.read_text(errors="replace")
2489
+ except OSError:
2490
+ continue
2491
+ scanned.append(str(path.relative_to(target)))
2492
+ signal = scan_untrusted(text)
2493
+ if signal.flagged:
2494
+ _finding(
2495
+ findings,
2496
+ target=target,
2497
+ path=path,
2498
+ line=1,
2499
+ severity="medium",
2500
+ category="handoff-injection",
2501
+ title="Pending handoff carries prompt-injection signals",
2502
+ evidence=signal.markers[0] if signal.markers else "injection signal",
2503
+ suggestion="Review this handoff before ingest; do not let an ingester auto-promote it.",
2504
+ )
2505
+ return scanned
2506
+
2507
+
2466
2508
  def scan_target(
2467
2509
  target: Path,
2468
2510
  *,
@@ -2476,6 +2518,7 @@ def scan_target(
2476
2518
  target = target.expanduser().resolve()
2477
2519
  findings: list[dict[str, Any]] = []
2478
2520
  scanned_files: list[str] = []
2521
+ scanned_files.extend(_scan_handoff_inboxes(findings, target=target))
2479
2522
  for path in _iter_scan_files(target):
2480
2523
  if not include_templates and _confidence_for(path, target) == "template":
2481
2524
  continue
@@ -5,7 +5,7 @@
5
5
  "Describes the handoff inbox + routing targets that Hermes should treat",
6
6
  "as the canonical memory contract."
7
7
  ],
8
- "_brigade_version": "0.8.2",
8
+ "_brigade_version": "0.9.1",
9
9
  "_brigade_status": "experimental",
10
10
  "memory_handoff": {
11
11
  "inbox_dir": ".hermes/memory-handoffs",