llmevals

Mimicking Developer Styles with Coding Agents

LLMs mimic Studio Ghibli art. What if they mimic-ed developers? And solved a SINGLE problem in their styles? Can we learn from that?

I picked a five-step checkout state machine problem:

I had ChatGPT identify famous JS developers and used Codex CLI to write code in each developer’s style (“Write in the style of $DEVELOPER.”)

Here is the result:

Developer How their code works
addyosmani Code used a transitions “table” of functions to get the next value. He calls allowedFor(state) before computing next to validate. That’s a clean separation of can I? vs do it.
antfu Code used a graph object that maps each state to its next states. He implements allowed() as Object.keys(graph[current]) to list valid events for the current state. That keeps branching low and makes the code friendly to edit.
davidkpiano Code used a small helper shift(delta) to move forward or back through the steps. He then dispatches via a transitions map of tiny functions. That reads like a compact, explicit state machine.
developit Code wrote straight-line, imperative code with a tiny move(next) helper to change state. He hand-wrote the allowed() cases for clarity. It’s very easy to skim.
evanw Code returned a compact api object and used optional chaining on the graph lookups. He calls notify(state) with the new state, which leaves room to extend notifications later. It feels neat and tooling-like.
jarred-sumner Code inlined almost everything for speed, but he does not validate initial. With an invalid initial state, a BACK event can set state to undefined (because steps[index-1] with index=-1 becomes undefined) and then notify subscribers with undefined. It’s fast, but has sharp edges.
kentcdodds Code defined a clear allowedMap, plus small move(next) and notify() helpers. The surface area is gentle and test-friendly.
lukeed Code kept a micro-library feel and first guards with allowed().includes(evt). He does not normalize initial. That’s mostly safe: the first NEXT snaps to 'idle', while other events are blocked.
mbostock Code based everything on an index and updates via update(nextIndex) and avoids re-looking up allowed events. He also kept separate allowedEvents. It’s very explicit, diff-friendly, and avoids recomputing work.
paulirish Code extracted a pure nextState(state, event) function. He also kept a mutable machine.state field in sync with the internal state. That matches the target TypeScript shape, but it’s a foot-gun: consumers can assign machine.state = 'done' and desync things.
rich-harris Code wrote a direct, branchy send with a tidy notify() call. He listed allowed() explicitly per state. The result is clear and compiler-friendly, with no indirection.
ryansolid Code used two maps—flow for forward and trail for back—so NEXT/BACK never need indices. He drives allowed() from an options map. It’s nicely decomposed.
sebmck Code used a compiler-style flow graph and returned a single api object. He relied on optional chaining and key lookups. It’s cohesive and tersely “tooling”.
sindresorhus Code added tiny helpers (STEPS, indexOf) and gated with allowed() early to keep branching minimal. It feels like a sharp utility.
tannerlinsley Code paired an allowedMap with a setState(next) helper that both updates and notifies. That makes the internal API ergonomic.

Some common patterns:

Some differences:

By studying the masters, we learn a lot about how to approach a problem.

But with LLM style transfer, we no longer need masters to learn from their work. We can apply all their methods to any problem.

To me, that’s staggering!

Addendum

I asked Codex CLI (gpt-5-high) to suggest an expert to refactor my AIPipe repo.

Here is the conversation

Why use a generic coding agent when it can write in an expert’s style?