justin․searls․co

I was red-pilled by Claude Code over 4th of July weekend. Its performance was incredible. Ever since, it's been unbelievably incompetent by comparison.

Now the AI bros tell me Anthropic's servers get slammed during US business hours and Claude becomes 70% stupider. It's 4pm on a Friday and I only realized because Claude stopped fucking everything up. Great job, everyone.

I am 40 damn years old and still believe it is a moral failing to take two trips to carry shit from one place to another, even if it's likely I'll drop everything.

Invoice for my first Mac (2004)

Thanks to a bug in Apple Mail, my Gmail archive likes to revert to sort by ascending date every now and then. Today, I scanned through some of those early emails and stumbled upon this incredible artifact: the e-mail invoice from Apple.com for my first Mac. It was a build-to-order 12" iBook G4 in July 2004.

Besides being set in such carefully-coifed monospace plaintext, the invoice provides an almost hilarious level of detail and verbiage by today's standards. Also, it never gets old to marvel at how much computers have depreciated over time. A whopping $1,362.00 for a mid-tier build of Apple's smallest, cheapest laptop in 2004. That's $2,317.82 in 2025 dollars after inflation. Today, the cheapest laptop Apple.com will sell you is the M4 MacBook Air (in an unusually recommendable configuration), starting at $999.

Big thanks to my dad Fred for spoiling me with a second computer literally one year into college (for which he bought me a Dell in June of 2003), because I was so insistent on switching to the Mac. (I sure was an entitled piece of shit.) I really wish I'd managed to hold onto that thing—a lot of fond memories, looking back.

The full invoice follows:

Apple Computer, Inc.                               INVOICE RECEIPT

Please remit to:
FOR YOUR RECORDS ONLY

Customer Number    Invoice Number
900007             9212467049

Reference Date     07/14/04

Amount Due         .00


Please Reference Apple's Invoice Number on Your Remittance

Sold To:                                 Ship To:
Fred Searls                              Justin Searls
REDACTED                                 REDACTED
TRENTON MI  48183                        GRAND RAPIDS MI  49504
USA                                      USA

________________________________________________________________________________
Customer Number    Customer P.O. Number    Sales Order Number
900007             7346758400              7010461968

Invoice Number     Invoice Date            Terms
9212467049         07/14/04                Credit Card
________________________________________________________________________________

Item Product   Product                        Total   Total   Unit      Extended
     Number    Description                    Ordered Shipped Price     Price
________________________________________________________________________________

002 Z0A704KVH  IBOOK 12.1/1.GHZ/768/60G/COMB      1     1  1,362.00     1,362.00
               Original ordered material was Z0A7
               SerialNo.: ( UV42906LR73 )

               The unit above contains the following options:

               Memory                    065-5001  768MB DDR266
               Hard Drive                065-5004  60GB ULTRA ATA DRIVE
               Optical Drive             065-5006  COMBO DRIVE
               Airport                   065-5009  Airport Extreme Card
               BlueTooth                 065-5011  Internal BlueTooth Module
               Custom SW I               065-4683  Not Applicable
               Keyboard/Mac OS Language  065-5012  Keyboard/Mac OS

________________________________________________________________________________

Subtotal              1,362.00

Tax                      81.72

Shipping Charges

TOTAL  USD            1,443.72
                                    DO NOT PAY
________________________________________________________________________________
Questions? Call (800) 676-2775 Mon-Fri 8am-9pm, Sat-Sun 9am-6pm CT
________________________________________________________________________________
Salesperson   Contact  Entry Date  Ship Date  Routing   Waybill Number
              BD       07/11/04    07/13/04   FEDERAL EX658584351832
________________________________________________________________________________
Shipped From:
F/G Distribution Center
Elk Grove, Ca 95758



               Web Order Number: W8731448

               Billed To: Credit Card


________________________________________________________________________________
After Remitting Payment Retain This Portion Of Invoice For Your Records.

Please See Below For Terms And Conditions Pertaining To This Order.
________________________________________________________________________________

Apple Computer, Inc.
________________________________________________________________________________
TERMS & CONDITIONS OF SALE


ORDER STATUS  For order status information, you may visit
http://www.apple.com/OrderStatus or navigate to http://store.apple.com/ and click
the "Your Account" button to view the status of your order.

U.S. SALES ONLY  The Apple Store sells and ships products only within the
continental United States, Alaska, and Hawaii. No shipments can be outside the
United States. You may not export any products purchased at the Apple Store.

SALES TO END USERS ONLY  The Apple Store sells and ships products to end user
customers only.

RETURN & REFUND POLICY   If you are not satisfied with your Apple purchase of a
pre-built product, please call 1-800-676-2775 for a Return Material Authorization
(RMA) request within 10 business days of the receipt of the product. If the item
is returned unopened in the original box, we will exchange it or offer you a
refund based on your original method of payment. The product must be returned to
the Apple warehouse within 10 business days of the issuance of the RMA. All
products must be packed in the original, unmarked packaging including any
accessories, manuals, documentation and registration that shipped with the
product. A 10% open box fee will be assessed on any opened hardware or accessory.
If you purchased your order using an Apple Instant Loan or an Apple Business
Lease, you may be asked to provide a major credit card (Visa, MasterCard,
American Express, or Discover) for Apple to assess the 10% open box restocking
fee.

Please note that Apple does not permit the return of or offer refunds for the
following products:

  1. Product that is custom configured to your specifications
  2. Opened memory
  3. Opened software
  4. Electronic software downloads

NOTE: Apple recommends that you (1) use a carrier that offers shipment tracking
for all returns and (2) either insure your package for safe return to Apple or
declare the full value of the shipment so that you are completely protected if
the shipment is lost or damaged in transit. If you choose not to (1) use a
carrier that offers tracking and (2) insure or declare the full value of the
product, you will be responsible for any loss or damage to the product during
shipping. Please note that the United States Postal Service (USPS) offers limited
tracking capabilities and that there is a 30-calendar-day waiting period before
the USPS will initiate a trace.

DEFECTIVE ITEMS  If you discover what you believe is a product defect for any
Apple-branded product, please contact Apple Care Technical Support at
1-800-APL-CARE (275-2273). Such a defect, if any, is covered under the terms of
your product's warranty. Please refer to the warranty information and other
supporting documentation that came with your product. (See Product Warranty
section below for specific information about Apple's product warranties.)

If you discover what you believe is a product defect for any third-party product,
please contact the manufacturer directly for information regarding the
manufacturer's warranty.

PROOF OF PURCHASE  This receipt is your proof of purchase from Apple.

CUSTOM-CONFIGURED PRODUCT  We are pleased to offer product that is
custom-configured to your specifications, and we encourage you to review your
order carefully. Since the product is built to your specifications, the order
cannot be changed, modified, or canceled once your order is in production.

SUPPORT PRODUCTS  Support products (such as the AppleCare Protection Plan) are
subject to the terms and conditions that accompany those products. By requesting

services under those products or completing and returning to Apple any
accompanying enrollment forms, you agree to the terms and conditions that apply
to those products. Those terms and conditions take precedence over any
inconsistent provisions in these Terms & Conditions of Sale.

SALES TAX  Apple Store purchases will include sales tax based on the ship-to
location and the sales tax rate in effect at the time of shipping. If you phone
in your order, the Apple Store sales representative will provide the final dollar
total of your order including tax and any applicable shipping charges at the time
you place your order. If the sales tax rate for the state to which your order is
being shipped changes before the product is shipped, the new tax rate in effect
at the time of shipment will apply. The proof of purchase that Apple mails to you
will include any applicable sales tax.

PRICES  The Apple Store endeavors to offer you competitive prices on current
Apple products and selected refurbished and clearance products Your total order
price will include the price of the product (on the day of shipping) plus any
applicable sales tax and shipping charges. Apple reserves the right to change
prices for products displayed at the Apple Store at any time.

Should Apple reduce its price on any shipped product within 10 calendar days of
shipment, you may contact Apple Sales Support at 1-800-676-2775 to request a
refund or credit of the difference between the price you were charged and the
current selling price. To receive the refund or credit you must contact Apple
within 14 business days of shipment.

PRODUCT AVAILABILITY  Given the popularity of some products, Apple may restrict
the number of such items that you may purchase. Any product limit restrictions
will be posted on the Apple Store web site.  This information is subject to
change.

PRODUCT WARRANTY  The sole warranty for Apple-branded product shall be Apple's
standard Limited Warranty as set forth in the documentation that accompanies each
Apple product.

Non-Apple-branded/Third-party products are sold "AS IS" by the Apple Store, but
may be accompanied by their manufacturers' standard warranties. "AS IS" products
are sold by Apple as is, where is, and with all faults, and without express or
implied warranties from Apple. If you have questions about any manufacturers'
warranties that accompany such products, please call 1-800-APL-CARE (275-2273)..

OTHER TERMS AND CONDITIONS
- Apple is not responsible for typographical errors.
- Apple reserves the right to change the terms and conditions of sale at the
Apple Store at any time.
- Title and risk of loss to all products will pass to you on delivery.
- All sales at the Apple Store are governed by California law, without giving
effect to California's conflict of law provisions.
- No Apple employee or agent has the authority to vary any of the Apple Store's
policies or the terms and conditions governing any sale.
- Additional terms and conditions may apply to Education customers purchasing for
personal use. Please refer to the Education Individual sales policies located at:
http://store.apple.com/Catalog/US/Images/salespoliciesEdIndividual.html


02-CONS-05-09-03

TLDR is the best test runner for Claude Code

A couple years ago, Aaron and I had an idea for a satirical test runner that enforced fast feedback by giving up on running your tests after 1.8 seconds. It's called TLDR.

I kept pulling on the thread until TLDR could stand as a viable non-satirical test runner and a legitimate Minitest alternative. Its 1.0 release sported a robust CLI, configurable (and disable-able) timeouts, and a compatibility mode that makes TLDR a drop-in replacement for Minitest in most projects.

Anyway, as I got started working with Claude Code and learned about how hooks work, I realized that a test runner with a built-in concept of a timeout was suddenly a very appealing proposition. To make TLDR a great companion to agentic workflows, I put some work into a new release this weekend that allows you to do this:

tldr --timeout 0.1 --exit-0-on-timeout --exit-2-on-failure

The above command does several interesting things:

  • Runs as many tests in random order and in parallel as it can in 100ms
  • If some tests don't run inside 100ms, TLDR will exit cleanly (normally a timeout fails with exit code 3)
  • If a test fails, the command fails with status code 2 (normally, failures exit code 1)

These three flags add up to a really interesting combination when you configure them as a Claude Code hook:

  • A short timeout means you can add TLDR to run as an after-write hook for Claude Code without slowing you or Claude down very much
  • By exiting with code 0 on a timeout, Claude Code will happily proceed so long as no tests fail. Because Claude Code tends to edit a lot of files relatively quickly, the hook will trigger many randomized test runs as Claude works—uncovering any broken tests reasonably quickly
  • By exiting code 2 on test failures, Claude will—according to the docs—block Claude from proceeding until the tests are fixed

Here's an example Claude Code configuration you can drop into any project that uses TLDR. My .claude/settings.json file on todo_or_die looks like this:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bundle exec tldr --timeout 0.1 --exit-0-on-timeout --exit-2-on-failure"
          }
        ]
      }
    ]
  }
}

If you maintain a linter or a test runner, you might want to consider exposing configuration for timeouts and exit codes in a similar way. I suspect demand for hook-aware CLI tools will become commonplace soon.

Breaking Change artwork

v39.0.1 - Use AI in Anger

Breaking Change - Hotfix

Video of this episode is up on YouTube:

Welcome to the first episode of 🔥Hotfix🔥! Breaking Change's first show-within-a-show, wherein I let somebody else talk for once. Each episode will show up as a patch release in the Breaking Change feed and feature guests with Hot takes about a relevant issue and a clear fix in mind for what we can do about it.

That first guest is a long-time collaborator and top 5 all-time colleague of mine named Dave Mosher, who's here to drop some truth bombs labeled "agentic coding" on the unsuspecting populace.

My secret mission on each of these is to lean into the show's E-for-explicit tag and try to get the guest to say something that could get them fired. I failed this time, but in fairness to me, Dave is Canadian.

We'd love to get your feedback to podcast@searls.co — I'll read it all and flag relevant questions and comments for the next Breaking Change.

You can follow Dave Mosher online at:

A handful of things we mentioned:

Show those show notes…

Notify your iPhone or Watch when Claude Code finishes

I taught Claude Code a new trick this weekend and thought others might appreciate it.

I have a very bad habit of staring at my computer screen while waiting for it to do stuff. My go-to solution for this is to make the computer do stuff faster, but there's no getting around it: Claude Code insists on taking an excruciating four or five minutes to accomplish a full day's work. Out of the box, claude rings the terminal bell when it stops out of focus, and that's good enough if you've got other stuff to do on your Mac. But because Claude is so capable running autonomously (that is, if you're brave enough to --dangerously-skip-permissions), that I wanted to be able to walk away from my Mac while it cooked.

This led me to cobble together this solution that will ping my iPhone and Apple Watch with a push notification whenever Claude needs my attention or runs out of work to do. Be warned: it requires paying for the Pro tier of an app called Pushcut, but anyone willing to pay $200/month for Claude Code can hopefully spare $2 more.

Here's how you can set this up for yourself:

  1. Install Pushcut to your iPhone and whatever other supported Apple devices you want to be notified on
  2. Create a new notification in the Notifications tab. I named mine "terminal". The title and text don't matter, because we'll be setting custom parameters each time when we POST to the HTTP webhook
  3. Copy your webhook secret from Pushcut's Account tab
  4. Set that webhook secret to an environment variable named PUSHCUT_WEBHOOK_SECRET in your ~/.profile or whatever
  5. Save the shell script below
  6. Use this settings.json to configure Claude Code hooks

Of course, now I have a handy notify_pushcut executable I can call from any tool to get my attention, not just Claude Code. The script is fairly clever—it won't notify you while your terminal is focused and the display is awake. You'll only get buzzed if the display is asleep or you're in some other app. And if it's ever too much and you want to disable the behavior, just set a NOTIFY_PUSHCUT_SILENT variable.

The script

I put this file in ~/bin/notify_pushcut and made it executable with chmod +x ~/bin/notify_pushcut:

#!/usr/bin/env bash

set -e

# Doesn't source ~/.profile so load env vars ourselves
source ~/icloud-drive/dotfiles/.env

if [ -n "$NOTIFY_PUSHCUT_SILENT" ]; then
    exit 0
fi

# Check if argument is provided
if [ $# -eq 0 ]; then
    echo "Usage: $0 TITLE [DESCRIPTION]"
    exit 1
fi

# Check if PUSHCUT_WEBHOOK_SECRET is set
if [ -z "$PUSHCUT_WEBHOOK_SECRET" ]; then
    echo "Error: PUSHCUT_WEBHOOK_SECRET environment variable is not set"
    exit 1
fi

# Function to check if Terminal is focused
is_terminal_focused() {
    local frontmost_app=$(osascript -e 'tell application "System Events" to get name of first application process whose frontmost is true' 2>/dev/null)

    # List of terminal applications to check
    local terminal_apps=("Terminal" "iTerm2" "iTerm" "Alacritty" "kitty" "Warp" "Hyper" "WezTerm")

    # Check if frontmost app is in the array
    for app in "${terminal_apps[@]}"; do
        if [[ "$frontmost_app" == "$app" ]]; then
            return 0
        fi
    done

    return 1
}

# Function to check if display is sleeping
is_display_sleeping() {
    # Check if system is preventing display sleep (which means display is likely on)
    local assertions=$(pmset -g assertions 2>/dev/null)

    # If we can't get assertions, assume display is awake
    if [ -z "$assertions" ]; then
        return 1
    fi

    # Check if UserIsActive is 0 (user not active) and no prevent sleep assertions
    if echo "$assertions" | grep -q "UserIsActive.*0" && \
       ! echo "$assertions" | grep -q "PreventUserIdleDisplaySleep.*1" && \
       ! echo "$assertions" | grep -q "Prevent sleep while display is on"; then
        return 0  # Display is likely sleeping
    fi

    return 1  # Display is awake
}

# Set title and text
TITLE="$1"
TEXT="${2:-$1}"  # If text is not provided, use title as text

# Only send notification if Terminal is NOT focused OR display is sleeping
if ! is_terminal_focused || is_display_sleeping; then
    # Send notification to Pushcut - using printf to handle quotes properly
    curl -s -X POST "https://api.pushcut.io/$PUSHCUT_WEBHOOK_SECRET/notifications/terminal" \
         -H 'Content-Type: application/json' \
         -d "$(printf '{"title":"%s","text":"%s"}' "${TITLE//\"/\\\"}" "${TEXT//\"/\\\"}")"
    exit 0
fi

Claude hooks configuration

You can configure Claude hooks in ~/.claude/settings.json:

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/bin/bash -c 'json=$(cat); message=$(echo \"$json\" | grep -o '\"message\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | sed 's/.*: *\"\\(.*\\)\"/\\1/'); $HOME/bin/notify_pushcut \"Claude Code\" \"${message:-Notification}\"'"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$HOME/bin/notify_pushcut \"Claude Code Finished\" \"Claude has completed your task\""
          }
        ]
      }
    ]
  }
}

If candidates are cheating your interview process by using AI, the solution is not to quiz them on computer science topics. It's to pair with them and watch them cook! If they can cheat with AI better than you can, hire them.

People email me asking for my consulting rate and I tell them I'm not taking clients.

People email me about my blog post and I give them 3000 words of free consulting over six replies.

Full-breadth Developers

The software industry is at an inflection point unlike anything in its brief history. Generative AI is all anyone can talk about. It has rendered entire product categories obsolete and upended the job market. With any economic change of this magnitude, there are bound to be winners and losers. So far, it sure looks like full-breadth developers—people with both technical and product capabilities—stand to gain as clear winners.

What makes me so sure? Because over the past few months, the engineers I know with a lick of product or business sense have been absolutely scorching through backlogs at a dizzying pace. It may not map to any particular splashy innovation or announcement, but everyone agrees generative coding tools crossed a significant capability threshold recently. It's what led me to write this. In just two days, I've completed two months worth of work on Posse Party.

I did it by providing an exacting vision for the app, by maintaining stringent technical standards, and by letting Claude Code do the rest. If you're able to cram critical thinking, good taste, and strong technical chops into a single brain, these tools hold the potential to unlock incredible productivity. But I don't see how it could scale to multiple people. If you were to split me into two separate humans—Product Justin and Programmer Justin—and ask them to work the same backlog, it would have taken weeks instead of days. The communication cost would simply be too high.

We can't all be winners

When I step back and look around, however, most of the companies and workers I see are currently on track to wind up as losers when all is said and done.

In recent decades, businesses have not only failed to cultivate full-breadth developers, they've trained a generation into believing product and engineering roles should be strictly segregated. To suggest a single person might drive both product design and technical execution would sound absurd to many people. Even for companies who realize inter-disciplinary developers are the new key to success, their outmoded job descriptions and salary bands are failing to recruit and retain them.

There is an urgency to this moment. Up until a few months ago, the best developers played the violin. Today, they play the orchestra.

Google screwed up

I've been obsessed with this issue my entire career, so pardon me if I betray any feelings of schadenfreude as I recount the following story.

I managed to pass a phone screen with Google in 2007 before graduating college. This earned me an all-expense paid trip for an in-person interview at the vaunted Googleplex. I went on to experience complete ego collapse as I utterly flunked their interview process. Among many deeply embarrassing memories of the trip was a group session with a Big Deal Engineer who was introduced as the inventor of BigTable. (Jeff Dean, probably? Unsure.) At some point he said, "one of the great things about Google is that engineering is one career path and product is its own totally separate career path."

I had just paid a premium to study computer science at a liberal arts school and had the audacity to want to use those non-technical skills, so I bristled at this comment. And, being constitutionally unable to keep my mouth shut, I raised my hand to ask, "but what if I play a hybrid class? What if I think it's critical for everyone to engage with both technology and product?"

The dude looked me dead in the eyes and told me I wasn't cut out for Google.

The recruiter broke a long awkward silence by walking us to the cafeteria for lunch. She suggested I try the ice cream sandwiches. I had lost my appetite for some reason.

In the years since, an increasing number of companies around the world have adopted Silicon Valley's trademark dual-ladder career system. Tech people sit over here. Idea guys go over there.

What separates people

Back to winners and losers.

Some have discarded everything they know in favor of an "AI first" workflow. Others decry generative AI as a fleeting boondoggle like crypto. It's caused me to broach the topic with trepidation—as if I were asking someone their politics. I've spent the last few months noodling over why it's so hard to guess how a programmer will feel about AI, because people's reactions seem to cut across roles and skill levels. What factors predict whether someone is an overzealous AI booster or a radicalized AI skeptic?

Then I was reminded of that day at Google. And I realized that developers I know who've embraced AI tend to be more creative, more results-oriented, and have good product taste. Meanwhile, AI dissenters are more likely to code for the sake of coding, expect to be handed crystal-clear requirements, or otherwise want the job to conform to a routine 9-to-5 grind. The former group feels unchained by these tools, whereas the latter group just as often feels threatened by them.

When I take stock of who is thriving and who is struggling right now, a person's willingness to play both sides of the ball has been the best predictor for success.

Role Engineer Product Full-breadth
Junior
Senior

Breaking down the patterns that keep repeating as I talk to people about AI:

  • Junior engineers, as is often remarked, don't have a prayer of sufficiently evaluating the quality of an LLM's work. When the AI hallucinates or makes mistakes, novice programmers are more likely to learn the wrong thing than to spot the error. This would be less of a risk if they had the permission to decelerate to a snail's pace in order to learn everything as they go, but in this climate nobody has the patience. I've heard from a number of senior engineers that the overnight surge in junior developer productivity (as in "lines of code") has brought organization-wide productivity (as in "working software") to a halt—consumed with review and remediation of low-quality AI slop. This is but one factor contributing to the sense that lowering hiring standards was a mistake, so it's no wonder that juniors have been first on the chopping block

  • Senior engineers who earnestly adopt AI tools have no problem learning how to coax LLMs into generating "good enough" code at a much faster pace than they could ever write themselves. So, if they're adopting AI, what's the problem? The issue is that the productivity boon is becoming so great that companies won't need as many senior engineers as they once did. Agents work relentlessly, and tooling is converging on a vision of senior engineers as cattle ranchers, steering entire herds of AI agents. How is a highly-compensated programmer supposed to compete with a stable of agents that can produce an order of magnitude more code at an acceptable level of quality for a fraction of the price?

  • Junior product people are, in my experience, largely unable to translate amorphous real-world problems into well-considered software solutions. And communicating those solutions with the necessary precision to bring those solutions to life? Unlikely. Still, many are having success with app creation platforms that provide the necessary primitives and guardrails. But those tools always have a low capability ceiling (just as with any low-code/no-code platform). Regardless, is this even a role worth hiring? If I wanted mediocre product direction, I'd ask ChatGPT

  • Senior product people are among the most excited I've seen about coding agents—and why shouldn't they be? They're finally free of the tyranny of nerds telling them everything is impossible. And they're building stuff! Reddit is lousy with posts showing off half-baked apps built in half a day. Unfortunately, without routinely inspecting the underlying code, anything larger than a toy app is doomed to collapse under its own weight. The fact LLMs are so agreeable and unwilling to push back often collides with the blue-sky optimism of product people, which can result in each party leading the other in circles of irrational exuberance. Things may change in the future, but for now there's no way to build great software without also understanding how it works

Hybrid-class operators, meanwhile, seem to be having a great time regardless of their skill level or years experience. And that's because what differentiates full-stack developers is less about capability than about mindset. They're results-oriented: they may enjoy coding, but they like getting shit done even more. They're methodical: when they encounter a problem, they experiment and iterate until they arrive at a solution. The best among them are visionaries: they don't wait to be told what to work on, they identify opportunities others don't see, and they dream up software no one else has imagined.

Many are worried the market's rejection of junior developers portends a future in which today's senior engineers age out and there's no one left to replace them. I am less concerned, because less experienced full-breadth developers are navigating this environment extraordinarily well. Not only because they excitedly embraced the latest AI tools, but also because they exhibit the discipline to move slowly, understand, and critically assess the code these tools generate. The truth is computer science majors, apprenticeship programs, and code schools—today, all dead or dying—were never very effective at turning out competent software engineers. Claude Pro may not only be the best educational resource under $20, it may be the best way to learn how to code that's ever existed.

There is still hope

Maybe you've read this far and the message hasn't resonated. Maybe it's triggered fears or worries you've had about AI. Maybe I've put you on the defensive and you think I'm full of shit right now. In any case, whether your organization isn't designed for this new era or you don't yet identify as a full-breadth developer, this section is for you.

Leaders: go hire a good agency

While my goal here is to coin a silly phrase to help us better communicate about the transformation happening around us, we've actually had a word for full-breadth developers all along: consultant.

And not because consultants are geniuses or something. It's because, as I learned when I interviewed at Google, if a full-breadth developer wants to do their best work, they need to exist outside the organization and work on contract. So it's no surprise that some of my favorite full-breadth consultants are among AI's most ambitious adopters. Not because AI is what's trending, but because our disposition is perfectly suited to get the most out of these new tools. We're witnessing their potential to improve how the world builds software firsthand.

When founding our consultancy Test Double in 2011, Todd Kaufman and I told anyone who would listen that our differentiator—our whole thing—was that we were business consultants who could write software. Technology is just a means to an end, and that end (at least if you expect to be paid) is to generate business value. Even as we started winning contracts with VC-backed companies who seemed to have an infinite money spigot, we would never break ground until we understood how our work was going to make or save our clients money. And whenever the numbers didn't add up, we'd push back until the return on investment for hiring Test Double was clear.

So if you're a leader at a company who has been caught unprepared for this new era of software development, my best advice is to hire an agency of full-breadth developers to work alongside your engineers. Use those experiences to encourage your best people to start thinking like they do. Observe them at work and prepare to blow up your job descriptions, interview processes, and career paths. If you want your business to thrive in what is quickly becoming a far more competitive landscape, you may be best off hitting reset on your human organization and starting over. Get smaller, stay flatter, and only add structure after the dust settles and repeatable patterns emerge.

Developers: congrats on your new job

A lot of developers are feeling scared and hopeless about the changes being wrought by all this. Yes, AI is being used as an excuse by executives to lay people off and pad their margins. Yes, how foundation models were trained was unethical and probably also illegal. Yes, hustle bros are running around making bullshit claims. Yes, almost every party involved has a reason to make exaggerated claims about AI.

All of that can be true, and it still doesn't matter. Your job as you knew it is gone.

If you want to keep getting paid, you may have been told to, "move up the value chain." If that sounds ambiguous and unclear, I'll put it more plainly: figure out how your employer makes money and position your ass directly in-between the corporate bank account and your customers' credit card information. The longer the sentence needed to explain how your job makes money for your employer, the further down the value chain you are and the more worried you should be. There's no sugar-coating it: you're probably going to have to push yourself way outside your comfort zone.

Get serious about learning and using these new tools. You will, like me, recoil at first. You will find, if you haven't already, that all these fancy AI tools are really bad at replacing you. That they fuck up constantly. Your new job starts by figuring out how to harness their capabilities anyway. You will gradually learn how to extract something that approximates how you would have done it yourself. Once you get over that hump, the job becomes figuring out how to scale it up. Three weeks ago I was a Cursor skeptic. Today, I'm utterly exhausted working with Claude Code, because I can't write new requirements fast enough to keep up with parallel workers across multiple worktrees.

As for making yourself more valuable to your employer, I'm not telling you to demand a new job overnight. But if you look to your job description as a shield to protect you from work you don't want to do… stop. Make it the new minimum baseline of expectations you place on yourself. Go out of your way to surprise and delight others by taking on as much as you and your AI supercomputer can handle. Do so in the direction of however the business makes its money. Sit down and try to calculate the return on investment of your individual efforts, and don't slow down until that number far exceeds the fully-loaded cost you represent to your employer.

Start living these values in how you show up at work. Nobody is going to appreciate it if you rudely push back on every feature request with, "oh yeah? How's it going to make us money?" But your manager will appreciate your asking how you can make a bigger impact. And they probably wouldn't be mad if you were to document and celebrate the ROI wins you notch along the way. Listen to what the company's leadership identifies as the most pressing challenges facing the business and don't be afraid to volunteer to be part of the solution.

All of this would have been good career advice ten years ago. It's not rocket science, it's just deeply uncomfortable for a lot of people.

Good game, programmers

Part of me is already mourning the end of the previous era. Some topics I spent years blogging, speaking, and building tools around are no longer relevant. Others that I've been harping on for years—obsessively-structured code organization and ruthlessly-consistent design patterns—are suddenly more valuable than ever. I'm still sorting out what's worth holding onto and what I should put back on the shelf.

As a person, I really hate change. I wish things could just settle down and stand still for a while. Alas.

If this post elicited strong feelings, please e-mail me and I will respond. If you find my perspective on this stuff useful, you might enjoy my podcast, Breaking Change. 💜

Anybody else have a recent MacBook Pro (M4 Pro in my case) for which the keyboard suddenly became really squeaky? Every time I hit the space bar, it's like nails on a chalkboard.

Using Claude Code makes me realize my trademark disposition that "nobody's work is nearly good enough and I can reflexively list 20 specific ways in which this code sucks" is finally valuable. REALLY valuable.

Huge unlock working with Claude Code: Ultrawide mode in Vision Pro's Mac Virtual Display. Keep a terminal off to the side and still have plenty of room for your own work. If Claude is worth $200/mo, this display experience is worth $3500.

A handy script for launching editors

Today, I want to share with you a handy edit script I use to launch my editor countless times each day. It can:

  • edit posse_party – will launch my editor with project ~/code/searls/posse_party
  • edit -e vim rails/rails – will change to the ~/code/rails/rails directory and run vim
  • edit testdouble/mo[TAB] – will auto-complete to edit testdouble/mocktail
  • edit emoruby – will, if not found locally, clone and open searls/emoruby

This script relies on following the convention of organizing working copies of projects in a GitHub <org>/<repo> format (under ~/code by default). I can override this and a few other things with environment variables:

  • CODE_DIR - defaults to "$HOME/code"
  • DEFAULT_ORG - defaults to "searls"
  • DEFAULT_EDITOR - defaults to cursor (for the moment)

I've been organizing my code like this for 15 years, but over the last year I've found myself bouncing between various AI tools so often that I finally bit the bullet to write a custom meta-launcher.

If you want something like this, you can do it yourself:

  1. Add the edit executable to a directory on your PATH
  2. Make sure edit is executable with chmod +x edit
  3. Download the edit.bash bash completions and put them somewhere
  4. In .profile or .bashrc or whatever, run source path/to/edit.bash

The rest of this post is basically a longer-form documentation of the script that you're welcome to peruse in lieu of a proper README.

What happens next will shock you…

How to subscribe to email newsletters via RSS

I have exactly one inbox for reading blogs and following news, and it's expressly not my e-mail client—it's my feed reader. (Looking for a recommendation? Here are some instructions on setting up NetNewsWire; for once, the best app is also the free and open source one.)

Anyway, with the rise of Substack and the trend for writers to eschew traditional web publishing in favor of e-mail newsletters, more and more publishers want to tangle their content up in your e-mail. Newsletters work because people will see them (so long as they ever check their e-mail…), whereas routinely visiting a web site requires a level of discipline that social media trained out of most people a decade ago.

But, if you're like me, and you want to reserve your e-mail for bidirectional communication with humans and prefer to read news at the time and pace of your choosing, did you know you can convert just about any e-mail newsletter into an RSS feed and follow that instead?

Many of us nerds have known about this for a while, and while various services have tried to monetize the same feature, it's hard to beat Kill the Newsletter: it doesn't require an account to set up and it's totally free.

How to convert an e-mail newsletter into a feed

Suppose you're signed up to the present author's free monthly newsletter, Searls of Wisdom, and you want to start reading it in a feed reader. (Also suppose that I do not already publish an RSS feed alternative, which I do).

Here's what you can do:

  1. Visit Kill the Newsletter and enter the human-readable title you want for the newsletter. In this case you might type Searls of Wisdom and and click Create Feed.

  2. This yields two generated strings: an e-mail address and a feed URL

  3. Copy the e-mail address (e.g. 1234@kill-the-newsletter.com) and subscribe to the newsletter via the publisher's web site, just as you would if you were giving them your real e-mail address

  4. Copy the URL (e.g. https://kill-the-newsletter.com/feeds/1234.xml) and subscribe to it in your feed reader, as if it was any normal RSS/Atom feed

  5. Confirm it's working by checking the feed in your RSS reader. Because this approach simply recasts e-mails into RSS entries, the first thing you see will probably be a welcome message or a confirmation link you'll need to click to verify your subscription

  6. Once it's working, if you'd previously subscribed to the newsletter with your personal e-mail address, unsubscribe from it and check it in your feed reader instead

That's it! Subscribing to a newsletter with a bogus-looking address so that a bogus-looking feeds starts spitting out articles is a little counter-intuitive, I admit, but I have faith in you.

(And remember, you don't need to do this for my newsletter, which already offers a feed you can just follow without the extra steps.)

Why is Kill the Newsletter free? How can any of this be sustainable? Nobody knows! Isn't the Internet cool?