@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
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env python3
2
+ """ClaudeCodeDriver -- reference AgentDriver for the Claude Code backend.
3
+
4
+ This is the PARITY reference: it maps the five AgentDriver operations onto what
5
+ Claude Code's Workflow harness already provides. It is intentionally a thin,
6
+ well-documented adapter, because in Claude Code the actual dispatch does NOT run
7
+ inside this Python process -- it runs inside the harness's Workflow context
8
+ (the `agent()`, `parallel()`, Read/Write/Bash tools, `budget.spent()`).
9
+
10
+ WHAT MAPS WHERE
11
+ ---------------
12
+ Operation Claude Code mechanism Lives where
13
+ ------------------- ------------------------------- ------------------------
14
+ probe_capabilities static, known-good facts this file (concrete)
15
+ dispatch_worker Workflow agent()/Task tool HARNESS (conceptual)
16
+ worker_status heartbeat + harness liveness HARNESS + state files
17
+ run_command Bash tool HARNESS
18
+ resolve_model Anthropic model-name passthrough this file (concrete)
19
+
20
+ So two of the five ops (probe_capabilities, resolve_model) are fully concrete
21
+ Python here -- they are pure data/mapping and need no harness. The other three
22
+ (dispatch_worker, worker_status, run_command) are documented adapters: in a live
23
+ Claude Code wave they are serviced by the harness's own tools, not by this
24
+ process. This class exists so the SEAM is real and testable -- the wave loop can
25
+ be written against AgentDriver and this reference proves the Claude Code backend
26
+ satisfies the contract. When the wave-flat-dispatch template is refactored onto
27
+ the driver (spike Phase 1), these three methods become the documented handoff
28
+ points to the harness.
29
+
30
+ For out-of-harness use (tests, tooling, local scripts) run_command is given a
31
+ real subprocess implementation so it is not a dead stub; dispatch_worker and
32
+ worker_status raise a clear, explained error rather than pretending to spawn a
33
+ Claude agent from plain Python.
34
+
35
+ stdlib-only, ASCII-only, Windows + Linux safe.
36
+ """
37
+
38
+ import subprocess
39
+ from typing import Optional
40
+
41
+ from agent_driver import (
42
+ AgentDriver,
43
+ CommandResult,
44
+ DriverCapabilities,
45
+ ROLE_SETUP,
46
+ ROLE_VERIFY,
47
+ ROLE_WORKER,
48
+ WorkerRequest,
49
+ WorkerResult,
50
+ WorkerStatus,
51
+ WORKER_UNKNOWN,
52
+ )
53
+
54
+
55
+ # Default abstract-role -> Anthropic model mapping. Workers are Haiku by policy
56
+ # (aesop cardinal rule: subagents are always Haiku); setup/verify may lift to
57
+ # Sonnet. resolve_model() reads this and is overridable via the constructor.
58
+ _DEFAULT_MODEL_MAP = {
59
+ ROLE_WORKER: "haiku",
60
+ ROLE_SETUP: "sonnet",
61
+ ROLE_VERIFY: "haiku",
62
+ }
63
+
64
+ # Marker error text shared with tests: the ops that only a live harness can do.
65
+ _HARNESS_ONLY = (
66
+ "ClaudeCodeDriver.{op} is serviced by the Claude Code Workflow harness "
67
+ "(agent()/Task tool), not by this Python process. In a live wave the "
68
+ "orchestrator dispatches through the harness; this reference adapter marks "
69
+ "the seam. See driver/README.md 'What maps where'."
70
+ )
71
+
72
+
73
+ class ClaudeCodeDriver(AgentDriver):
74
+ """Reference adapter mapping AgentDriver onto Claude Code."""
75
+
76
+ name = "claude-code"
77
+
78
+ def __init__(self, model_map: Optional[dict] = None):
79
+ # Copy so callers cannot mutate our defaults; fall back per-role.
80
+ self._model_map = dict(_DEFAULT_MODEL_MAP)
81
+ if model_map:
82
+ self._model_map.update(model_map)
83
+
84
+ # -- Operation 1: capability probe (concrete) --------------------------
85
+ def probe_capabilities(self) -> DriverCapabilities:
86
+ """Claude Code is the self-contained, high-accuracy reference backend.
87
+
88
+ Every capability is native and instant; tool-use accuracy is ~0.99, so
89
+ the recommended verification tier is 1 (light spot-check). These facts
90
+ are static and known-good -- no probing round-trip required.
91
+ """
92
+ return DriverCapabilities(
93
+ name=self.name,
94
+ parallel_dispatch=True, # native parallel() in the harness
95
+ worker_filesystem_access=True, # workers use Read/Write tools
96
+ worker_shell_access=True, # workers use the Bash tool
97
+ structured_output=True, # agent(schema=...) is near-perfect
98
+ worktree_isolation=True, # orchestrator manages git worktrees
99
+ native_cost_tracking=True, # budget.spent() real-time API
100
+ native_stall_detection=True, # harness + heartbeat liveness
101
+ tool_use_accuracy=0.99,
102
+ recommended_verification_tier=1,
103
+ available_models=("haiku", "sonnet", "opus"),
104
+ notes=(
105
+ "Reference backend. Self-contained: no external harness. "
106
+ "dispatch_worker/worker_status/run_command are serviced by the "
107
+ "Claude Code Workflow harness in a live wave."
108
+ ),
109
+ )
110
+
111
+ # -- Operation 2: dispatch (harness-serviced) --------------------------
112
+ def dispatch_worker(self, request: WorkerRequest) -> WorkerResult:
113
+ """Documented seam: real dispatch happens in the harness.
114
+
115
+ In a live Claude Code wave the orchestrator spawns the worker via the
116
+ harness's agent()/Task tool with the resolved model, the owned-files
117
+ contract, and (optionally) request.result_schema. From plain Python
118
+ there is no Claude agent to spawn, so we raise a clear, explained error
119
+ rather than fake a result.
120
+ """
121
+ raise NotImplementedError(_HARNESS_ONLY.format(op="dispatch_worker"))
122
+
123
+ # -- Operation 3: stall detection (harness-serviced) -------------------
124
+ def worker_status(self, worker_id: str) -> WorkerStatus:
125
+ """Documented seam: liveness comes from the harness + heartbeat files.
126
+
127
+ A live wave reads worker liveness from the harness and the fleet's
128
+ heartbeat/state files. Out of harness there is nothing to observe, so
129
+ we report UNKNOWN honestly.
130
+ """
131
+ return WorkerStatus(
132
+ worker_id=worker_id,
133
+ state=WORKER_UNKNOWN,
134
+ stalled=False,
135
+ age_s=0.0,
136
+ detail=_HARNESS_ONLY.format(op="worker_status"),
137
+ )
138
+
139
+ # -- Operation 4: orchestrator-side command (real) ---------------------
140
+ def run_command(
141
+ self,
142
+ command: str,
143
+ cwd: Optional[str] = None,
144
+ shell: Optional[str] = None,
145
+ ) -> CommandResult:
146
+ """Run a command on the orchestrator host.
147
+
148
+ In a live wave this is the Bash tool; out of harness we back it with a
149
+ real subprocess so tooling/tests get genuine behavior. `shell` is
150
+ advisory -- we always execute through the platform shell so the same
151
+ call works on Windows and Linux.
152
+ """
153
+ try:
154
+ completed = subprocess.run(
155
+ command,
156
+ cwd=cwd,
157
+ shell=True,
158
+ capture_output=True,
159
+ text=True,
160
+ )
161
+ return CommandResult(
162
+ exit_code=completed.returncode,
163
+ stdout=completed.stdout or "",
164
+ stderr=completed.stderr or "",
165
+ )
166
+ except OSError as exc:
167
+ return CommandResult(exit_code=127, stdout="", stderr=str(exc))
168
+
169
+ # -- Operation 5: model selection (concrete) ---------------------------
170
+ def resolve_model(self, role: str) -> str:
171
+ """Map an abstract role to an Anthropic model name.
172
+
173
+ Unknown roles fall back to the worker (Haiku) mapping so a mis-typed
174
+ role can never silently escalate cost.
175
+ """
176
+ return self._model_map.get(role, self._model_map[ROLE_WORKER])
177
+
178
+ # -- Optional: cost tracking -------------------------------------------
179
+ def get_tokens_spent(self) -> Optional[int]:
180
+ """Return None: per-instance spend is not observable from the harness-serviced driver.
181
+
182
+ CONTRACT:
183
+ The orchestrator-side driver cannot directly observe driver instance spend
184
+ because dispatch happens inside the harness's Workflow context (agent()/Task
185
+ tool), not in this Python process. In a live wave the harness-side budget.spent()
186
+ API is not exposed to this adapter.
187
+
188
+ DESIGN:
189
+ Cost enforcement is delivered by the wave loop passing None here, which causes
190
+ cost_ceiling.check() to perform its own windowed ledger fallback. This ensures
191
+ that period windowing (e.g., daily caps) is respected: cost_ceiling reads the
192
+ ledger directly and filters rows by the requested period. Returning a lifetime
193
+ sum would bypass that windowing logic and cause false trips after wave 2+.
194
+
195
+ See cost_ceiling.py:read_ledger_total_tokens() for the authoritative windowing
196
+ implementation.
197
+ """
198
+ return None