DEV Community

Casey Sun
Casey Sun

Posted on

Every Token Is a Line Item: A Ledger Workflow for Agent Spend

Every Token Is a Line Item: A Ledger Workflow for Agent Spend

A developer asks a simple question: how much does the agent cost per run? Nobody answers. The dashboard shows a monthly total. The total hides the details. One task type may burn most of the budget. Retries add a silent surcharge. Context grows across steps. The answer lives in a ledger, not a dashboard.

This article builds that ledger. The worked example uses MonkeyCode's free tier. MonkeyCode is an open source project. It offers 10 million free tokens and a free server option. Both claims are operator-supplied. No model names, hardware, or quotas are assumed here. The workflow itself is the artifact. Run it against any OpenAI-compatible endpoint.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The question nobody can answer

Most teams track latency. Few track token spend per task. Latency is visible in every request log. Token spend is buried in usage fields. Aggregated dashboards smooth out the spikes. A weekly total cannot show which task caused the spike. The fix is bookkeeping. Record every run. Group by task type. Reconcile weekly.

A ledger, not a dashboard

A ledger stores one row per run. Each row records the task type, the token counts, and the retry count. This schema is small enough to start in SQLite. It is portable enough to move to Postgres later.

CREATE TABLE token_ledger (
    id INTEGER PRIMARY KEY,
    ts TEXT NOT NULL,
    task_type TEXT NOT NULL,
    run_id TEXT NOT NULL,
    model TEXT NOT NULL,
    prompt_tokens INTEGER NOT NULL,
    completion_tokens INTEGER NOT NULL,
    total_tokens INTEGER NOT NULL,
    retries INTEGER NOT NULL DEFAULT 0,
    ok INTEGER NOT NULL DEFAULT 1
);
Enter fullscreen mode Exit fullscreen mode

Run_id links retries to the original attempt. Task_type links spend to a feature. The model column keeps the ledger honest during model swaps.

Logging every run

The logging step is a thin wrapper around the client call. It writes one row per attempt. It writes failures too. Failed runs consume tokens. They belong in the ledger.

import sqlite3
from datetime import datetime, timezone

def log_run(conn, task_type, run_id, model, usage, retries=0, ok=True):
    conn.execute(
        "INSERT INTO token_ledger "
        "(ts, task_type, run_id, model, prompt_tokens, "
        "completion_tokens, total_tokens, retries, ok) "
        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
        (
            datetime.now(timezone.utc).isoformat(),
            task_type,
            run_id,
            model,
            usage.prompt_tokens,
            usage.completion_tokens,
            usage.total_tokens,
            retries,
            int(ok),
        ),
    )
    conn.commit()
Enter fullscreen mode Exit fullscreen mode

The wrapper is deliberately dumb. No aggregation. No filtering. Raw rows only. Aggregation belongs in queries.

Three queries that explain spend

Query 1: cost per task type

SELECT task_type,
       COUNT(*) AS runs,
       ROUND(AVG(total_tokens)) AS avg_tokens,
       SUM(total_tokens) AS total_burn
FROM token_ledger
WHERE ok = 1
GROUP BY task_type
ORDER BY total_burn DESC;
Enter fullscreen mode Exit fullscreen mode

This query ranks workloads by burn. The top row is the first place to optimize. A single task type often dominates. The average can be distorted by one long run. Check the distribution before trusting the mean.

Query 2: retry cost

SELECT run_id,
       COUNT(*) AS attempts,
       SUM(total_tokens) AS run_cost
FROM token_ledger
GROUP BY run_id
HAVING COUNT(*) > 1
ORDER BY run_cost DESC;
Enter fullscreen mode Exit fullscreen mode

Every retry re-sends the full context. The prompt tokens are paid twice. This query groups attempts by run_id. It shows the true cost of a flaky call. A 10 percent retry rate adds roughly 10 percent to the burn.

Query 3: the reconciliation check

SELECT SUM(total_tokens) AS burn_so_far,
       10000000 - SUM(total_tokens) AS remaining
FROM token_ledger;
Enter fullscreen mode Exit fullscreen mode

The 10,000,000 in this query is the operator-supplied free tier figure. Replace it with your own budget. Run this check weekly. Compare the burn rate to the calendar. If the week used more than one-seventh of the budget, the month will not fit.

The weekly reconciliation

Once a week, run the three queries. That is the moment to act. Reduce retries. Shorten context. Move heavy tasks to a different lane. Reconciliation is a habit, not a script. The queries take seconds. The discipline takes a calendar reminder.

What the ledger typically reveals

Three patterns show up in most ledgers:

  • One task type dominates. The fix is targeted: shorten the prompt or split the task.
  • Retries are a hidden tax. The fix is a timeout budget and a backoff policy.
  • Multi-step runs grow context. Each tool result feeds the next call. The ledger shows the growth as a row-by-row cost.

None of these patterns require a benchmark. They require bookkeeping.

Where the free server fits

The ledger also informs server choice. Treat the free server as a single lane until measured otherwise. It suits bursty, low-concurrency workloads. A nightly job fits. A CI smoke test fits. A steady stream of parallel requests does not. The ledger shows the request pattern. Let the data decide.

Limitations

This workflow records what the client reports. It does not measure server-side capacity or uptime. The 10 million token figure is operator-supplied. Verify the current terms before relying on them. The ledger is a cost tool, not a performance tool. Latency and correctness need separate measurements.

Who should skip this

Teams with strict latency SLAs should not point production at a free server. High-concurrency workloads need a load-tested lane. Long-context agents may exhaust the budget before the week ends. The ledger will tell them. It will not save them.

Start the ledger before you start the agent. The first row is the cheapest lesson.

MonkeyCode provides free models that can run this workflow.

Top comments (0)