DEV Community

Jordan Huang
Jordan Huang

Posted on

Free Tokens Are Not Free Work: Five Quota Myths and a Ledger You Can Run

Last week I burned a ten-million-token allowance before dinner. I merged two small fixes. Where did the rest go?

Not into the model. Into my loop. I resent the same files, re-asked the same question, and accepted almost nothing.

I ran that mess on MonkeyCode, which offers free model access and a free server option. The team says the current free allowance is ten million tokens.

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

Allowances change, so check the live terms yourself. The allowance was never my problem. My accounting was.

Here are five claims I used to repeat, and what actually held up.

Myth 1: A token is a unit of work

A token is a unit of billing. That is all it is. Two tasks can cost the same tokens and deliver very different value.

So stop asking "how many tokens did I use?". Ask "how many tokens per accepted change?". That second number is the one that survives contact with a deadline.

Here is the shape of my log, with illustrative numbers. These are not benchmark results.

task calls tokens accepted tokens/accepted
fix-import 6 14,900 1 14,900
rename-symbol 2 5,100 1 5,100
write-changelog 1 1,700 1 1,700

Same allowance. Very different economics. The first row is where my afternoon went.

Myth 2: A bigger allowance makes retries cheap

Retries are not free just because the meter is free. They cost your attention, and they cost wall-clock time.

Worse, retries compound. Each failed attempt usually gets appended to the next prompt. The transcript grows, and every later call pays for the earlier mistakes.

I call this retry amplification. It is calls divided by accepted results. Anything above three means the loop is broken, not the quota.

Myth 3: The free server is where I should measure speed

No. The free server is where the loop runs. It is not a benchmark host.

Use it for the boring win: a long run survives a closed laptop lid. Do not use it to compare models or claim latency numbers.

Why? Because you do not control the neighbors, the network path, or the scheduling. Any timing you publish from there is a rumor with a timestamp.

Myth 4: The model remembers my repo

Context is per request. Nothing persists unless you paste it again or the tool re-reads the files.

This is why the same bug costs more on the third attempt. You are paying to re-explain a repo the model never kept.

Fix it with a frozen context block, not a longer chat. Pick the files once, hash them, and reuse the same set until the task closes.

Myth 5: Acceptance is obvious, so I don't need to log it

If you cannot state the acceptance rule, you cannot compute cost per accepted change. Write the rule before the first call.

Mine is short. Tests pass. Diff stays under 80 lines. I would actually merge it.

Notice that the third clause is a judgment call. Log it honestly anyway. A ledger with fuzzy acceptance still beats no ledger.

The artifact: a token ledger you can run

You do not need a vendor dashboard. You need one JSONL file and twenty lines of Python.

First, the schema. One record per model call.

  • task: short stable id, like fix-import.
  • attempt: integer, starting at 1.
  • prompt_tokens, completion_tokens: your client's counts.
  • ctx_chars: size of the context you sent, in characters.
  • accepted: boolean, set by you after review.

Append a record with a single shell line:

printf '%s\n' '{"task":"fix-import","attempt":1,"prompt_tokens":1840,"completion_tokens":210,"ctx_chars":7400,"accepted":false}' >> ledger.jsonl
Enter fullscreen mode Exit fullscreen mode

Now the reporter. Python 3 standard library only, no dependencies:

#!/usr/bin/env python3
"""ledger.py - per-task token accounting for a free-tier coding loop.

Reads JSONL, one record per model call. You write the records yourself.
Keys: task, attempt, prompt_tokens, completion_tokens, ctx_chars, accepted
"""
import json
import sys
from collections import defaultdict


def load(path):
    rows = []
    with open(path, encoding="utf-8") as fh:
        for line in fh:
            line = line.strip()
            if line:
                rows.append(json.loads(line))
    return rows


def report(rows):
    buckets = defaultdict(list)
    for row in rows:
        buckets[row["task"]].append(row)

    print(f"{'task':24} {'calls':>5} {'tokens':>8} {'acc':>4} {'tok/acc':>8} {'amp':>6}")
    for task, calls in sorted(buckets.items()):
        tokens = sum(c["prompt_tokens"] + c["completion_tokens"] for c in calls)
        accepted = sum(1 for c in calls if c["accepted"])
        amp = len(calls) / max(accepted, 1)
        per_accept = tokens / max(accepted, 1)
        print(f"{task:24} {len(calls):>5} {tokens:>8} {accepted:>4} {per_accept:>8.0f} {amp:>6.2f}")


if __name__ == "__main__":
    report(load(sys.argv[1]))
Enter fullscreen mode Exit fullscreen mode

Run it:

python3 ledger.py ledger.jsonl
Enter fullscreen mode Exit fullscreen mode

You get a table. tok/acc is your real unit cost. amp is the retry amplification from Myth 2.

How to read the numbers

Three bands, no magic:

  1. amp at or below 1.5: the loop is healthy. Keep going.
  2. amp between 1.5 and 3: shrink the context block. Cut files, cut history.
  3. amp above 3: stop calling the model. Rewrite the task spec first.

That third band is the important one. More quota does not move you out of it. A clearer request does.

A decision table for free-tier loops

Not every task belongs in a free loop. Here is how I route mine.

Task Needs repo-wide context? Acceptance rule checkable? Fits the free loop?
Rename a symbol No Yes, build passes Yes
Fix one failing unit test Sometimes Yes, that test Yes, with a frozen context
Write a changelog entry No Partly Yes
Refactor a core module Yes Weakly Only with a reviewer
Anything with a deadline SLA Yes Weakly No

Two rules sit under that table. Freeze the context. Write the acceptance rule first.

Limitations you should hear from me, not from a launch post

  • The token counts come from my client, not the provider's meter. They drift.
  • The ledger measures spend, never quality. A cheap accepted diff can still be wrong.
  • Free allowances and free server capacity change without notice. Re-read the terms.
  • The free server is not a load-test host. Do not publish latency claims from it.
  • accepted is a human field. If you lie to it, the whole table lies back.

Who should not use this

Skip this workflow if you need an SLA or a support contract. Skip it if your acceptance rule is "looks fine to me".

Also skip it if you are benchmarking. A free box with unknown neighbors cannot support a benchmark claim, and pretending otherwise wastes everyone's review time.

What I changed in my own loop

I now log before I prompt. That small ordering change did more than any quota increase.

My first attempt of the week already carries a smaller context block. My amplification dropped because I stopped re-sending the whole story.

Is your free allowance the bottleneck? Or is it your retry count? Run the ledger for one week and you will know.

If you want to try it, the free tier is enough to run this ledger on a handful of real tasks and see your own amp.

Top comments (0)