Summary
A harness provider needs an external coding-agent to be present at runtime (a CLI binary and/or a Python/JS SDK wrapper, plus auth). Today there is no first-class way to (a) install the providers you intend to use, or (b) verify they are actually installed and usable before you run a real workflow. Failures surface late, mid-run, as a subprocess error inside app.harness(...). This is especially painful in containers/CI where you want the image build to fail fast if a required harness is missing.
We want a clean, bloat-free DX for declaring and verifying harness provider availability, consistent across the Python, TypeScript, and Go SDKs.
Why "just add pip/npm extras" is not enough
The real dependency is usually a binary, not a pip/npm library:
| Provider |
Python install |
TS/JS install |
Underlying binary |
| claude-code |
claude-agent-sdk (PyPI) |
@anthropic-ai/claude-agent-sdk (npm) |
bundles the Claude Code CLI |
| codex |
openai-codex (PyPI) or raw CLI |
@openai/codex-sdk (npm) |
codex (Rust binary, npm/brew) |
| gemini |
none (CLI only) |
none official (CLI only) |
gemini (npm @google/gemini-cli) |
| opencode |
opencode-ai (PyPI, alpha) or raw CLI |
@opencode-ai/sdk (npm) |
opencode (curl/npm) |
So pip/npm extras can pin the Python/JS glue where an SDK exists, but they cannot install the actual agent binary (gemini, opencode, codex, the bundled claude node binary). An extra that installs nothing real (e.g. gemini) would be misleading. We need extras and a runtime preflight that checks ground truth (binary on PATH + version + auth).
Context: gemini-cli is being retired for consumer tiers on 2026-06-18 (superseded by Antigravity). Factor this into how aggressively we invest in a gemini extra.
Proposed DX (three layers)
1. Optional extras for the pip/npm-installable wrappers
- Python:
agentfield[harness-claude], [harness-codex], [harness-opencode], and [harness-all]. (Today only harness / harness-claude exist and both just pull claude-agent-sdk.)
- TS: optional
peerDependencies for @openai/codex-sdk and @opencode-ai/sdk (we already mark @anthropic-ai/claude-agent-sdk optional).
- These pin versions and make
import work; they do not claim to install binaries.
2. A harness doctor preflight (the real fix for "is it installed?")
A single command/function that, per provider, checks: binary on PATH (shutil.which), version (and min-version compatibility), and auth (required env vars present). Returns a structured report and a non-zero exit when a requested provider is unusable.
- CLI:
af harness doctor [--provider opencode,codex] [--json]
- Library:
await app.harness_doctor(providers=[...]) -> list[ProviderHealth]
- This is the thing you run in a Dockerfile / CI step / container entrypoint to guarantee the harness is present before any real (paid) run. Same pattern as
flutter doctor, gh auth status.
3. Standardized, actionable missing-dependency errors (fail fast, not mid-run)
- Every provider does a
shutil.which-style preflight before spawning the subprocess, and raises a typed HarnessProviderUnavailable naming the exact install command and the missing auth env var.
- The CLI providers already do part of this on
FileNotFoundError; make it proactive, typed, and uniform across all four providers and all three SDKs.
Acceptance criteria
Open question
Should doctor optionally attempt a zero-cost liveness probe (e.g. --version / a no-op invocation) per provider, or only static PATH/env checks? Static is faster and offline-safe; a probe catches broken installs. Lean static by default, probe behind a --probe flag.
Spun out of the harness UX/DX review done alongside #684 (project_dir/cwd output placement fix).
Summary
A harness provider needs an external coding-agent to be present at runtime (a CLI binary and/or a Python/JS SDK wrapper, plus auth). Today there is no first-class way to (a) install the providers you intend to use, or (b) verify they are actually installed and usable before you run a real workflow. Failures surface late, mid-run, as a subprocess error inside
app.harness(...). This is especially painful in containers/CI where you want the image build to fail fast if a required harness is missing.We want a clean, bloat-free DX for declaring and verifying harness provider availability, consistent across the Python, TypeScript, and Go SDKs.
Why "just add pip/npm extras" is not enough
The real dependency is usually a binary, not a pip/npm library:
claude-agent-sdk(PyPI)@anthropic-ai/claude-agent-sdk(npm)openai-codex(PyPI) or raw CLI@openai/codex-sdk(npm)codex(Rust binary, npm/brew)gemini(npm@google/gemini-cli)opencode-ai(PyPI, alpha) or raw CLI@opencode-ai/sdk(npm)opencode(curl/npm)So pip/npm extras can pin the Python/JS glue where an SDK exists, but they cannot install the actual agent binary (gemini, opencode, codex, the bundled claude node binary). An extra that installs nothing real (e.g. gemini) would be misleading. We need extras and a runtime preflight that checks ground truth (binary on PATH + version + auth).
Proposed DX (three layers)
1. Optional extras for the pip/npm-installable wrappers
agentfield[harness-claude],[harness-codex],[harness-opencode], and[harness-all]. (Today onlyharness/harness-claudeexist and both just pullclaude-agent-sdk.)peerDependenciesfor@openai/codex-sdkand@opencode-ai/sdk(we already mark@anthropic-ai/claude-agent-sdkoptional).importwork; they do not claim to install binaries.2. A
harness doctorpreflight (the real fix for "is it installed?")A single command/function that, per provider, checks: binary on PATH (
shutil.which), version (and min-version compatibility), and auth (required env vars present). Returns a structured report and a non-zero exit when a requested provider is unusable.af harness doctor [--provider opencode,codex] [--json]await app.harness_doctor(providers=[...]) -> list[ProviderHealth]flutter doctor,gh auth status.3. Standardized, actionable missing-dependency errors (fail fast, not mid-run)
shutil.which-style preflight before spawning the subprocess, and raises a typedHarnessProviderUnavailablenaming the exact install command and the missing auth env var.FileNotFoundError; make it proactive, typed, and uniform across all four providers and all three SDKs.Acceptance criteria
harness-claude,harness-codex,harness-opencode,harness-all.af harness doctorCLI +app.harness_doctor()library API returning structured per-provider health (installed / version / auth / usable), non-zero exit on any requested provider being unusable.HarnessProviderUnavailableraised before subprocess spawn, with exact install command + missing auth env var, uniform across providers.Open question
Should
doctoroptionally attempt a zero-cost liveness probe (e.g.--version/ a no-op invocation) per provider, or only static PATH/env checks? Static is faster and offline-safe; a probe catches broken installs. Lean static by default, probe behind a--probeflag.Spun out of the harness UX/DX review done alongside #684 (project_dir/cwd output placement fix).