@enderfga/claw-orchestrator 7.12.1 → 7.14.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 (88) hide show
  1. package/README.md +14 -11
  2. package/configs/engines/README.md +20 -0
  3. package/configs/engines/dsh.json +17 -0
  4. package/configs/engines/kimi-code.json +17 -0
  5. package/dist/bin/cli.js +123 -34
  6. package/dist/bin/cli.js.map +1 -1
  7. package/dist/src/acp-server.js +4 -2
  8. package/dist/src/acp-server.js.map +1 -1
  9. package/dist/src/autoloop/dispatcher.d.ts +19 -0
  10. package/dist/src/autoloop/dispatcher.js +57 -0
  11. package/dist/src/autoloop/dispatcher.js.map +1 -1
  12. package/dist/src/autoloop/runner.d.ts +102 -2
  13. package/dist/src/autoloop/runner.js +367 -44
  14. package/dist/src/autoloop/runner.js.map +1 -1
  15. package/dist/src/autoloop/types.d.ts +17 -0
  16. package/dist/src/autoloop/types.js.map +1 -1
  17. package/dist/src/dashboard/index.html +79 -73
  18. package/dist/src/embedded-server.js +35 -7
  19. package/dist/src/embedded-server.js.map +1 -1
  20. package/dist/src/engine-presets.d.ts +7 -3
  21. package/dist/src/engine-presets.js +39 -6
  22. package/dist/src/engine-presets.js.map +1 -1
  23. package/dist/src/engine-spawn.d.ts +8 -1
  24. package/dist/src/engine-spawn.js +13 -3
  25. package/dist/src/engine-spawn.js.map +1 -1
  26. package/dist/src/index.js +78 -71
  27. package/dist/src/index.js.map +1 -1
  28. package/dist/src/kernel/agent-step.d.ts +3 -0
  29. package/dist/src/kernel/agent-step.js.map +1 -1
  30. package/dist/src/kernel/engine.d.ts +5 -2
  31. package/dist/src/kernel/engine.js +11 -12
  32. package/dist/src/kernel/engine.js.map +1 -1
  33. package/dist/src/kernel/nodes/autoloop.d.ts +32 -2
  34. package/dist/src/kernel/nodes/autoloop.js +122 -15
  35. package/dist/src/kernel/nodes/autoloop.js.map +1 -1
  36. package/dist/src/kernel/nodes/goal.d.ts +94 -0
  37. package/dist/src/kernel/nodes/goal.js +386 -0
  38. package/dist/src/kernel/nodes/goal.js.map +1 -0
  39. package/dist/src/kernel/nodes/index.d.ts +2 -1
  40. package/dist/src/kernel/nodes/index.js +3 -1
  41. package/dist/src/kernel/nodes/index.js.map +1 -1
  42. package/dist/src/kernel/templates/index.d.ts +27 -3
  43. package/dist/src/kernel/templates/index.js +78 -1
  44. package/dist/src/kernel/templates/index.js.map +1 -1
  45. package/dist/src/kernel/types.d.ts +41 -2
  46. package/dist/src/kernel/types.js.map +1 -1
  47. package/dist/src/persistent-acp-session.d.ts +76 -0
  48. package/dist/src/persistent-acp-session.js +409 -0
  49. package/dist/src/persistent-acp-session.js.map +1 -0
  50. package/dist/src/persistent-agy-session.js +1 -0
  51. package/dist/src/persistent-agy-session.js.map +1 -1
  52. package/dist/src/persistent-codex-app-session.d.ts +55 -26
  53. package/dist/src/persistent-codex-app-session.js +109 -24
  54. package/dist/src/persistent-codex-app-session.js.map +1 -1
  55. package/dist/src/persistent-codex-session.js +1 -0
  56. package/dist/src/persistent-codex-session.js.map +1 -1
  57. package/dist/src/persistent-cursor-session.js +1 -0
  58. package/dist/src/persistent-cursor-session.js.map +1 -1
  59. package/dist/src/persistent-custom-session.js +2 -0
  60. package/dist/src/persistent-custom-session.js.map +1 -1
  61. package/dist/src/persistent-gemini-session.js +1 -0
  62. package/dist/src/persistent-gemini-session.js.map +1 -1
  63. package/dist/src/persistent-grok-session.js +1 -0
  64. package/dist/src/persistent-grok-session.js.map +1 -1
  65. package/dist/src/persistent-opencode-session.js +1 -0
  66. package/dist/src/persistent-opencode-session.js.map +1 -1
  67. package/dist/src/persistent-session.js +1 -0
  68. package/dist/src/persistent-session.js.map +1 -1
  69. package/dist/src/sanitize.d.ts +10 -0
  70. package/dist/src/sanitize.js +26 -0
  71. package/dist/src/sanitize.js.map +1 -1
  72. package/dist/src/session-manager.d.ts +25 -20
  73. package/dist/src/session-manager.js +92 -43
  74. package/dist/src/session-manager.js.map +1 -1
  75. package/dist/src/types.d.ts +35 -1
  76. package/dist/src/types.js +2 -0
  77. package/dist/src/types.js.map +1 -1
  78. package/openclaw.plugin.json +1 -1
  79. package/package.json +2 -2
  80. package/skills/SKILL.md +8 -5
  81. package/skills/references/acp.md +4 -0
  82. package/skills/references/autoloop.md +27 -2
  83. package/skills/references/claude-cli-tracking.md +3 -1
  84. package/skills/references/cli.md +79 -39
  85. package/skills/references/dashboard.md +5 -1
  86. package/skills/references/multi-engine.md +39 -10
  87. package/skills/references/tools.md +77 -65
  88. package/skills/references/workflow.md +87 -13
@@ -8,57 +8,58 @@ All 78 tools are registered as OpenClaw plugin tools and exposed over MCP by `cl
8
8
 
9
9
  Start a persistent coding session with full CLI flag support.
10
10
 
11
- | Parameter | Type | Description |
12
- | ------------------------------------ | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
13
- | `name` | string | Session name (auto-generated if omitted) |
14
- | `cwd` | string | Working directory |
15
- | `engine` | `'claude'` \| `'codex'` \| `'codex-app'` \| `'agy'` \| `'grok'` \| `'opencode'` \| `'custom'` | Engine to use (default: `claude`). `agy` wraps Google Antigravity CLI. `grok` wraps xAI Grok Build and reports its own per-turn cost. `opencode` wraps sst/opencode (pass model as `provider/model`). Use `custom` with `customEngine` for any CLI. (`'gemini'` and `'cursor'` are still accepted for existing callers but are legacy — not version-tracked; use `agy` for Google and `grok` in place of Cursor.) |
16
- | `model` | string | Model alias or full name |
17
- | `permissionMode` | string | `acceptEdits`, `bypassPermissions`, `plan`, `auto`, `manual`, `dontAsk` (`default` = legacy alias for `manual`) |
18
- | `sandboxMode` | `'read-only'` \| `'workspace-write'` \| `'danger-full-access'` | Sandbox policy. Codex supports all values. `read-only` is enforced on every other built-in engine too: Claude → plan mode; Antigravity → its plan mode; OpenCode → a generated `clawo-readonly` agent denying `edit`/`bash`. Grok → its OS-enforced `--sandbox read-only` profile (refused for a project under the temp directory, on platforms without Seatbelt or Landlock, and when grok cannot apply it). A `custom` engine must map it via `permissionModes`, or the session refuses to start. Persisted across session resume. |
19
- | `allowedTools` | string[] | Tools to auto-approve |
20
- | `disallowedTools` | string[] | Tools to deny |
21
- | `maxTurns` | number | Max agent loop turns |
22
- | `maxBudgetUsd` | number | Max API spend (USD). Enforced by the runtime on every engine: once the session's cumulative cost reaches the cap, further sends are refused before the engine is spawned. See [observability.md](observability.md) for the accuracy caveat on engines that estimate token counts. |
23
- | `autoCompactPercent` | number | Compact the conversation before a send once `contextPercent` reaches this value (1–99). Off by default. For long-lived sessions, where cost grows with context size; survives a server restart. A failed compaction does not block the send. |
24
- | `systemPrompt` | string | Replace system prompt |
25
- | `appendSystemPrompt` | string | Append custom instructions to the system prompt. Claude Code and Grok take it natively; Codex, Antigravity and OpenCode have no such flag and receive it at the top of the first message of a conversation |
26
- | `agents` | object | Custom sub-agents JSON |
27
- | `agent` | string | Default agent to use |
28
- | `bare` | boolean | Skip hooks, LSP, auto-memory, CLAUDE.md |
29
- | `worktree` | string \| boolean | Run in git worktree |
30
- | `fallbackModel` | string \| string[] | Fallback model(s) when the primary is overloaded; an array is tried in order |
31
- | `resumeSessionId` | string | Resume existing session by ID |
32
- | `jsonSchema` | string | JSON Schema for structured output. Claude: `--json-schema` (inline). Codex: `--output-schema` (written to a temp file, requires Codex 0.132+). Other engines ignore it. |
33
- | `mcpConfig` | string \| string[] | MCP server config file(s) |
34
- | `settings` | string | Settings.json path or inline JSON |
35
- | `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). |
36
- | `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 |
37
- | `ignoreUserConfig` | boolean | Codex only. Run without loading `$CODEX_HOME/config.toml`, so an orchestrated run is decided by what the caller passed rather than by the machine's own Codex config — notably a `model = …` line in that file, which otherwise picks the model while the ledger records this engine's default. Auth still resolves from `CODEX_HOME`. |
38
- | `codexProfile` | string | Codex only. Named profile from `~/.codex/config.toml`, passed as `codex exec --profile` |
39
- | `restricted` | boolean | Claude Code only. Restricted mode (`--restricted`): the CLI removes the built-in tools that run commands or code — Bash, PowerShell, the REPL — plus `WebFetch` unless `tools` names them, and ignores user, project and local settings files. Separate from `sandboxMode: 'read-only'`: that maps to plan mode, which holds on its own, while this makes the shell absent rather than refused. It also drops the caller's CLAUDE.md and hooks, so it is never switched on implicitly. |
40
- | `betas` | string \| string[] | Custom beta headers |
41
- | `enableAgentTeams` | boolean | Enable experimental agent teams |
42
- | `enableAutoMode` | boolean | Enable auto permission mode |
43
- | `customEngine` | object | Custom engine config (required when `engine='custom'`). See [Multi-Engine: Custom Engine](./multi-engine.md#custom-engine-engine-custom). |
44
- | `crossSessionInbound` | string | `accept` / `hold` / `refuse` — policy for peer messages from other Claude Code sessions on this machine (Claude engine). Delivered as a settings key; there is no CLI flag. Without it the CLI holds messages whose two sides run different permission modes, which is the usual orchestrated-session-to-human-terminal case |
45
- | `includeHookEvents` | boolean | Stream hook lifecycle events (PreToolUse/PostToolUse) as `system` events |
46
- | `forwardSubagentText` | boolean | Forward subagent text and thinking into the output stream (Claude engine, CLI 2.1.211+). Without it the parent stream stays quiet while a subagent works |
47
- | `chrome` | boolean | Let the session use the user's Chrome through the Claude in Chrome extension, acting with that browser's sign-ins (Claude engine, `--chrome`). Off by default. Needs Chrome running with the extension and a claude.ai login; survives a server restart |
48
- | `permissionPromptTool` | string | MCP tool name to delegate permission prompts to (non-interactive use). When omitted, the session runs with `--permission-prompts none`: a prompt nobody could answer is denied rather than left waiting until the turn timeout. |
49
- | `excludeDynamicSystemPromptSections` | boolean | Move cwd/env/git context from system prompt to user message for better prompt cache hits; auto-enabled with `bare: true` |
50
- | `enablePromptCaching1H` | boolean | Enable 1-hour prompt cache TTL (vs default 5-min); auto-enabled with `bare: true` |
51
- | `debug` | string \| string[] | Debug categories to enable (e.g. `"api,mcp"` or `["api", "mcp"]`) |
52
- | `debugFile` | string | File path to write debug output to |
53
- | `fromPr` | string | Resume a session linked to a GitHub PR number or URL |
54
- | `channels` | string \| string[] | MCP channel subscription spec (research preview) |
55
- | `dangerouslyLoadDevelopmentChannels` | string \| string[] | Development MCP channel subscriptions (research preview) |
56
- | `forkSubagent` | boolean | Fork subagent for non-interactive sessions (sets `CLAUDE_CODE_FORK_SUBAGENT=1`) |
57
- | `enableToolSearch` | boolean | Enable Vertex AI tool search (sets `ENABLE_TOOL_SEARCH=1`) |
58
- | `otelLogUserPrompts` | boolean | OpenTelemetry: log user prompts (sets `OTEL_LOG_USER_PROMPTS=1`) |
59
- | `otelLogRawApiBodies` | boolean | OpenTelemetry: log raw API request/response bodies (sets `OTEL_LOG_RAW_API_BODIES=1`); debug only |
60
- | `bedrockServiceTier` | `'default'` \| `'flex'` \| `'priority'` | AWS Bedrock service tier (sets `ANTHROPIC_BEDROCK_SERVICE_TIER`); only effective when routing through Bedrock |
61
- | `effort` | `'low'` \| `'medium'` \| `'high'` \| `'xhigh'` \| `'max'` \| `'ultra'` \| `'auto'` | Reasoning effort level. Engines do not share one ladder: Claude Code takes up to `max`, Codex adds `ultra`, Grok stops at `xhigh`, Antigravity at `high`, and OpenCode forwards the level to its provider unvalidated. A level above an engine's ceiling clamps rather than being dropped. `high` and above trigger the `ultrathink` prefix on Claude user messages. |
11
+ | Parameter | Type | Description |
12
+ | ------------------------------------ | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
13
+ | `name` | string | Session name (auto-generated if omitted) |
14
+ | `cwd` | string | Working directory |
15
+ | `engine` | `'claude'` \| `'codex'` \| `'codex-app'` \| `'agy'` \| `'grok'` \| `'opencode'` \| `'acp'` \| `'custom'` | Engine to use (default: `claude`). `agy` wraps Google Antigravity CLI. `grok` wraps xAI Grok Build and reports its own per-turn cost. `opencode` wraps sst/opencode (pass model as `provider/model`). `acp` drives any Agent Client Protocol agent named by `acpAgent`. Use `custom` with `customEngine` for any CLI. (`'gemini'` and `'cursor'` are still accepted for existing callers but are legacy — not version-tracked; use `agy` for Google and `grok` in place of Cursor.) |
16
+ | `model` | string | Model alias or full name |
17
+ | `permissionMode` | string | `acceptEdits`, `bypassPermissions`, `plan`, `auto`, `manual`, `dontAsk` (`default` = legacy alias for `manual`) |
18
+ | `sandboxMode` | `'read-only'` \| `'workspace-write'` \| `'danger-full-access'` | Sandbox policy. Codex supports all values. `read-only` is enforced on every other built-in engine too: Claude → plan mode; Antigravity → its plan mode; OpenCode → a generated `clawo-readonly` agent denying `edit`/`bash`. Grok → its OS-enforced `--sandbox read-only` profile (refused for a project under the temp directory, on platforms without Seatbelt or Landlock, and when grok cannot apply it). A `custom` engine must map it via `permissionModes`, or the session refuses to start. Persisted across session resume. |
19
+ | `allowedTools` | string[] | Tools to auto-approve |
20
+ | `disallowedTools` | string[] | Tools to deny |
21
+ | `maxTurns` | number | Max agent loop turns |
22
+ | `maxBudgetUsd` | number | Max API spend (USD). Enforced by the runtime on every engine: once the session's cumulative cost reaches the cap, further sends are refused before the engine is spawned. See [observability.md](observability.md) for the accuracy caveat on engines that estimate token counts. |
23
+ | `autoCompactPercent` | number | Compact the conversation before a send once `contextPercent` reaches this value (1–99). Off by default. For long-lived sessions, where cost grows with context size; survives a server restart. A failed compaction does not block the send. |
24
+ | `systemPrompt` | string | Replace system prompt |
25
+ | `appendSystemPrompt` | string | Append custom instructions to the system prompt. Claude Code and Grok take it natively; Codex, Antigravity and OpenCode have no such flag and receive it at the top of the first message of a conversation |
26
+ | `agents` | object | Custom sub-agents JSON |
27
+ | `agent` | string | Default agent to use |
28
+ | `bare` | boolean | Skip hooks, LSP, auto-memory, CLAUDE.md |
29
+ | `worktree` | string \| boolean | Run in git worktree |
30
+ | `fallbackModel` | string \| string[] | Fallback model(s) when the primary is overloaded; an array is tried in order |
31
+ | `resumeSessionId` | string | Resume existing session by ID |
32
+ | `jsonSchema` | string | JSON Schema for structured output. Claude: `--json-schema` (inline). Codex: `--output-schema` (written to a temp file, requires Codex 0.132+). Other engines ignore it. |
33
+ | `mcpConfig` | string \| string[] | MCP server config file(s) |
34
+ | `settings` | string | Settings.json path or inline JSON |
35
+ | `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). |
36
+ | `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 |
37
+ | `ignoreUserConfig` | boolean | Codex only. Run without loading `$CODEX_HOME/config.toml`, so an orchestrated run is decided by what the caller passed rather than by the machine's own Codex config — notably a `model = …` line in that file, which otherwise picks the model while the ledger records this engine's default. Auth still resolves from `CODEX_HOME`. |
38
+ | `codexProfile` | string | Codex only. Named profile from `~/.codex/config.toml`, passed as `codex exec --profile` |
39
+ | `restricted` | boolean | Claude Code only. Restricted mode (`--restricted`): the CLI removes the built-in tools that run commands or code — Bash, PowerShell, the REPL — plus `WebFetch` unless `tools` names them, and ignores user, project and local settings files. Separate from `sandboxMode: 'read-only'`: that maps to plan mode, which holds on its own, while this makes the shell absent rather than refused. It also drops the caller's CLAUDE.md and hooks, so it is never switched on implicitly. |
40
+ | `betas` | string \| string[] | Custom beta headers |
41
+ | `enableAgentTeams` | boolean | Enable experimental agent teams |
42
+ | `enableAutoMode` | boolean | Enable auto permission mode |
43
+ | `customEngine` | object | Custom engine config (required when `engine='custom'`). See [Multi-Engine: Custom Engine](./multi-engine.md#custom-engine-engine-custom). |
44
+ | `acpAgent` | string \| object | The ACP agent (required when `engine='acp'`): a bundled preset id (`kimi-code`, `dsh`), or, from a local caller only, `{ name, command, commandEnv?, args?, env? }`. See [Multi-Engine: ACP agents](./multi-engine.md#acp-agents-engine-acp). |
45
+ | `crossSessionInbound` | string | `accept` / `hold` / `refuse` — policy for peer messages from other Claude Code sessions on this machine (Claude engine). Delivered as a settings key; there is no CLI flag. Without it the CLI holds messages whose two sides run different permission modes, which is the usual orchestrated-session-to-human-terminal case |
46
+ | `includeHookEvents` | boolean | Stream hook lifecycle events (PreToolUse/PostToolUse) as `system` events |
47
+ | `forwardSubagentText` | boolean | Forward subagent text and thinking into the output stream (Claude engine, CLI 2.1.211+). Without it the parent stream stays quiet while a subagent works |
48
+ | `chrome` | boolean | Let the session use the user's Chrome through the Claude in Chrome extension, acting with that browser's sign-ins (Claude engine, `--chrome`). Off by default. Needs Chrome running with the extension and a claude.ai login; survives a server restart |
49
+ | `permissionPromptTool` | string | MCP tool name to delegate permission prompts to (non-interactive use). When omitted, the session runs with `--permission-prompts none`: a prompt nobody could answer is denied rather than left waiting until the turn timeout. |
50
+ | `excludeDynamicSystemPromptSections` | boolean | Move cwd/env/git context from system prompt to user message for better prompt cache hits; auto-enabled with `bare: true` |
51
+ | `enablePromptCaching1H` | boolean | Enable 1-hour prompt cache TTL (vs default 5-min); auto-enabled with `bare: true` |
52
+ | `debug` | string \| string[] | Debug categories to enable (e.g. `"api,mcp"` or `["api", "mcp"]`) |
53
+ | `debugFile` | string | File path to write debug output to |
54
+ | `fromPr` | string | Resume a session linked to a GitHub PR number or URL |
55
+ | `channels` | string \| string[] | MCP channel subscription spec (research preview) |
56
+ | `dangerouslyLoadDevelopmentChannels` | string \| string[] | Development MCP channel subscriptions (research preview) |
57
+ | `forkSubagent` | boolean | Fork subagent for non-interactive sessions (sets `CLAUDE_CODE_FORK_SUBAGENT=1`) |
58
+ | `enableToolSearch` | boolean | Enable Vertex AI tool search (sets `ENABLE_TOOL_SEARCH=1`) |
59
+ | `otelLogUserPrompts` | boolean | OpenTelemetry: log user prompts (sets `OTEL_LOG_USER_PROMPTS=1`) |
60
+ | `otelLogRawApiBodies` | boolean | OpenTelemetry: log raw API request/response bodies (sets `OTEL_LOG_RAW_API_BODIES=1`); debug only |
61
+ | `bedrockServiceTier` | `'default'` \| `'flex'` \| `'priority'` | AWS Bedrock service tier (sets `ANTHROPIC_BEDROCK_SERVICE_TIER`); only effective when routing through Bedrock |
62
+ | `effort` | `'low'` \| `'medium'` \| `'high'` \| `'xhigh'` \| `'max'` \| `'ultra'` \| `'auto'` | Reasoning effort level. Engines do not share one ladder: Claude Code takes up to `max`, Codex adds `ultra`, Grok stops at `xhigh`, Antigravity at `high`, and OpenCode forwards the level to its provider unvalidated. A level above an engine's ceiling clamps rather than being dropped. `high` and above trigger the `ultrathink` prefix on Claude user messages. |
62
63
 
63
64
  ### `session_send`
64
65
 
@@ -297,38 +298,37 @@ Returns `{ ok, stdout, stderr }`.
297
298
 
298
299
  ### `codex_goal_set`
299
300
 
300
- Set a long-horizon objective. Sends `/goal <objective>` via the app-server. **Requires `engine: "codex-app"`.**
301
+ 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
302
 
302
- | Parameter | Type | Required |
303
- | ----------- | ------ | -------- |
304
- | `name` | string | yes |
305
- | `objective` | string | yes |
306
- | `timeout` | number | |
303
+ | Parameter | Type | Required | Notes |
304
+ | ------------- | ------ | -------- | ---------------------------------------------------------------- |
305
+ | `name` | string | yes | |
306
+ | `objective` | string | yes | |
307
+ | `tokenBudget` | number | | Tokens the goal may spend; it stops as `budgetLimited` past this |
307
308
 
308
- Returns `{ ok, text, goal }` where `goal` is `{ objective, status: "active"|"paused"|"budgetLimited"|"complete", tokensUsed, timeUsedSeconds, tokenBudget?, ... }` or `null`.
309
+ Returns `{ ok, goal }` where `goal` is `{ objective, status, tokenBudget, tokensUsed, timeUsedSeconds, ... }`. `status` is one of `active`, `paused`, `blocked`, `usageLimited`, `budgetLimited`, `complete`.
309
310
 
310
311
  ### `codex_goal_get`
311
312
 
312
- Read the cached goal state. Pure read — does not send a turn.
313
+ Ask the app-server for the goal (`thread/goal/get`). Sends no turn.
313
314
 
314
315
  | Parameter | Type | Required |
315
316
  | --------- | ------ | -------- |
316
317
  | `name` | string | yes |
317
318
 
318
- Returns `{ ok, goal }` (`null` if no goal active).
319
+ Returns `{ ok, goal }` (`null` if the thread has no goal).
319
320
 
320
321
  ### `codex_goal_pause` / `codex_goal_resume` / `codex_goal_clear`
321
322
 
322
- Send `/goal pause`, `/goal resume`, or `/goal clear` respectively. Requires `engine: "codex-app"`.
323
+ 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
324
 
324
325
  | Parameter | Type | Required |
325
326
  | --------- | ------ | -------- |
326
327
  | `name` | string | yes |
327
- | `timeout` | number | |
328
328
 
329
- Returns `{ ok, text, goal }`.
329
+ Returns `{ ok, goal }` (`null` after `clear`).
330
330
 
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.
331
+ 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
332
 
333
333
  ### Codex app-server RPCs
334
334
 
@@ -645,7 +645,11 @@ or smaller values are rejected, and there is deliberately no
645
645
  Each successful increase appends one migration row to `decisions.jsonl`; the
646
646
  original run spec, history, and prior audit bytes are not rewritten. The
647
647
  matching live awaiting-resume condition is advanced without replaying the
648
- timed-out logical dispatch.
648
+ timed-out logical dispatch. A live ordinary or activity-lease pause
649
+ (`pending_dispatch` null) resumes with no timeout fields: the call returns once
650
+ the run is active again, the lease re-arms without moving the hard deadline,
651
+ and Planner chat parked during the pause is then delivered once, in order. A
652
+ no-option resume does not clear a pending send timeout.
649
653
 
650
654
  ### `autoloop_chat`
651
655
 
@@ -656,6 +660,14 @@ Send a message into the Planner conversation.
656
660
  | `run_id` | string | yes |
657
661
  | `text` | string | yes |
658
662
 
663
+ The message is accepted only once it is stored in the run checkpoint; otherwise
664
+ the call fails with `autoloop chat could not be persisted` (or a stopping,
665
+ restoring or limit error) and nothing is sent. Accepted chat survives
666
+ `autoloop_stop` and owner loss and is delivered once, in order, after a resume.
667
+ A message that was mid-delivery when the run stopped is not resent; it is
668
+ reported through `unconfirmed_chat` in `autoloop_status` and one notice in chat
669
+ history.
670
+
659
671
  ### `autoloop_status`
660
672
 
661
673
  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