Skip to content

Tips & Best Practices

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.

Start here

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.

Write tasks the model can act on

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.

  • Be specific and bounded. “Find the three largest files under ./src and summarize each” beats “clean up my code”.
  • State the finish condition. Tell it what “done” looks like, so it knows when to call reply or finish.
  • Give a starting point. A path, a URL, or a filename saves the model from guessing.

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.

Lean on memory instead of long messages

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:

ChannelWhat it holdsTool
Profile factsDurable key/value facts about youmemory.profile.set / .list
NotesSearchable freeform notes (FTS5/BM25)memory.notes.store / .recall
Lessons & proceduresDistilled patterns from past sessionsmemory.lessons.recall / memory.procedures.recall

Best practices:

  • Pin identity facts. memory.profile.set { key, value, pinned: true } renders every turn. Use it for things like your name, stack, or conventions.
  • Use contextual facts for the rest. Set 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.
  • Don’t re-paste prior conversation. Reflection runs automatically at the end of each turn and stores useful observations. Recall surfaces them next time — you don’t need to remind the agent of what it already learned.

Turn on embeddings for fuzzy recall

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.

Keep the prompt cache warm

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:

  • Don’t swap the model mid-session unless you mean to. A model swap is detected and triggers a grammar/profile rebuild, which changes the prefix.
  • Install skills before you start, not mid-turn. Installing or removing a skill rebuilds the catalog and the stable prefix.
  • Loading a skill body with 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.

Batch read-only tools; serialize the rest

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).
  • Writes and other side-effecting tools serialize in order.
  • Terminal calls (reply, finish) run last, after every other tool in the batch settles.

You don’t configure this per call, but you can influence it:

  • Raise agent.maxParallelToolCalls (env ATOMIC_AGENT_MAX_PARALLEL_TOOL_CALLS, max 16) if you want wider read fan-out on a fast machine.
  • Encourage the model to gather context first (reads) before acting (writes) by phrasing tasks as “look at X and Y, then do Z”.

Tune approvals for your context

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.

Terminal window
atomic-agent run

Let the loop breaker work — don’t fight repetition

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:

  • Warnings nudge the model when it repeats the same call.
  • Critical vetoes block a call that keeps producing no progress.
  • The breaker forces a clean, synthetic reply after repeated vetoes — it ends the turn normally, it does not crash or mark the session failed.

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:

Terminal window
ATOMIC_AGENT_LOOP_WARNING_THRESHOLD # warn after N arg-only repeats
ATOMIC_AGENT_LOOP_CRITICAL_THRESHOLD # veto after N no-progress repeats
ATOMIC_AGENT_LOOP_WANDERING_ESCALATION # force reply when search args spread too wide

Give the model room to finish

If a turn ends with max_steps instead of a real reply, the model ran out of budget mid-task.

  • Raise the step budget for big tasks: atomic-agent run --max-steps 40 (or agent.maxSteps in config, default 25).
  • Or split the work across turns. Because memory persists, the agent picks up where it left off — you don’t lose context by stopping and continuing.

Match the model to the work

Managed local models are swappable. A few rules of thumb:

  • Reasoning-heavy or multi-step tasks → a larger model (e.g. a 9B+ or Gemma 4 variant) thinks more reliably.
  • Fast, repetitive, or tool-routing tasks → a smaller model (the default qwen-3.5-4b) is quicker and cheaper on VRAM.
  • Vision work → pick a vision-capable model and pull its mmproj projector.
Terminal window
atomic-agent models list # see installed + available
atomic-agent models pull <id> # download a model
atomic-agent models use <id> # switch the active model
atomic-agent models status # check the daemon

Diagnose with traces

When a session behaves oddly, traces are your best tool. They record every prompt, completion, tool call, and memory operation as append-only NDJSON.

Terminal window
atomic-agent trace list # recent sessions
atomic-agent trace show <sessionId> # full chronology
atomic-agent trace replay <sessionId> # detect prompt-stack drift

trace 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.”

Quick reference

GoalLever
Remember something durablymemory.profile.set { pinned: true }
Surface a fact only when relevantmemory.profile.set { pinned: false, keywords: [...] }
Fuzzy recallmemory.embeddings.enabled = true
Wider parallel readsagent.maxParallelToolCalls / ATOMIC_AGENT_MAX_PARALLEL_TOOL_CALLS
Longer tasks--max-steps N / agent.maxSteps
Autonomous runs--no-approval / agent.approvalRequired
More/less loop patienceATOMIC_AGENT_LOOP_* thresholds
Better reasoningatomic-agent models use <larger-model>
Debug a bad sessionatomic-agent trace show / replay