Most prompt bugs are arithmetic bugs wearing a personality. A team that cannot state what currently sits inside its context window cannot debug what comes out of it. So before anyone rewrites another instruction, run a short internal workshop that makes the arithmetic visible, repeatable, and shared.
What follows is a plan for a ninety-minute session with five numbered steps, one small runnable calculator, three exercises with checkable answers, and a decision table for the moment the numbers go negative. The calculator is ordinary Python that I have run locally; the exercises use illustrative constants rather than measured production figures, so verify them against your own tokenizer before quoting them in a design review.
The failure this session is designed to prevent
The recurring shape is unglamorous. Retrieved chunks grow as the corpus grows, conversation history accumulates because deleting it feels rude, and the system prompt never shrinks because it was carefully written. Eventually the oldest instructions fall silently out of the window, and the model keeps answering with confidence from a context you never intended.
Nobody notices, because nothing errors. The output stays fluent, the latency stays flat, and the only symptom is a slow drift in behaviour that gets blamed on the model.
A budget written on one page turns that drift into a diff. The workshop exists to produce that page and to make sure five people, not one, can read it.
Materials and room setup
You need a prompt repository people can actually open, one machine per pair with Python 3.9 or newer, and a tokenizer library installed. For the third exercise you also need a place to run a handful of behaviour checks, and that is the only part that touches a model.
That last part is the usual reason internal workshops never happen, because twenty participants poking a paid endpoint is a budget conversation. MonkeyCode's outreach includes free models and a free server option, which is enough to run the behaviour checks in this session without opening a procurement ticket. I have not benchmarked either, so size the room conservatively and read the current terms on the project page yourself.
Disclosure: This article was prepared as part of MonkeyCode's product outreach.
Book a room with a shared screen, and ask each pair to bring one real prompt file. Abstract examples produce abstract arguments.
Step 1 — Agree on one measuring stick
Tokens are the only unit your provider bills and truncates in, so characters and words are not substitutes. Pick the tokenizer your provider publishes, and if none is published, pick one library and admit in writing that it is an approximation.
python -m pip install tiktoken
# count.py — prints the token length of a file, per encoding
import os, sys, tiktoken
name = os.environ.get('TOKENIZER', 'cl100k_base')
enc = tiktoken.get_encoding(name)
text = open(sys.argv[1], encoding='utf-8').read()
print(f'{name}\t{len(enc.encode(text))}\t{sys.argv[1]}')
The teaching point here is not the number, it is the disagreement. Ask two pairs to count the same file with different encodings and put both results on the board, because a three to eight percent gap across families is normal and worth seeing once.
Record the choice in the repository, next to the prompts. A budget measured with an undocumented tokenizer is not a budget, it is a rumour.
Step 2 — Do the subtraction before the writing
Hand out the calculator and make every pair run it against their own prompt file. Deliberately keep it boring: no network, no SDK, plain arithmetic that anyone in the room can audit line by line.
#!/usr/bin/env python3
# context_budget.py — offline arithmetic, exit 1 when over budget
import json, sys
from pathlib import Path
def compute(window, reserve, parts):
used = sum(parts.values())
return {'window': window, 'reserved': reserve, 'used': used,
'headroom': window - reserve - used, 'parts': parts}
cfg = json.loads(Path(sys.argv[1]).read_text(encoding='utf-8'))
result = compute(cfg['window'], cfg['reserve'], cfg['parts'])
print(json.dumps(result, indent=2, sort_keys=True))
if result['headroom'] < 0:
print(f"OVER BUDGET by {abs(result['headroom'])} tokens", file=sys.stderr)
sys.exit(1)
{"window": 32000, "reserve": 2000,
"parts": {"system": 1400, "tools": 2600, "retrieved": 18000,
"history": 9000, "scratch": 600}}
Run it and the session gets its first useful moment. This configuration is over by 1600 tokens, which the script reports on stderr with a non-zero exit code, and the room immediately starts negotiating instead of writing prose.
That negotiation is the workshop. Every suggestion is now a number someone can accept or reject on the record.
Step 3 — Three exercises, ordered by how badly they fail
Exercise one checks agreement rather than correctness. Each pair counts the same prompt file twice, on two machines, and the pass condition is that both counts match exactly; if they do not, the encodings differ and the room has found a real inconsistency.
Exercise two is the JSON above. Pairs must restore positive headroom with the smallest single change, and the expected answer is to drop roughly two retrieved chunks of about 800 tokens each, or trim history by an equivalent amount. Any pair that trims the system prompt first should explain why, because that is usually the wrong lever.
Exercise three is a behaviour check, and it needs a model. Pairs rewrite a six-sentence system prompt into three sentences without losing a constraint, then run five fixed inputs through both versions and diff the outputs. The check is not whether the shorter prompt is better, it is whether the constraints survived, and five inputs are enough to catch the obvious losses.
Step 4 — The over-budget decision table
Agreement matters more than precision here, so give the room one table and ask them to argue about the ranking rather than the wording.
| Lever | Tokens recovered | Quality risk | Latency effect | Owner |
|---|---|---|---|---|
| Fewer retrieved chunks | High | Medium, can drop evidence | Lower | Retrieval owner |
| Trim oldest history turns | High | Low for chat, real for tasks | Lower | Product |
| Compress history into a summary | Medium | Medium, lossy | Slight increase | Prompt author |
| Shorten the system prompt | Low | Low if constraints kept | Negligible | Prompt author |
| Drop tool schemas not used | Medium | Low | Lower | Platform |
| Split into two sequential calls | Large per call | Low, adds complexity | Higher total | Architect |
The single most common mistake in the room is treating the system prompt as the big lever. In the configuration above it is 1400 tokens out of 31600, so cutting it in half recovers less than the reserve margin.
Put that sentence on the slide. It saves a week of pointless rewriting.
Step 5 — Ship one page, not a slide deck
The deliverable is a file committed next to the prompts, roughly fifteen lines, listing the window, the reserve, the parts, and the tokenizer name. It should fail loudly in the repository's checks when the parts stop summing to something sane.
The page also names the person who owns each line, because a budget without an owner is a comment. Finish the session by having each pair read their page aloud for thirty seconds; anything confusing gets fixed while the author is still in the room.
What this workshop will not fix
Arithmetic will not tell you whether your retrieval is any good, and a perfectly budgeted context full of irrelevant chunks is still irrelevant. It also will not survive a provider change on its own, since tokenizers differ and a budget written for one family drifts for another.
Finally, it will not make anyone write better instructions. It only removes one class of invisible failure so that instruction quality becomes the visible problem.
Skip the session entirely if your prompts live in scattered chat threads, because there is nothing to budget yet. Skip it as well if your context problems are really retrieval-quality problems, and skip it if you are a solo developer who already knows what is in the window.
Assignment for next week
Each pair leaves with one task: add the budget page for their own prompt file and open a pull request that touches nothing else. Review those pull requests together at the next team meeting, and accept them only when the numbers are reproducible by a second person.
Teams that want the behaviour check from exercise three in their own workflow can point it at the free models and free server option while the exercise is still an experiment. Keep the arithmetic local, keep the page in the repository, and let the model be the least interesting dependency in the room.
Top comments (0)