@enderfga/claw-orchestrator 7.15.0 → 7.16.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 (41) hide show
  1. package/README.md +6 -4
  2. package/dist/bin/cli.js +13 -6
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/src/autoloop/dispatcher.js +50 -9
  5. package/dist/src/autoloop/dispatcher.js.map +1 -1
  6. package/dist/src/claude-goal-session.d.ts +147 -0
  7. package/dist/src/claude-goal-session.js +355 -0
  8. package/dist/src/claude-goal-session.js.map +1 -0
  9. package/dist/src/council.js +2 -1
  10. package/dist/src/council.js.map +1 -1
  11. package/dist/src/index.js +20 -4
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/kernel/agent-step.d.ts +6 -0
  14. package/dist/src/kernel/agent-step.js.map +1 -1
  15. package/dist/src/kernel/nodes/goal.d.ts +11 -4
  16. package/dist/src/kernel/nodes/goal.js +41 -15
  17. package/dist/src/kernel/nodes/goal.js.map +1 -1
  18. package/dist/src/kernel/templates/index.d.ts +10 -8
  19. package/dist/src/kernel/templates/index.js +6 -5
  20. package/dist/src/kernel/templates/index.js.map +1 -1
  21. package/dist/src/kernel/types.d.ts +7 -3
  22. package/dist/src/kernel/types.js.map +1 -1
  23. package/dist/src/models.js +8 -0
  24. package/dist/src/models.js.map +1 -1
  25. package/dist/src/persistent-agy-session.js +4 -0
  26. package/dist/src/persistent-agy-session.js.map +1 -1
  27. package/dist/src/persistent-session.d.ts +9 -0
  28. package/dist/src/persistent-session.js +23 -0
  29. package/dist/src/persistent-session.js.map +1 -1
  30. package/dist/src/session-manager.d.ts +11 -0
  31. package/dist/src/session-manager.js +39 -4
  32. package/dist/src/session-manager.js.map +1 -1
  33. package/package.json +1 -1
  34. package/skills/references/autoloop.md +7 -3
  35. package/skills/references/claude-cli-tracking.md +3 -1
  36. package/skills/references/cli.md +22 -20
  37. package/skills/references/council.md +11 -0
  38. package/skills/references/multi-engine.md +6 -5
  39. package/skills/references/tools.md +20 -12
  40. package/skills/references/verification.md +0 -2
  41. package/skills/references/workflow.md +60 -16
@@ -348,9 +348,13 @@ compact, through the app-server's own thread compaction.
348
348
  Subprocess deaths (Claude session lost), failed `git commit` in an iter, and
349
349
  other phase-bound failures surface as `phase_error` messages instead of
350
350
  silently masquerading as a "clarification request". An empty or whitespace-only
351
- Coder reply is also a phase error. Only a non-empty reply without
352
- `iter_complete` is treated as a clarification request. The runner counts
353
- consecutive `phase_error`s and:
351
+ Coder reply is also a phase error. A non-empty Coder reply without a valid
352
+ `iter_complete` returns `directive_ack` (`understood: false`) without review or
353
+ iteration advance. Structured `request_clarification` keeps a short
354
+ `clarification` question. Any other incomplete turn puts fixed status/decision
355
+ wording, a labelled sanitized truncated reply tail, and a write-time persisted
356
+ path (`iter/<n>/coder_reply_<dispatch_id>.txt`) or generic not-persisted result
357
+ into `clarification`. The runner counts consecutive `phase_error`s and:
354
358
 
355
359
  1. Fires `on_phase_error` on each one (defaults to error / both channels).
356
360
  2. After `phaseErrorCircuit` consecutive errors (default **3**) emits a
@@ -2,12 +2,14 @@
2
2
 
3
3
  This document tracks which Claude Code CLI version Claw Orchestrator is currently synced to, and which features have been integrated. Recent rows also record the other engines' versions checked in the same sync.
4
4
 
5
- ## Currently tracked: **Claude Code CLI 2.1.310** (as of 2026-10-26, plugin v7.15.0)
5
+ ## Currently tracked: **Claude Code CLI 2.1.316** (as of 2026-10-31, plugin v7.16.1)
6
6
 
7
7
  ## Sync history
8
8
 
9
9
  | Plugin Version | Claude CLI Version | Date | Notable integrations |
10
10
  | ------------------- | ------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | v7.16.1 | 2.1.316 | 2026-10-31 | CC 2.1.310→2.1.316, Codex 0.164.0→0.166.0, agy 1.4.6→1.4.12, OpenCode 1.19.4→1.19.5; grok 1.0.70 unchanged. One live turn per engine through its wrapper ok; 27 models checked against published prices, 0 drift. Integrated: agy `--settings` (1.4.12, inline JSON or a path; agy validates the keys); GPT-6.1 Terra (Codex 0.165.0). Read, no change needed: CC `CLAUDE_CODE_SUBAGENT_EFFORT`, `permissions.blockWritesOutsideWorkingDirectories`; Codex 0.165 effort changes mid-conversation on by default (codex-app already sends effort per turn); dsh 0.2.1-rc.4 keeps diagnostics off stdout in ACP mode. |
12
+ | v7.16.0 | 2.1.310 | 2026-10-28 | Pins as tracked in v7.15.0; not re-run live this release (installed: CC 2.1.312, Codex 0.165.0, agy 1.4.9). Integrated: `/goal` on Claude Code behind the `goal` node — measured on CC 2.1.312 in stream-json mode (bare `/goal` probe, Stop-hook turns, `interrupt` control request). |
11
13
  | v7.15.0 | 2.1.310 | 2026-10-26 | Engine versions as tracked in v7.14.0 (agy 1.4.7 is installed but not yet run live; the pin stays 1.4.6). Integrated: `codex-app` passes reasoning effort — `turn/start` `effort` and `model_reasoning_effort` in the thread `config` on `thread/start` / `thread/resume` (Codex 0.164.0). |
12
14
  | v7.14.0 | 2.1.310 | 2026-10-25 | CC 2.1.307→2.1.310, agy 1.4.4→1.4.6, grok 1.0.67→1.0.70, OpenCode 1.19.3→1.19.4; Codex 0.164.0 unchanged. No flag the wrappers pass changed; one live turn per engine ok. Integrated: the `acp` engine (an ACP client over `@agentclientprotocol/sdk` 1.3.0), run against Kimi Code 2.3.1 (`kimi acp`, model from `KIMI_MODEL_*`), dsh 0.2.1-rc.2 (`dsh --profile acp`, `--patch` honoured) and OpenCode 1.19.4 (`opencode acp`, recall across a resumed session). Kimi Code and dsh report no usage over ACP. |
13
15
  | v7.13.0 | 2.1.307 | 2026-10-24 | Codex 0.163.0→0.164.0; the other engines as tracked in v7.12.1. Integrated: Codex 0.164 app-server goal RPCs (`thread/goal/set` / `get` / `clear`, six goal states, `tokenBudget`, `thread/goal/updated`), structured `error` notifications (`codexErrorInfo`, `willRetry`), `turn/steer` during goal turns, and `approvalPolicy` on `thread/start` / `thread/resume`; the `goal` workflow node is built on them. Measured: a goal objective is capped at 4,000 characters, and a thread can be resumed only after its first turn. |
@@ -263,34 +263,36 @@ clawo fanout "<task>" [--engines <list>] [--synthesize] [--check "<command>"]...
263
263
 
264
264
  ## `clawo goal`
265
265
 
266
- Run a Codex `/goal` on one `codex-app` thread, then have the runtime check the
267
- result: goal → verify → repair on the same thread. See [workflow.md](./workflow.md#goal).
266
+ Run a `/goal` on one thread — a Codex `codex-app` thread, or a Claude Code
267
+ session with `--engine claude` — then have the runtime check the result: goal →
268
+ verify → repair on the same thread. See [workflow.md](./workflow.md#goal).
268
269
 
269
270
  ```bash
270
271
  clawo goal "<objective>" | --objective-file <file>
271
272
  [--check "<command>"]... [--contract <file>] [--check-timeout <minutes>]
272
- [--launcher <arg>]... [--model <model>] [--effort <level>] [--sandbox <mode>] [--thread <id>]
273
+ [--engine codex|claude] [--launcher <arg>]... [--model <model>] [--effort <level>] [--sandbox <mode>] [--thread <id>]
273
274
  [--token-budget N] [--goal-timeout <minutes>] [--max-repairs N]
274
275
  [--cwd <dir>] [--wait] [--json]
275
276
  ```
276
277
 
277
- | Option | Default | Notes |
278
- | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------- |
279
- | `--objective-file` | — | Read the objective from a file instead of the argument. Codex accepts at most 4,000 characters |
280
- | `-c, --check` | — | A command check, repeatable, run after the goal. Split on whitespace; quote-needing commands go in `--contract` |
281
- | `--contract` | — | A contract JSON file; `--check` entries are appended to it |
282
- | `--check-timeout` | 10 | Minutes for each `--check` (at least 1). The verifier's node timeout is sized from the checks |
283
- | `--launcher` | — | Run codex under this command, one argv element per flag: `--launcher ./sandbox.sh --launcher task --launcher "0 1"` |
284
- | `-m, --model` | codex's own | Codex model |
285
- | `--effort` | codex's own | Codex reasoning effort |
286
- | `--sandbox` | `workspace-write` | Codex's own sandbox mode. With an outer sandbox as the boundary, `danger-full-access` |
287
- | `--thread` | — | Start on this existing codex thread: its goal is replaced, its history kept |
288
- | `--token-budget` | — | The goal stops as `budgetLimited` past this |
289
- | `--goal-timeout` | none | Wall-clock minutes for one goal pass |
290
- | `--max-repairs` | `1` | Times a red verdict sends the goal back to the same thread |
291
- | `--cwd` | current directory | Project directory |
292
- | `-w, --wait` | off | Follow the run; exit `0` only if it completes |
293
- | `--json` | off | Print `{ runId, state }`, or with `--wait` the final run record |
278
+ | Option | Default | Notes |
279
+ | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
280
+ | `--objective-file` | — | Read the objective from a file instead of the argument. A goal accepts at most 4,000 characters |
281
+ | `-e, --engine` | `codex` | Who runs the goal: `codex` (a `codex-app` thread) or `claude` (a Claude Code session) |
282
+ | `-c, --check` | — | A command check, repeatable, run after the goal. Split on whitespace; quote-needing commands go in `--contract` |
283
+ | `--contract` | — | A contract JSON file; `--check` entries are appended to it |
284
+ | `--check-timeout` | 10 | Minutes for each `--check` (at least 1). The verifier's node timeout is sized from the checks |
285
+ | `--launcher` | — | Run the engine under this command, one argv element per flag: `--launcher ./sandbox.sh --launcher task --launcher "0 1"` |
286
+ | `-m, --model` | the engine's own | Model |
287
+ | `--effort` | the engine's own | Reasoning effort |
288
+ | `--sandbox` | `workspace-write` | Codex's own sandbox mode (claude has none). With an outer sandbox as the boundary, `danger-full-access` |
289
+ | `--thread` | — | Start on this existing codex thread or claude session: its goal is replaced, its history kept |
290
+ | `--token-budget` | — | The goal stops as `budgetLimited` past this |
291
+ | `--goal-timeout` | none | Wall-clock minutes for one goal pass |
292
+ | `--max-repairs` | `1` | Times a red verdict sends the goal back to the same thread |
293
+ | `--cwd` | current directory | Project directory |
294
+ | `-w, --wait` | off | Follow the run; exit `0` only if it completes |
295
+ | `--json` | off | Print `{ runId, state }`, or with `--wait` the final run record |
294
296
 
295
297
  `clawo workflow show <runId>` prints the goal's status, tokens, time, resume
296
298
  attempts and thread id while it runs; `clawo workflow steer <runId> "<text>"`
@@ -229,6 +229,17 @@ The charter is each seat's only instruction channel, and it reaches every engine
229
229
  natively on Claude Code and Grok, as the top of the seat's first message on Codex, Antigravity and OpenCode.
230
230
  Nothing is written into the worktrees.
231
231
 
232
+ ## Member session names
233
+
234
+ Each council member starts an internal `SessionManager` session named
235
+ `{councilRunId}-{memberName}-r{round}` (for example
236
+ `council-m1abc2de-9f3c1a2b-Architect-r1`). The name carries the complete council
237
+ run id so two concurrent councils that share a member name and round do not
238
+ reuse one engine session, working directory, or cleanup target. `sessionKey` on
239
+ each agent response is that opaque name; callers should treat it as an opaque
240
+ handle, not parse it. `parentRunId` on ledger turns remains the full council run
241
+ id.
242
+
232
243
  ## Transcript Logging
233
244
 
234
245
  All council sessions save transcripts to `~/.openclaw/council-logs/council-<timestamp>.md`. Transcripts are for humans to read; nothing parses them. Completed councils stay queryable via `council_status` indefinitely — the run record is on disk.
@@ -45,7 +45,7 @@ as options (see the notes under [Antigravity](#google-antigravity-engine-agy) an
45
45
 
46
46
  ### Claude Code (`engine: 'claude'`)
47
47
 
48
- Default engine. Long-running subprocess with streaming JSON I/O. Tested with Claude Code CLI **2.1.310**.
48
+ Default engine. Long-running subprocess with streaming JSON I/O. Tested with Claude Code CLI **2.1.316**.
49
49
 
50
50
  - Persistent multi-turn conversations
51
51
  - Real-time streaming (text, tool_use, tool_result, system events)
@@ -82,7 +82,7 @@ await manager.startSession({
82
82
 
83
83
  ### OpenAI Codex (`engine: 'codex'`)
84
84
 
85
- Wraps the `codex exec` subcommand. Each `send()` spawns a new process. Tested with `codex` CLI **0.164.0**.
85
+ Wraps the `codex exec` subcommand. Each `send()` spawns a new process. Tested with `codex` CLI **0.166.0**.
86
86
 
87
87
  - Non-interactive execution via `codex exec --sandbox workspace-write --skip-git-repo-check --json`
88
88
  - Real `usage` from the `turn.completed` JSON event (input, output, cached, reasoning tokens). **These are cumulative over the thread, not per turn**, so they replace the session totals rather than being added to them; subtracting consecutive values gives one turn's prompt
@@ -120,7 +120,7 @@ await manager.startSession({
120
120
 
121
121
  ### OpenAI Codex App-Server (`engine: 'codex-app'`)
122
122
 
123
- Wraps `codex app-server --listen stdio:// --enable goals` as a long-running JSON-RPC subprocess. **Required for `/goal` long-horizon objective support** — Codex's exec subcommand has no goal surface. Tested with `codex` CLI **0.164.0**.
123
+ Wraps `codex app-server --listen stdio:// --enable goals` as a long-running JSON-RPC subprocess. **Required for `/goal` long-horizon objective support** — Codex's exec subcommand has no goal surface. Tested with `codex` CLI **0.166.0**.
124
124
 
125
125
  - Long-running subprocess; one `codex app-server` per session
126
126
  - JSON-RPC 2.0 over stdio with v2 protocol method names (`initialize`, `thread/start`, `turn/start`, ...)
@@ -152,7 +152,7 @@ await manager.codexGoal('codex-goal-task', { action: 'set', objective: 'build a
152
152
 
153
153
  Wraps Google's **Antigravity CLI** (`agy`) — the successor to Gemini CLI (consumer
154
154
  Gemini CLI tiers stopped serving 2026-06-18). Each `send()` spawns a new process
155
- in print mode, with the message as the `-p` argument. Tested with `agy` **1.4.6**.
155
+ in print mode, with the message as the `-p` argument. Tested with `agy` **1.4.12**.
156
156
 
157
157
  - One-shot execution per message (no persistent subprocess)
158
158
  - **Structured output and real usage** — `--output-format stream-json` emits an
@@ -196,6 +196,7 @@ in print mode, with the message as the `-p` argument. Tested with `agy` **1.4.6*
196
196
  must explicitly choose `bypassPermissions` for a write-enabled session; it is
197
197
  not a recovery mechanism. In particular, an Autoloop Planner stays on
198
198
  `--mode plan` when its preserved conversation is resumed.
199
+ - `settings` is passed as `--settings`: settings.json keys as inline JSON or a file path, for this run only. agy refuses a key it does not know.
199
200
  - The engine always passes `--print-timeout`, set just inside the send timeout
200
201
  (10% earlier, at most 10s). Since agy 1.2.9 a headless run whose agent started a
201
202
  background task (a dev server, a watcher) stays open until that deadline and
@@ -304,7 +305,7 @@ await manager.startSession({
304
305
 
305
306
  ### OpenCode (`engine: 'opencode'`)
306
307
 
307
- Wraps the [OpenCode](https://github.com/anomalyco/opencode) CLI with `run --format json`. Each `send()` spawns a new process. Tested with `opencode` **1.19.4**.
308
+ Wraps the [OpenCode](https://github.com/anomalyco/opencode) CLI with `run --format json`. Each `send()` spawns a new process. Tested with `opencode` **1.19.5**.
308
309
 
309
310
  - Conversation continuity: the session id from the event envelope is captured and passed back as `--session <id>` on later sends, so the model sees prior turns. `--continue` is deliberately not used: it means "the last session on this machine", which collides between concurrent sessions.
310
311
  - NDJSON event stream with envelope `{ type, timestamp, sessionID, ... }`
@@ -35,7 +35,7 @@ else the value applies.
35
35
  | `resumeSessionId` | string | Resume an earlier conversation by the engine's own id: a Claude Code session id, a Codex or `codex-app` thread id, an Antigravity conversation id, a Grok or OpenCode session id, an ACP agent's session id, or a custom engine's id when its config maps a resume flag |
36
36
  | `jsonSchema` | string | JSON Schema for structured output. Claude and Grok: `--json-schema` (inline). Codex: `--output-schema` (written to a temp file, requires Codex 0.132+). Other engines ignore it. |
37
37
  | `mcpConfig` | string \| string[] | MCP server config file(s) |
38
- | `settings` | string | Settings.json path or inline JSON |
38
+ | `settings` | string | Settings.json path or inline JSON, for this session only. Claude Code and Antigravity (`agy --settings`, which validates its keys) take it |
39
39
  | `pluginUrl` | string \| string[] | Claude only. Plugin `.zip` URL(s) fetched for this session only (`--plugin-url`) |
40
40
  | `ultracode` | boolean | Claude only. Enable "ultracode" / dynamic workflows — Claude plans a JS orchestration script per substantive task and fans out to subagents. Injected as the `ultracode:true` settings key (merged into `settings`). The workflow runs in the background: `session_send` returns at launch, and the completion turn is not returned by a later send (see [sessions.md](./sessions.md#ultracode-claude-dynamic-workflows)). |
41
41
  | `noSessionPersistence` | boolean | Do not save session to disk — both the engine's own transcript and this orchestrator's resume registry, so a later start under the same name does not reattach |
@@ -370,23 +370,31 @@ Run one task across N engine/model agents **in parallel** and collect their answ
370
370
 
371
371
  ### `fanout_start`
372
372
 
373
- | Parameter | Type | Required | Description |
374
- | ------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
375
- | `task` | string | yes | Shared task sent to every agent, optionally after its `persona`. |
376
- | `projectDir` | string | yes | Working directory all agents run in. |
377
- | `agents` | array | yes | Up to 16 specs: `{ name, engine?, model?, effort?, prompt?, persona?, baseUrl?, permissionMode?, customEngine?, acpAgent? }`. Names must be unique (each forms a session name); `permissionMode` defaults to `bypassPermissions`. |
378
- | `synthesize` | boolean | | Run a final synthesis pass over the successful results (needs ≥2). |
379
- | `synthesisModel` / `synthesisEngine` | string | | Model/engine for the synthesis pass (default engine `claude`). |
380
- | `synthesisAcpAgent` | string | | With `synthesisEngine: 'acp'`: the ACP agent preset the synthesis pass starts. |
381
- | `agentTimeoutMs` | number | | Per-agent timeout (default 600000). |
382
- | `maxTurnsPerAgent` | number | | Max agent loop turns (default 30). |
383
- | `maxBudgetUsd` | number | | Per-agent spend cap. |
373
+ | Parameter | Type | Required | Description |
374
+ | ------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
375
+ | `task` | string | yes | Shared task sent to every agent, optionally after its `persona`. |
376
+ | `projectDir` | string | yes | Working directory all agents run in. |
377
+ | `agents` | array | yes | Up to 16 specs: `{ name, engine?, model?, effort?, prompt?, persona?, baseUrl?, permissionMode?, sandboxMode?, customEngine?, acpAgent? }`. Names must be unique (each forms a session name); `permissionMode` defaults to `bypassPermissions`. |
378
+ | `synthesize` | boolean | | Run a final synthesis pass over the successful results (needs ≥2). |
379
+ | `synthesisModel` / `synthesisEngine` | string | | Model/engine for the synthesis pass (default engine `claude`). |
380
+ | `synthesisAcpAgent` | string | | With `synthesisEngine: 'acp'`: the ACP agent preset the synthesis pass starts. |
381
+ | `agentTimeoutMs` | number | | Per-agent timeout (default 600000). |
382
+ | `maxTurnsPerAgent` | number | | Max agent loop turns (default 30). |
383
+ | `maxBudgetUsd` | number | | Per-agent spend cap. |
384
384
 
385
385
  Runs in the background; returns `{ ok, id, status, ... }`. Poll with `fanout_status`.
386
386
  Each agent's optional `effort` accepts `low`, `medium`, `high`, `xhigh`, `max`,
387
387
  `ultra`, or `auto`. Omit it to keep the session default. The engine applies or
388
388
  clamps the value as documented for `session_start`.
389
389
 
390
+ Per-agent `permissionMode` uses the same enum and each engine's own permission
391
+ handling as `session_start`. Workers that must not write should set
392
+ `sandboxMode` to `read-only`. Per-agent `sandboxMode` (`read-only` \|
393
+ `workspace-write` \| `danger-full-access`) uses the same values and per-engine
394
+ behavior as `session_start` (omit to keep the session default). These worker
395
+ fields do not constrain optional synthesis, and `fanout_start` does not expose a
396
+ synthesis permission override.
397
+
390
398
  Per-agent `persona` provides role instructions without replacing the shared
391
399
  task. Fan-out sends `<persona>\n\n## Shared task\n\n<task>`. A non-empty
392
400
  per-agent `prompt` keeps its original full-override semantics: it is sent by
@@ -20,8 +20,6 @@ goes through `normalizeContract()`, which drops anything it does not recognise,
20
20
  it carries no fields the executor did not model; one with no recognised check is
21
21
  refused before the run starts. That argument takes each check bare,
22
22
  `{ "type": "command", … }`, or wrapped, `{ "id"?, "spec": { … }, "required"? }`.
23
- A contract written inside a spec — `spec.contract`, or a verifier's inline
24
- `contract` — is used as written, so its checks must be in the wrapped form.
25
23
 
26
24
  A workflow start normalises every contract the run carries the same way: the
27
25
  `contract` start option, the spec's own `contract`, and each verifier node's
@@ -157,12 +157,12 @@ is unrecoverable and reads back as "not found".
157
157
  | `agent` | One session, one turn. A new session per attempt unless `sessionName` pins one |
158
158
  | `fanout` | N agents in parallel on a shared prompt, optional synthesis pass. Succeeds when at least one agent does |
159
159
  | `council` | The council engine; its votes are recorded as advisory. Fails only when the council itself errors |
160
- | `verifier` | Runs an acceptance contract, writes evidence — see [`verification.md`](./verification.md). `"contract": "run"` with no run-level contract passes through and verifies nothing; an inline contract with no recognised check is refused at start |
160
+ | `verifier` | Runs an acceptance contract, writes evidence — see [`verification.md`](./verification.md). `"contract": "run"` with no run-level contract passes through and verifies nothing; an inline contract with no recognised check is refused at start |
161
161
  | `human_gate` | Parks the run until a person answers; a rejection fails the run |
162
162
  | `router` | Picks the next node from declarative conditions; a backwards route is the loop |
163
163
  | `subflow` | Runs another workflow as a child run and adopts its verdict, with the tree digest the verdict was taken against; a child that ends `unverified` hands up no verdict |
164
164
  | `autoloop` | A long-lived Planner / Coder / Reviewer loop; its executor is injected. On the node's first visit (`visits === 1`) the shared fresh-start boundary applies (dirty-worktree refusal + run-local `tasks/<config.runId>/.gitignore`); resume and later visits skip it. |
165
- | `goal` | A Codex `/goal` on one `codex-app` thread, run until the goal finishes — see [below](#goal) |
165
+ | `goal` | A `/goal` on one Codex `codex-app` thread or Claude Code session, run until the goal finishes — see [below](#goal) |
166
166
  | `ultraapp_synth`, `ultraapp_deploy` | UltraApp's synth and deploy stages; their executors are injected too |
167
167
 
168
168
  ### Spec and node fields
@@ -194,12 +194,12 @@ The kind-specific fields:
194
194
  | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
195
195
  | `agent` | `prompt` (required); `engine`, `model`, `effort`, `acpAgent` (a bundled ACP preset id, for `engine: "acp"`); `cwd` (default: the run's); `sessionName`, to reuse one named session across nodes; `permissionMode` (default `bypassPermissions`); `appendSystemPrompt`, standing instructions for the session |
196
196
  | `fanout` | `prompt` (required, the shared task) and `agents` (required); `synthesize`, `synthesisEngine` (default `claude`), `synthesisModel`, `synthesisAcpAgent`, `synthesisPermissionMode` (default `bypassPermissions`); `maxTurnsPerAgent` and `maxBudgetUsd`, per agent; `cwd`; `agentTimeoutMs` |
197
- | `council` | `task` (required) and `agents` (required); `projectDir` (default: the run's cwd); `maxRounds` (default 15, as for `council_start`); `maxTurnsPerAgent` and `maxBudgetUsd`, per agent; `defaultPermissionMode`; `agentTimeoutMs` |
197
+ | `council` | `task` (required) and `agents` (required); `projectDir` (default: the run's cwd); `maxRounds` (default 15, as for `council_start`); `maxTurnsPerAgent` and `maxBudgetUsd`, per agent; `defaultPermissionMode`; `agentTimeoutMs` |
198
198
  | `verifier` | `contract` (required): an inline contract, or `"run"` for the run-level one; `cwd` (default: the run's) |
199
199
  | `human_gate` | `prompt` (required) |
200
200
  | `router` | `routes` (required): `[{ "when": <condition>, "to": <node id> }]`, first match wins; `default`, taken when nothing matches (omitted: fall through to the next node) |
201
201
  | `subflow` | `workflow` (required): an inline `WorkflowSpec`, or the id of an existing run, whose stored spec runs again as a new child run. Template names do not resolve here |
202
- | `goal` | `objective` (required); `cwd`, `model`, `effort`, `sandboxMode`, `launcher`, `threadId`, `tokenBudget`, `capacityRetry`, `stallMs` — see [Goal](#goal) |
202
+ | `goal` | `objective` (required); `engine`, `cwd`, `model`, `effort`, `sandboxMode`, `launcher`, `threadId`, `tokenBudget`, `capacityRetry`, `stallMs` — see [Goal](#goal) |
203
203
  | `autoloop` | `workspace` and `config` (the `autoloop_start` options). Started by `autoloop_start` |
204
204
  | `ultraapp_synth`, `ultraapp_deploy` | `appRunId`, `runDir`, `slug`; the deploy stage adds `version` and `codebasePath`. Started by UltraApp builds |
205
205
 
@@ -306,11 +306,11 @@ with `visits_lt`.
306
306
  }
307
307
  ```
308
308
 
309
- A contract written inside a spec — the run-level `contract`, or a verifier's
310
- inline one — is used as written, so each check goes in the `{ "spec": { … } }`
311
- wrapper shown here, with `id` and `required` beside `spec`. The `contract` argument
312
- of `workflow_start` and `POST /workflow/new` is normalized first and also accepts
313
- bare checks (`{ "type": "command", … }`); when given, it replaces the spec's own.
309
+ Every contract a run carries — the run-level `contract`, a verifier's inline one,
310
+ and the `contract` argument of `workflow_start` and `POST /workflow/new` — is
311
+ normalized at start, so a check may be written bare (`{ "type": "command", … }`) or
312
+ in the `{ "spec": { … } }` wrapper shown here, with `id` and `required` beside
313
+ `spec`. The `contract` argument, when given, replaces the spec's own.
314
314
  See [`verification.md`](./verification.md#the-one-rule-about-where-contracts-come-from).
315
315
 
316
316
  When the router sends control back to `implement`, the agent is told what the
@@ -333,7 +333,7 @@ specs and post them.
333
333
  | `solve` | `triage` (fan-out) → `approve` (human gate, only with `humanGate`) → `implement` (agent) → `review` (fan-out, only with `reviewers`) → `verify` → `repair-gate` (router) | `agents` (the triage scouts; default one agent on the default engine), `implementer` (`engine`, `model`), `reviewers`, `humanGate`, `maxRepairs` (default 3), `contract` |
334
334
  | `council` | `council`, then `__verify` when a contract is declared | `agents`, `maxRounds` (default 15), `contract` |
335
335
  | `fanout` | `fanout`, then `__verify` when a contract is declared | `agents`, `contract` |
336
- | `goal` | `goal` → `verify` → `repair-gate` (router); `task` is the objective. See [below](#goal) | `model`, `tokenBudget`, `launcher`, `maxRepairs` (default 1), `contract` |
336
+ | `goal` | `goal` → `verify` → `repair-gate` (router); `task` is the objective. See [below](#goal) | `engine` (`codex` default, or `claude`), `model`, `tokenBudget`, `launcher`, `maxRepairs` (default 1), `contract` |
337
337
 
338
338
  `solve` is the shape above: the triage and review fan-outs add a synthesis pass
339
339
  when they have two or more agents, `implement` and `review` continue on failure so
@@ -349,16 +349,19 @@ somewhere to deploy to), which only UltraApp starts.
349
349
 
350
350
  ## Goal
351
351
 
352
- A `goal` node runs one Codex `/goal` on one `codex-app` thread. Codex's
353
- app-server runs the goal itself: `thread/goal/set` starts its turn loop, which
354
- keeps going until the goal is `complete`, out of budget, `blocked`, or stopped
355
- by a usage limit. The node adds what an unattended run needs around that loop.
352
+ A `goal` node runs one `/goal` on one thread: a Codex `codex-app` thread by
353
+ default, or a Claude Code session with `"engine": "claude"` (see
354
+ [On Claude Code](#on-claude-code)). Codex's app-server runs the goal itself:
355
+ `thread/goal/set` starts its turn loop, which keeps going until the goal is
356
+ `complete`, out of budget, `blocked`, or stopped by a usage limit. The node adds
357
+ what an unattended run needs around that loop.
356
358
 
357
359
  ```jsonc
358
360
  {
359
361
  "id": "goal",
360
362
  "kind": "goal",
361
363
  "objective": "Reach the goal described in GOAL.md …",
364
+ "engine": "codex", // default; or "claude"
362
365
  "cwd": "/work/task/ws",
363
366
  "model": "gpt-6.1-sol", // optional; codex's own default otherwise
364
367
  "effort": "high", // optional reasoning effort
@@ -417,6 +420,47 @@ by a usage limit. The node adds what an unattended run needs around that loop.
417
420
  reason. Cancel interrupts the running turn and pauses the goal, and so does a
418
421
  `timeoutMs` that runs out. Like `autoloop`, the node has no default timeout.
419
422
 
423
+ ### On Claude Code
424
+
425
+ With `"engine": "claude"` the same node drives Claude Code's `/goal` (CLI
426
+ 2.1.139 or later) through `ClaudeGoalSession`. Claude Code has no goal RPCs or
427
+ goal notifications, so the adapter reads the goal from what the CLI does in
428
+ stream-json mode:
429
+
430
+ - `/goal <objective>` sets the goal and starts working. A Stop hook — a separate
431
+ model judging the condition against the session — runs after every turn and
432
+ feeds the turn back while the condition does not hold, all inside one send;
433
+ one `result` arrives when the goal is met, and the goal clears itself.
434
+ - A bare `/goal` answers at once, without a model turn — `Goal active: …` or
435
+ `No goal set.` A failed turn clears the goal too, so a gone goal is not proof:
436
+ the goal is `complete` only when a turn that started with it set ended without
437
+ an error and it is gone after. A goal still set with nothing driving it, a
438
+ failed turn, and a reopened session whose goal is gone are `paused`, which the
439
+ node resumes within its bound. Resuming sends a short "continue" message when
440
+ the goal is still set and sets it again (`/goal <objective>`) when it is not,
441
+ so a goal that was already met costs one turn to confirm.
442
+ - A failed turn is read from its text: usage limits become `usageLimited`,
443
+ overloaded and 5xx errors the matching transient codes, so the node backs off
444
+ and resumes as it does for Codex. A failed login is `blocked` at once.
445
+ - When the Stop hook blocks the agent's stop nine times running, the CLI ends
446
+ the turn anyway and says so; the goal is then `blocked` (the agent keeps
447
+ asking to stop, and continuing only repeats that). The template's verifier
448
+ still judges the tree. Write the objective as a condition the agent can show
449
+ it met from inside the session; one that depends on something after the
450
+ agent stops can never be met.
451
+ - The session id is the thread id. A new session is started with
452
+ `--session-id` so it is known before the goal is set, and the session is kept
453
+ out of the registry with `skipPersistence` (not `noSessionPersistence`, which
454
+ would stop the CLI writing the transcript `--resume` needs). A reopened
455
+ process resumes it with `--resume`; the goal is still set there, so the node
456
+ continues it at once.
457
+ - Steers are written into the running turn, which the CLI folds in. Cancel and
458
+ pause send stream-json's `interrupt` control request; the goal stays set.
459
+ - `tokensUsed` counts the session's input, output and cache-read tokens, and is
460
+ carried across reopened processes. `tokenBudget` counts from when the current
461
+ objective was set; past it the turn is interrupted and the goal ends
462
+ `budgetLimited`. `sandboxMode` does not apply; put the boundary in `launcher`.
463
+
420
464
  The `goal` template wraps this in `goal → verify → repair-gate`. The goal node
421
465
  continues on failure, so a goal that ran out of budget is still judged. The
422
466
  verifier's node timeout is sized from the contract — the sum of every check's
@@ -472,8 +516,8 @@ which is not the same as success.
472
516
  The implicit `__verify` is the last node, and a run only ends `completed` after
473
517
  its last node has run, so every such path is checked. A spec that places its own
474
518
  `"contract": "run"` verifier gets no `__verify`, and must route every path through
475
- that node: a run whose path skips it ends `completed` / `unverified`, with no
476
- check run.
519
+ that node: a run whose path skips it ends `failed` / `unverified`, with no check
520
+ run (see below).
477
521
 
478
522
  A run whose spec declares a run-level `contract` cannot complete without having
479
523
  run it. The kernel appends a terminal verifier unless the spec places its own