@matt82198/aesop 0.1.0 → 0.3.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.
Files changed (130) hide show
  1. package/CHANGELOG.md +117 -2
  2. package/README.md +59 -218
  3. package/bin/cli.js +168 -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/HOOK-INSTALL.md +15 -56
  10. package/docs/INSTALL.md +74 -4
  11. package/docs/PORTING.md +166 -0
  12. package/docs/README.md +33 -3
  13. package/docs/TEAM-STATE.md +372 -0
  14. package/docs/reproduce.md +33 -3
  15. package/driver/CLAUDE.md +150 -0
  16. package/driver/README.md +383 -0
  17. package/driver/aesop.config.example.json +80 -0
  18. package/driver/agent_driver.py +355 -0
  19. package/driver/backend_config.py +253 -0
  20. package/driver/claude_code_driver.py +198 -0
  21. package/driver/codex_driver.py +673 -0
  22. package/driver/openai_compatible_driver.py +249 -0
  23. package/driver/openai_transport.py +179 -0
  24. package/driver/verification_policy.py +75 -0
  25. package/driver/wave_bridge.py +254 -0
  26. package/driver/wave_loop.py +1408 -0
  27. package/driver/wave_scheduler.py +890 -0
  28. package/hooks/pre-push-policy.sh +131 -33
  29. package/mcp/server.mjs +320 -4
  30. package/monitor/collect-signals.mjs +69 -0
  31. package/package.json +22 -14
  32. package/skills/CLAUDE.md +132 -2
  33. package/skills/buildsystem/SKILL.md +330 -0
  34. package/skills/buildsystem/wave-flat-dispatch.template.mjs +658 -0
  35. package/skills/fleet/SKILL.md +113 -0
  36. package/skills/power/SKILL.md +246 -131
  37. package/state_store/__init__.py +4 -2
  38. package/state_store/api.py +19 -4
  39. package/state_store/coordination.py +209 -0
  40. package/state_store/identity.py +51 -0
  41. package/state_store/projections.py +63 -0
  42. package/state_store/read_api.py +156 -0
  43. package/state_store/store.py +185 -73
  44. package/state_store/write_api.py +462 -0
  45. package/templates/wave-presets/data.json +65 -0
  46. package/templates/wave-presets/library.json +65 -0
  47. package/templates/wave-presets/saas.json +64 -0
  48. package/tools/audit_report.py +388 -0
  49. package/tools/bench_runner.py +100 -3
  50. package/tools/ci_merge_wait.py +256 -35
  51. package/tools/ci_workflow_lint.py +430 -0
  52. package/tools/claudemd_drift.py +394 -0
  53. package/tools/claudemd_lint.py +359 -0
  54. package/tools/common.py +39 -3
  55. package/tools/cost_ceiling.py +166 -43
  56. package/tools/cost_econ.py +480 -0
  57. package/tools/cost_projection.py +559 -0
  58. package/tools/crossos_drift.py +394 -0
  59. package/tools/defect_escape.py +252 -0
  60. package/tools/doctor.js +1 -1
  61. package/tools/eod_sweep.py +188 -26
  62. package/tools/fleet.js +260 -0
  63. package/tools/fleet_ledger.py +209 -7
  64. package/tools/git_identity_check.py +315 -0
  65. package/tools/health-score.js +40 -0
  66. package/tools/health_score.py +361 -0
  67. package/tools/metrics_gate.py +13 -4
  68. package/tools/mutation_test.py +523 -0
  69. package/tools/portability_check.py +206 -0
  70. package/tools/proposals.mjs +47 -2
  71. package/tools/reconcile.py +7 -4
  72. package/tools/reproduce.js +405 -0
  73. package/tools/secret_scan.py +207 -65
  74. package/tools/self_stats.py +20 -0
  75. package/tools/stall_check.py +247 -16
  76. package/tools/stateapi_lint.py +325 -0
  77. package/tools/test_battery.py +173 -0
  78. package/tools/transcript_digest.py +380 -0
  79. package/tools/verify_activity_filter.py +437 -0
  80. package/tools/verify_agent_inspector.py +2 -0
  81. package/tools/verify_cost_panel.py +345 -0
  82. package/tools/verify_dash.py +2 -0
  83. package/tools/verify_dispatch_panel.py +301 -0
  84. package/tools/verify_failure_drilldown.py +188 -0
  85. package/tools/verify_prboard.py +2 -0
  86. package/tools/verify_scorecards.py +281 -0
  87. package/tools/verify_submit_encoding.py +2 -0
  88. package/tools/verify_ui_trio.py +409 -0
  89. package/tools/verify_wave_telemetry.py +268 -0
  90. package/tools/wave_backlog_analyzer.py +490 -0
  91. package/tools/wave_ledger_hook.py +150 -0
  92. package/tools/wave_preflight.py +779 -0
  93. package/tools/wave_resume.py +215 -0
  94. package/tools/wave_templates.py +340 -0
  95. package/ui/agents.py +68 -14
  96. package/ui/collectors.py +81 -55
  97. package/ui/config.py +7 -2
  98. package/ui/cost.py +231 -12
  99. package/ui/handler.py +383 -55
  100. package/ui/quality_scorecard.py +232 -0
  101. package/ui/sse.py +3 -3
  102. package/ui/wave_audit_tail.py +213 -0
  103. package/ui/wave_dispatch.py +280 -0
  104. package/ui/wave_failure.py +288 -0
  105. package/ui/wave_gantt.py +152 -0
  106. package/ui/wave_reasoning_tail.py +176 -0
  107. package/ui/wave_telemetry.py +383 -0
  108. package/ui/web/dist/assets/index-CNQxaiOW.css +1 -0
  109. package/ui/web/dist/assets/index-CP68RIh3.js +9 -0
  110. package/ui/web/dist/index.html +2 -2
  111. package/bin/CLAUDE.md +0 -76
  112. package/daemons/CLAUDE.md +0 -36
  113. package/dash/CLAUDE.md +0 -32
  114. package/docs/archive/README.md +0 -3
  115. package/docs/archive/spikes/tiered-cognition/ACTIVATION.md +0 -125
  116. package/docs/archive/spikes/tiered-cognition/DESIGN.md +0 -287
  117. package/docs/archive/spikes/tiered-cognition/FINDINGS.md +0 -113
  118. package/docs/archive/spikes/tiered-cognition/README.md +0 -27
  119. package/docs/archive/spikes/tiered-cognition/aesop-cognition.example.md +0 -32
  120. package/docs/archive/spikes/tiered-cognition/force-model-policy.merged.mjs +0 -673
  121. package/docs/archive/spikes/tiered-cognition/strip-tools-hook.mjs +0 -434
  122. package/hooks/CLAUDE.md +0 -89
  123. package/mcp/CLAUDE.md +0 -213
  124. package/monitor/CLAUDE.md +0 -40
  125. package/scan/CLAUDE.md +0 -30
  126. package/state_store/CLAUDE.md +0 -39
  127. package/tools/CLAUDE.md +0 -79
  128. package/ui/CLAUDE.md +0 -127
  129. package/ui/web/dist/assets/index-0qQYnvMC.js +0 -9
  130. package/ui/web/dist/assets/index-BdIlFieV.css +0 -1
@@ -0,0 +1,383 @@
1
+ # AgentDriver — multi-model portability for aesop
2
+
3
+ > Run aesop's wave loop on backends other than Claude Code — Codex, and
4
+ > eventually open models — through one narrow interface.
5
+
6
+ This directory contains the **AgentDriver seam** (Phase 1), a working Codex
7
+ implementation (Phase 2), and the wave bridge connecting backends to orchestrator
8
+ dispatch (Phase 3). The phase-1 abstraction seam is the interface; the
9
+ phase-2 Codex driver proves a non-Claude backend can execute a real coding task
10
+ end-to-end and produce orchestrator-verified results, entirely offline (no API
11
+ key, no network in CI tests). Phase 3 routes work items through any backend with
12
+ honest verification (test exit code only) and backend-driven verification tier.
13
+
14
+ ---
15
+
16
+ ## The problem
17
+
18
+ Aesop's orchestration core — the wave / flat-dispatch cycle — is written against
19
+ Claude Code's Workflow harness. It calls `agent()`, `parallel()`, the
20
+ Read/Write/Bash tools, and `budget.spent()` directly. Those calls only exist
21
+ inside Claude Code, so the wave loop cannot run anywhere else.
22
+
23
+ The spike's finding: ~80% of aesop (daemons, tools, state_store, MCP, UI) is
24
+ already portable. The coupling is concentrated in **how the wave loop talks to
25
+ its execution backend**. Extract that into one interface and the loop becomes
26
+ backend-agnostic.
27
+
28
+ ## The abstraction
29
+
30
+ `AgentDriver` (in `agent_driver.py`) is that interface — an abstract base class
31
+ with **five** operations, which are everything the wave loop needs from any
32
+ backend:
33
+
34
+ | # | Operation | What it gives the wave loop |
35
+ |---|-----------------------------------|--------------------------------------------------------------|
36
+ | 1 | `probe_capabilities()` | Honest self-report → drives the whole verification strategy. |
37
+ | 2 | `dispatch_worker(request)` | Spawn one isolated worker (read/write files, run shell, return structured result). |
38
+ | 3 | `worker_status(worker_id)` | Liveness / stall detection for the watchdog. |
39
+ | 4 | `run_command(cmd, cwd, shell)` | Orchestrator-side execution: tests, git, verification. |
40
+ | 5 | `resolve_model(role)` | Abstract role (`worker`/`setup`/`verify`) → concrete model. |
41
+
42
+ Plus one optional op: `get_tokens_spent()`.
43
+
44
+ The wave loop calls **only** these methods. A new backend is a new subclass — no
45
+ changes to the orchestration algorithm. That is the entire point of the seam.
46
+
47
+ ### What maps where (Claude Code reference)
48
+
49
+ In Claude Code the actual dispatch runs inside the harness, not in this Python
50
+ process. So the reference adapter (`claude_code_driver.py`) is deliberately thin:
51
+
52
+ | Operation | Claude Code mechanism | Concrete here? |
53
+ |----------------------|------------------------------|:--------------:|
54
+ | `probe_capabilities` | static known-good facts | yes |
55
+ | `resolve_model` | Anthropic model-name map | yes |
56
+ | `run_command` | Bash tool (subprocess out of harness) | yes |
57
+ | `dispatch_worker` | Workflow `agent()`/Task tool | harness-serviced |
58
+ | `worker_status` | harness + heartbeat files | harness-serviced |
59
+
60
+ The two harness-serviced ops raise a clear, explained error out of harness
61
+ rather than fake a Claude agent from plain Python. When the wave-flat-dispatch
62
+ template is refactored onto the driver (Phase 1, below), these become the
63
+ documented handoff points to the harness.
64
+
65
+ ---
66
+
67
+ ## Per-backend capability matrix
68
+
69
+ Encoded honestly in each driver's `probe_capabilities()` — the numbers are the
70
+ spike's findings as data, so the orchestrator can plan **before** any CLI wiring
71
+ exists:
72
+
73
+ | Capability | **claude-code** | **codex** (Phase 2) | open-model (future) |
74
+ |------------------------|:---------------:|:-------------------------:|:--------------------------:|
75
+ | parallel_dispatch | native | no — external event loop | no — external event loop |
76
+ | worker filesystem I/O | yes (tools) | no — orchestrator injects | no — orchestrator injects |
77
+ | worker shell | yes (Bash tool) | no — orchestrator runs | no — orchestrator runs |
78
+ | structured output | yes (~perfect) | yes (JSON schema) | partial — regex recovery |
79
+ | worktree isolation | git-worktree | no — temp-dir | no — temp-dir |
80
+ | native cost tracking | `budget.spent()`| usage metadata (real) | manual (len/4 estimate) |
81
+ | tool-use accuracy | ~0.99 | ~0.90–0.95 | ~0.70–0.85 |
82
+ | **verification tier** | **1** | **2** | **4** |
83
+
84
+ Read the trend down the last row — it is the design's thesis, not an accident.
85
+
86
+ ---
87
+
88
+ ## The key insight — verification is load-bearing
89
+
90
+ > **Cheaper / weaker workers RAISE the need for the verification layer aesop
91
+ > already built. They do not lower the orchestrator's burden — they shift cost
92
+ > from inference to orchestration.**
93
+
94
+ Aesop's original bet was "Haiku suffices as a subagent because its tool-use
95
+ accuracy is ~99%, so the orchestrator only spot-checks lightly." A weaker
96
+ backend breaks that assumption:
97
+
98
+ - **Codex (gpt-3.5/4-turbo, ~90–95%)** returns 5–10% malformed JSON. The
99
+ orchestrator must validate every output and budget ≥2 repair rounds → **Tier 2**.
100
+ - **Open models (~70–85%)** return 15–30% malformed JSON. Every Build result
101
+ needs validation + strong spot-check (Sonnet-verified), with high triage
102
+ escalation → **Tier 4**.
103
+
104
+ So the money saved on cheap inference is partly re-spent on orchestrator
105
+ verification (the spike models DeepSeek at ~6.7× cheaper than Haiku, not the
106
+ headline 10×, once recovery is counted). This is exactly why aesop's existing
107
+ adversarial-review / mutation / verification tooling is **load-bearing** for
108
+ portability: it is the thing that makes weak-but-cheap backends viable at all.
109
+ `recommended_verification_tier` on every `DriverCapabilities` encodes this
110
+ inverse relationship — lower accuracy, higher tier — and the test suite asserts
111
+ it as an invariant (`TestVerificationThesisEncoded`).
112
+
113
+ The Haiku baseline is **unchanged**: it stays Tier 1. Portability *extends* the
114
+ system; it does not replace the original principle (autonomous fleet work needs
115
+ high-confidence subagents **plus** strong orchestration).
116
+
117
+ ---
118
+
119
+ ## Phased roadmap
120
+
121
+ | Phase | Scope | Status |
122
+ |-------|--------------------------------------------|----------------------------|
123
+ | **1** | Driver interface + Claude Code parity | **shipped** |
124
+ | | Reference adapter, honest Codex stub, tests| in this directory |
125
+ | | Refactor wave-flat-dispatch onto the driver| next (harness handoff pts) |
126
+ | **2** | Codex OpenAI Chat Completions HTTP backend | **shipped** |
127
+ | | Transport seam (urllib, injectable); dispatch_worker (file injection, JSON validation with retry, full-file replacement); run_command (subprocess); worker_status (in-memory registry); verification_policy mapping; offline test suite with FakeTransport + gated live test | implemented in `codex_driver.py` + `openai_transport.py` + `verification_policy.py` + tests |
128
+ | **3** | Wave bridge + verification policy routing | **shipped** |
129
+ | | Connect AgentDriver backends to wave-flat-dispatch manifest items; honest green (test exit code only); backend-driven verification tier. OpenAI-compatible driver for hosted models (OpenRouter, etc.) and local models (Ollama). | implemented in `wave_bridge.py` + `openai_compatible_driver.py` + tests |
130
+ | **4** | Open-model runner library | future |
131
+ | | Dedicated Ollama/local-model adapter, per-model prompt tuning, error-recovery protocol, Tier-4 enforcement, `bench/` accuracy benchmark | future |
132
+
133
+ **Deployment posture** (from the spike): Claude Code is production. Codex and
134
+ open models stay **experimental / opt-in** until their tiers are proven —
135
+ recommend Haiku for production fleets.
136
+
137
+ ---
138
+
139
+ ## Usage
140
+
141
+ ```python
142
+ import sys
143
+ sys.path.insert(0, "driver") # bare imports within the domain
144
+
145
+ from claude_code_driver import ClaudeCodeDriver
146
+ from codex_driver import CodexDriver
147
+ from verification_policy import verification_policy
148
+ from backend_config import build_driver, load_backend_config, describe_backend
149
+
150
+ for driver in (ClaudeCodeDriver(), CodexDriver()):
151
+ caps = driver.probe_capabilities()
152
+ print(caps.summary()) # ASCII one-liner for logs/dashboards
153
+ print("worker model ->", driver.resolve_model("worker"))
154
+
155
+ # The verification policy is RESOLVED in Python (verification_policy function)
156
+ # and baked into the manifest by build_manifest_item. JS consumes these literal fields;
157
+ # it does NOT recompute the policy (that was the drift trap).
158
+ policy = verification_policy(caps)
159
+ print("verification tier:", caps.recommended_verification_tier)
160
+ print(" repair_cap:", policy['repair_cap'])
161
+ print(" require_adversarial_review:", policy['require_adversarial_review'])
162
+ print(" spot_check_frac:", policy['spot_check_frac'])
163
+ print(" validate_all_json:", policy['validate_all_json'])
164
+ ```
165
+
166
+ ### Running other models (OpenAI-compatible backends)
167
+
168
+ Aesop can target any OpenAI Chat Completions-compatible endpoint: OpenRouter,
169
+ Together AI, Ollama (local), or any service offering a compatible API. Use the
170
+ `OpenAICompatibleDriver`:
171
+
172
+ ```python
173
+ from openai_compatible_driver import OpenAICompatibleDriver
174
+
175
+ # OpenRouter (hosted model, Tier 2)
176
+ driver = OpenAICompatibleDriver(
177
+ base_url="https://openrouter.ai/api/v1",
178
+ model="openrouter/auto", # or specific model like "openai/gpt-4-turbo"
179
+ api_key_env="OPENAI_API_KEY", # env var name (default)
180
+ )
181
+
182
+ # Local Ollama (small/local model, Tier 3)
183
+ driver = OpenAICompatibleDriver(
184
+ base_url="http://localhost:11434/v1",
185
+ model="neural-chat",
186
+ is_local=True, # Marks as local -> tier 3, higher verification
187
+ )
188
+
189
+ # Together AI
190
+ driver = OpenAICompatibleDriver(
191
+ base_url="https://api.together.xyz/v1",
192
+ model="meta-llama/Llama-2-70b-chat",
193
+ api_key_env="TOGETHER_API_KEY",
194
+ )
195
+ ```
196
+
197
+ All OpenAI-compatible backends run through the **Phase 2 orchestrator-managed
198
+ execution contract**: the orchestrator injects file contents, validates JSON
199
+ output, writes files, and runs tests. No backend has native filesystem/shell
200
+ access. The driver reports its honest verification tier (2 for hosted strong
201
+ models, 3 for local/small models), and the wave template enforces the
202
+ appropriate verification policy (validate all JSON, spot-check, repair bounds).
203
+
204
+ To run aesop against a backend:
205
+
206
+ 1. Set up the environment (API key, endpoint URL).
207
+ 2. Instantiate the driver.
208
+ 3. Pass it to your wave orchestration loop:
209
+ ```python
210
+ caps = driver.probe_capabilities()
211
+ policy = verification_policy(caps)
212
+ # Proceed with wave dispatch, respecting policy.verification_tier
213
+ ```
214
+
215
+ **Important note**: Non-agentic backends (Ollama, smaller models) run at a higher
216
+ verification tier (3+) because their tool-use accuracy is lower. The cost of
217
+ cheaper inference is re-spent on orchestrator verification. See the verification
218
+ thesis in the README for details.
219
+
220
+ ### Configuring a backend
221
+
222
+ Aesop's backend can be configured via an `aesop.config.json` file in the
223
+ repository root (or any other path). This allows dropping a single JSON file to
224
+ switch backends without changing code. The configuration is **offline-safe**:
225
+ building a driver requires no API key; keys are read from environment variables
226
+ at call time during live dispatch.
227
+
228
+ **Configuration schema** (backend block):
229
+ ```json
230
+ {
231
+ "backend": "claude" | "codex" | "openai-compatible",
232
+ "model": "...", // Required for codex, openai-compatible
233
+ "base_url": "...", // Required for openai-compatible
234
+ "api_key_env": "OPENAI_API_KEY", // Optional (default: OPENAI_API_KEY)
235
+ "is_local": false, // Optional, for openai-compatible only
236
+ "max_owned_bytes": 200000, // Optional file-size limit
237
+ "max_retries": 2, // Optional retry cap for malformed JSON
238
+ "timeout_s": 120.0 // Optional HTTP timeout
239
+ }
240
+ ```
241
+
242
+ **Default**: If no config file exists, aesop uses Claude Code (preserves today's
243
+ behavior).
244
+
245
+ **Example configurations**:
246
+
247
+ ```python
248
+ # backend_config.py provides helpers to load and build drivers from JSON:
249
+
250
+ from backend_config import load_backend_config, build_driver, describe_backend
251
+
252
+ # Load from aesop.config.json (or default to Claude)
253
+ config = load_backend_config() # path="aesop.config.json" by default
254
+
255
+ # Instantiate the driver (offline-safe; no API key required at build time)
256
+ driver = build_driver(config)
257
+
258
+ # Describe the backend for logging
259
+ print(describe_backend(config))
260
+ # Example output: "claude-code: parallel=1 wfs=1 ... tier=1"
261
+ ```
262
+
263
+ **Claude Code** (production):
264
+ ```json
265
+ {
266
+ "backend": "claude"
267
+ }
268
+ ```
269
+ - Haiku workers, Tier 1 verification
270
+ - No API key needed (Claude Code manages auth)
271
+ - Recommended for production
272
+
273
+ **OpenAI Codex** (experimental):
274
+ ```json
275
+ {
276
+ "backend": "codex",
277
+ "model": "gpt-3.5-turbo"
278
+ }
279
+ ```
280
+ - Requires `OPENAI_API_KEY` environment variable set
281
+ - Tier 2 verification (validate all JSON, spot-check, repair budget)
282
+ - Cheaper than Claude but needs higher orchestrator burden
283
+
284
+ **OpenAI-compatible hosted model** (OpenRouter, experimental):
285
+ ```json
286
+ {
287
+ "backend": "openai-compatible",
288
+ "base_url": "https://openrouter.ai/api/v1",
289
+ "model": "openai/gpt-4-turbo",
290
+ "api_key_env": "OPENROUTER_API_KEY"
291
+ }
292
+ ```
293
+ - Requires the named environment variable set
294
+ - Tier 2 verification (hosted strong model)
295
+ - Supports any OpenAI-compatible endpoint (OpenRouter, Together, etc.)
296
+
297
+ **OpenAI-compatible local model** (Ollama, experimental):
298
+ ```json
299
+ {
300
+ "backend": "openai-compatible",
301
+ "base_url": "http://localhost:11434/v1",
302
+ "model": "neural-chat",
303
+ "is_local": true
304
+ }
305
+ ```
306
+ - No API key required (uses dummy `local-only` if not set)
307
+ - Tier 3 verification (local small model: validate all, heavy spot-check, adversarial review)
308
+ - Requires `ollama serve` running on localhost:11434
309
+
310
+ **How to run**:
311
+
312
+ 1. Copy `driver/aesop.config.example.json` to `aesop.config.json` in the repo root
313
+ 2. Edit `aesop.config.json` to select a backend and set any required fields
314
+ 3. For non-Claude backends, set the API key environment variable:
315
+ ```bash
316
+ export OPENAI_API_KEY=sk-... # for Codex
317
+ export OPENROUTER_API_KEY=sk-... # for OpenRouter
318
+ # Ollama needs no key
319
+ ```
320
+ 4. Run aesop; the orchestration loop loads the config and instantiates the driver (from backend_config):
321
+ ```python
322
+ from backend_config import load_backend_config, build_driver
323
+
324
+ config = load_backend_config()
325
+ driver = build_driver(config)
326
+ # Pass driver to wave orchestration loop
327
+ ```
328
+
329
+ **Testing**: All drivers build offline (no API key required at import or build
330
+ time). Keys are read from `os.environ` only at dispatch time if a live call is
331
+ made. Tests can inject a `FakeTransport` to avoid network entirely.
332
+
333
+ ### Wiring verification tier into a wave manifest
334
+
335
+ When building a manifest for `wave-flat-dispatch.template.mjs`, the backend's
336
+ verification policy is RESOLVED in Python (via `build_manifest_item`) and baked
337
+ into the manifest as literal fields:
338
+
339
+ ```python
340
+ from wave_bridge import build_manifest_item
341
+
342
+ item = {
343
+ "slug": "fix-test",
344
+ "ownsFiles": ["test.py"],
345
+ "prompt": "Fix the test",
346
+ "testCmd": "python -m unittest test",
347
+ }
348
+
349
+ # build_manifest_item resolves ALL FOUR policy knobs from the driver's tier
350
+ # and includes them in the manifest as literal fields (no JS recomputation).
351
+ manifest_item = build_manifest_item(driver, item)
352
+
353
+ # Result includes:
354
+ # "model": "haiku" (from driver.resolve_model)
355
+ # "verificationTier": 1 (from driver.probe_capabilities)
356
+ # "repairCap": 1 (from verification_policy)
357
+ # "requireAdversarialReview": false (from verification_policy)
358
+ # "spotCheckFrac": 0.10 (from verification_policy)
359
+ # "validateAllJson": false (from verification_policy)
360
+ ```
361
+
362
+ The wave template **consumes these literal fields directly** — it does NOT
363
+ recompute the policy. This eliminates the JS/Python drift trap: the single source
364
+ of truth is Python's `verification_policy()` function; JS just uses the manifest
365
+ values. See `skills/buildsystem/wave-flat-dispatch.template.mjs` for the complete
366
+ template arguments and consumption logic.
367
+
368
+ Run the contract tests:
369
+
370
+ ```
371
+ python -m unittest tests.test_agent_driver
372
+ python -m unittest tests.test_codex_driver_e2e
373
+ python -m unittest tests.test_openai_compatible_driver
374
+ ```
375
+
376
+ ## Design constraints
377
+
378
+ - **stdlib-only** at this layer (`abc`, `dataclasses`, `typing`, `subprocess`).
379
+ Provider SDKs (`openai`, `ollama`, …) belong to the concrete adapters, added
380
+ in Phases 2–3 — the interface stays importable everywhere.
381
+ - **ASCII-only**, **Windows + Linux safe**.
382
+ - **Honest probes.** `DriverCapabilities` defaults are conservative (no native
383
+ abilities, accuracy 0.0, tier 4). A backend must *opt in* to each capability.
@@ -0,0 +1,80 @@
1
+ {
2
+ "comment": "Aesop backend configuration examples. DO NOT include secrets in the actual aesop.config.json; use environment variables instead.",
3
+ "examples": [
4
+ {
5
+ "name": "Claude Code (default)",
6
+ "backend": "claude",
7
+ "description": "Default backend: runs aesop through Claude Code Workflow harness. No API key needed (Claude Code manages auth). Tier 1 verification."
8
+ },
9
+ {
10
+ "name": "OpenAI Codex / Chat Completions",
11
+ "backend": "codex",
12
+ "model": "gpt-3.5-turbo",
13
+ "description": "Uses OpenAI's Chat Completions API. Set OPENAI_API_KEY environment variable before running. Tier 2 verification (validate all JSON, spot-check, repair budget).",
14
+ "optional_fields": {
15
+ "model": "gpt-4-turbo for stronger verification",
16
+ "max_owned_bytes": 200000,
17
+ "max_retries": 2,
18
+ "timeout_s": 120.0
19
+ }
20
+ },
21
+ {
22
+ "name": "OpenAI-compatible (OpenRouter hosted)",
23
+ "backend": "openai-compatible",
24
+ "base_url": "https://openrouter.ai/api/v1",
25
+ "model": "openai/gpt-4-turbo",
26
+ "api_key_env": "OPENROUTER_API_KEY",
27
+ "description": "OpenAI-compatible endpoint on OpenRouter (a model aggregator). Set OPENROUTER_API_KEY environment variable. Tier 2 verification (hosted strong model).",
28
+ "optional_fields": {
29
+ "is_local": false,
30
+ "max_owned_bytes": 200000,
31
+ "max_retries": 2,
32
+ "timeout_s": 120.0
33
+ }
34
+ },
35
+ {
36
+ "name": "OpenAI-compatible (local Ollama)",
37
+ "backend": "openai-compatible",
38
+ "base_url": "http://localhost:11434/v1",
39
+ "model": "neural-chat",
40
+ "is_local": true,
41
+ "description": "Local/small open model via Ollama (no API key required, or dummy 'local-only' used). Tier 3 verification (validate all output, heavy spot-check, adversarial review).",
42
+ "optional_fields": {
43
+ "api_key_env": "OPENAI_API_KEY",
44
+ "max_owned_bytes": 200000,
45
+ "max_retries": 2,
46
+ "timeout_s": 120.0
47
+ }
48
+ },
49
+ {
50
+ "name": "OpenAI-compatible (Together.AI)",
51
+ "backend": "openai-compatible",
52
+ "base_url": "https://api.together.xyz/v1",
53
+ "model": "meta-llama/Llama-2-70b-chat",
54
+ "api_key_env": "TOGETHER_API_KEY",
55
+ "description": "OpenAI-compatible endpoint on Together AI. Set TOGETHER_API_KEY environment variable. Tier 2 verification (hosted model).",
56
+ "optional_fields": {
57
+ "is_local": false,
58
+ "max_owned_bytes": 200000,
59
+ "max_retries": 2,
60
+ "timeout_s": 120.0
61
+ }
62
+ }
63
+ ],
64
+ "production_config": {
65
+ "backend": "claude",
66
+ "comment": "Recommended production configuration: Claude Code with Haiku workers, Tier 1 verification. Drop this into aesop.config.json (removing comments) to use."
67
+ },
68
+ "experimental_codex": {
69
+ "backend": "codex",
70
+ "model": "gpt-3.5-turbo",
71
+ "comment": "Experimental Codex backend. Requires OPENAI_API_KEY set. Tier 2 verification."
72
+ },
73
+ "experimental_ollama": {
74
+ "backend": "openai-compatible",
75
+ "base_url": "http://localhost:11434/v1",
76
+ "model": "neural-chat",
77
+ "is_local": true,
78
+ "comment": "Experimental local Ollama backend. Requires 'ollama serve' running on localhost:11434. No API key needed (dummy 'local-only' used). Tier 3 verification."
79
+ }
80
+ }