@matt82198/aesop 0.3.2 → 0.4.1
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 +47 -0
- package/README.md +24 -9
- package/aesop.config.example.json +16 -0
- package/bin/cli.js +107 -34
- package/daemons/run-watchdog.sh +6 -2
- package/docs/CONFIGURE.md +31 -20
- package/docs/FIRST-WAVE.md +29 -9
- package/docs/INSTALL.md +181 -26
- package/docs/MICROKERNEL.md +452 -0
- package/docs/PORTING.md +4 -0
- package/docs/README.md +7 -3
- package/docs/THE-AESOP-HYPOTHESIS.md +156 -0
- package/driver/CLAUDE.md +123 -123
- package/driver/README.md +40 -2
- package/driver/adjudication_gate.py +367 -0
- package/driver/aesop.config.example.json +20 -4
- package/driver/backend_config.py +603 -12
- package/driver/claude_code_driver.py +9 -17
- package/driver/codex_driver.py +80 -25
- package/driver/context_pack.py +454 -0
- package/driver/openai_compatible_driver.py +53 -11
- package/driver/openai_transport.py +31 -10
- package/driver/orchestrator_backend.py +332 -0
- package/driver/orchestrator_driver.py +589 -0
- package/driver/proc_util.py +134 -0
- package/driver/wave_loop.py +801 -59
- package/driver/wave_scheduler.py +361 -37
- package/monitor/collect-signals.mjs +83 -0
- package/package.json +1 -1
- package/state_store/coordination.py +65 -5
- package/tools/ci_merge_wait.py +88 -42
- package/tools/ci_shard_runner.py +128 -0
- package/tools/doctor.js +124 -12
- package/tools/reproduce.js +11 -2
- package/tools/seated_shadow_adjudication.py +920 -0
- package/tools/self_stats.py +61 -6
- package/tools/shadow_adjudication.py +1024 -0
- package/tools/verify_test_suite_count.py +250 -0
- package/tools/verify_ui_trio_redaction_proof.py +292 -0
- package/tools/wave_manifest_lint.py +485 -0
- package/tools/wave_scorecard.py +430 -0
- package/ui/config.py +1 -1
- package/ui/cost.py +176 -3
- package/ui/web/dist/assets/{index-CP68RIh3.js → index-4rp6B_ID.js} +1 -1
- package/ui/web/dist/assets/{index-CNQxaiOW.css → index-B2lTtpsH.css} +1 -1
- package/ui/web/dist/index.html +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
**Version scheme**: Stable releases are `0.x.y`; `0.x.0-beta.N` / `-rc.N` are pre-releases; `0.1.0-wave.N` were internal wave-milestone previews.
|
|
9
9
|
|
|
10
|
+
## [0.4.1] - 2026-07-26
|
|
11
|
+
|
|
12
|
+
### Onboarding overhaul
|
|
13
|
+
- **Config home-directory expansion** (PR #413): User-set `aesop_root: "~/myfleet"` now expands correctly via `.expanduser()` instead of treating tilde as a literal path.
|
|
14
|
+
- **Reproduce graceful degradation** (PR #413): Fresh scaffolds (`.git` present, no `package-lock.json`) detect scaffold mode and run installed-mode verification instead of failing on `npm ci`; clear one-line message on graceful degrade.
|
|
15
|
+
- **Scaffolder absolute paths** (PR #413): All NEXT STEPS `cd` commands in CLI output now print absolute resolved paths matching config's stored resolved paths (no relative dirs).
|
|
16
|
+
- **Scaffold and doctor fixes** (PR #407): Corrected path handling in scaffolder and doctor, improved validation logic, clearer guidance on remediation.
|
|
17
|
+
- **Setup docs field-name sync** (PR #405): Fixed CONFIGURE block field names and added missing Claude Code install steps; docs now match actual config structure.
|
|
18
|
+
- **Watchdog smoke-test verdict** (PR #406): New `watchdog --once` exits with explicit PASS/FAIL verdict for CI/doctor integration; clear signal for fleet health checks.
|
|
19
|
+
|
|
20
|
+
### CI/test hardening
|
|
21
|
+
- **PowerShell syntax gate** (PR #401): Pre-commit CI gate validates all `*.ps1` files for correct syntax; prevents shell-script drift on Windows daemon scripts.
|
|
22
|
+
- **Workflow_dispatch on main-full** (PR #399): Main CI now accepts manual dispatch trigger for on-demand full-suite runs without waiting for a commit.
|
|
23
|
+
- **Self-updating test suite count gate** (PR #403): New `tools/verify_test_suite_count.py` auto-reconciles test counts in `tests/CLAUDE.md`; `--check` mode for CI (fail-closed on drift), `--fix` mode for lanes. Eliminates merge blocks from concurrent test additions.
|
|
24
|
+
- **Frontier-slice test depollution** (PR #400): Frontier-slice benchmark output now writes to gitignored temp location instead of polluting repo; clean CI artifacts.
|
|
25
|
+
- **Git-identity isolation + runtime tripwire** (PR #412): Fixed root cause of Test User ghost commits — 6 test files used shell fallthrough causing silent git config writes to shared `.git/config`. Now using direct `spawn('git', …, {cwd})` with no shell; runtime tripwire in `test_test_hygiene.py` fails suite if repo identity mutates during test run.
|
|
26
|
+
|
|
27
|
+
### Honesty / stats
|
|
28
|
+
- **Stats truth-sync + verify tool** (PR #411): Fixed stale v0.1.0 stats in stats.json; new `scripts/verify-stats.sh` documents single-stats-source wrapper (`self_stats --check/--regenerate`); ancestor principles named (Temporal, Candea & Fox crash-only, Erlang/OTP, K8s reconciliation).
|
|
29
|
+
- **Self_stats squash-merge fix** (PR #398): Merged PR count now authoritative from GitHub API (387, up from undercounted 268). Git fallback for offline use handles both merge-commit and squash-merge styles; deduplicates on PR number.
|
|
30
|
+
|
|
31
|
+
### Bench
|
|
32
|
+
- **gpt-4o-mini worker seat dogfood** (PR #404): Benchmark expands with gpt-4o-mini seated as worker model; includes real context-tip item-9 discrimination and co-model A/B measurement.
|
|
33
|
+
|
|
34
|
+
## [0.4.0] - 2026-07-25
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- **Two-seat unified config** (HS-1): New `seats` configuration block allows swapping both worker AND orchestrator models from a single config block — eliminates split configuration and enables model experimentation without code changes. No-op default: existing installations remain unchanged (install-time safety).
|
|
38
|
+
- **Live orchestrator-seat swap** (HS-2): Added `final_catch` gate in the wave loop with block/quarantine + crash-only degradation — orchestrator model can be swapped mid-flight without restarting the entire fleet. Failure path quarantines the wave and logs the incident.
|
|
39
|
+
- **Microkernel architecture guide** (HS-3): New `docs/MICROKERNEL.md` explains the proof-of-concept model-swap seam, multi-model verification bounds, and a 60-second "swap a seat's model" quickstart for adopters.
|
|
40
|
+
- **Scaffold completeness** (`npx aesop init`): driver/ directory now scaffolds on first run (was omitted, breaking adopter first-run experience). Added --force idempotent re-scaffold and child process timeout protection.
|
|
41
|
+
|
|
42
|
+
### Security / Hardening
|
|
43
|
+
- **IPv6 SSRF + DNS-resolution validation**: Requests to orchestrator's `base_url` now validate against IPv6 loopback and route-local semantics; DNS resolution blocked for external hostnames; `is_local` pinned to loopback only.
|
|
44
|
+
- **API key environment variable allowlist** (primary enforcement): `api_key_env` rejects obvious secret patterns (AWS_SECRET, AZURE_KEY, etc.) and logs a loud NOTICE for non-standard names; fail-closed on read errors.
|
|
45
|
+
- **Worker model field validation**: `worker.model` config field no longer silently ignored if orchestrator uses a non-Claude driver; now validated at load time.
|
|
46
|
+
- **Wave execution timeouts**: Added `run_command` timeouts to prevent indefinite wave hangs on subprocess failures; child processes now respect explicit timeout boundaries (no more wave-level hard stops).
|
|
47
|
+
- **CI merge-wait fail-closed**: `ci_merge_wait` gate now exits with explicit failure codes (not silent pass) on timeout or missing CI status, preventing accidental merges of untested code.
|
|
48
|
+
- **Windows CI shard concurrency cap**: Reduced `max-parallel` for Windows runner to cut container contention flakes; Windows shard now stable on standard GitHub Actions.
|
|
49
|
+
- **Path redaction completeness** (bench tooling): Bench results and logs redact full paths before reporting; `is_local` validation prevents accidental leakage of internal network topology.
|
|
50
|
+
- **JSON-boundary fail-open holes patched**: Orchestrator/driver seam now validates JSON boundaries at worker<->orchestrator message crossings; malformed messages fail-closed (not skipped).
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
- **`npx aesop init` driver scaffolding**: Adopters running init on a fresh repo now get a complete driver/ directory tree; was silently omitting driver/, causing "module not found" on first wave.
|
|
54
|
+
- **Scaffold idempotency + child timeouts**: Re-running init --force no longer corrupts existing templates; child scaffold processes timeout cleanly instead of hanging.
|
|
55
|
+
- **Gate incumbent-validation**: Pre-gate validation of model incumbent (before swap attempt) catches incompatibilities early and logs them for forensics.
|
|
56
|
+
|
|
10
57
|
## [0.3.2] - 2026-07-23
|
|
11
58
|
|
|
12
59
|
### Fixed
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<em>
|
|
6
|
+
<em>Crash-only multi-agent orchestration for any repository</em>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
@@ -14,7 +14,15 @@
|
|
|
14
14
|
|
|
15
15
|
## What It Does
|
|
16
16
|
|
|
17
|
-
**Aesop** is a
|
|
17
|
+
**Aesop** is a **crash-recoverable orchestration harness** for multi-agent workflows on any repository. One-line theme: *stateless agent execution over git-backed durable memory*.
|
|
18
|
+
|
|
19
|
+
Core idea: **agent behavior is source code.** Every decision lives in durable, human-diffable files—git history, plain-text STATE.md, append-only BUILDLOG.md, Python guardrails. When a machine fails, you re-read from disk. No vector DBs, no distributed consensus, no magic. This repo's own 387 merged PRs across 1181 commits were delivered by Aesop's own `/buildsystem` wave loop—a supervised loop under a human operator who sets goals and owns outward gates (npm publish, releases, history rewrites).
|
|
20
|
+
|
|
21
|
+
**Why it matters:** crash recovery is not a special path; it is how the system *always* starts. Stateless workers, persistent filesystem brain, Haiku-first dispatch (4.3× cheaper than hierarchical design, proven by real A/B), fail-closed guardrails (pre-push secret gate, kill-switch, cost ceiling), and observable heartbeats. The result: 387 PRs across 1181 commits; Haiku at 39/39 on a 39-task benchmark vs Opus 38/39, at ~1/3 the cost.
|
|
22
|
+
|
|
23
|
+
**Why it's built this way:** [The Aesop Hypothesis](./docs/THE-AESOP-HYPOTHESIS.md) — the design philosophy, the trade-offs, the cancelled architectures with published data.
|
|
24
|
+
|
|
25
|
+
**New in 0.4.0:** Swap the **worker** and **orchestrator** model (Claude, Codex, or any OpenAI-compatible endpoint) from one `seats` config block without code changes. See [docs/MICROKERNEL.md](./docs/MICROKERNEL.md) for the two-seat architecture and a 60-second quickstart. Single-instance proven; multi-instance coordination is scheduled.
|
|
18
26
|
|
|
19
27
|
## Feature Demo
|
|
20
28
|
|
|
@@ -86,16 +94,20 @@ Aesop is built entirely by its own `/buildsystem` wave cycle—running parallel
|
|
|
86
94
|
|
|
87
95
|
| Metric | Value |
|
|
88
96
|
| --- | --- |
|
|
89
|
-
| Merged PRs |
|
|
90
|
-
| Total Commits |
|
|
91
|
-
| Project Age |
|
|
97
|
+
| Merged PRs | 387 <!-- metrics-verified: self_stats.py (git log) --> |
|
|
98
|
+
| Total Commits | 1181 <!-- metrics-verified: self_stats.py (git log) --> |
|
|
99
|
+
| Project Age | 14 days <!-- metrics-verified: self_stats.py (git log) --> |
|
|
92
100
|
| Waves | 30 <!-- metrics-verified: self_stats.py (git log) --> |
|
|
93
|
-
| Insertions + Deletions |
|
|
94
|
-
| Files Tracked |
|
|
101
|
+
| Insertions + Deletions | 222,290 <!-- metrics-verified: self_stats.py (git log) --> |
|
|
102
|
+
| Files Tracked | 642 <!-- metrics-verified: self_stats.py (git log) --> |
|
|
95
103
|
| Distinct Co-authors | 11 <!-- metrics-verified: self_stats.py (git log) --> |
|
|
96
104
|
|
|
97
105
|
<!-- STATS:END -->
|
|
98
106
|
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
99
111
|
*Wave: one complete build cycle (intake → dispatch → verify → ship) run by the orchestration engine.*
|
|
100
112
|
|
|
101
113
|
|
|
@@ -108,17 +120,18 @@ Aesop is built entirely by its own `/buildsystem` wave cycle—running parallel
|
|
|
108
120
|
|
|
109
121
|
## Why Haiku-First Works
|
|
110
122
|
|
|
111
|
-
The benchmark proves
|
|
123
|
+
The benchmark proves sufficiency: across 39 judgment tasks (code review, severity calibration, root-cause analysis, refactor equivalence, security spots), Haiku scored **39/39** vs Opus **38/39** at ~1/3 the per-token cost. See [`bench/results/2026-07-17-judgment-v3-haiku-sonnet-opus.md`](./bench/results/2026-07-17-judgment-v3-haiku-sonnet-opus.md). The pre-declared ceiling rule (when ≥2 tiers score ≥92%, the instrument failed to discriminate) trips on this result — both Haiku and Sonnet achieved 39/39, meaning the benchmark maps a *sufficiency floor*, not tier equivalence. **Curated set, N=39; scoped to extraction and judgment tasks with context at the seam** — does NOT reach frontier reasoning, long-horizon planning, or open-ended synthesis. Full analysis: [`bench/results/2026-07-26-judgment-v3-ceiling-addendum.md`](./bench/results/2026-07-26-judgment-v3-ceiling-addendum.md) and [`bench/EQUIVALENCE-MARGIN.md`](./bench/EQUIVALENCE-MARGIN.md).
|
|
112
124
|
|
|
113
125
|
## Learn More
|
|
114
126
|
|
|
115
127
|
- **[docs/INSTALL.md](./docs/INSTALL.md)** — Setup and first wave
|
|
128
|
+
- **[docs/MICROKERNEL.md](./docs/MICROKERNEL.md)** — The two swappable seats (worker + orchestrator), the invariant Report/state boundary, and a 60-second quickstart for swapping either seat's model
|
|
116
129
|
- **[docs/PORTING.md](./docs/PORTING.md)** — Adopter's guide: port Aesop to your repo (prerequisites, scaffold, 10 failure modes)
|
|
117
130
|
- **[docs/HOW-THE-LOOP-WORKS.md](./docs/HOW-THE-LOOP-WORKS.md)** — Concrete walkthrough of a wave cycle
|
|
118
131
|
- **[docs/DISPATCH-MODEL.md](./docs/DISPATCH-MODEL.md)** — Cost analysis and scaling
|
|
119
132
|
- **[docs/CARDINAL-RULES.md](./docs/CARDINAL-RULES.md)** — 10 foundational principles
|
|
120
133
|
- **[docs/autonomous-swe.md](./docs/autonomous-swe.md)** — What "autonomous" means (and doesn't), evidence for all claims, honest limits
|
|
121
|
-
- **[RELEASE-NOTES.md](./RELEASE-NOTES.md)** — Version 0.
|
|
134
|
+
- **[RELEASE-NOTES.md](./RELEASE-NOTES.md)** — Version 0.4.0 (the two-seat micro-kernel): swappable worker + orchestrator models from one config, live orchestrator seat-swap gate, IPv6/DNS hardening, scaffolding completeness
|
|
122
135
|
|
|
123
136
|
## Contributing
|
|
124
137
|
|
|
@@ -133,6 +146,8 @@ The repo develops itself via its own `/buildsystem` loop; code changes are made
|
|
|
133
146
|
|
|
134
147
|
**Source-available** under the [PolyForm Strict License 1.0.0](./LICENSE). You may read, run, and use the software for any permitted purpose, but **modification and redistribution are not permitted**. See [`LICENSE`](./LICENSE) for the full terms and the definition of permitted (noncommercial and personal) purposes.
|
|
135
148
|
|
|
149
|
+
**License history:** Aesop was released under the MIT License until 2026-07-17, when it was relicensed to PolyForm Strict 1.0.0. Snapshots cloned or forked before that date retain their original MIT license grant; new work lives under PolyForm Strict 1.0.0.
|
|
150
|
+
|
|
136
151
|
Copyright 2026 Matt Culliton.
|
|
137
152
|
|
|
138
153
|
## References
|
|
@@ -46,6 +46,22 @@
|
|
|
46
46
|
"cardinal_rules": {
|
|
47
47
|
"subagent_model": "haiku"
|
|
48
48
|
},
|
|
49
|
+
"seats": {
|
|
50
|
+
"_comment": "Unified two-seat model selection (0.4.0). ONE block swaps BOTH seats: 'worker' = the coding agents (AgentDriver), 'orchestrator' = the decision seat (OrchestratorBackend). The values below ARE the defaults -- Claude Code worker + live-harness orchestrator -- so this block as shipped changes nothing; deleting it changes nothing either. To swap a seat, replace its block with one of the _worker_examples/_orchestrator_examples. Keys are read from env vars named by api_key_env at CALL time, never stored in this file. 'is_local': true = LOOPBACK endpoint only (localhost/127.0.0.1/::1 -- rejected otherwise): no API key needed, honest verification tier 3. Separate surface: cardinal_rules.subagent_model (above) pins the model for LIVE-HARNESS Claude Code subagents; seats.worker swaps the AgentDriver worker seam itself.",
|
|
51
|
+
"worker": { "backend": "claude" },
|
|
52
|
+
"orchestrator": { "backend": "harness" },
|
|
53
|
+
"_worker_examples": {
|
|
54
|
+
"_note": "Asymmetry: worker openai-compatible seats REQUIRE base_url; the orchestrator seat may omit base_url (defaults to the hosted OpenAI endpoint).",
|
|
55
|
+
"codex_hosted_openai": { "backend": "codex", "model": "gpt-4o-mini" },
|
|
56
|
+
"openai_compatible_openrouter": { "backend": "openai-compatible", "base_url": "https://openrouter.ai/api/v1", "model": "openai/gpt-4-turbo", "api_key_env": "OPENROUTER_API_KEY" },
|
|
57
|
+
"openai_compatible_local_ollama": { "backend": "openai-compatible", "base_url": "http://localhost:11434/v1", "model": "mistral", "is_local": true }
|
|
58
|
+
},
|
|
59
|
+
"_orchestrator_examples": {
|
|
60
|
+
"harness_default": { "backend": "harness" },
|
|
61
|
+
"openai_hosted": { "backend": "openai-compatible", "model": "gpt-4o-mini", "api_key_env": "OPENAI_API_KEY" },
|
|
62
|
+
"local_ollama": { "backend": "openai-compatible", "base_url": "http://localhost:11434/v1", "model": "mistral", "is_local": true }
|
|
63
|
+
}
|
|
64
|
+
},
|
|
49
65
|
"limits": {
|
|
50
66
|
"_comment": "Cost ceiling / kill switch (tools/cost_ceiling.py, tools/halt.py). null disables a given ceiling (feature opt-in). When spend meets or exceeds a configured ceiling, cost_ceiling.py trips tools/halt.py's .HALT sentinel, which daemons/run-watchdog.sh checks at the top of every cycle and refuses to do work (no backup, no push, no scan) until cleared via 'python tools/halt.py --clear'.",
|
|
51
67
|
"max_wave_tokens": null,
|
package/bin/cli.js
CHANGED
|
@@ -259,7 +259,7 @@ const repoUrlsStr = getFlag('--repo-urls');
|
|
|
259
259
|
if (fs.existsSync(targetDir)) {
|
|
260
260
|
const contents = fs.readdirSync(targetDir);
|
|
261
261
|
// Allow .git and aesop scaffolded files to already exist (for idempotency)
|
|
262
|
-
const aesopDirs = ['daemons', 'dash', 'monitor', 'tools', 'ui', 'docs', 'state_store', 'skills', 'mcp', 'scan', 'hooks', '.git', 'state'];
|
|
262
|
+
const aesopDirs = ['daemons', 'dash', 'monitor', 'tools', 'ui', 'docs', 'state_store', 'skills', 'mcp', 'scan', 'hooks', 'driver', '.git', 'state'];
|
|
263
263
|
const aesopFiles = [
|
|
264
264
|
'aesop.config.example.json',
|
|
265
265
|
'aesop.config.json',
|
|
@@ -317,6 +317,7 @@ const filesToCopy = [
|
|
|
317
317
|
'mcp',
|
|
318
318
|
'scan',
|
|
319
319
|
'hooks',
|
|
320
|
+
'driver',
|
|
320
321
|
'aesop.config.example.json',
|
|
321
322
|
'README.md',
|
|
322
323
|
'LICENSE',
|
|
@@ -421,8 +422,10 @@ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repo
|
|
|
421
422
|
port: 8770
|
|
422
423
|
},
|
|
423
424
|
cardinal_rules: {
|
|
425
|
+
// NOTE: orchestrator_model was RETIRED in 0.4.0 (HS-1): it was written
|
|
426
|
+
// here but read by nothing. The orchestrator seat's model now lives in
|
|
427
|
+
// seats.orchestrator.model (see aesop.config.example.json).
|
|
424
428
|
subagent_model: 'haiku',
|
|
425
|
-
orchestrator_model: 'opus',
|
|
426
429
|
tdd_first: true,
|
|
427
430
|
never_push_main: true,
|
|
428
431
|
secret_scan_gates_push: true
|
|
@@ -431,7 +434,7 @@ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repo
|
|
|
431
434
|
}
|
|
432
435
|
|
|
433
436
|
// Update with provided values
|
|
434
|
-
exampleConfig.aesop_root = targetDir;
|
|
437
|
+
exampleConfig.aesop_root = path.resolve(targetDir);
|
|
435
438
|
exampleConfig.brain_root = '~/.claude';
|
|
436
439
|
exampleConfig.scripts_root = '~/scripts';
|
|
437
440
|
exampleConfig.temp_root = '~/.aesop-temp';
|
|
@@ -464,14 +467,31 @@ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repo
|
|
|
464
467
|
|
|
465
468
|
// Print next steps and optionally run watchdog (returns a Promise)
|
|
466
469
|
async function printNextStepsAndWatchdog(rl, targetDir, configPath, port) {
|
|
467
|
-
|
|
468
|
-
console.log(
|
|
469
|
-
console.log('
|
|
470
|
-
console.log(`
|
|
471
|
-
console.log('
|
|
470
|
+
const resolvedTargetDir = path.resolve(targetDir);
|
|
471
|
+
console.log('\n🎯 NEXT STEPS — Customize, validate, and launch:\n');
|
|
472
|
+
console.log('1. Customize CLAUDE.md domains and team info:');
|
|
473
|
+
console.log(` cd ${resolvedTargetDir}`);
|
|
474
|
+
console.log(' Edit CLAUDE.md — update domains, team, and project details');
|
|
475
|
+
console.log('');
|
|
476
|
+
console.log('2. Set real repository URLs in aesop.config.json:');
|
|
477
|
+
console.log(' Edit aesop.config.json — replace placeholder URLs (https://github.com/user/...) with actual repo URLs');
|
|
478
|
+
console.log('');
|
|
479
|
+
console.log('3. Copy the skills (required for orchestration):');
|
|
480
|
+
console.log(' cp ~/.claude/skills/power/SKILL.md . (verify it exists first)');
|
|
481
|
+
console.log(' cp ~/.claude/skills/buildsystem/SKILL.md . (verify it exists first)');
|
|
482
|
+
console.log('');
|
|
483
|
+
console.log('4. Run preflight checks:');
|
|
484
|
+
console.log(' aesop doctor (or: npx @matt82198/aesop doctor)');
|
|
485
|
+
console.log('');
|
|
486
|
+
console.log('5. Launch watchdog (one-time smoke test):');
|
|
487
|
+
console.log(' bash daemons/run-watchdog.sh --once');
|
|
488
|
+
console.log('');
|
|
489
|
+
console.log(`6. Launch dashboard (on localhost:${port}):`);
|
|
490
|
+
console.log(' python3 ui/serve.py (or python as fallback)\n');
|
|
491
|
+
console.log('📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
|
|
472
492
|
console.log(' mkdir -p ~/.claude/memory');
|
|
473
|
-
console.log(` cp ${
|
|
474
|
-
console.log(` cp ${
|
|
493
|
+
console.log(` cp ${resolvedTargetDir}/CLAUDE.md ~/.claude/CLAUDE.md (review and customize)`);
|
|
494
|
+
console.log(` cp ${resolvedTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)\n`);
|
|
475
495
|
|
|
476
496
|
return new Promise((resolve) => {
|
|
477
497
|
rl.question('Run watchdog --once now? (y/N): ', (answer) => {
|
|
@@ -924,38 +944,91 @@ if (!isRuntimeCommand) {
|
|
|
924
944
|
process.exit(0);
|
|
925
945
|
} else if (wizardMode) {
|
|
926
946
|
// Wizard mode with --yes flag (non-interactive)
|
|
927
|
-
|
|
928
|
-
console.log(
|
|
929
|
-
console.log('
|
|
930
|
-
console.log(`
|
|
931
|
-
console.log('
|
|
947
|
+
const resolvedFinalTargetDir = path.resolve(finalTargetDir);
|
|
948
|
+
console.log('\n🎯 NEXT STEPS — Customize, validate, and launch:\n');
|
|
949
|
+
console.log('1. Customize CLAUDE.md domains and team info:');
|
|
950
|
+
console.log(` cd ${resolvedFinalTargetDir}`);
|
|
951
|
+
console.log(' Edit CLAUDE.md — update domains, team, and project details');
|
|
952
|
+
console.log('');
|
|
953
|
+
console.log('2. Set real repository URLs in aesop.config.json:');
|
|
954
|
+
console.log(' Edit aesop.config.json — replace placeholder URLs (https://github.com/user/...) with actual repo URLs');
|
|
955
|
+
console.log('');
|
|
956
|
+
console.log('3. Copy the skills (required for orchestration):');
|
|
957
|
+
console.log(' cp ~/.claude/skills/power/SKILL.md . (verify it exists first)');
|
|
958
|
+
console.log(' cp ~/.claude/skills/buildsystem/SKILL.md . (verify it exists first)');
|
|
959
|
+
console.log('');
|
|
960
|
+
console.log('4. Run preflight checks:');
|
|
961
|
+
console.log(' aesop doctor (or: npx @matt82198/aesop doctor)');
|
|
962
|
+
console.log('');
|
|
963
|
+
console.log('5. Launch watchdog (one-time smoke test):');
|
|
964
|
+
console.log(' bash daemons/run-watchdog.sh --once');
|
|
965
|
+
console.log('');
|
|
966
|
+
console.log(`6. Launch dashboard (on localhost:${dashboardPort}):`);
|
|
967
|
+
console.log(' python3 ui/serve.py (or python as fallback)');
|
|
968
|
+
console.log('');
|
|
969
|
+
console.log('📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
|
|
932
970
|
console.log(' mkdir -p ~/.claude/memory');
|
|
933
|
-
console.log(` cp ${
|
|
934
|
-
console.log(` cp ${
|
|
971
|
+
console.log(` cp ${resolvedFinalTargetDir}/CLAUDE.md ~/.claude/CLAUDE.md (review and customize)`);
|
|
972
|
+
console.log(` cp ${resolvedFinalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
|
|
935
973
|
process.exit(0);
|
|
936
974
|
} else if (finalProjectName) {
|
|
975
|
+
const resolvedFinalTargetDir = path.resolve(finalTargetDir);
|
|
937
976
|
console.log('\n✅ Headless scaffolding complete!\n');
|
|
938
|
-
console.log('🎯
|
|
939
|
-
console.log(
|
|
940
|
-
console.log(
|
|
941
|
-
console.log(
|
|
942
|
-
console.log('
|
|
977
|
+
console.log('🎯 NEXT STEPS — Customize, validate, and launch:\n');
|
|
978
|
+
console.log('1. Customize CLAUDE.md domains and team info:');
|
|
979
|
+
console.log(` cd ${resolvedFinalTargetDir}`);
|
|
980
|
+
console.log(' Edit CLAUDE.md — update domains, team, and project details');
|
|
981
|
+
console.log('');
|
|
982
|
+
console.log('2. Set real repository URLs in aesop.config.json:');
|
|
983
|
+
console.log(' Edit aesop.config.json — replace placeholder URLs (https://github.com/user/...) with actual repo URLs');
|
|
984
|
+
console.log('');
|
|
985
|
+
console.log('3. Copy the skills (required for orchestration):');
|
|
986
|
+
console.log(' cp ~/.claude/skills/power/SKILL.md . (verify it exists first)');
|
|
987
|
+
console.log(' cp ~/.claude/skills/buildsystem/SKILL.md . (verify it exists first)');
|
|
988
|
+
console.log('');
|
|
989
|
+
console.log('4. Run preflight checks:');
|
|
990
|
+
console.log(' aesop doctor (or: npx @matt82198/aesop doctor)');
|
|
991
|
+
console.log('');
|
|
992
|
+
console.log('5. Launch watchdog (one-time smoke test):');
|
|
993
|
+
console.log(' bash daemons/run-watchdog.sh --once');
|
|
994
|
+
console.log('');
|
|
995
|
+
console.log(`6. Launch dashboard (on localhost:${dashboardPort}):`);
|
|
996
|
+
console.log(' python3 ui/serve.py (or python as fallback)');
|
|
997
|
+
console.log('');
|
|
998
|
+
console.log('📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
|
|
943
999
|
console.log(' mkdir -p ~/.claude/memory');
|
|
944
|
-
console.log(` cp ${
|
|
945
|
-
console.log(` cp ${
|
|
1000
|
+
console.log(` cp ${resolvedFinalTargetDir}/CLAUDE.md ~/.claude/CLAUDE.md (review and customize)`);
|
|
1001
|
+
console.log(` cp ${resolvedFinalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
|
|
946
1002
|
} else {
|
|
1003
|
+
const resolvedFinalTargetDir = path.resolve(finalTargetDir);
|
|
947
1004
|
console.log('\n✅ Scaffold complete!\n');
|
|
948
|
-
console.log('🎯
|
|
949
|
-
console.log(
|
|
950
|
-
console.log('
|
|
951
|
-
console.log(`
|
|
952
|
-
console.log('
|
|
953
|
-
console.log('
|
|
954
|
-
console.log('
|
|
955
|
-
console.log('
|
|
1005
|
+
console.log('🎯 NEXT STEPS — Customize, validate, and launch:\n');
|
|
1006
|
+
console.log('1. Create aesop.config.json from example:');
|
|
1007
|
+
console.log(' cp aesop.config.example.json aesop.config.json');
|
|
1008
|
+
console.log(` cd ${resolvedFinalTargetDir}`);
|
|
1009
|
+
console.log(' Edit aesop.config.json with your configuration and actual repository URLs');
|
|
1010
|
+
console.log('');
|
|
1011
|
+
console.log('2. Customize CLAUDE.md domains and team info:');
|
|
1012
|
+
console.log(' Edit CLAUDE-TEMPLATE.md and save as CLAUDE.md');
|
|
1013
|
+
console.log(' Update domains, team, and project details');
|
|
1014
|
+
console.log('');
|
|
1015
|
+
console.log('3. Copy the skills (required for orchestration):');
|
|
1016
|
+
console.log(' cp ~/.claude/skills/power/SKILL.md . (verify it exists first)');
|
|
1017
|
+
console.log(' cp ~/.claude/skills/buildsystem/SKILL.md . (verify it exists first)');
|
|
1018
|
+
console.log('');
|
|
1019
|
+
console.log('4. Run preflight checks:');
|
|
1020
|
+
console.log(' aesop doctor (or: npx @matt82198/aesop doctor)');
|
|
1021
|
+
console.log('');
|
|
1022
|
+
console.log('5. Launch watchdog (one-time smoke test):');
|
|
1023
|
+
console.log(' bash daemons/run-watchdog.sh --once');
|
|
1024
|
+
console.log('');
|
|
1025
|
+
console.log(`6. Launch dashboard (on localhost:${dashboardPort}):`);
|
|
1026
|
+
console.log(' python3 ui/serve.py (or python as fallback)');
|
|
1027
|
+
console.log('');
|
|
1028
|
+
console.log('📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
|
|
956
1029
|
console.log(' mkdir -p ~/.claude/memory');
|
|
957
|
-
console.log(` cp ${
|
|
958
|
-
console.log(` cp ${
|
|
1030
|
+
console.log(` cp ${resolvedFinalTargetDir}/CLAUDE-TEMPLATE.md ~/.claude/CLAUDE.md (then edit domains/team info)`);
|
|
1031
|
+
console.log(` cp ${resolvedFinalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
|
|
959
1032
|
}
|
|
960
1033
|
console.log('\nFor full documentation, see the README.md in the scaffolded directory.');
|
|
961
1034
|
process.exit(0);
|
package/daemons/run-watchdog.sh
CHANGED
|
@@ -228,6 +228,7 @@ main() {
|
|
|
228
228
|
if [ "$MODE" = "--once" ]; then
|
|
229
229
|
if check_halt "$AESOP_ROOT/state/FLEET-BACKUP.log"; then
|
|
230
230
|
release_lock "$LOCK_DIR"
|
|
231
|
+
printf 'WATCHDOG SMOKE: PASSED\n'
|
|
231
232
|
exit 0
|
|
232
233
|
fi
|
|
233
234
|
full_out=$("${CYCLE_CMD_ARRAY[@]}" 2>&1)
|
|
@@ -236,13 +237,16 @@ main() {
|
|
|
236
237
|
if [ $cmd_exit -ne 0 ]; then
|
|
237
238
|
err_msg="[$(date '+%F %T')] ERROR: cycle #1 failed with exit code $cmd_exit"
|
|
238
239
|
echo "$err_msg" >> "$AESOP_ROOT/state/FLEET-BACKUP.log"
|
|
239
|
-
|
|
240
|
+
printf 'WATCHDOG SMOKE: FAILED — [ERROR: exit %d]\n' "$cmd_exit" >&2
|
|
241
|
+
release_lock "$LOCK_DIR"
|
|
242
|
+
exit $cmd_exit
|
|
240
243
|
fi
|
|
241
244
|
if [ -n "$PYTHON_EXE" ]; then
|
|
242
245
|
"$PYTHON_EXE" "$AESOP_ROOT/tools/alert_bridge.py" --scan || true
|
|
243
246
|
fi
|
|
244
247
|
release_lock "$LOCK_DIR"
|
|
245
|
-
|
|
248
|
+
printf 'WATCHDOG SMOKE: PASSED\n'
|
|
249
|
+
exit 0
|
|
246
250
|
fi
|
|
247
251
|
|
|
248
252
|
n=0
|
package/docs/CONFIGURE.md
CHANGED
|
@@ -10,8 +10,8 @@ After setup, you'll have an `aesop.config.json` in your harness root. This file
|
|
|
10
10
|
|
|
11
11
|
```json
|
|
12
12
|
{
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"aesop_root": "/home/user/aesop",
|
|
14
|
+
"brain_root": "/home/user/.claude",
|
|
15
15
|
"repos": [
|
|
16
16
|
{
|
|
17
17
|
"path": "/home/user/my-api",
|
|
@@ -22,14 +22,16 @@ After setup, you'll have an `aesop.config.json` in your harness root. This file
|
|
|
22
22
|
"name": "web-frontend"
|
|
23
23
|
}
|
|
24
24
|
],
|
|
25
|
-
"
|
|
25
|
+
"dashboard": {
|
|
26
|
+
"port": 8770
|
|
27
|
+
},
|
|
26
28
|
"dashboardOrigin": "http://localhost:8770"
|
|
27
29
|
}
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
### Field Reference
|
|
31
33
|
|
|
32
|
-
#### `
|
|
34
|
+
#### `aesop_root` (string, required)
|
|
33
35
|
|
|
34
36
|
Absolute path to this Aesop harness directory. Used by daemons to locate scripts and state files.
|
|
35
37
|
|
|
@@ -39,7 +41,7 @@ Absolute path to this Aesop harness directory. Used by daemons to locate scripts
|
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
|
42
|
-
#### `
|
|
44
|
+
#### `brain_root` (string, required)
|
|
43
45
|
|
|
44
46
|
Absolute path to your Claude Code home directory. This is where skills (`.claude/skills/`) and memory (`.claude/MEMORY.md`) live.
|
|
45
47
|
|
|
@@ -78,7 +80,7 @@ Each repo object has:
|
|
|
78
80
|
|
|
79
81
|
---
|
|
80
82
|
|
|
81
|
-
#### `
|
|
83
|
+
#### `dashboard.port` (number, default: 8770)
|
|
82
84
|
|
|
83
85
|
HTTP port for the web dashboard. The dashboard runs a Python HTTP server on this port.
|
|
84
86
|
|
|
@@ -116,15 +118,17 @@ The origin (scheme + host + port) for the dashboard. Used for CORS validation an
|
|
|
116
118
|
|
|
117
119
|
```json
|
|
118
120
|
{
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
+
"aesop_root": "/home/user/aesop",
|
|
122
|
+
"brain_root": "/home/user/.claude",
|
|
121
123
|
"repos": [
|
|
122
124
|
{
|
|
123
125
|
"path": "/home/user/my-app",
|
|
124
126
|
"name": "my-app"
|
|
125
127
|
}
|
|
126
128
|
],
|
|
127
|
-
"
|
|
129
|
+
"dashboard": {
|
|
130
|
+
"port": 8770
|
|
131
|
+
},
|
|
128
132
|
"dashboardOrigin": "http://localhost:8770"
|
|
129
133
|
}
|
|
130
134
|
```
|
|
@@ -133,8 +137,8 @@ The origin (scheme + host + port) for the dashboard. Used for CORS validation an
|
|
|
133
137
|
|
|
134
138
|
```json
|
|
135
139
|
{
|
|
136
|
-
"
|
|
137
|
-
"
|
|
140
|
+
"aesop_root": "/home/user/aesop",
|
|
141
|
+
"brain_root": "/home/user/.claude",
|
|
138
142
|
"repos": [
|
|
139
143
|
{
|
|
140
144
|
"path": "/home/user/services/auth",
|
|
@@ -153,7 +157,9 @@ The origin (scheme + host + port) for the dashboard. Used for CORS validation an
|
|
|
153
157
|
"name": "infrastructure"
|
|
154
158
|
}
|
|
155
159
|
],
|
|
156
|
-
"
|
|
160
|
+
"dashboard": {
|
|
161
|
+
"port": 8770
|
|
162
|
+
},
|
|
157
163
|
"dashboardOrigin": "http://localhost:8770"
|
|
158
164
|
}
|
|
159
165
|
```
|
|
@@ -162,15 +168,17 @@ The origin (scheme + host + port) for the dashboard. Used for CORS validation an
|
|
|
162
168
|
|
|
163
169
|
```json
|
|
164
170
|
{
|
|
165
|
-
"
|
|
166
|
-
"
|
|
171
|
+
"aesop_root": "C:\\Users\\user\\aesop",
|
|
172
|
+
"brain_root": "C:\\Users\\user\\.claude",
|
|
167
173
|
"repos": [
|
|
168
174
|
{
|
|
169
175
|
"path": "C:\\Users\\user\\projects\\my-api",
|
|
170
176
|
"name": "api"
|
|
171
177
|
}
|
|
172
178
|
],
|
|
173
|
-
"
|
|
179
|
+
"dashboard": {
|
|
180
|
+
"port": 8770
|
|
181
|
+
},
|
|
174
182
|
"dashboardOrigin": "http://localhost:8770"
|
|
175
183
|
}
|
|
176
184
|
```
|
|
@@ -205,14 +213,17 @@ Aesop credentials (GitHub tokens, API keys) should never go in `aesop.config.jso
|
|
|
205
213
|
You can override config values via environment variables (optional):
|
|
206
214
|
|
|
207
215
|
```bash
|
|
208
|
-
# Override the Aesop root
|
|
216
|
+
# Override the Aesop root (used by daemons)
|
|
209
217
|
export AESOP_ROOT=/path/to/aesop
|
|
210
218
|
|
|
211
|
-
# Override the
|
|
212
|
-
export
|
|
219
|
+
# Override the Aesop state directory (default: ./state)
|
|
220
|
+
export AESOP_STATE_ROOT=/path/to/state
|
|
221
|
+
|
|
222
|
+
# Override the Claude Code home (used by /power skill and orchestrator)
|
|
223
|
+
export BRAIN_ROOT=/path/to/.claude
|
|
213
224
|
|
|
214
|
-
#
|
|
215
|
-
export
|
|
225
|
+
# Override the scripts directory
|
|
226
|
+
export SCRIPTS_ROOT=/path/to/scripts
|
|
216
227
|
```
|
|
217
228
|
|
|
218
229
|
If set, these override the values in `aesop.config.json`.
|
package/docs/FIRST-WAVE.md
CHANGED
|
@@ -47,19 +47,39 @@ This tells you the orchestrator is ready.
|
|
|
47
47
|
|
|
48
48
|
Before running a wave, you need ranked work. The orchestrator needs to know what to build.
|
|
49
49
|
|
|
50
|
-
###
|
|
50
|
+
### Where your backlog lives
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Create a `state/BACKLOG.md` file (or update the backlog section in `state/STATE.md`). Use this markdown format:
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
```markdown
|
|
55
|
+
# Wave 15 Backlog
|
|
56
|
+
|
|
57
|
+
## P1: Critical
|
|
58
|
+
|
|
59
|
+
- [ ] Fix secret-scan gate hang (blocking CI) — backend-dev — 5min
|
|
60
|
+
- [ ] Update MEMORY.md with wave-15 learnings — docs-agent — 3min
|
|
61
|
+
|
|
62
|
+
## P2: Features
|
|
63
|
+
|
|
64
|
+
- [ ] Add cost-ceiling dashboard widget — frontend-dev — 8min
|
|
65
|
+
- [ ] Implement fleet-ops monitoring — backend-dev — 10min
|
|
66
|
+
|
|
67
|
+
## P3: Tech Debt
|
|
68
|
+
|
|
69
|
+
- [ ] Refactor monitor/collect-signals.mjs (duplicate checks) — backend-dev — 15min
|
|
70
|
+
- [ ] Add type hints to Python tools — test-bot — 10min
|
|
60
71
|
```
|
|
61
72
|
|
|
62
|
-
**Backlog
|
|
73
|
+
**Backlog format**:
|
|
74
|
+
- **Sections**: Group by priority (P1/P2/P3)
|
|
75
|
+
- **Items**: Checkbox (`[ ]`) + title + agent type + time estimate
|
|
76
|
+
- **Sizing guide**:
|
|
77
|
+
- **3–5 min**: Typo fix, simple config change, one-line refactor
|
|
78
|
+
- **5–10 min**: New function, small feature, unit test
|
|
79
|
+
- **10–15 min**: Module refactor, feature with 2–3 functions
|
|
80
|
+
- **15+ min**: Split into smaller items (waves work best in 30–90 min total)
|
|
81
|
+
|
|
82
|
+
### Backlog principles
|
|
63
83
|
|
|
64
84
|
- **Sized for Haiku**: Each task should take 1 Haiku agent 3–10 minutes (not 30 minutes)
|
|
65
85
|
- **Scoped**: "Fix auth timeout" is better than "Refactor auth system"
|