Thorsten Ball’s tutorial on building agents only takes an hour or two to work through. It’s an excellent read for audiences of all technical acumen.

It’s not that hard to build a fully functioning, code-editing agent.

It seems like it would be. When you look at an agent editing files, running commands, wriggling itself out of errors, retrying different strategies — it seems like there has to be a secret behind it.

There isn’t. It’s an LLM, a loop, and enough tokens.

How to Build an Agent

After you’ve dabbled a bit with vibe coding tools, there’s no better way to wrap your head around vibe coding than to build it for yourself. There’s no magic, even if you don’t know Go!

If you’re handy with Ruby, you can easily compress the ideas therein down to about a hundred lines of code.

	  class ReadFile < RubyLLM::Tool
	    description <<~DESC
	      Read the contents of a given relative file path. Use this when you want to see what's inside a file. Do not use this with directory names.
	    DESC
	    param :path,
	          type: :string,
	          required: true,
	          desc: 'The relative path of a file in the working directory.'
	
	    def execute(path:)
	      File.read(path)
	    rescue StandardError => e
	      { error: e.message }
	    end
	  end

RubyLLM is a fantastic library. Nearly all the ideas in the tutorial are concise abstractions. Recommended.


If a team identifies a process, feature, or subsystem as “slow”, it risks resisting change by mythology alone.

Slowness seems to make a special contribution to this picture in our heads. Time is especially valuable. So as we learn that a task is slow, an especial cost accrues to it. Whenever we think of doing the task again, we see how expensive it is, and bail.

– James Somers, Speed Matters: Why Working Quickly Is More Important Than It Seems

Today’s “this took longer than I’d hoped” can become tomorrow’s “here be dragons” or “we need to do days and weeks of planning and estimating before we start in this part of the system”.

I’ve found cross-organizational conversations prevent ‘slowness mythologies’ from forming. Retrospectives and 1:1s let team members identify friction points. From there, I gather holistic feedback and pitch solutions to the team.

Engineering leadership is fundamentally social!


For circa 2015 Adam, two of the most stressful words in software development were deadlines and estimates. To my surprise, deadlines were easier to write about.

Deadlines prevent work from snowballing. They guide us to favor the clarity of the present over the speculative grandeur of the future.

More of a strongly worded date, if I’m being honest

I didn’t have a way to work it to the essay above, but I’d be remiss if I didn’t mention one of the greatest deadline hacks of the past half-century:

The show doesn’t go on because it’s ready; it goes on because it’s eleven-thirty.

— Lorne Michaels

Saturday Night Live, what fantastic hack! 😉 If you’re playing along at home, SNL is actually two deadline hacks:

  • There’s a Big Consequences deadline at 11:30pm on Saturday; the show goes on whether a prop, sketch, or actor is ready or not.
  • Every live show week has a long-established cadence: pitching the host on Monday, writing through the night on Tuesday, table read on Wednesday, rehearsals and iteration Thursday and Friday, dress rehearsal on Saturday, final changes, and then the live show.

I should worry less about missing One Amazing Thing, the feed FOMO. I can’t read the whole internet. Not even the small part I’ve carefully selected and loaded into my feed reader.

Newsblur has an option to expire feed items after some number of days. I’d previously disabled this, erroneously thinking I could at least read the part of the internet I have manually identified as interesting.

So, with some hesitation, I turned on expiring items, taking me from several thousand unread items to several hundred. This is a nice, but superficial, step forward. As a result, I’m reading feeds more frequently because there’s a less-scary top-line number. (Even when I had the number hidden, it was still scary.)

The good stuff, even if automatically expired, will probably find its way back to me. I’m likely to return to writers I enjoy and look through the archives anyway. Instead of feed FOMO, I should worry more about reading the bigger, guaranteed good things. There are books, essays, longer articles out there. Not to mention making my own stuff. Do more of that!

I wonder what other kinds of data would be improved with an expiration date. Not that all data should disappear. Backlog/task-shaped data seems the most likely to benefit from automatically deleting themselves. Unread emails, tasks, project work, read-it-later links, watch-list videos, that one season you never got around to watching on a streaming service you’re still paying for. If those archived themselves, or I archived them every few months, maybe that would make for checking off more of the good stuff!


Portland Cars and Coffee. Even on Mustang day, the European and Japanese cars were good.

Vintage BMW wheel and roundel

Pininfarina brightwork on a Ferrari

Side air scoop on a Porsche 911 Turbo

Not pictured: the most tastefully modified Toyota GR86 I’ve ever seen. 👌🏻


📺 Currently watching:

  • Paradise (S1): James Marsden and Sterling K. Brown make an excellent cast. The show itself is an okay puzzle box/mystery story. Interestingly, not the deepest or best at building a mysterious world, so they may be able to land the second season without falling off.
  • Drive to Survive (S7): this season was gifted with equal parts on-track competition and behind-the-scenes backstabbing. The 2024 season was surprisingly competitive. Nearly half of the drivers were seeking new seats. This makes for good television! (Reminder: this is a “Real Housewives” style show, not a sports documentary.🤣)
  • Severance (S2): they still got it. Splendid cast, writing, production.
  • White Lotus (S3): they also still got it. Another great cast of actors you know, some actors you don’t. Great scenery! Reminder: if you ever see show-creator Mike White on your vacation, probably move away so you don’t end up a character on the next season.
  • Andor (S1): rewatching this anticipating Season 2. Definitely the best Star Wars of the Disney+ era, even though it’s not strictly the most entertaining one.
  • Slow Horses (S1 & S2): Gary Oldman as the leader of a band of misfits, outcast MI-5 spies? It works.

Shows returning later this year that I’m looking forward to: Poker Face S2, Andor S2, Hacks S4.


As goes writing, so goes software development teams:

“Having a method, a process, makes my writing more consistently good. This might sound like a win, but it is a problem. The usefulness and beauty of essays follow a power law, where the outliers create almost all the value—so if I make my essays more consistent, I remove not only the mistakes but also much of the upside. A method can, if used wisely, be a tool that helps you see possibilities. It can’t replace paying close attention to the material and figuring out what it is asking of you.”

— Henrik Karlsson, How I Write Essays

Growing teams are often nostalgic for the times when they were smaller. Maybe it’s not Founder Mode or yearning for a time when there was more low-hanging fruit. Perhaps they’re remember a time when they could swing for the fences more often at the expense of striking out more often? That is, processes designed for predictability and throughput weren’t constraining the magnitude of their big wins or their focus on all the details that make something excellent.


James Edward Gray II, Scrappy Parsing:

The good news is that Elixir is the best language I have ever worked with for doing serious parsing. Let’s prove it. Let’s pull the data out of a SQLite database file using vanilla Elixir and some tricks from my Scrappy Programmer Livebook series.

Reader: he proves it. I enjoyed the heck out of reading this. James has still got it. (One should never doubt that he might lose it!)

James’ code reminded me of the many ways Elixir is really lovely. I’ve annotated his code with my own reflections on what makes Elixir great. All the code is James’ work; the comments are my, well, commentary and opinions.

  # First off, Elixir is lovely and I'm a little sad I've 
  # never had the opportunity to work with it on a daily 
  # basis.
  parse_page = fn bytes, i ->
    start = if i == 1, do: 100, else: 0

    # Reading binary data via pattern matching is one of the
    # the best things about Erlang, so it's also a great thing 
    # about Elixir.
    <<raw_type::1*8,
      _first_page_freeblock::2*8,
      cell_count::2*8,
      _raw_cell_content_start::2*8,
      _fragmented_free_bytes::1*8,
      rest::binary>> = binary_slice(bytes, start, 12)

    # "Plain old pattern matching", also lovely
    type =
      case raw_type do
        2 -> :interior_index
        5 -> :interior_table
        10 -> :leaf_index
        13 -> :leaf_table
      end

    right_most_pointer =
      if type in [:interior_index, :interior_table] do
        <<right_most_pointer::4*8>> = rest
        right_most_pointer
      else
        nil
      end

    %{
      index: i,
      start: start,
      type: type,
      cell_count: cell_count,
      right_most_pointer: right_most_pointer
    }
  end

  # Here we have a function defined for a very specific pattern match, including structural _and_ guard conditions. How many conditionals does this save in function bodies? I don't know how often this helps daily Elixir users, but I sure do love reading it.
  read_page = fn %{page_count: last_page} = db, i when i > 0 and i <= last_page ->
    :file.position(db.file, (i - 1) * db.page_size)

    # Despite many attempts, Elixir's syntax design for function 
    # pipelines will probably always eclipse the same design in JavaScript or Ruby.
    # Spoiler: it's because Elixir doesn't have to rearrange `self` and the threaded parameter. 🤷🏻‍♂️
    db.file
    |> IO.binread(db.page_size)
    |> parse_page.(i)
  end

  # I've tripped all over myself praising Elixir here, but I'd
  # like to point out that Elixir has the same ungainly syntax
  # for calling anonymous functions that Ruby does. 😆
  open_db.(db_path, fn db ->
    Enum.map(1..3//1, fn i ->
      read_page.(db, i)
    end)
  end)

(This is not recruiter bait, but I’m listening, if you’re out there. 😉)


Our trees are putting on a show lately! I’m not sure if we’re still in Fake Spring here in Portland, OR. The color and temperature beats Austin though! 😉


Observations on excellent teams, from my newsletter:

Teams at the top of their game have a few things going for them. They operate with pace and confidence, reducing the need for time-consuming and detailed planning. They work together with coherence and trust, anticipating each other’s actions and decisions. This lets each individual on the team act with high agency to solve problems and act upon feedback quickly.


Our calendars are often painful because they display order (meetings) too well, but don’t display disorder (surprises and interruptions) at all.

Into every developer’s day (and managers in particular) arrives surprises, interruptions, questions, and side-quests. A bit of chaotic disorder.

Personally, in signing up for the job of engineering manager, I feel like I also signed up for the job of handling surprises and side-quests. I take them on not to protect my teams’ focus or time, but because surprises and questions are some of the best kind of information I can receive. They represent the friction points between my mental model of the organization or system and the details of the real world.

I would probably trade more interruptions and side quests for fewer recurring meetings!


Sync Engines are the Future:

So, what’s the significance of sync engines? I have a theory that every major technology shift happened when one part of the stack collapsed with another. For example:

  • Web apps collapsed cross-platform development. Instead of developing two or three versions of your app, you now develop one, available everywhere!
  • Node.js collapsed client and server development. You get one language instead of two! You can share code between them!
  • Docker collapsed the distinction between dev and prod.
  • React collapsed HTML and JS, Tailwind collapsed JS and CSS.

So where does that leave sync engines? They collapse the database and the server. If your database is smart enough and capable enough, why would you even need a server? Hosted database saves you from the horrors of hosting and lets your data flow freely to the frontend.

  1. Conceptual compression is a big deal. Even discounting for uneven distribution of technological shifts, like Docker dev environments and collapsing client/server, HTML, and CSS all into JS.
  2. Sync and local-first storage engines seem like they could be a big deal. It’s a tricky problem to solve. And, governments taking a turn for the weird lately, being able to move your data to another locality and point, with certainty at where data rests, is a useful ability!

Tina Turner covers, very slowly:

On the upside: the more I put my love of songs played slowly into the universe, the more it provides! On the downside: I may have to rewrite my laws of slow songs. 🙃


These two traits—high mental capacity and clear focus—are essential to solving all but the most trivial computer programming tasks. The ability to maintain a large “mental stack” and the discipline to move seamlessly up and down that stack without succumbing to distraction are hallmarks of many great programmers.

— Justin Searls, Programming is about mental stack management

I’m reminded that one of the most amazing developers I’ve worked with was legitimately able to multitask. I think this was due zero-cost push/pop of their context stack. Whether this was possible because of a unique brain or an excellent system of note-taking, I don’t know!


Text boxes were not meant for collaboration.

How often do you find the majority of the coordination, collaboration, and team work you do happens by typing into (sometimes unsophisticated) text boxes and reading what other people typed into similar text boxes?

And now we’re increasingly typing in text boxes to interact with simulacra of human intelligence!

Emoji have helped — teamwork is easier if people opt into leaving hints about how they feel about something. Corollary: do not try to dead-pan in a text-only or high-latency video format. It will only end poorly.

I’m not entirely sure what to make of the humble text box’s crucial role in our society increasingly built on communication, knowledge, and using the two to generate more of the latter.

On one hand, before there were text boxes, writers have used various styli, pens, and typewriters to compose basically all of human culture and knowledge. So maybe the tool-in-hand (i.e., a text box) is not the crucial element.

On the other hand, given slightly more expressive tools, musicians have created the gamut of musical culture in only a few hundred years.


Every career step is searching for the next set of collaborators. And, even in a buyer’s market like we face today, it’s a bidirectional affair. The employer and the employee have to choose each other. Granted, I’ve been at this particular job search longer than I’d hoped!


New to me diner. Old school “where people meet in TV shows” vibes. Perfect for a Friday morning.


Vibe coding is generating code with an LLM (Claude, ChatGPT, Copilot, etc.) and just going for it. No review, no tests, just prompt/reload/repeat.

Hopefully, you’re only doing this for prototypes! I’m sure some folks are not. Surely, they don’t read this website.

When working this way, I’m tempted to accept every suggestion from the robot “product” collaborator. Yeah, my humble little idea could use a two-pane navigation interface, lazy update semantics, insightful logging, robust error handling, and keyboard shortcuts! Sure, go ahead and try to implement that thousand word spec you just generated in one shot. Without automated feedback. I’ll wait.

This goes about as well a human trying to implement the entire spec in one epic commit. At best, you get a big ball of illegible mud that looks right but doesn’t quite work. At worst, it’s riddled with syntax errors or misused APIs, aka “hallucinations”.

For better or worse, an LLM can slop out as much code as you are willing to pay for, but the compiler/runtime still has the last laugh.


A return to hand-written notes by learning to read & write – Google research on training models to recognize not just text in handwriting, but the actual strokes. So you could color or even edit-in-place the handwritten strokes later on. I hope someone is working on productizing this! A Remarkable/Kindle/Boox/Daylight tablet that recognizes sloppy handwriting and allows tweaking it later would make e-ink displays live up to the name. 🙃

Adjacent: Ink and Switch is publishing more of their programmable ink work lately.

If we play our cards right, the next couple years could be exciting for pen-and-paper sorts of thinkers.


Harper Reed, My LLM codegen workflow atm:

If you have a small or large project that you are procrastinating on, I would recommend giving it a shot. You will be surprised how far you can get in a short amount of time.

My hack to-do list is empty because I built everything. I keep thinking of new things and knocking them out while watching a movie or something.

The workflow includes: prompts for generating product requirements, technical specifications, project plans. It recommended tools for implementing those ideas into new and existing projects. CLI-friendly throughout, no need to change workflows to an AI-infused flavor-of-the-month. And, there are caveats for skeptics. It’s not a “everything is shiny and free from surprising consequences” sort of piece.

As if you haven’t heard it enough lately: it is, earnestly, mind blowing that we can go from a few sentences describing an idea to a working prototype in a few hours of supervising an LLM. Inevitably, we’ll learn about shortcomings, scaling problems, and pitfalls in the coming years. As ever! But, the cost function for software is going to change a lot in the coming years and, if we play our cards right, it will be a fun ride.