@enderfga/claw-orchestrator 7.12.0 → 7.13.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 (76) hide show
  1. package/README.md +6 -4
  2. package/dist/bin/cli.js +66 -6
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/src/autoloop/dispatcher.d.ts +19 -0
  5. package/dist/src/autoloop/dispatcher.js +57 -0
  6. package/dist/src/autoloop/dispatcher.js.map +1 -1
  7. package/dist/src/autoloop/runner.d.ts +102 -2
  8. package/dist/src/autoloop/runner.js +367 -44
  9. package/dist/src/autoloop/runner.js.map +1 -1
  10. package/dist/src/autoloop/types.d.ts +17 -0
  11. package/dist/src/autoloop/types.js.map +1 -1
  12. package/dist/src/dashboard/index.html +79 -73
  13. package/dist/src/embedded-server.js +28 -5
  14. package/dist/src/embedded-server.js.map +1 -1
  15. package/dist/src/engine-spawn.d.ts +8 -1
  16. package/dist/src/engine-spawn.js +13 -3
  17. package/dist/src/engine-spawn.js.map +1 -1
  18. package/dist/src/index.js +58 -69
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/kernel/agent-step.d.ts +3 -0
  21. package/dist/src/kernel/agent-step.js.map +1 -1
  22. package/dist/src/kernel/engine.d.ts +5 -2
  23. package/dist/src/kernel/engine.js +11 -12
  24. package/dist/src/kernel/engine.js.map +1 -1
  25. package/dist/src/kernel/nodes/autoloop.d.ts +32 -2
  26. package/dist/src/kernel/nodes/autoloop.js +122 -15
  27. package/dist/src/kernel/nodes/autoloop.js.map +1 -1
  28. package/dist/src/kernel/nodes/goal.d.ts +94 -0
  29. package/dist/src/kernel/nodes/goal.js +386 -0
  30. package/dist/src/kernel/nodes/goal.js.map +1 -0
  31. package/dist/src/kernel/nodes/index.d.ts +2 -1
  32. package/dist/src/kernel/nodes/index.js +3 -1
  33. package/dist/src/kernel/nodes/index.js.map +1 -1
  34. package/dist/src/kernel/templates/index.d.ts +27 -3
  35. package/dist/src/kernel/templates/index.js +78 -1
  36. package/dist/src/kernel/templates/index.js.map +1 -1
  37. package/dist/src/kernel/types.d.ts +41 -2
  38. package/dist/src/kernel/types.js.map +1 -1
  39. package/dist/src/models.js +10 -2
  40. package/dist/src/models.js.map +1 -1
  41. package/dist/src/persistent-agy-session.js +1 -0
  42. package/dist/src/persistent-agy-session.js.map +1 -1
  43. package/dist/src/persistent-codex-app-session.d.ts +55 -26
  44. package/dist/src/persistent-codex-app-session.js +109 -24
  45. package/dist/src/persistent-codex-app-session.js.map +1 -1
  46. package/dist/src/persistent-codex-session.js +1 -0
  47. package/dist/src/persistent-codex-session.js.map +1 -1
  48. package/dist/src/persistent-cursor-session.js +1 -0
  49. package/dist/src/persistent-cursor-session.js.map +1 -1
  50. package/dist/src/persistent-custom-session.js +2 -0
  51. package/dist/src/persistent-custom-session.js.map +1 -1
  52. package/dist/src/persistent-gemini-session.js +1 -0
  53. package/dist/src/persistent-gemini-session.js.map +1 -1
  54. package/dist/src/persistent-grok-session.d.ts +4 -0
  55. package/dist/src/persistent-grok-session.js +12 -2
  56. package/dist/src/persistent-grok-session.js.map +1 -1
  57. package/dist/src/persistent-opencode-session.js +1 -0
  58. package/dist/src/persistent-opencode-session.js.map +1 -1
  59. package/dist/src/persistent-session.js +1 -0
  60. package/dist/src/persistent-session.js.map +1 -1
  61. package/dist/src/sanitize.d.ts +10 -0
  62. package/dist/src/sanitize.js +26 -0
  63. package/dist/src/sanitize.js.map +1 -1
  64. package/dist/src/session-manager.d.ts +25 -20
  65. package/dist/src/session-manager.js +217 -44
  66. package/dist/src/session-manager.js.map +1 -1
  67. package/dist/src/types.d.ts +6 -0
  68. package/package.json +2 -2
  69. package/skills/SKILL.md +8 -5
  70. package/skills/references/autoloop.md +52 -8
  71. package/skills/references/claude-cli-tracking.md +3 -1
  72. package/skills/references/cli.md +32 -1
  73. package/skills/references/dashboard.md +5 -1
  74. package/skills/references/multi-engine.md +26 -15
  75. package/skills/references/tools.md +25 -14
  76. package/skills/references/workflow.md +87 -13
package/skills/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: claw-orchestrator
3
- description: Manage persistent coding sessions across Claude Code, Codex, Antigravity (agy), Grok Build, and OpenCode engines. Use when orchestrating multi-engine coding agents, starting/sending/stopping sessions, running multi-agent council collaborations, cross-session messaging, ultraplan deep planning, ultrareview parallel code review, autoloop autonomous workspace iteration, ultraapp building deployable web apps from a structured Q&A interview, switching models/tools at runtime, exposing the orchestrator's 78 tools as an MCP server to Hermes Agent / Claude Desktop / Cursor / Cline / Continue / Zed / Windsurf / Goose, or running as an Agent Client Protocol (ACP) agent that Zed / JetBrains / Neovim / Emacs / VS Code / dsh can drive directly. Triggers on "start a session", "send to session", "run council", "ultraplan", "ultrareview", "autoloop", "ultraapp", "Forge tab", "build a web app", "one-click app", "AppSpec", "autonomous iteration", "iterate until goal", "auto research", "switch model", "hand off a session", "session handoff", "switch engine", "continue on codex", "continue on claude", "move this session to another engine", "multi-agent coding", "coding session", "session inbox", "grok session", "grok build", "opencode", "mcp server", "clawo-mcp", "hermes mcp", "model context protocol", "ultracode", "dynamic workflow", "fanout", "fan-out", "best-of-N", "steer turn", "interrupt turn", "fork thread", "rollback turns", "acp", "agent client protocol", "clawo acp", "zed agent", "jetbrains agent", "external agent", "dsh subagent", "deepseek harness", "clawo runs", "run ledger", "session cost", "coding-agent token usage", "spend cap", "budget limit", "maxBudgetUsd", "durable workflow", "resume a run", "verify a coding run", "acceptance contract", "evidence bundle", "did the agent's tests actually pass", "protected tests", "agent edited the tests", "human gate", "repair loop", "clawo workflow", "clawo verify", "clawo solve", "clawo fanout", "fix and verify", "solve from the terminal".
3
+ description: Manage persistent coding sessions across Claude Code, Codex, Antigravity (agy), Grok Build, and OpenCode engines. Use when orchestrating multi-engine coding agents, starting/sending/stopping sessions, running multi-agent council collaborations, cross-session messaging, ultraplan deep planning, ultrareview parallel code review, autoloop autonomous workspace iteration, ultraapp building deployable web apps from a structured Q&A interview, switching models/tools at runtime, exposing the orchestrator's 78 tools as an MCP server to Hermes Agent / Claude Desktop / Cursor / Cline / Continue / Zed / Windsurf / Goose, or running as an Agent Client Protocol (ACP) agent that Zed / JetBrains / Neovim / Emacs / VS Code / dsh can drive directly. Triggers on "start a session", "send to session", "run council", "ultraplan", "ultrareview", "autoloop", "ultraapp", "Forge tab", "build a web app", "one-click app", "AppSpec", "autonomous iteration", "iterate until goal", "auto research", "switch model", "hand off a session", "session handoff", "switch engine", "continue on codex", "continue on claude", "move this session to another engine", "multi-agent coding", "coding session", "session inbox", "grok session", "grok build", "opencode", "mcp server", "clawo-mcp", "hermes mcp", "model context protocol", "ultracode", "dynamic workflow", "fanout", "fan-out", "best-of-N", "steer turn", "interrupt turn", "fork thread", "rollback turns", "acp", "agent client protocol", "clawo acp", "zed agent", "jetbrains agent", "external agent", "dsh subagent", "deepseek harness", "clawo runs", "run ledger", "session cost", "coding-agent token usage", "spend cap", "budget limit", "maxBudgetUsd", "durable workflow", "resume a run", "verify a coding run", "acceptance contract", "evidence bundle", "did the agent's tests actually pass", "protected tests", "agent edited the tests", "human gate", "repair loop", "clawo workflow", "clawo verify", "clawo solve", "clawo fanout", "fix and verify", "solve from the terminal", "codex goal", "/goal", "clawo goal", "long-horizon goal", "unattended codex run", "goal node", "run codex in a sandbox", "launcher".
4
4
  metadata:
5
5
  {
6
6
  'openclaw':
@@ -213,15 +213,18 @@ For setup, the dsh YAML block, and the cancellation/permission limits: see [refe
213
213
 
214
214
  ## Durable workflows
215
215
 
216
- `workflow_start` runs a declarative graph of `agent` / `fanout` / `council` / `verifier` /
217
- `human_gate` / `router` / `subflow` / `autoloop` / `ultraapp_synth` /
216
+ `workflow_start` runs a declarative graph of `agent` / `fanout` / `council` / `goal` /
217
+ `verifier` / `human_gate` / `router` / `subflow` / `autoloop` / `ultraapp_synth` /
218
218
  `ultraapp_deploy` nodes. Every state transition is checkpointed to
219
219
  `~/.claw-orchestrator/wf/<runId>/`, so a run survives a process restart and `workflow_resume`
220
220
  picks it up at the node boundary — nodes already succeeded are not re-run, and the one that
221
221
  was in flight is retried because a half-finished node left no result to trust.
222
222
 
223
- Three built-in templates: `solve` (triage → implement → verify → repair-until-green →
224
- review), `council`, and `fanout`. Retry, per-node timeout, cancel, steer, human gates, and
223
+ Four built-in templates: `solve` (triage → implement → verify → repair-until-green →
224
+ review), `council`, `fanout`, and `goal` (a Codex `/goal` on one `codex-app` thread, run
225
+ unattended for as long as it takes — reattached on resume, resumed after usage limits and
226
+ stalls within a bound, optionally under a sandbox `launcher` — then verify → repair on the
227
+ same thread; `clawo goal` from the terminal). Retry, per-node timeout, cancel, steer, human gates, and
225
228
  bounded loops come from the kernel rather than from each mode's own state machine.
226
229
 
227
230
  For node shapes, routing conditions, and the control surfaces:
@@ -138,6 +138,19 @@ A successful increase appends exactly one `timeout_migration` record to
138
138
  pending dispatch identity when available. It does not rewrite the original
139
139
  stored spec, chat or iteration evidence, or any earlier audit bytes.
140
140
 
141
+ A live run paused by `pause_loop` or an expired activity lease, with
142
+ `pending_dispatch` null, continues on `autoloopResume()` / `POST /autoloop/<id>/resume`
143
+ with no timeout fields. That resume clears the lease expiry, sets status back
144
+ to `planning` (or `running` once subagents have been spawned), re-arms the
145
+ activity lease from the resume, and leaves the original hard deadline where it
146
+ was. That call returns once the run is active again; Planner chat accepted
147
+ during the pause was parked, not delivered, and is then delivered once, in
148
+ order, by the background drain. If the hard deadline has already passed, the
149
+ same resume terminates the run with `hard_timeout_exceeded` and delivers
150
+ nothing. A no-option resume of an `awaiting_resume` send-timeout pause is still
151
+ a no-op: the pending dispatch, its reason, and the lease suspension stay as
152
+ they are until an explicit timeout increase names that dispatch.
153
+
141
154
  ## Quick start
142
155
 
143
156
  Over HTTP, against `clawo serve` (default `127.0.0.1:18796`):
@@ -212,7 +225,7 @@ removes partial files, and suppresses both spawn and directives.
212
225
  | `notify_user` | `level` ('info' / 'warn' / 'decision' / 'error'), `summary`, `detail?`, `channel?` ('auto' / 'wechat' / 'webchat' / 'both' / 'email') | Push you out-of-band. |
213
226
  | `spawn_subagents` | `coder_engine?`, `coder_model?`, `reviewer_engine?`, `reviewer_model?`, `initial_directive?` | Start Coder + Reviewer. Omitted values inherit run defaults. An engine change without a model uses the new engine's default. Once a role session has started, changing its engine/model is rejected. Custom configs cannot be emitted by Planner. Only after explicit user approval. |
214
227
  | `send_directive` | `goal`, `constraints?`, `success_criteria?`, `max_attempts?` | Next iter's instruction to Coder. |
215
- | `pause_loop` | `reason` | Halt subloop at next iter boundary; chat keeps working. |
228
+ | `pause_loop` | `reason` | Pause the live run. Planner chat is parked during a pause and is delivered once, in order, on resume. |
216
229
  | `resume_loop` | — | Resume after pause. |
217
230
  | `terminate` | `reason` | End run. |
218
231
  | `update_push_policy` | partial PushPolicy | Mutate notification rules (e.g. when you say "tell me every iter"). |
@@ -390,7 +403,7 @@ Every JSON artifact in the ledger carries a `schema_version` field (currently
390
403
  | `GET /autoloop/<id>/events` | SSE: `snapshot` / `message` / `state` / `push` / `iter_done` / `planner_reply` / `planner_error` / `coder_reply` / `reviewer_reply` / `terminated`. For runs that are NOT in this process's memory (terminated, or live in another process), the endpoint emits a single-shot `snapshot` + `terminated` then closes — the dashboard's existing handlers render history without hanging. A run still in memory that has already reached `terminated` or `crashed` gets the same single-shot pair instead of an open stream that would never receive another event. Every such stream sets `retry: 864000000`, so an `EventSource` does not keep reconnecting to a stream that can only end again. |
391
404
  | `POST /autoloop/<id>/chat` | **202** `{ ok, queued: true }` — body `{ text }`. Fire-and-forget: the Planner's reply streams back via the `/events` SSE channel as a `planner_reply` event (or `planner_error` on failure); the HTTP response intentionally does NOT wait for it, because first-contact replies routinely exceed reverse-proxy idle limits (e.g. Cloudflare Tunnel cuts at ~100s → 524). 400 on empty text. 404 when the run is not in this process's memory: if the store still holds it, the error says so and names `POST /autoloop/<id>/resume`; an unknown or malformed id is plain `not found`. The MCP `autoloop_chat` tool path keeps the synchronous await-and-return-reply semantics (it runs in-process). |
392
405
  | `GET /autoloop/<id>/resume-requirements` | `{ ok, runId, rolesNeedingCustomEngine }` — the roles whose engine was `custom`, so a caller knows which secret references a resume needs. Role names only; nothing sensitive. 404 when there is no such run. |
393
- | `POST /autoloop/<id>/resume` | `{ ok, state }` — restore the role engine/model choices from the run's spec and re-create dispatcher + runner. For recoverable send timeouts, body fields `send_timeout_ms` and `pending_dispatch_id` apply the increase-only migration described above; `allow_decrease`, lease overrides, and hard-cap overrides are rejected. A custom-engine config is never persisted and is never accepted over HTTP, so a role using `custom` is re-supplied by **reference**: `plannerCustomEngineRef` / `coderCustomEngineRef` / `reviewerCustomEngineRef` name an environment variable `CLAWO_CUSTOM_ENGINE_<NAME>` on the orchestrator host, which the server reads and resolves. The name is not sensitive, the value never crosses the wire, and an unknown name is an error rather than a silent start without credentials. Existing engine-specific conversation resume behavior is reused where supported; `chat.jsonl` remains the visual history fallback. 404 when there is no such run. |
406
+ | `POST /autoloop/<id>/resume` | `{ ok, state }` — for a live ordinary or activity-lease pause (`pending_dispatch` null), an empty timeout body continues that run: the response returns once status is `planning` or `running` again, the lease re-arms, the hard deadline stays put, and parked Planner input is then delivered once, in order. A live `awaiting_resume` pause is unchanged unless the body increases the send timeout. Otherwise restore the role engine/model choices from the run's spec and re-create dispatcher + runner. For recoverable send timeouts, body fields `send_timeout_ms` and `pending_dispatch_id` apply the increase-only migration described above; `allow_decrease`, lease overrides, and hard-cap overrides are rejected. A custom-engine config is never persisted and is never accepted over HTTP, so a role using `custom` is re-supplied by **reference**: `plannerCustomEngineRef` / `coderCustomEngineRef` / `reviewerCustomEngineRef` name an environment variable `CLAWO_CUSTOM_ENGINE_<NAME>` on the orchestrator host, which the server reads and resolves. The name is not sensitive, the value never crosses the wire, and an unknown name is an error rather than a silent start without credentials. Existing engine-specific conversation resume behavior is reused where supported; `chat.jsonl` remains the visual history fallback. 404 when there is no such run. |
394
407
  | `POST /autoloop/<id>/delete` | `{ ok }` — stops the loop if still live, deletes the run record from the run store, and purges the role sessions' persisted resume ids so the run cannot be resumed. The ledger directory under `<workspace>/tasks/<run_id>/` is kept on disk. 404 when there is no such run. |
395
408
 
396
409
  The dashboard's 3-pane autoloop view (`/dashboard`) consumes these endpoints:
@@ -464,13 +477,39 @@ Resume is explicit. `POST /autoloop/<id>/resume` (or
464
477
  `SessionManager.autoloopResume()`) restarts a run from its stored spec.
465
478
  Custom-engine configs are the one thing the spec does not carry (they can hold
466
479
  secrets), so a resume must be given them again. Cancelling a run stops all three
467
- agents, the same as `autoloop_stop`. If the highest committed Coder iteration
480
+ agents, the same as `autoloop_stop`.
481
+
482
+ On a non-fresh boot (resume / revisit), before any Planner session or
483
+ checkpoint publish, the boot reads the run ledger once and restores typed
484
+ `iter` and `metric_history` from the contiguous valid closed prefix of
485
+ `iter/0..K` (each closed entry needs `directive.json` plus a parsed
486
+ `verdict.json` whose `iter` matches and whose `decision` is a supported
487
+ Reviewer decision). Finite verdict metrics are kept in order, capped at
488
+ `MAX_METRIC_HISTORY` (20). The stored checkpoint's `iter` / `metric_history`
489
+ are never progress authority. A fresh start skips that read. When there is no
490
+ valid closed prefix (including missing or open/malformed `iter/0` with a later
491
+ canonical directory present), the reader returns without restore or refusal —
492
+ same Planner-only resume as before. If the highest committed Coder iteration
468
493
  has ledger artifacts and no `verdict.json`, and `HEAD` still names that iter,
469
- resume starts and sends only the Reviewer: one `review_request` for that
470
- checkpoint, and the dispatcher persists `verdict.json`. It does not create or
471
- resume a Coder session, and a historical persisted Coder registry row is left
472
- unchanged. An in-flight send is still not retried, and there is no message
473
- outbox.
494
+ resume still starts and sends only the Reviewer: one `review_request` for that
495
+ iteration (with rebuilt `prior_metrics`), and the dispatcher persists
496
+ `verdict.json`. It does not create or resume a Coder session, and a historical
497
+ persisted Coder registry row is left unchanged. An in-flight send is still not
498
+ retried, and there is no message outbox. A gap or malformed closed tail after a
499
+ valid prefix refuses the resume with a fixed generic error before any new
500
+ session or effect; ledger text is never echoed into the error.
501
+
502
+ **Accepted chat survives stop and owner loss.** `autoloop_chat` and `POST
503
+ /autoloop/:id/chat` accept a message only once it is in the run's checkpoint;
504
+ otherwise they fail (`autoloop chat could not be persisted`, or a stopping,
505
+ restoring or limit error) and nothing is sent. Up to 1,000 entries and 8 MiB
506
+ can be pending. Chat that was not yet handed to the Planner is delivered once,
507
+ in order, after a resume. Chat that was being delivered when the run stopped is
508
+ not resent: the status gains `unconfirmed_chat` (`count`, `last_at`,
509
+ `history_pending`) and chat history gets one system notice asking to re-send it
510
+ if needed. No further chat is handed over until that notice is recorded; if it
511
+ cannot be written the run pauses with `chat_notice_pending`, and a plain resume
512
+ retries it.
474
513
 
475
514
  ## Known limitations
476
515
 
@@ -489,6 +528,11 @@ outbox.
489
528
  process until it is resumed, and a send that was in flight is not retried.
490
529
  - **Multi-run / same workspace** races on `git index.lock`. Run separate
491
530
  workspaces (or git worktrees) for concurrent runs.
531
+ - **Closed-ledger restore does not rebuild streaks or status.** Only `iter` and
532
+ capped `metric_history` are restored from the closed prefix; `rejectStreak`,
533
+ `regressionStreak`, and run `status` fields are not reconstructed. Prefixless
534
+ corruption, path/symlink size hardening, and fresh `autoloop_start` reuse of a
535
+ retained ledger id remain out of scope.
492
536
 
493
537
  ## Related
494
538
 
@@ -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.302** (as of 2026-10-17, plugin v7.12.0)
5
+ ## Currently tracked: **Claude Code CLI 2.1.307** (as of 2026-10-24, plugin v7.13.0)
6
6
 
7
7
  ## Sync history
8
8
 
9
9
  | Plugin Version | Claude CLI Version | Date | Notable integrations |
10
10
  | ------------------- | ------------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | 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. |
12
+ | v7.12.1 | 2.1.307 | 2026-10-22 | CC 2.1.302→2.1.307, agy 1.4.0→1.4.4, grok 1.0.62→1.0.67; Codex 0.163.0 and OpenCode 1.19.3 unchanged. No flag the wrappers pass changed. grok 1.0.67 makes `grok-4.7` its default and only model: registered (same prices and 500K window as `grok-4.6`), the `grok` alias moved to it, and a session with no `model` is labelled with the model grok reports. grok read-only re-measured on 1.0.67 (direct and shell writes blocked; the subagent probe hit the free-tier limit). OpenCode 2 still beta-only, still refused. |
11
13
  | v7.12.0 | 2.1.302 | 2026-10-17 | CC 2.1.296→2.1.302, Codex 0.162.1→0.163.0, agy 1.3.2→1.4.0, grok 1.0.50→1.0.62, OpenCode 1.19.0→1.19.3. No flag the wrappers pass changed. grok read-only re-measured on 1.0.62 (direct, shell and subagent writes blocked; the failed-sandbox warning unchanged). OpenCode 2 still beta-only, still refused. Codex 0.163.0 turns Daybreak (security programme, not a model) on for eligible accounts; billing follows the model codex reports. |
12
14
  | v7.11.0 | 2.1.296 | 2026-10-11 | CC 2.1.295→2.1.296, Codex 0.162.0→0.162.1, OpenCode 1.18.35→1.19.0; agy 1.3.2 and grok 1.0.50 unchanged. No flag the wrappers pass changed. OpenCode 1.19.0 offers `opencode upgrade --major` to OpenCode 2 (beta builds `0.0.0-beta-N`, replaces V1): measured on 0.0.0-beta-17823 it drops `step_finish` and `--variant`, and its free tier answers 403 to a custom agent, so the read-only agent is unverifiable — the OpenCode session now refuses a V2 binary at start. |
13
15
  | v7.10.0 | 2.1.295 | 2026-10-09 | CC 2.1.292→2.1.295, Codex 0.160.1→0.162.0, agy 1.3.1→1.3.2, grok 1.0.46→1.0.50; OpenCode 1.18.35 unchanged. No flag the wrappers pass changed. Integrated: Claude Haiku 5.5 registered and the `haiku` alias moved to it (`--model haiku` resolves to `claude-haiku-5-5` in 2.1.295); Sonnet 5.5's cache-hit price corrected to 0.05× input. Integrated: grok 1.0.50's `--sandbox read-only` backs Grok's `sandboxMode: 'read-only'`, measured against direct, shell, subagent, resumed-turn and out-of-project writes; a profile grok cannot apply only warns, so the session kills the process on that warning. |
@@ -238,6 +238,37 @@ engine may appear more than once. With `--wait` the run is followed to the end
238
238
  and every answer is printed, followed by the synthesis when `--synthesize` was
239
239
  given. Checks run after the fan-out, as for `solve`.
240
240
 
241
+ ## `clawo goal`
242
+
243
+ Run a Codex `/goal` on one `codex-app` thread, then have the runtime check the
244
+ result: goal → verify → repair on the same thread. See [workflow.md](./workflow.md#goal).
245
+
246
+ ```bash
247
+ clawo goal "<objective>" | --objective-file <file>
248
+ [--check "<command>"]... [--contract <file>] [--check-timeout <minutes>]
249
+ [--launcher <arg>]... [--model <model>] [--effort <level>] [--sandbox <mode>] [--thread <id>]
250
+ [--token-budget N] [--goal-timeout <minutes>] [--max-repairs N]
251
+ [--cwd <dir>] [--wait] [--json]
252
+ ```
253
+
254
+ | Option | Default | Notes |
255
+ | ------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------- |
256
+ | `--objective-file` | — | Read the objective from a file instead of the argument. Codex accepts at most 4,000 characters |
257
+ | `-c, --check` | — | A command check, repeatable, run after the goal. Split on whitespace; quote-needing commands go in `--contract` |
258
+ | `--check-timeout` | 10 | Minutes for each `--check`. The verifier's node timeout is sized from the checks |
259
+ | `--launcher` | — | Run codex under this command, one argv element per flag: `--launcher ./sandbox.sh --launcher task --launcher "0 1"` |
260
+ | `-m, --model` | codex's own | Codex model |
261
+ | `--sandbox` | `workspace-write` | Codex's own sandbox mode. With an outer sandbox as the boundary, `danger-full-access` |
262
+ | `--thread` | — | Start on this existing codex thread: its goal is replaced, its history kept |
263
+ | `--token-budget` | — | The goal stops as `budgetLimited` past this |
264
+ | `--goal-timeout` | none | Wall-clock minutes for one goal pass |
265
+ | `--max-repairs` | `1` | Times a red verdict sends the goal back to the same thread |
266
+ | `-w, --wait` | off | Follow the run; exit `0` only if it completes |
267
+
268
+ `clawo workflow show <runId>` prints the goal's status, tokens, time, resume
269
+ attempts and thread id while it runs; `clawo workflow steer <runId> "<text>"`
270
+ goes into the running turn.
271
+
241
272
  ## `clawo workflow`
242
273
 
243
274
  ```bash
@@ -245,7 +276,7 @@ clawo workflow list [--state <s>] [--workflow <name>] [--limit N] [--json]
245
276
  clawo workflow show <runId> [--json]
246
277
  clawo workflow resume <runId> # re-attach to a run whose process died
247
278
  clawo workflow cancel <runId>
248
- clawo workflow steer <runId> "<text>" # queue a correction for the next agent node
279
+ clawo workflow steer <runId> "<text>" # a correction for the next agent node, or into a running goal
249
280
  clawo workflow approve <runId> [reject]
250
281
  ```
251
282
 
@@ -120,7 +120,11 @@ that both read the file always agree.
120
120
  Opening a run whose `status` is `terminated` (because its process has
121
121
  exited, or because you're viewing it cross-process) fetches
122
122
  `/autoloop/<id>/chat_history`, replays the conversation into the Planner pane,
123
- and shows a green **Resume run** button in the topbar. Clicking it POSTs `/autoloop/<id>/resume`;
123
+ and shows a green **Resume run** button in the topbar. The same button is shown
124
+ for any live paused run, and it follows later SSE state: a pause adds it, and
125
+ returning to an active status removes it. Timeout fields are included only when
126
+ `pending_dispatch` exists; an ordinary or activity-lease pause resumes with
127
+ an empty timeout body. Clicking it POSTs `/autoloop/<id>/resume`;
124
128
  the orchestrator re-attaches the Planner (reusing the persisted Claude
125
129
  session ID when available, so Claude's context picks up where it left
126
130
  off) and the dashboard reconnects to `/events` for live updates.
@@ -28,7 +28,7 @@ SessionManager
28
28
 
29
29
  ### Claude Code (`engine: 'claude'`)
30
30
 
31
- Default engine. Long-running subprocess with streaming JSON I/O. Tested with Claude Code CLI **2.1.302**.
31
+ Default engine. Long-running subprocess with streaming JSON I/O. Tested with Claude Code CLI **2.1.307**.
32
32
 
33
33
  - Persistent multi-turn conversations
34
34
  - Real-time streaming (text, tool_use, tool_result, system events)
@@ -62,7 +62,7 @@ await manager.startSession({
62
62
 
63
63
  ### OpenAI Codex (`engine: 'codex'`)
64
64
 
65
- Wraps the `codex exec` subcommand. Each `send()` spawns a new process. Tested with `codex` CLI **0.163.0**.
65
+ Wraps the `codex exec` subcommand. Each `send()` spawns a new process. Tested with `codex` CLI **0.164.0**.
66
66
 
67
67
  - Non-interactive execution via `codex exec --sandbox workspace-write --skip-git-repo-check --json`
68
68
  - 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
@@ -102,19 +102,18 @@ await manager.startSession({
102
102
 
103
103
  ### OpenAI Codex App-Server (`engine: 'codex-app'`)
104
104
 
105
- 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 slash-command surface.
105
+ 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**.
106
106
 
107
107
  - Long-running subprocess; one `codex app-server` per session
108
108
  - JSON-RPC 2.0 over stdio with v2 protocol method names (`initialize`, `thread/start`, `turn/start`, ...)
109
109
  - Real-time streaming via `item/agentMessage/delta` notifications
110
110
  - Cumulative token tracking from `thread/tokenUsage/updated` notifications. The same notification's `last` breakdown and `modelContextWindow` drive `contextPercent`, so it reports live occupancy against the window the server enforces rather than a running total over the model's published window
111
111
  - `appendSystemPrompt` is placed at the top of the first message of a new thread (app-server has no system-prompt flag); a resumed thread already carries it
112
- - Goal lifecycle observation via `thread/goal/updated` and `thread/goal/cleared` notifications
113
- - Goal control via the `codex_goal_*` tools (which internally send the `/goal` slash command as user text — see [tools.md](./tools.md#codex-13))
114
- - v2 RPC tools (Codex 0.137): `codex_interrupt` (`turn/interrupt`), `codex_steer` (`turn/steer`), `codex_fork` (`thread/fork`), `codex_rollback` (`thread/rollback`), `codex_models` (`model/list`), `codex_thread_list` (`thread/list`). A `turn/completed` with `status: 'failed'` rejects the turn and increments `toolErrors`.
115
- - Thread resume: starting with `resumeSessionId` loads the existing thread via `thread/resume` instead of `thread/start`.
116
-
117
- > **Feature flag.** `goals` is an experimental Codex feature. The session always passes `--enable goals`; some goal commands may still fail or be ignored by the server.
112
+ - Goals through the typed RPCs `thread/goal/set` / `get` / `clear`: setting an objective starts the server's own turn loop, which runs until the goal is `complete`, `budgetLimited`, `blocked`, `usageLimited` or `paused`. Each change arrives as `thread/goal/updated`. The `codex_goal_*` tools wrap these; the kernel's `goal` node drives them for unattended runs ([workflow.md](./workflow.md#goal))
113
+ - `error` notifications are read as `{ error: { message, codexErrorInfo }, willRetry }`. The session keeps the last one (`lastError`, with `codexErrorInfo` as a name such as `serverOverloaded`) and emits it as `codex:error`; an error notification never throws when nothing listens for errors
114
+ - v2 RPC tools (Codex 0.137): `codex_interrupt` (`turn/interrupt`), `codex_steer` (`turn/steer`, including into a turn the goal loop started), `codex_fork` (`thread/fork`), `codex_rollback` (`thread/rollback`), `codex_models` (`model/list`), `codex_thread_list` (`thread/list`). A `turn/completed` with `status: 'failed'` rejects the turn and increments `toolErrors`.
115
+ - Threads are opened and resumed with `approvalPolicy: "never"`, and a server request the session cannot handle (an approval, a request for user input) gets an error reply at once: nothing here can answer one, and an unanswered request blocks its turn. The sandbox mode is the boundary.
116
+ - Thread resume: starting with `resumeSessionId` loads the existing thread via `thread/resume` instead of `thread/start`. The id the session manager stores and replays (model switch, restart) is the app-server's own thread id. A thread resumed with an active goal continues it on its own.
118
117
 
119
118
  ```typescript
120
119
  await manager.startSession({
@@ -123,17 +122,27 @@ await manager.startSession({
123
122
  model: 'gpt-5.5',
124
123
  cwd: '/project',
125
124
  });
126
- // Then either:
127
- // await manager.codexGoalCommand('codex-goal-task', 'build a tic-tac-toe app');
125
+ await manager.codexGoal('codex-goal-task', { action: 'set', objective: 'build a tic-tac-toe app' });
128
126
  // or via the codex_goal_set tool:
129
127
  // await tool('codex_goal_set', { name: 'codex-goal-task', objective: 'build a tic-tac-toe app' });
130
128
  ```
131
129
 
130
+ ### Running an engine under a launcher
131
+
132
+ `SessionConfig.launcher` is an argv prefix the engine binary runs under, for every
133
+ engine: `launcher: ['/opt/task/sandbox.sh', 'task', '0 1']` spawns
134
+ `/opt/task/sandbox.sh task '0 1' codex app-server …`. This is how a caller puts
135
+ the agent inside its own sandbox (bubblewrap, a container entry point, `taskset`)
136
+ without a custom engine. The launcher is the caller's own command, at the same
137
+ trust level as a contract's command check, which the HTTP API also accepts: set
138
+ it through the SessionManager API, `/session/start` or a workflow spec (the `goal`
139
+ node's `launcher`). It is not a parameter of the `session_start` tool.
140
+
132
141
  ### Google Antigravity (`engine: 'agy'`)
133
142
 
134
143
  Wraps Google's **Antigravity CLI** (`agy`) — the successor to Gemini CLI (consumer
135
144
  Gemini CLI tiers stopped serving 2026-06-18). Each `send()` spawns a new process
136
- in print mode. Tested with `agy` **1.4.0**.
145
+ in print mode. Tested with `agy` **1.4.4**.
137
146
 
138
147
  - One-shot execution per message (no persistent subprocess)
139
148
  - **Structured output and real usage** — `--output-format stream-json` emits an
@@ -218,12 +227,14 @@ await manager.startSession({
218
227
  ### Grok Build (`engine: 'grok'`)
219
228
 
220
229
  Wraps xAI's **Grok Build** CLI. Each `send()` spawns `grok -p <msg> --output-format json`, which
221
- prints a single JSON object and exits. Tested with `grok` **1.0.62**.
230
+ prints a single JSON object and exits. Tested with `grok` **1.0.67**.
222
231
 
223
232
  - **Cost comes from the engine, not from the price table.** The result object carries
224
233
  `total_cost_usd`, and the wrapper writes it straight into the session's spend, so the run ledger
225
234
  and the `maxBudgetUsd` gate both read what xAI charged. Other engines multiply tokens by a rate in
226
- `models.ts`. `grok-4.6` is still registered, for its context window and an indicative breakdown.
235
+ `models.ts`. `grok-4.7` (grok's default since 1.0.67) and `grok-4.6` are still registered, for
236
+ their context window and an indicative breakdown; with no `model` set, the session is labelled with
237
+ the model grok reports under `modelUsage`.
227
238
  - **Real conversation continuity**: the `sessionId` from turn 1 is replayed as `--resume <id>`.
228
239
  `--continue` is not used — it means "the most recent session for this cwd", which collides
229
240
  between concurrent sessions.
@@ -263,7 +274,7 @@ prints a single JSON object and exits. Tested with `grok` **1.0.62**.
263
274
  await manager.startSession({
264
275
  name: 'grok-task',
265
276
  engine: 'grok',
266
- model: 'grok-4.6',
277
+ model: 'grok-4.7',
267
278
  cwd: '/project',
268
279
  });
269
280
  ```
@@ -297,38 +297,37 @@ Returns `{ ok, stdout, stderr }`.
297
297
 
298
298
  ### `codex_goal_set`
299
299
 
300
- Set a long-horizon objective. Sends `/goal <objective>` via the app-server. **Requires `engine: "codex-app"`.**
300
+ Set a long-horizon objective (`thread/goal/set`). Codex then works turn after turn on its own until the goal leaves `active`. **Requires `engine: "codex-app"`.**
301
301
 
302
- | Parameter | Type | Required |
303
- | ----------- | ------ | -------- |
304
- | `name` | string | yes |
305
- | `objective` | string | yes |
306
- | `timeout` | number | |
302
+ | Parameter | Type | Required | Notes |
303
+ | ------------- | ------ | -------- | ---------------------------------------------------------------- |
304
+ | `name` | string | yes | |
305
+ | `objective` | string | yes | |
306
+ | `tokenBudget` | number | | Tokens the goal may spend; it stops as `budgetLimited` past this |
307
307
 
308
- Returns `{ ok, text, goal }` where `goal` is `{ objective, status: "active"|"paused"|"budgetLimited"|"complete", tokensUsed, timeUsedSeconds, tokenBudget?, ... }` or `null`.
308
+ Returns `{ ok, goal }` where `goal` is `{ objective, status, tokenBudget, tokensUsed, timeUsedSeconds, ... }`. `status` is one of `active`, `paused`, `blocked`, `usageLimited`, `budgetLimited`, `complete`.
309
309
 
310
310
  ### `codex_goal_get`
311
311
 
312
- Read the cached goal state. Pure read — does not send a turn.
312
+ Ask the app-server for the goal (`thread/goal/get`). Sends no turn.
313
313
 
314
314
  | Parameter | Type | Required |
315
315
  | --------- | ------ | -------- |
316
316
  | `name` | string | yes |
317
317
 
318
- Returns `{ ok, goal }` (`null` if no goal active).
318
+ Returns `{ ok, goal }` (`null` if the thread has no goal).
319
319
 
320
320
  ### `codex_goal_pause` / `codex_goal_resume` / `codex_goal_clear`
321
321
 
322
- Send `/goal pause`, `/goal resume`, or `/goal clear` respectively. Requires `engine: "codex-app"`.
322
+ Pause (`status: "paused"`), resume (`status: "active"`, also for a goal stopped by a usage limit) or remove (`thread/goal/clear`) the goal. Requires `engine: "codex-app"`.
323
323
 
324
324
  | Parameter | Type | Required |
325
325
  | --------- | ------ | -------- |
326
326
  | `name` | string | yes |
327
- | `timeout` | number | |
328
327
 
329
- Returns `{ ok, text, goal }`.
328
+ Returns `{ ok, goal }` (`null` after `clear`).
330
329
 
331
- > **Stability note:** Codex's `goals` feature is experimental upstream. The wrapper only formats the `/goal` slash text, so upstream changes affect that text, not the protocol.
330
+ For a goal that has to run unattended for hours, judged by checks the agent did not write, use the `goal` workflow (`workflow_start` with `template: "goal"`, or `clawo goal`) instead of these tools; see [workflow.md](./workflow.md#goal).
332
331
 
333
332
  ### Codex app-server RPCs
334
333
 
@@ -645,7 +644,11 @@ or smaller values are rejected, and there is deliberately no
645
644
  Each successful increase appends one migration row to `decisions.jsonl`; the
646
645
  original run spec, history, and prior audit bytes are not rewritten. The
647
646
  matching live awaiting-resume condition is advanced without replaying the
648
- timed-out logical dispatch.
647
+ timed-out logical dispatch. A live ordinary or activity-lease pause
648
+ (`pending_dispatch` null) resumes with no timeout fields: the call returns once
649
+ the run is active again, the lease re-arms without moving the hard deadline,
650
+ and Planner chat parked during the pause is then delivered once, in order. A
651
+ no-option resume does not clear a pending send timeout.
649
652
 
650
653
  ### `autoloop_chat`
651
654
 
@@ -656,6 +659,14 @@ Send a message into the Planner conversation.
656
659
  | `run_id` | string | yes |
657
660
  | `text` | string | yes |
658
661
 
662
+ The message is accepted only once it is stored in the run checkpoint; otherwise
663
+ the call fails with `autoloop chat could not be persisted` (or a stopping,
664
+ restoring or limit error) and nothing is sent. Accepted chat survives
665
+ `autoloop_stop` and owner loss and is delivered once, in order, after a resume.
666
+ A message that was mid-delivery when the run stopped is not resent; it is
667
+ reported through `unconfirmed_chat` in `autoloop_status` and one notice in chat
668
+ history.
669
+
659
670
  ### `autoloop_status`
660
671
 
661
672
  Get the current state and push log.
@@ -46,7 +46,9 @@ its choice is not recorded. A run parked at a `human_gate` parks there again.
46
46
  Steers survive a restart. They are logged when they arrive and recorded as
47
47
  consumed when the node that took them finishes, so on resume every steer no
48
48
  finished node consumed is queued again — including one a node was holding when
49
- it died, which goes to that node's retry.
49
+ it died, which goes to that node's retry. A `goal` node delivers steers into
50
+ the running turn as they arrive, so one delivered before a crash is delivered
51
+ again after the resume.
50
52
 
51
53
  **This makes node execution at-least-once, not exactly-once.** There is no
52
54
  idempotency key and no side-effect commit marker, so a node that wrote files and
@@ -136,17 +138,18 @@ is unrecoverable and reads back as "not found".
136
138
 
137
139
  ## Node kinds
138
140
 
139
- | Kind | Does |
140
- | ------------ | ----------------------------------------------------------------------------------------- |
141
- | `agent` | One session, one turn |
142
- | `fanout` | N agents in parallel, optional synthesis |
143
- | `council` | The existing council engine, votes recorded as advisory |
144
- | `verifier` | Runs an acceptance contract, writes evidence — see [`verification.md`](./verification.md) |
145
- | `human_gate` | Parks the run until a person answers |
146
- | `router` | Picks the next node from declarative conditions; a backwards route is the loop |
147
- | `subflow` | Runs another workflow as a step and adopts its verdict |
141
+ | Kind | Does |
142
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
143
+ | `agent` | One session, one turn |
144
+ | `fanout` | N agents in parallel, optional synthesis |
145
+ | `council` | The existing council engine, votes recorded as advisory |
146
+ | `verifier` | Runs an acceptance contract, writes evidence — see [`verification.md`](./verification.md) |
147
+ | `human_gate` | Parks the run until a person answers |
148
+ | `router` | Picks the next node from declarative conditions; a backwards route is the loop |
149
+ | `subflow` | Runs another workflow as a step and adopts its verdict |
148
150
  | `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. |
149
- | `ultraapp_*` | UltraApp's synth and deploy stages; their executors are injected too |
151
+ | `goal` | A Codex `/goal` on one `codex-app` thread, run until the goal finishes — see [below](#goal) |
152
+ | `ultraapp_*` | UltraApp's synth and deploy stages; their executors are injected too |
150
153
 
151
154
  Every node takes `retry: { max, backoffMs }`, `timeoutMs`, and
152
155
  `onFailure: 'fail' | 'continue'`.
@@ -258,9 +261,79 @@ test suite would double the most expensive part of the run to learn nothing new.
258
261
  - **`council`** — one council node, plus the implicit verifier when a contract is
259
262
  declared.
260
263
  - **`fanout`** — one fan-out node.
264
+ - **`goal`** — a `goal` node → verify → repair on the same thread; `task` is the
265
+ objective. See [below](#goal).
261
266
 
262
267
  These are ordinary specs, not privileged paths.
263
268
 
269
+ ## Goal
270
+
271
+ A `goal` node runs one Codex `/goal` on one `codex-app` thread. Codex's
272
+ app-server runs the goal itself: `thread/goal/set` starts its turn loop, which
273
+ keeps going until the goal is `complete`, out of budget, `blocked`, or stopped
274
+ by a usage limit. The node adds what an unattended run needs around that loop.
275
+
276
+ ```jsonc
277
+ {
278
+ "id": "goal",
279
+ "kind": "goal",
280
+ "objective": "Reach the goal described in GOAL.md …",
281
+ "cwd": "/work/task/ws",
282
+ "model": "gpt-6.1-sol", // optional; codex's own default otherwise
283
+ "launcher": ["/work/goal/sandbox/sandbox.sh", "task", "0 1"], // optional argv prefix
284
+ "threadId": "019c…", // optional: start on this existing thread, replacing its goal
285
+ "tokenBudget": 50000000, // optional; the goal ends as budgetLimited past it
286
+ "capacityRetry": { "max": 20, "backoffMs": 60000 }, // default
287
+ "stallMs": 300000, // default 5 min
288
+ "timeoutMs": 86400000, // optional wall-clock budget; no default
289
+ }
290
+ ```
291
+
292
+ - **The objective fits Codex's limit.** Codex accepts at most 4,000 characters;
293
+ a longer objective fails the node before a session opens. Put a long brief in
294
+ a file in the working directory and name the file in the objective.
295
+ - **The thread is checkpointed.** Node data holds `threadId`, `status`,
296
+ `tokensUsed`, `timeUsedSeconds`, `resumes`, `lastError`, the agent's last reply
297
+ (`lastMessage`, at most 4,000 characters) and the thread's spend
298
+ (`costUsd`), updated as the goal moves (progress at most every 10 s, status
299
+ changes at once). `workflow_status` and `clawo workflow show` read it while the
300
+ goal runs.
301
+ - **Resume reattaches, it does not restart.** A resumed run hands the stored
302
+ thread id to `thread/resume`; a goal that had not finished continues where it
303
+ was. If the resume lands on a different thread the node fails rather than
304
+ starting the objective over. An app-server that exits mid-goal is reopened on
305
+ the same thread the same way.
306
+ - **Stalls are resumed within a bound.** A goal that is `usageLimited` or
307
+ `paused`, or `active` with no turn running and either no news for `stallMs` or
308
+ an error the server will not retry (`serverOverloaded`, `usageLimitExceeded`,
309
+ `rateLimitExceeded`, a dropped connection), is set back to `active` after a
310
+ backoff that starts at `capacityRetry.backoffMs` and doubles to at most 15 min.
311
+ Every attempt counts before it is made, reopening a dead app-server included;
312
+ past `capacityRetry.max` the node fails.
313
+ - **Repair on the same thread.** Revisited after a red verifier, the node clears
314
+ the finished goal and sets a new objective on the same thread: the failing
315
+ checks first (as diagnostic data, like an agent node's repair brief), then the
316
+ original objective. The agent keeps its context. The original objective is
317
+ always kept whole; when both do not fit in 4,000 characters the checks are cut
318
+ (the full output stays in the run's evidence). A first goal that was never set
319
+ left nothing on its thread, so its revisit starts a new one.
320
+ - **Steering is live.** `workflow_steer` text goes into the running turn through
321
+ `turn/steer`; with no turn running it waits for the next one. Text queued
322
+ before the goal is set is put in front of the objective.
323
+ - **No approval prompts.** Nothing can answer one, so the thread runs with
324
+ `approvalPolicy: "never"` and any request the server sends anyway (approval,
325
+ user input) is answered with an error at once; the sandbox mode is the
326
+ boundary.
327
+ - **Ends.** `complete` succeeds. `budgetLimited` and `blocked` fail with the
328
+ reason. Cancel interrupts the running turn and pauses the goal. Like
329
+ `autoloop`, the node has no default timeout.
330
+
331
+ The `goal` template wraps this in `goal → verify → repair-gate`. The goal node
332
+ continues on failure, so a goal that ran out of budget is still judged. The
333
+ verifier's node timeout is sized from the contract (each check's timeout, at
334
+ least 30 min), so a judge that takes hours is not cut off at the 30-minute node
335
+ default. `maxRepairs` defaults to 1.
336
+
264
337
  ## The verifier is a terminal barrier
265
338
 
266
339
  A passing verdict only stands while it still describes the tree.
@@ -299,7 +372,7 @@ success.
299
372
 
300
373
  | Action | Tool | HTTP | CLI |
301
374
  | ------------- | ------------------ | --------------------------------- | -------------------------------------- |
302
- | Start | `workflow_start` | `POST /workflow/new` | — |
375
+ | Start | `workflow_start` | `POST /workflow/new` | `clawo solve` / `fanout` / `goal` |
303
376
  | Poll | `workflow_status` | `GET /workflow/<id>/state` | `clawo workflow show <id>` |
304
377
  | List | `workflow_list` | `GET /workflow/list` | `clawo workflow list` |
305
378
  | Resume | `workflow_resume` | `POST /workflow/<id>/resume` | `clawo workflow resume <id>` |
@@ -309,7 +382,8 @@ success.
309
382
  | Evidence | — | `GET /workflow/<id>/evidence` | `clawo verify <id>` |
310
383
  | Live events | — | `GET /workflow/<id>/events` (SSE) | — |
311
384
 
312
- Steer text is **prepended** to the next agent node's prompt: an instruction that
385
+ In a running `goal` node, steer text goes into the current turn (`turn/steer`).
386
+ Otherwise, steer text is **prepended** to the next agent node's prompt: an instruction that
313
387
  arrives while the previous node was running is a correction, and corrections
314
388
  belong before the task.
315
389