A free AI coding server is a budget, not a speed limit. The practical problem is not whether the quota is large enough — it is that nobody sees the consumption until a request fails. This article builds a small token meter that records every request, computes a daily burn rate, and predicts the exhaustion date. The tool works with any OpenAI-compatible endpoint, including the free server that the open-source MonkeyCode project currently advertises.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Why invisible consumption is the real problem
Free tiers advertise a token allowance. The MonkeyCode project, for example, currently lists a free tier with 10 million tokens and a free hosted server. That number sounds abstract. In practice, consumption comes from many directions:
- Editor autocomplete and inline chat requests
- Scripts that batch-process files
- CI jobs that run AI-assisted review
- Manual experiments with prompts
Each request is small. The sum is not. Without a meter, the first sign of trouble is a 429 or a quota-exceeded error in the middle of a task.
A token meter in three parts
The meter has three components: a SQLite table for usage records, a wrapper around the OpenAI client, and a report function.
1. The storage layer
import sqlite3
import time
from pathlib import Path
DB_PATH = Path.home() / ".token_meter.db"
def init_db():
conn = sqlite3.connect(DB_PATH)
conn.execute("""
CREATE TABLE IF NOT EXISTS usage (
ts INTEGER PRIMARY KEY,
model TEXT,
prompt_tokens INTEGER,
completion_tokens INTEGER,
total_tokens INTEGER
)
""")
conn.commit()
return conn
2. The metered client
from openai import OpenAI
class MeteredClient:
def __init__(self, base_url, api_key, model):
self.client = OpenAI(base_url=base_url, api_key=api_key)
self.model = model
self.conn = init_db()
def chat(self, messages, **kwargs):
resp = self.client.chat.completions.create(
model=self.model,
messages=messages,
**kwargs
)
usage = resp.usage
self.conn.execute(
"INSERT INTO usage (ts, model, prompt_tokens, completion_tokens, total_tokens) VALUES (?, ?, ?, ?, ?)",
(int(time.time()), self.model, usage.prompt_tokens, usage.completion_tokens, usage.total_tokens)
)
self.conn.commit()
return resp
3. The report
def burn_rate(days=7):
conn = sqlite3.connect(DB_PATH)
cutoff = int(time.time()) - days * 86400
row = conn.execute(
"SELECT SUM(total_tokens), COUNT(*), MIN(ts), MAX(ts) FROM usage WHERE ts >= ?",
(cutoff,)
).fetchone()
total, count, first, last = row
if not total or not first or first == last:
return None
elapsed_days = (last - first) / 86400
return {
"total_tokens": total,
"requests": count,
"elapsed_days": round(elapsed_days, 2),
"tokens_per_day": int(total / elapsed_days),
}
def report(allowance):
rate = burn_rate()
if not rate:
print("No usage recorded yet.")
return
days_left = allowance / rate["tokens_per_day"]
print(f"Usage over {rate['elapsed_days']} days:")
print(f" Total tokens: {rate['total_tokens']:,}")
print(f" Requests: {rate['requests']}")
print(f" Burn rate: {rate['tokens_per_day']:,} tokens/day")
print(f" At this rate, {allowance:,} tokens last ~{days_left:.0f} days")
Wiring it into a workflow
Replace the direct client construction with the metered version. The interface is identical, so existing code keeps working.
client = MeteredClient(
base_url="https://your-server.example.com/v1",
api_key="none", # free tiers often ignore the key
model="model-id-from-docs"
)
resp = client.chat([
{"role": "user", "content": "Refactor this function to use async/await."}
])
print(resp.choices[0].message.content)
Check the report anytime:
python -c "from meter import report; report(10_000_000)"
The output shows the daily burn rate and a projected exhaustion date. Run it once a day, or add a cron job that emails the report when the projected days-left drops below a threshold.
Reading the numbers
Three patterns matter.
- Steady burn below 25% of the allowance per month. The free tier is a reasonable fit. Keep monitoring, but no action needed.
- Burn rate above 25% per month. The allowance will not last. Start evaluating paid APIs or self-hosting before the quota hits zero.
- Burn rate accelerating. Compare this week to last week. If the rate is climbing, the workload changed — a new script, a new editor plugin, a teammate joining the project. Find the source before it becomes a surprise.
Limitations
The meter only sees requests that go through the wrapped client. Editor extensions, other scripts, or CI jobs that call the API directly bypass the recording. A complete view requires integrating the meter into every entry point, or reading server-side usage logs if the provider exposes them.
The prediction is a linear extrapolation. Bursty workloads — a large refactor, a batch review of a pull request — can push actual consumption far above the forecast. Treat the meter as an early warning system, not a billing audit.
Who should not use this approach
- One-off experimenters. A single weekend of testing will not exhaust a 10-million-token allowance. The meter is overhead.
- Paid API users. No quota, no need for a meter.
- Teams that need exact billing. This tool is an approximation. It does not capture prompt caching, retries, or provider-side adjustments.
Conclusion
The quota problem on a free AI coding server is not the size of the allowance. It is the visibility. A thirty-line meter turns "how much is left" from a guess into a reading. Collect data for a few days, then decide whether the free tier, a paid API, or a self-hosted setup is the right host. The numbers decide; the meter just makes them visible.
MonkeyCode provides free models that can run this workflow.