Agentic AI Atlasby a5c.ai
OverviewWikiGraphFor AgentsEdgesSearchWorkspace
/
GitHubDocsDiscord
iiRecord
Agentic AI Atlas · `adapters launch` — Unified Harness Launcher
page:docs-adapters-archive-design-launchera5c.ai
Search record views/
Record · tabs

Available views

II.Record viewspp. 1 - 1
overviewarticlejsongraph
II.
Page overview

page:docs-adapters-archive-design-launcher

Reference · live

`adapters launch` — Unified Harness Launcher overview

Inspect the raw attributes, linked wiki pages, and inbound or outbound graph edges for page:docs-adapters-archive-design-launcher.

PageOutgoing · 0Incoming · 1

Attributes

nodeKind
Page
sourcePath
docs/adapters/archive/design/launcher.md
sourceKind
repo-docs
title
`adapters launch` — Unified Harness Launcher
displayName
`adapters launch` — Unified Harness Launcher
slug
docs/adapters/archive/design/launcher
articlePath
wiki/docs/adapters/archive/design/launcher.md
article
# `adapters launch` — Unified Harness Launcher > Archived design document. Preserved for historical context; not part of the current normative `reference/` contract. **Specification v1.0** | `@a5c-ai/adapters-cli` --- ## 1. Overview `adapters launch` is a CLI command that launches (or resumes) an interactive or non-interactive coding agent session with full stdin/stdout passthrough. Unlike `adapters run`, which parses and normalizes agent output into the `AgentEvent` stream, `adapters launch` acts as a **transparent proxy** — the user interacts directly with the harness as if they invoked it natively. The key differentiation: | Concern | `adapters run` | `adapters launch` | |---|---|---| | Output format | Normalized `AgentEvent` stream | Raw harness output (bypass) | | Input format | `RunOptions` / SDK API | Raw stdin passthrough | | Provider config | N/A (each harness's own) | Unified provider/model resolution | | Proxy orchestration | No | Yes (`--with-proxy-if-needed`) | | Use case | Programmatic orchestration, multi-agent | Direct harness usage with provider flexibility | ### 1.1 Cross-References | Concept | Spec | |---|---| | Provider/model configuration | `docs/adapters-provider-config.md` | | `adapters-proxy` bridge package | `docs/provider-adapter.md` | | Adapter system | `05-adapter-system.md` | | Built-in adapters | `12-built-in-adapters.md` | | CLI reference | `10-cli-reference.md` | | Process lifecycle | `11-process-lifecycle-and-platform.md` | --- ## 2. Command Syntax ``` adapters launch <harness> [provider] [flags...] ``` ### 2.1 Positional Arguments | Argument | Required | Description | |---|---|---| | `<harness>` | Yes | Target harness name. Must be a registered `SubprocessAdapter.agent` value: `claude`, `codex`, `gemini`, `opencode`, `copilot`, `cursor`, `pi`, `omp`, `openclaw`, `hermes`, `droid`, `amp`, `qwen` | | `[provider]` | No | Provider/backend identifier. If omitted, uses the harness's default native provider. See §3 for the full taxonomy. | ### 2.2 Flags #### Provider Configuration | Flag | Short | Type | Description | |---|---|---|---| | `--model` | `-m` | `string` | Model identifier (provider-specific format). Required for non-default providers. | | `--api-key` | | `string` | API key for the target provider. Can also be set via provider-specific env vars. | | `--api-base` | | `string` | Custom API base URL. Overrides provider defaults. | | `--region` | | `string` | Cloud region (for Bedrock, Vertex). | | `--project` | | `string` | Cloud project ID (for Vertex, Foundry). | | `--resource-group` | | `string` | Resource group (for Azure/Foundry). | | `--endpoint-name` | | `string` | Named deployment/endpoint (Azure, Foundry, Bedrock). | | `--transport` | `-t` | `string` | Wire protocol the harness should speak. One of: `anthropic`, `openai-chat`, `openai-responses`, `google`. Default: auto-detected from harness+provider. | | `--profile` | | `string` | Named provider profile from `~/.adapters/providers.json`. | | `--auth-command` | | `string` | External command that emits a bearer token on stdout. | #### Proxy Control | Flag | Type | Default | Description | |---|---|---|---| | `--with-proxy-if-needed` | `boolean` | `false` | Launch `adapters-proxy` automatically if the harness cannot speak the provider's native transport directly. | | `--with-proxy` | `boolean` | `false` | Force proxy launch even if the harness supports the provider natively. Useful for observability/logging. | | `--no-proxy` | `boolean` | `false` | Explicitly disable proxy. Error if the harness cannot reach the provider without one. | | `--proxy-port` | `number` | `0` (auto) | Port for the proxy server. `0` = ephemeral port. | | `--proxy-log-level` | `string` | `warn` | Log level for the proxy process: `debug`, `info`, `warn`, `error`. | #### Session Control | Flag | Short | Type | Description | |---|---|---|---| | `--resume` | `-r` | `string` | Resume an existing session by ID or name. Passes the appropriate resume flag to the harness. | | `--session-id` | `-s` | `string` | Explicit session ID for a new session. | #### Execution Mode | Flag | Short | Type | Description | |---|---|---|---| | `--prompt` | `-p` | `string` | Initial prompt. If set, runs in **non-interactive** mode: sends the prompt, streams output, and exits when the harness exits. If omitted, runs in **interactive** mode with full stdin/stdout passthrough. | | `--max-turns` | | `number` | Turn limit (non-interactive mode). | | `--max-budget-usd` | | `number` | Cost limit (where harness supports it). | #### Harness Passthrough | Flag | Type | Description | |---|---|---| | `--harness-args` | `string[]` | Raw arguments forwarded verbatim to the harness CLI after all adapters-managed args. Use `--` separator: `adapters launch claude api -- --bare --verbose` | #### General | Flag | Short | Type | Default | Description | |---|---|---|---|---| | `--json` | | `boolean` | `false` | Output machine-readable JSON for launch status and proxy lifecycle events (does not affect harness output). | | `--debug` | `-d` | `boolean` | `false` | Debug mode. Logs proxy and harness process details. | | `--dry-run` | | `boolean` | `false` | Print the resolved command, env vars, and proxy config without executing. | --- ## 3. Provider Taxonomy Providers are organized into categories. Each provider implies a specific wire transport protocol and authentication mechanism. ### 3.1 Provider Categories | Category | Provider IDs | Wire Protocol | Auth Mechanism | |---|---|---|---| | **Direct API** | `api` | Provider-native | API key | | **Cloud (AWS)** | `bedrock` | Bedrock Converse / Anthropic Messages | AWS IAM / STS / Profile | | **Cloud (GCP)** | `vertex` | Vertex AI / Google GenAI | ADC / Service Account / OAuth | | **Cloud (Azure)** | `azure`, `foundry` | Azure OpenAI / Foundry | API key / AD token / SPN | | **OAuth** | `oauth` | Provider-native | OAuth2 browser flow | | **Local** | `local`, `ollama` | OpenAI Chat / Responses | None (localhost) | | **Custom** | `custom` | Any (requires `--transport`) | Any (via flags) | ### 3.2 Provider ↔ Harness Native Support Matrix This matrix defines which harness/provider combinations work **without** a proxy: | | `api` | `bedrock` | `vertex` | `azure` | `foundry` | `oauth` | `local` | `ollama` | |---|---|---|---|---|---|---|---|---| | **claude** | ✅ Anthropic | ✅ Built-in | ✅ Built-in | ❌ | ✅ Built-in | ✅ Browser | ❌ | ⚠️ via `ANTHROPIC_BASE_URL` | | **codex** | ✅ OpenAI | ❌ | ❌ | ❌ | ❌ | ✅ `codex login` | ❌ | ✅ `--oss` / config.toml | | **gemini** | ✅ Google | ❌ | ✅ ADC | ❌ | ❌ | ✅ Browser | ❌ | ❌ | | **opencode** | ✅ Multi | ✅ SDK | ✅ SDK | ✅ SDK | ❌ | ❌ | ❌ | ⚠️ OpenAI-compat | | **copilot** | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ GitHub | ❌ | ❌ | | **cursor** | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | Legend: ✅ = native support, ⚠️ = works with env var hack, ❌ = not supported (proxy required) ### 3.3 Transport Protocol Registry | Transport ID | Description | Endpoint Format | Used By | |---|---|---|---| | `anthropic` | Anthropic Messages API | `POST /v1/messages` (SSE streaming) | Claude Code | | `openai-chat` | OpenAI Chat Completions | `POST /v1/chat/completions` | Codex (wire_api=chat), OpenCode | | `openai-responses` | OpenAI Responses API | `POST /v1/responses` | Codex (wire_api=responses) | | `google` | Google GenerateContent | `POST /v1beta/models/:model:generateContent` | Gemini CLI | --- ## 4. Launch Resolution Algorithm When `adapters launch <harness> [provider] [flags]` is invoked, the following resolution steps execute in order: ### Step 1: Validate Harness ``` 1. Look up <harness> in AdapterRegistry 2. If not found → error: "Unknown harness '<harness>'. Available: <list>" 3. Verify adapter is SubprocessAdapter type 4. If not subprocess → error: "Harness '<harness>' is a <type> adapter and cannot be launched via CLI" ``` ### Step 2: Resolve Provider ``` 1. If <provider> is given, resolve from provider taxonomy (§3.1) 2. If --profile is given, load profile from ~/.adapters/providers.json, merge with flags 3. If neither, use harness default: - claude → api (Anthropic) - codex → api (OpenAI) - gemini → api (Google) - opencode → infer from env vars 4. Validate required auth for provider (--api-key, env vars, or --auth-command) ``` ### Step 3: Resolve Transport ``` 1. If --transport is explicit, use it 2. Otherwise, infer from harness native protocol: - claude → anthropic - codex → openai-responses (or openai-chat if configured) - gemini → google - opencode → openai-chat 3. Record resolved transport as T_harness 4. Record provider's native transport as T_provider ``` ### Step 4: Determine Proxy Necessity ``` 1. Check native support matrix (§3.2) for (harness, provider) pair 2. If natively supported: a. If --with-proxy → proxy = FORCE (user wants it anyway) b. If --no-proxy → proxy = SKIP c. Otherwise → proxy = SKIP (redundant, skip for performance) d. Log: "Proxy not needed: <harness> speaks <provider> natively" 3. If NOT natively supported: a. If --no-proxy → error: "<harness> does not support <provider> natively. Use --with-proxy-if-needed or configure the harness manually." b. If --with-proxy-if-needed or --with-proxy → proxy = REQUIRED c. Otherwise → error: "<harness> requires a proxy for <provider>. Use --with-proxy-if-needed to auto-launch the proxy." ``` ### Step 5: Launch Proxy (if needed) ``` 1. Resolve proxy port (--proxy-port or ephemeral) 2. Build proxy configuration: - target_provider: provider config (model, api_key, region, project, etc.) - exposed_transport: T_harness (what the harness expects to speak) - port: resolved port 3. Spawn adapters-proxy process (see docs/provider-adapter.md §5) 4. Wait for proxy health check (GET /health → 200) 5. Record proxy URL as PROXY_BASE_URL = http://127.0.0.1:<port> 6. If proxy fails to start within 15s → error + cleanup ``` ### Step 6: Build Harness Environment Based on harness identity and whether proxy is active, construct the environment variables and CLI args. #### Claude Code ```bash # Direct (no proxy, api provider) ANTHROPIC_API_KEY=<key> ANTHROPIC_MODEL=<model> # if --model given claude [session-flags] [harness-args] # Via proxy ANTHROPIC_BASE_URL=http://127.0.0.1:<port> ANTHROPIC_API_KEY="adapters-proxy" ANTHROPIC_AUTH_TOKEN="adapters-proxy" claude [session-flags] [harness-args] # Bedrock (native) CLAUDE_CODE_USE_BEDROCK=1 AWS_REGION=<region> AWS_ACCESS_KEY_ID=<key> # or use profile claude [session-flags] [harness-args] # Vertex (native) CLAUDE_CODE_USE_VERTEX=1 GOOGLE_CLOUD_PROJECT=<project> GOOGLE_CLOUD_LOCATION=<region> claude [session-flags] [harness-args] ``` #### Codex ```bash # Direct (no proxy, api provider) OPENAI_API_KEY=<key> codex [exec] [session-flags] [harness-args] # Via proxy (proxy exposes OpenAI Responses API) OPENAI_BASE_URL=http://127.0.0.1:<port> OPENAI_API_KEY="adapters-proxy" codex [exec] [session-flags] [harness-args] # Ollama (native) codex --oss [session-flags] [harness-args] ``` #### Gemini CLI ```bash # Direct (no proxy, api provider) GEMINI_API_KEY=<key> gemini [--prompt <prompt>] [harness-args] # Vertex (native) GOOGLE_GENAI_USE_VERTEXAI=true GOOGLE_CLOUD_PROJECT=<project> GOOGLE_CLOUD_LOCATION=<region> gemini [--prompt <prompt>] [harness-args] # Via proxy (proxy exposes Google GenerateContent) CODE_ASSIST_ENDPOINT=http://127.0.0.1:<port> GEMINI_API_KEY="adapters-proxy" gemini [--prompt <prompt>] [harness-args] ``` #### OpenCode ```bash # Direct (any supported provider) OPENCODE_CONFIG_CONTENT='{"$schema":"https://opencode.ai/config.json","provider":{"resolved":{"npm":"@ai-sdk/anthropic","options":{}}},"model":{"default":"resolved/<model>"}}' opencode [session-flags] [harness-args] # Via proxy (proxy exposes OpenAI Chat Completions) OPENCODE_CONFIG_CONTENT='{"$schema":"https://opencode.ai/config.json","provider":{"adapters-proxy":{"npm":"@ai-sdk/openai-compatible","options":{"baseURL":"http://127.0.0.1:<port>/v1"}}},"model":{"default":"adapters-proxy/<model>"}}' opencode [session-flags] [harness-args] ``` ### Step 7: Spawn Harness Process ``` 1. Resolve full command + args for the harness 2. If --prompt is set: a. Inject prompt via harness-specific mechanism: - claude: --print <prompt> (or stdin stream-json message) - codex: codex exec <prompt> - gemini: --prompt <prompt> - opencode: (stdin after launch) b. Set nonInteractive = true 3. If --resume is set: a. Pass harness-specific resume flag: - claude: --resume <id> - codex: codex resume <id> - gemini: (not supported → error) - opencode: --session <id> 4. Spawn child process with: - stdin: process.stdin (passthrough) - stdout: process.stdout (passthrough) - stderr: process.stderr (passthrough) - env: merged (process.env + harness env + proxy env) - cwd: process.cwd() 5. Wire SIGINT, SIGTERM, SIGHUP to child process 6. Register cleanup handler for proxy (if running) ``` ### Step 8: Cleanup on Exit ``` 1. On child process exit: a. If proxy is running: - Send SIGTERM to proxy - Wait up to 5s for graceful shutdown - SIGKILL if needed b. Forward child exit code as adapters exit code 2. On SIGINT/SIGTERM to adapters: a. Forward signal to child b. Wait for child exit c. Clean up proxy d. Exit with child's code (or 130 for SIGINT) ``` --- ## 5. Interactive vs Non-Interactive Mode ### 5.1 Interactive Mode (default) When no `--prompt` flag is given: - stdin, stdout, and stderr are passed through directly to the harness - adapters does **not** parse or transform the output - The user interacts with the harness TUI natively - adapters only manages the proxy lifecycle and process signals - PTY allocation follows the harness's native preference (most harnesses need a PTY for their TUI) ```bash # Interactive Claude Code session via Bedrock adapters launch claude bedrock --region us-east-1 --with-proxy-if-needed # Interactive Codex session with a custom provider adapters launch codex custom --api-base https://my-llm.corp.net --api-key $KEY --transport openai-responses ``` ### 5.2 Non-Interactive Mode When `--prompt` is given: - The prompt is delivered to the harness via its native mechanism - stdout and stderr are still passed through (no AgentEvent normalization) - The process exits when the harness completes its response - Suitable for scripting and CI/CD pipelines ```bash # One-shot Claude via Vertex adapters launch claude vertex --project my-project --region us-central1 \ -p "Explain the authentication flow in this codebase" \ --max-turns 3 # One-shot Codex via Bedrock (needs proxy: Codex speaks OpenAI, Bedrock speaks Anthropic) adapters launch codex bedrock --region us-west-2 --model anthropic.claude-sonnet-4 \ --with-proxy-if-needed \ -p "Fix the failing test in src/auth.ts" ``` --- ## 6. Dry Run Output `--dry-run` prints the resolved launch plan as JSON and exits: ```json { "harness": "claude", "provider": "bedrock", "transport": "anthropic", "model": "anthropic.claude-sonnet-4-20250514-v1:0", "proxyNeeded": false, "proxyReason": "claude supports bedrock natively via CLAUDE_CODE_USE_BEDROCK", "command": "claude", "args": ["--print", "--output-format", "stream-json", "--model", "claude-sonnet-4-20250514"], "env": { "CLAUDE_CODE_USE_BEDROCK": "1", "AWS_REGION": "us-east-1" }, "harnessArgs": [] } ``` When proxy is needed: ```json { "harness": "codex", "provider": "bedrock", "transport": "openai-responses", "model": "anthropic.claude-sonnet-4-20250514-v1:0", "proxyNeeded": true, "proxyReason": "codex does not support bedrock natively; proxy bridges bedrock → openai-responses", "proxy": { "targetProvider": "bedrock", "targetModel": "anthropic.claude-sonnet-4-20250514-v1:0", "exposedTransport": "openai-responses", "port": 0, "command": "adapters-proxy", "env": { "ADAPTERS_PROXY_TARGET_PROVIDER": "bedrock", "ADAPTERS_PROXY_TARGET_MODEL": "anthropic.claude-sonnet-4-20250514-v1:0", "ADAPTERS_PROXY_EXPOSED_TRANSPORT": "openai-responses", "ADAPTERS_PROXY_PORT": "0", "AWS_REGION": "us-east-1" } }, "command": "codex", "args": ["exec"], "env": { "OPENAI_BASE_URL": "http://127.0.0.1:<resolved-port>", "OPENAI_API_KEY": "adapters-proxy" }, "harnessArgs": [] } ``` --- ## 7. Error Catalog | Code | Condition | Message Template | |---|---|---| | `HARNESS_NOT_FOUND` | Unknown harness name | `Unknown harness '{name}'. Available: {list}` | | `HARNESS_NOT_INSTALLED` | Harness binary not in PATH | `{harness} is not installed. Install with: {installCommand}` | | `PROVIDER_UNSUPPORTED` | Harness+provider combo not feasible | `{harness} cannot use provider '{provider}' (no native support and proxy not enabled)` | | `PROXY_REQUIRED` | Harness needs proxy but `--no-proxy` set | `{harness} requires a proxy for {provider}. Remove --no-proxy or use --with-proxy-if-needed` | | `PROXY_LAUNCH_FAILED` | adapters-proxy failed to start | `Failed to launch proxy: {error}. Is adapters-proxy installed? (pip install adapters-proxy)` | | `PROXY_HEALTH_TIMEOUT` | Proxy didn't become healthy | `Proxy health check timed out after 15s on port {port}` | | `AUTH_MISSING` | Required auth not provided | `Provider '{provider}' requires authentication. Set {envVar} or use --api-key` | | `TRANSPORT_MISMATCH` | Explicit --transport not feasible | `Transport '{transport}' is not available for {harness}+{provider}` | | `RESUME_NOT_SUPPORTED` | Harness doesn't support resume | `{harness} does not support session resumption` | | `MODEL_NOT_SPECIFIED` | Provider requires explicit model | `Provider '{provider}' requires --model to be specified` | --- ## 8. Relationship to `adapters run` `adapters launch` and `adapters run` are complementary: | | `adapters launch` | `adapters run` | |---|---|---| | **Primary user** | Humans, scripts wanting raw harness UX | Applications, orchestrators, multi-agent systems | | **Output** | Raw harness output (bypass) | Normalized `AgentEvent` stream | | **Provider flexibility** | Full (any provider via proxy) | Limited to harness native | | **Session management** | Delegates to harness | Managed by adapters SessionManager | | **Cost tracking** | Delegated to harness | Tracked by adapters | | **Hooks** | Not fired (bypass) | Full hook lifecycle | | **Multi-agent** | Single harness only | Dispatch across multiple agents | A future enhancement could add `--observe` to `adapters launch` that tees the harness output to both stdout (raw) and an internal parser (for cost tracking and session recording), without transforming the user-facing output. --- ## 9. Implementation Notes ### 9.1 Package Location The `launch` command is implemented in `packages/cli/src/commands/launch.ts` as part of the existing `@a5c-ai/adapters-cli` package. It reuses: - `AdapterRegistry` for harness lookup and capability checking - `BaseAgentAdapter.detectInstallation()` for binary discovery - `BaseAgentAdapter.detectAuth()` for auth validation - Provider resolution from `@a5c-ai/comm-adapter` (new module: `provider-config.ts`) ### 9.2 Proxy Process Management The proxy is spawned as a detached child process with stdio set to `pipe` (not inherited). Its stdout/stderr are captured and logged at the `--proxy-log-level`. The proxy PID is tracked via `ProcessTracker` for cleanup guarantees. ### 9.3 Signal Handling On Windows, `SIGINT` is not reliable for child processes. The launcher uses `process.kill(child.pid, 'SIGTERM')` and falls back to `taskkill /PID <pid> /F` after timeout. ### 9.4 PTY Allocation Interactive mode allocates a PTY for harnesses that require it (most TUI-based harnesses). The `node-pty` library is used, matching the existing `SpawnRunner` implementation. Non-interactive mode uses plain pipes.
documents
[]

Outgoing edges

None.

Incoming edges

contains_page1
  • page:docs-adapters-archive-design·Pageadapters archive: design

Related pages

No related wiki pages for this record.

Shortcuts

Open in graph
Browse node kind