@matt82198/aesop 0.1.0-beta.3 → 0.1.0-beta.5

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 (234) hide show
  1. package/CHANGELOG.md +79 -95
  2. package/CLAUDE-TEMPLATE.md +115 -0
  3. package/README.md +126 -245
  4. package/aesop.config.example.json +34 -26
  5. package/bin/CLAUDE.md +67 -0
  6. package/bin/cli.js +593 -36
  7. package/daemons/CLAUDE.md +36 -0
  8. package/daemons/backup-fleet.sh +92 -21
  9. package/daemons/run-watchdog.sh +95 -12
  10. package/dash/CLAUDE.md +32 -0
  11. package/dash/dash-extra.mjs +194 -21
  12. package/dash/watchdog-gui.sh +23 -6
  13. package/docs/BEHAVIORAL-PR-REVIEW.md +86 -0
  14. package/docs/CHECKPOINTING.md +100 -0
  15. package/docs/DISPATCH-MODEL.md +11 -7
  16. package/docs/FORENSICS.md +204 -0
  17. package/docs/GOVERNANCE.md +4 -2
  18. package/docs/HOOK-INSTALL.md +307 -0
  19. package/docs/HOW-THE-LOOP-WORKS.md +175 -0
  20. package/docs/MEMORY-TEMPLATE.md +61 -0
  21. package/docs/README.md +44 -0
  22. package/docs/RELEASING.md +159 -0
  23. package/docs/RELIABILITY.md +61 -0
  24. package/docs/RESTORE.md +397 -0
  25. package/docs/SCRIPTS-POLICY.md +97 -0
  26. package/docs/archive/README.md +3 -0
  27. package/docs/archive/spikes/tiered-cognition/ACTIVATION.md +125 -0
  28. package/docs/archive/spikes/tiered-cognition/DESIGN.md +287 -0
  29. package/docs/archive/spikes/tiered-cognition/FINDINGS.md +113 -0
  30. package/docs/archive/spikes/tiered-cognition/README.md +27 -0
  31. package/docs/archive/spikes/tiered-cognition/aesop-cognition.example.md +32 -0
  32. package/docs/archive/spikes/tiered-cognition/force-model-policy.merged.mjs +673 -0
  33. package/docs/archive/spikes/tiered-cognition/strip-tools-hook.mjs +434 -0
  34. package/docs/case-study-portfolio.md +61 -0
  35. package/docs/self-stats-data.json +11 -0
  36. package/docs/templates/FLEET-OPS-ANALYSIS.example.md +27 -0
  37. package/docs/templates/FLEET-OPS-RECOMMENDATIONS.example.md +24 -0
  38. package/docs/templates/PROPOSALS-LOG.example.md +64 -0
  39. package/hooks/CLAUDE.md +61 -0
  40. package/hooks/claude/force-model-policy.mjs +159 -0
  41. package/hooks/pre-push-policy.sh +753 -0
  42. package/mcp/CLAUDE.md +213 -0
  43. package/mcp/package.json +26 -0
  44. package/mcp/server.mjs +543 -0
  45. package/monitor/.signal-state.json +3 -0
  46. package/monitor/ACTIONS.log +1 -0
  47. package/monitor/BRIEF.md +24 -0
  48. package/monitor/CHARTER.md +75 -88
  49. package/monitor/CLAUDE.md +40 -0
  50. package/monitor/SIGNALS.json +54 -0
  51. package/monitor/collect-signals.mjs +613 -61
  52. package/package.json +15 -3
  53. package/scan/fleet-scan.example.mjs +292 -0
  54. package/skills/CLAUDE.md +3 -0
  55. package/skills/healthcheck/SKILL.md +44 -0
  56. package/skills/power/SKILL.md +161 -0
  57. package/state_store/CLAUDE.md +39 -0
  58. package/state_store/__init__.py +24 -0
  59. package/state_store/__pycache__/__init__.cpython-314.pyc +0 -0
  60. package/state_store/__pycache__/api.cpython-314.pyc +0 -0
  61. package/state_store/__pycache__/export.cpython-314.pyc +0 -0
  62. package/state_store/__pycache__/ingest.cpython-314.pyc +0 -0
  63. package/state_store/__pycache__/projections.cpython-314.pyc +0 -0
  64. package/state_store/__pycache__/store.cpython-314.pyc +0 -0
  65. package/state_store/api.py +35 -0
  66. package/state_store/export.py +19 -0
  67. package/state_store/ingest.py +24 -0
  68. package/state_store/projections.py +52 -0
  69. package/state_store/store.py +102 -0
  70. package/tools/CLAUDE.md +72 -0
  71. package/tools/__pycache__/alert_bridge.cpython-314.pyc +0 -0
  72. package/tools/__pycache__/buildlog.cpython-314.pyc +0 -0
  73. package/tools/__pycache__/ci_merge_wait.cpython-314.pyc +0 -0
  74. package/tools/__pycache__/ensure_state.cpython-314.pyc +0 -0
  75. package/tools/__pycache__/eod_sweep.cpython-314.pyc +0 -0
  76. package/tools/__pycache__/fleet_ledger.cpython-314.pyc +0 -0
  77. package/tools/__pycache__/fleet_prompt_extractor.cpython-314.pyc +0 -0
  78. package/tools/__pycache__/healthcheck.cpython-314.pyc +0 -0
  79. package/tools/__pycache__/heartbeat.cpython-314.pyc +0 -0
  80. package/tools/__pycache__/inbox_drain.cpython-314.pyc +0 -0
  81. package/tools/__pycache__/launch_tui.cpython-314.pyc +0 -0
  82. package/tools/__pycache__/metrics_gate.cpython-314.pyc +0 -0
  83. package/tools/__pycache__/orchestrator_status.cpython-314.pyc +0 -0
  84. package/tools/__pycache__/power_selftest.cpython-314.pyc +0 -0
  85. package/tools/__pycache__/prepublish_scan.cpython-314.pyc +0 -0
  86. package/tools/__pycache__/rotate_logs.cpython-314.pyc +0 -0
  87. package/tools/__pycache__/scanner_selftest.cpython-314.pyc +0 -0
  88. package/tools/__pycache__/secret_scan.cpython-314.pyc +0 -0
  89. package/tools/__pycache__/self_stats.cpython-314.pyc +0 -0
  90. package/tools/__pycache__/session_usage_summary.cpython-314.pyc +0 -0
  91. package/tools/__pycache__/stall_check.cpython-314.pyc +0 -0
  92. package/tools/__pycache__/transcript_replay.cpython-314.pyc +0 -0
  93. package/tools/__pycache__/transcript_timeline.cpython-314.pyc +0 -0
  94. package/tools/__pycache__/verify_dash.cpython-314.pyc +0 -0
  95. package/tools/__pycache__/verify_submit_encoding.cpython-314.pyc +0 -0
  96. package/tools/agent-forensics.sh +186 -0
  97. package/tools/alert_bridge.py +449 -0
  98. package/tools/buildlog.py +182 -0
  99. package/tools/ci_merge_wait.py +317 -0
  100. package/tools/ensure_state.py +94 -0
  101. package/tools/eod_sweep.py +239 -0
  102. package/tools/fleet_ledger.py +272 -0
  103. package/tools/fleet_prompt_extractor.py +134 -0
  104. package/tools/healthcheck.py +296 -0
  105. package/tools/heartbeat.py +131 -0
  106. package/tools/inbox_drain.py +249 -0
  107. package/tools/launch_tui.py +51 -3
  108. package/tools/lock.mjs +211 -0
  109. package/tools/metrics_gate.py +205 -0
  110. package/tools/orchestrator_status.py +99 -0
  111. package/tools/power_selftest.py +386 -0
  112. package/tools/prepublish_scan.py +84 -0
  113. package/tools/proposals.mjs +248 -0
  114. package/tools/reconstitute.sh +467 -0
  115. package/tools/rotate_logs.py +228 -0
  116. package/tools/scanner_selftest.py +303 -0
  117. package/tools/secret_scan.py +138 -31
  118. package/tools/self_stats.py +509 -0
  119. package/tools/session_usage_summary.py +198 -0
  120. package/tools/stall_check.py +172 -0
  121. package/tools/svg_to_png.mjs +50 -0
  122. package/tools/transcript_replay.py +236 -0
  123. package/tools/transcript_timeline.py +184 -0
  124. package/tools/verify_dash.py +513 -0
  125. package/tools/verify_submit_encoding.py +202 -0
  126. package/ui/CLAUDE.md +125 -0
  127. package/ui/__pycache__/agents.cpython-314.pyc +0 -0
  128. package/ui/__pycache__/collectors.cpython-314.pyc +0 -0
  129. package/ui/__pycache__/config.cpython-314.pyc +0 -0
  130. package/ui/__pycache__/cost.cpython-314.pyc +0 -0
  131. package/ui/__pycache__/csrf.cpython-314.pyc +0 -0
  132. package/ui/__pycache__/handler.cpython-314.pyc +0 -0
  133. package/ui/__pycache__/render.cpython-314.pyc +0 -0
  134. package/ui/__pycache__/serve.cpython-314.pyc +0 -0
  135. package/ui/__pycache__/sse.cpython-314.pyc +0 -0
  136. package/ui/agents.py +183 -0
  137. package/ui/api/__init__.py +84 -0
  138. package/ui/api/__pycache__/__init__.cpython-314.pyc +0 -0
  139. package/ui/api/__pycache__/submit.cpython-314.pyc +0 -0
  140. package/ui/api/__pycache__/tracker.cpython-314.pyc +0 -0
  141. package/ui/api/submit.py +97 -0
  142. package/ui/api/tracker.py +116 -0
  143. package/ui/collectors.py +735 -0
  144. package/ui/config.py +123 -0
  145. package/ui/cost.py +260 -0
  146. package/ui/csrf.py +144 -0
  147. package/ui/handler.py +676 -0
  148. package/ui/render.py +49 -0
  149. package/ui/serve.py +68 -796
  150. package/ui/sse.py +183 -0
  151. package/ui/web/.gitattributes +13 -0
  152. package/ui/web/dist/assets/index-2LZDQirC.js +9 -0
  153. package/ui/web/dist/assets/index-D4M1qyOv.css +1 -0
  154. package/ui/web/dist/index.html +14 -0
  155. package/ui/web/index.html +13 -0
  156. package/ui/web/package-lock.json +2225 -0
  157. package/ui/web/package.json +26 -0
  158. package/ui/web/src/App.test.tsx +74 -0
  159. package/ui/web/src/App.tsx +142 -0
  160. package/ui/web/src/CONTRIBUTING-UI.md +49 -0
  161. package/ui/web/src/components/AgentRow.css +187 -0
  162. package/ui/web/src/components/AgentRow.test.tsx +209 -0
  163. package/ui/web/src/components/AgentRow.tsx +207 -0
  164. package/ui/web/src/components/AgentsPanel.css +108 -0
  165. package/ui/web/src/components/AgentsPanel.test.tsx +41 -0
  166. package/ui/web/src/components/AgentsPanel.tsx +58 -0
  167. package/ui/web/src/components/AlertsPanel.css +88 -0
  168. package/ui/web/src/components/AlertsPanel.test.tsx +51 -0
  169. package/ui/web/src/components/AlertsPanel.tsx +67 -0
  170. package/ui/web/src/components/BacklogPanel.test.tsx +126 -0
  171. package/ui/web/src/components/BacklogPanel.tsx +122 -0
  172. package/ui/web/src/components/CostChart.css +110 -0
  173. package/ui/web/src/components/CostChart.test.tsx +144 -0
  174. package/ui/web/src/components/CostChart.tsx +152 -0
  175. package/ui/web/src/components/CostTable.css +93 -0
  176. package/ui/web/src/components/CostTable.test.tsx +165 -0
  177. package/ui/web/src/components/CostTable.tsx +94 -0
  178. package/ui/web/src/components/EventsFeed.css +68 -0
  179. package/ui/web/src/components/EventsFeed.test.tsx +36 -0
  180. package/ui/web/src/components/EventsFeed.tsx +31 -0
  181. package/ui/web/src/components/HealthHeader.css +137 -0
  182. package/ui/web/src/components/HealthHeader.test.tsx +278 -0
  183. package/ui/web/src/components/HealthHeader.tsx +281 -0
  184. package/ui/web/src/components/InboxForm.css +135 -0
  185. package/ui/web/src/components/InboxForm.test.tsx +208 -0
  186. package/ui/web/src/components/InboxForm.tsx +116 -0
  187. package/ui/web/src/components/MessagesTail.module.css +144 -0
  188. package/ui/web/src/components/MessagesTail.test.tsx +176 -0
  189. package/ui/web/src/components/MessagesTail.tsx +94 -0
  190. package/ui/web/src/components/ReposPanel.css +90 -0
  191. package/ui/web/src/components/ReposPanel.test.tsx +45 -0
  192. package/ui/web/src/components/ReposPanel.tsx +67 -0
  193. package/ui/web/src/components/Scorecard.css +106 -0
  194. package/ui/web/src/components/Scorecard.test.tsx +117 -0
  195. package/ui/web/src/components/Scorecard.tsx +85 -0
  196. package/ui/web/src/components/Timeline.module.css +151 -0
  197. package/ui/web/src/components/Timeline.test.tsx +215 -0
  198. package/ui/web/src/components/Timeline.tsx +99 -0
  199. package/ui/web/src/components/TrackerBoard.test.tsx +121 -0
  200. package/ui/web/src/components/TrackerBoard.tsx +107 -0
  201. package/ui/web/src/components/TrackerCard.test.tsx +180 -0
  202. package/ui/web/src/components/TrackerCard.tsx +160 -0
  203. package/ui/web/src/components/TrackerForm.test.tsx +189 -0
  204. package/ui/web/src/components/TrackerForm.tsx +144 -0
  205. package/ui/web/src/lib/api.ts +218 -0
  206. package/ui/web/src/lib/format.test.ts +89 -0
  207. package/ui/web/src/lib/format.ts +103 -0
  208. package/ui/web/src/lib/sanitizeUrl.test.ts +84 -0
  209. package/ui/web/src/lib/sanitizeUrl.ts +38 -0
  210. package/ui/web/src/lib/types.ts +230 -0
  211. package/ui/web/src/lib/useHashRoute.test.ts +60 -0
  212. package/ui/web/src/lib/useHashRoute.ts +23 -0
  213. package/ui/web/src/lib/useSSE.ts +175 -0
  214. package/ui/web/src/main.tsx +10 -0
  215. package/ui/web/src/styles/global.css +179 -0
  216. package/ui/web/src/styles/theme.css +184 -0
  217. package/ui/web/src/styles/work.css +572 -0
  218. package/ui/web/src/test/fixtures.ts +385 -0
  219. package/ui/web/src/test/setup.ts +49 -0
  220. package/ui/web/src/views/Activity.module.css +43 -0
  221. package/ui/web/src/views/Activity.test.tsx +89 -0
  222. package/ui/web/src/views/Activity.tsx +31 -0
  223. package/ui/web/src/views/Cost.css +87 -0
  224. package/ui/web/src/views/Cost.test.tsx +142 -0
  225. package/ui/web/src/views/Cost.tsx +54 -0
  226. package/ui/web/src/views/Overview.css +51 -0
  227. package/ui/web/src/views/Overview.test.tsx +76 -0
  228. package/ui/web/src/views/Overview.tsx +46 -0
  229. package/ui/web/src/views/Work.test.tsx +82 -0
  230. package/ui/web/src/views/Work.tsx +79 -0
  231. package/ui/web/src/vite-env.d.ts +10 -0
  232. package/ui/web/tsconfig.json +22 -0
  233. package/ui/web/vite.config.ts +25 -0
  234. package/ui/web/vitest.config.ts +12 -0
@@ -0,0 +1,397 @@
1
+ # Cross-Machine Reconstitution — Restore Aesop & Fleet After a Wipe
2
+
3
+ **Purpose**: Aesop is designed so that compute is disposable. The brain (rules, memory, configuration) and fleet work (git commits, backups) live in remotes. This playbook describes how to reconstitute a full fleet on a new machine from scratch using only git and the aesop harness.
4
+
5
+ ---
6
+
7
+ ## 1. Before a Wipe: Continuous Posture
8
+
9
+ **What the watchdog guarantees** (if running continuously):
10
+
11
+ The watchdog daemon (`daemons/run-watchdog.sh`) runs every 150 seconds and:
12
+ - **Discovers fleet repos** automatically by scanning `~/.* ~/* ~/dev/*` (dot-directories in home, home root, dev subtree)
13
+ - **Backs up uncommitted work** as ephemeral commits to `backup/wip-YYYYMMDD` branches (named by calendar date)
14
+ - **Backs up unpushed commits** on `master`/`main` to `backup/master-wip-YYYYMMDD` branches
15
+ - **Pushes feature branches** normally to origin
16
+ - **Scans for secrets** before every push (via `tools/secret_scan.py`); blocks if credentials are detected
17
+ - **Writes heartbeat** to `state/.watchdog-heartbeat` (epoch seconds; used by the watchdog itself to avoid duplicate runs)
18
+ - **Logs all actions** to `state/FLEET-BACKUP.log` (append-only; persists across sessions)
19
+ - **Records repo state** to `state/.watchdog-repos.json` (which repos were touched, what state: SNAPSHOTTED/PUSHED/BLOCKED/CLEAN)
20
+
21
+ **Verify your current posture right now**:
22
+
23
+ ```bash
24
+ # 1. Check watchdog heartbeat age (should be <200s if daemon is alive)
25
+ stat state/.watchdog-heartbeat
26
+ # On Unix: check "Modify" timestamp
27
+ # On Windows: check "Last Write Time"
28
+
29
+ # 2. Tail the backup log to see last cycle
30
+ tail -20 state/FLEET-BACKUP.log
31
+
32
+ # 3. Check which repos were touched in the last cycle
33
+ cat state/.watchdog-repos.json | jq '.' # (requires jq, or use any JSON viewer)
34
+ ```
35
+
36
+ **What is NOT backed up automatically**:
37
+ - Heartbeat files, logs, and JSON status are transient (in `.gitignore`) — useful for live monitoring but not recovered after a wipe.
38
+ - `aesop.config.json` (holds your local paths, credentials, custom settings) is git-ignored for security — you must recreate it.
39
+ - The private brain directory (`~/.claude/`) lives in a separate private remote, not in this public aesop repo.
40
+
41
+ ---
42
+
43
+ ## 2. After a Wipe: Reconstitute the Fleet
44
+
45
+ ### Step 1: Clone Aesop
46
+
47
+ ```bash
48
+ git clone <aesop-remote-url> ~/aesop
49
+ cd ~/aesop
50
+ ```
51
+
52
+ Replace `<aesop-remote-url>` with your remote (e.g., `https://github.com/your-org/aesop` or `git@github.com:your-org/aesop.git`).
53
+
54
+ ### Step 2: Restore the Private Brain
55
+
56
+ The team brain lives in a separate private remote (not in the aesop repo). Clone it early so rules and memory prime your session:
57
+
58
+ ```bash
59
+ git clone <brain-remote-url> ~/.claude
60
+ ```
61
+
62
+ This populates:
63
+ - `~/.claude/CLAUDE.md` — your team's cardinal rules and agent governance
64
+ - `~/.claude/MEMORY.md` or individual fact files in `~/.claude/memory/` — your team knowledge
65
+ - `~/.claude/docs/` — architecture guides, dispatch patterns, etc.
66
+
67
+ Without the brain, Claude Code sessions will lack your org's policies and context.
68
+
69
+ ### Step 3: Create Local Configuration
70
+
71
+ ```bash
72
+ cd ~/aesop
73
+ cp aesop.config.example.json aesop.config.json
74
+ ```
75
+
76
+ Edit `aesop.config.json` to match your setup:
77
+ - `aesop_root`: path to your aesop installation (e.g., `/home/user/aesop` or `$HOME/aesop`)
78
+ - `brain_root`: path to your brain (e.g., `$HOME/.claude`)
79
+ - `scripts_root`: path to reusable scripts (e.g., `$HOME/scripts`)
80
+ - `temp_root`: temporary scratch directory (e.g., `/tmp` or `$env:TEMP` on Windows)
81
+ - `repos[]`: list of fleet repos (path, name, primary_branch, backup_branch)
82
+ - `watchdog.cycle_seconds`: how often the daemon runs (default 150)
83
+ - `watchdog.heartbeat_threshold_seconds`: how long before heartbeat is considered stale (default 200)
84
+
85
+ ### Step 4: Create Required Directories
86
+
87
+ ```bash
88
+ mkdir -p ~/aesop/state
89
+ mkdir -p ~/.claude/memory # If not already created by brain clone
90
+ ```
91
+
92
+ The `state/` directory will be populated by the watchdog at runtime.
93
+
94
+ ### Step 5: Set Environment Variables (Optional but Recommended)
95
+
96
+ ```bash
97
+ # Bash/Unix
98
+ export AESOP_ROOT=$HOME/aesop
99
+
100
+ # PowerShell/Windows
101
+ $env:AESOP_ROOT = "$env:USERPROFILE\aesop"
102
+ ```
103
+
104
+ The scripts check `AESOP_ROOT` and default to `.` (current directory) if unset. Setting it explicitly avoids confusion.
105
+
106
+ ### Step 6: Verify the Watchdog
107
+
108
+ Run the watchdog in single-shot mode to verify the setup:
109
+
110
+ ```bash
111
+ bash $AESOP_ROOT/daemons/run-watchdog.sh --once
112
+ ```
113
+
114
+ Expected output: logs to `state/FLEET-BACKUP.log` showing which repos it discovered and their states (CLEAN, SNAPSHOTTED, PUSHED, or BLOCKED).
115
+
116
+ ### Step 7: Clone Fleet Repos Using Reconstitute
117
+
118
+ The aesop harness includes a bootstrap tool to clone and fetch all your fleet repos automatically. This is the recommended approach for reconstituting a full fleet:
119
+
120
+ #### Option A: Using aesop.config.json (Recommended)
121
+
122
+ If your `aesop.config.json` includes a `repos` array with `url` and `path` fields, run:
123
+
124
+ ```bash
125
+ bash $AESOP_ROOT/tools/reconstitute.sh
126
+ ```
127
+
128
+ This will clone any missing repos and fetch existing ones, printing a summary of cloned, fetched, and failed repos.
129
+
130
+ #### Option B: Using a repos file
131
+
132
+ Create a text file with one repo per line in the format `<url> <target-dir>` or `<url>⇥<target-dir>` (tab-delimited):
133
+
134
+ ```
135
+ https://github.com/user/project1.git ~/project1
136
+ https://github.com/user/project2.git ~/project2
137
+ ```
138
+
139
+ Then run:
140
+
141
+ ```bash
142
+ bash $AESOP_ROOT/tools/reconstitute.sh --repos-file repos.txt
143
+ ```
144
+
145
+ #### Dry-run mode (preview without executing)
146
+
147
+ ```bash
148
+ bash $AESOP_ROOT/tools/reconstitute.sh --dry-run
149
+ ```
150
+
151
+ #### Manual fallback
152
+
153
+ If you prefer to clone repos manually or need fine-grained control, you can still clone individually:
154
+
155
+ ```bash
156
+ # For each fleet repo, clone from its remote
157
+ git clone <repo-url> <local-path>
158
+
159
+ # Example: if repos are at ~/project1, ~/project2, etc.
160
+ cd ~/project1 && git fetch -q origin
161
+ cd ~/project2 && git fetch -q origin
162
+ ```
163
+
164
+ ### Step 8: Recover Snapshotted Uncommitted Work
165
+
166
+ The watchdog pushed uncommitted work to `backup/wip-YYYYMMDD` branches. To recover:
167
+
168
+ ```bash
169
+ # In each repo, check for backup branches
170
+ git branch -r | grep backup
171
+
172
+ # Example: backup/wip-20260712 exists
173
+ # Inspect what was snapshotted
174
+ git log --oneline origin/backup/wip-20260712 -5
175
+
176
+ # RECOMMENDED: Cherry-pick specific commits (safe, adds commits on top)
177
+ git cherry-pick origin/backup/wip-20260712
178
+
179
+ # WARNING: Only use reset if you will NOT do Step 9 after this step.
180
+ # Resetting here will be overwritten by Step 9's reset, losing work.
181
+ # (Use reset only if you're certain you want to replace your entire branch
182
+ # and have no unpushed commits to recover in Step 9)
183
+ # git reset --hard origin/backup/wip-20260712
184
+ ```
185
+
186
+ ### Step 9: Recover Snapshotted Unpushed Commits on Main/Master
187
+
188
+ If you had unpushed commits on your default branch, the watchdog pushed them to `backup/master-wip-YYYYMMDD`:
189
+
190
+ ```bash
191
+ # Check for master/main backup branches
192
+ git branch -r | grep backup.*master
193
+
194
+ # Example: backup/master-wip-20260712 exists
195
+ # Inspect the commits
196
+ git log --oneline origin/backup/master-wip-20260712 -10
197
+
198
+ # Reapply them to your main branch
199
+ git reset --hard origin/backup/master-wip-20260712
200
+ git push origin HEAD:main # or 'master' if that's your primary branch
201
+ ```
202
+
203
+ ### Step 10: Restart the Daemon
204
+
205
+ Once your fleet is restored and verified, restart the watchdog in daemon mode:
206
+
207
+ ```bash
208
+ bash $AESOP_ROOT/daemons/run-watchdog.sh &
209
+ ```
210
+
211
+ Or, if using your own process manager (systemd, supervisor, etc.), start it according to your setup.
212
+
213
+ The watchdog will now run every 150 seconds, backing up any new changes and pushing them to origin.
214
+
215
+ ---
216
+
217
+ ## 3. Recovering the Private Brain
218
+
219
+ The brain directory (`~/.claude/`) is the single point of truth for your org's rules, memory, and agent behavior. It lives in a **separate private remote** (not in the public aesop repo) so credentials and private facts never leak.
220
+
221
+ ### Clone the Brain
222
+
223
+ Before or alongside restoring aesop, clone your brain:
224
+
225
+ ```bash
226
+ git clone <your-private-brain-remote> ~/.claude
227
+ ```
228
+
229
+ ### Brain Contents
230
+
231
+ Once cloned, you have:
232
+
233
+ **CLAUDE.md** — Your team's version of the cardinal rules, tailored to your org:
234
+ - Which domains your team works on (e.g., "infrastructure," "security," "data")
235
+ - Org-specific policies (e.g., approval chains, secret-scan rules, cost limits)
236
+ - Escalation paths and decision-makers
237
+ - Reusable tool policies (e.g., "AWS CLI always requires approval")
238
+
239
+ **MEMORY.md or `memory/` fact files** — Long-lived team knowledge:
240
+ - Team names, email addresses, and roles
241
+ - Past decisions and their rationales (searchable history)
242
+ - Known limitations and workarounds
243
+ - Approved vendors, tool licenses, cost budgets
244
+
245
+ **docs/** — Org-specific architecture and tutorials:
246
+ - Dispatch patterns that work well for your team
247
+ - Performance characteristics and lessons learned
248
+ - Custom monitoring and alerting playbooks
249
+
250
+ ### Why It's Separate
251
+
252
+ The brain is in a private repo because:
253
+ - It may contain credentials (API keys for dashboards, auth tokens for internal services).
254
+ - It may reference internal team facts (email addresses, org structure) that are not public.
255
+ - It evolves independently of the aesop harness itself.
256
+
257
+ **Do NOT** put the brain in the public aesop repo. Clone it from your private remote on every fresh machine.
258
+
259
+ ---
260
+
261
+ ## 4. Drill: Test Recovery on a Second Machine or VM
262
+
263
+ To verify this playbook works end-to-end, run a recovery on a clean machine (or a new VM):
264
+
265
+ ### Prerequisites
266
+
267
+ - Git is installed and configured with access to your remotes (SSH keys or credentials available).
268
+ - Bash is available (Git Bash on Windows, bash on Unix).
269
+ - Python 3.10+ is available (for secret-scan, optional for testing the watchdog).
270
+ - Node.js 18+ is available (optional; dashboard requires it but is not essential for the watchdog).
271
+
272
+ ### Drill Steps
273
+
274
+ ```bash
275
+ # 1. Start with a clean home directory (or VM)
276
+ # Simulate a wipe by deleting ~/aesop, ~/project1, ~/project2, etc.
277
+
278
+ # 2. Clone aesop
279
+ git clone <aesop-remote> ~/aesop
280
+ cd ~/aesop
281
+
282
+ # 3. Clone the brain
283
+ git clone <brain-remote> ~/.claude
284
+
285
+ # 4. Create config (edit paths to match the new machine)
286
+ cp aesop.config.example.json aesop.config.json
287
+ # Edit aesop.config.json with your local paths and repo list (including repos[].url)
288
+
289
+ # 5. Create state directory
290
+ mkdir -p ~/aesop/state
291
+
292
+ # 6. Clone fleet repos using reconstitute
293
+ bash $AESOP_ROOT/tools/reconstitute.sh
294
+
295
+ # 7. Run watchdog once
296
+ export AESOP_ROOT=$HOME/aesop
297
+ bash $AESOP_ROOT/daemons/run-watchdog.sh --once
298
+
299
+ # 8. Check the log
300
+ tail -30 $AESOP_ROOT/state/FLEET-BACKUP.log
301
+
302
+ # 9. Recover any snapshotted work from backup branches
303
+ cd ~/project1
304
+ git branch -r | grep backup
305
+ git log --oneline origin/backup/wip-* -5
306
+ # (cherry-pick or reset as needed)
307
+
308
+ # 10. Verify all work is recovered
309
+ git status
310
+ git log --oneline -10
311
+ ```
312
+
313
+ ### Expected Recovery Time
314
+
315
+ For a typical fleet (3–5 repos, average size 100MB–500MB):
316
+ - **Clone aesop + brain**: ~30 seconds
317
+ - **Create config + directories**: ~10 seconds
318
+ - **Clone fleet repos**: ~2–5 minutes (depends on size and network)
319
+ - **Run watchdog once**: ~30 seconds
320
+ - **Recover snapshotted work**: ~1–2 minutes (git operations)
321
+
322
+ **Total**: ~5–10 minutes start-to-finish.
323
+
324
+ For very large repos (>1GB) or slow networks, add 2–3 minutes per repo.
325
+
326
+ ---
327
+
328
+ ## 5. Known Limitations
329
+
330
+ ### What This Playbook Does NOT Do
331
+
332
+ 1. **Automatic repo discovery on clone (Solved by reconstitute.sh)**
333
+ - The watchdog discovers repos when it runs, but only repos that already exist on disk.
334
+ - Use `bash $AESOP_ROOT/tools/reconstitute.sh` to clone all repos from `aesop.config.json` automatically.
335
+ - Reconstitute supports `--dry-run` for preview and `--repos-file` for custom repo lists.
336
+
337
+ 2. **Recover transient state/ directory**
338
+ - Heartbeat files (`.watchdog-heartbeat`), logs (`FLEET-BACKUP.log`), and JSON status (`.watchdog-repos.json`) are git-ignored.
339
+ - They are recreated fresh when the watchdog runs, so you lose the history of what happened during the wipe.
340
+ - Future enhancement: persist logs to a cloud service or central logging system.
341
+
342
+ 3. **Recover aesop.config.json**
343
+ - The config file is git-ignored for security (contains local paths, possibly credentials).
344
+ - You must recreate it manually after a wipe.
345
+ - Workaround: store a template or commented version in a separate private repo, or use a configuration management tool (Ansible, Terraform).
346
+
347
+ 4. **Authenticate to private remotes**
348
+ - Git credentials (SSH keys, personal access tokens) are machine-local and not backed up.
349
+ - You must set up git authentication (SSH keys, git credential helper, or `~/.netrc`) on the new machine before cloning remotes.
350
+ - This is a feature, not a bug: credentials must never leave the machine.
351
+
352
+ 5. **Restore stashed work**
353
+ - If you stashed uncommitted work in a repo (e.g., via `git stash`), it is NOT in the watchdog backups.
354
+ - The watchdog only backs up uncommitted changes that are in the working directory or staging area at the time it runs.
355
+ - Mitigation: always commit or snapshot work before a wipe; use `git stash pop` before a wipe to restore stashed work.
356
+
357
+ 6. **Recover monitor state**
358
+ - The orchestration monitor (`monitor/collect-signals.mjs`) writes `BRIEF.md`, `SIGNALS.json`, and `.monitor-heartbeat` files, which are git-ignored.
359
+ - After a wipe, you start with a fresh slate; you lose the history of orchestration signals.
360
+ - Future enhancement: persist monitor state to a cloud service.
361
+
362
+ 7. **Recover custom dashboards or extensions**
363
+ - If you've customized `dash/watchdog-gui.sh`, `ui/serve.py`, or added extensions to `tools/`, ensure they are committed to the repo.
364
+ - Only committed code is restored; uncommitted customizations are lost.
365
+
366
+ ### Mitigations
367
+
368
+ - **For critical uncommitted work**: Ensure the watchdog is always running so work is snapshotted every 150 seconds.
369
+ - **For credentials and config**: Use a separate private remote for `aesop.config.json` templates and credentials, or use a CI/CD system to inject them.
370
+ - **For large repos**: Consider using git shallow clones (`--depth 1`) or sparse checkouts to speed up recovery for disaster scenarios.
371
+ - **For compliance and audit trails**: Periodically archive `state/FLEET-BACKUP.log` to a central logging system so you can audit what happened after a wipe.
372
+
373
+ ---
374
+
375
+ ## Summary
376
+
377
+ | Phase | Action | Time |
378
+ |-------|--------|------|
379
+ | Clone | `git clone <aesop>` + `git clone <brain>` | ~1 min |
380
+ | Config | Create `aesop.config.json` + `mkdir state/` | ~2 min |
381
+ | Repos | `bash tools/reconstitute.sh` (clone + fetch) | ~2–5 min |
382
+ | Verify | `bash daemons/run-watchdog.sh --once` | ~1 min |
383
+ | Recover | `git cherry-pick` from `backup/wip-*` branches | ~1–2 min |
384
+ | Restart | `bash daemons/run-watchdog.sh &` | immediate |
385
+ | **Total** | | **~7–12 min** |
386
+
387
+ The watchdog, combined with continuous git discipline, ensures that **compute is disposable but work is durable**. A machine wipe is annoying but not catastrophic.
388
+
389
+ ---
390
+
391
+ ## References
392
+
393
+ - `README.md` — installation and quick-start guide
394
+ - `CARDINAL-RULES.md` — foundational principles (rule #5: "durable state")
395
+ - `daemons/run-watchdog.sh` — watchdog daemon implementation
396
+ - `daemons/backup-fleet.sh` — backup and push logic
397
+ - `.gitignore` — what is and isn't persisted across wipes
@@ -0,0 +1,97 @@
1
+ # Scripts Policy: Local-only, shared library
2
+
3
+ This policy governs how auxiliary scripts and automation tools are written, organized, and maintained in Aesop-driven orchestration systems.
4
+
5
+ ## Rule 1: Never run scripts in the cloud
6
+
7
+ Python, shell, and other ad-hoc scripts execute **LOCALLY on the orchestrator machine only** — never inside:
8
+ - Cloud sandboxes or serverless functions
9
+ - Remote/scheduled cloud agents
10
+ - Remote workflow environments
11
+ - Containerized runners without local bind-mounts
12
+
13
+ **Why?** Local scripts often rely on local state (configuration files, home directory, machine-specific paths, local credentials). Pushing them to cloud breaks those assumptions and risks secret leaks. Local-only keeps boundaries clear and reproducible.
14
+
15
+ ## Rule 2: One common scripts library
16
+
17
+ Before writing any new script, **check the library first**.
18
+
19
+ **Workflow**:
20
+ 1. Look in the shared library (e.g., `aesop/tools/` for core tools, or a dedicated `~/scripts` folder for utility scripts)
21
+ 2. If the script exists, edit or extend the existing one
22
+ 3. If it doesn't exist and it's genuinely reusable (useful across tasks/projects/teams), add it to the library
23
+ 4. If it's task-local and unlikely to be reused, keep it in a temporary scratchpad
24
+
25
+ **Library conventions**:
26
+ - Snake_case filenames (e.g., `secret_scan.py`, `rotate_logs.py`)
27
+ - Module docstring at the top explaining purpose, usage, and parameters
28
+ - One-line entry in the library's `CLAUDE.md` index
29
+ - Python: include a `if __name__ == "__main__":` section with example usage
30
+
31
+ **Example entry**:
32
+ ```markdown
33
+ - `secret_scan.py` — scan staged files for secrets; blocks push if found. Usage: `python secret_scan.py --staged --repo <path>`
34
+ ```
35
+
36
+ ## Rule 3: Task-local vs. reusable
37
+
38
+ **Task-local scripts** not worth keeping are deleted at task end. Examples:
39
+ - One-off data transforms for a single feature or bugfix
40
+ - Temporary test harnesses
41
+ - Ad-hoc debugging helpers for a specific issue
42
+
43
+ **Reusable scripts** added to the library. Examples:
44
+ - Secret scanning (multi-project, multi-task)
45
+ - Build validation and health checks
46
+ - Linting and format automation
47
+ - Data migration templates
48
+ - Log rotation and archival
49
+
50
+ **Decision heuristic**: If you'd use it again in another project or another day on this project, it belongs in the library. If it's solving a one-time problem, delete it.
51
+
52
+ ## Rule 4: Library growth & discovery
53
+
54
+ The library evolves as new patterns emerge. On every orchestration boot or refresh cycle, the orchestrator can scan the library's `CLAUDE.md` to discover available tools.
55
+
56
+ **Keep the index current**: Every new reusable script gets a one-line entry so it's discoverable and documented. Entries stay alphabetical and include usage examples.
57
+
58
+ ## Rule 5: Environment & security
59
+
60
+ Scripts must be idempotent and deterministic.
61
+
62
+ **DO**:
63
+ - Detect and skip if already run (idempotent)
64
+ - Use local paths and respect working directory
65
+ - Log actions for auditability
66
+ - Handle errors explicitly (exit 1 on failure)
67
+
68
+ **DON'T**:
69
+ - Hardcode machine-specific paths (use `$HOME`, relative paths, or environment variables)
70
+ - Embed credentials (read from environment variables or secure config files instead)
71
+ - Leave large temporary files in `/tmp` or scratchpad (clean up on exit)
72
+ - Run cloud-bound commands that phone home
73
+
74
+ ## Rule 6: Version control & archival
75
+
76
+ Scripts in the library are **checked into git** so they're versioned and auditable. Task-local scripts can be git-ignored or committed temporarily (depending on repo policy).
77
+
78
+ **Library scripts**:
79
+ - Committed to the repo
80
+ - Updates are reviewed like any other code
81
+ - On removal/deprecation, archive the old version (add date suffix, keep for 3 months for reference)
82
+
83
+ ## Implementation checklist
84
+
85
+ When adding a new script to the library:
86
+ - [ ] Snake_case filename
87
+ - [ ] Module docstring explaining purpose and usage
88
+ - [ ] Entry in CLAUDE.md with one-line description and usage example
89
+ - [ ] Idempotent (safe to run multiple times)
90
+ - [ ] Handles errors explicitly (exit 1 on failure)
91
+ - [ ] No hardcoded personal paths or credentials
92
+ - [ ] Runs locally only (no cloud / scheduled execution)
93
+ - [ ] Git-committed and documented
94
+
95
+ ---
96
+
97
+ **Why this policy matters**: A shared, versioned scripts library reduces duplication, improves discoverability, and ensures automation is auditable and reproducible across team members and machines. Local-only execution keeps secrets safe and performance predictable. Together, they form the **automation core** that enables reliable, maintainable orchestration at scale.
@@ -0,0 +1,3 @@
1
+ # Archived Spike Investigations
2
+
3
+ Spike investigations that were cancelled or superseded; kept for reference and historical context.
@@ -0,0 +1,125 @@
1
+ # ACTIVATION runbook — force-model-policy.merged.mjs
2
+
3
+ Swap the staged merged hook in for the live model-policy hook. **Do not run
4
+ this casually** — the live hook governs every subagent dispatch in every
5
+ session. Perform the swap between waves, not mid-fleet.
6
+
7
+ Paths used below:
8
+
9
+ - LIVE hook: `C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs`
10
+ - STAGED file: `<aesop>\docs\spikes\tiered-cognition\force-model-policy.merged.mjs`
11
+ - Shim agent def: `<aesop>\docs\spikes\tiered-cognition\aesop-cognition.example.md`
12
+
13
+ ## Phase A activation (recommended first step)
14
+
15
+ Default behavior after the swap: model policy identical to today, plus
16
+ opus/fable-frontmatter dispatches rewritten to the message-only
17
+ `aesop-cognition` shim. Sonnet specialists untouched (no prompt loss —
18
+ FINDINGS.md condition 3 deferred). Layer 2 stays dormant.
19
+
20
+ 1. **Install the shim agent definition** (the merged hook rewrites cognition
21
+ dispatches to `subagent_type: aesop-cognition`; without the definition
22
+ those dispatches would fail):
23
+
24
+ ```powershell
25
+ Copy-Item <aesop>\docs\spikes\tiered-cognition\aesop-cognition.example.md `
26
+ C:\Users\matt8\.claude\agents\aesop-cognition.md
27
+ ```
28
+
29
+ Then edit the copied file's `description:` to remove the "NOT INSTALLED"
30
+ sentence. Keep `tools: Agent, SendMessage, TaskStop, Monitor` and do NOT
31
+ add a `model:` line (the hook passes the effective model explicitly).
32
+
33
+ 2. **Back up the live hook** (timestamped, same directory):
34
+
35
+ ```powershell
36
+ Copy-Item C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs `
37
+ C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs.bak-$(Get-Date -Format yyyyMMdd-HHmmss)
38
+ ```
39
+
40
+ 3. **Verify the staged file before copying** (must print `SELF-TEST: ALL PASS`,
41
+ exit 0):
42
+
43
+ ```powershell
44
+ node --check <aesop>\docs\spikes\tiered-cognition\force-model-policy.merged.mjs
45
+ node <aesop>\docs\spikes\tiered-cognition\force-model-policy.merged.mjs --self-test
46
+ ```
47
+
48
+ 4. **Copy over the live hook, keeping the live FILENAME** so settings.json
49
+ needs no edit:
50
+
51
+ ```powershell
52
+ Copy-Item <aesop>\docs\spikes\tiered-cognition\force-model-policy.merged.mjs `
53
+ C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs -Force
54
+ ```
55
+
56
+ 5. **Verify the settings matcher is unchanged and correct.** In
57
+ `C:\Users\matt8\.claude\settings.json` the `hooks.PreToolUse` entry with
58
+ matcher `Agent|Task` must point at
59
+ `~/.claude/hooks/force-haiku-subagents.mjs` (node command). Do NOT add any
60
+ other hook on that matcher — this file must remain the ONLY `updatedInput`
61
+ owner for `Agent|Task`; wiring a second rewriting hook there reintroduces
62
+ the exact collision this merge exists to fix.
63
+
64
+ 6. **Re-run the self-test on the installed copy** (proves the copy is intact):
65
+
66
+ ```powershell
67
+ node C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs --self-test
68
+ ```
69
+
70
+ 7. **Restart.** Claude Code snapshots hook config at session start — running
71
+ sessions keep the old hook until restarted. Restart the orchestrator
72
+ session and any long-lived fleet sessions/daemons that dispatch subagents.
73
+
74
+ 8. **Smoke-check in a fresh session:** dispatch a generic Haiku agent (expect
75
+ pass/route-to-haiku, no shim), a `bash-pro` (expect claude-sonnet-5, no
76
+ shim), and — if any opus/fable-frontmatter agent def is installed — one of
77
+ those (expect the `⛓ … tools stripped via 'aesop-cognition' shim` system
78
+ message). Confirm escape uses append to
79
+ `state/MODEL-POLICY-ESCAPES.log` / `state/TIER-POLICY-ESCAPES.log`.
80
+
81
+ ## Phase B (later, deliberate)
82
+
83
+ Set `TIER_STRIP_SCOPE=all` in the environment Claude Code launches from to
84
+ extend the shim to sonnet specialists — ONLY after per-specialist cognition
85
+ variants exist (FINDINGS.md condition 3), otherwise specialist system prompts
86
+ are lost to the generic shim. `TIER_STRIP_SCOPE=off` reduces the hook to pure
87
+ live-hook model-policy behavior (useful as a soft rollback).
88
+
89
+ ## Phase C — arming Layer 2 (call-time backstop; later, deliberate)
90
+
91
+ Dormant until BOTH of these are true:
92
+
93
+ 1. `TIER_ENFORCE=1` in the environment.
94
+ 2. settings.json gains a second `PreToolUse` entry running this same hook file
95
+ with a matcher covering the denied tools, e.g.
96
+ `Read|Write|Edit|MultiEdit|NotebookEdit|Bash|PowerShell|Glob|Grep|WebFetch|WebSearch|Skill|Artifact`.
97
+ (That entry never emits `updatedInput` — deny/allow only — so the
98
+ single-owner rule is preserved.)
99
+
100
+ Before arming: validate transcript sniffing on real sidechain transcripts and
101
+ decide the main-thread carve-out (FINDINGS.md condition 2 / risk 4).
102
+
103
+ ## Rollback
104
+
105
+ 1. Restore the newest backup:
106
+
107
+ ```powershell
108
+ Copy-Item C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs.bak-<TS> `
109
+ C:\Users\matt8\.claude\hooks\force-haiku-subagents.mjs -Force
110
+ ```
111
+
112
+ 2. Optionally remove `C:\Users\matt8\.claude\agents\aesop-cognition.md`
113
+ (harmless to leave installed; nothing routes to it without the merged hook).
114
+ 3. Unset `TIER_ENFORCE` / `TIER_STRIP_SCOPE` if set; remove any Layer-2
115
+ matcher added in Phase C.
116
+ 4. Restart running sessions (same snapshot rule as step 7 above).
117
+
118
+ ## Env knobs (merged hook)
119
+
120
+ | Var | Default | Effect |
121
+ |---|---|---|
122
+ | `FORCE_ALL_HAIKU=1` | off | Every dispatch → haiku (bash-pro excepted) — unchanged from live hook |
123
+ | `TIER_STRIP_SCOPE` | `opus-fable` | `opus-fable` (Phase A) / `all` (Phase B) / `off` (model policy only) |
124
+ | `TIER_ENFORCE=1` | off | Arms the Layer-2 call-time backstop (needs the Phase C matcher too) |
125
+ | `AESOP_ROOT` | `~/aesop` | Root for `state/*-ESCAPES.log` audit logs |