essay
The AI Token Efficiency of Brass
What forty coding sessions tell us about language, tooling and cost
When an AI model changes a program, it spends tokens reading the code, working out what to change and writing the result. Brass is a new language built around that process, with models writing the code and people reviewing it. Its function declarations say what a function may do and what it promises. The full checker rejects code that breaks those declarations; the brass tool in these runs checks a program’s structure, runs its examples and helps the model find its way around the code. These trials ask whether it makes the work cheaper.
The trials were 40 sessions on 19 October 2026, all with the same model, Claude Sonnet. In each one, the model was handed a working expense-report system and asked to add one feature. It read the code, made the change and decided for itself when it was finished. The system exists twice, once written in Brass and once in Python, so both languages faced the same job. There were two features to add: cash advances, attempted 30 times, and trip plans, attempted 10 times. When a session ended, its program was run against a set of test cases the model never saw. Both languages were scored against the same cases, so a pass means the same thing in each.
Brass needed fewer rounds with the model. It used a third to half as many model calls as Python, and its average bill was 14 to 24 percent lower, depending on the task and codebase size. The model spent more tokens on reasoning, but was sent less than half as much text over a session. That total includes the conversation sent again on every call; it does not mean the model opened half as much source code.
Here, Brass means the language and its tooling together. Thirteen of its 15 sessions passed every task test; Python passed them all in 15 of 15. The other ten sessions used the Brass language with ordinary file tools only. That setup was more expensive than Python on cash advances, the only task it ran.
The trials at a glance
The program. Every trial used an expense-report system. Staff submit reports, and the amount decides who must approve them. The system checks budgets, pays approved reports and records every action in an audit trail. Cash advances were tested on two versions of the program, the larger about 2.5 times the size of the smaller.
The tasks. Each session added one of two features. Both needed changes across several parts of the program.
| Task | The change | Starting code |
|---|---|---|
| Cash advances | Let staff receive cash before a trip, then settle it against an expense report. Use the report approval rules for advances too. | Small: 448 lines of Brass, 514 of Python. Larger: 1,121 lines of Brass, 1,211 of Python. |
| Trip plans | Let staff submit a travel plan for approval, amend it, reconcile it with actual spending and close it. | The cash-advance program, with that feature added: 1,331 lines of Brass, 1,398 of Python. |
The larger codebase adds eleven subsystems a real expense desk acquires, such as corporate cards, vendors and forecasting, as new files only. The code the task changes is the same in both, so the difference is how much unrelated code the model has to find its way around.
Trip plans was written after the tooling was finished, to try it on work the tooling was not designed around. It had been used once before, in an earlier trial.
The setups. Brass was tested as a complete workflow: the language plus its tooling, which helps an AI model find its way around the code and change it. The tooling is the brass command, a project map and a host contract. On these pages, Brass means that whole package. The language also ran with ordinary file tools only, to see how much the tooling contributed. Cash advances compared three setups:
- Python, with ordinary tools for reading and editing files.
- Brass, lang. only, with the same file tools.
- Brass: the same file tools, plus the project map, the host contract and
brass, which can show declarations from several modules in one call and check a patch before writing it.
Python had ordinary file tools only, with no map. An earlier test that gave Python a similar tool and module map closed most of the reading gap, so part of what Brass saves here comes from its tooling, not the language alone.
Trip plans compared Python with Brass; the language-only setup didn’t run on that task.
A session is one attempt at a task, starting from the supplied program. Each combination of task, setup and codebase size got five sessions: 30 for cash advances and 10 for trip plans. Sessions with brass were asked to make their edits through it, but could still edit files directly.
How context piles up, turn by turn
Each call sends the model the conversation so far: instructions, code, tool replies and earlier responses. A later call therefore includes much of what the model has already received, plus whatever happened since. That repeated text is part of the token bill.
Here, a turn means one call to the model. It can request several tool actions, such as opening three files at once.
The lines show that running total for the ten sessions. Python finished after 31 to 60 turns; Brass finished after 14 to 28. Fewer turns meant fewer times the growing conversation was sent again.
The ten lines are the cash-advance sessions on the larger codebase: five Python and five Brass, numbered 1 to 5 within each setup. Each line ends with its session number and total input. The same sessions appear in Every tool call, in order, further down; The numbers, at the end, lists all 40.
A note on color. In the charts, Python is red, Brass is deep bluedeep green, and Brass, lang. only is light bluelight green. In Every tool call, in order, colors mean actions instead: reading, editing or checking. A red block there is an edit, whichever language the session used.
One session from each side, turn by turn
Session 4 from each setup shows how the work unfolded. Both spent seven turns reading. On turn 8, each produced its largest block of output, mostly reasoning about the change.
Python began editing the project during that turn. Brass began drafting a patch, submitted it on turn 11 and finished on turn 14. Python continued editing individual files, then wrote and ran tests before finishing on turn 32. Each additional turn carried the conversation forward again.
Both programs passed every test; the Brass session cost $1.23, the Python session $1.51.
In the chart, the context sent appears above the line and output below it. Output includes hidden reasoning, replies and tool requests. It is drawn three times taller, so that a 10k-token output remains visible beside 100k tokens of context.
What happens to context as the codebase grows
A larger program means more to read, so every setup was sent more text on the codebase 2.5 times the size. The chart shows how much more. Each line joins a setup's average total input on the small codebase to its average on the larger one, five sessions at each size.
Brass grew the most in percentage terms, 75 percent against Python's 46, because it started from the lowest total. Even on the larger codebase, it was sent less than half as much text as Python.
Every session on four measures
The averages hide how much attempts varied. These panels show every session on four measures: total input, model calls, reasoning tokens and cost.
Each row groups one setup on one task and codebase size. A dot represents a session. The upright mark shows the row’s average, also printed on the right. Further left means fewer tokens, fewer calls or a lower bill.
Reasoning tokens count the model’s hidden working and are billed as output. Cost is the reported session bill.
Every tool call, in order
These rows show what the ten larger-codebase sessions actually did: gather code, make changes and check their work. Each block is one tool action, in the order requested. Several blocks can belong to the same model turn.
Green blocks retrieve code through brass. Purple blocks apply or check a patch: dark for apply, light for check. Red blocks edit a project file directly; orange blocks run Python tests.
Gray blocks read or search with ordinary file tools such as Read, Grep and cat. The palest blocks work on temporary files, including draft patches and test scripts.
brass: declarationsbrass: whole filesread one filesearchbrass apply: every edit, checked firstedit one filewrite a scratch filebrass checkrun Python testsEach row is one session, and the number at its end is the session’s total tool actions. The marker on the first row of each group points to the session’s first apply (Brass) or first direct edit (Python).
The Brass sessions gathered declarations and whole files, then submitted changes through apply, sometimes in more than one attempt. Session 5 also edited a file directly. Python sessions opened files individually, often requesting several in one turn, then edited them and ran tests. Both the number of actions and the way they were grouped affected the number of model calls.
How the Brass sessions used their built-in tooling
Across the fifteen Brass sessions, the model called brass 129 times. Most calls fetched code. This table separates those reads from the calls that applied or checked changes.
| Command | What it does | Calls | Total reply size |
|---|---|---|---|
info | shows where a declaration is used and how | 6 | 45k chars |
show | lists every module, its declarations and imports | 16 | 45k chars |
show names | retrieves the named modules’ declarations and contracts | 9 | 77k chars |
show --body | retrieves whole files: four modules per call on average, up to eight | 59 | 561k chars |
apply | check a patch, then write all of it or none | 20 | 62k chars |
check | checks the current project without applying a patch | 19 | 48k chars |
Counts and reply sizes come from the brass log; each bar is scaled to the largest value in its column. For scale, 9,000 characters is roughly 2,500 tokens, though the ratio depends on the text.
apply and check return results rather than code. An apply reply says what was written, or why the patch was rejected. A check reply lists the problems it found, if any.
Reading. Sessions typically gathered code in about five show calls, starting with the index and then fetching declarations or files in batches. A reply could contain several related modules. Whole files from show --body accounted for about two thirds of the text returned. The other reading commands together returned less than a third as much as show --body. Python sessions also requested several file reads in a single turn, so reading alone does not explain the gap in turns. On cash advances, most of the difference in turn count came after the first edit. On trip plans, however, four of the five Python sessions read one file per turn for about 30 turns. info appeared in five sessions. No session used show --for; the model mostly asked for declarations and whole files.
Writing. Of the 20 apply calls, 17 wrote their patch. One was refused before checking started, because a block was left unclosed. Two more failed the check: one supplied an argument to a function that took none; the other supplied two arguments where five were required. Each mistake was corrected on the next attempt. The rejected patches changed no project files. check catches mistakes such as calls that don’t match their declarations. Whether a program does what the task asks is a different question, and the hidden tests answer it: they found failures in programs that passed check.
Direct edits. Ten of the fifteen sessions made all project edits through apply. Two mixed it with direct edits. Three used the ordinary editor throughout and ran check afterwards.
| Sessions | Cash advances, small | Cash advances, larger | Trip plans |
|---|---|---|---|
Wrote only through apply | 3 | 4 | 3 |
Used apply and also edited a file directly | 0 | 1 | 1 |
Never used apply | 2 | 0 | 1 |
Every session that edited directly ended with a clean check and passed every hidden test. Reviewers later found two Brass rule violations in directly edited files. They found neither in patches submitted through apply, but that does not establish that apply would have caught them: it runs the same check.
What each session paid for
Tokens have different prices, so sending less text does not reduce every part of the bill equally. These panels split the average cash-advance bill into cached input, new text written to the cache and output. Each panel shows the three setups, averaged across both codebase sizes.
Brass saved mostly on cached input, the cheapest part of the bill. It spent more on output, most of it reasoning. The input saving still outweighed that extra expense: the average bill was about a fifth lower on cash advances and about a seventh lower on trip plans.
Familiarity may explain some of the extra reasoning. Python gives the model patterns it has encountered before; Brass asks it to work through new rules. These runs do not isolate that cause. The next test will settle more recurring language questions and measure whether reasoning falls.
Hidden reasoning, task by task
Brass used more reasoning tokens on both tasks. The language-only sessions showed the same pattern on cash advances. Each point in this chart is a setup’s average: first cash advances at the two codebase sizes, then trip plans.
The language-only line stops at cash advances. That setup was a directional check, and it had already shown higher token use than Brass with its tooling, so it was not carried on to trip plans.
Brass used about 1.4 to 1.8 times as many reasoning tokens as Python, with the largest difference in token count on trip plans. This identifies where the extra output went, but not which language rules caused it.
Cost against the size of the change
The trip-plan feature requires more code changes than cash advances. To compare the bills against that size, this chart uses a reference solution for each task and language. Every session on the same task and language gets the same horizontal position; it does not represent the size of that session’s own patch.
Each dot is a session, with higher cost plotted upwards. Filled dots show cash advances and open dots show trip plans. The reference changes count added and removed lines, including new files: 231 lines of Brass and 213 of Python for cash advances, and 326 and 278 for trip plans.
Dividing each bill by its reference change size gives an average of 0.55 cents per line for Brass, 0.76 for Python and 0.82 for the language-only setup. The last of those covers cash advances only. Lines describe the amount of code in a change; they do not measure its difficulty.
What a careful read found that the tests missed
After the runs, eight Claude Opus 5.5 agents reviewed five finished programs each. They checked Brass rules and task requirements that the behavioral tests could miss.
Each reviewer received the task, a checklist, the language spec and the starting code. Programs had random-number labels. Costs, test scores and setup labels were withheld until all reviews were complete, although the code still revealed whether a program was Python or Brass.
| Sessions that | Python | Brass, lang. only | Brass |
|---|---|---|---|
| passed every test case | 15 of 15 | 10 of 10 | 13 of 15 |
| broke none of the Brass rules on the review checklist | n/a | 9 of 10 | 15 of 15 |
| met the written requirements on the review checklist | 15 of 15 | 9 of 10 | 15 of 15 |
The checklist rows do not cover every possible defect. Reviewers also reported problems outside them, including two Brass rule violations that do not appear in those totals.
- A state from the wrong workflow. One language-only session built a statement row for a cash advance using an expense-report state. Every hidden test passed, but the code broke a Brass rule.
- Different answers to an unstated question. Reconciling a trip plan records what was actually spent. Repeating it should add an audit entry only if the result changes. All five Python programs compared the whole result, including the identities of the card transactions counted. The Brass programs compared selected fields and left those identities out. If the transactions changed but the fields being compared stayed the same, no new audit entry was written. The task did not define which fields counted as a changed result, so the audit difference was reported without changing the checklist score. One Brass program also skipped saving the updated result, leaving the old transaction list in place.
- Two mistakes
brassaccepted. The reviewers found a reserved keyword used as a name, and an outside-service declaration written twice. Both break Brass rules, and both passedcheck. One session edited entirely withoutapply; the other mixedapplywith direct edits.
What this shows
- Correctness held up. Working from a 3,300-word language reference and no prior exposure to Brass, the model passed 1,621 of 1,625 test executions, and 13 of 15 sessions passed every case. In Python, a language it knows deeply, it passed all 1,625 and all 15. The four misses came from two Brass sessions, two cases each. The same cases were run repeatedly across sessions.
- Brass cost less in these runs. Its average bill was 14 to 24 percent below Python's, depending on the task and codebase size. Brass used roughly one model call for every two or three Python needed, and less than half as much total input.
- The tooling contributed to the saving. Language-only sessions used more input than Python and cost the most on cash advances. This run did not give Python equivalent tooling. An earlier trial did and closed most of the gap in total input.
- Brass used more reasoning tokens. The model spent about 1.4 to 1.8 times as many as it did on Python. In an earlier trial, settling one open language question cut reasoning by nearly a third; whether settling the rest closes the gap is the next test.
- The scope is narrow. Five sessions per task, setup and size, one model, and two tasks on one program. Both tasks were written for these trials, and trip plans had been used in an earlier one. The results describe these runs; they do not show how the languages compare on other work.
The numbers
Calls, input, reasoning and cost are averages per session. Tests passed are totals across the five sessions. Reference lines changed counts additions and removals in the reference solution, including new files. M means million tokens; k means thousand.
All 40 sessions ran on 19 October 2026: 30 on cash advances, then 10 on trip plans. An earlier attempt at the trip-plan run was stopped partway; these results cover the completed runs. The model was claude-sonnet-5 at high effort, in Claude Code 2.1.302. Each session started separately, outside the repository, with a clean environment. All setups had ordinary file tools. Brass also received brass, the project map and the host contract. Costs are the reported bills through the end of each session, not the cost of repairing every failed result. Each panel of the bill-breakdown chart prints its rate. Frozen inputs, transcripts and reviews are in the repository’s tools-and-testing/snapshot-20261019/ folder.
Closing thoughts
In these forty sessions, Brass used fewer calls and cost less than Python, in a language the model had never seen, and the price was more reasoning. The next step is to make Brass run: the full checker, then a compiled runtime. A model will then compile its change, get an exact answer, proven or what is still missing, and run the result. That is the test that shows whether Brass makes a correct change less work, and which parts of the language still make it harder than it needs to be.
FAQ
How can Brass cost less while using more reasoning tokens?
Reasoning is only one part of the bill. Brass sessions finished in fewer calls, so the growing conversation was sent back to the model fewer times. The savings on repeated input outweighed the extra reasoning cost.
Does token efficiency mean writing shorter code?
No. The reference solutions in Brass changed more lines than their Python equivalents. The savings came from how the model worked through the change, not from producing a smaller program. Explicit declarations can add code while making its requirements easier to find.
Could the same approach help models working in other languages?
Yes. An earlier trial gave Python the same kind of tool and project map. Python then read far less, closing most of the gap with Brass. The tool did two simple things: it showed every module without its function bodies, and it applied a batch of edits in one go. Any language could do both.
What would a full checker and runtime add?
The current tool already checks program structure, catches mistakes such as calls that don’t match their declarations, and runs examples. A full checker would also prove that function bodies keep their declared promises. Together with a compiled runtime, that would let the model check and run its changes as it works, and make it possible to measure the cost through a working result, including repairs.
This page reports the trials behind Brass v0.3. It’s a record, shared for feedback. Until 2026-10-10 the language was called Keel and its tool keelc; the earlier trials ran under those names. The language itself is introduced in Welcome to Brass Language.