Summary
Today the ACP runtime registry is hard-coded to four entries — codex-acp, claude-acp, gemini-acp, kilo-acp — in apps/desktop/src/features/ai/utils/runtimeMetadata.ts (RUNTIME_METADATA). The customBinaryPath setting in AIProvidersSettings.tsx only overrides the binary path for those four IDs; it doesn't allow registering a new runtime.
This means users with their own ACP-speaking agents (Hermes, internal tooling, fine-tuned wrappers, SSH-bridged remote agents, etc.) can't connect them to NeverWrite — even though Zed and other ACP clients let you do this with a few lines of config.
Use cases
- Custom memory/indexing wrappers — agents that wrap an LLM with their own persistent memory store. Routing prompts through them via ACP captures the conversation + file context into that memory; routing through the built-in Claude/Codex runtimes does not.
- Remote agents over SSH — running an ACP server on a workstation/cluster and tunneling stdio over SSH from the laptop running NeverWrite.
- Fine-tuned or self-hosted models — anything that speaks ACP/JSON-RPC over stdio.
- OSS ACP runtimes that ship later — avoids needing a NeverWrite release every time a new ACP agent appears.
Proposed shape
A user-defined runtime entry, configured in Settings → AI Providers, with at minimum:
| Field |
Notes |
id |
user-chosen, must be unique |
name |
display name |
command |
program to launch (absolute path or PATH-resolved) |
args |
array of arguments |
env |
optional environment variables |
cwd |
optional working directory |
capabilities |
optional override; default to a conservative set |
Persisted in the same settings store the existing runtime overrides use. Spawned the same way the built-in ACP sidecars are spawned (stdio JSON-RPC).
Why this is low-risk
- ACP is already the transport for the four built-ins, so the spawn/lifecycle/IPC code paths exist.
- The change is essentially: turn
RUNTIME_METADATA from a const array into [...builtIns, ...userRuntimes], and add a small CRUD UI in AIProvidersSettings.tsx.
- Capability discovery already happens at runtime via the ACP handshake, so the hard-coded
capabilities arrays in runtimeMetadata.ts are nice-to-have hints rather than load-bearing.
Workaround until then
Users can sacrifice one of the built-in slots (e.g. Kilo) by pointing its customBinaryPath at a wrapper script that exec's their own ACP server. This works but mislabels the runtime in the UI and inherits Kilo's hard-coded capability list.
Happy to contribute
If a maintainer signals this is in scope, I'm willing to take a stab at a PR. Wanted to file the issue first so the design isn't wasted effort.
Summary
Today the ACP runtime registry is hard-coded to four entries —
codex-acp,claude-acp,gemini-acp,kilo-acp— inapps/desktop/src/features/ai/utils/runtimeMetadata.ts(RUNTIME_METADATA). ThecustomBinaryPathsetting inAIProvidersSettings.tsxonly overrides the binary path for those four IDs; it doesn't allow registering a new runtime.This means users with their own ACP-speaking agents (Hermes, internal tooling, fine-tuned wrappers, SSH-bridged remote agents, etc.) can't connect them to NeverWrite — even though Zed and other ACP clients let you do this with a few lines of config.
Use cases
Proposed shape
A user-defined runtime entry, configured in Settings → AI Providers, with at minimum:
idnamecommandargsenvcwdcapabilitiesPersisted in the same settings store the existing runtime overrides use. Spawned the same way the built-in ACP sidecars are spawned (stdio JSON-RPC).
Why this is low-risk
RUNTIME_METADATAfrom a const array into[...builtIns, ...userRuntimes], and add a small CRUD UI inAIProvidersSettings.tsx.capabilitiesarrays inruntimeMetadata.tsare nice-to-have hints rather than load-bearing.Workaround until then
Users can sacrifice one of the built-in slots (e.g. Kilo) by pointing its
customBinaryPathat a wrapper script that exec's their own ACP server. This works but mislabels the runtime in the UI and inherits Kilo's hard-coded capability list.Happy to contribute
If a maintainer signals this is in scope, I'm willing to take a stab at a PR. Wanted to file the issue first so the design isn't wasted effort.