Mudpuppy lets me review my AI agent before it opens a PR
Written on
I’ve been building a little tool called mudpuppy. It’s a TUI for reviewing code, kind of like Github’s PR review page, except instead of leaving comments for a coworker you’re leaving them for an AI agent running on your own machine. You read the diff, drop comments on the lines you care about, and the agent reads them and comments back. It’s still rough and I’m buffing out the early snags, but I’ve been using it a lot lately, so I figured I’d write about it.
mudpuppy doesn’t have an AI agent built into it. It’s the other way around: mudpuppy lives outside the agent. It’s just a CLI tool, and the agent, or really any other program, can call it. There’s no MCP server to set up, no integration to wire in. The agent runs mudpuppy agent --help, and that help text tells it everything it needs to know about the whole review loop.
The nice part is you bring your own AI tool, with whatever login and billing you already have. I pay for a Claude Code subscription, so I just point Claude Code at mudpuppy and go. I don’t have to create a separate API account, generate a key, and start paying per-token API rates on top of the subscription I’m already paying for. If you’d rather use OpenCode or something else, it works the exact same way, because none of these tools need to know anything special about mudpuppy beyond go read mudpuppy agent --help.
The turns work like this: The agent leaves its comments, then runs mudpuppy agent wait. That command just hangs. While it hangs, I read the diff in the TUI, reply to the agent’s comments, and leave my own. When I’m done I release the turn, the wait command unblocks, and it prints out everything I changed: my replies, my new comments, whatever. The agent picks up from there on its own. I don’t have to go back and prompt it, copy-paste anything, or tell it “okay I’m done, go look.” It was already waiting, and automatically gets unblocked.
I built it for two things. The first is reviewing the agent’s work before it opens a PR. Before mudpuppy my review loop was a bit of a mess. I’d review some of the files locally, read the rest of the diff on Github, and then talk to the agent down in my terminal, saying things like “on xxx.ts you did this, but you should have done that instead.” It works, but pointing the agent at the right spot by describing it in prose is clumsy. And Github’s web diff viewer isn’t great for this either. It’s fine for a handful of files, but it hides large files by default, and expanding them is slow. Once you’re looking at a lot of files, or a few very big ones, reading the diff there becomes a chore. That’s getting more common too, now that everyone’s using AI agents, because the code they write tends to be a lot more verbose. The tidier option would be to push the work up as a PR and leave real review comments on it, but that’s even slower, because every single back-and-forth costs you a full CI run. With mudpuppy I review the diff locally before any of that happens. I leave comments right on the code, the agent fixes them, and we go back and forth as many times as we need without opening a PR or kicking off CI even once. By the time a PR actually goes up, it’s already been through a review.
The second is reviewing other people’s PRs. I check out the PR, open it in mudpuppy, and ask the agent to review it at the same time I’m reading through it myself. The agent leaves annotations on anything it thinks is worth a look, and I can jump straight to them as I go. So I get my own read plus a second pair of eyes flagging anything I might have missed.
The agent’s comments stay in mudpuppy. It never writes anything to Github. I don’t let the agent post comments on a PR, because I want to review everything it has to say before any of it goes out. I’m not going to spam my coworkers with a wall of AI-generated nonsense. I read what it flagged, make sure I actually understand it and agree with it, and then I write the reply myself. The one exception is other AI reviewers. If an automated reviewer leaves a comment on the PR, I’m fine letting the agent answer that one, since it’s just one AI talking to another and nobody’s feelings are on the line.
mudpuppy is configurable, but there’s no YAML or TOML file to edit. You write your config as code, in Luau, and mudpuppy runs it. I like this a lot more than a static config file. Since your config is a real program, you can write your own functions and actually add behavior to the tool that you couldn’t express in a plain config format at all. And config formats tend to grow into half-baked programming languages anyway. They sprout variables, then conditionals, then templating, until one day they’re accidentally turing-complete. I’d just rather configure things with a real programming language from the start. I like how a lot of JS tooling works this way, like how you configure Vite with a JS file.
I want to talk about the name of the project too. I was set on naming it after an animal, so I dug through a huge list of them, and one after another they were all taken. Tech companies, apps, websites, some investment firm, whatever else. I was about ready to give up when I got down to “mudpuppy” on the list, looked it up, and found nothing using it. A mudpuppy is a salamander, and it’s extremely cute, you can look it up. They are similar to axolotls, except they’re native to where I live, so the name turned out to be a nice little coincidence on top of being free. I drew the logo myself.
It’s early and I’m fixing things as I run into them, but if you want to poke at it the code is up at Barmore-Genc/mudpuppy.
