feat(launch): add Atomic Agent as a one-click Launch-page assistant - #258
Conversation
Atomic Chat can already install fifteen external agents and point them at the local OpenAI-compatible server, but AtomicBot-ai/atomic-agent — our own local-first operator agent — was not one of them, so running it on Atomic Chat's models meant hand-editing its config file. Install spawns the project's official bootstrap script (curl | sh on Unix, irm | iex on Windows) because it ships as a Node SEA binary from GitHub Releases, not as an npm package. Run then merges a single `openai-compatible` provider into `<state dir>/config.json` and selects it as `llm.activeTextProvider`. The write is a merge, never a replacement: config.json is the agent's own trust surface, so other providers, their keys, unknown top-level blocks and the `version` field survive verbatim. A block created from nothing also carries the `local-llama` entry the agent otherwise synthesises for itself, because `llm.activeEmbeddingProvider` must name a provider that exists or the agent rejects the whole file — and embeddings drive memory recall, not chat, so Run never repoints them. Verified end-to-end against atomic-agent v0.4.1: the written config loads through its own parser, builds the `atomic-chat` provider, and completes a request against `http://127.0.0.1:1337/v1/chat/completions` with the configured model. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Thanks for this, @plombeer31 — our own agent being the one missing from that page was a real gap, and the way you closed it is careful in the places that matter. Two things stand out: treating Rather than take the description on trust I cloned
Verified on your branch merged onto current
Three things. Only the first needs a diff. 1. Three rustfmt violations, all new
2.
|
…ddings to local-llama Review follow-ups on the Atomic Agent Launch integration. rustfmt: the three new violations are gone, so commands.rs is fmt-clean again. Only that file was formatted — src-tauri has pre-existing drift elsewhere that is not this PR's to fix. toolTransport: dropped. The agent defaults an absent one to "auto" itself (parseUserLlmFileConfig), so the insert could only ever restate the agent's own choice while adding a key to the user's file. That also makes the ADR's "only two keys plus the embedding repair" claim true again. Embedding repair: the local-llama seed used to fire only when `providers` was empty, so a non-empty list without local-llama fell through to our own id — the one target the ADR argues against. The seed now runs in the repair path too, and the repair target is always local-llama. The test asserts which provider it lands on, not merely that the value is listed. The seeded local-llama URL is now mode-aware, matching the agent's own default: under localModels.mode "managed" it follows managed.port (19091 by default), not localModels.url. An empty model is refused before the write instead of relying on the callers: the agent's parseOptionalString rejects "" rather than treating it as absent, so an empty defaultChatModel would take the whole file down. Verified: 497 passed / 0 failed (was 493, +4 new tests); clippy clean in the added range; rustfmt clean on commands.rs. Re-ran the end-to-end against atomic-agent v0.4.1 for three shapes — fresh install, managed mode, and the repair path over a real provider list — all three load through the agent's own parser and build the atomic-chat provider, with toolTransport resolving to "auto" without us writing it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Thanks — you read the agent's parser rather than my description of it, and items 2 and 3 are both real. All three are fixed in 1. rustfmtFixed. I formatted only that file, deliberately. 2.
|
|
Thanks for the quick turnaround, @plombeer31 — all three items and both nits are closed, and I checked each against the agent's own parser rather than against the commit message. Doing that turned up one new thing in the same area, and it's the only reason I'm not merging today. Verified on your branch — it's based on
The seeded
|
Creating the `llm` block moves the agent from the config branch that reads `localModels.*` directly to the one that resolves a provider entry as `baseUrl ?? url`. The seeded `local-llama` entry wrote only `url`, so for anyone running the embeddings daemon, pressing Run silently repointed embedding requests at the chat daemon — the outcome the ADR rules out, arriving by a different route than the dangling-provider one. Seed `baseUrl` the way the no-`llm`-block branch computes it: `localModels.embeddings.url` (or `http://127.0.0.1:<embeddings.port>`) when that daemon is enabled, the entry's own mode-aware chat URL when it is not. Copying the agent's own synthesised entry literally was the other option and is worse: it sets `baseUrl` unconditionally, which would point a default install at :19092 with nothing listening. Verified against the agent's own parser (`loadConfig()` + `resolveEmbeddingLlmConfig()`, atomic-agent v0.1.67) rather than by reading the source: all six cases — external/managed × daemon off/on/custom port — resolve byte-identically before and after the writer touches the file. Also write `defaultChatModel` trimmed, since it is validated trimmed, and narrow the ADR's preservation claim to `requestTimeoutMs`, which is what the code actually preserves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You beat me to it — I had the same fix in flight when your Since you verified my commits against the parser rather than the commit message, here's the same treatment of yours — I re-ran it rather than reading it. Your fix, verifiedSame six-case matrix, driving the agent's own And the harness isn't vacuous — I ran it against Also on
|
|
Took the The seed follows the no- fn atomic_agent_embedding_base_url(root, chat_url) -> String // embeddings.enabled ? embeddings.url : chat_urlwith Verified the same way you did — through
On Also in:
Merging. Generated by Claude Code |
What
Adds Atomic Agent (
AtomicBot-ai/atomic-agent) to the Launch page as a one-click assistant, next to Hermes and OpenClaw — and toatomic-chat-cli launchwith it, since the two catalogs share the sameconfigure_*writers.Everything else on that page already works this way; our own agent was the one missing, so running it on Atomic Chat's models meant hand-editing its config file.
How
curl -fsSL https://atomicagent.io/install | shon Unix,irm https://atomicagent.io/install.ps1 | iexon Windows. It ships as a Node SEA binary from GitHub Releases, not as an npm package, so the prerequisite iscurl/powershell— same shape as Goose, Hermes and Poolside. Neither script prompts, so there is no wizard to skip.configure_atomic_agentupserts one provider into<state dir>/config.jsonand setsllm.activeTextProviderto it.atomic-agentopens the TUI, so norun_argsare needed.The entry it writes:
{ "id": "atomic-chat", "kind": "openai-compatible", "baseUrl": "http://127.0.0.1:1337/v1", "apiKey": "atomic", "defaultChatModel": "<running model>", "supportsTools": true, "requestTimeoutMs": 300000 }The state dir is resolved the way the agent's own
loadConfig()resolves it:ATOMIC_AGENT_STATE_DIRfirst (read fromHKCU\Environmentbeforestd::env::varon Windows, for the stale-snapshot reason in the 2026-07-01 Hermes ADR), else~/.atomic-agent.Design calls worth reviewing
config.jsonis the agent's own trust surface — it holdsagent.approvalLeveland is guarded by its approval ladder — so onlyllm.providers[atomic-chat]andllm.activeTextProviderare rewritten. Other providers, their API keys, unknown top-level blocks and theversionfield survive verbatim. We deliberately do not stamp a schema version: the agent fills every block it does not find with its own defaults on the next start, so there is nothing here to keep in sync.activeEmbeddingProvideris load-bearing. The agent rejects the whole config when it names a provider that is not inllm.providers, so a block created from nothing also carries thelocal-llamaentry the agent otherwise synthesises for itself, pointed at whateverlocalModels.urlsays. Embeddings drive memory recall rather than chat, so Run never repoints them — the key is only filled when absent or dangling.modelkey.requestTimeoutMsis a tightening, like Hermes'. The agent's OpenAI-compatible provider defaults to 600 s, long enough that a wedged local turn looks like a hang. 300 s is seeded, and a value the user already tuned on our entry is preserved.endpointWithPrefix: true. The storedbaseUrlreads as the base URL a user would paste; the agent'snormalizeOpenAiBaseUrlstrips the trailing/v1itself, so requests land on/v1/chat/completions, not/v1/v1/...(verified below).Verification
Rust, on this branch:
Six new unit tests cover the merge: seeding a self-consistent block from nothing, following the user's
localModels.url, preserving foreign blocks/providers/keys, idempotent re-runs that keep a tuned timeout, repairing a danglingactiveEmbeddingProvider, and rejecting a non-object file.End-to-end against atomic-agent v0.4.1, with the exact
config.jsonthis writer produces and a stub OpenAI-compatible server on:1337:So the file loads through the agent's own parser, builds the provider, and serves a completion — no
/v1/v1doubling, no config-validation error.Known limitation
The Unix installer drops the binary in
~/.local/binand appends to a shell rc file, which the memoised login-shell PATH in the running app cannot see — so the "Installed" chip catches up only on the next app start. Same as Goose, Poolside and Zed today; the terminal Run opens is a fresh login shell, so the launch itself works. Not addressed here.Notes
docs/decisions/2026-08-25-add-atomic-agent-as-a-one-click-launch-page-assistant.md, indexed under Launch page & external coding agents.assets/logo.svgin that repo), inlined as SVG rather than added as an image asset.web-applint/typecheck were not run here (they need the fullmake devtoolchain); the two TS changes are a catalog entry and oneinvokecase, and both files parse clean.🤖 Generated with Claude Code