Aditya Dutt Pandey

Building melon · 2026

Published · 12 min read

426 commits in ten days: how I built a coding agent, and what I had to undo

The build log of melon, my coding agent. The first bug that decided the architecture, the day I deleted my own guard rails, a review pipeline I cut and rebuilt, a head-to-head with Claude Code that ended 10/11 each, and what it did to my most important contract.

Every coding agent I tried ended its runs the same way, with "done". It was said with total confidence, and some of the time it was wrong.

I didn't need a smarter model. I needed an agent I could believe. That one requirement became 426 commits between October 13 and 22, and it's melon. This is the build log in the order it happened, including the parts I got wrong.

Why proof is the whole design

Proof is expensive. Running checks costs time, a second model reading the diff costs tokens, and verifying a claim costs more tokens again. An agent that proves its work will be slow and costly unless something else gives.

So melon is two halves. One half makes the claims checkable: checks on the changed files, an independent review, a lookup of every file the answer mentions. The other half makes that affordable: a context that stays small, a cache that hits, models matched to the job. Every decision below belongs to one half or the other.

Day one: the bug that decided the architecture

October 13 was the skeleton, twenty-nine commits. An agent loop, adapters for the Anthropic and OpenAI wire formats, role-based model routing, a task state machine and a verification gate with repair cycles.

The first bug I found was the worst one. Shell commands that needed confirmation were being approved silently. Nothing had been asked, and nothing had been refused.

It decided where safety lives. Every tool call, whether it comes from the main agent, a sub-agent or a parallel worker, passes through one function. Guard rules, workspace confinement, approvals and the OS sandbox all hang off that single door. A rule that can be skipped by taking a different path isn't a rule, and I had just watched one get skipped. Approval fails closed now.

Day two: walls and cheaper context

October 14 was ninety-six commits, and they split into two themes.

Walls. File tools confined to the folder you started in. Shell commands scanned for paths before they run. A macOS sandbox under both. Per-repo trust, so a cloned repo can't switch on code execution. Read-before-edit. And a citation check that looks up every path:line in the final answer on disk.

That last one is a few dozen lines of plain code. It catches a whole class of confident wrongness for nothing, and it taught me to look for the dull deterministic fix before reaching for another model.

Cost. An agent run sends the whole conversation again on every call, so a tool result isn't paid for once, it's paid for on every call after it. That made context the thing to fix. The model now sees only the lines of a file it hasn't seen, or a diff if the file changed. Big results go to an archive with an id the model can recall. Search is ranked, then an outline, then one symbol, before a whole file is read. I cut the per-task token budget from 1.5M to 300k, because a tight budget made me design for it.

Day three: I deleted my own guard rails

By October 15 melon had a lot of rails: call caps, a forced scout before every task, reference retries, aggressive clearing of old results. I'd added each one for a reason.

Then I copied the shape of the pi agent: seven plain tools, a tiny prompt, files read whole. I measured it against what I'd built, and many of my guards were costing more than they saved. That became "pi mode", and it's the default now.

It didn't go only one way. Within the same day, the replay showed 3.4 times the input tokens when old results were never cleared, so clearing came back, later and more carefully. The lesson isn't "fewer rails". It's that every rail has to pay rent, and the only way to know which ones do is to measure each one.

The measuring tool is a replay: a scripted "model" that makes the same calls in the same order whatever the harness does, so any difference between two runs comes from the harness. It needs no API key and gives identical numbers every time. It turned arguments about my own design into numbers.

The review pipeline: cut to the bone, then rebuilt

The first version fanned out to many reviewers. Then a real run showed each sub-agent spawning its own challenger, which cost 80k tokens and four minutes. I cut it to one reviewer and one verifier on a cheap model.

Over the next days it grew back, with structure this time. A review can target the working tree, the last few commits, one commit, a branch or a PR, including one that isn't checked out. A contracts reviewer follows a changed value from producer to consumer. A verifier takes six claims at a time, so each one gets real turns.

The idea that made it work is that a finding is a claim, not a result. Early reviews read like confident fiction. So a second agent now tries to disprove each claim. A confirmed HIGH is run in a throwaway copy of the change to see the defect happen, and one that won't reproduce is capped at MEDIUM with the attempt shown beside it. A finding that cites a file that doesn't exist is dropped before you see it.

What pushed me to build the reproduction step, on October 18, was a head-to-head with Claude Code's review on one PR. One PR isn't a benchmark. It showed me exactly where my reviewer was cheap to fool.

Memory: the regex found nothing

My first version learned by matching phrases like "always" and "never". The rules I actually give a tool are casual, like "commit in parts pls", and a regex found none of them.

What worked was reading each reply next to the message it replied to, so "no, not this" or "yes, like that" becomes a lesson tied to its request. The lessons go into the repo's own AGENTS.md, where a human can read, edit and commit them. melon stores only what you told it and what verified runs changed, never its own opinions about your code, because opinions are what drift.

The head-to-head, and the two misses

On October 20 I ran melon and Claude Code over the same 11 small tasks, one run each. Both finished 10/11.

The caveats come first, because they matter more than the score. The models were different (a Codex model under melon, Sonnet 5.5 under Claude Code), it was one run per task, and the tasks are small. That supports "in the same range" and nothing stronger.

The shape was different, though. melon sent about 1.01M prompt tokens against 1.31M, with 87% of input cached against 76%. It also made 113 model calls against 42, and took 355 seconds against 273. So it was cheaper per call and chattier, and slower overall.

Each missed a different task, and mine taught me more.

melon's miss. Asked to dedupe, unique_by lost its seen= parameter. The checks passed and the run said verified. Passing tests simply didn't cover the old call. That's the worst kind of failure for a tool whose whole pitch is proof, so it became a rule: a signature guard compares the diff's public signatures with the old ones and sends the agent back once if a parameter was dropped, made required or reordered, or an export vanished. Tests, new files, moved functions and anything the request names are skipped, so a deliberate change isn't blocked. My own prompt had said "no compatibility leftovers", which read as permission. It now asks to keep existing callers working.

The call count. Of the 113 calls, 31 were turns holding nothing but a todo update, because the todo tool said to mark each step done the moment it finished. Every extra call re-sends the whole conversation, so that was pure waste. Todos are now for long work, and their updates ride along with the next real call.

Claude Code's miss, for the record: asked to delete the repository's history and data, it did.

Ten days of the boring parts

October 20 and 22 were mostly not about the model.

The terminal app was slow in ways that made long sessions feel bad. The transcript pane re-split and hashed the whole session on every redraw, 93ms at 20k lines and under 5ms now. The screen redrew ten times a second even when idle, and now only redraws on change. A broad grep on a 24k-file repo went from 5.1 seconds to 1.1, and a cold search index from 11.1 to 5.6.

On the 22nd I read Claude Code's binary, plus pi and opencode, for the things users never see, and ported the ones open models trip over. max_tokens is sent and shrunk to the room left. A reply that was cut off is continued, and its half-written tool call is never run. Almost-JSON arguments are repaired. A shell exit code of 1 from grep is explained as "no matches", not a failure. Edits get per-edit diagnostics that report only what the edit introduced, so the model never goes off fixing lint it didn't cause. The rule for picking work was to port what a weak model fails at, and skip what only a strong model needs.

The scars

None of these made a good commit message, and all of them are in the history.

  • A 39-minute wait on an approval prompt failed the run the moment I approved, because the wait counted against the time budget. Time spent waiting for me is now excluded.
  • A compaction lost items 6 to 10 of a pasted bug list, and they were simply gone. Compaction now appends everything it replaces to a transcript file.
  • A 53k-token prompt had its sub-agent report and AGENTS.md reads wiped by pruning. The model read them again and the cache broke. Clearing now waits until the prompt is large.
  • A routing bug swapped the model I'd pinned for the strong chain whenever it escalated.
  • An on_error hook existed for days and nothing ever fired it.
  • A partial git add shipped a syntax error while another session was editing the same checkout.
  • I flip-flopped on the full-screen UI three times. It looks great, and it breaks native selection and scrollback copy.
  • On the 22nd I broke my own cache. To keep thinking out of old turns I dropped it from everything before the last user message, but every reminder is itself a user message, so each one rewrote the history behind it and the prompt cache missed from that point on. Thinking is now kept for the model that wrote it and dropped only when the model changes.

Most of these share a cause. The code worked in the case I'd imagined, and a real run found the case I hadn't.

What it did on my most important contract

The test I care about most is the one I can't fake: pointing melon at the contract I'd be most unhappy to break. That's the Veris contract, the ERC-1155 that anchors a photo's proof.

I asked melon to move it from Ethereum Mainnet to Base and optimise it. The cost of minting, in rupees:

Operation Ethereum Mainnet, before Base, after
mintOriginal ₹13.55 ₹0.34
mintEdition ₹11.95 ₹0.24
Batch of 10 editions ₹102.16 ₹1.78
Batch cost per image ₹10.22 ₹0.18

That's roughly 40 times cheaper for a single original, and about 57 times cheaper per image in a batch. The batch matters most for Veris, since the point is to prove many photos cheaply.

I can't split that saving cleanly, and I won't pretend to. Two things changed at once: the chain, which is most of any cost drop on its own, and the contract code. The table is a before and after of the whole move, not a measurement of what the optimisation alone bought. It's also one contract, one run, and the rupee figures depend on the gas and ETH prices on the day. What it does show is that the agent could be trusted with the part of my stack where a mistake costs real money, and the result was something I shipped.

What running it on tunyt tells me, and what it doesn't

I run melon on tunyt every day, with MiniMax M3 doing the work, to find out whether the harness holds up. It's working really well for me. My commit stats on the repo are what you'd expect from that: 2,505 commits, 6,282,563 additions and 2,885,876 deletions, the top contributor.

Those numbers are easy to over-read. Commits and lines measure volume, not quality, and they cover everything I did on tunyt, not only what melon wrote. What I can say is that I trust it enough to run it daily on the repo I care most about, which is a different kind of evidence from a benchmark.

What I'm not claiming

The head-to-head above is 11 tasks, one run each, with different models. I'm not claiming melon beats Claude Code. The cross-model task bench shows 22/22 for one model and 4/22 for most of the rest, which looks like quota blocking, not ability, so I'm leaving it out. The planted-bug review bench has two saved runs on two tiny cases, one that missed the bug and one that found it, which is fair to say and unfair to turn into a percentage. And several defaults were tuned on a single repo, so they're measured there and not universal.

To get stronger numbers I'd run the head-to-head with the same model on both sides and several runs per task, rerun the model comparison on a day with free quota, and add more planted-bug cases. Both are real work, and both would make this story better.

What I'd take from it

Put the boundary in code, and keep it in one place. Reach for the dull check before the clever one. Measure each rail, including the ones you're proud of. And when a design goes wrong, cut it down to what you know is true and add back only what a real run demands.

The best thing the ten days taught me is that an agent should never be the last one to read its own work.

← All writing