Skip to content

Auto-acquire the built-in ACP agents, and let users turn them off - #161

Merged
pacifio merged 1 commit into
0.3.0-xfrom
acp-builtin-auto-acquire
Aug 16, 2026
Merged

Auto-acquire the built-in ACP agents, and let users turn them off#161
pacifio merged 1 commit into
0.3.0-xfrom
acp-builtin-auto-acquire

Conversation

@Ukaykhingmarma28

Copy link
Copy Markdown
Collaborator

Fixes #160.

Cursor, OpenCode and Kilo were shown as "Built-in" while Atlas bundled nothing and offered no way to install them. Their specs shell out to bare CLIs (cursor-agent acp, opencode acp, kilo acp); on a machine without those, the spawn failed, the error was swallowed, and the only visible symptom was a chat with no model picker. Claude and Codex were fine because npx -y self-installs their adapter.

This makes Atlas do for those three what npx already does for the other two — then lets you turn them off if you don't want them.

Acquisition — cache-first, the model Zed uses

RegistryStore::ensure_builtin downloads the official per-platform binary from the ACP registry manifest on first use and caches it, reusing the existing versioned-cache / sha256 / prune machinery rather than adding a parallel one. It hangs off the pre-flight agents_spawn already ran for registry externals.

Never fatal. No manifest yet, unsupported platform, offline, bad checksum — every failure falls back to the bare PATH command, which is exactly today's behaviour. sha256 is verified where the manifest publishes one (kilo, opencode); Cursor ships none upstream, so it installs unverified, as it does in Zed.

AUTO_MANAGED_BUILTIN_IDS marks the three, and known_specs lets an acquired binary replace the bare command in place — same id, same slot, same display name — so the plugin catalogue never sees two entries for one agent. Built-in specs are emitted after installed ones, so a manifest-current binary outranks a frozen install record; a machine that installed OpenCode from the marketplace before it shipped built-in has both, and that case has a test.

First-use progress

The composer's boot pill reads "Setting up Cursor… 42%" instead of stalling silently through a 77 MB download.

Progress is throttled to whole-percent changes. The registry's callback fires once per HTTP chunk — ~56k times for Cursor's archive — and one IPC event each would flood the bridge and jank the UI. acquire_pct_to_emit collapses that to 101 events, pinned by a test that replays the real byte/chunk counts.

These get their own atlas:agent-acquire:* events rather than reusing the marketplace's install events: only the install flow clears that progress map, so feeding it from here would leak entries, and the built-in cards short-circuit to the "Built-in" badge before the progress branch anyway.

Sign-in

These adapters advertise an auth method but ship no _meta.terminal-auth, so Atlas's existing terminal-auth runner had nothing to execute — and since the CLI now lives in Atlas's app-data dir rather than on PATH, "run cursor-agent login" was advice a user could not follow. enrich_auth_methods synthesises the missing spec from the managed binary for both the list and run commands, so what the UI offers is exactly what executes. An adapter-supplied spec always wins.

Worth knowing for future work: Cursor rejects session/new, not the prompt. An unauthenticated agent therefore dies at bind time and never reaches the turn-failure route that raises atlas:auth-required. Both paths now offer the same one-click "Sign in", and the bind path retries itself once credentials land. Bind failures were previously a bare console.warn, so they are now actually reported.

Turning them off

AppSettings::disabled_builtin_agents, with a switch on the three built-in marketplace cards. Off means hidden from the picker and never spawned — including both background pre-warms and a resume of an older session recorded against that agent.

The Rust guard is the authority and hard-filters against AUTO_MANAGED_BUILTIN_IDS, so a hand-edited state.json cannot switch off Claude, Codex or Cersei. Chat history is never hidden.

Verification

Verified against the real binaries, not just mocks:

  • Cursor cold-downloaded (77 MB, ~19 s), extracted, and answered an ACP initialize with protocol v1 and the cursor_login auth method — i.e. it now spawns on a machine with no Cursor CLI.
  • Each agent's login argv was read off its own --help (cursor login; opencode/kilo auth login), not assumed.
  • The -32000 Authentication required response was reproduced against the CLI and is pinned verbatim in a regression test.

Automated: 512 frontend tests, 230 Rust app tests, 14 atlas-acp, 12 atlas-registry; typecheck and lint clean.

Not covered

  • The full sign-in loop is unverified end to end — browser → authenticate() → rebind needs a real account.
  • OpenCode and Kilo will hang on the "Sign in" button. Their auth login is an interactive TUI (provider picker, then an API-key prompt) and the auth runner spawns with stdin closed. Cursor is unaffected (browser OAuth). Setting a key works today via the CLI in a terminal, or via the provider env vars the binary reads (ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, GEMINI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY). The clean follow-up is to inject Atlas's existing BYOK keys into those agents' env at spawn.
  • Separately noticed and left alone: adaptiveSuggestions exists in the frontend AppSettings but has no field in the Rust struct, so serde drops it on every save and it does not survive a restart.

🤖 Generated with Claude Code

Cursor, OpenCode and Kilo were presented as "Built-in" but Atlas bundled
nothing and offered no way to install them: their specs shell out to bare
CLIs (`cursor-agent acp`, `opencode acp`, `kilo acp`) that most machines
don't have. The spawn failed, the error was swallowed, and the only visible
symptom was a chat with no model picker. Claude and Codex were unaffected
because `npx -y` self-installs their adapter.

Atlas now does for these three what npx does for the other two.

Acquisition (cache-first, the model Zed uses)
  - `RegistryStore::ensure_builtin` downloads the official per-platform
    binary from the ACP registry manifest on first use and caches it,
    reusing the existing versioned-cache/sha256/prune machinery. Verified
    against sha256 where the manifest publishes one (kilo, opencode);
    Cursor ships none upstream, so it installs unverified, as in Zed.
  - Hooked into the pre-flight `agents_spawn` already ran for registry
    externals. Never fatal: any failure (no manifest, unsupported platform,
    offline) falls back to the bare PATH command, i.e. the old behaviour.
  - `AUTO_MANAGED_BUILTIN_IDS` marks the three, and `known_specs` lets their
    acquired binary replace the bare command IN PLACE — same id, same slot,
    same display name, so the plugin catalogue never sees two entries.
  - Built-in specs are emitted after installed ones so a manifest-current
    binary outranks a frozen install record (a machine that installed
    OpenCode from the marketplace before it shipped built-in has both).

First-use progress
  - The composer's boot pill reads "Setting up Cursor... 42%" instead of
    stalling silently through a 77 MB download.
  - Progress is throttled to whole-percent changes: the registry callback
    fires once per HTTP chunk (~56k times for Cursor), and one IPC event
    each would flood the bridge. 101 events per download, test-pinned.
  - Its own `atlas:agent-acquire:*` events rather than the marketplace's
    install events, which only its install flow clears.

Sign-in
  - These adapters advertise an auth method but no `_meta.terminal-auth`,
    and their CLI now lives in Atlas's app-data dir rather than on PATH, so
    "run `cursor-agent login`" was advice no one could follow.
    `enrich_auth_methods` synthesises the missing spec from the managed
    binary; an adapter-supplied spec always wins.
  - Cursor rejects `session/new` when signed out, so this surfaces at BIND
    time and never reaches the turn-failure route that raises
    `atlas:auth-required`. Both paths now offer the same one-click "Sign
    in", and the bind path retries itself once credentials land.
  - Bind failures used to be a bare console.warn; they are now reported.

Turning them off
  - `AppSettings::disabled_builtin_agents` + a switch on the three built-in
    marketplace cards. Off means hidden from the picker and never spawned —
    including both background pre-warms and a resume of an older session.
  - The Rust guard is the authority and hard-filters against
    AUTO_MANAGED_BUILTIN_IDS, so a hand-edited state.json cannot disable
    Claude, Codex or Cersei. Chat history is never hidden.

Verified against the real binaries, not just mocks: Cursor cold-downloaded
(77 MB, ~19 s), extracted, and answered an ACP initialize with protocol v1
and the `cursor_login` auth method; each agent's login argv was read off
its own `--help`.

Fixes #160

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pacifio
pacifio merged commit 45a101d into 0.3.0-x Aug 16, 2026
18 checks passed
@Ukaykhingmarma28
Ukaykhingmarma28 deleted the acp-builtin-auto-acquire branch August 16, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants