Skip to content

Why local-first

Atomic Agent runs on your computer. The language model, your conversations, your memory, your tasks — all of it lives in a folder on your machine, not on someone else’s server.

That one design choice changes what the agent can promise you. Nobody bills you per token. Inference runs on your own hardware, and the ways data can leave are listed on this page so you can close the ones you don’t want. And because every part is on disk, you can open it up, read it, and change it.

Two things do reach the network on a fresh install without you asking for them each time: anonymous usage stats and crash reports (model name, timing, token counts, never your prompts or files), and web searches, which go to Exa’s hosted search by default when the agent searches. Both can be turned off. See Egress and Telemetry below.

What “local-first” means here

By default, the agent talks to a local llama-server (llama.cpp) running on 127.0.0.1. It does inference on your own GPU or CPU using a quantized model you downloaded once. Your prompts, the model’s replies, and everything the agent remembers are stored on your disk.

Own the control plane

The runtime, the model, the tool loop, and the data are all processes and files you control. No remote orchestrator decides what runs.

Private by default

Inference is local. Memory is a local SQLite file. Your prompts, replies and files go out only through the tools and integrations listed below. Anonymous usage stats and crash reports are on by default and one flag away from off.

No per-token fees

You pay for electricity, not for tokens. Run the agent for hours; the marginal cost is your own hardware.

Hackable all the way down

Config is a JSON file. Skills are folders. Traces are NDJSON. Open any of it in your editor.

Where your data actually lives

Everything the agent persists goes under one state directory — by default ~/.atomic-agent, overridable with ATOMIC_AGENT_STATE_DIR.

WhatWhereNotes
User config<stateDir>/config.jsonPlain JSON, versioned, edit by hand or via atomic-agent config set
Secrets<stateDir>/.envAPI keys, TELEGRAM_BOT_TOKEN; written with mode 0600
Memorymemory.sqliteProfile facts, notes, lessons, procedures (FTS5 + optional embeddings)
Sessionssessions.sqliteFull conversation transcripts
Taskstasks.sqliteScheduled and recurring task queue
Traces<stateDir>/traces/<sessionId>.ndjsonAppend-only, on by default for run, tui and serve
Analytics state<stateDir>/analytics.jsonAnonymous install id
Models<stateDir>/models/ (override with localModels.managed.dataDirOverride)Contains models/ (GGUF weights) and backend/ (the managed llama-server)
Terminal window
# Point the whole runtime at a different state directory
ATOMIC_AGENT_STATE_DIR=/Volumes/encrypted/atomic atomic-agent tui

No per-token fees

Because the default backend is a local llama-server, there is no metered API in the loop. The runtime is built to make that local model affordable to run for long, multi-step sessions:

  • Stable prompt prefix + KV-cache reuse. The persona, tool catalog, and skill index form a byte-stable prefix that llama-server caches once per session. Each step reuses it via cache_prompt and slot affinity instead of reprocessing it.
  • Bounded prompts. Every section of the prompt tail has a cap, and the conversation is sized to fit the model’s context window (agent.conversationMaxTokens: 0 means auto). Memory grows in SQLite, not in the prompt; the model only sees compact pointers.
  • Compressed tool results. Verbose output is summarized before it re-enters the conversation, so a noisy grep or test run doesn’t blow the budget.

If you want a cloud model for some work, you can configure one under llm.providers[]. That is an explicit opt-in, and it is the point where tokens start costing money and your prompts start going to a cloud provider — see Egress below.

Terminal window
# Run fully local, managed model lifecycle
atomic-agent models pull qwen-3.5-4b
atomic-agent models use qwen-3.5-4b
atomic-agent tui

Egress: the points where data can leave

Local-first does not mean airtight. The agent is useful precisely because it can act in the world — browse, fetch, run shell commands. The honest framing is: egress is explicit and enumerable. Here are the doors out.

flowchart LR
    Core["atomic-agent runtime<br/>(local model, memory,<br/>sessions, tasks)"]
    Core --> Browser["browser.* tools<br/>(navigate, fetch)"]
    Core --> Http["os.http / os.web.fetch<br/>os.web.search"]
    Core --> Shell["os.shell<br/>(inherits your env)"]
    Core --> Skills["skill.run_script"]
    Core --> Cloud["cloud LLM providers<br/>(llm.providers, opt-in)"]
    Core --> Mcp["MCP servers<br/>(mcp.servers, opt-in)"]
    Core --> Tg["Telegram channel<br/>(opt-in, single-user)"]
    Core --> Tel["telemetry<br/>(on by default)"]
    Core --> Upd["update check<br/>(on by default)"]
    Core --> Hub["ClawHub skill registry<br/>(on by default)"]
    Core --> Search["web search<br/>(Exa by default)"]
    Core --> Integr["Discord, GitHub,<br/>Atomic Mail, Composio<br/>(opt-in)"]
    Core --> Fusion["Fusion orchestrator<br/>(opt-in, cloud by default)"]

    Browser --> Net((Internet))
    Http --> Net
    Skills --> Net
    Cloud --> Net
    Mcp --> Net
    Tg --> Net
    Tel --> Net
    Upd --> Net
    Hub --> Net
    Search --> Net
    Integr --> Net
    Fusion --> Net

    style Core fill:#e8f5e9
    style Net fill:#fff3e0

Each door, and what stands in front of it:

  • Browser and HTTP tools (browser.navigate, os.web.fetch, os.web.search, os.http.request) reach the internet on purpose and run without a prompt by default. Browser navigation to a non-http(s) URL asks below level 5. To gate outbound HTTP, set http.approvalMode to "writes" (ask before POST) or "always"; http.hostAllowlist limits which hosts os.http.request may reach.
  • Shell and skill scripts (os.shell, skill.run_script) run with the agent process’s environment and can do anything you can do at a terminal. Both are approval-gated. Shell commands additionally pass a command guard (hardline blocks for catastrophic commands such as rm -rf /, mkfs and raw disk writes, plus dangerous-pattern checks).
  • Cloud LLM providers are off unless you configure llm.providers[]. When active, prompts go to that provider.
  • MCP servers are off unless listed in mcp.servers[]. Each server has a trust level; the default is approval_gated (fail-closed), so even hallucinated tool names from a stale server land in the safe lane. Tools that advertise readOnlyHint skip the prompt.
  • Telegram is constructed but inert unless telegram.enabled is true and a token is present. It is deliberately single-user (owner-pairing, fail-closed when ownerUserId is null).
  • Other integrations (Discord, GitHub, Atomic Mail, Composio) are off until you connect them. Once connected their tools talk to those services; GitHub publishing, network git and e-mail sends go through the approval gate.
  • Fusion mode sends the orchestrator’s prompts to the orchestrator’s provider (a cloud model by default); with the default pairing the workers run locally.

These doors are open on a fresh install. Web search carries the search query; the other three do not carry your prompts or files:

  • Web search sends the query to Exa’s hosted endpoint by default (DuckDuckGo as fallback) whenever the agent runs os.web.search. Change web.search.provider (for example to searxng with your own instance) or set web.search.enabled: false.
  • Telemetry sends anonymous usage stats and crash reports. Off with analytics.enabled: false — see Telemetry.
  • Update check asks the GitHub releases API whether a newer version exists when the TUI starts. Off with ATOMIC_AGENT_UPDATE_CHECK_ON_STARTUP=false.
  • ClawHub is the skill registry behind skill browse and skill search. It is contacted only when you run those commands or open the Skills panel. Off with skills.clawhub.enabled: false.

Telemetry

Atomic Agent sends anonymous usage stats so we can see which models people run, where the agent is slow, and what crashes. It is on by default and takes one line to turn off.

What is sent: an anonymous install id, platform, app version, which onboarding screens you passed and whether you chose a local or cloud model, and per message the model and provider name, response latency, step count, how the turn ended, token counts and estimated cost. Crash reports carry the error type, a bounded tool name or URL host, and stack frames with paths stripped.

What is never sent: your prompts, the model’s replies, file contents, file paths, tool arguments or memory. Your IP address is not stored: neither PostHog nor the crash reporter is asked to keep it, and GeoIP lookup is disabled (the request itself still comes from your network, like any web request). The scrubber that guards this is an allowlist — fields must be explicitly permitted to travel, so nothing leaks by omission.

// config.json — disables usage stats and crash reporting together
{
"analytics": {
"enabled": false
}
}

That single flag governs both the usage stats and the crash reporter. There is no separate switch to remember.

You can also flip it without leaving the TUI. /analytics on, /analytics off, and /analytics status toggle the same setting and report its current state; /privacy analytics on|off is the same command under the Privacy panel’s namespace. Either form opens the Privacy tab, where a toggles it directly.

Own the control plane

“Control plane” means the part that decides what runs and when. With a hosted agent, that lives on a vendor’s servers. With Atomic Agent, it is createAgentRuntime running in your process, wiring together the model provider, tool registry, memory stores, and the agent loop. You start it, you stop it, you see everything it does.

Concretely, you own:

  • The entry point. CLI (atomic-agent run), TUI (atomic-agent tui), HTTP server (atomic-agent serve), or the Tauri sidecar — all construct the same local runtime.
  • The serving surface. atomic-agent serve exposes an OpenAI-compatible API on a host and port you choose, bound to 127.0.0.1 by default. Pass --api-key (or set ATOMIC_AGENT_API_KEY) to require a bearer token. Without one the server starts unauthenticated and says so in its startup line: auth=none. Always set a key before changing --host off localhost.
  • Concurrency and ordering. A per-session FIFO turn controller serializes turns; different sessions run in parallel. This is enforced locally, not by a remote queue.
Terminal window
# Your machine becomes the API endpoint, bound to localhost.
atomic-agent serve --host 127.0.0.1 --port 8787 --api-key "$MY_KEY"

Hackable all the way down

Local-first only matters if you can actually reach in and change things. Every layer is a file or a documented surface:

  • Config is config.json — read it, edit it, or drive it with atomic-agent config get / atomic-agent config set '<json>'.
  • Skills are folders (SKILL.md + optional scripts/). Install with atomic-agent skill install <path>, list with atomic-agent skill list, toggle with atomic-agent skill enable|disable.
  • Memory is a SQLite database you can open with any SQLite client, or browse read-only in the TUI Memory tab.
  • Traces are append-only NDJSON under <stateDir>/traces/, on by default for run, tui and serve (turn off with tracing.trace.enabled: false). Inspect with atomic-agent trace list / trace show <sessionId> or detect prompt drift with atomic-agent trace replay <sessionId>.
  • Models are managed by you: atomic-agent models list|pull|use|start|stop|status.

When you might not want local-first

Being honest about the tradeoffs:

  • Hardware matters. Local inference quality depends on the model your machine can run. A 4B quantized model is not a frontier cloud model. You can mix in a cloud provider for hard turns, at the cost of egress and per-token fees.
  • Platform support. Releases today cover macOS on Apple Silicon, Linux x64/arm64, and Windows x64.
  • You operate it. No vendor patches your runtime overnight. Updates are explicit (atomic-agent update or your package manager).

For most local automation — browsing, files, shell, document extraction, memory that persists across sessions — keeping the model and your data on your machine is the whole point.