Phrase the task well
One clear goal per turn. The model classifies your task and adjusts its own guidance.
Atomic Agent runs on small, quantized models on your own machine. That is the whole point — your data stays local, there are no per-token fees, and you can hack any layer. But a 4B model running through llama.cpp is not GPT-4. It needs a little help to do its best work.
This page is a practical checklist. Each tip maps to something the runtime actually does, so you can lean into the grain of the system instead of fighting it.
Phrase the task well
One clear goal per turn. The model classifies your task and adjusts its own guidance.
Let memory do the remembering
Don’t paste history back in. Pin facts; let recall and reflection handle the rest.
Keep prompts cache-friendly
A stable prompt prefix means fast steps. Avoid forcing changes that bust the KV-cache.
Pick a model that fits
Bigger models reason better; smaller models are faster. Match the model to the work.
The agent runs a loop: it reads your message, calls tools, and repeats until it replies or finishes. Small models do best when each turn has one clear objective.
./src and summarize each” beats “clean up my code”.reply or finish.Under the hood, the prompt builder runs renderTaskPolicy(), which classifies your message into debug, code_edit, broad_exploration, or multi_step and emits tailored guidance. Clear phrasing helps it classify correctly, which directly improves the plan.
Local models have small context windows. Atomic Agent keeps prompts tight (default budget agent.tokenBudget, with conversation clamped to the model’s real context window) by storing knowledge outside the prompt and recalling only what’s relevant.
Three memory channels do the heavy lifting:
| Channel | What it holds | Tool |
|---|---|---|
| Profile facts | Durable key/value facts about you | memory.profile.set / .list |
| Notes | Searchable freeform notes (FTS5/BM25) | memory.notes.store / .recall |
| Lessons & procedures | Distilled patterns from past sessions | memory.lessons.recall / memory.procedures.recall |
Best practices:
memory.profile.set { key, value, pinned: true } renders every turn. Use it for things like your name, stack, or conventions.pinned: false with keywords, and the fact only appears when your message mentions one of those keywords (memory.profile.contextualKeywordGate is on by default). This keeps the prompt lean.By default, recall uses BM25 keyword search. If you want paraphrase-tolerant recall (“the auth bug” finding a note that said “login token failure”), enable embeddings:
// <stateDir>/config.json{ "memory": { "embeddings": { "enabled": true }, "links": { "enabled": true } // optional: expand to linked neighbors }}Embeddings run on a second llama.cpp daemon. If it fails to start, recall silently falls back to BM25 — nothing breaks.
Each step reuses a byte-stable prompt prefix (persona, tools, skills, capabilities) via llama.cpp’s KV-cache. A cache hit is what makes multi-step sessions affordable on local hardware. Anything that changes the prefix forces a full recompute.
What keeps the cache warm:
skill.view is fine — it lands in the variable tail, not the prefix, and is cached for the rest of the session.flowchart LR
A["Stable prefix<br/>persona · tools · skills"] -->|cached once| KV["KV-cache slot"]
B["Variable tail<br/>conversation · memory · world"] -->|rebuilt per step| Step["LLM step"]
KV -->|reused every step| Step
Step -->|reply / finish| Done["Turn ends"]
Step -->|more tools| B
The tail is deliberately ordered slowest-to-fastest changing, so hot sections (conversation) never invalidate slower ones (profile, loaded skills) sitting above them in the cache.
In a single step the model can emit one or many tool calls as a JSON array. The executor groups them by resource class:
pure_read tools run in parallel (e.g. several os.fs.read calls at once).reply, finish) run last, after every other tool in the batch settles.You don’t configure this per call, but you can influence it:
agent.maxParallelToolCalls (env ATOMIC_AGENT_MAX_PARALLEL_TOOL_CALLS, max 16) if you want wider read fan-out on a fast machine.Dangerous operations (shell, os.fs.write, os.http.request, archive extraction, process kill, skill scripts) pause for approval by default.
Approval prompts appear in your terminal, TUI, Telegram, or HTTP /api/events stream. This is the safe default for everyday use.
atomic-agent runFor test runs, sandboxes, or fully autonomous tasks, bypass the gate. Every dangerous tool auto-approves and you lose visibility into what ran — use only where you trust the workload.
atomic-agent run --no-approvalatomic-agent serve --no-approvalEquivalent config:
{ "agent": { "approvalRequired": false } }Small models sometimes get stuck repeating a tool call or wandering through searches. Atomic Agent has a per-turn loop detector that handles this gracefully:
The takeaway: if the agent gets stuck, it will recover on its own and reply. You rarely need to intervene. If you see frequent loops on a specific task, that’s usually a sign the task is underspecified — tighten the phrasing or break it into smaller turns.
The thresholds are tunable if a particular workload needs more or less patience:
ATOMIC_AGENT_LOOP_WARNING_THRESHOLD # warn after N arg-only repeatsATOMIC_AGENT_LOOP_CRITICAL_THRESHOLD # veto after N no-progress repeatsATOMIC_AGENT_LOOP_WANDERING_ESCALATION # force reply when search args spread too wideIf a turn ends with max_steps instead of a real reply, the model ran out of budget mid-task.
atomic-agent run --max-steps 40 (or agent.maxSteps in config, default 25).Managed local models are swappable. A few rules of thumb:
qwen-3.5-4b) is quicker and cheaper on VRAM.mmproj projector.atomic-agent models list # see installed + availableatomic-agent models pull <id> # download a modelatomic-agent models use <id> # switch the active modelatomic-agent models status # check the daemonWhen a session behaves oddly, traces are your best tool. They record every prompt, completion, tool call, and memory operation as append-only NDJSON.
atomic-agent trace list # recent sessionsatomic-agent trace show <sessionId> # full chronologyatomic-agent trace replay <sessionId> # detect prompt-stack drifttrace replay is especially useful after upgrading: it rebuilds the stable prefix with your current tools/skills and flags whether anything drifted since recording — a common cause of “it used to work.”
| Goal | Lever |
|---|---|
| Remember something durably | memory.profile.set { pinned: true } |
| Surface a fact only when relevant | memory.profile.set { pinned: false, keywords: [...] } |
| Fuzzy recall | memory.embeddings.enabled = true |
| Wider parallel reads | agent.maxParallelToolCalls / ATOMIC_AGENT_MAX_PARALLEL_TOOL_CALLS |
| Longer tasks | --max-steps N / agent.maxSteps |
| Autonomous runs | --no-approval / agent.approvalRequired |
| More/less loop patience | ATOMIC_AGENT_LOOP_* thresholds |
| Better reasoning | atomic-agent models use <larger-model> |
| Debug a bad session | atomic-agent trace show / replay |