kitbash / benchmark
#The standing token tax, measured
Every agent that cannot lazy-load carries a skill's entire body in context every session, before the skill is ever invoked. No other skill format has a field for that cost. Kitbash measures it at compile time — these are the numbers, generated by the benchmark script from committed fixtures run through the real compile pipeline.
kitbash compile#What is measured
Two costs matter, and conflating them is how the expensive one stays invisible:
- Loaded — tokens the agent reads when the skill is actually in play. Roughly the same everywhere; this is the number people assume they are paying.
- Standing — tokens sitting in the context window every session, before the skill is invoked. Lazy targets keep only a short stub. Eager targets keep the whole body. This is the number nobody measures.
Token counts are estimates at roughly four characters per token — the same estimator the compiler enforces context.budget and context.standing with, so the benchmark and the build agree by construction. Loading modes are read from the adapters themselves, not restated here, so these tables cannot drift from what the compiler emits.
Kitbash compiles to the cheapest loading mode each target actually supports. Claude Code, Cursor, Copilot, Devin (ex-Windsurf), Gemini CLI and the vendor-neutral .agents/skills/ path all load on demand, so a skill there costs only its stub. What the tables below price is the rest: Cline, Aider and the AGENTS.md floor, whose only mode is eager — they carry the whole body, every session, before the skill is invoked.
#prereview — manifested, budget 1500, authored lazy
The first-party example skill, compiled to all nine targets.
| Target | Loaded (tok) | Standing (tok) | Loading |
|---|---|---|---|
claude-code | 567 | 40 | lazy |
cursor | 568 | 40 | lazy |
agents | 567 | 40 | lazy |
copilot | 567 | 40 | lazy |
cline | 539 | 539 | eager |
windsurf | 569 | 40 | lazy |
gemini | 567 | 40 | lazy |
aider | 560 | 560 | eager |
agentsmd | 560 | 560 | eager |
Standing tax: about 40 tokens on a lazy target against about 539 on an eager one — roughly 13× per session for the identical skill. A team running four agents pays that gap four times over, forever, unless something measures it.
#review-checklist — bare, no manifest
A plain SKILL.md folder following the skills.sh / Claude Skills convention. Longer body, no declared budget — the gap widens.
| Target | Loaded (tok) | Standing (tok) | Loading |
|---|---|---|---|
claude-code | 880 | 19 | lazy |
cursor | 879 | 19 | lazy |
agents | 880 | 19 | lazy |
copilot | 880 | 19 | lazy |
cline | 859 | 859 | eager |
windsurf | 881 | 19 | lazy |
gemini | 880 | 19 | lazy |
aider | 885 | 885 | eager |
agentsmd | 885 | 885 | eager |
Standing tax: about 19 tokens on a lazy target against about 859 on an eager one — roughly 45× per session. The longer the skill, the worse the ratio, because the lazy stub stays small while the eager copy grows with the body.
#What the compiler does with it
Measuring is only useful if something acts on the measurement. At compile time Kitbash:
- warns when a skill authored
lazylands on an eager target, naming the standing cost and the declared limit; - fails the build under
--strict, so the warning can gate CI instead of scrolling past; - enforces
context.budgetagainst the compiled body andcontext.standingagainst the stub, per target; - reports the whole repo's standing cost in
kitbash doctor, so the total is visible before it is a problem.
The copy-per-agent status quo pays the eager cost everywhere and never sees the number.
#Reproduce it
The table above is generated, committed, and re-checked in CI — if a change to any adapter moves a number and the committed results are not regenerated, the build fails.
git clone https://github.com/singhharsh1708/kitbash
cd kitbash/packages/cli && npm install
npm run bench
#Honest caveats
- Token counts are a four-characters-per-token estimate, not a model-specific tokenizer. Real counts vary by a few percent per model; the ratio between lazy and eager is what the argument rests on, and that ratio is robust.
- Only two fixtures are measured. They differ in size and manifest status on purpose, but they are not a survey of every skill anyone will write.
- This measures what the format costs, not what the model does with it. A cheap skill that gives bad instructions is still a bad skill — that is what
kitbash testandkitbash lintare for. - The standing figure is a floor. It counts one skill. Install ten and an eager agent carries all ten bodies at once.