feat(acp): author any ACP provider as config data and serve it generically - #7984
feat(acp): author any ACP provider as config data and serve it generically#7984billygerhard wants to merge 1 commit into
Conversation
913ecf6 to
cf484d5
Compare
cf484d5 to
40f7780
Compare
be309c0 to
ce50f70
Compare
First Principles Review (Fable 5, fork) —
|
GPT 5.6 Review (fork) —
|
Design Review (Fable 5, fork) —
|
Opus 4.8 Review (fork) —
|
ce50f70 to
e0e11a4
Compare
…cally Operator-authored harnesses: agent.harnesses config descriptors (executable, argv template, capabilities, model_source, mcp_delivery) served through a generic ACP adapter with protocol profiles, harness-bound sessions across chat/spawn/cron, per-harness MCP delivery (file-fed/wire-fed), selection surfaces with per-harness unavailability reasons, and a composer/session harness chip.
e0e11a4 to
35aeea6
Compare
|
Closing in favor of a 3-PR stack: this PR's 3.3 MB diff exceeds the fork AI-review lanes' 1 MB fail-closed cap, so PR Readiness can never pass here regardless of CI state (all deterministic checks were green as of the last push). The same work, unchanged in substance, now ships as three sequential PRs each under the cap — part 1 (core descriptors/registry/selection) is open at #8255; parts 2 (consumer wiring) and 3 (UI + docs) follow as each predecessor merges. Thanks to the maintainers for the earlier CI iterations here — those fixes all carry over into the stack. |
Problem / Motivation
KiroCrew can drive multiple AI providers today, but every provider is a hand-written code path: Kiro CLI, KAS, and Claude Code each have bespoke spawn logic, capability handling, and UI wiring, and Codex is being hand-built the same way. An operator who wants to run any other ACP-speaking provider — pi, goose, opencode, or an in-house ACP adapter — cannot: there is no way to describe a provider to KiroCrew without writing and shipping a new backend.
Why it matters
Every new provider currently costs a full per-backend PR (the open Codex backend PR is 61 files). The ACP conversation is identical across providers — only the launch command line differs — so that cost is accidental, not essential. Config-authored providers make "run provider X" an operator decision instead of a maintainer roadmap item, which is exactly the shape needed for the stated pi/goose/opencode direction.
What changed (motivation → approach → change)
Goal: author ANY ACP provider as configuration data and serve it through one generic path, without weakening the per-harness security posture.
Approach: make the harness descriptor the single source of truth. A descriptor carries the launch recipe (executable, argv template with
{executable}/{agent}/{model}/{workdir}placeholders only), an opt-inCapabilitySet(everything defaults off, fail-closed), amodel_source(ACP-advertised or static), and anmcp_deliverymode (wire_fed/file_fed). Bundled providers (Kiro CLI, KAS, Claude Code, the dormant Codex seam) are expressed as bundled descriptors; operators add more underagent.harnessesinconfig.json— a map keyed by harness id, validated per entry with a diagnosable reason (one bad entry never costs the others), no restart required, and no per-provider code.What was built on that:
acp/harness_descriptor.py,acp/harness_registry.py): parsing/validation with per-field reasons; alias resolution for the legacyagent.acp_backendkey; availability probing. Four capabilities (internal_sandbox,acp_runtime_pool,session_sharing,kiro_identity_store) are code-only — honoured by machinery written for specific bundled harnesses — and are refused from configuration with a written reason (internal_sandboxwould otherwise let a config entry waive KiroCrew's own OS sandbox).acp/harness_adapters.py, protocol profiles): aGenericAdapterspeaks the standard ACP wire to any descriptor-launched binary;ProtocolProfilecaptures per-harness wire dialects (kiro-cli's date-string protocolVersion vs the public integer,session/set_config_optionvs/effort), replacing scatteredis_claude-style branches.acp/harness_selection.py,session_allocation.py,subagent_manager/admission.py): aHarnessBindingresolves once per session and threads through chat, spawn (per-subagent), and cron paths; the warm pool bypasses on harness mismatch; MCP delivery follows the bound descriptor's declared mode, gated on the transports the harness advertised at initialize.codex-acpadapter (thecodexCLI alone does not serve ACP, per the seam's own spawn path).KIROCREW_PORTbeside the existingKIROCREW_HOME), fixing spawn callbacks on gateways bound to non-default ports whose hosts fail the run-marker ownership proof closed.Deletions:
website/src/pages/developer/AgentBackendTab.tsxand its test are replaced by the SettingsHarnessPanel(server-derived rows, per-row reasons).config-baseline.jsonis regenerated for the newagent.harnesses/agent.default_harnessfields.website/package-lock.jsonchurn is transitive-only (nopackage.jsonchange).Tests
false), operator-grantable flags still parse, argv placeholder allowlist.codex-acpadapter shape, capability grants pinned against the leafACP_BACKENDS_*sets and shipped literals (three-way agreement test).ensure_ready()/_spawn— full chat turn, permission round-trips, model advertisement, sandbox wrap decision, spawn/cron binding resolution, and the bound descriptor winning MCP delivery over the backend roster (regression for a review finding where operator sessions silently got zero MCP servers).scripts/check_harness_parity.py+ tests): added lines may not test harness identity by negation or bare literal; golden kiro argv byte-identity pinned against the pre-migration formula.Manual verification
Exercised hands-on in a pod: all three bundled providers serve real sessions; a config-authored stub provider (
agent.harnessesentry) appears in the picker, serves an echo session, and advertises its own models; an invalid descriptor renders in the picker with its per-field reason; the composer chip shows the session's harness. The doc example was validated end-to-end (a wrongmcp_deliveryvalue in the shipped example was caught this way and is now pinned by a test that validates every doc example against the real parser).Screenshots / video
Settings — registered harnesses panel
Related Issues
no linked issue: this implements the generic provider-authoring path discussed alongside the per-provider backends (e.g. the open Codex backend PR #5349 becomes an optional refinement rather than a prerequisite for running Codex).
Pattern harvest
Rule candidate: review-prompt
Pattern: "a capability flag parseable from operator config must be provably honoured by code that works for arbitrary processes — a flag honoured only by machinery built for one bundled binary is code-only and the parser must refuse it."
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)