Why We Have AI Write YAML Instead of Code
Our examples folder has eight apps in it. This week we ran a line count across all of them, source on one side and generated application on the other, because we had been repeating a claim for months in conversations without once checking the number behind it.
The claim was that describing an app costs a fraction of building one. That is the sort of thing that sounds true and often is not.
The count
Source is Cord, our YAML format. The second column is what that app costs to exist starting from an empty folder: the C# and Vue generated for the app itself, plus the runtime underneath it. Both columns are tokens rather than lines, counted on Anthropic's own tokeniser, because tokens are the thing you actually pay for. The last column is what the difference would cost to write at today's Claude Opus 5 output price.
| app | source | from scratch | tokens skipped | not spent |
|---|---|---|---|---|
| expenses | 3,245 | 204,551 | ~98.4% | ~€4.34 |
| task manager | 5,825 | 313,519 | ~98.1% | ~€6.63 |
| crm | 14,570 | 377,295 | ~96.1% | ~€7.82 |
| time and leave | 45,425 | 495,013 | ~90.8% | ~€9.69 |
| budget planner | 45,296 | 483,818 | ~90.6% | ~€9.45 |
Prices are Anthropic's published rates on 3 September 2026: Claude Opus 5 at $25 per million output tokens, converted at 1 USD to 0.8624 EUR that day. The token counts are measured rather than estimated. Every file above went through Anthropic's own count_tokens endpoint, each app separately and the runtime once. The euro column counts output tokens only, so it is a floor: one clean pass, nothing re-read, nothing retried.
So the claim survives, and by more than we had been claiming. Expenses is sixty three to one. The task manager is fifty four to one.
We nearly published that column with the runtime left out of it, counting only the domain model and each app's own code, on the grounds that nobody generates a runtime per app.
Which is true of Cordango and false of everything else. An agent starting from an empty folder does not get a runtime as a package, because there is no package. It writes the identity handling, the record access, the permission checks and the audit trail into that app. Then it writes them again into the next app, because the next app is another empty folder. Those 8,152 lines are 141,596 tokens on Anthropic's own tokeniser, and they get shared exactly once, by us. That sharing is the entire product. Leaving them out understated the small apps by nearly a factor of three.
Would a model really write all 8,152 of them? Not on the first pass, no. It would write a thinner version, skip the audit log because nobody asked for one, and put a permission check in a Vue component where anyone can walk around it. That is the same comparison with a worse app at the end of it.
(We ran the count twice. The first pass swept in node_modules and told us the CRM was 1.3 million lines, which would have made a much better headline and a completely false one.)
What the model never writes
Open the generated budget planner and the folders under api/ are Identity, Migrations, Controllers, Data, Security, Seed, Hooks, Computed, Commands, Workflows and Resources. Nobody described any of those. They are the same shape in all eight apps because they come from the same compiler.
Migrations/00000000000001_InitialCreate.Designer.cs alone is 2,126 lines. It is completely uninteresting, it has to be exactly right, and no human is going to read it.
Here is the whole of what the source says about who a finance planner is:
role: planner
name: Finance Planner
description: Builds and maintains the plan but cannot archive
scenarios or change app settings.
grants:
hiring_line:
create: true
read: true
update: true
delete: true
commands:
- approve_hire
- open_recruiting
- mark_filled
That compiles into roles on the server, per-entity checks in the controllers, and a UI that does not offer buttons the user cannot press. On the platform it does not compile into anything at all, because identity and permissions are already there before the app exists.
We have an opinion about this that we will defend. An agent that writes the authorisation code also owns every bug in it, forever, and nobody is reviewing 27,000 lines of generated C# line by line. Pretending otherwise is how you end up with a permission check that lives in a Vue component. The industry keeps measuring AI coding tools by how much code they produce, which is roughly like measuring a builder by how much concrete they pour.
We had the shape of this backwards
Look at the table again and the ratio does not hold steady. It collapses.
Task manager: 5,825 tokens of source, 313,519 from scratch, fifty four to one. Budget planner: 45,296 and 483,818, closer to eleven to one. Nearly eight times the source and only 1.5 times the application.
We assumed a bigger app would save more. It saves less, and the reason is obvious once you see it. Most of the budget planner's source is not structure at all, it is arithmetic that nobody could have guessed for us:
loaded_cost_per_head:
type: money
currency: EUR
calculate:
expression: gross_salary * (1 + employer_cost_rate / 100)
+ other_cost_per_head
With a default of 21 for employer_cost_rate, because that is roughly what German employer social contributions add on top of gross. That line is the actual work. No format was ever going to make it shorter, and we would be worried if it did.
So the honest version of our claim is narrower than the one we had been making. The scaffolding cost goes to nearly nothing. The domain cost stays exactly where it was. What changes is the ratio between them.
The tokens are the smaller half
Look at the euro column again, because it is the least impressive number in this post. Nine euros and forty five cents on the biggest app. That is what four hundred and thirty eight thousand skipped tokens are worth if you only count the writing.
We could have left that column out. It undersells us. But output tokens are the cheap part, and quoting the flattering half of a measurement is how you end up with a number somebody disproves in an afternoon.
The expensive part of an agent writing an application is everything that is not writing. Reading files back to remember what it did. Running the build. Reading the compiler output. Finding the type error. Re-reading three files to fix it. Running the build again. That loop runs over the 483,818 tokens, not over the 45,296, and it runs many times.
With Cord there is no codebase to hold in context, because the codebase does not exist yet. There is a short document and one command that answers with a diagnostic and the exact path in the file that caused it. When we handed ChatGPT the command line last month it needed four rounds of that loop, on a subscription, with no repository to chew through.
That is the part we would point at. Not that the model types less. That the model is only ever reasoning about the domain, because the parts that are the same in every business app were moved out of its way and into a compiler that gets them right the same way every time.
The same app twice
Both columns in that table describe the same app. Same intent, same screens, near enough the same behaviour. What differs is everything underneath, and it differs again every time you ask.
Ask a model for an expenses app twice and you get two applications. Both plausible. Different file layout, different names, a different opinion about where the permission check belongs, and a bug in one that is not in the other. Nothing was specified differently between the two runs. The model took a different path through the same request, which is what sampling is.
cordango build is not sampling. Same definition, same output, byte for byte, and there is a test suite that does nothing else. Two_runs_produce_byte_identical_trees hands the generator the same files in a different order and fingerprints both trees. The_build_metadata_carries_no_clock_and_no_machine searches the build record for a timestamp, the current year, the machine name and the temp path, and fails if it finds any of them, because a build record with a clock in it is a build record that never matches twice.
That is worth more than it sounds. A diff between two builds shows what you changed and nothing else. The thing that passed review in March is the thing running in September. Somebody can regenerate the app on a different laptop and get your app rather than a cousin of it.
We are not claiming this makes an app correct. A wrong definition compiles into a wrong app very reliably. The claim is narrower than that. The layer nobody reads should not be a fresh draft every time, and when a model writes the code it always is.
Where this does not help
If you are working inside a large existing codebase, use a coding agent. Cord has nothing to offer you there and we are not going to pretend it does.
If your app needs a screen shape the format cannot express, the generator stops and tells you the code rather than quietly building you something smaller than you asked for. That is the right behaviour and it is still a wall. Our targets list is honest about what it will not build.
And the whole toolchain is pre-alpha. It works end to end and none of it is stable.
Try the count yourself
The numbers above are reproducible in about a minute. Install the CLI, run cordango new and describe something small you actually need, then cordango build and count what came out.
The one we are curious about is an app with genuinely awkward rules, the kind with an exception that only three people in your company know about. Our examples are all reasonable apps. Reasonable apps are not the ones that eat six weeks of an internal project. If you build an unreasonable one and the compiler refuses, send us the diagnostic code, because that list is how we decide what to do next.
See Cordango in your own company
The fastest way to understand it is to watch it stand up a company and add an app live.
Book a demo →