Skip to content

Ponytail: teaching an AI coding agent to write less code

From the work/ 7 min read

What the Ponytail plugin does, how to install it, and the Railway bill we cut by deleting an image optimizer instead of tuning it again.

  • AI
  • Claude Code
In this article (6)
  1. 1. The idea: be lazy about the solution, not about the change
  2. 2. Installing it
  3. 3. Levels and commands
  4. 4. A real example: our own Railway bill
  5. 5. What it cost us
  6. 6. What the benchmark says, and what it does not

Ask an AI coding agent for a date picker and a common outcome is a new dependency or a hand-built calendar: a few hundred lines that now belong to you. Ask a senior developer and they look at what is already there first. The repository has an Input component and every browser ships a native date picker, so the answer is about ten lines.

Ponytail is an open source plugin, MIT licensed and written by Dietrich Gebert, that tries to make the agent behave like the second person. It is a set of instructions plus a few lifecycle hooks, and it runs in Claude Code, Codex and a long list of other agents. We use it on our own repositories, and this post covers what it does, how to set it up, and one change it led us to on this website.

1. The idea: be lazy about the solution, not about the change

The plugin describes itself as "lazy senior dev mode". The laziness is aimed at one thing only: how much new code the solution needs. It is not permission to skip work. The skill says so directly: finish every part the task needs, including the callers, tests and fixtures your change breaks.

In practice that turns into a short decision ladder. Before writing anything the agent goes down it and stops at the first rung that fully solves the problem.

Scroll the figure sideways to see all of it

  1. Does it need to exist? Features, options and flexibility nobody asked for are skipped, and named in one line so you can ask for them.
  2. Is it already in this codebase? A helper, a component, a service or a pattern, used the way the surrounding code uses it.
  3. Does the standard library or the platform do it? Unless the project has its own version, in which case the house component wins.
  4. Is there an installed dependency for it? Use it. Never add a new dependency for a few lines.
  5. Can it be one line a reader gets at a glance? Then one line. A one-liner that needs decoding does not count.
  6. Otherwise, the minimum code that works, plus one small test if it has real logic.

Just as important is the list of things it never cuts: validation at trust boundaries, error handling that prevents data loss, security, accessibility, and anything you explicitly asked for. A shorter diff that drops one of those is not the smallest correct change. It is simply a wrong one.

2. Installing it

In Claude Code it is a plugin from its own marketplace:

/plugin marketplace add DietrichGebert/ponytail
/plugin install ponytail@ponytail

Codex uses the same repository through codex plugin marketplace add DietrichGebert/ponytail. For agents without a plugin system, the repository ships an AGENTS.md you can copy into the project, plus rule files for Cursor, Windsurf, Cline, Copilot and others. The author asks people to install only from DietrichGebert/ponytail on GitHub or @dietrichgebert/ponytail on npm, and notes that it never ships .exe or .dll files. That is worth checking for any tool that gets to run inside your editor.

3. Levels and commands

Once installed it stays on for the session until you say "stop ponytail" or "normal mode". There are three levels:

  • lite builds what was asked and names the smaller option in one line, so you choose.
  • full is the default and applies the ladder above.
  • ultra also questions the request and pushes back on any part the need does not justify.

The commands are one-shot reports that change nothing:

/ponytail full          # switch level: lite | full | ultra
/ponytail-review        # review a change: correct, safe, holds under load, tested, lean
/ponytail-audit         # the same questions across the whole repository
/ponytail-debt          # list every "shortcut:" comment as a ledger
/ponytail-gain          # the published benchmark numbers

The debt command is the part we like most. When the agent takes a shortcut with a known limit, it has to leave a comment in a fixed form, shortcut: <the limit>, <when to upgrade>. /ponytail-debt collects them, so a deliberate deferral cannot quietly become permanent.

4. A real example: our own Railway bill

This site is a Next.js app on Railway, plus a small Postgres database for the blog. In October the project's usage was $5.28 so far in the billing period, and $5.12 of it was memory. CPU was close to zero. The Postgres service averaged 54 MB. The web service averaged 0.99 GB over seven days, which works out to roughly $10 a month in memory alone at Railway's rate of $0.000231 per GB per minute.

We had already tried to fix this in September. The diagnosis was that next/image re-encoded every image variant once a minute, and the fix was tuning: a 30-day cache, a single libvips thread, MALLOC_ARENA_MAX=2 and a heap cap. It helped, taking the average from about 1.25 GB to 0.99 GB, but every one of those settings was code added to keep a component we had never questioned.

Rung one asks the question we had skipped: does the runtime optimizer need to exist? We counted what it was optimizing. Every image on the site comes from /public. There were 47 WebP files, none wider than 1440 pixels and 2.2 MB in total, plus six PNGs that were actually used. Nothing in that set needs to be re-encoded on the server, on every deploy, by a native library that keeps its memory.

The change was a deletion. The tuning came out of next.config.ts and one setting went in:

images: {
  // Add new images to /public as WebP sized for their largest display.
  // shortcut: no srcset, so phones get the desktop-sized file; turn the
  // optimizer back on if /public gains large photos.
  unoptimized: true,
},

The six PNGs were converted to WebP once, on a laptop, with the sharp that was already installed. The logo was a 6345-pixel-wide PNG of 164 KB drawn at 30 pixels high. As a 96-pixel-high WebP it is 10 KB. The app icon went from 281 KB to 6 KB, and the four app screenshots from about 180 KB each to about 40 KB. Visitors download less than they did through the optimizer.

Scroll the figure sideways to see all of it

We then built the site and crawled all 274 pages in its sitemap. The server process sat at 173 MB idle and 197 MB after the crawl, against a 344 MB peak in the same test with the tuned optimizer. Two cautions apply here. Those numbers were measured locally, not on Railway, and a local run does not reproduce the Linux memory allocator that caused the problem. The production figure is the one that settles it, and we will confirm it after the deploy. Even at 250 MB, memory for the web service costs about $2.50 a month.

5. What it cost us

Ponytail asks the agent to end each piece of work by saying what it skipped, so here is ours. Without the optimizer there is no srcset, so a phone downloads the same 1440-pixel capture as a desktop. For our images that is between 11 and 141 KB, which we accept. If the site starts publishing large photography, the shortcut comment says exactly when to turn it back on. New images now have to be added as WebP at the right size, which is a rule for people rather than a setting in the code.

6. What the benchmark says, and what it does not

The project publishes an agentic benchmark: headless Claude Code on 39 tasks, five runs each, against the same agent without the skill. The tasks include feature tickets in a FastAPI and React repository, bug fixes, and security and privacy cases. Against that baseline it reports 53% fewer lines of code, 45% fewer output tokens, 26% lower cost and 41% less time. Hidden correctness and safety checks passed at 97%, against 96%, and a test was written where the logic needed one 98% of the time, against 68%.

Those are averages from someone else's tasks. The author is careful about that too: /ponytail-gain refuses to invent a per-repository savings figure, because the version that was never written has no line count. Read it the same way we do. It is a prompt that pushes the agent toward the question a senior reviewer would ask. It does not replace that reviewer, and it does not replace measuring the result, which is the part of this example that mattered.

Written by

Luis Morales

Luis Morales

Frontend and Shopify developer, EcomLabs

@luismoralesdev on Instagram

Published October 20, 2026 · updated October 23, 2026

← Blog