feat(S-601): Create docs/ai-cli-dispatch.md
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
# 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
|
||||
|
||||
The tool is a lightweight sync-only dispatcher. It does not implement streaming, chat sessions, or ACP orchestration. For ACP-based harnesses, see `docs/openclaw-acp-orchestration.md`.
|
||||
|
||||
## Setup
|
||||
|
||||
From the repo or installed skill directory:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch list [--json|--text]
|
||||
ai-cli-dispatch run --client <client> --prompt <prompt> [--json|--text]
|
||||
ai-cli-dispatch dispatch <prompt> [--client <client>] [--json|--text]
|
||||
ai-cli-dispatch --help
|
||||
```
|
||||
|
||||
### `list`
|
||||
|
||||
Discover and report all supported clients.
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch list --json
|
||||
```
|
||||
|
||||
Example JSON output:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"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:
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch list --text
|
||||
```
|
||||
|
||||
### `run`
|
||||
|
||||
Execute a prompt directly through a named client.
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch run --client codex --prompt "refactor this function"
|
||||
ai-cli-dispatch run --client claude --prompt "add tests for auth middleware"
|
||||
ai-cli-dispatch run --client opencode --prompt "migrate to ESM"
|
||||
```
|
||||
|
||||
The prompt is forwarded with each client’s native argument shape:
|
||||
|
||||
| Client | Arguments passed |
|
||||
|---|---|
|
||||
| `codex` | `exec "<prompt>"` |
|
||||
| `claude` | `-p "<prompt>"` |
|
||||
| `opencode` | `"<prompt>"` |
|
||||
|
||||
### `dispatch`
|
||||
|
||||
Auto-resolve the client from prompt keywords, then execute.
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch dispatch "fix the bug" --client claude
|
||||
```
|
||||
|
||||
## 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:
|
||||
|
||||
```text
|
||||
~/.openclaw/ai-cli-dispatch.json
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"paths": {
|
||||
"codex": "/usr/local/bin/codex",
|
||||
"claude": "/opt/homebrew/bin/claude"
|
||||
},
|
||||
"defaultClient": "claude"
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
JSON success shape (`run` and `dispatch`):
|
||||
|
||||
```json
|
||||
{
|
||||
"stdout": "...",
|
||||
"stderr": "...",
|
||||
"exitCode": 0
|
||||
}
|
||||
```
|
||||
|
||||
JSON error shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "..."
|
||||
}
|
||||
```
|
||||
|
||||
Exit codes:
|
||||
|
||||
| Code | Meaning |
|
||||
|---|---|
|
||||
| `0` | Success |
|
||||
| `1` | Missing/unknown command, missing argument, unknown client, resolution failure, or execution 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 300000ms`
|
||||
|
||||
Meaning: the client subprocess did not finish within the default 5-minute timeout.
|
||||
|
||||
Action: the client may be waiting for interactive input or the task is too large. Break the prompt into smaller pieces, or run the client directly to diagnose.
|
||||
|
||||
### `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.
|
||||
|
||||
## Common Flows
|
||||
|
||||
### Check what is installed
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch list --json
|
||||
```
|
||||
|
||||
### Run a quick task through a specific client
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch run --client codex --prompt "fix lint errors in src/app.ts"
|
||||
```
|
||||
|
||||
### Let the tool pick the client from the prompt
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch dispatch "claude: add unit tests for utils.ts"
|
||||
```
|
||||
|
||||
### Force a client when the prompt is ambiguous
|
||||
|
||||
```bash
|
||||
ai-cli-dispatch dispatch "review this PR" --client claude
|
||||
```
|
||||
|
||||
## Coexistence with ACP
|
||||
|
||||
`ai-cli-dispatch` is a direct subprocess dispatcher. It runs the client binary synchronously and returns its output. 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.
|
||||
- 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 client’s stable CLI contract.
|
||||
- The default timeout is 5 minutes (`300_000` ms).
|
||||
- On Windows, discovery uses `where` instead of `which` and `.exe` extensions are assumed.
|
||||
Reference in New Issue
Block a user