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.
- brigade/__init__.py +3 -0
- brigade/__main__.py +5 -0
- brigade/cli.py +258 -0
- brigade/config.py +65 -0
- brigade/doctor.py +393 -0
- brigade/fragments.py +64 -0
- brigade/handoff.py +23 -0
- brigade/ingest.py +298 -0
- brigade/install.py +217 -0
- brigade/prompt.py +135 -0
- brigade/py.typed +0 -0
- brigade/reconfigure.py +64 -0
- brigade/registry.py +39 -0
- brigade/scrub.py +90 -0
- brigade/selection.py +66 -0
- brigade/station.py +36 -0
- brigade/status.py +24 -0
- brigade/templates/claude/memory-handoffs/TEMPLATE.md +57 -0
- brigade/templates/codex/memory-handoffs/TEMPLATE.md +57 -0
- brigade/templates/depth/repo.json +12 -0
- brigade/templates/depth/workspace.json +30 -0
- brigade/templates/generic/harness-adapter-checklist.md +55 -0
- brigade/templates/generic/memory-contract.md +41 -0
- brigade/templates/harnesses/claude.json +12 -0
- brigade/templates/harnesses/codex.json +11 -0
- brigade/templates/harnesses/hermes.json +16 -0
- brigade/templates/harnesses/openclaw.json +17 -0
- brigade/templates/hermes/README.md +25 -0
- brigade/templates/hermes/memory-handoff.harness.json +36 -0
- brigade/templates/hermes/model-lanes.harness.json +17 -0
- brigade/templates/hermes/workspace.harness.json +30 -0
- brigade/templates/hooks/pre-push +36 -0
- brigade/templates/includes/publisher.json +15 -0
- brigade/templates/memory/cards/backup-restic.md +126 -0
- brigade/templates/memory/cards/chat-surface-crawlers.md +103 -0
- brigade/templates/memory/cards/content-safety.md +54 -0
- brigade/templates/memory/cards/handoff-flow.md +70 -0
- brigade/templates/memory/cards/memory-architecture.md +56 -0
- brigade/templates/memory/cards/memory-care-staleness.md +58 -0
- brigade/templates/memory/cards/memory-scanner.md +98 -0
- brigade/templates/memory/cards/multi-workspace-handoff-admin.md +63 -0
- brigade/templates/memory/cards/obsidian-notes.md +82 -0
- brigade/templates/memory/cards/pipeline-standups.md +88 -0
- brigade/templates/memory/cards/tokenjuice-output-compaction.md +106 -0
- brigade/templates/openclaw/README.md +40 -0
- brigade/templates/openclaw/acp-escalation.openclaw.json +33 -0
- brigade/templates/openclaw/model-aliases.openclaw.json +21 -0
- brigade/templates/openclaw/ollama-memory-search.openclaw.json +24 -0
- brigade/templates/policies/public-content.json +28 -0
- brigade/templates/policies/public-repo.json +27 -0
- brigade/templates/scripts/backup-restic.sh +156 -0
- brigade/templates/skills/note/SKILL.md +173 -0
- brigade/templates/workspace/AGENTS.md +146 -0
- brigade/templates/workspace/CLAUDE.md +48 -0
- brigade/templates/workspace/HEARTBEAT.md +41 -0
- brigade/templates/workspace/IDENTITY.md +27 -0
- brigade/templates/workspace/INSTALL_FOR_AGENTS.md +61 -0
- brigade/templates/workspace/MEMORY.md +102 -0
- brigade/templates/workspace/SAFETY_RULES.md +164 -0
- brigade/templates/workspace/SOUL.md +92 -0
- brigade/templates/workspace/TOOLS.md +116 -0
- brigade/templates/workspace/USER.md +88 -0
- brigade/templates.py +88 -0
- brigade_cli-0.5.0.dist-info/METADATA +211 -0
- brigade_cli-0.5.0.dist-info/RECORD +69 -0
- brigade_cli-0.5.0.dist-info/WHEEL +5 -0
- brigade_cli-0.5.0.dist-info/entry_points.txt +3 -0
- brigade_cli-0.5.0.dist-info/licenses/LICENSE +21 -0
- 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.
|