OpenCode, Cursor, and Kilo Code are presented as "Built-in" in the agents marketplace, but Atlas does not bundle their CLIs and offers no way to install them. When their binary is absent, the spawn fails, the error is swallowed, and the only user-visible symptom is a chat with no model picker at all — which reads as "I can't connect a model to this agent."
Reproduce
On a machine without the opencode, cursor-agent, or kilo CLIs on PATH:
- Open Settings → Agents. All three show a "✓ Built-in" chip with the tooltip "This agent ships with Atlas" and no Install button.
- Switch a chat tab to any of the three.
- The tab binds, the composer renders — but the model picker never appears, and nothing indicates why.
Claude Code and Codex are unaffected: they launch via npx -y @agentclientprotocol/..., which self-installs the adapter.
Root cause
1. Bare-binary specs with no install path
The three specs shell out to binaries the user is expected to already have (crates/atlas-acp/src/registry.rs:121-170):
| Agent |
Command |
Bootstraps itself? |
| Claude Code |
npx -y @agentclientprotocol/claude-agent-acp |
yes |
| Codex |
npx -y @agentclientprotocol/codex-acp |
yes |
| OpenCode |
opencode acp |
no |
| Cursor |
cursor-agent acp |
no |
| Kilo Code |
kilo acp |
no |
2. "Built-in" is conflated with "installed"
BUILTIN_REGISTRY_IDS (crates/atlas-registry/src/store.rs:24) includes opencode, cursor, and kilo. Two consequences:
agents-marketplace.tsx:356 renders the "✓ Built-in" chip and suppresses the Install button.
RegistryStore::install() actively refuses them — "{id} is built into Atlas and cannot be installed from the registry" (store.rs:155).
So the UI asserts the agent is ready, provides no way to make it ready, and it isn't. The flag currently means "a first-party spec exists," but it is rendered to the user as "the runtime is present."
3. The failure surfaces as an empty model picker
Model lists for ACP agents only arrive in the session/new response — spawning is the only way to learn them (src/features/chat/lib/warm-acp-models.ts:5-8). So:
spawn ENOENT → no session → no `models` blob → acpAvailableModels empty
→ acp-models-cache empty → picker returns null
// src/features/chat/components/message-input.tsx:451
if (models.length === 0) return null;
The dropdown is not disabled or annotated — it is simply not rendered.
4. The correct diagnostic is written, then discarded
explain_spawn_failure (crates/atlas-acp/src/spawn.rs:210-260) already produces exactly the right message per agent:
the OpenCode CLI was not found. Install it from https://opencode.ai (then optionally run opencode auth login) and relaunch Atlas.
...plus equivalents for cursor-agent login and npm install -g @kilocode/cli. Every UI caller swallows it:
src/features/chat/components/chat-panel.tsx:408 — console.warn("Agent session creation failed:", err)
src/features/chat/components/chat-panel.tsx:566 — .catch(() => {}) on prewarm
src/features/chat/components/chat-panel.tsx:124 — console.warn("agent restart failed:", err)
src/features/chat/lib/warm-acp-models.ts:74 — bare catch {}
The hints land in the devtools console and nowhere else.
Suggested direction
Two independently useful fixes:
- Make install state honest. Detect whether the runtime actually resolves (
resolve_program_abs already does this) and surface it in RegistryEntryView as a separate field from builtin — e.g. runtime_available. The marketplace card can then show "Not installed" with the install command / help URL instead of "✓ Built-in". Optionally allow the marketplace to run the install for the three (npm i -g @kilocode/cli, the OpenCode/Cursor install scripts), the way node_setup already bootstraps Node.
- Stop swallowing spawn errors. Propagate the
explain_spawn_failure string into the chat surface — a banner or a disabled model picker with the reason — rather than console.warn. The message is already good; it just needs a UI destination.
Environment
- Atlas
0.3.0-x @ 1594e3a
- macOS (Darwin 24.6.0), Intel x86_64
- Node v24.16.0 via nvm,
npx on PATH
opencode, cursor-agent, kilo: not installed (no binary on PATH, no ~/.opencode, no ~/.cursor, no ~/.local/share/kilo/kilo.db)
Related
Distinct from #101 ("Opencode cannot change models"), which was the legacy models-blob deserialization drop fixed by model_sniff.rs. That path is fine — this issue is that the agent never spawns to produce a blob in the first place.
OpenCode, Cursor, and Kilo Code are presented as "Built-in" in the agents marketplace, but Atlas does not bundle their CLIs and offers no way to install them. When their binary is absent, the spawn fails, the error is swallowed, and the only user-visible symptom is a chat with no model picker at all — which reads as "I can't connect a model to this agent."
Reproduce
On a machine without the
opencode,cursor-agent, orkiloCLIs on PATH:Claude Code and Codex are unaffected: they launch via
npx -y @agentclientprotocol/..., which self-installs the adapter.Root cause
1. Bare-binary specs with no install path
The three specs shell out to binaries the user is expected to already have (
crates/atlas-acp/src/registry.rs:121-170):npx -y @agentclientprotocol/claude-agent-acpnpx -y @agentclientprotocol/codex-acpopencode acpcursor-agent acpkilo acp2. "Built-in" is conflated with "installed"
BUILTIN_REGISTRY_IDS(crates/atlas-registry/src/store.rs:24) includesopencode,cursor, andkilo. Two consequences:agents-marketplace.tsx:356renders the "✓ Built-in" chip and suppresses the Install button.RegistryStore::install()actively refuses them — "{id} is built into Atlas and cannot be installed from the registry" (store.rs:155).So the UI asserts the agent is ready, provides no way to make it ready, and it isn't. The flag currently means "a first-party spec exists," but it is rendered to the user as "the runtime is present."
3. The failure surfaces as an empty model picker
Model lists for ACP agents only arrive in the
session/newresponse — spawning is the only way to learn them (src/features/chat/lib/warm-acp-models.ts:5-8). So:The dropdown is not disabled or annotated — it is simply not rendered.
4. The correct diagnostic is written, then discarded
explain_spawn_failure(crates/atlas-acp/src/spawn.rs:210-260) already produces exactly the right message per agent:...plus equivalents for
cursor-agent loginandnpm install -g @kilocode/cli. Every UI caller swallows it:src/features/chat/components/chat-panel.tsx:408—console.warn("Agent session creation failed:", err)src/features/chat/components/chat-panel.tsx:566—.catch(() => {})on prewarmsrc/features/chat/components/chat-panel.tsx:124—console.warn("agent restart failed:", err)src/features/chat/lib/warm-acp-models.ts:74— barecatch {}The hints land in the devtools console and nowhere else.
Suggested direction
Two independently useful fixes:
resolve_program_absalready does this) and surface it inRegistryEntryViewas a separate field frombuiltin— e.g.runtime_available. The marketplace card can then show "Not installed" with the install command / help URL instead of "✓ Built-in". Optionally allow the marketplace to run the install for the three (npm i -g @kilocode/cli, the OpenCode/Cursor install scripts), the waynode_setupalready bootstraps Node.explain_spawn_failurestring into the chat surface — a banner or a disabled model picker with the reason — rather thanconsole.warn. The message is already good; it just needs a UI destination.Environment
0.3.0-x@1594e3anpxon PATHopencode,cursor-agent,kilo: not installed (no binary on PATH, no~/.opencode, no~/.cursor, no~/.local/share/kilo/kilo.db)Related
Distinct from #101 ("Opencode cannot change models"), which was the legacy
models-blob deserialization drop fixed bymodel_sniff.rs. That path is fine — this issue is that the agent never spawns to produce a blob in the first place.