@matt82198/aesop 0.1.0-beta.5 → 0.1.0
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.
- package/CHANGELOG.md +158 -5
- package/LICENSE +66 -21
- package/README.md +97 -33
- package/aesop.config.example.json +6 -0
- package/bin/CLAUDE.md +12 -3
- package/bin/cli.js +211 -40
- package/daemons/CLAUDE.md +1 -1
- package/daemons/backup-fleet.sh +209 -51
- package/daemons/run-watchdog.sh +208 -62
- package/dash/dash-extra.mjs +73 -4
- package/dash/watchdog-gui.sh +41 -35
- package/docs/ARCHITECTURE.md +296 -0
- package/docs/CONCEPTS.md +254 -0
- package/docs/CONFIGURE.md +256 -0
- package/docs/FIRST-WAVE.md +276 -0
- package/docs/INSTALL.md +224 -0
- package/docs/README.md +176 -27
- package/docs/autonomous-swe.md +149 -0
- package/docs/reproduce.md +121 -0
- package/hooks/CLAUDE.md +28 -0
- package/hooks/install-waveguard.sh +68 -0
- package/hooks/pre-commit-waveguard.sh +26 -0
- package/hooks/pre-push-policy.sh +253 -15
- package/monitor/CLAUDE.md +3 -3
- package/monitor/collect-signals.mjs +133 -20
- package/package.json +15 -7
- package/scan/CLAUDE.md +30 -0
- package/skills/CLAUDE.md +1 -0
- package/state_store/ingest.py +18 -1
- package/state_store/projections.py +78 -4
- package/state_store/store.py +102 -7
- package/tools/CLAUDE.md +25 -18
- package/tools/alert_bridge.py +14 -10
- package/tools/bench_runner.py +438 -0
- package/tools/buildlog.py +4 -7
- package/tools/ci_merge_wait.py +215 -34
- package/tools/common.py +62 -0
- package/tools/cost_ceiling.py +191 -0
- package/tools/dash.js +102 -0
- package/tools/doctor.js +220 -0
- package/tools/fleet_ledger.py +189 -17
- package/tools/halt.py +172 -0
- package/tools/healthcheck.py +24 -21
- package/tools/heartbeat.py +4 -7
- package/tools/metrics_gate.py +8 -2
- package/tools/orchestrator_status.py +4 -9
- package/tools/reconcile.py +277 -0
- package/tools/rotate_logs.py +152 -62
- package/tools/scanner_selftest.py +28 -3
- package/tools/secret_scan.py +359 -90
- package/tools/self_stats.py +292 -4
- package/tools/status.js +187 -0
- package/tools/verify_agent_inspector.py +289 -0
- package/tools/verify_prboard.py +344 -0
- package/tools/watch.js +49 -0
- package/ui/CLAUDE.md +2 -0
- package/ui/agents.py +332 -33
- package/ui/api/tracker.py +15 -7
- package/ui/collectors.py +125 -32
- package/ui/config.py +22 -2
- package/ui/cost.py +98 -3
- package/ui/csrf.py +2 -1
- package/ui/handler.py +209 -21
- package/ui/sse.py +102 -16
- package/ui/wave_prs.py +230 -0
- package/ui/web/dist/assets/index-0qQYnvMC.js +9 -0
- package/ui/web/dist/assets/index-BdIlFieV.css +1 -0
- package/ui/web/dist/index.html +2 -2
- package/monitor/.signal-state.json +0 -3
- package/monitor/ACTIONS.log +0 -1
- package/monitor/BRIEF.md +0 -24
- package/monitor/SIGNALS.json +0 -54
- package/state_store/__pycache__/__init__.cpython-314.pyc +0 -0
- package/state_store/__pycache__/api.cpython-314.pyc +0 -0
- package/state_store/__pycache__/export.cpython-314.pyc +0 -0
- package/state_store/__pycache__/ingest.cpython-314.pyc +0 -0
- package/state_store/__pycache__/projections.cpython-314.pyc +0 -0
- package/state_store/__pycache__/store.cpython-314.pyc +0 -0
- package/tools/__pycache__/alert_bridge.cpython-314.pyc +0 -0
- package/tools/__pycache__/buildlog.cpython-314.pyc +0 -0
- package/tools/__pycache__/ci_merge_wait.cpython-314.pyc +0 -0
- package/tools/__pycache__/ensure_state.cpython-314.pyc +0 -0
- package/tools/__pycache__/eod_sweep.cpython-314.pyc +0 -0
- package/tools/__pycache__/fleet_ledger.cpython-314.pyc +0 -0
- package/tools/__pycache__/fleet_prompt_extractor.cpython-314.pyc +0 -0
- package/tools/__pycache__/healthcheck.cpython-314.pyc +0 -0
- package/tools/__pycache__/heartbeat.cpython-314.pyc +0 -0
- package/tools/__pycache__/inbox_drain.cpython-314.pyc +0 -0
- package/tools/__pycache__/launch_tui.cpython-314.pyc +0 -0
- package/tools/__pycache__/metrics_gate.cpython-314.pyc +0 -0
- package/tools/__pycache__/orchestrator_status.cpython-314.pyc +0 -0
- package/tools/__pycache__/power_selftest.cpython-314.pyc +0 -0
- package/tools/__pycache__/prepublish_scan.cpython-314.pyc +0 -0
- package/tools/__pycache__/rotate_logs.cpython-314.pyc +0 -0
- package/tools/__pycache__/scanner_selftest.cpython-314.pyc +0 -0
- package/tools/__pycache__/secret_scan.cpython-314.pyc +0 -0
- package/tools/__pycache__/self_stats.cpython-314.pyc +0 -0
- package/tools/__pycache__/session_usage_summary.cpython-314.pyc +0 -0
- package/tools/__pycache__/stall_check.cpython-314.pyc +0 -0
- package/tools/__pycache__/transcript_replay.cpython-314.pyc +0 -0
- package/tools/__pycache__/transcript_timeline.cpython-314.pyc +0 -0
- package/tools/__pycache__/verify_dash.cpython-314.pyc +0 -0
- package/tools/__pycache__/verify_submit_encoding.cpython-314.pyc +0 -0
- package/ui/__pycache__/agents.cpython-314.pyc +0 -0
- package/ui/__pycache__/collectors.cpython-314.pyc +0 -0
- package/ui/__pycache__/config.cpython-314.pyc +0 -0
- package/ui/__pycache__/cost.cpython-314.pyc +0 -0
- package/ui/__pycache__/csrf.cpython-314.pyc +0 -0
- package/ui/__pycache__/handler.cpython-314.pyc +0 -0
- package/ui/__pycache__/render.cpython-314.pyc +0 -0
- package/ui/__pycache__/serve.cpython-314.pyc +0 -0
- package/ui/__pycache__/sse.cpython-314.pyc +0 -0
- package/ui/api/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ui/api/__pycache__/submit.cpython-314.pyc +0 -0
- package/ui/api/__pycache__/tracker.cpython-314.pyc +0 -0
- package/ui/web/.gitattributes +0 -13
- package/ui/web/dist/assets/index-2LZDQirC.js +0 -9
- package/ui/web/dist/assets/index-D4M1qyOv.css +0 -1
- package/ui/web/index.html +0 -13
- package/ui/web/package-lock.json +0 -2225
- package/ui/web/package.json +0 -26
- package/ui/web/src/App.test.tsx +0 -74
- package/ui/web/src/App.tsx +0 -142
- package/ui/web/src/CONTRIBUTING-UI.md +0 -49
- package/ui/web/src/components/AgentRow.css +0 -187
- package/ui/web/src/components/AgentRow.test.tsx +0 -209
- package/ui/web/src/components/AgentRow.tsx +0 -207
- package/ui/web/src/components/AgentsPanel.css +0 -108
- package/ui/web/src/components/AgentsPanel.test.tsx +0 -41
- package/ui/web/src/components/AgentsPanel.tsx +0 -58
- package/ui/web/src/components/AlertsPanel.css +0 -88
- package/ui/web/src/components/AlertsPanel.test.tsx +0 -51
- package/ui/web/src/components/AlertsPanel.tsx +0 -67
- package/ui/web/src/components/BacklogPanel.test.tsx +0 -126
- package/ui/web/src/components/BacklogPanel.tsx +0 -122
- package/ui/web/src/components/CostChart.css +0 -110
- package/ui/web/src/components/CostChart.test.tsx +0 -144
- package/ui/web/src/components/CostChart.tsx +0 -152
- package/ui/web/src/components/CostTable.css +0 -93
- package/ui/web/src/components/CostTable.test.tsx +0 -165
- package/ui/web/src/components/CostTable.tsx +0 -94
- package/ui/web/src/components/EventsFeed.css +0 -68
- package/ui/web/src/components/EventsFeed.test.tsx +0 -36
- package/ui/web/src/components/EventsFeed.tsx +0 -31
- package/ui/web/src/components/HealthHeader.css +0 -137
- package/ui/web/src/components/HealthHeader.test.tsx +0 -278
- package/ui/web/src/components/HealthHeader.tsx +0 -281
- package/ui/web/src/components/InboxForm.css +0 -135
- package/ui/web/src/components/InboxForm.test.tsx +0 -208
- package/ui/web/src/components/InboxForm.tsx +0 -116
- package/ui/web/src/components/MessagesTail.module.css +0 -144
- package/ui/web/src/components/MessagesTail.test.tsx +0 -176
- package/ui/web/src/components/MessagesTail.tsx +0 -94
- package/ui/web/src/components/ReposPanel.css +0 -90
- package/ui/web/src/components/ReposPanel.test.tsx +0 -45
- package/ui/web/src/components/ReposPanel.tsx +0 -67
- package/ui/web/src/components/Scorecard.css +0 -106
- package/ui/web/src/components/Scorecard.test.tsx +0 -117
- package/ui/web/src/components/Scorecard.tsx +0 -85
- package/ui/web/src/components/Timeline.module.css +0 -151
- package/ui/web/src/components/Timeline.test.tsx +0 -215
- package/ui/web/src/components/Timeline.tsx +0 -99
- package/ui/web/src/components/TrackerBoard.test.tsx +0 -121
- package/ui/web/src/components/TrackerBoard.tsx +0 -107
- package/ui/web/src/components/TrackerCard.test.tsx +0 -180
- package/ui/web/src/components/TrackerCard.tsx +0 -160
- package/ui/web/src/components/TrackerForm.test.tsx +0 -189
- package/ui/web/src/components/TrackerForm.tsx +0 -144
- package/ui/web/src/lib/api.ts +0 -218
- package/ui/web/src/lib/format.test.ts +0 -89
- package/ui/web/src/lib/format.ts +0 -103
- package/ui/web/src/lib/sanitizeUrl.test.ts +0 -84
- package/ui/web/src/lib/sanitizeUrl.ts +0 -38
- package/ui/web/src/lib/types.ts +0 -230
- package/ui/web/src/lib/useHashRoute.test.ts +0 -60
- package/ui/web/src/lib/useHashRoute.ts +0 -23
- package/ui/web/src/lib/useSSE.ts +0 -175
- package/ui/web/src/main.tsx +0 -10
- package/ui/web/src/styles/global.css +0 -179
- package/ui/web/src/styles/theme.css +0 -184
- package/ui/web/src/styles/work.css +0 -572
- package/ui/web/src/test/fixtures.ts +0 -385
- package/ui/web/src/test/setup.ts +0 -49
- package/ui/web/src/views/Activity.module.css +0 -43
- package/ui/web/src/views/Activity.test.tsx +0 -89
- package/ui/web/src/views/Activity.tsx +0 -31
- package/ui/web/src/views/Cost.css +0 -87
- package/ui/web/src/views/Cost.test.tsx +0 -142
- package/ui/web/src/views/Cost.tsx +0 -54
- package/ui/web/src/views/Overview.css +0 -51
- package/ui/web/src/views/Overview.test.tsx +0 -76
- package/ui/web/src/views/Overview.tsx +0 -46
- package/ui/web/src/views/Work.test.tsx +0 -82
- package/ui/web/src/views/Work.tsx +0 -79
- package/ui/web/src/vite-env.d.ts +0 -10
- package/ui/web/tsconfig.json +0 -22
- package/ui/web/vite.config.ts +0 -25
- package/ui/web/vitest.config.ts +0 -12
package/docs/README.md
CHANGED
|
@@ -1,44 +1,193 @@
|
|
|
1
|
-
# Aesop Documentation
|
|
1
|
+
# Aesop Documentation
|
|
2
2
|
|
|
3
|
-
Aesop is a fable-fleet orchestration harness for Claude Code. It runs fast, cheap delivery waves: parallel Haiku agents,
|
|
3
|
+
Aesop is a fable-fleet orchestration harness for Claude Code. It runs fast, cheap delivery waves: parallel Haiku agents, durable state, observable machinery, security gates.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Adopter Journey (Start Here)
|
|
8
|
+
|
|
9
|
+
If you're new to Aesop, follow this 4-stage path:
|
|
10
|
+
|
|
11
|
+
### Stage 1: Install
|
|
12
|
+
**[INSTALL.md](INSTALL.md)** — Prerequisites, `npx` scaffold, what gets created
|
|
13
|
+
|
|
14
|
+
- System requirements (Claude Code CLI, Git, Bash, Node.js, Python)
|
|
15
|
+
- Quick-start: `npx @matt82198/aesop@beta my-fleet`
|
|
16
|
+
- Manual setup for development (git clone)
|
|
17
|
+
- Pre-push hook installation
|
|
18
|
+
|
|
19
|
+
### Stage 2: Configure
|
|
20
|
+
**[CONFIGURE.md](CONFIGURE.md)** — aesop.config.json, repos, ports, brain root
|
|
21
|
+
|
|
22
|
+
- Field reference (`aesopRoot`, `braindRoot`, `repos`, `dashboardPort`, `dashboardOrigin`)
|
|
23
|
+
- Example configurations (single repo, microservices, Windows paths)
|
|
24
|
+
- Security notes (git-ignore config, no secrets in config)
|
|
25
|
+
- Environment variables
|
|
6
26
|
|
|
7
|
-
|
|
27
|
+
### Stage 3: First Wave
|
|
28
|
+
**[FIRST-WAVE.md](FIRST-WAVE.md)** — Run `/power` then `/buildsystem` end-to-end
|
|
29
|
+
|
|
30
|
+
- What to expect from each phase (rank → dispatch → verify → close)
|
|
31
|
+
- Monitoring (dashboard, TUI, logs)
|
|
32
|
+
- When agents hang (watchdog protocol, retry cap)
|
|
33
|
+
- Common Q&A (wave duration, cost, cancellation, failure handling)
|
|
34
|
+
|
|
35
|
+
### Stage 4: Concepts
|
|
36
|
+
**[CONCEPTS.md](CONCEPTS.md)** — Dispatch model, cost, state, security, governance
|
|
37
|
+
|
|
38
|
+
- The wave cycle at a glance
|
|
39
|
+
- Dispatch model (Haiku-first subagents, cost model, patterns)
|
|
40
|
+
- State & checkpointing (STATE.md, BUILDLOG.md, durable recovery)
|
|
41
|
+
- Security gates (secret-scan, branch discipline)
|
|
42
|
+
- Governance (single-writer files, heartbeat protocol)
|
|
43
|
+
- Reliability core (inputs always produce outputs, pride bar)
|
|
44
|
+
- Links to all deep-dive reference docs
|
|
8
45
|
|
|
9
46
|
---
|
|
10
47
|
|
|
11
|
-
##
|
|
48
|
+
## System Architecture
|
|
12
49
|
|
|
13
|
-
|
|
50
|
+
**[ARCHITECTURE.md](ARCHITECTURE.md)** — Visual flow diagram + component overview
|
|
51
|
+
|
|
52
|
+
- Mermaid diagram: orchestrator → parallel fleet → merge train → checkpoint → audit → next backlog
|
|
53
|
+
- Component breakdown (watchdog, monitor, dashboard, durable state)
|
|
54
|
+
- Cost model and scaling characteristics
|
|
55
|
+
- Security model (pre-push hook + GitHub branch protection)
|
|
56
|
+
|
|
57
|
+
---
|
|
14
58
|
|
|
15
|
-
##
|
|
59
|
+
## Deep-Dive Reference Docs
|
|
16
60
|
|
|
17
|
-
|
|
18
|
-
- [RELIABILITY.md](RELIABILITY.md) — Reliability core: never wait, inputs always produce outputs, pride bar for completion
|
|
19
|
-
- [CHECKPOINTING.md](CHECKPOINTING.md) — Durable STATE.md/BUILDLOG.md lifecycle, recovery on resume, log rotation patterns
|
|
20
|
-
- [SCRIPTS-POLICY.md](SCRIPTS-POLICY.md) — Local-only execution, shared script library, task-local vs. reusable heuristics
|
|
21
|
-
- [DISPATCH-MODEL.md](DISPATCH-MODEL.md) — Fable/Haiku orchestration patterns and cost calculations
|
|
22
|
-
- [GOVERNANCE.md](GOVERNANCE.md) — Single-instance loops, single-writer files, heartbeat protocol, security gates
|
|
61
|
+
Once you've completed the adopter journey, use these for operational reference:
|
|
23
62
|
|
|
24
|
-
|
|
63
|
+
### Wave Cycle & Orchestration
|
|
64
|
+
- **[HOW-THE-LOOP-WORKS.md](HOW-THE-LOOP-WORKS.md)** — Concrete walkthrough of one complete `/buildsystem` wave cycle (rank → fan-out → verify → merge → close)
|
|
65
|
+
|
|
66
|
+
### Dispatch & Cost
|
|
67
|
+
- **[DISPATCH-MODEL.md](DISPATCH-MODEL.md)** — Haiku-first subagent dispatch, cost analysis, patterns (fan-out, sequential, hierarchical)
|
|
68
|
+
|
|
69
|
+
### State Management & Recovery
|
|
70
|
+
- **[CHECKPOINTING.md](CHECKPOINTING.md)** — STATE.md and BUILDLOG.md lifecycle, recovery on resume, log rotation patterns
|
|
71
|
+
|
|
72
|
+
### Foundational Principles
|
|
73
|
+
- **[CARDINAL-RULES.md](CARDINAL-RULES.md)** — 10 foundational principles (dispatch model, cost, subagent discipline, TDD, reliability, orchestrator isolation, orchestrator focus, durable handoff, control files, security & version control)
|
|
74
|
+
|
|
75
|
+
### Operational Governance
|
|
76
|
+
- **[GOVERNANCE.md](GOVERNANCE.md)** — Single-instance loops, single-writer files, heartbeat protocol, inbox pattern, AUTO/PROPOSE action tiers
|
|
77
|
+
|
|
78
|
+
### Reliability Guarantees
|
|
79
|
+
- **[RELIABILITY.md](RELIABILITY.md)** — Reliability core (inputs always produce outputs, no silent waits, pride bar for completion), failure scenarios, recovery patterns
|
|
80
|
+
|
|
81
|
+
### Security & Hooks
|
|
82
|
+
- **[HOOK-INSTALL.md](HOOK-INSTALL.md)** — Install and customize `hooks/pre-push-policy.sh` (branch discipline, secret-scan enforcement at push time)
|
|
83
|
+
|
|
84
|
+
### Team Onboarding
|
|
85
|
+
- **[MEMORY-TEMPLATE.md](MEMORY-TEMPLATE.md)** — Canonical format for team memory and facts (to be stored in `~/.claude/MEMORY.md`)
|
|
86
|
+
|
|
87
|
+
### Behavioral Review Checklist
|
|
88
|
+
- **[BEHAVIORAL-PR-REVIEW.md](BEHAVIORAL-PR-REVIEW.md)** — Checklist for reviewing PRs that modify rules, policies, or orchestration behavior
|
|
89
|
+
|
|
90
|
+
### Operational Guides
|
|
91
|
+
- **[FORENSICS.md](FORENSICS.md)** — Reconstruct agent failures using `tools/agent-forensics.sh`; make agent behavior git-debuggable
|
|
92
|
+
- **[RESTORE.md](RESTORE.md)** — Reconstitute Aesop & fleet on a new machine from git + watchdog backups
|
|
93
|
+
- **[PUBLISHING.md](PUBLISHING.md)** — Release Aesop to npm using GitHub Actions with OIDC trusted publishing
|
|
94
|
+
- **[av-resilience.md](av-resilience.md)** — Antivirus and behavioral-engine resilience patterns for reliable agent execution
|
|
95
|
+
|
|
96
|
+
### Lessons & Case Studies
|
|
97
|
+
- **[autonomous-swe.md](autonomous-swe.md)** — The 0.1.0-rc.1 milestone told honestly: what "autonomous SWE" means here (a fleet running the wave loop under a human who owns the outward gates), the committed evidence behind each claim (held-out benchmark, verified audit, proven kill-switch, reproducible package), and the limits the project owns
|
|
98
|
+
- **[case-study-portfolio.md](case-study-portfolio.md)** — How Aesop built its own portfolio site; full audit trail and cost breakdown
|
|
99
|
+
- **[SCRIPTS-POLICY.md](SCRIPTS-POLICY.md)** — Local-only execution, shared script library (`~/scripts`), task-local vs. reusable heuristics
|
|
100
|
+
|
|
101
|
+
---
|
|
25
102
|
|
|
26
|
-
|
|
27
|
-
- [MEMORY-TEMPLATE.md](MEMORY-TEMPLATE.md) — Canonical index format and structure for team memory & facts
|
|
103
|
+
## Quick Index by Use Case
|
|
28
104
|
|
|
29
|
-
|
|
30
|
-
|
|
105
|
+
**I'm setting up Aesop for the first time**
|
|
106
|
+
→ [INSTALL.md](INSTALL.md) → [CONFIGURE.md](CONFIGURE.md) → [FIRST-WAVE.md](FIRST-WAVE.md)
|
|
31
107
|
|
|
32
|
-
|
|
33
|
-
- [
|
|
108
|
+
**I want to understand the cost model**
|
|
109
|
+
→ [DISPATCH-MODEL.md](DISPATCH-MODEL.md) or [HOW-THE-LOOP-WORKS.md](HOW-THE-LOOP-WORKS.md#why-its-fast--cheap)
|
|
34
110
|
|
|
35
|
-
|
|
36
|
-
|
|
111
|
+
**I want to know what's actually proven vs. claimed (the rc.1 milestone)**
|
|
112
|
+
→ [autonomous-swe.md](autonomous-swe.md)
|
|
37
113
|
|
|
38
|
-
|
|
39
|
-
|
|
114
|
+
**I need to understand how state survives a crash**
|
|
115
|
+
→ [CHECKPOINTING.md](CHECKPOINTING.md)
|
|
116
|
+
|
|
117
|
+
**I'm reviewing a PR that changes orchestration behavior**
|
|
118
|
+
→ [BEHAVIORAL-PR-REVIEW.md](BEHAVIORAL-PR-REVIEW.md)
|
|
119
|
+
|
|
120
|
+
**An agent failed and I need to debug it**
|
|
121
|
+
→ [FORENSICS.md](FORENSICS.md)
|
|
122
|
+
|
|
123
|
+
**I need to set up Aesop on a new machine after a wipe**
|
|
124
|
+
→ [RESTORE.md](RESTORE.md)
|
|
125
|
+
|
|
126
|
+
**I want to release a new version of Aesop**
|
|
127
|
+
→ [PUBLISHING.md](PUBLISHING.md)
|
|
128
|
+
|
|
129
|
+
**I'm experiencing reliability issues**
|
|
130
|
+
→ [RELIABILITY.md](RELIABILITY.md) or [GOVERNANCE.md](GOVERNANCE.md)
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Architecture Diagram (Quick Reference)
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Ranked Backlog
|
|
138
|
+
↓
|
|
139
|
+
Orchestrator (main thread)
|
|
140
|
+
↓
|
|
141
|
+
Parallel Haiku Fleet (worktrees)
|
|
142
|
+
[test] [build] [docs] [ui] ...
|
|
143
|
+
↓
|
|
144
|
+
Watchdog (heartbeat + respawn)
|
|
145
|
+
↓
|
|
146
|
+
Integration Merge Train
|
|
147
|
+
↓
|
|
148
|
+
Checkpoint (STATE.md + BUILDLOG.md)
|
|
149
|
+
↓
|
|
150
|
+
Closing Audit (findings)
|
|
151
|
+
↓
|
|
152
|
+
Monitor + Dashboard (signals)
|
|
153
|
+
↓
|
|
154
|
+
Next Backlog (feedback loop)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for the full diagram and component breakdown.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Quick Answers
|
|
162
|
+
|
|
163
|
+
**Q: How do I start a wave?**
|
|
164
|
+
A: Type `/power` to prime your orchestrator brain, then `/buildsystem` to start a wave cycle. See [FIRST-WAVE.md](FIRST-WAVE.md).
|
|
165
|
+
|
|
166
|
+
**Q: How much does a wave cost?**
|
|
167
|
+
A: ~$0.03–$0.05 USD (1 Opus orchestrator + 5–8 Haiku agents). See [DISPATCH-MODEL.md](DISPATCH-MODEL.md).
|
|
168
|
+
|
|
169
|
+
**Q: What if an agent hangs?**
|
|
170
|
+
A: The watchdog detects it (>200s idle), respawns automatically (up to 3 retries), then surfaces to you if still stuck. See [CARDINAL-RULES.md](CARDINAL-RULES.md).
|
|
171
|
+
|
|
172
|
+
**Q: How do I add my repos?**
|
|
173
|
+
A: Edit `aesop.config.json` and add paths to `repos` array. See [CONFIGURE.md](CONFIGURE.md).
|
|
174
|
+
|
|
175
|
+
**Q: Do agents work in the primary tree?**
|
|
176
|
+
A: No. Each agent works in its own sibling worktree (via `git worktree add`). See [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
177
|
+
|
|
178
|
+
**Q: How do I set up secret-scan?**
|
|
179
|
+
A: The pre-push hook is auto-installed. Customize `tools/secret_scan.py` with your rules. See [HOOK-INSTALL.md](HOOK-INSTALL.md).
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Contributing
|
|
184
|
+
|
|
185
|
+
Aesop is **source-available** under the PolyForm Strict License 1.0.0, which doesn't permit modification or redistribution — so outside code patches can't be merged as contributions. **Issues, bug reports, and discussion are warmly welcome**, and are the best way to help. The repo develops itself via its own `/buildsystem` loop; code changes are made by the maintainer at their discretion, or by prior arrangement.
|
|
186
|
+
|
|
187
|
+
See [CONTRIBUTING.md](../CONTRIBUTING.md) for details and [CARDINAL-RULES.md](CARDINAL-RULES.md) for core principles.
|
|
188
|
+
|
|
189
|
+
---
|
|
40
190
|
|
|
41
|
-
##
|
|
191
|
+
## License
|
|
42
192
|
|
|
43
|
-
- [
|
|
44
|
-
- [av-resilience.md](av-resilience.md) — Antivirus & behavioral-engine resilience patterns for reliable agent execution
|
|
193
|
+
**Source-available** under the [PolyForm Strict License 1.0.0](../LICENSE). Use is permitted for a permitted purpose; **modification and redistribution are not**. See [`LICENSE`](../LICENSE) for full terms.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# It shipped itself: the 0.1.0-rc.1 milestone, told honestly
|
|
2
|
+
|
|
3
|
+
Aesop reached its first release candidate — `0.1.0-rc.1` — by running its own
|
|
4
|
+
`/buildsystem` wave loop across the backlog that produced it: rank work, fan out
|
|
5
|
+
parallel Haiku workers on file-disjoint domains, watchdog them, verify merges,
|
|
6
|
+
close with an audit that seeds the next wave. This document is the honest account
|
|
7
|
+
of what that milestone is and is not. Aesop's entire premise is candor, so the
|
|
8
|
+
caveats here are load-bearing, not fine print.
|
|
9
|
+
|
|
10
|
+
## What "autonomous SWE" means here
|
|
11
|
+
|
|
12
|
+
It means something specific and narrow:
|
|
13
|
+
|
|
14
|
+
> The **fleet** autonomously runs the wave loop — audit → parallel build → verify →
|
|
15
|
+
> merge-train — under a **human** who sets the goals and owns the outward gates.
|
|
16
|
+
|
|
17
|
+
Concretely:
|
|
18
|
+
|
|
19
|
+
- **The fleet drives the loop.** Ranking, dispatch, worktree isolation, verification,
|
|
20
|
+
and the merge train run without a human hand-writing the code in each domain.
|
|
21
|
+
- **A human owns the outward gates.** npm publishes, tagged releases, and git history
|
|
22
|
+
rewrites are all human-approved. The fleet proposes; a person disposes at the
|
|
23
|
+
repo boundary.
|
|
24
|
+
- **The dispatch core is out-of-repo.** The actual model calls happen inside the
|
|
25
|
+
Claude Code harness, which is *not* part of this repository. What Aesop ships is
|
|
26
|
+
the machinery *around* that core — orchestration rules, guardrails, durable state,
|
|
27
|
+
the dashboard, and tooling.
|
|
28
|
+
|
|
29
|
+
What it is **not**: it is not an unsupervised agent, not a hosted control plane, and
|
|
30
|
+
not AGI. Calling it "autonomous SWE" is accurate only with those boundaries stated.
|
|
31
|
+
Drop them and the phrase becomes hype.
|
|
32
|
+
|
|
33
|
+
## The evidence, and the honest limit on each
|
|
34
|
+
|
|
35
|
+
The milestone's real differentiator is not that an AI wrote code — plenty of tools do
|
|
36
|
+
that. It is that the credibility and safety claims ship with **committed artifacts a
|
|
37
|
+
skeptical reader can check**, each paired with the limit the project already owns.
|
|
38
|
+
|
|
39
|
+
### 1. Haiku is good enough for the judgment work a fleet does
|
|
40
|
+
|
|
41
|
+
The harness's whole cost model depends on cheap Haiku workers being adequate for
|
|
42
|
+
subagent judgment, not just extraction. That was long asserted from the fleet grading
|
|
43
|
+
its own output — agents vouching for agents, recorded in a private memory file. Not
|
|
44
|
+
evidence an outsider can check.
|
|
45
|
+
|
|
46
|
+
`bench/` plus `tools/bench_runner.py` replace that with a **held-out benchmark scored
|
|
47
|
+
by plain Python string/regex matching — no model, no agent in the grading loop**.
|
|
48
|
+
Across a combined **39 judgment tasks** (spanning bug-in-diff, finding-inflation,
|
|
49
|
+
acceptance-criteria coverage, severity calibration, root-cause-from-trace,
|
|
50
|
+
refactor-equivalence, and security-spotting):
|
|
51
|
+
|
|
52
|
+
| Model | Score | Cost (per-token) |
|
|
53
|
+
| ------ | ----- | ---------------- |
|
|
54
|
+
| Haiku | **39/39 (100%)** | ~1/3 of Opus |
|
|
55
|
+
| Sonnet | 39/39 (100%) | — |
|
|
56
|
+
| Opus | 38/39 (97%) | baseline |
|
|
57
|
+
|
|
58
|
+
On the single task any model missed — a severity call — it was *Opus* that erred, not
|
|
59
|
+
Haiku. Full dated runs: [`bench/results/`](../bench/results/).
|
|
60
|
+
|
|
61
|
+
**Honest limits (the project's own words):**
|
|
62
|
+
|
|
63
|
+
- **Curated, not sampled.** The tasks were constructed by reasoning about fleet work,
|
|
64
|
+
not drawn from real fleet transcripts. Selection bias remains.
|
|
65
|
+
- **N=39 is bigger, not statistically large.** Treat this as directional evidence for
|
|
66
|
+
this workload, not a universal law.
|
|
67
|
+
- **It measures a floor, not the frontier.** The benchmark found *no* task where Opus
|
|
68
|
+
beats Haiku. So the defensible claim is bounded: *Haiku is sufficient for the
|
|
69
|
+
judgment shapes measured here*, **not** *Haiku equals Opus at the reasoning
|
|
70
|
+
frontier*. If tasks exist where Opus's depth is worth 3×, this set hasn't captured
|
|
71
|
+
them.
|
|
72
|
+
- **Cost is the token-price ratio**, not measured wall-clock latency.
|
|
73
|
+
|
|
74
|
+
### 2. Audits stop hallucinating findings
|
|
75
|
+
|
|
76
|
+
An earlier wave (wave-24) exposed a real failure mode: an all-Haiku audit reported
|
|
77
|
+
four P0 issues, **zero of which were real**. The release audit for this RC was run
|
|
78
|
+
with **adversarial verification of every finding** and closed with **0 hallucinated
|
|
79
|
+
issues**.
|
|
80
|
+
|
|
81
|
+
**Honest limit:** it is an internal audit. No third party has re-run it.
|
|
82
|
+
|
|
83
|
+
### 3. The kill-switch actually aborts a wave
|
|
84
|
+
|
|
85
|
+
A halt control is only worth the claim if it's proven. The fleet-wide kill-switch
|
|
86
|
+
([`tools/halt.py`](../tools/halt.py)) is wired into the **live dispatch path** and was
|
|
87
|
+
exercised end-to-end: a single signal **aborted a real wave with zero workers
|
|
88
|
+
spawned**.
|
|
89
|
+
|
|
90
|
+
**Honest limit:** it is operator-triggered — a manual brake a human pulls, not an
|
|
91
|
+
autonomous safety monitor that trips on its own.
|
|
92
|
+
|
|
93
|
+
### 4. A cost ceiling brakes runaway spend
|
|
94
|
+
|
|
95
|
+
A per-wave spend ceiling ([`tools/cost_ceiling.py`](../tools/cost_ceiling.py)) halts
|
|
96
|
+
dispatch when the configured budget is exceeded.
|
|
97
|
+
|
|
98
|
+
**Honest limit:** it brakes against a **configured** ceiling; it is **not yet tied to
|
|
99
|
+
live token spend**. It's a guardrail you set, not a live meter.
|
|
100
|
+
|
|
101
|
+
### 5. The package installs and reproduces from a clean clone
|
|
102
|
+
|
|
103
|
+
The npm tarball is a **~409 kB** package (measured via `npm pack`) that **builds and
|
|
104
|
+
validates from a fresh clone in CI** — the `reproduce` workflow proves the tarball is
|
|
105
|
+
self-contained. The dashboard views shipped this RC (Wave PR Board, Agent Inspector)
|
|
106
|
+
were **browser-proven** with Playwright. Steps to reproduce offline:
|
|
107
|
+
[docs/reproduce.md](./reproduce.md).
|
|
108
|
+
|
|
109
|
+
**Honest limit:** the offline reproduce job runs the test suites and the benchmark
|
|
110
|
+
*scorer*; it does **not** run real-model benchmark calls or the Playwright browser
|
|
111
|
+
proofs, which need local setup and (for the models) API keys.
|
|
112
|
+
|
|
113
|
+
## The limits the project owns, in one place
|
|
114
|
+
|
|
115
|
+
None of these are hidden, because hiding them would betray the one thing the project is
|
|
116
|
+
actually selling — candor:
|
|
117
|
+
|
|
118
|
+
1. **The benchmark is curated (N=39), not transcript-sampled.** Directional, not
|
|
119
|
+
definitive; it maps a floor, not the frontier.
|
|
120
|
+
2. **The real dispatch core is out-of-repo.** It runs in the Claude Code harness. This
|
|
121
|
+
package is the harness around it, not a turnkey autonomous runtime.
|
|
122
|
+
3. **No third party has reproduced any of it yet.** The artifacts are committed so a
|
|
123
|
+
skeptic can — that is transparency, not a substitute for independent replication.
|
|
124
|
+
4. **The cost ceiling is a brake, not a live meter.** It enforces a configured budget,
|
|
125
|
+
not measured spend.
|
|
126
|
+
5. **It is local-first.** State lives in git and local files; there is no hosted
|
|
127
|
+
control plane. Team scale beyond one machine is on the roadmap, not shipped.
|
|
128
|
+
6. **It is a release candidate.** APIs, config, and dashboard contracts may still shift
|
|
129
|
+
before 0.1.0. Pin the exact version if you need stability.
|
|
130
|
+
|
|
131
|
+
## Where to check the receipts
|
|
132
|
+
|
|
133
|
+
- [`bench/results/`](../bench/results/) — dated benchmark runs (v1 extraction, v2 & v3
|
|
134
|
+
judgment), each with its own honest interpretation and limits.
|
|
135
|
+
- [`bench/README.md`](../bench/README.md) — why the benchmark exists and how the scoring
|
|
136
|
+
removes agents from the grading loop.
|
|
137
|
+
- [`tools/halt.py`](../tools/halt.py), [`tools/cost_ceiling.py`](../tools/cost_ceiling.py)
|
|
138
|
+
— the kill-switch and cost-ceiling implementations.
|
|
139
|
+
- [docs/reproduce.md](./reproduce.md) — reproduce the tests and benchmark scorer from a
|
|
140
|
+
clean clone.
|
|
141
|
+
- [RELEASE-NOTES.md](../RELEASE-NOTES.md#honest-limits) — release-level "Honest limits".
|
|
142
|
+
- [CHANGELOG.md](../CHANGELOG.md) — the full `0.1.0-rc.1` entry.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
The one-line version: **the fleet built, tested, audited, and benchmarked its way to a
|
|
147
|
+
shippable release candidate, and every claim about that comes with a committed artifact
|
|
148
|
+
and a stated limit.** That combination — self-built *and* honest about the seams — is
|
|
149
|
+
the milestone.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Reproducing Aesop
|
|
2
|
+
|
|
3
|
+
This document explains how to reproduce the project's claims from a clean checkout.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Aesop project includes:
|
|
8
|
+
1. **Full test suites** (Node.js + Python) that verify core functionality
|
|
9
|
+
2. **An offline benchmark scorer** that proves the benchmark scoring logic works correctly
|
|
10
|
+
|
|
11
|
+
Both can be reproduced entirely offline, without API keys or external dependencies, from any clean clone of the repository.
|
|
12
|
+
|
|
13
|
+
## Reproducing from a Clean Clone
|
|
14
|
+
|
|
15
|
+
### Prerequisites
|
|
16
|
+
|
|
17
|
+
- **Node.js**: 18 or later
|
|
18
|
+
- **Python**: 3.12 or later
|
|
19
|
+
- **Git**: any recent version
|
|
20
|
+
|
|
21
|
+
### Steps
|
|
22
|
+
|
|
23
|
+
1. Clone the repository (no special flags needed):
|
|
24
|
+
```bash
|
|
25
|
+
git clone https://github.com/matt82198/aesop.git
|
|
26
|
+
cd aesop
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
2. Verify Node.js and Python are installed:
|
|
30
|
+
```bash
|
|
31
|
+
node --version
|
|
32
|
+
python --version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. Install Node.js dependencies:
|
|
36
|
+
```bash
|
|
37
|
+
npm ci
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
4. Run the full test suite (Python + Node.js):
|
|
41
|
+
```bash
|
|
42
|
+
# Run Node.js tests
|
|
43
|
+
npm run test:node
|
|
44
|
+
|
|
45
|
+
# Run Python tests
|
|
46
|
+
python -m unittest discover -s tests
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
5. Run the benchmark scorer offline:
|
|
50
|
+
```bash
|
|
51
|
+
# Run the benchmark unit tests (syntax, ground truth format, etc.)
|
|
52
|
+
python -m unittest tests.test_bench_runner -v
|
|
53
|
+
|
|
54
|
+
# Run the offline mock benchmark
|
|
55
|
+
python tools/bench_runner.py --runner mock
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## What the `.github/workflows/reproduce.yml` Job Does
|
|
59
|
+
|
|
60
|
+
The `reproduce` workflow in GitHub Actions automates the above steps:
|
|
61
|
+
|
|
62
|
+
1. **Fresh checkout**: Uses a clean clone (no state reuse from other CI jobs)
|
|
63
|
+
2. **Syntax checks**: Validates all Node.js (.mjs) and shell scripts (.sh)
|
|
64
|
+
3. **Node.js tests**: Runs the full test suite with `npm run test:node`
|
|
65
|
+
4. **Python tests**: Runs the full test suite with `python -m unittest discover`
|
|
66
|
+
5. **Benchmark scorer**: Proves the offline mock benchmark reproduces (no external API calls)
|
|
67
|
+
|
|
68
|
+
The workflow is triggered:
|
|
69
|
+
- **Manually**: Via GitHub Actions "Run workflow" button (workflow_dispatch)
|
|
70
|
+
- **Weekly**: Every Sunday at 2:00 AM UTC (schedule)
|
|
71
|
+
|
|
72
|
+
## What Is and Isn't Reproduced
|
|
73
|
+
|
|
74
|
+
### Reproduced (offline, no API keys needed)
|
|
75
|
+
|
|
76
|
+
- ✓ All committed test suites (correctness, integration, governance)
|
|
77
|
+
- ✓ The benchmark **scorer logic** (matching, scoring, reporting)
|
|
78
|
+
- ✓ The benchmark **mock runner** (deterministic offline accuracy score)
|
|
79
|
+
- ✓ The committed benchmark files (`bench/tasks.jsonl`, `bench/ground_truth.jsonl`)
|
|
80
|
+
|
|
81
|
+
### Not Reproduced (requires external APIs)
|
|
82
|
+
|
|
83
|
+
- ✗ A real multi-model benchmark (calling Claude API, OpenAI, etc.)
|
|
84
|
+
- ✗ The dashboard browser tests (Playwright, requires UI setup)
|
|
85
|
+
- ✗ Performance/timing benchmarks
|
|
86
|
+
- ✗ The full CI job's additional linting and drift checks
|
|
87
|
+
|
|
88
|
+
The benchmark mock runner always returns the same accuracy score because it uses a hardcoded heuristic (plain string/regex matching), not a real model. This is intentional — the tests prove the *scorer* works correctly, not that any model achieves a specific accuracy.
|
|
89
|
+
|
|
90
|
+
## Interpreting Results
|
|
91
|
+
|
|
92
|
+
### Success
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
YAML is valid
|
|
96
|
+
All Node.js tests pass
|
|
97
|
+
All Python tests pass
|
|
98
|
+
Benchmark reproduction successful
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Failure
|
|
102
|
+
|
|
103
|
+
If any step fails, the workflow exits with a non-zero exit code and prints the failure details. Common issues:
|
|
104
|
+
|
|
105
|
+
1. **Node.js test failure**: Check `tests/*.test.mjs` for the specific failing test.
|
|
106
|
+
2. **Python test failure**: Check the error message; most often a missing test fixture or a test isolation bug.
|
|
107
|
+
3. **Benchmark reproduction failure**: Run `python tools/bench_runner.py --runner mock` manually to see the exact error.
|
|
108
|
+
|
|
109
|
+
## For Project Maintainers
|
|
110
|
+
|
|
111
|
+
When you add new features or tests:
|
|
112
|
+
|
|
113
|
+
1. Ensure all tests pass locally: `npm run test:all` (or individually per suite)
|
|
114
|
+
2. The `reproduce` workflow will catch any regressions automatically
|
|
115
|
+
3. If reproduction fails, it indicates the committed test fixtures or scorer are inconsistent
|
|
116
|
+
|
|
117
|
+
## References
|
|
118
|
+
|
|
119
|
+
- Test discovery: `python -m unittest discover --help`
|
|
120
|
+
- Benchmark scorer: `python tools/bench_runner.py --help`
|
|
121
|
+
- GitHub Actions workflow syntax: https://docs.github.com/en/actions
|
package/hooks/CLAUDE.md
CHANGED
|
@@ -30,6 +30,34 @@ Runs on `git push` via `.git/hooks/pre-push` symlink or copy.
|
|
|
30
30
|
- See `docs/HOOK-INSTALL.md` for symlink (Linux/macOS/Git Bash) and copy (Windows) methods
|
|
31
31
|
- Test with `bash hooks/pre-push-policy.sh --test` before org distribution
|
|
32
32
|
|
|
33
|
+
## Hook: pre-commit-waveguard.sh
|
|
34
|
+
|
|
35
|
+
Prevents accidental commits to the PRIMARY aesop tree during a wave cycle. Runs on `git commit` via `.git/hooks/pre-commit`.
|
|
36
|
+
|
|
37
|
+
**Purpose**: During orchestrated waves, the orchestrator sets a marker file (`state/.wave-in-flight`) in the PRIMARY tree only. Sibling worktrees do not inherit this marker (separate working trees), so fleet agents commit freely in worktrees while stray commits to the primary tree are rejected.
|
|
38
|
+
|
|
39
|
+
**Mechanism**:
|
|
40
|
+
1. **Marker Contract**: Orchestrator writes `state/.wave-in-flight` in the PRIMARY tree before dispatching wave work. The marker is git-ignored, so sibling worktrees checked out during the wave do NOT carry it.
|
|
41
|
+
2. **Pre-Commit Check**: Hook resolves the marker relative to the CURRENT working tree via `git rev-parse --show-toplevel` (NOT a hardcoded `$HOME/aesop` — that resolved to the primary tree from every worktree and blocked the whole fleet mid-wave, the wave-24 incident). Primary tree (has marker during a wave) → exit 1 (reject); sibling worktree (no marker) → exit 0 (allow).
|
|
42
|
+
3. **Override**: User or orchestrator may delete `state/.wave-in-flight` to manually allow commits to primary tree.
|
|
43
|
+
|
|
44
|
+
**Exit Contract**:
|
|
45
|
+
- Exit 0: Marker absent, commit allowed (normal operation)
|
|
46
|
+
- Exit 1: Marker present, commit blocked with clear error message
|
|
47
|
+
|
|
48
|
+
**Error Message**:
|
|
49
|
+
```
|
|
50
|
+
Error: Wave in flight. Commit from a sibling worktree, or clear <marker_path> to override.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Installation**:
|
|
54
|
+
- Run `bash hooks/install-waveguard.sh` to idempotently install into `.git/hooks/pre-commit`.
|
|
55
|
+
- If a pre-commit hook already exists, installer backs it up (`.git/hooks/pre-commit.waveguard-backup`) and wraps both (waveguard first, then existing hook if present).
|
|
56
|
+
|
|
57
|
+
**Idempotency**:
|
|
58
|
+
- Installer checks if hook already calls waveguard; skips if already installed.
|
|
59
|
+
- Safe to re-run multiple times.
|
|
60
|
+
|
|
33
61
|
## Hook: hooks/claude/force-model-policy.mjs
|
|
34
62
|
|
|
35
63
|
Claude Code hook enforcing subagent Haiku dispatch (cost optimization).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
main() {
|
|
5
|
+
local repo_root
|
|
6
|
+
repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
7
|
+
if [ -z "$repo_root" ]; then
|
|
8
|
+
printf 'Error: Not in a git repository\n' >&2
|
|
9
|
+
return 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
local hooks_dir="$repo_root/.git/hooks"
|
|
13
|
+
local waveguard_src="$repo_root/hooks/pre-commit-waveguard.sh"
|
|
14
|
+
local pre_commit_dest="$hooks_dir/pre-commit"
|
|
15
|
+
local pre_commit_orig="$hooks_dir/pre-commit.waveguard-backup"
|
|
16
|
+
|
|
17
|
+
if [ ! -f "$waveguard_src" ]; then
|
|
18
|
+
printf 'Error: Source hook not found at %s\n' "$waveguard_src" >&2
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
mkdir -p "$hooks_dir"
|
|
23
|
+
|
|
24
|
+
if [ -f "$pre_commit_dest" ]; then
|
|
25
|
+
if grep -q 'pre-commit-waveguard' "$pre_commit_dest" 2>/dev/null; then
|
|
26
|
+
printf 'Info: pre-commit hook already has waveguard; skipping.\n'
|
|
27
|
+
return 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
cp "$pre_commit_dest" "$pre_commit_orig"
|
|
31
|
+
printf 'Info: Existing pre-commit hook backed up to %s\n' "$pre_commit_orig"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
cat > "$pre_commit_dest" <<'HOOK_WRAPPER'
|
|
35
|
+
#!/usr/bin/env bash
|
|
36
|
+
set -uo pipefail
|
|
37
|
+
|
|
38
|
+
repo_root=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
|
39
|
+
if [ -z "$repo_root" ]; then
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
waveguard_hook="$repo_root/hooks/pre-commit-waveguard.sh"
|
|
44
|
+
if [ -f "$waveguard_hook" ]; then
|
|
45
|
+
bash "$waveguard_hook"
|
|
46
|
+
waveguard_exit=$?
|
|
47
|
+
if [ $waveguard_exit -ne 0 ]; then
|
|
48
|
+
exit $waveguard_exit
|
|
49
|
+
fi
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
backup_hook="$repo_root/.git/hooks/pre-commit.waveguard-backup"
|
|
53
|
+
if [ -f "$backup_hook" ] && [ -x "$backup_hook" ]; then
|
|
54
|
+
bash "$backup_hook"
|
|
55
|
+
exit $?
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
exit 0
|
|
59
|
+
HOOK_WRAPPER
|
|
60
|
+
|
|
61
|
+
chmod +x "$pre_commit_dest"
|
|
62
|
+
printf 'Info: Installed waveguard pre-commit hook to %s\n' "$pre_commit_dest"
|
|
63
|
+
return 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|
67
|
+
main "$@"
|
|
68
|
+
fi
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -uo pipefail
|
|
3
|
+
|
|
4
|
+
main() {
|
|
5
|
+
# Resolve the marker relative to the CURRENT working tree, NOT a hardcoded primary path.
|
|
6
|
+
# This is load-bearing: the marker (state/.wave-in-flight) is git-ignored, so a sibling
|
|
7
|
+
# worktree checked out during a wave does NOT carry it — only the PRIMARY tree (where the
|
|
8
|
+
# orchestrator sets it) does. Checking the current tree's own toplevel means primary-tree
|
|
9
|
+
# commits are blocked during a wave while legitimate worktree-agent commits pass. A prior
|
|
10
|
+
# version hardcoded ${AESOP_ROOT:-$HOME/aesop}, which resolved to the primary tree from every
|
|
11
|
+
# worktree and thus blocked the entire fleet mid-wave (wave-24 incident). Do not reintroduce.
|
|
12
|
+
local toplevel
|
|
13
|
+
toplevel=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
|
|
14
|
+
local marker_file="$toplevel/state/.wave-in-flight"
|
|
15
|
+
|
|
16
|
+
if [ -f "$marker_file" ]; then
|
|
17
|
+
printf 'Error: Wave in flight in this tree (%s). Commit from a sibling worktree, or clear the marker to override.\n' "$marker_file" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
exit 0
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|
25
|
+
main "$@"
|
|
26
|
+
fi
|