brigade-cli 0.5.0__py3-none-any.whl

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 (69) hide show
  1. brigade/__init__.py +3 -0
  2. brigade/__main__.py +5 -0
  3. brigade/cli.py +258 -0
  4. brigade/config.py +65 -0
  5. brigade/doctor.py +393 -0
  6. brigade/fragments.py +64 -0
  7. brigade/handoff.py +23 -0
  8. brigade/ingest.py +298 -0
  9. brigade/install.py +217 -0
  10. brigade/prompt.py +135 -0
  11. brigade/py.typed +0 -0
  12. brigade/reconfigure.py +64 -0
  13. brigade/registry.py +39 -0
  14. brigade/scrub.py +90 -0
  15. brigade/selection.py +66 -0
  16. brigade/station.py +36 -0
  17. brigade/status.py +24 -0
  18. brigade/templates/claude/memory-handoffs/TEMPLATE.md +57 -0
  19. brigade/templates/codex/memory-handoffs/TEMPLATE.md +57 -0
  20. brigade/templates/depth/repo.json +12 -0
  21. brigade/templates/depth/workspace.json +30 -0
  22. brigade/templates/generic/harness-adapter-checklist.md +55 -0
  23. brigade/templates/generic/memory-contract.md +41 -0
  24. brigade/templates/harnesses/claude.json +12 -0
  25. brigade/templates/harnesses/codex.json +11 -0
  26. brigade/templates/harnesses/hermes.json +16 -0
  27. brigade/templates/harnesses/openclaw.json +17 -0
  28. brigade/templates/hermes/README.md +25 -0
  29. brigade/templates/hermes/memory-handoff.harness.json +36 -0
  30. brigade/templates/hermes/model-lanes.harness.json +17 -0
  31. brigade/templates/hermes/workspace.harness.json +30 -0
  32. brigade/templates/hooks/pre-push +36 -0
  33. brigade/templates/includes/publisher.json +15 -0
  34. brigade/templates/memory/cards/backup-restic.md +126 -0
  35. brigade/templates/memory/cards/chat-surface-crawlers.md +103 -0
  36. brigade/templates/memory/cards/content-safety.md +54 -0
  37. brigade/templates/memory/cards/handoff-flow.md +70 -0
  38. brigade/templates/memory/cards/memory-architecture.md +56 -0
  39. brigade/templates/memory/cards/memory-care-staleness.md +58 -0
  40. brigade/templates/memory/cards/memory-scanner.md +98 -0
  41. brigade/templates/memory/cards/multi-workspace-handoff-admin.md +63 -0
  42. brigade/templates/memory/cards/obsidian-notes.md +82 -0
  43. brigade/templates/memory/cards/pipeline-standups.md +88 -0
  44. brigade/templates/memory/cards/tokenjuice-output-compaction.md +106 -0
  45. brigade/templates/openclaw/README.md +40 -0
  46. brigade/templates/openclaw/acp-escalation.openclaw.json +33 -0
  47. brigade/templates/openclaw/model-aliases.openclaw.json +21 -0
  48. brigade/templates/openclaw/ollama-memory-search.openclaw.json +24 -0
  49. brigade/templates/policies/public-content.json +28 -0
  50. brigade/templates/policies/public-repo.json +27 -0
  51. brigade/templates/scripts/backup-restic.sh +156 -0
  52. brigade/templates/skills/note/SKILL.md +173 -0
  53. brigade/templates/workspace/AGENTS.md +146 -0
  54. brigade/templates/workspace/CLAUDE.md +48 -0
  55. brigade/templates/workspace/HEARTBEAT.md +41 -0
  56. brigade/templates/workspace/IDENTITY.md +27 -0
  57. brigade/templates/workspace/INSTALL_FOR_AGENTS.md +61 -0
  58. brigade/templates/workspace/MEMORY.md +102 -0
  59. brigade/templates/workspace/SAFETY_RULES.md +164 -0
  60. brigade/templates/workspace/SOUL.md +92 -0
  61. brigade/templates/workspace/TOOLS.md +116 -0
  62. brigade/templates/workspace/USER.md +88 -0
  63. brigade/templates.py +88 -0
  64. brigade_cli-0.5.0.dist-info/METADATA +211 -0
  65. brigade_cli-0.5.0.dist-info/RECORD +69 -0
  66. brigade_cli-0.5.0.dist-info/WHEEL +5 -0
  67. brigade_cli-0.5.0.dist-info/entry_points.txt +3 -0
  68. brigade_cli-0.5.0.dist-info/licenses/LICENSE +21 -0
  69. brigade_cli-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,36 @@
1
+ {
2
+ "_comment": [
3
+ "EXPERIMENTAL fragment for Hermes integration.",
4
+ "",
5
+ "Describes the handoff inbox + routing targets that Hermes should treat",
6
+ "as the canonical memory contract."
7
+ ],
8
+ "_brigade_version": "0.1.0",
9
+ "_brigade_status": "experimental",
10
+ "memory_handoff": {
11
+ "inbox_dir": ".claude/memory-handoffs",
12
+ "processed_dir": ".claude/memory-handoffs/processed",
13
+ "review_inbox": "memory/handoff-inbox",
14
+ "routing_targets": {
15
+ "cards": "memory/cards",
16
+ "tools": "TOOLS.md",
17
+ "user_prefs": "USER.md",
18
+ "rules": "rules",
19
+ "errors": ".learnings/ERRORS.md",
20
+ "learnings": ".learnings/LEARNINGS.md",
21
+ "feature_requests": ".learnings/FEATURE_REQUESTS.md"
22
+ },
23
+ "auto_promote": {
24
+ "card_filename_regex": "^[A-Za-z0-9._-]+\\.md$",
25
+ "card_content_must_start_with": "---",
26
+ "document_targets_allowed": [
27
+ "TOOLS.md",
28
+ "USER.md",
29
+ "rules/*.md",
30
+ ".learnings/LEARNINGS.md",
31
+ ".learnings/ERRORS.md",
32
+ ".learnings/FEATURE_REQUESTS.md"
33
+ ]
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "_comment": [
3
+ "EXPERIMENTAL fragment for Hermes integration.",
4
+ "",
5
+ "Suggested model lane names. Same shape as the OpenClaw alias map so",
6
+ "knowledge cards and runbooks can talk about lanes without naming providers."
7
+ ],
8
+ "_brigade_version": "0.1.0",
9
+ "_brigade_status": "experimental",
10
+ "model_lanes": {
11
+ "main": "<provider/main-model-id>",
12
+ "coder": "<provider/coder-model-id>",
13
+ "cron": "<provider/cron-model-id>",
14
+ "fast": "<provider/fast-model-id>",
15
+ "escalation": "<provider/escalation-model-id>"
16
+ }
17
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "_comment": [
3
+ "EXPERIMENTAL fragment for Hermes integration.",
4
+ "",
5
+ "Hermes support follows the same contract as OpenClaw; only the file names",
6
+ "and command paths change. This fragment is a placeholder until validated",
7
+ "against a real Hermes install.",
8
+ "",
9
+ "Replace <hermes-config-path> with your Hermes config location."
10
+ ],
11
+ "_brigade_version": "0.1.0",
12
+ "_brigade_status": "experimental",
13
+ "workspace": {
14
+ "root": "<workspace-root>",
15
+ "bootstrap_files": [
16
+ "AGENTS.md",
17
+ "CLAUDE.md",
18
+ "SOUL.md",
19
+ "USER.md",
20
+ "TOOLS.md",
21
+ "MEMORY.md",
22
+ "IDENTITY.md",
23
+ "HEARTBEAT.md",
24
+ "SAFETY_RULES.md",
25
+ "INSTALL_FOR_AGENTS.md"
26
+ ],
27
+ "memory_owner": "hermes",
28
+ "handoff_inbox": ".claude/memory-handoffs"
29
+ }
30
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+ # pre-push: block push if content-guard finds public-leak violations.
3
+ #
4
+ # Installed by `brigade init`. Activate once with:
5
+ # git config core.hooksPath hooks
6
+ #
7
+ # Bypass only if you know what you are allowing through:
8
+ # git push --no-verify
9
+ #
10
+ # Requires content-guard: https://github.com/solomonneas/content-guard
11
+ set -euo pipefail
12
+
13
+ SCANNER_DIR="${CONTENT_GUARD_DIR:-$HOME/repos/content-guard}"
14
+ POLICY="${CONTENT_GUARD_POLICY:-$SCANNER_DIR/policies/public-repo.json}"
15
+
16
+ if [[ ! -d "$SCANNER_DIR" ]]; then
17
+ echo "pre-push: content-guard not found at $SCANNER_DIR" >&2
18
+ echo "pre-push: clone https://github.com/solomonneas/content-guard, or set CONTENT_GUARD_DIR" >&2
19
+ exit 1
20
+ fi
21
+
22
+ if [[ ! -f "$POLICY" ]]; then
23
+ echo "pre-push: policy file not found: $POLICY" >&2
24
+ exit 1
25
+ fi
26
+
27
+ REPO_ROOT="$(git rev-parse --show-toplevel)"
28
+ echo "pre-push: scanning $REPO_ROOT against $(basename "$POLICY")"
29
+
30
+ if ! PYTHONPATH="$SCANNER_DIR/src" python3 -m content_guard scan "$REPO_ROOT" --policy "$POLICY"; then
31
+ echo >&2
32
+ echo "pre-push: BLOCKED. content-guard found violations." >&2
33
+ echo "pre-push: fix the leak, or add an inline allow-tag on the offending line:" >&2
34
+ echo "pre-push: <!-- content-guard: allow <rule-id> -->" >&2
35
+ exit 1
36
+ fi
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "publisher",
3
+ "description": "content-guard policies + scrub cache for users who publish blogs, social, or docs.",
4
+ "files": [
5
+ {"src": "policies/public-content.json", "dst": ".brigade/policies/public-content.json"},
6
+ {"src": "memory/cards/content-safety.md", "dst": "memory/cards/content-safety.md"}
7
+ ],
8
+ "dirs": [
9
+ ".brigade/scrub-cache"
10
+ ],
11
+ "post_install_notes": [
12
+ "Run `brigade scrub --target . --policy public-content` before publishing user-facing content.",
13
+ "Add `brigade scrub` to your publish workflow as a hard gate."
14
+ ]
15
+ }
@@ -0,0 +1,126 @@
1
+ ---
2
+ topic: backup-restic
3
+ category: infrastructure
4
+ tags: [backup, restic, rclone, gdrive, nas, retention, recovery]
5
+ ---
6
+
7
+ # Workspace Backup (Restic + rclone + NAS)
8
+
9
+ Twice-daily restic backups to two destinations: Google Drive (via rclone) and a local NAS mount. Encrypted, deduplicated, snapshot-pruned. The reference script ships at `scripts/backup-restic.sh`; this card explains *why* the shape is what it is.
10
+
11
+ ## Why both destinations
12
+
13
+ | Failure mode | Local NAS only | gdrive only | Both |
14
+ |--------------|----------------|-------------|------|
15
+ | Workstation disk dies | Recover from NAS, fast | Recover from gdrive, slow | Either |
16
+ | NAS hardware failure | Lose everything | Recover from gdrive | gdrive saves you |
17
+ | Google account locked / quota | Lose everything that ran since last NAS run | Lose everything | NAS saves you |
18
+ | Ransomware hits workstation | Possibly hits NAS too | Off-site immutable copy | gdrive saves you |
19
+
20
+ Two destinations covers the "one of them is broken" case without raising the recovery time for the common case (NAS is faster).
21
+
22
+ ## Cadence
23
+
24
+ ```cron
25
+ 0 3,15 * * * /path/to/backup-restic.sh
26
+ ```
27
+
28
+ 03:00 + 15:00. Twice a day means worst-case data loss window is ~12 hours. Adjust if your write velocity is higher.
29
+
30
+ ## What gets backed up
31
+
32
+ Default paths:
33
+
34
+ - The agent workspace (`~/.brigade` or your equivalent)
35
+ - All repos under `~/repos`
36
+ - Local scripts and bin (`~/bin`)
37
+ - Dotfiles: `.bashrc`, `.profile`, `.gitconfig`, `.ssh`, `.claude`, `.codex`, `.npmrc`
38
+ - Notes (`~/notes`)
39
+ - Obsidian vault (`~/Obsidian`)
40
+
41
+ Excluded by default: `node_modules`, `.git/objects`, `__pycache__`, `*.pyc`, `.venv`, `dist`, `build`, `.next`, `.astro`, `coverage`, `.turbo`, `*.jsonl`, `.pm2/logs`, `.pm2/pids`, `.ollama`, `.obsidian/workspace*.json`, `.obsidian/cache`, `.trash`.
42
+
43
+ Edit the `BACKUP_PATHS` and `EXCLUDES` arrays in the script for your stack.
44
+
45
+ ## Retention
46
+
47
+ ```text
48
+ --keep-daily 7
49
+ --keep-weekly 4
50
+ --keep-monthly 3
51
+ ```
52
+
53
+ About 14 snapshots overlapping over three months. Plenty for human-paced workflows.
54
+
55
+ ## Why rclone is throttled hard
56
+
57
+ Google Drive can reject bursty restic-over-rclone writes when other rclone jobs (Obsidian bisync, cookbook sync, etc.) are running. The script sets:
58
+
59
+ ```bash
60
+ RCLONE_TRANSFERS=1
61
+ RCLONE_CHECKERS=2
62
+ RCLONE_TPSLIMIT=4
63
+ RCLONE_TPSLIMIT_BURST=4
64
+ RCLONE_DRIVE_PACER_MIN_SLEEP=500ms
65
+ RCLONE_DRIVE_PACER_BURST=10
66
+ RCLONE_RETRIES=8
67
+ RCLONE_LOW_LEVEL_RETRIES=20
68
+ ```
69
+
70
+ Conservative on purpose. A backup that takes 40 minutes and finishes beats one that races, hits Drive quota, and dies in a retry loop.
71
+
72
+ ## NAS shape
73
+
74
+ The NAS mount is typically an SMB/NFS share at `/mnt/nas/backups`. The script:
75
+
76
+ 1. Skips cleanly if the mount is not present.
77
+ 2. Uses a separate restic repo path on the NAS (independent encryption + deduplication state).
78
+ 3. Tags NAS snapshots distinctly (`scheduled-nas`) so summaries are easy to read.
79
+
80
+ NAS-side considerations:
81
+
82
+ - **Permissions:** the NAS share must allow write from the workstation user.
83
+ - **Lock files:** restic uses lockfiles inside the repo. A killed process can leave stale locks; the script runs `restic unlock --remove-all` after each successful backup.
84
+ - **Read-only by default:** if the NAS holds irreplaceable family photos or other "do not touch" data, keep that data on a separate path and treat the rest of the NAS as read-only for the agent. See `SAFETY_RULES.md`.
85
+
86
+ ## Password
87
+
88
+ ```bash
89
+ echo "<strong-password>" > ~/.brigade/.restic-password
90
+ chmod 600 ~/.brigade/.restic-password
91
+ ```
92
+
93
+ Never commit this file. Never paste the password in a chat. If the password is lost, the encrypted snapshots are unrecoverable.
94
+
95
+ ## Recovery
96
+
97
+ ```bash
98
+ # list snapshots
99
+ restic snapshots
100
+
101
+ # restore a specific snapshot to /tmp/restore/
102
+ restic restore <id> --target /tmp/restore
103
+
104
+ # restore just one path
105
+ restic restore <id> --target /tmp/restore --include "$HOME/repos/<project>"
106
+ ```
107
+
108
+ Practice this. A backup you have never restored is a hope, not a backup.
109
+
110
+ ## Monitoring
111
+
112
+ Log file path:
113
+
114
+ ```text
115
+ ~/.brigade/logs/backup-YYYYMMDD.log
116
+ ```
117
+
118
+ Worth wiring into the morning report (`memory/cards/pipeline-standups.md`): grep recent logs for `ERROR` and surface in the briefing. A silent backup that has been failing for three weeks is the second-worst kind of bug.
119
+
120
+ ## Anti-patterns
121
+
122
+ - **One destination only.** Single point of failure.
123
+ - **No retention policy.** Old snapshots accumulate, gdrive quota fills, new backups fail.
124
+ - **Backing up `node_modules`.** Wastes deduplication windows. Use the excludes.
125
+ - **Backing up secrets unencrypted.** `.env` files get backed up too; that is intentional because restic encrypts everything at rest. The password file is the keystone; protect it.
126
+ - **Skipping verification.** Run `restic check` periodically. Snapshots that exist but are corrupted are not snapshots.
@@ -0,0 +1,103 @@
1
+ ---
2
+ topic: chat-surface-crawlers
3
+ category: foundation
4
+ tags: [chat-archives, discord, slack, whatsapp, telegram, sqlite, ingest]
5
+ ---
6
+
7
+ # Chat Surface Crawlers
8
+
9
+ If you let your agent operate across messaging surfaces (Discord, WhatsApp, Slack, Telegram, etc.), you need each surface mirrored into a queryable local store. Native search on those platforms is inconsistent, rate-limited, and disappears when the platform decides to. A local crawl gives you durable history and feeds the [memory-scanner](memory-scanner.md).
10
+
11
+ ## Pattern
12
+
13
+ ```text
14
+ chat platform local mirror searchable store
15
+ (Discord, (bot or auth-token (SQLite + FTS5,
16
+ Slack, with read access) or vector index)
17
+ WhatsApp,
18
+ Telegram,
19
+ iMessage)
20
+ |
21
+ v
22
+ crawler tail/sync (live + periodic repair)
23
+ |
24
+ v
25
+ memory scanner reads recent archive ranges
26
+ |
27
+ v
28
+ .claude/memory-handoffs/ or direct card writes
29
+ ```
30
+
31
+ Each crawler is platform-specific (auth differs, intents differ, rate limits differ), but they share the same shape:
32
+
33
+ - **Live tail.** Long-running process that receives new messages as they arrive.
34
+ - **Periodic full sync.** Repair pass that catches anything the live tail missed.
35
+ - **Local SQLite store.** Messages, threads, members, mentions, attachments.
36
+ - **FTS5 search index** (or equivalent) so the scanner can query without ranking on the platform's API.
37
+ - **Read-only export.** Other machines or readers consume a snapshot; only the canonical host runs live sync.
38
+
39
+ ## Surfaces and tools
40
+
41
+ | Platform | Crawler (suggested name) | Status |
42
+ |----------|--------------------------|--------|
43
+ | Discord | [`discrawl`](https://github.com/solomonneas/discrawl) | Available. Bot-token, SQLite + FTS5, git-snapshot read mode. |
44
+ | Slack | `slackcrawl` | Pattern-name. Bot-token + RTM events; same SQLite shape. |
45
+ | WhatsApp | `whatsappcrawl` | Pattern-name. Likely via WhatsApp Business API or Multi-Device session bridge. |
46
+ | Telegram | `tgcrawl` | Pattern-name. Bot API + MTProto for history backfill. |
47
+ | iMessage | `imescrawl` | Pattern-name. macOS-only; reads from local `chat.db`. |
48
+ | Signal | `signalcrawl` | Pattern-name. Signal-cli session export. |
49
+ | Email (Gmail/IMAP) | `mailcrawl` | Pattern-name. IMAP IDLE for tail, full-folder sync for repair. |
50
+
51
+ The names above follow the `<platform>crawl` convention used by `discrawl`. Swap them for whatever tool you actually use - the contract matters, not the binary name.
52
+
53
+ ## Discrawl reference (the tested one)
54
+
55
+ `discrawl` is the canonical implementation:
56
+
57
+ - mirrors Discord guilds into SQLite
58
+ - FTS5 search across all archived content
59
+ - offline member directory from archived profile payloads
60
+ - structured mention/role/attachment indexing
61
+ - Gateway event tail for live updates, periodic repair sync
62
+ - private git-backed snapshot publish for org-wide read access without bot credentials
63
+
64
+ Use it as the template for other surfaces. New crawlers should expose:
65
+
66
+ 1. A `sync` verb that fetches history.
67
+ 2. A `tail` verb that streams new messages.
68
+ 3. A read-only SQL or HTTP query surface.
69
+ 4. Read-only consumption that does not require platform credentials.
70
+
71
+ ## How the memory scanner consumes archives
72
+
73
+ The [memory-scanner](memory-scanner.md) does not read raw transcripts. It queries the crawler's archive for recent ranges and asks the underlying model to extract durable facts.
74
+
75
+ Typical pattern:
76
+
77
+ ```bash
78
+ # scanner pseudocode
79
+ since=$(date -d 'yesterday' -u +%Y-%m-%dT%H:%MZ)
80
+ discrawl query --since "$since" --channel "#decisions" --format json |
81
+ memory-scan extract --to-handoff .claude/memory-handoffs/
82
+ ```
83
+
84
+ The scanner writes one Memory Handoff per durable finding. The conservative ingester routes those handoffs into cards / runbooks / learnings the same way it routes anything else.
85
+
86
+ ## Privacy boundary
87
+
88
+ Chat archives are *intimate*. The crawler's local SQLite often contains:
89
+
90
+ - DMs the agent should not summarize back to a group
91
+ - Private mentions of other people who never consented to AI processing
92
+ - Credentials, addresses, financial details that landed in a chat once
93
+
94
+ Rules:
95
+
96
+ - The scanner produces summaries, never quotes. Original messages stay in the crawl archive.
97
+ - Cards promoted from chat archives must not include third-party PII unless the user explicitly approved.
98
+ - Run `brigade scrub --policy public-content` over any export of crawl-derived content before publishing.
99
+ - The publish gate (`hooks/pre-push` + content-guard) catches accidental leaks at the repo boundary.
100
+
101
+ ## Not connected to a chat surface?
102
+
103
+ That is fine. The memory scanner works with just daily session logs and `.learnings/*.md`. Crawlers are additive - they expand the surface from which durable facts get distilled.
@@ -0,0 +1,54 @@
1
+ ---
2
+ topic: content-safety
3
+ category: foundation
4
+ tags: [publishing, content-guard, pre-push, scrubber]
5
+ ---
6
+
7
+ # Content Safety
8
+
9
+ `brigade` installs a publish gate so private infrastructure does not leak into public docs, commits, or social drafts.
10
+
11
+ ## Default blocked classes
12
+
13
+ - Private IP addresses and loopback endpoints
14
+ - Internal hostnames, usernames, and private domains
15
+ - Local service URLs and sensitive ports
16
+ - Secrets, tokens, API keys, OAuth material
17
+ - Personal contact details and account IDs
18
+ - Private project names or unreleased identifiers
19
+ - AI attribution trailers (`Co-Authored-By: Claude`, etc.)
20
+
21
+ ## Two layers
22
+
23
+ 1. **Pre-push hook.** `hooks/pre-push` runs `content-guard` against the working tree before every `git push`. Blocks on violations. Inline allow-tags exist for intentional examples.
24
+ 2. **Deterministic scrub.** `brigade scrub --target .` runs the same scanner standalone. Use it before generating public artifacts (blog posts, social drafts, docs PRs).
25
+
26
+ ## Bypass
27
+
28
+ `git push --no-verify` skips the pre-push hook. Use it only when you understand exactly what you are allowing through. Both `brigade scrub` and the hook log every violation so you can audit later.
29
+
30
+ ## Inline allow
31
+
32
+ If an example genuinely needs a localhost reference: <!-- content-guard: allow localhost-bare -->
33
+
34
+ ```markdown
35
+ A local service might run on localhost:8080. <!-- content-guard: allow localhost-port -->
36
+ ```
37
+
38
+ ## Setup
39
+
40
+ ```bash
41
+ git config core.hooksPath hooks
42
+ ```
43
+
44
+ If content-guard is not installed:
45
+
46
+ ```bash
47
+ git clone https://github.com/solomonneas/content-guard ~/repos/content-guard
48
+ ```
49
+
50
+ The hook reads `CONTENT_GUARD_DIR` (defaults to `$HOME/repos/content-guard`) and `CONTENT_GUARD_POLICY` (defaults to `$SCANNER_DIR/policies/public-repo.json`).
51
+
52
+ ## Why this is part of the product
53
+
54
+ Most leaks are accidental. A blog post mentions a port. A commit message includes an internal IP. A social draft pastes an OAuth profile path. Without a gate, all of those reach the public eventually. The gate runs deterministically on every push, so the question stops being "did I remember to scrub" and starts being "did the scanner say clean".
@@ -0,0 +1,70 @@
1
+ ---
2
+ topic: handoff-flow
3
+ category: foundation
4
+ tags: [memory, handoff, ingester, claude-code, codex]
5
+ ---
6
+
7
+ # Memory Handoff Flow
8
+
9
+ Claude Code, Codex, and other side harnesses write Memory Handoffs to `.claude/memory-handoffs/`. A conservative ingester parses them and routes durable knowledge into canonical memory.
10
+
11
+ ## End-to-end
12
+
13
+ 1. Side harness finishes a substantial task.
14
+ 2. Closeout rule fires: "did this session produce durable knowledge?"
15
+ 3. If yes, the harness writes `.claude/memory-handoffs/<YYYY-MM-DD-HHMM>-<slug>.md` using `TEMPLATE.md`.
16
+ 4. The ingester (run by the memory owner) parses each handoff.
17
+ 5. Handoffs route to: a memory card, an appendable document, or the review inbox.
18
+ 6. Processed handoffs move to `.claude/memory-handoffs/processed/`.
19
+
20
+ ## Multiple Workspaces
21
+
22
+ If you administer more than one agent setup, keep this flow hub-and-spoke. Secondary workspaces write local handoffs, then the canonical owner pulls them into staging directories and runs the same ingester. This lets agents on separate machines or repos inform each other about what changed without creating competing memory stores.
23
+
24
+ See [multi-workspace-handoff-admin](multi-workspace-handoff-admin.md) for the full pattern.
25
+
26
+ ## Auto-promotion rules
27
+
28
+ Only three handoff shapes can silently mutate canonical memory. Everything else lands in `memory/handoff-inbox/` for manual review.
29
+
30
+ **Card auto-promotion:**
31
+ - `Recommended memory action` is `create-card` or `update-card`.
32
+ - `Target card` matches `^[A-Za-z0-9._-]+\.md$` (no path traversal).
33
+ - `Suggested card content` starts with YAML frontmatter.
34
+
35
+ **Document routing:**
36
+ - `Recommended memory action` is `no-card`.
37
+ - `Target document` is one of: `TOOLS.md`, `USER.md`, `rules/*.md`, `.learnings/*.md`.
38
+ - `Suggested document content` has no `##` headings (would parse as new sections).
39
+
40
+ ## Closeout instruction
41
+
42
+ The harness must be told to write handoffs without prompting. Put this in the harness's instruction file (e.g. `~/.claude/CLAUDE.md` or equivalent):
43
+
44
+ ```text
45
+ At the end of any substantial task, check whether the session produced durable
46
+ knowledge. If yes, create a Memory Handoff in `.claude/memory-handoffs/`
47
+ using the standard format. Do this without waiting to be reminded.
48
+ ```
49
+
50
+ ## Verification
51
+
52
+ ```bash
53
+ # Handoffs being produced
54
+ find . -path "*/.claude/memory-handoffs/*.md" -not -path "*/processed/*" -mtime -7
55
+
56
+ # Ingest run
57
+ brigade ingest --target . --dry-run
58
+
59
+ # Cards landed via promotion
60
+ find memory/cards -mtime -7 -name "*.md"
61
+
62
+ # Review inbox depth
63
+ ls memory/handoff-inbox/ 2>/dev/null | wc -l
64
+ ```
65
+
66
+ ## Gotchas
67
+
68
+ - `##` inside `Suggested document content` parses as a new handoff section. Use `###` or deeper.
69
+ - Auto-promotion writes to the filesystem immediately. Ingest during quiet hours if you care about cache continuity.
70
+ - The ingester is intentionally conservative. If your inbox grows, refine your handoff quality; do not loosen the rules.
@@ -0,0 +1,56 @@
1
+ ---
2
+ topic: memory-architecture
3
+ category: foundation
4
+ tags: [memory, bootstrap, handoff, canonical-owner]
5
+ ---
6
+
7
+ # Memory Architecture
8
+
9
+ This workspace uses a single canonical memory owner. Side harnesses may keep local session context, but durable knowledge flows back through Memory Handoffs and is routed into the canonical store.
10
+
11
+ ## Layout
12
+
13
+ ```text
14
+ ./
15
+ AGENTS.md # operating rules + memory contract
16
+ MEMORY.md # slim index pointing to cards
17
+ TOOLS.md # operational runbook (appendable target)
18
+ USER.md # stable user preferences (appendable target)
19
+ IDENTITY.md
20
+ SOUL.md
21
+ HEARTBEAT.md
22
+ SAFETY_RULES.md
23
+ INSTALL_FOR_AGENTS.md
24
+ memory/
25
+ cards/ # durable knowledge cards (auto-promotion target)
26
+ decay/ # optional staleness scan output + refresh queue
27
+ handoff-inbox/ # ambiguous handoffs land here for review
28
+ rules/ # workflow rules (appendable target)
29
+ .learnings/ # concrete failures + lessons (appendable target)
30
+ .claude/
31
+ memory-handoffs/
32
+ TEMPLATE.md
33
+ processed/ # archive of ingested handoffs
34
+ ```
35
+
36
+ ## Why one owner
37
+
38
+ Two canonical memory systems is one too many. Either both have to be reconciled on every read, or one drifts silently and contradicts the other. Pick one owner. Everything else writes to it through handoffs.
39
+
40
+ ## What goes where
41
+
42
+ | Kind of knowledge | Target |
43
+ |-------------------|--------|
44
+ | Architecture decision, durable concept, recurring pattern | `memory/cards/*.md` (frontmatter required) |
45
+ | Command, port, endpoint, script, runbook | `TOOLS.md` |
46
+ | Stable user preference | `USER.md` |
47
+ | Workflow rule, recurring correction | `rules/<name>.md` |
48
+ | Concrete failure | `.learnings/ERRORS.md` |
49
+ | Lesson or workaround | `.learnings/LEARNINGS.md` |
50
+ | Missing capability or enhancement request | `.learnings/FEATURE_REQUESTS.md` |
51
+
52
+ ## Maintenance
53
+
54
+ - Keep `MEMORY.md` under ~200 lines so it stays in cache.
55
+ - Remove stale entries after verifying the source is obsolete.
56
+ - Consolidate duplicates. One topic, one card.
@@ -0,0 +1,58 @@
1
+ ---
2
+ topic: memory-care-staleness
3
+ category: foundation
4
+ tags: [memory, staleness, decay, refresh, maintenance]
5
+ ---
6
+
7
+ # Memory Care Staleness
8
+
9
+ Memory needs care after it is written. Durable cards can become wrong when services move, workflows change, models are renamed, or project priorities expire. A staleness checker gives the memory owner a queue of cards that need refresh, without letting an agent rewrite sensitive or judgment-heavy knowledge blindly.
10
+
11
+ ## Reference Loop
12
+
13
+ ```text
14
+ memory/cards/*.md
15
+ |
16
+ v
17
+ card decay scanner
18
+ |
19
+ v
20
+ memory/cards/decay/scan-latest.json
21
+ memory/cards/decay/refresh-queue.json
22
+ |
23
+ v
24
+ safe refresh agent or manual review
25
+ ```
26
+
27
+ ## Scanner Output
28
+
29
+ Store scan state under `memory/cards/decay/`:
30
+
31
+ - `scan-latest.json` - latest full scan, counts, card statuses, decay ratios, and refresh queue size.
32
+ - `refresh-queue.json` - small queue of cards that are stale enough to review.
33
+
34
+ The scanner should report at least total cards, fresh count, aging count, stale count, critical count, and refresh queue size.
35
+
36
+ ## Safe Refresh Rules
37
+
38
+ Only auto-refresh cards when current facts are grounded in local source-of-truth files read during the run. Good sources include `TOOLS.md`, `MEMORY.md`, recent `memory/YYYY-MM-DD.md`, local project docs, local scripts, and repo health reports.
39
+
40
+ Do not auto-refresh cards that require human judgment, personal context, career decisions, school work, business strategy, or outside research. Put those in a manual queue.
41
+
42
+ Never refresh by only bumping an `updated:` date. The content must change because a current source proves it should change.
43
+
44
+ ## Suggested Schedule
45
+
46
+ - Daily scanner during quiet hours.
47
+ - Safe auto-refresh shortly after the scanner, capped to a small number of cards.
48
+ - Weekly deep report for manual review of sensitive or repeatedly skipped stale cards.
49
+
50
+ ## Verification
51
+
52
+ ```bash
53
+ test -f memory/cards/decay/scan-latest.json
54
+ test -f memory/cards/decay/refresh-queue.json
55
+ jq '.counts, .refresh_queue_size' memory/cards/decay/scan-latest.json
56
+ ```
57
+
58
+ If the queue grows for several days, either the refresh agent is too conservative, the source-of-truth files are stale, or the cards need manual pruning.