Files
stef-openclaw-skills/docs/ai-cli-dispatch.md
T

12 KiB
Raw Blame History

ai-cli-dispatch

Dispatch AI CLI coding tasks to available clients (Codex, Claude Code, OpenCode) with automatic discovery, version checking, and execution.

Scope

  • discover installed AI CLI clients on the host
  • report client versions and availability
  • dispatch a prompt to a specific client by name
  • auto-resolve the best client from prompt keywords
  • forward arguments natively to each client
  • run tasks asynchronously as background jobs with lifecycle management
  • run tasks synchronously when blocking until completion is desired

The tool supports both async (default) and sync execution modes. Async jobs run as detached background processes and are tracked on disk. For ACP-based harnesses, see docs/openclaw-acp-orchestration.md.

Setup

From the repo or installed skill directory:

cd tools/ai-cli-dispatch
npm install

The dispatcher itself requires only Node.js 20+ and npm. The actual AI CLI clients (codex, claude, opencode) are discovered from the host PATH; they are not bundled.

Commands

ai-cli-dispatch list [--json|--text]
ai-cli-dispatch run --client <client> --prompt <prompt> [--sync] [--timeout <ms>] [--debug] [--json|--text]
ai-cli-dispatch dispatch <prompt> [--client <client>] [--sync] [--timeout <ms>] [--debug] [--json|--text]
ai-cli-dispatch start --client <client> --prompt <prompt> [--timeout <ms>] [--debug] [--json|--text]
ai-cli-dispatch status <job-id> [--json|--text]
ai-cli-dispatch results <job-id> [--json|--text]
ai-cli-dispatch cancel <job-id> [--json|--text]
ai-cli-dispatch list-jobs [--status running|completed|failed] [--json|--text]
ai-cli-dispatch cleanup-jobs [--max-age <number>[h|m|s|d]] [--json|--text]
ai-cli-dispatch --help

list

Discover and report all supported clients.

ai-cli-dispatch list --json

Example JSON output:

[
  {
    "name": "codex",
    "path": "/usr/local/bin/codex",
    "version": "1.2.3",
    "found": true
  },
  {
    "name": "claude",
    "found": false
  },
  {
    "name": "opencode",
    "path": "/opt/homebrew/bin/opencode",
    "version": "0.5.1",
    "found": true
  }
]

Use --text for human-readable checkmarks:

ai-cli-dispatch list --text

run

Execute a prompt directly through a named client. By default, this starts a background job and returns immediately.

# Async (default) — returns a job ID
ai-cli-dispatch run --client codex --prompt "refactor this function"

# Sync — blocks until the client finishes
ai-cli-dispatch run --client claude --prompt "add tests for auth middleware" --sync

# With custom timeout and debug diagnostics
ai-cli-dispatch run --client opencode --prompt "migrate to ESM" --timeout 600000 --debug

The prompt is forwarded with each clients native argument shape:

Client Arguments passed
codex exec "<prompt>"
claude -p "<prompt>"
opencode "<prompt>"

dispatch

Auto-resolve the client from prompt keywords, then execute. Defaults to async; use --sync to block.

ai-cli-dispatch dispatch "use claude to write tests"
ai-cli-dispatch dispatch "codex refactor auth module"
ai-cli-dispatch dispatch "opencode migrate to ESM"

Keyword matching is case-insensitive and ordered:

  1. --client flag (highest precedence)
  2. "open code" (spaced variant) → opencode
  3. "claude"claude
  4. "codex"codex
  5. "opencode"opencode
  6. defaultClient from config (lowest precedence)

Override auto-resolution explicitly:

ai-cli-dispatch dispatch "fix the bug" --client claude

start

Explicitly start a background job (same as run without --sync). Useful when you want the async behavior unambiguously.

ai-cli-dispatch start --client codex --prompt "refactor this function"

status

Check the status of a background job.

ai-cli-dispatch status <job-id>

JSON output:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "client": "codex",
  "prompt": "refactor this function",
  "status": "running",
  "startedAt": "2026-05-19T12:34:56.789Z",
  "pid": 12345
}

Statuses: running, completed, failed, timed_out, cancelled.

results

Retrieve the execution result of a completed job.

ai-cli-dispatch results <job-id>

JSON output:

{
  "stdout": "...",
  "stderr": "...",
  "exitCode": 0,
  "client": "codex",
  "durationMs": 45231
}

Requires status completed. For failed or timed_out jobs, use status to see the captured error.

cancel

Cancel a running job.

ai-cli-dispatch cancel <job-id>

list-jobs

List all tracked jobs, newest first.

ai-cli-dispatch list-jobs --json
ai-cli-dispatch list-jobs --status running --json

cleanup-jobs

Remove job files older than a threshold. Default unit is hours.

ai-cli-dispatch cleanup-jobs --max-age 24h
ai-cli-dispatch cleanup-jobs --max-age 30m

Async vs Sync Mode

By default, run and dispatch are async: they start a detached background process, persist a job record to disk, and return a job ID immediately. This is ideal for:

  • Fire-and-forget tasks that may run for minutes
  • Long-running codegen or migration tasks
  • Scenarios where the caller should not block

Use --sync when you need:

  • The complete output before the next step
  • Synchronous composition in shell pipelines or scripts
  • Immediate error propagation to the calling process
Aspect Async (default) Sync (--sync)
Return value Job ID + status Full stdout/stderr + exit code
Process model Detached child, parent exits immediately Attached child, parent waits
Persistence Job file written to disk No job file
Timeout Enforced via child.kill() after --timeout Enforced via child.kill() after --timeout

Client Discovery

Discovery searches PATH in this order for each client name:

  1. codex — OpenAI Codex CLI
  2. claude — Anthropic Claude Code
  3. opencode — OpenCode CLI

The search uses which (or where on Windows) first, then falls back to a manual PATH directory scan. If a binary is found, --version is invoked to extract a semver string.

Configuration

Optional config file:

~/.openclaw/ai-cli-dispatch.json

Example:

{
  "paths": {
    "codex": "/usr/local/bin/codex",
    "claude": "/opt/homebrew/bin/claude"
  },
  "defaultClient": "claude",
  "timeout": 300000
}

Resolution priority for paths and default client (highest to lowest):

  1. CLI flag (--client, --codex-path, etc.)
  2. Environment variable (AI_CLI_CODEX_PATH, AI_CLI_DEFAULT_CLIENT, etc.)
  3. Config file (paths, defaultClient)
  4. which / where discovery

Supported env vars:

Variable Purpose
AI_CLI_CODEX_PATH Override codex binary path
AI_CLI_CLAUDE_PATH Override claude binary path
AI_CLI_OPENCODE_PATH Override opencode binary path
AI_CLI_DEFAULT_CLIENT Override default client (codex, claude, or opencode)

Output Model

Default output is JSON. Use --text to stream raw stdout/stderr directly.

Sync JSON success shape (run --sync, dispatch --sync)

{
  "stdout": "...",
  "stderr": "...",
  "exitCode": 0,
  "client": "codex",
  "durationMs": 45231
}

Async JSON success shape (run, dispatch, start)

{
  "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "client": "codex",
  "status": "running"
}

Job status shape (status)

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "client": "codex",
  "prompt": "refactor this function",
  "status": "running",
  "startedAt": "2026-05-19T12:34:56.789Z",
  "pid": 12345
}

Job result shape (results)

{
  "stdout": "...",
  "stderr": "...",
  "exitCode": 0,
  "client": "codex",
  "durationMs": 45231
}

JSON error shape

{
  "error": "..."
}

Exit codes:

Code Meaning
0 Success
1 Missing/unknown command, missing argument, unknown client, resolution failure, execution error, or job lifecycle error

Error Handling Guidance

Client "<name>" not found or not installed

Meaning: the requested client binary is not on PATH and not overridden by config.

Actions:

  1. Confirm the client is installed (codex --version, claude --version, etc.)
  2. Check that its directory is on PATH
  3. Or override the path in ~/.openclaw/ai-cli-dispatch.json

Prompt cannot be empty

Meaning: the prompt string was empty or whitespace-only.

Action: supply a non-empty --prompt or positional prompt argument.

Execution timed out after 600000ms

Meaning: the client subprocess did not finish within the timeout.

Action: the client may be waiting for interactive input or the task is too large. Break the prompt into smaller pieces, increase --timeout, or run the client directly to diagnose. Async jobs that time out are recorded with status timed_out.

Could not resolve client from prompt

Meaning: dispatch found no matching keyword and no defaultClient is configured.

Action: include a client name in the prompt (e.g., "use claude to ...") or set defaultClient in config.

Job "<job-id>" not found

Meaning: the requested job ID does not exist in the job store.

Action: verify the job ID. Job files are stored under ~/.openclaw/ai-cli-dispatch/jobs/. If the directory was cleaned or the host restarted, old jobs may have been removed.

Job "<job-id>" result is not available (status: <status>)

Meaning: results was called on a job that has not finished (running) or finished unsuccessfully (failed, timed_out, cancelled).

Action: poll status until the job reaches completed, or inspect status output for the error field.

Job Lifecycle Workflows

Fire-and-forget

JOB=$(ai-cli-dispatch run --client codex --prompt "refactor auth" --json | jq -r '.jobId')
# caller continues immediately

Poll until completion

JOB=$(ai-cli-dispatch start --client claude --prompt "write tests" --json | jq -r '.jobId')
while [ "$(ai-cli-dispatch status "$JOB" --json | jq -r '.status')" = "running" ]; do
  sleep 5
done
ai-cli-dispatch results "$JOB" --json

Sync one-shot

ai-cli-dispatch run --client opencode --prompt "fix lint" --sync --text

Batch cleanup

ai-cli-dispatch cleanup-jobs --max-age 24h

Common Flows

Check what is installed

ai-cli-dispatch list --json

Run a quick task through a specific client (async)

ai-cli-dispatch run --client codex --prompt "fix lint errors in src/app.ts"

Run a quick task synchronously

ai-cli-dispatch run --client codex --prompt "fix lint errors in src/app.ts" --sync

Let the tool pick the client from the prompt

ai-cli-dispatch dispatch "claude: add unit tests for utils.ts"

Force a client when the prompt is ambiguous

ai-cli-dispatch dispatch "review this PR" --client claude

Coexistence with ACP

ai-cli-dispatch is a direct subprocess dispatcher. It is not an ACP agent and does not participate in ACP orchestration.

  • Use ai-cli-dispatch when you need a quick, local, one-shot CLI execution or a background job.
  • Use ACP (docs/openclaw-acp-orchestration.md) when you need session-bound coding harnesses with thread context, multi-turn review, or orchestrator-managed verification gates.

Implementation Notes

  • The dispatcher is TypeScript/Node.js with a single external dependency (minimist).
  • Client arguments are hardcoded per tool to match each clients stable CLI contract.
  • The default timeout is 10 minutes (600_000 ms); override with --timeout or config.
  • On Windows, discovery uses where instead of which and .exe extensions are assumed.
  • Async jobs run as detached processes with stdio: ["ignore", "pipe", "pipe"] so the dispatcher can exit without waiting.
  • Job files are written atomically to ~/.openclaw/ai-cli-dispatch/jobs/<jobId>.json.