ponytail: less code, better code?
Agent Report
- Tool
- ponytail (76.5k ★)
- Type
- Critique
- Context
- full-stack-fastapi-template (medium) + Django (large, 522k LOC) — 4 A/B tasks, strong model
- Cost
- 8 agent sessions (baseline vs. ruleset); LOC measured with git diff
ponytail has been trending on GitHub for days: 76.5k stars, a
perfect tagline ("says nothing, writes one line, it works") and a
concrete promise — that your AI agent writes ~54% less code (up to
94%), ~20% cheaper, 100% safe. It's a plugin that injects a ruleset
—a "laziness ladder"— into 16+ agents (Claude Code, Cursor, Codex…): before
writing any code, the agent stops at the first rung that holds — does it need
to exist? does it already live in the repo? does the stdlib do it? a native
feature? an already-installed dependency? does it fit in one line? — and only
then writes the minimum.
The rare part: its benchmark is honest
Almost every viral project inflates its numbers. ponytail does the opposite. Its benchmark admits the original "80-94% less code" figure was inflated by a chatty baseline (flagged by Colin Eberhardt in #126), found and published a contamination bug in its own measurement (a hook that fired ponytail on the baseline too), rebuilt the test to be able to disprove itself, and corrected the figure to a defensible -54% agentic number, showing where it does not win. It's the opposite of the norm. There's no "gotcha" to make here.
But that benchmark has limits they list themselves: one model
(Haiku 4.5, small, which over-builds more and needs more hand-holding),
one medium template repo
(full-stack-fastapi-template) and greenfield feature
tickets where the headline trick —"a 404-line date picker →
<input type="date">"— dominates the average. Their own
table already shows backend CRUD converging to ~0%. That's where this study
comes in.
What I tested that they didn't
Their limits are my test: a strong model (not Haiku), a genuinely large, mature repo (Django, 522k lines of Python, 7,072 files) and harder axes than adding a widget — reusing a helper that already exists in a huge codebase, writing a fresh utility, and an "irreducible" task. A long trace, not two examples.
Method (theirs, extended): A/B of the same agent with
ponytail's ruleset injected vs. without it (baseline = the agent
doing the job properly, not a chatty model — the fair correction they made
themselves). Four real tickets against real repos, each arm in its own copy of
the repo, LOC measured as git diff added lines — their own metric.
Task 1 — the color picker (medium, over-build)
Ticket: "add a color picker to the item form." This is their signature task type. Result: baseline 168 lines, ponytail 41 — a -76% cut. But the detail matters: neither installed a library. Both went straight to the browser's native input:
<FormField
control={form.control}
name="color"
render={({ field }) => (
<FormItem>
<FormLabel>Color</FormLabel>
<FormControl>
<Input type="color" className="h-9 w-16 p-1" {...field} />
</FormControl>
</FormItem>
)}
/>
On a strong model, the "install flatpickr and build a wrapper component" trap
—the source of the -94% on Haiku— barely fires: the baseline
also used <input type="color">. So where did the -76% come
from? From scope. The baseline threaded the color end to end:
backend model, Alembic migration, a table column, hex validation, a text field
alongside the swatch. ponytail did only the frontend form — and the
color is never stored in the database (its own report admits it:
"backend out of the ticket's scope"). The ticket was ambiguous; ponytail took
the narrowest reading. Cleaner, yes — but the cut left a real gap.
Task 2 — reuse in 522k lines (Django, the hard claim)
Rung 2 ("already in the codebase? reuse it") is easy to write in a ruleset and
hard to honor: it requires the agent to find the helper in a huge
repo. Ticket: "a title_to_slug function that turns a title into a
slug." Django has django.utils.text.slugify buried among 522k
lines. Does it find it?
Yes — and it works. ponytail located it and wrote a one-line wrapper:
from django.utils.text import slugify
def title_to_slug(title):
"""
>>> title_to_slug("Hello, World!")
'hello-world'
"""
# ponytail: django.utils.text.slugify already does the work; just wrap it.
return slugify(title)
baseline 18 lines, ponytail 10 (-44%). But here's the nuance:
the baseline reused slugify too. The important
decision —don't reinvent the slug with a regex— was made by both. ponytail's
cut was ceremony (module docstring + __main__
block vs. one-liner + doctest), not a smarter decision. A competent agent
already climbs to rung 2 unprompted.
Task 3 — a fresh utility in the large repo
Ticket: a retry function with exponential backoff. There's no
public retry in Django or the stdlib, so both write it from scratch — fertile
ground to over-build (a configurable decorator? jitter? a policy class?).
Result: baseline 43, ponytail 32 (-26%). They nearly
converge. Neither over-built: both wrote a lean function with stdlib
time.sleep and left a runnable check. The real difference:
def retry(fn, attempts=3, base_delay=0.1):
if attempts < 1:
raise ValueError("attempts must be at least 1.") # baseline added this
...
The baseline added an input-validation guard (attempts < 1)
that ponytail skipped. Ironic: ponytail's own ruleset says
"not lazy about input validation at trust boundaries." Here, part of ponytail's
cut was exactly that guard.
Task 4 — the "trivial" endpoint
Ticket: "an endpoint that returns how many items the current user has." I
expected convergence (it's CRUD). It was the opposite: baseline
71 lines, ponytail 12 — a
-83% cut. ponytail wrote a clean endpoint, reused the existing
count query, and even ordered the route correctly (/count before
/{id}, a real routing detail). But:
Endpoint + a typed response model (OwnedItemsCount) + 3 tests: counts 0→3, does not count other users’ items, requires auth.
Endpoint returning a bare dict. No typed model, no test at all.
ponytail returned an untyped dict —breaking the typed-response
convention that all the rest of the repo uses (its own rung 2)— and
left no test, even though its rule says "non-trivial logic
leaves ONE runnable check." It judged the endpoint trivial. The baseline wrote
three tests that verify real things (that it doesn't count other users' items,
that it requires authentication). Did the baseline over-test, or did ponytail
under-test? Reasonable people differ — but the -83% cut wasn't bloat, it was
coverage and types.
The pattern
Mean of the four cuts: ~57% — almost exactly their -54%, even on a strong model and a large repo. The LOC number reproduces. What changes is where the cut comes from:
This is not a verdict against it. ponytail never wrote more
(its core claim holds), reused well in every case —including finding
slugify in half a million lines— and its team is one of the few
that measures honestly. But "less code" is not automatically "better code": on
a capable model the gain is modest and sometimes cuts scope, tests or a guard.
What others already knew
It's not just my measurement. An independent benchmark
(#236,
KuldeepB19: 480 builds, 24 jobs, Claude Opus 4.8, four levels)
found ~44% less code with no general loss of correctness or
security — but a real robustness cost on 5 jobs with unstated
edge-cases: "one build crashed on bad input where the plain version
handled it fine," and the ultra level degrades instead of
improving. It matches exactly what I saw: the cut sometimes takes a guard with
it. And the underlying question —does the always-on constraint hurt reasoning
on hard tasks (SWE-bench, Terminal-bench)?— remains
open and without data
(16 👍, no answer).
Verdict
ponytail is a good default: it doesn't bloat, it reuses well, and its team
measures with an honesty almost nobody has. But the "-54%" headline is a Haiku
figure; on a capable model the cut is modest and, in half of my tests, took
something worth keeping with it — a field's persistence, a handful of tests, a
validation guard. The tool itself ships a /ponytail-review command
that hands you a delete-list: it assumes you review the diff. That's exactly
this site's middle ground — use agents with judgment, measure before you
believe, review before you trust. Neither rejecting laziness by reflex, nor
swallowing the "-94%" without looking at what got cut.