@matt82198/aesop 0.1.0-rc.1 → 0.2.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +101 -2
  2. package/README.md +66 -15
  3. package/bin/cli.js +164 -41
  4. package/daemons/run-watchdog.sh +16 -4
  5. package/daemons/selfheal.sh +231 -0
  6. package/docs/ANY-REPO.md +427 -0
  7. package/docs/CONTRIBUTING.md +72 -0
  8. package/docs/DEMO.md +334 -0
  9. package/docs/INSTALL.md +70 -1
  10. package/docs/QUICKSTART.md +80 -0
  11. package/docs/README.md +33 -3
  12. package/docs/TEAM-STATE.md +540 -0
  13. package/driver/CLAUDE.md +148 -0
  14. package/driver/README.md +383 -0
  15. package/driver/aesop.config.example.json +80 -0
  16. package/driver/agent_driver.py +355 -0
  17. package/driver/backend_config.py +253 -0
  18. package/driver/claude_code_driver.py +198 -0
  19. package/driver/codex_driver.py +626 -0
  20. package/driver/openai_compatible_driver.py +249 -0
  21. package/driver/openai_transport.py +146 -0
  22. package/driver/verification_policy.py +75 -0
  23. package/driver/wave_bridge.py +246 -0
  24. package/driver/wave_loop.py +1041 -0
  25. package/hooks/pre-push-policy.sh +109 -28
  26. package/mcp/server.mjs +320 -4
  27. package/package.json +23 -15
  28. package/skills/CLAUDE.md +132 -2
  29. package/skills/buildsystem/SKILL.md +330 -0
  30. package/skills/buildsystem/wave-flat-dispatch.template.mjs +658 -0
  31. package/skills/fleet/SKILL.md +113 -0
  32. package/skills/power/SKILL.md +246 -131
  33. package/state_store/__init__.py +2 -1
  34. package/state_store/api.py +19 -4
  35. package/state_store/coordination.py +209 -0
  36. package/state_store/identity.py +51 -0
  37. package/state_store/store.py +185 -73
  38. package/templates/wave-presets/data.json +65 -0
  39. package/templates/wave-presets/library.json +65 -0
  40. package/templates/wave-presets/saas.json +64 -0
  41. package/tools/audit_report.py +388 -0
  42. package/tools/bench_runner.py +100 -3
  43. package/tools/ci_merge_wait.py +256 -35
  44. package/tools/ci_workflow_lint.py +430 -0
  45. package/tools/claudemd_drift.py +394 -0
  46. package/tools/claudemd_lint.py +359 -0
  47. package/tools/common.py +39 -3
  48. package/tools/cost_ceiling.py +63 -31
  49. package/tools/cost_econ.py +480 -0
  50. package/tools/defect_escape.py +252 -0
  51. package/tools/doctor.js +1 -1
  52. package/tools/eod_sweep.py +58 -0
  53. package/tools/fleet.js +260 -0
  54. package/tools/fleet_ledger.py +209 -7
  55. package/tools/git_identity_check.py +315 -0
  56. package/tools/health-score.js +40 -0
  57. package/tools/health_score.py +361 -0
  58. package/tools/metrics_gate.py +13 -4
  59. package/tools/mutation_test.py +401 -0
  60. package/tools/portability_check.py +206 -0
  61. package/tools/reconcile.py +7 -4
  62. package/tools/secret_scan.py +137 -50
  63. package/tools/self_stats.py +20 -0
  64. package/tools/transcript_digest.py +380 -0
  65. package/tools/verify_activity_filter.py +437 -0
  66. package/tools/verify_agent_inspector.py +2 -0
  67. package/tools/verify_dash.py +2 -0
  68. package/tools/verify_dispatch_panel.py +301 -0
  69. package/tools/verify_failure_drilldown.py +188 -0
  70. package/tools/verify_prboard.py +2 -0
  71. package/tools/verify_scorecards.py +281 -0
  72. package/tools/verify_submit_encoding.py +2 -0
  73. package/tools/verify_ui_trio.py +409 -0
  74. package/tools/verify_wave_telemetry.py +268 -0
  75. package/tools/wave_backlog_analyzer.py +490 -0
  76. package/tools/wave_ledger_hook.py +150 -0
  77. package/tools/wave_preflight.py +512 -0
  78. package/tools/wave_resume.py +215 -0
  79. package/tools/wave_templates.py +215 -0
  80. package/ui/agents.py +68 -14
  81. package/ui/collectors.py +0 -55
  82. package/ui/config.py +7 -2
  83. package/ui/cost.py +231 -12
  84. package/ui/handler.py +183 -0
  85. package/ui/quality_scorecard.py +232 -0
  86. package/ui/wave_audit_tail.py +213 -0
  87. package/ui/wave_dispatch.py +280 -0
  88. package/ui/wave_failure.py +288 -0
  89. package/ui/wave_gantt.py +152 -0
  90. package/ui/wave_reasoning_tail.py +176 -0
  91. package/ui/wave_telemetry.py +377 -0
  92. package/ui/web/dist/assets/index-BGbgw2Nh.js +9 -0
  93. package/ui/web/dist/assets/index-DqZLgwNg.css +1 -0
  94. package/ui/web/dist/index.html +2 -2
  95. package/bin/CLAUDE.md +0 -76
  96. package/daemons/CLAUDE.md +0 -36
  97. package/dash/CLAUDE.md +0 -32
  98. package/docs/archive/README.md +0 -3
  99. package/docs/archive/spikes/tiered-cognition/ACTIVATION.md +0 -125
  100. package/docs/archive/spikes/tiered-cognition/DESIGN.md +0 -287
  101. package/docs/archive/spikes/tiered-cognition/FINDINGS.md +0 -113
  102. package/docs/archive/spikes/tiered-cognition/README.md +0 -27
  103. package/docs/archive/spikes/tiered-cognition/aesop-cognition.example.md +0 -32
  104. package/docs/archive/spikes/tiered-cognition/force-model-policy.merged.mjs +0 -673
  105. package/docs/archive/spikes/tiered-cognition/strip-tools-hook.mjs +0 -434
  106. package/hooks/CLAUDE.md +0 -89
  107. package/mcp/CLAUDE.md +0 -213
  108. package/monitor/CLAUDE.md +0 -40
  109. package/scan/CLAUDE.md +0 -30
  110. package/state_store/CLAUDE.md +0 -39
  111. package/tools/CLAUDE.md +0 -79
  112. package/ui/CLAUDE.md +0 -127
  113. package/ui/web/dist/assets/index-0qQYnvMC.js +0 -9
  114. package/ui/web/dist/assets/index-BdIlFieV.css +0 -1
package/CHANGELOG.md CHANGED
@@ -5,7 +5,106 @@ All notable changes to Aesop are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [0.2.0] - 2026-07-21
9
+
10
+ Minor release shipping multi-model orchestration portability and adaptive verification safety.
11
+
12
+ ### Added
13
+ - **AgentDriver Phase 1-3 shipping** (wave-32+): Complete multi-model driver abstraction with three production drivers — Claude Code reference adapter, OpenAI-compatible backend (Ollama, OpenRouter, etc.), and Phase 3 wave bridge enabling any backend to drive coding tasks end-to-end with verified-honest verification tiers.
14
+ - **Multi-instance identity & coordination** (wave-32): Instance ID tagging (hostname:pid:nonce) and lease-by-append claims enable multi-writer coordination without collisions (fail-closed). Foundation for team-scale Aesop.
15
+ - **Honest verification-tier wiring** (wave-32): Weaker backends automatically trigger higher verification (tier 2→tier 4) — no code changes required; orchestrator transparently adapts rigor based on driver capabilities.
16
+ - **OpenAI-compatible backend configuration** (wave-32): `aesop.config.json` backend section configures model, base_url, and API key for local Ollama or OpenRouter inference.
17
+ - **Cost-ceiling enforcement** (wave-32): Per-wave spend ceiling enforced at dispatch time; blocks work if budget exceeded.
18
+ - **Transcript-sampled benchmark Phase 1** (wave-32): Infrastructure to extract coding tasks from real Claude Code session transcripts, enabling dynamic benchmark growth beyond hand-written examples.
19
+ - **Backend config & role resolution** (wave-32): `backend_config.py` for per-deployment model mappings (worker/setup/verify roles) without orchestrator changes.
20
+
21
+ ### Changed
22
+ - **Verification policy transparent** (wave-32): Verification tiers now driven by `AgentDriver.probe_capabilities()` — config-free, capability-driven safety.
23
+
24
+ ### Fixed
25
+ - **Authorization header cross-origin stripping** (PR #221): Blocks Authorization headers on cross-origin redirects to prevent credential leakage; security hardening for urllib transport.
26
+ - **Secret-scan fail-closed on read errors** (PR #226): `secret_scan.py` now fails CLOSED when unable to read files or git data, blocking pushes instead of silently passing; P1 security.
27
+ - **Driver subsystem in npm package** (PR #220): Multi-model AgentDriver backend abstraction now ships in the npm package, enabling production use of alternative backends.
28
+ - **CI/publish Node version parity** (PR #225): Unified Node.js version across CI and npm publish workflows for reproducible builds.
29
+ - **Adversarial-review safety fixes** (wave-32): Multiple orchestration loop hardening fixes identified and validated by external review (agent-grading-agent risks eliminated).
30
+
31
+ ### Security & Hardening (Post-Release Fixes)
32
+
33
+ Critical hardening round integrated after 0.2.0 release-artifact preparation (fe6bb04, 2026-07-21):
34
+
35
+ **AI & Prompt Security:**
36
+ - **Codex prompt-injection hardening** (fix/codex-prompt-injection): JSON-wrapped framing prevents prompt injection in orchestration context; multi-layer escaping for task/dispatch boundaries (P1 AI-security).
37
+ - **Codex frame integrity** (fix/codex-frame-integrity): SHA-256 digest + retry nudge for frame integrity verification across API boundaries; prevents frame corruption from in-flight mutations.
38
+ - **Codex path containment** (fix/codex-driver-path-containment): Cross-platform path normalization (Windows: `resolve()` + `commonpath()`, Unix: realpath) blocks directory traversal in task file operations (P2 security).
39
+ - **Codex escape-accounting** (fix/codex-prompt-injection): Measure `max_owned_bytes` post-escape to detect prompt-injection breakout payloads (P1 AI-security).
40
+
41
+ **System & Daemon Hardening:**
42
+ - **Daemon fail-closed on lock errors** (fix/daemons-lock-portability): Pre-push and coordination daemons now fail CLOSED on file-write errors, lock-acquisition timeout, or heartbeat stalls; prevents silently-skipped enforcements. CONDUCTOR_ROOT portability (Windows/Unix path handling).
43
+
44
+ **Data & Audit Security:**
45
+ - **Audit log JSON escaping** (fix/audit-log-repo-escape): Escape `repo_name` and payload fields in audit-log JSON emits to prevent injection attacks on durable audit trail (P1 security).
46
+ - **Audit-tail verdict fix** (fix/audit-tail-verdict): Correct column index in wave_audit_tail.py verdict parsing and add validation whitelist to prevent misclassified wave outcomes.
47
+
48
+ **Transcript & Observability Hardening:**
49
+ - **Redaction-proof transcript digest** (verify_ui_trio.py): Single-source redaction patterns (`transcript_digest.py`) ensure sensitive data (API keys, internal tokens, paths) are consistently masked across all observability exports — dashboard, audit, and external integrations.
50
+
51
+ **Pre-Push & CI Hardening:**
52
+ - **Pre-push delete-refspec hardening** (fix/prepush-delete-refspecs): Enforce branch-protection policy on force-delete and fast-forward-only mutations; prevent refspec conflicts from stalling the merge train.
53
+ - **Empty-stdin handling** (fix/prepush-delete-refspecs): Guard pre-push hook against stalled CI merge-wait (empty stdin → timeout → fail-closed block).
54
+ - **Cost-ceiling fail-closed** (fix/cost_ceiling): Per-wave spend ceiling now enforced at dispatch time; fails CLOSED on file/git read errors. **Caveat:** Enforced at every dispatch gate on ALL backends: drivers reporting live token spend are metered directly; drivers that cannot observe per-instance spend (the Claude Code reference driver, by honest contract) return None and the ceiling reads the outcomes ledger itself with proper period windowing.
55
+
56
+ ### Documentation
57
+ - **Multi-model configuration guide** (wave-32): docs/INSTALL.md now includes "Using Non-Claude Backends" section with Ollama example, verification-tier table, and troubleshooting.
58
+ - **Driver domain map complete** (wave-32): driver/CLAUDE.md now lists all Files (openai_compatible_driver.py, backend_config.py) with descriptions for one-file-per-domain rule.
59
+ - **State_store coordination modules** (wave-32): state_store/CLAUDE.md Module Layout now includes coordination.py and identity.py.
60
+
61
+ ## [0.1.1] - 2026-07-17
62
+
63
+ Patch release with first-hour adopter fixes, orchestration performance improvements, and observability enhancements. Targets users deploying 0.1.0 to production and the fleet during active wave execution.
64
+
65
+ ### Adopter / First-hour Fixes
66
+ - **Git init + --no-git scaffold flag** (wave-rc6): New `--no-git` scaffolder option for adopters integrating into existing repos without re-initializing version control.
67
+ - **Port conflict detection** (wave-rc6): CLI and doctor now detect and report port-binding conflicts before dashboard startup; helpful error messages with conflict resolution steps.
68
+ - **Next-steps ordering** (wave-rc5): Orchestration template ordering fixed so next-steps appear after state blocks, improving readability for first runs.
69
+ - **Aesop doctor subcommand** (wave-rc4): New preflight check validates configuration, hooks, state store health, and port availability before wave startup.
70
+ - **Executable bits in tarball** (wave-rc4): Vendored dispatch template + scripts now ship with correct execution bits set (CLI was inventing a standalone validator; real one now included).
71
+
72
+ ### Orchestration / Performance
73
+ - **Wave-dispatch template latency** (wave-rc5): Targeted performance repairs — self-check parallelization, postBuild hooks, multi-testCmd batching for faster feedback cycles.
74
+ - **Wave preflight validator** (wave-rc5): New structural validation before dispatch prevents malformed config from blocking the build.
75
+ - **CI merge-wait fail-closed** (wave-rc3): `ci_merge_wait` timeout now blocks dispatch (fail-closed) instead of silently passing; prevents merging while CI is still running.
76
+
77
+ ### Observability / Instrumentation
78
+ - **OUTCOMES-LEDGER producer** (wave-rc5): Append-wave ledger tracks per-wave execution outcomes (dispatch time, wave duration, merge timing) for fleet analytics.
79
+ - **CI workflow linter** (wave-rc5): New `tools/ci_workflow_lint.py` statically validates GitHub Actions YAML (npm-ci lockfile presence, every package.json test script is invoked, file references resolve) — catches the green-means-never-ran class.
80
+ - **Failure drilldown** (wave-rc3): Enhanced error reporting in dashboard drill-down view — inspect failure reasons, cost metrics, and agent transcript timestamps per-incident.
81
+ - **Cost-economics dashboard** (wave-rc4): Wave-level cost analytics with model breakdown, per-day bar chart (pure SVG), verdict scorecard (success/failure/hung rates), pricing estimates from config.
82
+ - **MCP cost tools** (wave-rc3): New read-only MCP cost-ledger and cost-ceiling tools expose spend tracking for external Claude integrations.
83
+ - **Transcript digest + claudemd_lint** (wave-rc6-obs): New tools/artifact for post-wave transcript summarization and CLAUDE.md scope linting (3-line max per section, enforcement on drift).
84
+
85
+ ### Security & Reliability
86
+ - **Gitignore-respecting secret scan** (wave-rc5): `secret_scan.py` now respects `.gitignore` patterns; skips ephemeral runtime files (state/, .env files, node_modules traces) to reduce false positives and scan time.
87
+ - **Aesop fleet CLI** (wave-rc3): New `aesop fleet` subcommand suite for production fleet inspection (list agents, query costs, export telemetry).
88
+
89
+ ### Documentation & Portability
90
+ - **ANY-REPO portability** (wave-rc4): Aesop now scaffolds into any existing Node/Python repo; setup guides, CONTRIBUTING.md, GitHub issue templates (SECURITY.md, CODE_OF_CONDUCT) included.
91
+ - **Domain CLAUDE.md minification** (wave-rc6): All domain-specific documentation scoped to one file per Haiku task; root CLAUDE.md now a pure map for faster load and maintenance.
92
+ - **CONTRIBUTING guide** (wave-rc6): Contributor workflow, test running, release process, branching discipline documented with examples.
93
+
94
+ ### Tests
95
+ - **Full gate green** (all waves): npm run test:py && test:node + all shell suites + secret-scan pass without signature warnings.
96
+
97
+ ## [0.1.0] - 2026-07-17
98
+
99
+ First stable release. This is the graduation of `0.1.0-rc.1` to a stable version with the
100
+ same feature set — no code changes beyond the version/documentation promotion. It publishes to
101
+ npm under the `latest` dist-tag. Highlights carried from rc.1: verified Opus audit (0
102
+ hallucinated findings), kill-switch wired into the live dispatch path, cost-ceiling guardrail,
103
+ a measured held-out benchmark (39 judgment tasks, Haiku on par with Opus at ~1/3 the cost),
104
+ the state-reconcile primitive, browser-proven dashboard views (Wave PR Board + Agent
105
+ Inspector), a source-available license, and a slim, reproducible ~409 kB npm package. See the
106
+ [0.1.0-rc.1] entry below for the full itemized list, and RELEASE-NOTES.md for the honest-limits
107
+ account (small-N benchmark, cost-ceiling not yet tied to live token spend, local-first).
9
108
 
10
109
  ## [0.1.0-rc.1] - 2026-07-17
11
110
 
@@ -239,7 +338,7 @@ package ships slim and reproducible from a clean clone.
239
338
 
240
339
  ## Initial Release
241
340
 
242
- This is the first public release of Aesop, a clean-room open-source implementation of the fable-fleet orchestration harness. The codebase includes:
341
+ This is the first public release of Aesop, a clean-room source-available implementation of the fable-fleet orchestration harness. The codebase includes:
243
342
 
244
343
  - The complete orchestration engine with watchdog and monitor
245
344
  - Web dashboard for fleet observability
package/README.md CHANGED
@@ -3,22 +3,24 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <em>Fable-Fleet Orchestration Harness</em>
6
+ <em>Autonomous Developer for Any Repository</em>
7
7
  </p>
8
8
 
9
9
  <p align="center">
10
10
  <a href="https://github.com/matt82198/aesop/actions/workflows/ci.yml"><img src="https://github.com/matt82198/aesop/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
11
- <a href="https://www.npmjs.com/package/@matt82198/aesop"><img src="https://img.shields.io/npm/v/@matt82198/aesop/rc" alt="npm"></a>
11
+ <a href="https://www.npmjs.com/package/@matt82198/aesop"><img src="https://img.shields.io/npm/v/@matt82198/aesop" alt="npm"></a>
12
12
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-PolyForm%20Strict%201.0.0-orange.svg" alt="License: PolyForm Strict 1.0.0 (source-available)"></a>
13
13
  </p>
14
14
 
15
- **Aesop** is a source-available orchestration harness for Claude Code that builds itself. It runs a `/buildsystem` wave cycle—ranking a backlog, fanning out parallel Haiku agents (1/3 the cost of Sonnet, 1/5 the cost of Opus), watchdogging them, verifying merges, then feeding the next wave via audit + ideation + fleet-ops monitoring. **This repo's own PRs are built by Aesop's own loop.** Dogfooding, not doctrine.
15
+ **Aesop** is a source-available autonomous developer that crawls into any repository and orchestrates intelligent work—**ranking tasks, dispatching parallel Haiku agents, verifying merges, auditing the work, and feeding the next iteration.**
16
16
 
17
- As of **0.1.0-rc.1**, that loop has carried the project to an installable, tested, audited, and benchmarked release candidate—the fleet running the wave loop on its own, under a human who sets goals and owns the outward gates. The claims below are backed by committed artifacts you can check, not adjectives. See [Milestone: it shipped itself](#milestone-it-shipped-itself-010-rc1).
17
+ What makes Aesop different: **durable state persists across multiple instances**, so your whole team uses one coordinated system. The state layer (`state_store/`) runs append-only events in SQLite (concurrent, transactional), rendered to git for checkpoints and hand-offs. Pair with [/power](#use-with-claude-code) (system init) and [/buildsystem](#core-concepts-and-operations) (the wave loop), and Aesop runs your delivery cycle—on any repository, any codebase shape, indefinitely. **This repo's own PRs are built by Aesop's own loop.** Dogfooding, not doctrine.
18
18
 
19
- What you get: **cost-optimized multi-agent dispatch** (Haiku-first subagents, lean orchestrator), **durable state** (git-committed checkpoints survive wipes), **observable machinery** (every agent run logged, every cost tracked), **live dashboard** (real-time fleet health at http://localhost:8770), and **security gates** (secret-scan blocks pushes, CI validates each merge).
19
+ As of **0.1.0**, that loop has carried the project to an installable, tested, audited, and benchmarked stable release—the fleet running the wave loop on its own, under a human who sets goals and owns the outward gates. The claims below are backed by committed artifacts you can check, not adjectives. See [Milestone: it shipped itself](#milestone-it-shipped-itself-010).
20
20
 
21
- ## Milestone: it shipped itself (0.1.0-rc.1)
21
+ **Cost-optimized multi-agent dispatch** (Haiku-first subagents, lean orchestrator) · **Durable state** (SQLite events + git exports, survives wipes) · **Observable machinery** (every agent run logged, every cost tracked) · **Live dashboard** (real-time fleet health at http://localhost:8770) · **Security gates** (secret-scan blocks pushes, CI validates each merge).
22
+
23
+ ## Milestone: it shipped itself (0.1.0)
22
24
 
23
25
  Aesop reached its first release candidate by running its own wave loop—**audit → parallel build → verify → merge-train**—across the backlog that produced it. This is the version where the load-bearing claims stopped being illustrations and became measurements. The word "autonomous" has a precise, deliberately narrow meaning here.
24
26
 
@@ -36,9 +38,49 @@ The differentiator is not "an AI wrote code." It's that the credibility and safe
36
38
 
37
39
  **Nobody outside this project has reproduced these results yet.** The evidence is committed so a skeptical reader can check it — that transparency is the point, not a substitute for independent replication. For the full, unhedged account of what is and isn't proven, read [docs/autonomous-swe.md](./docs/autonomous-swe.md) and the ["Honest limits" section of the release notes](./RELEASE-NOTES.md#honest-limits).
38
40
 
41
+ ## Core Concepts and Operations
42
+
43
+ ### What /power Does
44
+
45
+ `/power` initializes Aesop into a fresh repository. It:
46
+ - Loads your orchestrator brain (cardinal rules, domain map, team memory, system state)
47
+ - Verifies the system is healthy (filesystem, git, API keys, watchdog)
48
+ - Outputs a health brief and next-step recommendations
49
+
50
+ Run `/power` at the start of each session when using Claude Code. It's idempotent—safe to run multiple times. Setup once:
51
+
52
+ ```bash
53
+ cp -r skills/power/ ~/.claude/skills/power/
54
+ ```
55
+
56
+ Then in Claude Code, type `/power` to initialize.
57
+
58
+ ### What /buildsystem Does
59
+
60
+ `/buildsystem` runs **one complete wave cycle** of the autonomous delivery loop. It:
61
+ 1. **Ranks** the backlog (priority, dependencies, team affinity)
62
+ 2. **Dispatches** parallel Haiku agents on file-disjoint domains (tests, build, docs, UI, review, etc.)
63
+ 3. **Verifies** each merge (CI, security scans, audit spot-checks)
64
+ 4. **Checkpoints** (STATE.md + BUILDLOG.md committed to git, survive wipes)
65
+ 5. **Audits** fleet health and feeds next backlog (monitor signals, signal collectors, findings)
66
+
67
+ This is **not** a one-off fix or a single pass—it's the repeatable loop that runs your delivery cycle indefinitely, with each wave learning from the prior audit. You can run `/buildsystem` once per wave (typically 30 min–2 hours per wave depending on backlog size and scope).
68
+
69
+ See [docs/HOW-THE-LOOP-WORKS.md](./docs/HOW-THE-LOOP-WORKS.md) for a concrete walkthrough of one complete cycle.
70
+
71
+ ### Team State & Multi-Instance Vision
72
+
73
+ **Current Status (0.1.0)**: Single-instance proven. A team uses Aesop by designating one operator who runs the wave loop. State is durably checkpointed in git (STATE.md, BUILDLOG.md, tracker.json exports).
74
+
75
+ **In Design**: Multi-instance coordination via the state_store substrate. The event-sourced SQLite layer (`state_store/`) is production-ready but currently opt-in. A future release will enable multiple Aesop instances (e.g., per-team subgroups, geographic regions, or specialized fleets) to coordinate around a single source of truth—a Postgres-backed event log, with git as a diffable export. See [docs/TEAM-STATE.md](./docs/TEAM-STATE.md) (design in progress) for the vision and current architecture decisions.
76
+
39
77
  ## Why Aesop?
40
78
 
41
- Multi-agent AI fleets hit a wall: all-Opus orchestrators cost $10k+ per wave, and machine crashes lose state—losing work and context on restart. Aesop solves both: **Haiku-first** dispatch cuts costs to 1/3 of Opus, and **git-committed state** (STATE.md, BUILDLOG.md) survives machine wipes with zero data loss. See the wave cycle below: ranked backlog → parallel worktree-isolated fleet → merge train → checkpoint → audit feeds next wave.
79
+ Multi-agent AI fleets hit two walls: all-Opus orchestrators cost $10k+ per wave, and machine crashes lose state—losing work and context on restart. Aesop solves both:
80
+
81
+ - **Haiku-first dispatch** cuts costs to ~1/3 of Opus (Haiku subagents, Opus orchestrator).
82
+ - **Durable state** (SQLite event log + git-rendered exports) survives machine wipes with zero data loss and enables team/multi-instance coordination.
83
+ - **Portable orchestration** works on any repository; no custom agents per repo needed.
42
84
 
43
85
  ```
44
86
  ranked backlog
@@ -66,16 +108,18 @@ audit + fleet-ops monitoring
66
108
  - **Live web dashboard** — Real-time fleet health, security alerts, work-item kanban at `http://localhost:8770`.
67
109
  - **Secret-scan gates** — Pre-push hook blocks leaks; audit trail logged. Pair with GitHub branch protection for enforcement.
68
110
  - **Read-only MCP Fleet Server** — Expose fleet status, active agents, work items, and cost metrics to Claude Code (fleet_status, fleet_agents, fleet_tracker, fleet_cost tools). See [mcp/CLAUDE.md](./mcp/CLAUDE.md) for setup.
111
+ - **Multi-model portability** — AgentDriver abstraction decouples the wave loop from Claude Code; drivers for Claude Code, OpenAI-compatible backends (Ollama, OpenRouter), and Codex. Honest verification tiers: weaker backends get more checking. See [driver/README.md](./driver/README.md).
69
112
  - **Self-diagnosing npm publish** — OIDC token generation and publish reliability verified on each release; workflow surfaces diagnostics inline.
113
+ - **Verification & quality tooling** — mutation_test.py for test-quality assessment, defect_escape.py for first-try-green telemetry, held-out benchmark for robustness, and adversarial review to break and harden the orchestration loop.
70
114
 
71
115
  ## Get Started (3 steps, 5 min)
72
116
 
73
- **Note:** Aesop is at its first release candidate. Install the `@rc` tag for the latest prerelease (v0.1.0-rc.1); the `@beta` tag remains available for earlier prereleases.
117
+ **Note:** Aesop's first stable release is `0.1.0`, published to npm under the `latest` tag a plain `npx @matt82198/aesop` or `npm install @matt82198/aesop` pulls it. Earlier prereleases remain available under the `@rc` and `@beta` tags.
74
118
 
75
119
  ### Quickest path: npx scaffold
76
120
 
77
121
  ```bash
78
- npx @matt82198/aesop@rc my-fleet \
122
+ npx @matt82198/aesop my-fleet \
79
123
  --name "my-api" \
80
124
  --repos "/path/to/repo1,/path/to/repo2"
81
125
  cd my-fleet
@@ -130,17 +174,23 @@ Aesop is built entirely by its own `/buildsystem` wave cycle—running parallel
130
174
 
131
175
  | Metric | Value |
132
176
  | --- | --- |
133
- | Merged PRs | 170 <!-- metrics-verified: self_stats.py (git log) --> |
134
- | Total Commits | 556 <!-- metrics-verified: self_stats.py (git log) --> |
135
- | Project Age | 5 days <!-- metrics-verified: self_stats.py (git log) --> |
177
+ | Merged PRs | 223 <!-- metrics-verified: self_stats.py (git log) --> |
178
+ | Total Commits | 880 <!-- metrics-verified: self_stats.py (git log) --> |
179
+ | Project Age | 10 days <!-- metrics-verified: self_stats.py (git log) --> |
136
180
  | Waves | 30 <!-- metrics-verified: self_stats.py (git log) --> |
137
- | Insertions + Deletions | 96,065 <!-- metrics-verified: self_stats.py (git log) --> |
138
- | Files Tracked | 336 <!-- metrics-verified: self_stats.py (git log) --> |
181
+ | Insertions + Deletions | 161,064 <!-- metrics-verified: self_stats.py (git log) --> |
182
+ | Files Tracked | 500 <!-- metrics-verified: self_stats.py (git log) --> |
139
183
  | Distinct Co-authors | 9 <!-- metrics-verified: self_stats.py (git log) --> |
140
184
 
141
185
  <!-- STATS:END -->
142
186
 
143
187
 
188
+
189
+
190
+
191
+
192
+
193
+
144
194
  ## Recommended Agents
145
195
 
146
196
  Aesop pairs well with the open-source catalog of ~130 community-authored specialized agent definitions (TDD orchestrators, security reviewers, performance engineers, etc.). For optimal results, install agents from the upstream source and pair them with Aesop's cost-optimized Haiku dispatch. This is optional; Aesop works standalone with general-purpose Claude Code agents.
@@ -269,6 +319,7 @@ The dev server proxies `/data`, `/api`, `/events`, `/agent`, `/submit` to the Py
269
319
  - [docs/PUBLISHING.md](./docs/PUBLISHING.md) — Release Aesop to npm
270
320
  - [docs/autonomous-swe.md](./docs/autonomous-swe.md) — The 0.1.0-rc.1 milestone told honestly: what "autonomous SWE" means here, the evidence behind each claim, and the limits the project owns
271
321
  - [docs/case-study-portfolio.md](./docs/case-study-portfolio.md) — How Aesop built its own portfolio site; full audit trail and cost breakdown
322
+ - [docs/TEAM-STATE.md](./docs/TEAM-STATE.md) — Multi-instance and team coordination via state_store (design in progress)
272
323
 
273
324
  See [CHANGELOG.md](./CHANGELOG.md) and [RELEASE-NOTES.md](./RELEASE-NOTES.md) for release notes.
274
325
 
@@ -295,4 +346,4 @@ Copyright 2026 Matt Culliton.
295
346
 
296
347
  ---
297
348
 
298
- **Aesop**: Fable-fleet orchestration, built by Aesop itself. May your orchestrator be wise and your subagents swift.
349
+ **Aesop**: Autonomous developer for any repository, built by Aesop itself. May your orchestrator be wise and your subagents swift.
package/bin/cli.js CHANGED
@@ -11,8 +11,8 @@ const helpFlag = args.includes('--help') || args.includes('-h');
11
11
  const forceFlag = args.includes('--force');
12
12
  const yesFlag = args.includes('--yes');
13
13
 
14
- // Check for runtime subcommands (doctor, watch, dash, status)
15
- const runtimeCommands = ['doctor', 'watch', 'dash', 'status'];
14
+ // Check for runtime subcommands (doctor, watch, dash, status, fleet, health-score)
15
+ const runtimeCommands = ['doctor', 'watch', 'dash', 'status', 'fleet', 'health-score'];
16
16
  const isRuntimeCommand = runtimeCommands.includes(args[0]);
17
17
 
18
18
  if (isRuntimeCommand) {
@@ -20,7 +20,9 @@ if (isRuntimeCommand) {
20
20
  'doctor': '../tools/doctor.js',
21
21
  'watch': '../tools/watch.js',
22
22
  'dash': '../tools/dash.js',
23
- 'status': '../tools/status.js'
23
+ 'status': '../tools/status.js',
24
+ 'fleet': '../tools/fleet.js',
25
+ 'health-score': '../tools/health-score.js'
24
26
  };
25
27
  // Load and run the appropriate runtime module
26
28
  // These modules run async code that sets process.exitCode and will cause Node to exit
@@ -71,6 +73,66 @@ function validatePort(port) {
71
73
  return !isNaN(p) && p > 0 && p < 65536 ? p : null;
72
74
  }
73
75
 
76
+ // Test if a port is available (returns Promise<boolean>)
77
+ function isPortAvailable(port) {
78
+ return new Promise((resolve) => {
79
+ const net = require('net');
80
+ const sock = net.createConnection({ port, host: '127.0.0.1', timeout: 500 });
81
+ let resolved = false;
82
+
83
+ const cleanup = () => {
84
+ try {
85
+ sock.destroy();
86
+ } catch (e) {
87
+ // Ignore cleanup errors
88
+ }
89
+ };
90
+
91
+ sock.on('connect', () => {
92
+ if (!resolved) {
93
+ resolved = true;
94
+ cleanup();
95
+ resolve(false); // Port is in use
96
+ }
97
+ });
98
+
99
+ sock.on('error', () => {
100
+ if (!resolved) {
101
+ resolved = true;
102
+ cleanup();
103
+ resolve(true); // Port is free
104
+ }
105
+ });
106
+
107
+ sock.on('timeout', () => {
108
+ if (!resolved) {
109
+ resolved = true;
110
+ cleanup();
111
+ resolve(true); // Assume free on timeout
112
+ }
113
+ });
114
+
115
+ // Fallback timeout
116
+ setTimeout(() => {
117
+ if (!resolved) {
118
+ resolved = true;
119
+ cleanup();
120
+ resolve(true);
121
+ }
122
+ }, 2000);
123
+ });
124
+ }
125
+
126
+ // Find next available port starting from basePort
127
+ async function findAvailablePort(basePort = 8770) {
128
+ for (let port = basePort; port < basePort + 100; port++) {
129
+ if (await isPortAvailable(port)) {
130
+ return port;
131
+ }
132
+ }
133
+ return basePort; // Fallback to basePort
134
+ }
135
+
74
136
  // Parse named flags
75
137
  function getFlag(flagName) {
76
138
  const idx = args.findIndex(arg => arg === flagName);
@@ -91,12 +153,14 @@ Usage:
91
153
  npx @matt82198/aesop watch
92
154
  npx @matt82198/aesop dash
93
155
  npx @matt82198/aesop status
156
+ npx @matt82198/aesop fleet
94
157
 
95
158
  Commands:
96
159
  doctor Preflight readiness check (Node.js, Python, git, config, dirs, hook, port)
97
160
  watch Launch the watchdog daemon (spawns daemons/run-watchdog.sh)
98
161
  dash Launch the web dashboard (spawns python3 ui/serve.py or python fallback)
99
162
  status One-shot fleet status snapshot (heartbeats, dashboard port, git branch)
163
+ fleet One-shot fleet snapshot (agents, heartbeats, tracker lanes, orchestrator status)
100
164
  wizard Interactive onboarding (prompts for project name, repos, port)
101
165
 
102
166
  Arguments:
@@ -116,6 +180,7 @@ Examples:
116
180
  npx @matt82198/aesop watch # Launch watchdog daemon
117
181
  npx @matt82198/aesop dash # Launch web dashboard (default localhost:8770)
118
182
  npx @matt82198/aesop status # Show fleet status (heartbeats, port, git)
183
+ npx @matt82198/aesop fleet # Show fleet snapshot (JSON agents, heartbeats, tracker, orchestrator)
119
184
  npx @matt82198/aesop # Creates ./aesop-fleet/ with template
120
185
  npx @matt82198/aesop my-fleet # Creates ./my-fleet/ with template
121
186
  npx @matt82198/aesop wizard # Interactive onboarding (60-second setup)
@@ -314,7 +379,7 @@ function substituteTemplate(templateContent, projectName, domainsStr, reposStr)
314
379
  return result;
315
380
  }
316
381
 
317
- function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repoUrlsStr) {
382
+ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repoUrlsStr, port = 8770) {
318
383
  // Read example config
319
384
  const exampleConfigPath = path.join(templateRoot, 'aesop.config.example.json');
320
385
  let exampleConfig;
@@ -348,7 +413,8 @@ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repo
348
413
  dashboard: {
349
414
  refresh_seconds: 1,
350
415
  enable_jq_parsing: true,
351
- theme: 'dark'
416
+ theme: 'dark',
417
+ port: 8770
352
418
  },
353
419
  cardinal_rules: {
354
420
  subagent_model: 'haiku',
@@ -366,6 +432,8 @@ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repo
366
432
  exampleConfig.scripts_root = '~/scripts';
367
433
  exampleConfig.temp_root = '~/.aesop-temp';
368
434
  exampleConfig.fleet_root = os.homedir();
435
+ exampleConfig.dashboard = exampleConfig.dashboard || {};
436
+ exampleConfig.dashboard.port = port;
369
437
  exampleConfig._generated_note = 'This config uses portable ~ paths which expand at runtime on all platforms. Config loaders in ui/config.py (Python) and monitor/collect-signals.mjs (Node.js) automatically expand ~ paths to your home directory.';
370
438
 
371
439
  // Parse repos if provided
@@ -392,14 +460,14 @@ function generateConfigJson(targetDir, templateRoot, projectName, reposStr, repo
392
460
 
393
461
  // Print next steps and optionally run watchdog (returns a Promise)
394
462
  async function printNextStepsAndWatchdog(rl, targetDir, configPath, port) {
395
- console.log('\n🎯 Next 3 commands to get started:\n');
463
+ console.log('\n🎯 Next 2 commands to get started:\n');
396
464
  console.log(` 1. cd ${targetDir}`);
397
465
  console.log(' 2. bash daemons/run-watchdog.sh --once (one-time watchdog smoke test)');
398
466
  console.log(` 3. python3 ui/serve.py (or python as fallback; launch dashboard on localhost:${port})`);
399
- console.log('\n📖 After that, review:');
400
- console.log(' CLAUDE.md (pre-filled with your project info)');
401
- console.log(' aesop.config.json (pre-configured for your repos)');
402
- console.log(' docs/MEMORY-TEMPLATE.md (edit ~/.claude/MEMORY.md with your facts)\n');
467
+ console.log('\n📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
468
+ console.log(' mkdir -p ~/.claude/memory');
469
+ console.log(` cp ${targetDir}/CLAUDE.md ~/.claude/CLAUDE.md (review and customize)`);
470
+ console.log(` cp ${targetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)\n`);
403
471
 
404
472
  return new Promise((resolve) => {
405
473
  rl.question('Run watchdog --once now? (y/N): ', (answer) => {
@@ -422,6 +490,37 @@ async function printNextStepsAndWatchdog(rl, targetDir, configPath, port) {
422
490
  });
423
491
  }
424
492
 
493
+ // Initialize git repo if it doesn't exist
494
+ function initializeGitRepo(targetDir, noGitFlag = false) {
495
+ if (noGitFlag) {
496
+ return false; // User explicitly requested no git
497
+ }
498
+
499
+ const gitDir = path.join(targetDir, '.git');
500
+ if (fs.existsSync(gitDir)) {
501
+ return false; // Git already initialized
502
+ }
503
+
504
+ try {
505
+ // Initialize git repo
506
+ execSync('git init -q', { cwd: targetDir, stdio: 'pipe' });
507
+ console.log('✓ Initialized git repository');
508
+
509
+ // Create initial commit
510
+ execSync('git config user.email "aesop-scaffold@local"', { cwd: targetDir, stdio: 'pipe' });
511
+ execSync('git config user.name "Aesop Scaffold"', { cwd: targetDir, stdio: 'pipe' });
512
+ execSync('git add -A', { cwd: targetDir, stdio: 'pipe' });
513
+ execSync('git commit -q -m "Initial aesop scaffold"', { cwd: targetDir, stdio: 'pipe' });
514
+ console.log('✓ Created initial git commit');
515
+ return true;
516
+ } catch (e) {
517
+ // Git operations failed, continue anyway
518
+ console.warn('⚠ Warning: Failed to initialize git repo automatically');
519
+ console.warn(' Run manually: cd ' + targetDir + ' && git init && git add -A && git commit -m "Initial commit"');
520
+ return false;
521
+ }
522
+ }
523
+
425
524
  function installPreCommitWaveguard(targetDir, templateRoot) {
426
525
  // Install the pre-commit waveguard hook to prevent commits during a wave
427
526
  // Try to locate .git directory
@@ -664,6 +763,7 @@ if (!isRuntimeCommand) {
664
763
  let finalTargetDir = targetDir;
665
764
  let configPath = path.join(targetDir, 'aesop.config.json');
666
765
  let dashboardPort = 8770;
766
+ const noGitFlag = args.includes('--no-git');
667
767
 
668
768
  let wizardRl = null;
669
769
 
@@ -704,7 +804,7 @@ if (!isRuntimeCommand) {
704
804
  }
705
805
  finalReposStr = selectedRepos;
706
806
 
707
- // Q3: Dashboard port
807
+ // Q3: Dashboard port (with availability check)
708
808
  let port = '';
709
809
  while (!port) {
710
810
  port = await promptUser(wizardRl, 'Dashboard port', '8770');
@@ -713,7 +813,21 @@ if (!isRuntimeCommand) {
713
813
  console.log(' ✗ Invalid port. Must be a number between 1 and 65535.');
714
814
  port = '';
715
815
  } else {
716
- dashboardPort = validPort;
816
+ // Check if port is available
817
+ const available = await isPortAvailable(validPort);
818
+ if (!available) {
819
+ console.log(` ⚠ Port ${validPort} is in use. Trying next available port...`);
820
+ const nextPort = await findAvailablePort(validPort);
821
+ if (nextPort !== validPort) {
822
+ console.log(` → Using port ${nextPort} instead`);
823
+ dashboardPort = nextPort;
824
+ } else {
825
+ dashboardPort = validPort;
826
+ }
827
+ port = validPort.toString(); // Exit loop
828
+ } else {
829
+ dashboardPort = validPort;
830
+ }
717
831
  }
718
832
  }
719
833
 
@@ -728,8 +842,15 @@ if (!isRuntimeCommand) {
728
842
  // Non-interactive defaults for wizard mode with --yes
729
843
  finalProjectName = 'my-fleet';
730
844
  finalReposStr = '';
731
- dashboardPort = 8770;
845
+ // Find available port
846
+ dashboardPort = await findAvailablePort(8770);
732
847
  console.log('🪄 Running onboarding wizard with defaults (--yes)');
848
+ } else if (!wizardMode && finalProjectName) {
849
+ // Headless mode: check and find available port
850
+ dashboardPort = await findAvailablePort(8770);
851
+ if (dashboardPort !== 8770) {
852
+ console.log(`ℹ Port 8770 is in use, using port ${dashboardPort} instead`);
853
+ }
733
854
  }
734
855
 
735
856
  // Copy template files
@@ -767,8 +888,8 @@ if (!isRuntimeCommand) {
767
888
  // But if it does, warn and skip
768
889
  console.warn(`⚠ Warning: aesop.config.json already exists at ${configPath}`);
769
890
  } else {
770
- // Generate aesop.config.json
771
- const config = generateConfigJson(finalTargetDir, templateRoot, finalProjectName, finalReposStr, finalRepoUrlsStr);
891
+ // Generate aesop.config.json with the determined port
892
+ const config = generateConfigJson(finalTargetDir, templateRoot, finalProjectName, finalReposStr, finalRepoUrlsStr, dashboardPort);
772
893
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
773
894
  console.log('✓ Generated aesop.config.json (configured for your repos)');
774
895
  }
@@ -782,10 +903,13 @@ if (!isRuntimeCommand) {
782
903
  console.log('✓ Copied MEMORY-SEED.md (template for your facts)');
783
904
  }
784
905
 
785
- // Install the pre-push hook
906
+ // Initialize git repo if needed (BEFORE installing hooks)
907
+ initializeGitRepo(finalTargetDir, noGitFlag);
908
+
909
+ // Install the pre-push hook (only works if .git exists)
786
910
  installPrePushHook(finalTargetDir, templateRoot);
787
911
 
788
- // Install the pre-commit waveguard hook
912
+ // Install the pre-commit waveguard hook (only works if .git exists)
789
913
  installPreCommitWaveguard(finalTargetDir, templateRoot);
790
914
 
791
915
  console.log(`\n✅ Scaffolded aesop template into "${finalTargetDir}" (${copiedCount} files)`);
@@ -800,35 +924,34 @@ if (!isRuntimeCommand) {
800
924
  console.log(` 1. cd ${finalTargetDir}`);
801
925
  console.log(' 2. bash daemons/run-watchdog.sh --once (one-time watchdog smoke test)');
802
926
  console.log(` 3. python3 ui/serve.py (or python as fallback; launch dashboard on localhost:${dashboardPort})`);
803
- console.log('\n📖 After that, review:');
804
- console.log(' CLAUDE.md (pre-filled with your project info)');
805
- console.log(' aesop.config.json (pre-configured for your repos)');
806
- console.log(' docs/MEMORY-TEMPLATE.md (edit ~/.claude/MEMORY.md with your facts)');
927
+ console.log('\n📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
928
+ console.log(' mkdir -p ~/.claude/memory');
929
+ console.log(` cp ${finalTargetDir}/CLAUDE.md ~/.claude/CLAUDE.md (review and customize)`);
930
+ console.log(` cp ${finalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
807
931
  process.exit(0);
808
932
  } else if (finalProjectName) {
809
- console.log('\nHeadless scaffolding complete! Next steps:');
933
+ console.log('\n✅ Headless scaffolding complete!\n');
934
+ console.log('🎯 Next 3 commands to get started:\n');
810
935
  console.log(` 1. cd ${finalTargetDir}`);
811
- console.log(' 2. Review CLAUDE.md (pre-filled with your project info)');
812
- console.log(' 3. Review aesop.config.json (pre-configured for your repos)');
813
- console.log('\nInitialize your brain (Claude Code team memory):');
814
- console.log(' 4. mkdir -p ~/.claude/memory');
815
- console.log(` 5. cp ${finalTargetDir}/CLAUDE.md ~/.claude/CLAUDE.md (or review existing ~/.claude/CLAUDE.md)`);
816
- console.log(` 6. cp ${finalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
817
- console.log('\nRun the daemon and dashboard:');
818
- console.log(' 7. bash daemons/run-watchdog.sh --once (test run)');
819
- console.log(' 8. python3 ui/serve.py (or python as fallback; launch dashboard on localhost:8770)');
936
+ console.log(' 2. bash daemons/run-watchdog.sh --once (one-time watchdog smoke test)');
937
+ console.log(` 3. python3 ui/serve.py (or python as fallback; launch dashboard on localhost:${dashboardPort})`);
938
+ console.log('\n📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
939
+ console.log(' mkdir -p ~/.claude/memory');
940
+ console.log(` cp ${finalTargetDir}/CLAUDE.md ~/.claude/CLAUDE.md (review and customize)`);
941
+ console.log(` cp ${finalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
820
942
  } else {
821
- console.log('\nConfiguration steps:');
943
+ console.log('\n✅ Scaffold complete!\n');
944
+ console.log('🎯 Next 3 commands to get started:\n');
822
945
  console.log(` 1. cd ${finalTargetDir}`);
823
- console.log(' 2. cp aesop.config.example.json aesop.config.json');
824
- console.log(' 3. Edit aesop.config.json with your configuration');
825
- console.log('\nInitialize your brain (Claude Code team memory):');
826
- console.log(' 4. mkdir -p ~/.claude/memory');
827
- console.log(` 5. cp ${finalTargetDir}/CLAUDE-TEMPLATE.md ~/.claude/CLAUDE.md (then edit domains/team info)`);
828
- console.log(` 6. cp ${finalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
829
- console.log('\nRun the daemon and dashboard:');
830
- console.log(' 7. bash daemons/run-watchdog.sh --once (test run)');
831
- console.log(' 8. python3 ui/serve.py (or python as fallback; launch dashboard on localhost:8770)');
946
+ console.log(' 2. bash daemons/run-watchdog.sh --once (one-time watchdog smoke test)');
947
+ console.log(` 3. python3 ui/serve.py (or python as fallback; launch dashboard on localhost:${dashboardPort})`);
948
+ console.log('\n📖 Configuration steps (optional):\n');
949
+ console.log(' cp aesop.config.example.json aesop.config.json (if not generated)');
950
+ console.log(' Edit aesop.config.json with your configuration');
951
+ console.log('\n📖 Optional: Set up your brain (Claude Code orchestration memory):\n');
952
+ console.log(' mkdir -p ~/.claude/memory');
953
+ console.log(` cp ${finalTargetDir}/CLAUDE-TEMPLATE.md ~/.claude/CLAUDE.md (then edit domains/team info)`);
954
+ console.log(` cp ${finalTargetDir}/MEMORY-SEED.md ~/.claude/MEMORY.md (then add your facts)`);
832
955
  }
833
956
  console.log('\nFor full documentation, see the README.md in the scaffolded directory.');
834
957
  process.exit(0);