@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
@@ -1,116 +1,103 @@
1
- # Aesop Orchestration Monitor — Charter
1
+ # Orchestration Refinement Monitor — Charter
2
2
 
3
- A standing background monitor (Haiku subagent) that watches how the multi-agent system operates and acts on points of refinement. It improves the *machinery*, never the *mission*.
3
+ A standing background monitor (Haiku) that watches how the multi-agent system operates and
4
+ acts on points of refinement. It improves the *machinery*, never the *mission*.
4
5
 
5
6
  ## FIXED GOAL (never changes)
7
+ > Ship and maintain your projects correctly, cheaply, and autonomously under the cardinal rules
8
+ > (`~/.claude/CLAUDE.md`). The monitor's job is to make that machine run better — it must NOT
9
+ > redirect, re-scope, or invent new project goals. If it ever thinks the goal should change, it
10
+ > writes a note in `PROPOSALS.md` and stops there.
11
+
12
+ ## What it watches (via `collect-signals.mjs`, refreshed each cycle)
13
+ 1. **Junk-script sprawl** — one-off Python/JS scripts Claude Code writes to temp/scratch/cloud and
14
+ never reuses. Repeated throwaway `.py` to remote agents is a known cost/clutter sink.
15
+ 2. **Memory gaps** — projects/decisions/gotchas with no durable memory file; stale or duplicate memories.
16
+ 3. **Rule friction** — cardinal-rule violations in recent activity (non-Haiku subagents, main-thread
17
+ big reads, unpushed green work) and rules that are ambiguous, contradicted, or repeatedly ignored.
18
+ 4. **Orchestration health** — hung/stale agents, drift, repeated failures, git state across repos.
6
19
 
7
- > Maintain your projects correctly, cheaply, and autonomously under your cardinal rules.
8
- > The monitor's job is to make that machine run better — it must NOT redirect, re-scope,
9
- > or invent new project goals. If it ever thinks the goal should change, it writes a note
10
- > in `PROPOSALS.md` and stops there.
20
+ ## Action tiers
21
+ - **AUTO (apply immediately, then log to `ACTIONS.log`):**
22
+ - Persist/refresh project memory files (one fact each) + update `MEMORY.md` index.
23
+ - Quarantine confirmed-dead one-off scripts: move junk temp `.py`/`.mjs` (older than 24h, not
24
+ referenced by any repo, not the active session's scratchpad) into `orchestration-monitor/quarantine/`
25
+ with a manifest — never delete outright, never touch a live session scratchpad or repo `src/`.
26
+ - Clarifying, non-behavioral edits to a memory/log the monitor owns.
27
+ - **PROPOSE (write to `PROPOSALS.md`, do NOT apply — needs user OK):**
28
+ - Any change to `~/.claude/CLAUDE.md`, `~/.claude/skills/**`, or a project `CLAUDE.md`.
29
+ - Anything that alters agent behavior, model choice, push targets, or goal scope.
30
+ - Deleting anything outside the monitor's own quarantine.
11
31
 
12
- ## Standing checks (deterministic signal collection)
32
+ ## Hard guardrails (inviolable)
33
+ - Preserve the FIXED GOAL. Improve rules; never rewrite intent.
34
+ - Subagents are ALWAYS Haiku (this monitor included). Opus orchestrates on the main thread only.
35
+ - NEVER work around a classifier denial (cross-repo private-source push = exfil; reusing a
36
+ credential meant for another service = credential exploration). If seen, log + propose, don't act.
37
+ - NEVER print secret values. NEVER push to a remote or run a destructive command as an AUTO action.
38
+ - Idempotent + additive: safe to run repeatedly; prefer append/quarantine over overwrite/delete.
39
+ - Stay cheap: read the signal brief, not raw code/logs. One tight cycle, then sleep.
13
40
 
14
- Each cycle, `collect-signals.mjs` runs these checks and emits `BRIEF.md` + `SIGNALS.json`:
41
+ ## End-of-day wipe-survival sweep
15
42
 
16
- 1. **Heartbeat liveness check** read `.heartbeats/*` (epoch on line 1) + legacy beat files
17
- (`.monitor-heartbeat`, `.watchdog-heartbeat`); flag any older than threshold (watchdog 300s,
18
- monitor 3600s, others 1800s default) as stale loops; append warning to BRIEF.md.
43
+ The monitor may run `python ~/scripts/eod_sweep.py` in its final cycle of the day.
44
+ This verifies all known git repos are safe (no data loss risk):
45
+ - working trees clean OR dirty-file list logged
46
+ - current branch pushed to origin (ahead-count 0)
47
+ - untracked files not silently .gitignore'd
48
+ - SECURITY-ALERTS.log has no unreviewed HIGH/MED items
49
+ - memory INBOX consumed (0 pending items)
50
+ - no heartbeat file claims a dead loop (>1h stale)
19
51
 
20
- 2. **Git state across repos** for each repo in config: branch, last commit, uncommitted files,
21
- commits ahead of remote. Identifies unpushed work and dirty state.
52
+ Output: single verdict line (`EOD-SWEEP: SAFE` or `EOD-SWEEP: AT-RISK <n> findings`) + one finding per line;
53
+ appends to handoff log. Exit code 0 only if SAFE.
22
54
 
23
- 3. **Memory freshness** scan project memory files (excluding index/inbox); flag any >30 days old;
24
- append summary to BRIEF.md ("N memories stale — keeper should re-verify").
55
+ If findings detected, the monitor stages an alert: `EOD-SWEEP AT-RISK <n> findings` (each finding on bullet).
25
56
 
26
- 4. **Log rotation** check append-only logs against max-lines/max-kb thresholds (configurable,
27
- default 500 lines / 40 KB). If a log exceeds threshold, emit rotation signal (AUTO tier can
28
- invoke rotate_logs.py if available); append rotation summary to BRIEF.md.
57
+ ## Standing checks (trimmed for solo operation)
29
58
 
30
- 5. **Junk-script sprawl detection** — scan temp/scratch roots for throwaway `.py`/.mjs`/`.js` files
31
- older than 24 hours, not in a live session directory (avoid false-positives during active work).
32
- Count total, estimate quarantinable, list oldest. AUTO tier quarantines confirmed junk into
33
- `monitor/quarantine/` with manifest.
59
+ **KEPT (durable value):**
34
60
 
35
- 6. **Stray scripts in repo roots** scan recent commits (7d) to detect one-off `.py`/`.mjs`/`.sql`
36
- scripts committed directly to repo root (not under proper src/scripts paths). Flag for cleanup.
61
+ 1. **Scripts outside `~/scripts`**flag `.py`/`.mjs`/`.sh` accumulating outside `~/scripts`
62
+ (scratchpads, temp, repo roots). Quarantine per existing tiers; when one looks genuinely reusable,
63
+ suggest promotion to `~/scripts` (indexed in `~/scripts/CLAUDE.md`).
37
64
 
38
- 7. **Security alert review loop** — tail SECURITY-ALERTS.log for new HIGH/MED entries (skip suppressed);
39
- each new alert noted in BRIEF.md. Monitor agent does semantic review (REAL vs FP) each cycle.
65
+ 2. **Remote Python execution = HIGH-tier finding** — any scheduled/cloud agent or workflow that would
66
+ execute Python remotely violates Rule 5 (local-only execution). Flag immediately; never create one.
40
67
 
41
- 8. **Respawn watch (Rule 6 retry cap)** parse agent spawn records; normalize descriptions to
42
- prompt-signatures (first ~40 chars, lowercased); count occurrences in recent window (last 50 rows).
43
- Flag any signature appearing >3 times as probable hung-agent loop → rule 6 cap breached.
44
- Limitation: heuristic may have false positives for intentional similar-task fan-outs.
68
+ 3. **Memory freshness** — scan `~/.claude/projects/*/memory/*.md` (excluding INBOX.md, MEMORY.md); emit `staleMemories` signal in SIGNALS.json listing any file >30d old; append to BRIEF.md: "N memories >30d — keeper should re-verify: <names>".
45
69
 
46
- 9. **Cost cadence tracking** — every 3rd cycle, harvest agent spawn ledger and append cost tick
47
- to COST-LOG.md (cycle count, timestamp, model distribution). Flags non-haiku specializations.
70
+ 4. **SECURITY ALERT REVIEW LOOP** — on each /power cycle, arm a persistent Monitor tailing
71
+ SECURITY-ALERTS.log filtered to new 'HIGH'/'MED' lines (exclude SUPPRESSED-FP). Each new alert spawns a read-only fleet-auditor agent to classify REAL vs FALSE-POSITIVE (mask any secret: first 4 chars + ***), verdict appended to SECURITY-ALERTS.log as a REVIEW note and, if REAL, surfaced to the user immediately. Rationale: the append-only alert log is only useful if alerts are triaged; unreviewed HIGHs rot into ignored noise.
48
72
 
49
- 10. **Unreviewed agent prompts** — run fleet-prompt-extractor.py (if available) to collect NEW
50
- spawns since last review; emit count in SIGNALS.json + note in BRIEF.md.
73
+ 5. **Fleet ledger harvest** — each cycle, run `python ~/scripts/fleet_ledger.py harvest` to scan session task outputs (JSONL format) and append missing agent outcomes to OUTCOMES-LEDGER.md. Tracks last-harvest state in .fleet-ledger-harvest.json sidecar. Deterministic, local-only, append-only; feeds cost analysis and agent respawn detection. Then invoke `python ~/scripts/fleet_ledger.py rotate` to archive old rows if ledger exceeds 200 lines.
51
74
 
52
- ## Action tiers
75
+ 6. **Log rotation** — after ledger operations, invoke `python ~/scripts/rotate_logs.py <file> --max-lines 500 --max-kb 40` over: hook-activity.log, SECURITY-ALERTS.log, FLEET-BACKUP.log (BUILDLOG.md at 1000-line threshold — historical record). Emit `logRotations` list in SIGNALS.json and summary line in BRIEF.md.
53
76
 
54
- - **AUTO (apply immediately, then log to `ACTIONS.log`):**
55
- - Heartbeat freshness checks (read-only).
56
- - Log rotation (invoke rotate_logs.py if available; fail-open if not).
57
- - Persist heartbeat write (`.monitor-heartbeat` update after cycle).
58
- - Quarantine confirmed-junk scripts: move old temp `.py`/`.mjs` (not live session) into
59
- `monitor/quarantine/` with manifest — never delete outright.
60
-
61
- - **PROPOSE (write to `PROPOSALS.md`, do NOT apply — needs user approval):**
62
- - Changes to cardinal rules or agent configuration.
63
- - Alterations to agent behavior, model choice, or push targets.
64
- - Deletions of anything outside monitor's own quarantine.
65
- - Any change to orchestration policy.
77
+ 7. **Heartbeat liveness check** — read state/.heartbeats/* (epoch on line 1) + legacy beat files (.monitor-heartbeat, .watchdog-heartbeat, etc.); flag any older than threshold (watchdog 300s, monitor 3600s, others 1800s default) as `staleLoops` signal in SIGNALS.json; append warning to BRIEF.md. Continuous watchdog complement to /power selftest.
66
78
 
67
- ## Hard guardrails (inviolable)
79
+ 8. **Respawn watch (Rule 6 machine-enforcement)** — parse OUTCOMES-LEDGER.md for agent descriptions; normalize each to prompt-signature (first ~40 chars, lowercased, trimmed); count occurrences per signature within recent window (last 50 rows OR since marker in .signal-state.json). Any signature appearing >3 times = probable hung-agent respawn loop → add to `respawnWatch` in SIGNALS.json + warning line in BRIEF.md. *Limitation:* heuristic may have false positives for intentional similar-task fan-outs (e.g., per-file processing with distinct file names in description); BRIEF includes note to manually review flagged signatures. Pure node parsing (no LLM).
68
80
 
69
- - Preserve the FIXED GOAL. Improve rules; never rewrite intent.
70
- - **Subagents are ALWAYS Haiku** (cost optimization). Orchestrator on main thread only.
71
- - NEVER push destructively or to restricted remotes as an AUTO action.
72
- - NEVER edit cardinal-rules files (CLAUDE.md, skills/, agent configs) — only PROPOSE changes.
73
- - Idempotent + additive: safe to run repeatedly; prefer append over overwrite.
74
- - Stay cheap: read the signal brief, not raw logs. One tight cycle, then sleep.
75
- - Robust to missing files: treat missing dirs/logs as empty, never crash.
76
-
77
- ## Outputs
78
-
79
- - `BRIEF.md` — human-readable status snapshot (overwrite each cycle).
80
- - `SIGNALS.json` — machine-readable metrics and findings (overwrite each cycle).
81
- - `ACTIONS.log` — append-only record of AUTO actions taken (timestamped).
82
- - `PROPOSALS.md` — staged changes awaiting user approval.
83
- - `quarantine/` — parked junk scripts + `MANIFEST.tsv` (append-only).
84
- - `.monitor-heartbeat` — epoch timestamp (line 1) for liveness.
85
- - `.signal-state.json` — sidecar state (cycle count, seen prompts, etc.).
86
-
87
- ## Operating it
81
+ 9. **Semantic prompt review** — each cycle, collect-signals.mjs runs `fleet_prompt_extractor.py` to identify NEW unreviewed agent-spawn prompts (tracks seen-hash state in `.fleet-prompts-seen.json`); count is emitted as `unreviewedPrompts` in SIGNALS.json + noted in BRIEF.md. If count > 0, the monitor agent does semantic review (read each prompt, classify: OK / DRIFT / SUSPICIOUS) and runs `drift_escalator.py` to write verdicts to DRIFT-REVIEW.log + escalate any DRIFT/SUSPICIOUS findings to SECURITY-ALERTS.log + DRIFT-ESCALATIONS.md. This closes the gap: regex fleet-scan is NOT semantic review; LLM judgment gates malformed/off-goal/injection prompts. Completes before any flagged prompt's agent runs.
88
82
 
89
- 1. **Deploy the monitor** as a continuous background task (or invoke manually each cycle).
90
- 2. **Customize via config**: populate `aesop.config.json` with your repo paths, thresholds.
91
- 3. **Review PROPOSALS.md** periodically; approve changes or reject them.
92
- 4. **Check ACTIONS.log** to see what was automated.
93
- 5. **Monitor BRIEF.md** for drift signals; respond to findings.
83
+ 10. **Mirror refresh cadence (throttled)** each monitor cycle mirrors scripts and docs to your fleet-ops directory and regenerates asset indexes. If either produces diffs: check `.last-mirror-pr-time` in state/. Only open a PR if >1 hour has passed since last PR; otherwise log silently as no-op to ACTIONS.log with timestamp. Ensures mirrors stay in sync and asset lists reflect tier-1 changes, but prevents PR spam. Pure Python automation; runs in monitor context only.
94
84
 
95
- ## Customization
85
+ 11. **UI inbox drain (session-independent work queue)** — each cycle, run `python ~/scripts/inbox_drain.py pending` to surface queued submissions that arrived while no session was running. If items exist, write a one-line `QUEUED WORK PENDING` flag to BRIEF.md so an active monitor also surfaces it. This complements /power's inbox drain (step 5); the monitor ensures work doesn't rot in the queue even between sessions.
96
86
 
97
- Edit `collect-signals.mjs` to:
98
- - Add/remove checks based on your project needs.
99
- - Configure paths via environment variables (AESOP_ROOT, BRAIN_ROOT, SCRIPTS_ROOT, TEMP_ROOT)
100
- or load from aesop.config.json.
101
- - Set heartbeat thresholds appropriate to your workflow.
102
- - Integrate custom signal collectors (e.g., compliance checks, custom linters).
87
+ **CUT or DEMOTED (no durable value for solo operator):**
103
88
 
104
- See comments in `collect-signals.mjs` for extension points. **Keep it CRLF-safe** (no line
105
- continuations; maintain Windows+POSIX compatibility).
89
+ - **Suppression audit** (CUT) A solo operator watching the dashboard notices suppression count manually; meta-audits add ceremony without signal.
90
+ - **Cost cadence** — (DEMOTED; blocked) Ledger parsing incomplete; once cost meter is proven, restore. For now, flag as blocked in PROPOSALS.md if touched.
106
91
 
107
- ## Single-instance guard
92
+ **Rationale & changes:**
108
93
 
109
- Before running, check `.monitor-heartbeat` if <300s old, skip cycle (another monitor is running).
110
- After cycle completes, update `.monitor-heartbeat` with current epoch.
94
+ The original 12-check charter was ceremony-heavy for a one-person system. Cuts preserve the critical signals (liveness, security triage, hung loops, prompt safety, cost data acquisition) and demote/cut only checks whose value is marginal or already visible to a solo operator. Check #10 was throttled instead of cut because the mirror sync is critical, but PR-per-cycle wastes bandwidth — now it only PRs when changes exist AND at least 1 hour has passed.
111
95
 
112
- ## Single-writer discipline
96
+ Total standing checks: **11** (reflecting genericization; some checks are environment-specific).
113
97
 
114
- - Only the monitor edits `BRIEF.md`, `SIGNALS.json`, `ACTIONS.log`, `.monitor-heartbeat`, `.signal-state.json`.
115
- - External processes (human, other agents) write to `PROPOSALS.md` (append or structured inbox).
116
- - Quarantine manifest is append-only; never edit entries, only add new ones.
98
+ ## Outputs (all under orchestration-monitor/)
99
+ - `BRIEF.md` / `SIGNALS.json` the deterministic snapshot (written by the collector).
100
+ - `ACTIONS.log` append-only record of AUTO actions taken (timestamped).
101
+ - `PROPOSALS.md` — staged rule/behavior changes awaiting user approval.
102
+ - `quarantine/` — parked junk scripts + `MANIFEST.tsv`.
103
+ - `.monitor-heartbeat` — liveness for any dashboard.
@@ -0,0 +1,40 @@
1
+ # monitor/ — Orchestration monitor
2
+
3
+ **Purpose**: Continuous background signal collector and refinement proposer — watches fleet machinery health deterministically (Node.js, no LLM), emits cycle snapshots, and proposes rule changes via append-only PROPOSALS.md; GOAL IS FIXED (improve machinery, never mission).
4
+
5
+ ## Files
6
+
7
+ - **CHARTER.md** — Governance document; defines 10 signal checks (4 of them extended/opt-in), action tiers (AUTO/PROPOSE), outputs, single-instance guard, single-writer discipline. Read-only; behavior changes only via PROPOSALS/behavioral-PR flow.
8
+ - **collect-signals.mjs** — Deterministic signal collector (Node.js built-ins only); emits BRIEF.md + SIGNALS.json each cycle; reads config from env or aesop.config.json.
9
+ - **BRIEF.md** — Human-readable cycle snapshot (heartbeats, git state, memory freshness, log rotation, junk sprawl, stray scripts, security alerts, respawn watch, cost cadence, unreviewed prompts); overwritten each cycle; runtime.
10
+ - **SIGNALS.json** — Machine-readable metrics (same signal keys as BRIEF); JSON; overwritten each cycle; runtime.
11
+ - **PROPOSALS.md** — Structured inbox for user approval (idempotent per signal key, append-only); never edited by monitor after emission; tracks respawn-watch-breach, stray-repo-scripts, security-alerts-high-med, stale-memory-files; gitignored.
12
+ - **ACTIONS.log** — Append-only log of AUTO tier actions taken (heartbeat updates, log rotation invokes, junk quarantine); runtime; gitignored.
13
+ - **.monitor-heartbeat** — Epoch timestamp (line 1) for single-instance liveness check (<300s = skip cycle); runtime; gitignored.
14
+ - **.signal-state.json** — Sidecar state (cycleCount, etc.); runtime; gitignored.
15
+
16
+ ## Contracts
17
+
18
+ **Signal keys collected**: heartbeats, git, memory, logs, junk, strayRepo, alerts, respawnWatch, costTick, unreviewedPrompts. Outputs: BRIEF.md (human), SIGNALS.json (machine); both runtime/gitignored. PROPOSALS.md (tracked, append-only); ACTIONS.log (runtime/gitignored).
19
+
20
+ **Extended signals (opt-in, default OFF)**: checks 5 (junk), 6 (strayRepo), 8 (respawnWatch), and 10 (unreviewedPrompts) are extended — disabled by default.
21
+ - Config key: `monitor.extended_signals` (boolean, default `false`) in aesop.config.json.
22
+ - Env override: `AESOP_EXTENDED_SIGNALS` (`'true'` or `'1'` to enable).
23
+ - Precedence: env var > config file > default (false).
24
+ - When disabled, extended checks emit `{"skipped": true}` in SIGNALS.json and BRIEF.md notes them as "extended (off)"; their dirs are not walked. PROPOSE-tier signals for extended checks (respawn-watch-breach, stray-repo-scripts) are only emitted when extended_signals is ON.
25
+
26
+ **AUTO tier actions** (apply immediately, log to ACTIONS.log): heartbeat checks (read-only); log rotation (invoke rotate_logs.py if available, fail-open); heartbeat write (.monitor-heartbeat update); junk script quarantine (move old temp .py/.mjs to monitor/quarantine/ + manifest — only when extended_signals is ON).
27
+
28
+ **PROPOSE tier actions** (write to PROPOSALS.md, await user approval): rule changes, agent config changes, deletions outside monitor/quarantine/, orchestration policy changes.
29
+
30
+ **Idempotency rule**: Proposal emission keyed on signal key (e.g., 'respawn-watch-breach'); only emitted if not already present in PROPOSALS.md (check: `**Signal:** <key>` exists). Idempotent + append-only; safe to run repeatedly.
31
+
32
+ ## Invariants & Gotchas
33
+
34
+ - CHARTER.md is authority; monitor logic is faithful to it; never edit CHARTER.md or collect-signals.mjs directly — propose via PROPOSALS.md.
35
+ - Goal is FIXED (improve machinery, never mission); if monitor thinks goal should change, it writes note to PROPOSALS.md and stops.
36
+ - Single-instance guard via .monitor-heartbeat; if <300s old, skip cycle.
37
+ - Single-writer discipline: only monitor writes BRIEF.md, SIGNALS.json, ACTIONS.log, .monitor-heartbeat, .signal-state.json.
38
+ - Config from env (AESOP_ROOT, BRAIN_ROOT, SCRIPTS_ROOT, TEMP_ROOT, AESOP_EXTENDED_SIGNALS) or aesop.config.json; falls back to safe defaults.
39
+ - Robust to missing files; treats missing dirs/logs as empty, never crashes.
40
+ - Node.js only (no Python, no LLM, no cloud); deterministic + cheap.
@@ -0,0 +1,54 @@
1
+ {
2
+ "timestamp": "2026-07-12T19:11:11.520Z",
3
+ "cycleCount": 10,
4
+ "heartbeats": {
5
+ "staleCount": 0,
6
+ "details": []
7
+ },
8
+ "git": [],
9
+ "memory": {
10
+ "count": 26,
11
+ "staleMemories": [],
12
+ "staleCount": 0
13
+ },
14
+ "logs": [
15
+ {
16
+ "name": "FLEET-BACKUP.log",
17
+ "exists": true,
18
+ "sizeKb": "1.8",
19
+ "lineCount": 37,
20
+ "needsRotation": false
21
+ },
22
+ {
23
+ "name": "SECURITY-ALERTS.log",
24
+ "exists": false,
25
+ "sizeKb": 0,
26
+ "lineCount": 0,
27
+ "needsRotation": null
28
+ },
29
+ {
30
+ "name": "ACTIONS.log",
31
+ "exists": true,
32
+ "sizeKb": "0.2",
33
+ "lineCount": 1,
34
+ "needsRotation": false
35
+ }
36
+ ],
37
+ "junk": {
38
+ "skipped": true
39
+ },
40
+ "strayRepo": {
41
+ "skipped": true
42
+ },
43
+ "alerts": {
44
+ "count": 0,
45
+ "highMedCount": 0
46
+ },
47
+ "respawnWatch": {
48
+ "skipped": true
49
+ },
50
+ "costTick": null,
51
+ "unreviewedPrompts": {
52
+ "skipped": true
53
+ }
54
+ }