-
How I Review My Agents' Code
Coding agents have changed how I work. I now give code-review-style feedback to agents many times a day.
In the before times, I used
git diff main...to review my own changes locally before pushing to GitHub. As I noticed things, I wrote a todo list for myself to address. Rinse and repeat.These days that feedback goes to an agent, not to my own todo list. I used to copy-paste file names and code snippets into the chat, but that gets old and verbose fast. Now I use revdiff, a TUI built specifically for giving feedback to agents.
Giving Feedback on Diffs
At its heart,
revdiffopens a TUI that shows you changes in files. As you navigate, pressreturnto write a comment on a line (or several). When you’re done, pressqand the program prints your comments in the context of the lines they apply to. From their own example:## handler.go (file-level) consider splitting this file into smaller modules ## handler.go:43 (+) use errors.Is() instead of direct comparison ## handler.go:43-67 (+) refactor this hunk to reduce nesting ## store.go:18 (-) don't remove this validationI review code before every commit, to catch issues as early as possible. The default
revdiffinvocation shows unstaged changes. It fits my workflow exactly.You can also pass
gitranges:revdiff main...,revdiff branch-1...branch-2, and so on. That’s especially helpful for reviewing a whole branch.Giving Feedback on Plans
I have the agent write specs and plans first. That alone produces much better code (I use superpowers). I want to give feedback on those plans, but they aren’t diffs of anything, and most of the time I don’t even put them under source control.
revdiffhas me covered:revdiff --only path/to/plan.mdopens the same feedback mechanism, with table-of-contents support for markdown. It beats what I did before: opening the file in my editor, adding comments prefixed with--->(or similar), then telling the agent to go find them.No Skill
revdiffships with a skill that opens the feedback for you in an overlay window, supporting many different setups. I haven’t needed it. Because I have my agent set up to prompt me before committing any code, I get a yes/no question when it’s time to review a diff. I find it easy to switch to another terminal window, fire uprevdiff, give feedback, and switch back. Then I accept the changes, or select no and paste the output. The skill would require me to stop the agent just to invoke it.Copy to Clipboard on Exit
Shuttling output between windows by hand added friction, so I automated copying the revdiff output to my clipboard every time. My fish shell configuration:
function revdiff --description "Run revdiff and copy annotations to clipboard" set -l tmp (mktemp /tmp/revdiff.XXXXXX) command revdiff --output=$tmp $argv and cat $tmp and pbcopy < $tmp rm -f $tmp endI don’t worry about overriding my clipboard, because I use a Raycast’s clipboard manager.
Config Tweaks
Lastly, I’ve tweaked the configuration:
$ cat ~/.config/revdiff/config theme = nord cross-file-hunks = true compact = trueI can’t say enough good things about the Nord theme in dark mode.
Conclusion
revdiffhas been an immediate productivity boost. I use it many times a day, and it has made interacting with agents much easier. -
The REPL: Issue 141 - May 2026
Nate’s Dotfiles
A couple of nuggets I picked up:
mise.local.tomllets me add personal tool configuration to any project – even one whosemise.tomlI don’t control, or that has none at all..git/info/excludeworks like.gitignore, but for my eyes only..gitignoreis itself tracked by git;.git/info/excludeignores files without recording the exclusion in the repository.
Three Inverse Laws of AI
In a nod to Isaac Asimov’s laws for robots, the author proposes three laws for the humans using them – incomplete by their own admission, but worth chewing on:
- Non-Anthropomorphism
- Non-Deference
- Non-Abdication of Responsibility
It all comes down to one habit: keep exercising critical thinking.
Appearing Productive in The Workplace — No One’s Happy
What discipline looks like, in this environment, is almost embarrassingly old-fashioned and may seem obvious to most of you until you try to avoid it. Use the tool where you can verify precisely what it produces. Never ask a model for confirmation; the tool agrees with everyone, and an agreement that costs the agreer nothing is worth nothing.
I’ve been using this example with my non-tech friends: ask the 🤖 for a contract to sell your car in California and it will happily produce one, brimming with confidence that it’s sound. I’m not a lawyer, so I can’t judge it. I can skim it for anything obviously crazy, but I don’t know what’s missing, what it fails to protect me from, or whether every clause is even legal.
We replaced Redis with MySQL for inventory reservations—and it scaled (2026)
A clear account of moving the locking mechanism from Redis into the database to guarantee atomicity, with
FOR UPDATE SKIP LOCKEDput to great effect. The idea new to me was the “replenishing” pool: a set of reservable items large enough to absorb concurrent locks, yet small enough to stay practical. -
The REPL: Issue 140 - April 2026
Keeping a Postgres queue healthy — PlanetScale
Simeon Griggs explains the challenges and dynamics of queue workloads in Postgres. A job queue in Postgres is desirable because of transactionality, and because it spares you from maintaining a separate system. At a certain scale, though, it outpaces the database’s ability to clean up after itself. I haven’t evaluated PlanetScale’s solution to the problem.
Highlights from Git 2.54
gitis my most used command. I’m glad to see the CLI still improving.git historylooks genuinely useful for splitting or rewording commits. The new hook configuration also offers a much cleaner way to declare hooks – clearly needed, judging by the many popular hook-management systems out there.Do I belong in tech anymore?
Ky Decker writes a personal account of disillusionment with the tech sector. In the “The psychic toll of AI” section, Ky describes a thoughtless use of AI in his workplace, where critical thinking has gone out the window and AI is shoved everywhere. A harrowing account. I’m glad I’m not in that situation. In a short time, AI has changed how I plan features, explore alternatives, and code. Yet the technology has limitations and needs a human in the loop to check its output.
-
The REPL: Issue 139 - March 2026
LLMs can be absolutely exhausting
The author points out that some of the frustrating things about working with LLMs are derived from how you work with the LLM. The author is not wrong, but those same things he identifies as sources of diminishing returns are true without LLMs too. Fatigue has an impact on output, as do lack of thinking ahead of time about the correct end-state and slow feedback loops. There is nothing new under the sun.
What is agentic engineering? - Agentic Engineering Patterns
Agentic Engineering is a new term for me. I like it better than vibe coding, for the same reason that I always describe myself as a software engineer and not a coder. Engineering is designing and building systems. Not just knowing the correct syntax to talk to a computer.
Writing code has never been the sole activity of a software engineer. The craft has always been figuring out what code to write.
Exactly. Agents have made coding easier, but where I’ve felt they really increase my productivity is in the long planning sessions, effortless design documents, generating as many diagrams as I want in seconds. This lets me really dig into a design and hone it.
Warranty Void If Regenerated
I liked this short story a lot. At first glance a story about farming and AI seems weird. Farming is “close to the earth” and seems not very tech-oriented. Upon closer inspection, farming is an industry that has changed dramatically because of technology. Modern farming makes it possible for 5% of the population to produce all our food. It used to take >95%.
This story is imagining yet more changes to farming.
Reports of code’s death are greatly exaggerated
AI can already write a novel today. You can do it right now. Will that be a great novel? Probably not. And no one seems to be saying that it will lead to novelists being completely out of the job. In fact, I think AI is a mediocre writer, as writers go. But most people are not good at writing. Having an AI proofread or write what they want to say actually improves their communication.
Is it the same with code? Maybe there is something to that analogy. Today, AI can create great scripts that you can use locally. Even apps for personal use that will truly solve problems for individuals, even small businesses. Does that mean no one will need to know anything about software and vibe code Netflix’s streaming infrastructure? I’m not holding my breath.
I have a couple of friends that have small businesses and are vibe coding some internal apps. I am truly worried that they will get into trouble by publishing credentials, leaving open infrastructure, etc. And the thing is, they know so little about the risks and how the internet works, that it’s hard to explain to them what they are doing. “What if I ask 🤖 to review for security?”. Sure. It will help, but they probably don’t know enough to prompt it correctly.
-
Stop Using next in Ruby Loops
LLM-generated Ruby code tends to reach for
nextinside.eachloops. It works, but it’s not idiomatic. When you find yourself usingnext, there’s almost always a more expressive alternative using Enumerable methods.A Simple Example
Consider this loop that collects names of active users:
names = [] users.each do |user| next if user.inactive? names << user.name endThe
next ifis doing filtering, but it doesn’t say filtering. It says “skip this one,” which forces the reader to mentally invert the condition to understand what’s being kept. Compare:names = users.reject(&:inactive?).map(&:name)The intent is explicit: reject inactive users, then map to names. Each method communicates exactly one operation.
Discrete Steps
Enumerable methods let you express collection processing as discrete, named steps:
select,reject,map,filter_map. Each step communicates intent. When you usenextinside.each, you combine filtering and transformation into one opaque block. The reader has to mentally simulate the loop to understand what it does.Named methods are also composable. You can add, remove, or reorder steps without restructuring the entire loop. A chain of Enumerable methods reads as a description of what the code does, not how it iterates.
A More Complex Example
Here’s a loop that processes orders with multiple conditions:
summaries = [] orders.each do |order| next if order.cancelled? next if order.total < 100 next unless order.region == "US" summaries << { id: order.id, total: order.total, customer: order.customer_name } endThree
nextstatements, each encoding a different filter. You have to read all of them to understand which orders survive. Compare:summaries = orders .reject(&:cancelled?) .select { |o| o.total >= 100 } .select { |o| o.region == "US" } .map { |o| { id: o.id, total: o.total, customer: o.customer_name } }Each step is readable in isolation. The pipeline reads as a description: reject cancelled orders, keep those above $100 in the US region, then transform to summaries.
One Operation Per Step
Enumerable has methods like
filter_mapthat combine more than one operation. They can be useful, but at the cost of obscuring intent. Consider:results = items .select(&:valid?) .filter_map { |item| item.compute_value }filter_mapmaps and removesnilresults in one pass. But the reader has to know that to understand what’s happening. Compare:results = items .select(&:valid?) .map { |item| item.compute_value } .compactEach step does one thing: select valid items, transform them, remove nils. The tradeoff is worth considering –
filter_mapis more concise, but.map { ... }.compactmakes every operation visible.What About Performance?
The obvious objection: chaining creates intermediate arrays, while the
.eachloop iterates only once. In practice, this rarely matters. But when it does, that’s whatlazyis for:summaries = orders .lazy .reject(&:cancelled?) .select { |o| o.total >= 100 } .select { |o| o.region == "US" } .map { |o| { id: o.id, total: o.total, customer: o.customer_name } } .to_aSame expressive chain, single-pass iteration. You get clarity and performance.
Conclusion
When you see
nextin a loop, treat it as a signal. There’s probably an Enumerable method that says what you mean more clearly.