Run nanobot for a few dollars a month: a model budget that holds

Set a hard spending cap, a cheap primary model with a fallback, and a stronger model on demand in nanobot, then check the monthly bill against real token numbers.

· ranx.cloud

Illustration of a glass jar holding a few coins next to a small kitchen scale on a wooden counter

This guide is for people who use nanobot as a personal assistant and want its model bill to be a known, small number every month instead of a surprise. You end up with a spending cap the provider enforces, a cheap model that handles everyday chat and scheduled jobs, a fallback for when that model is down, a stronger model you switch to only for the conversation that needs it, and a way to compare your actual usage with the budget.

Everything below is done in the nanobot WebUI and in your provider's console. Labels were checked against nanobot v0.4.0 and its configuration docs. Prices are list prices from the OpenRouter model list and DeepSeek's pricing page, November 2026.

Where nanobot spends tokens

Every model call sends the system prompt (identity, SOUL.md, USER.md, MEMORY.md, skill summaries), the definitions of every enabled tool, and the conversation so far. One message from you can be several calls: the model asks for a tool, gets the result, then answers.

Four sources add up to your bill. Settings → Overview → Token usage → View details shows them under Usage by source:

Source What it is Default behaviour
Chat your messages in the WebUI and chat apps every message
Automations scheduled jobs you created one agent turn per run, in the job's chat
Memory Dream, which updates long-term memory every 2 hours, skipped when there's nothing new
Auxiliary calls internal calls without a chat of their own, such as idle compaction summaries compaction after 15 idle minutes

The heartbeat, a periodic check of HEARTBEAT.md, is counted under Automations. It is scheduled every 30 minutes but skipped without a model call while the file has no active tasks, so it is free by default. It only costs money once you add tasks under ## Active Tasks in HEARTBEAT.md; then it runs every 30 minutes around the clock. The interval can only be changed in nanobot's config file, not in the WebUI, so for anything at a fixed time ask for a scheduled job instead ("every weekday at 9...").

A worked monthly budget

A realistic personal profile: 15 messages a day, 2.5 model calls per message on average, 18,000 input tokens and 400 output tokens per call. Add two daily scheduled jobs (three calls each, 15,000 in, 300 out), Dream with work to do four times a day (20,000 in, 2,000 out), and three idle compactions a day (20,000 in, 1,000 out). Over 30 days:

chat:         15 × 2.5 × 30 = 1,125 calls → 20.25M in, 0.45M out
automations:  2 × 3 × 30    =   180 calls →  2.70M in, 0.05M out
memory:       4 × 30        =   120 runs  →  2.40M in, 0.24M out
compaction:   3 × 30        =    90 runs  →  1.80M in, 0.09M out
total                                     ≈ 27.15M in, 0.83M out

What that costs at list price, before any cache discount:

Model (via OpenRouter) $ per million in / out Input Output Month
DeepSeek V4.1 Flash 0.049 / 0.54 $1.33 $0.45 $1.78
GPT-5 nano 0.05 / 0.40 $1.36 $0.33 $1.69
Claude Haiku 5.5 0.10 / 0.50 $2.72 $0.42 $3.13
Gemini 3.1 Flash Lite 0.25 / 1.50 $6.79 $1.25 $8.04
Claude Sonnet 5.5 2.00 / 10.00 $54.30 $8.34 $62.64

Input dominates. Most of each call is the same system prompt and tool definitions, so prompt caching cuts it a lot when the provider supports it: Claude Haiku 5.5's cached input is $0.01 per million on OpenRouter, a tenth of the normal rate. The Cache hit rate figure on the token usage page tells you how much of that you're getting.

The 18,000-token figure is an assumption. Replace it after a few days: the context indicator next to the model badge in a WebUI conversation shows the current context size and per-round token use under Recent rounds.

Step 1: Put a hard cap at the provider

nanobot doesn't stop spending on its own. Put the limit where the money is.

With OpenRouter, create a key just for nanobot and set a credit limit on it, for example $5. When the key reaches the limit, OpenRouter refuses further requests on that key. DeepSeek's platform is prepaid, so its balance is its own cap.

Use one key per tool. If nanobot shares a key with other apps, you can't tell what it spent.

Step 2: A cheap primary model

  1. Open Settings → Models. If you see Convert to presets, choose it first.
  2. Choose New preset. Name it everyday.
  3. Open Provider, choose Add provider, pick OpenRouter, paste the key and save.
  4. Choose the model deepseek/deepseek-v4.1-flash (or type the ID). Under Advanced options, set Context window to 64k.
  5. Save.

The context window setting is a cost lever. nanobot compacts a conversation when it approaches the window, so a smaller window means older turns are summarized sooner and each call carries less history. 64k is plenty for chat and reminders; raise it only if you work with long documents.

Then make it primary: under Model order, use Enable preset and drag everyday to the top. The first enabled preset is the Primary.

Send a test message and ask for something that needs a tool, for example "what's today's date and what's the weather in Izmir". Small models differ a lot in how well they call tools; if this one fumbles, try anthropic/claude-haiku-5.5 in the same preset.

Step 3: A fallback

Create a second preset named backup with anthropic/claude-haiku-5.5 on the same OpenRouter provider, save it, and Enable preset. Order it below everyday.

nanobot tries the next enabled preset when the primary fails with a timeout, connection error, 5xx, rate limit, an authentication failure or exhausted credit, but not for refusals or malformed requests. Two consequences:

  • Keep the fallback on the same capped key. A fallback on a different, uncapped provider turns "budget reached" into "switch to the uncapped account".
  • When presets have different context windows, nanobot builds prompts for the smallest window in the chain, so give both the same value.

Step 4: A strong model only when you ask

Create a third preset, deep, with anthropic/claude-sonnet-5.5, and don't enable it in the order. Presets that aren't in the order can still be selected per conversation:

/model deep

That switches only the current conversation, and the choice persists for that conversation across restarts. Switch back with:

/model everyday

Scheduled jobs run in the chat where you created them and use that chat's model. If you once switched your Telegram chat to deep and forgot, its reminders now run on Sonnet. /model with no argument shows what a chat is using.

Step 5: Settings that keep calls small

  • Leave idle compaction on. Settings → System, Auto-compact idle sessions, with Idle timeout at 15 minutes. A conversation you come back to after lunch then resumes from a summary instead of the full transcript.
  • Start a new topic for a new subject. /new in a chat app, New topic in the WebUI. One endless conversation is the most common reason for large calls.
  • Use a temporary chat for one-offs. Nothing is added to history or memory.
  • Keep tool lists short. Every enabled MCP tool is sent with every call. Disable tools you don't use in Apps → MCP → Manage → Tools; the GitHub guide shows this for one server.
  • Prune MEMORY.md. It's in every prompt. See the memory guide.
  • Memory consolidation under Settings → Capabilities turns Dream off entirely. Dream's interval and a cheaper Dream-only model (agents.defaults.dream.intervalH and modelOverride) exist, but only in the config file; the WebUI has no control for them.

Check it after a week

Open Settings → Overview → Token usage. Multiply the week's input and output tokens by your model's prices and by about 4.3 for the month. If Automations is a large share, look at what each job does; if Chat is, look at conversation length and tool count.

On ranx.cloud the instance price is separate and fixed by plan; this guide is only about the model bill, which goes to your own provider account.

What goes wrong

nanobot stops replying and the WebUI shows a model failure. The provider refused the request, often because the key's credit limit was reached. The WebUI keeps the failure category and offers Continue once you've fixed the cause. Raise the limit or wait for the next month; the fallback won't help if it uses the same key, which is the point.

The bill is higher than the table. Usually long conversations or many enabled tools. One user reported a million tokens in two hours with no visible activity; the token usage page now shows the source, so check whether it's Memory, Automations or Auxiliary calls before changing models.

Heartbeat costs a lot. You added tasks to HEARTBEAT.md. Each run is a full agent turn every 30 minutes. Older versions also replayed the heartbeat session's history each time (#2375, closed). Move fixed-time checks to scheduled jobs and keep HEARTBEAT.md for rare, quiet checks.

You can't tell which model answered. There's an open report that the model button doesn't reflect a fallback that served the turn (#6550), and chat apps aren't notified of fallbacks at all (#6031). Model trends on the token usage details page shows which models were actually used.

"provider not found" or model errors after saving. A typo in the model ID. For OpenRouter, copy the ID exactly as the model list shows it, including the vendor prefix.

The cheap model loops on tool calls. Some small models repeat a failing tool call. Stop the turn with /stop, try the same request on backup, and if that's consistently better, make it the primary. A $1.35 difference a month isn't worth an assistant that fails.