
While I've been impressed with the advancements in software engineering LLMs over the past six months, it's hard for me to say that anything has been really paradigm shifting. What I mean by that is I feel increasingly comfortable offloading larger and more nuanced tasks to cloud or whatever the hottest LLM of the given week is, but it's not really changing how I approach building software or how I approach what my day looks like. It simply makes me faster and more productive. This has been a bit of a through line for me really since Copilot came out, which is that a lot of the iteration in this space feels like very strong and impressive incremental improvements, but with obvious jank, especially once you escape the lovely sandbox of small, un-nuanced apps without the accretion of technical debt or erstwhile design decisions or things that don't necessarily fit into a corpus trained on Stack Overflow and other such sites.
Outside of the realm of software engineering, I have found a tool that has changed the way I work on a day-to-day basis. I've used it for a grand sum of one month, so this is not exactly a gargantuan sample size — but the tool has held up and done remarkably well in such a way that my day viscerally feels different than it used to. This tool is called Aqua Voice.
Aqua Voice is a speech-to-text transcriber. It's an LLM thing, technically. I say technically because you don't really feel like you're interacting with an LLM. There's no chat paradigm. There's not a lot of losslessness there. It feels like the way LLM-powered search feels, which is here's this thing that has always been possible with varying degrees of fidelity, speed, and other trade-offs. Now it's just much better in ways that are hard to quantify but easy to internalize.
I spend a lot of my days writing things. I write blog posts (including this one!), long-winded pull request comments, and many, many emails to prospects, active customers, potential team members, and existing team members. This is frankly kind of tiring. I'm old now: my wrists and fingers aren't as bereft of carpal tunnel as they used to be, and I often feel myself intentionally limiting my communication because the effort in having to write out something that is nuanced or complicated and perhaps long-winded is just difficult to do. It's hard to really pour everything you have into writing a five-paragraph email when you know once you hit send there are 47 left.
And that brings me to Aqua Voice, which I am (as you might have guessed) using to write this very blog post, though I likely won't use it for others (my prose is verbose enough as-is, and this just makes it worse!). Aqua is just a really, really good transcriber. There's nothing else to say about it from a product or UX perspective, though maybe that'll change. Really, it's just an example of something being so, so good that you start to find places to use it where you wouldn't have even fathomed. And that's a marked difference from my previous experiences of using speech-to-text, where things were fine and solid, but you couldn't really trust it to be character perfect. You had to do a lot of massaging and editing after the fact, which, from a volume perspective, often made me conclude that it really wasn't worth it compared to just writing out stuff myself or sending a voice memo in very specific cases.
I want to give two examples of things that I am just straight up doing differently now compared to a week ago because I have this tool:
- Writing issue descriptions in Linear or whatever tool you want to use. I'm really bad at this in no small part because it's hard for me to jump a rat's nest of context and state and known knowns and known unknowns and all of the flotsam that is required to write up a good ticket. What ends up happening is 95% of the time, I will just write a ticket that has the title and no description, and if I end up taking it a couple of months down the line, hopefully, I remember what it's about. If someone else takes it, they have to kind of figure out what it means and maybe we just cancel it because I cannot remember. Now I'm just writing a bunch of ticket descriptions.
- The blank screen problem. It's regardless of what the artifact is, whether it's a changelog entry, a blog post, or a position paper. I often find there's this huge mental tax in just getting the first couple bullet points out the door. This tax feels heavier when I'm more tired or have a lot on my mind, or it's been a tricky day in some respect. And yet with Aqua, I can just start talking. Often the talking is kind of rambly, and I might want to go back and delete a paragraph or two — which is, of course, fine, because the hard work has already been completed (going from zero to non-zero words.)
I think so much of the AI discourse, such as it is, is prescriptivist: you kind of implicitly take a position before evaluating the thing, whether the thing is, you know, image generation or automatic code review or whatever (a failure mode of which I have certainly been guilty, on both sides!)
But to me, what feels like both the more ideologically pure and more pragmatic thing to do is pretend the AI does not exist. Pretend the LLM is an implementation detail to which you as a user are not privy, and evaluate the tool, whatever it is, on its own merits. This is where Aqua is really interesting to me — it could secretly be backed by nothing LLM-ish at all, and it's just really, really great from a performance perspective. I don't care. It's a super useful tool that makes my day easier, and I am grateful that it exists.
I wrote this essay around three weeks ago and let it sit for no other reason than laziness and a very long to-do list. In those past three weeks, I've continued to use Aqua.
Whether it's hedonic adaptation or some other cause, the experience has kind of gotten worse in the way that AI experiences sadly tend to. Aqua was rewriting my words if I was in a certain composer like Gmail. Suddenly, the sub-500 milliseconds wake time would drop the first sentence or two. How much of this is due to AI? How much of this is due to my own shifting demands for how snappy this should be? How much is just due to code being code or network connection being network connections? It is impossible to tell, which is one of the tricky things about this bit of software. I'm still happy enough with the experience to continue using it over any of its competitors, but the tools that I use for years on end are the ones that benefit from a confidence and muscle memory in their usage. And as I read back this essay, I am reminded that it is very hard for LLM tools to develop any sort of patina at all.

Do you ever get the feeling that there's something going on that we don't know about?
Fascinating film with a lot to chew on and a lot to admire. The first thing that comes to mind is that most of the actors are folks who I kind of think of as memes now. When I think of Mickey Rourke, I think of 30 Rock. I think of Kevin Bacon. I think of, well, Kevin Bacon. I think of Steve Guttenberg. I think of Party Down. Seeing them in this production a little north of 40 years ago, I am just absolutely blown away. It is perhaps obvious to commend a film called Diner for its diner scenes, but the ease and grace with which these five friends plot and chide and yap and shit talk and love each other is legitimately one of the most earnest and beautiful depictions of male friendship that I've ever seen in any medium. Watching these guys talk about sandwiches is cinema, and on those notes alone, I'm grateful.
The other thing that comes to mind is that for this being a hangout movie along the lines of Everybody Wants Some or Dazed and Confused, there's a melancholy and a gravity to this that feels honest and interesting and not at all heavy-handed. Everybody Wants Some is probably my favorite film, or at least was my favorite film in this genre, and that had a seriousness too, but it was a sun-drenched seriousness. There was a nostalgia for a simpler time in Linklater's life. Diner feels like, in many ways, the opposite argument, even if it is so vividly informed by Levinson's own memories and childhood. He is not trying to use the past to talk about the present; he is trying to use the past to remind us about what doesn't change. These people are happy and some of them are having a good time, but they don't all necessarily end the film in a better place than they start. Nor do they get the freeze frame happy ending that you'd expect out of this sort of 80s ensemble dramedy. The point in this film that I come back to and know will live in my head forever is, of course, the strip club scene. This is a cliché that shouldn't work. The idea that we've seen this sort of thing dozens and dozens of times before, before and after dinner, to varying degrees of success, I have always found it maudlin and fantastical. This is not how the world works. This is pointless and a little bit demeaning to the viewer, and yet I loved this scene. This might have been one of my favorite scenes of all time, not because of the music, though that worked well too. Seeing Billy, this guy who is introduced as the graduate in more senses than one, having figured it all out, being on the precipice of the greater world in a way that the other four guys haven't quite reached. Getting punched in the face a few times and breaking and letting that break not turn him into a shell but into a virtuoso pianist, letting the light displace everything.
What worked for me about this scene was Guttenberg, whose performance topped the class in what was a really, really great series of performances. He's delightful throughout this entire thing, but that one scene where he goes from a certain kind of very real 25-year-old despair into a man so caught up with joy and music and the understanding that life will still have its moments. I don't know how you come away from that scene without feeling 10 pounds lighter.
What are we to make of the fact that we never see Elyse's face? I think it's easy to read this with a certain backwards-facing criticism: that this film is not just a product of its time but a product of a product of its time. And I think that's not giving Levinson enough credit for the nuance he's trying to hit. We know everything about Elise that we need to know from her voice, warm and timid and half amused as she rattles off answers to NFL trivia questions. But the movie is not about Elise, nor is it about Beth, Carol, or Jean. It is about what it means to be one of the boys. And what it means to have yourself change or not change in rhythm and syncopation with the people you consider your whole life.
All good books are different but all bad books are exactly the same. I know this to be a fact because in my line of work I read a lot of bad books - books so bad they aren't even published, which is quite a feat, when you consider what is published. And what they all have in common, these bad books, be they novels or memoirs, is this: they don't ring true. I'm not saying that a good book is true necessarily, just that it feels true for the time you're reading it.
My first indication that The Ghost was going to be closer to the airport-bookstore end of the spectrum than the Le Carré end probably should have been when I saw that Audible had chosen an Americanized title to coincide with the movie adaptation (starring Pierce Brosnan—an actor I find impossible to associate with serious or meaningful sociopolitical inquiry). The book itself struggles to be as cynical as it thinks it is, though perhaps that's more a reflection of the last two decades than of the book's own quality.
I can, albeit faintly, recall a world in which the illegal detainment and torture of four non-combatants would be considered a civil rights violation and a political firebomb large enough to engulf the career of a British prime minister. Now, it feels like the sort of thing that would be buried on the fourth page of an article nobody read but everyone quote-tweeted.
Even setting aside the realism of the politics, there just isn't much substance here. None of the characters are interesting enough to have a personality beyond the three sentences they were assigned at birth. The narrator is exactly as smart or reckless as the scene requires, the charismatic but soulless politico is a cipher, and the wife is—spoiler alert—so obviously telegraphed as a master manipulator that the third-act twists land with a thud. There's a cutesiness in the faux-metafiction of the book's closing that feels dated, if mildly fun, and that's about it.
The book's best asset is its pace and propulsive readability. I finished it in three days, and the leanness of its prose at least leaves nothing lingering in your mouth—better than a bad taste, I suppose. But the best thrillers engage you both viscerally and intellectually; The Ghost is light on both counts, and what little viscera it has hasn't aged well.

I'm emerging from what already feels like, in retrospect, the hardest two months of my career and the hardest I've worked since I was an over-caffeinated undergrad whose diet consisted of PBR and Qdoba (Chipotle if I was in the mood to splurge). This isn't an oblique metaphor or a veiled reference to any one specific thing: it's simply been a very demanding stretch, filled with long nights, longer to-do lists, and stressful incidents. A certain malaise attacks me when I have so much to do and neither time or energy to do even a fraction of it: a recursive stress, a gray goo of Bad Vibes that seeps unchecked without exogenous intervention.
About that exogenous intervention.
Whenever I heard my friends talk about being a parent, the happiness always seemed abstract in much the same way that someone talks about summiting Everest: an accomplishment and pride more than a day-to-day feeling. That’s not what it is: the happiness is visceral, even if trying to speak to it diminishes its power. What I am trying to say is this: every morning, I am the first person Lucy sees, and whether her eyes are hooded by fatigue or her cheeks reddened and dampened with tears, she invariably forgets whatever first-order things are happening and locks her eyes with mine and smiles. This is an event that buoys an entire day (or week, or month.)
Last weekend, we got back from a lovely vacation with my lovely family. We were gone for a week and change, and my in-laws graciously offered to watch Telly.
When they dropped him back off the following day, the thing that finally pierced me and turned me back into myself was not his joy at seeing us, nor mine at seeing him, but Lucy’s joy at seeing him: a joy so bright and perfect that it spawned the loudest and squeakiest shriek of delight I have heard from her and perhaps from anyone. That single noise washed away the past six weeks and untied a few knots in my back.
All of this is to say I have been gone for a while; I missed this, and I'm happy to be back. Thank you for your patience, whether you've been waiting for an email or a text or a RSS notification. I promise I'm speeding towards you as fast as I can, holding a child who through some miracle of physics makes me lighter for carrying her.
One of the most useful and janky internal tools we have in Buttondown’s codebase is a codegen pipeline called “autogen”. There is nothing “auto” about autogen: it is a series of scripts that munges a bunch of data into a bunch of different formats, to generate things like our API clients and code snippets and storybooks. Some of this data is stateful, and therefore requires a database, and therefore requires migrations — you see how this kind of thing can grow somewhat labrynthine.
Each individual script is pretty simple, but as we’ve found more and more things to glom onto autogen. This, to be clear, is a good thing. It’s really nice to have automatic, consistent data and types everywhere, so that we literally cannot change the API without also pushing a concomitant change to the API docs. With each glom, though, the wall-clock time of running autogen increases — and so I found myself staring down the barrel at a 50second script running whenever we wanted to make any sort of non-trivial change to our schema.
Fifty seconds was too many seconds. I set a budget of ten seconds — still a long time, but significantly less onerous — and began digging in at low-hanging fruit. There was a lot. A few that come to mind:
- We split up our
vite
config so we could only run the portion that we needed (cross-piling and minifying our CSS bundles;
- We disabled all Sentry and perf-tracing stuff that was getting enabled as part of the standard build;
- We no-oped all of the Python-land data generation if it was already there, since that stateful data didn’t change very often.
This was all great, but we were still left with 15 seconds of wall clock time. Profiling each individual cog in the script revealed that the problem was essentially “it’s Python”: four items in the script ran Django commands, and just spinning up the Django process and running autodiscovery took around two seconds. Ouch!
The impulse was to cut down that runtime. A great post by Adam led us to discover the biggest culprit was our Stripe imports, and we timeboxed a bit of time to try and get rid of them, either by deferring the imports or excising the library; neither seemed particularly feasible.
Then, suddenly, the answer seemed obvious. If we have four scripts where the fixed cost of invoking Django is the long pole, why not simply combine the scripts?
And that’s exactly what we did:
if len(sys.argv) > 1 and "," in sys.argv[1]:
commands = sys.argv[1].split(",")
original_argv = sys.argv.copy()
for command in commands:
sys.argv[1] = command
execute_from_command_line(sys.argv)
sys.argv = original_argv
else:
execute_from_command_line(sys.argv)
A fun romp that I’m surprised I hadn’t heard of sooner (thanks owed to The Big Picture’s 1982 Movie Draft pod) and it checks all of my boxes: a simultaneous love letter and pastiche to the murder mystery. It is obvious in retrospect that Knives Out owes a lot to Deathtrap, as does (much less successfully) Skin.
Deathtrap is a play, and it feels perhaps unfair to criticize the performances for being too theatrical: Dyan Cannon and Irene Worth are game and funny but do not feel real in any sense of the word, which works well in the comedic scenes and less so when Deathtrap wants you to take it earnestly as a thriller. (SImilarly, Caine is great in the first third of the movie as someone Going Through Things, and then every aspect of his role recedes into the obvious.) But Reeve — who I don’t think I’ve ever seen as someone other than Superman — is the star of the show, with a performance that wins and convinces every step of the way.
(Also, a great ending, even more than a good ending.)

I’m coming at White Lotus a little bit after the zeitgeist; as I write this, the third season is currently airing, and I understand the metatext (each season a new location, with some overlapping characters) in a way the original viewers of the first season probably did not. And it’s hard not to enjoy the framing device! It’s a great canvas that Mike White has engineered for himself: six hours is a good amount of time to stay with a series of folks, long but not too long, and its easy to get interesting actors who might not otherwise be interested in committing to an HBO series for fear of overcommitting themselves.
This being a miniseries (or at least miniseries-series) also helps in that, frankly, I can’t imagine spending that much more time with many of these characters who all feel either insufferably one-note or insufferably two-note. (That is the point, you might argue: it is a satire, meant to reveal the human condition as through the prism of the upper class. I would argue back: okay, I get it.)
Still, it’s a good watch. Mike White has a flair for both dialogue and casting; to the extent that this show gets brought up in the same vein as Succession (which I think is trying to deal with bigger questions and ideas), these scripts (perhaps even more so. than Succession) are modern, surgical, and deeply clever, and the actors clearly love them.
Coolidge gets (got?) a lot of the attention for reviving her career in a delightfully lampshaded performance, but to me the hallmark of the show was Connie Britton as Supermom. There’s a sincerity in her performance (which, like Coolidge, feels somewhat in conversation with her previous role in Friday Night Lights) and her ability to switch from unflappable and warm to, in alternating (and incredible) scenes sharply bitter and deeply, shatteringly, unloved.
Everything you’ve been doing is bullshit. Underlying every one of my stories was the traditional belief that you’re in a democracy and the power in a democracy comes from being elected. Yet here was a man, Robert Moses, who had never been elected to anything, and he had enough power to turn around a whole state government in one day. And he’s had this power for more than forty years, and you, Bob Caro, who are supposed to be writing about political power and explaining it, you have no idea where he got this power. And, thinking about it later, I realized: and neither does anybody else.
You’re never going to achieve what you want to, Mr. Caro, if you don’t stop thinking with your fingers.
The women who lived that life, a life before electricity — millions and millions of them — of course are almost all dead, and they can’t tell their story to their descendants If in even small measure I told it for them, these women of the American frontier, and in order to accomplish that, ‘The Path to Power’ took a couple of years longer to write, well — so what?
everyone else, minds rotted from overconsumption of narrative media: conviction! passion! belief! / me, only reading nonfiction and poetry (a kind of nonfiction): administrative capacity
— Alex Williams
I've said many times now that Robert Caro has ruined me for the vast majority of non-fiction ; I think it is only recently that I've really internalized the fact Robert Caro more than any other writer, thinker, or public intellectual has changed my understanding of the world and my place therein. Caro is a crusader but not a zealot: he believes in the possibility of institutions to make great things, and he thinks it is important to understand how those institutions operate and the process by which individuals can capture, change, and subvert those institutions. He understands — and teaches the reader — that things do not Happen, but are part of a fractal and infinite web of cause and effect, and that the footnotes of history — the footnotes of life — are littered with fascinating and terrible and honorable people, all of whom had loved and lived and grieved and died — sometimes on the periphery, sometimes in the far far distance.
It was hard for me to get around to reading Working, despite all this. This book, from a distance, felt like the kind of — I don't want to be unkind and call it a cash grab, but maybe a collection of b-sides from an artist spending a long time in the studio, something that doesn't detract from the ouevre necessarily but still feels somewhat cheap in the holding. (I am thinking specifically of Murakami when I say this, who I still love dearly but the guy has never seen a quick-hit book deal he doesn't like.)
And, to be clear, Working is very much that kind of book. I think it's fair to only say half of it is truly new material from Caro; a third of it is a collage of (good, but repetitive) interviews and press clippings from the past few decades, and a sixth of it is passages from his earlier (and perfect) work.
The new material, though! It is reductive (Caro's first job; how Caro moved to the Hill Country; why Caro takes so long between books; Caro's writing routine) and somewhat anodyne, and I don't really care. I think everything Caro publishes is valuable; I think reading this book felt akin to reading a blog of his, and in that light I was happy to do so.
Ain't no way to keep a band together. Bands come and go. You got to keep on playin', no matter with who.
I'm Guy Patterson, I'm from Erie, Pennsylvania, I'm in a band called The Wonders and we just cut a record, we're out here on the coast and I play the drums and I have all your records well not all of them but a lot of them but ah at least I did until some of them got swiped when I was stationed in Germany and you were playing in Germany at the time that I was stationed there, but you know what I couldn't see you because you were playing in Hamburg and I was stationed in Munich but I listen to your records and I think you're great.
There is a sheer competence to That Thing You Do!, a fim that is slightly overlong but capable from start to finish. No beat is surprising; no scene is revelatory; everything moves with a grace and light-chuckle ease like a particularly well-maintained carnival ride. The surrounding cast are all doing a great job (especially Liv Tyler, who does her best with a script that requires her to sit around and do nothing but project and collect unrequited love); Tom Everett Scott gives an absolute lights-out performance that makes me surprised that this was not his ticket to a broader stardom.
Does this movie share any insights about fame, passion, or the human condition? Not really. There's a child-like sensibility to the entire thing, a refusal to budge from the American Storybook narrative arc that I at this point readily associate with Tom Hanks on either side of the camaera. But it is well-done, and provides relief, and purports to do little else than that. (And the title track is a banger!)
3/14/2025: Updated the snippet to include imports and remove some unused stuff. Thanks, Andy!
Here is a confession: I am a very strong proponent of a robust test suite being perhaps the single most important asset of a codebase, but when it comes to auxiliary services like admin sites or CLIs when it comes to testing I tend to ask for forgiveness more than I ask for permission. Django's admin site is no different: and, because Django's admin DSL is very magic-string-y, there's a lot of stuff that never gets caught by CI or mypy until a lovely CS agent informs me that something is blowing up in their face.
Take this example, which bites me more often than I care to admit:
from django.contrib import admin
from stripe.models import StripeCustomer
class StripeCustomer(models.Model):
id = models.CharField(max_length=100, unique=True)
username = models.CharField(max_length=100, unique=True)
email_address = models.EmailField()
creation_date = models.DateTimeField(auto_now=True)
@admin.register(StripeCustomer)
class StripeCustomerAdmin(admin.ModelAdmin):
list_display = (
"id",
"username",
"email",
"creation_date",
)
search_fields = (
"username",
"email",
)
One thing that has made my life slightly easier in this respect is a parametric test that just makes sure we can render the empty state for every single admin view. Code snippet first, explanation after:
from django.test import Client
from django.urls import get_resolver, reverse
from django.urls.resolvers import URLResolver
def extract_routes(resolver: URLResolver) -> iter[str]:
keys = [key for key in resolver.reverse_dict.keys() if isinstance(key, str)]
for key in keys:
yield key
for key, (prefix, subresolver) in resolver.namespace_dict.items():
for route in extract_routes(subresolver):
yield f"{key}:{route.name}"
def is_django_admin_route(route_name: str):
return route_name.split(":").endswith("changelist")
ADMIN_URL_ROUTE = "buttondown.urls.admin"
DJANGO_ADMIN_CHANGELIST_ROUTES = [
route.name for route in extract_routes(get_resolver(ADMIN_URL_ROUTE))
if is_django_admin_route(route.name)
]
@pytest.fixture
def superuser_client(superuser: User, client: Client) -> Client:
client.force_login(superuser)
return client
@pytest.mark.parametrize(
"url",
DJANGO_ADMIN_CHANGELIST_ROUTES
)
def test_can_render_route(superuser_client: Any, url: str) -> None:
url = reverse(url, args=[])
response = superuser_client.get(url)
assert response.status_code == 200
Okay, a bit of a mouthful, but the final test itself is very clean and tidy and catches a lot of stuff.
- That
extract_routes
implementation looks scary and magical, and it is — I use a more robust implementation in django-typescript-routes
, which itself we gratefully purloined from django-js-reverse
. Lots of scary indexing, but its held up well for a while.
- The fixture and
parametrize
assumes usage of pytest
(you should use pytest!) but it's trivially rewritable to use subTest
instead.
A strategy should hurt. / Leadership is disappointing people at a rate they can absorb.
First, let my biases be explicit: while I didn’t work closely with Claire during my time at Stripe I certainly enjoyed my time in her orbit. My working understanding of her was largely in concordance of her presentation in the introduction: extraordinarily competent, with an ability to context switch from granular to big-picture, deeply empathetic, entertaining and charming. She was a great executive, and I was saddened to see her step back from her role as COO.
That being said: who is this book for? Hughes Johnson attempts to give a very explicit answer early on, joking that “yes, you should do weekly chats with your direct reports, but if you need to know that then this is not the book for you”. And yet, this book is presented as a very practical guide:
There’s a Pablo Picasso quote we like to repeat at Stripe: “When art critics get together, they talk about Form and Structure and Meaning. When painters get together, they talk about where you can buy cheap turpentine.” Sometimes you want to read a book about Picasso’s life, and sometimes you just want to know where to buy the cheapest turpentine. Consider this the latter: an insider’s guide to management turpentine.
If I were to be slightly catty, I would say this is less of an insider’s guide to turpentine and more an explanation on: here is why turpentine is important, here are some ways other artists have used turpentine, here are some challenges that other people have faced when dealing with a lot of turpentine. The entire book feels cursory, and I use that word deliberately: Hughes Johnson never knows quite what level of specificity she wants to dwell, and instead flits around from topic to topic — nothing she says is wrong or even, I think, controversial, but each of the major points (goals/planning, team structure, hiring, and perf) are neither thorough enough to be a primer nor idiosyncratic enough to be novel.
The book is buttressed by a series of sidebars that are largely “here’s how it worked at Stripe.” A lot of these were fun trips down memory lane; some of them were, to a person who lived through them , slightly undermining Claire’s theses:
- She cites Stripe Home as an example of Stripe’s outsized investment in internal tooling, even though Home was a hackathon project and its running joke during my tenrue was that its staffing was HDD — hackathon-driven development, because Stripe could never actually devote resources to it;
- She cites Stripe’s (now-deprecated, I assume) “TPP” as a way of rolling up many disparate and discrete goals into a legible shortlist of 3—5 true priorities for an organization; when I left Stripe, TPP had ballooned to twenty, and a long-standing joke was whether or not those twenty priorities were stack-ranked or not.
I bring up these nits self-servingly, to a certain extent. My already-foggy memory of my time at Stripe was that its late-period success was less about the systems and processes it developed and more about the fact that its culture and talent base was so overwhelmingly strong (in terms of empathy, in terms of agency, in terms of ability) that folks overcame the myriad systems and processes. I don't think Stripe's perf or resource planning is that much different than, say, Amazon's — and even if I don't like Amazon's system, Working Backwards is a much better and specific resource for implementing that kind of thing, and I didn't like that book either.
Maybe this kind of book is simply Not For Me. I think organizational design and growth is a really tricky, really nebulous subject that resists easy text (High Output Management being a singular exception, and of course cited heavily in Scaling People.) Many things are either so obvious that if you need a book to tell you how to do them you're probably not in the right role or so nuanced and specific that any broader discussion is worthlessly anodyne.
All of this to say: skip this book, perhaps skip all of these books and listen to some of her interviews instead. They’ll be more informative, and more real.
When we added support for complex filtering in Buttondown, I spent a long time trying to come up with a schema for filters that felt sufficiently ergonomic and future-proof. I had a few constraints, all of which were reasonable:
- It needed to be JSON-serializable, and trivially parsable by both the front-end and back-end.
- It needed to be arbitrarily extendible across a number of domains (you could filter subscribers, but also you might want to filter emails or other models.)
- It needed to be able to handle both and and or logic (folks tagged foo and bar as well as folded tagged foo or bar).
- It needed to handle nested logic (folks tagged foo and folks tagged bar or baz.)
The solution I landed upon is not, I’m sure, a novel one, but googling “recursive filter schema” was unsuccessful and I am really happy with the result so here it is in case you need something like this:
@dataclass
class FilterGroup:
filters: list[Filter]
groups: list[FilterGroup]
predicate: "and" | "or"
@dataclass
class Filter:
field: str
operator: "less_than" | "greater_than" | "equals" | "not_equals" | "contains" | "not_contains"
value: str
And there you have it. Simple, easily serializable/type-safe, can handle everything you throw at it.
For example, a filter for all folks younger than 18 or older than 60 and retired:
FilterGroup(
predicate="or",
filters=[
Field(
field="age",
operator="less_than",
value="18"
)
],
groups=[
FilterGroup(
predicate="and",
filters=[
Field(
field="age",
operator="greater_than",
value="60"
),
Field(
field="status",
operator="equals",
value="retired"
)
]
groups=[],
)
]
)
“Making art was really about the problem of the soul, of losing it. It was a technique for inhabiting the world. For not dissolving into it.”
All you can do is involve yourself totally in your own life, your own moment, Lonzi said. And when we feel pessimism crouching on our shoulders like a stinking vulture, he said, we banish it, we smother it with optimism. We want, and our want kills doom.
I (unlike much of the NYRB cognoscenti, apparently) really enjoyed Creation Lake last fall and resolved to explore more of Kushner's work — a resolution which led me to The Flamethrowers, her debut in spirit if not in fact, a book which threw her into a bit of a national spotlight as an Important Vital Female Writer.
Perhaps with a decade of hindsight, it is easy to understand why this book — and Kushner's style — was so hotly discussed. This book has the whiff of a high-budget prestige post-Mad Men series: big ideas, a smorgasboard of perspectives (literal and figurative), set pieces galore, a period piece that feels very much in conversation with What Is Going On Today, writing that is interesting and dense. It is hard not to come away from The Flamethrowers with a strong conviction that Kushner is very smart and very interesting and has a lot to say.
And yet. Perhaps it is indicative more of the literary movement of the past decade more than of this novel, but: using 1970's New York as a backdrop for discussions of broader societal issues feels old hat and, moreover, boring. Skewering countercultural art scions as largely bourgeoisie sons of bourgeoisie parents is old hat and, moreover, boring. Listening to Harper's essays about the relationship between art and performance and reality, thinly rewritten to be monologues from thinly-written characters is old hat and, moreover, boring.
This is a shame because when Kushner leaves the relative comfort of the framing device of urban-flight New York and explores more interesting points of view (post-war Italy; the Bonneville flats) the book comes alive. She is witty and idiosyncratic and — if not mean, cutting in a way that makes her writing feel so vivacious in a way that Cusk and others in her vaguely-modernist cohort feel lacking in my esteem. There are images of real beauty in The Flamethrowers; it is also very clearly a work from a writer who has not learned to carve herself lean, and I think that's where Creation Lake proves itself the stronger work.
If there's been one through line in changes to Buttondown's architecture over the past six months or so, it's been the removal and consolidation of dependencies: on the front-end, back-end, and in paid services. I built our own very spartan version of Metabase, Notion, and Storybook; we vended a half-dozen or so Django packages that were not worth the overhead of pulling from PyPI (and rewrote another half-dozen or so, which we will open-source in due time); we ripped out c3, our visualization library, and built our own; we ripped out vuedraggable
and a headlessui
and a slew more of otherwise-underwhelming frontend packages in favor of purpose-built (faster, smaller, less-flexible) versions.
There are a few reasons for this:
- Both Buttondown as an application and I as a developer have now been around long enough to be scarred by big ecosystem changes. Python has gone through both the 2.x to 3.x transition and, more recently, the untyped to typed transition; Vue has gone from 2.x to 3.x. The academic problem of "what happens if this language completely changes?" is no longer academic, and packages that we installed back in 2018 slowly succumbed to bitrot.
- It's more obvious to me now than a few years ago that pulling in dependencies incurs a non-trivial learning cost for folks paratrooping into the codebase. A wrapper library around
fetch
might be marginally easier to invoke once you get used to it, but it's a meaningful bump in the learning curve to adapt to it for the first time.
- It is easier than ever to build 60% of a tool, which is problematic in many respects but useful if you know exactly which 60% you care about. (Internal tools like Storybook or Metabase are great examples of this. It was a fun and trivial exercise to get Claude to build a tool that did everything I wanted Metabase to do, and save me $120/mo in the process.)
We still use a lot of very heavy, very complex stuff that we're very happy with. Our editor sits on top of tiptap
(and therefore ProseMirror
); we use marked
and turndown
liberally, because they're fast and robust. On the Python side, our number of non-infrastructural packages is smaller but still meaningful (beautifulsoup
, for instance, and django-allauth
/ django-anymail
which are both worth their weight in gold). But the bar for pulling in a small dependency is much higher than it was, say, twelve months ago.

After many wonderful years of working out of my home office (see Workspaces), I've now "expanded" into an office of my own. 406 W Franklin St #201 is now the Richmond-area headquarters of Buttondown. Send me gifts!
The move is a bittersweet one; it was a great joy to be so close to Haley and Lucy (and, of course, Telly), and the flexibility of being able to hop off a call and then take the dog for a walk or hold Lucy for a while was very, very nice.
At the same time, for the first time in my life that flexibility has become a little bit of a burden! It turns out it is very hard to concentrate on responding to emails when your alternative is to play with your daughter giggling in the adjoining room; similarly, as Buttondown grows and as more and more of my time is spent on calls, it turns out long-winded demos and onboarding calls are logistically trickier when it is Nap Time a scant six feet away. And, beyond that, it's felt harder and harder to turn my brain off for the day: when there is always more work to be done, it's hard not to poke away at a stubborn pull request or jot down some strategy notes instead of being more present for my family (or even for myself, in a non-work capacity.)
So, I leased an office. The space is pretty cool: it's downtown in the sweet spot of a little more than a mile away from the house: trivially walkable (or bikeable, as the above photo suggests) but far enough away to give me a good bit of mental space. The building is an old manor (turned dormitory, turned office building). I've got a bay window with plenty of light but no views; I've got a nice ethernet connection and a Mac Mini with very few things installed; I've got a big Ikea desk and a printer; I've got an alarm on my phone for 4:50pm, informing me that it's time to go home, where my world becomes once again lively and lovely, full of noise and joy and laughter.
I love this bit from Paul Graham on pattern-matching founders:
Though the most successful founders are usually good people, they tend to have a piratical gleam in their eye. They're not Goody Two-Shoes type good. Morally, they care about getting the big questions right, but not about observing proprieties. That's why I'd use the word naughty rather than evil. They delight in breaking rules, but not rules that matter. This quality may be redundant though; it may be implied by imagination.
I love this not because I agree with the sentiment, and in fact I think you can point to a lot of Icarian tendencies (and perhaps pervasive industry-wide rot) as germinating in this naughtiness, but because it is a specific and opinionated characteristic — as opposed to, like, "determined!" and "smart!" and "driven!" It's novel, it's a characteristic with a viewpoint around which reasonable people can agree/disagree.
Antimetal is not a YC company, but it certainly embodies naughtiness. Its founder made a large hullabaloo about trying to commission "the highest quality publicly available version" of the Facebook Red Book, but of course couldn't resist a tiny act of digital vandalism by inserting its own branding into the scan.
Does this matter, on a grand scale? Is this an evil act? Probably not, but certainly a naughty one.
Buttondown in 2025 has reached a sort of escape velocity, less in terms of growth per ce (though also that!) and more in terms of the median user being very far way from my orbit: these users are less technical and more wary than the ones I am used to onboarding.
Users of new tools — especially tools that must be entrusted with important data — are wary these days. They're wary of pivots to video, of shifting business models and sudden price hikes and emails announcing that the curtain is coming down this time next week. It is unfortunate that this wariness — a kind of cynicism — is not only pervasive but entirely rational. Anyone who has used anything new over the past few years has a high number of since-shuttered apps that they trusted with their time and money and data and energy, only to be rewarded with an "Our Incredible Journey" email.
At a high level, I think this stems from the same vein as naughtiness: a tendency to think of systems and expectations as something to be overcome, as social contracts as a thing to be voided or ignored rather than bolstered.
We get a lot of questions that boil down to "why should I trust [Buttondown]?" The blithe answer — the one that I generally try not to give, even though I think it's the most rigorous and correct one — is that, well, you shouldn't — insofaras you should only trust any company as much as you can exfiltrate your data. We've made a lot of decisions in service of decades-long continuity; we're cash-flow positive, we're stable and robust; our incentives are aligned with yours. But, more than that, the email space is novel in that you can always pack up your entire dataset — archives, addresses, et al — and ship them off to a competitor. You shouldn't need to trust us; you should find us valuable enough to be worth keeping around.
Email is also unique in that it's, by software standards, a very mature industry — one with a long history already. Many of my customers come with data exports from tools that they started using fifteen years ago; prospects who I reached out to in 2019 follow up in 2025.
After twelve months of active usage, we ask every paying customer a single question: "why are you still using Buttondown?" There are two answers whose volume dwarf the rest:
- Because the customer support is really good.
- Because I haven't had an experience that has prompted me to look elsewhere.
Customer goodwill is a real asset; it is one that will probably become more valuable over the next decade, as other software-shaped assets start to become devalued. It feels almost anodyne to say "it is in a company's best interest to do right by their customers", but our low churn and high unpaid growth in a space uniquely defined by lack of vendor lock-in is perhaps a sign that being nice is an undervalued strategy. And "being nice" in a meaningful sense is, like "being naughty", something that gets baked into an organization's culture very early and very deeply.

There are a handful of brilliant-yet-relatively-obscure works whose relative obscurity I ascribe almost entirely to the vagaries of chance, or at least "chance" in the way we think of, say, inclement weather. A sixty percent chance of snow is not 60% as defined like a constant in a program, but as an artifact of hundreds of thousands of variables and interactions that are impossible to understand or internalize in any systemic and coherent way. (Happy Endings, my favorite sitcom of all time, is a show that — if you replayed the universe ten times over — would have become a smash hit at least once or twice, but the dice just never quite landed on the right number.)
And it is partially through this lens that I find Pantheon so interesting, at least at a meta-textual level. But first, let's talk about the show itself.
Pantheon is a terrific show, screaming right out of the gate with a competence and ambition that I am shocked I had never heard of it before, and shocked still that it's not an ur-text for science fiction fans everywhere. Developed from a Ken Liu series of short stories , Pantheon draws inspiration (and lampshades it nicely) from everything from Serial Experiments Lain and Ghost in the Shell to more American fare like The Matrix and Blade Runner. There are works of science fiction that are obviously dumb and uninterested in in anything but aesthetic; this is, I'd say, the exact opposite. It is very interested in exploring ideas and themes, and doing so in a way that doesn't feel laborious (like parts of the aforementioned Lain can) nor facile (like Devs, which shares a lot of DNA with this show). Characters are written and voiced extremely well; the show deftly balances the Really Big Ideas it has about where the world might be going and the very real personalities of the folks impacted by it.
You should watch Pantheon; very few people have. It was released on AMC+, a streaming service that I did not even know existed, and then moved to Netflix a few years later. Perhaps if Netflix was the original distributor, this would have been the kind of smash hit that, say, Invincible became; it certainly seems poised to be embedded deep within the zeitgeist, and yet it toils away in cult-classic obscurity.
We live in a weird time, content-wise. There was a brief five-year period in which almost every media corporation was happy to throw unfathomable amounts of capital at creators of all repute under the vague promise of "amassing a catalog", and that was immediately followed by our current era where these media corporations are outright incentivized to completely hide some of their work so as to declare it a loss and harvest some tax breaks. I suspect there are dozens of Pantheons flitting around, buoyed by barely-there licensing deals, glittering gems waiting to be discovered and preserved.
Buttondown's core application is a Django app, and a fairly long-lived one at that — it was, until recently, sporting around seven hundred migration files (five hundred of which were in emails
, the "main" module of the app). An engineer pointed out that the majority of our five minute backend test suite was spent not even running the tests but just setting up the database and running all of these migrations in parallel.
I had been procrastinating squashing migrations for a while; the last time I did so was around two years ago, when I was being careful to the point of agony by using the official squash tooling offered by Django. Django's official squashing mechanism is clever, but tends to fall down when you have cross-module dependencies, and I lost an entire afternoon to trying to massage things into a workable state.
This time, I went with a different tactic: just delete the damn things and start over. (This is something that is inconsiderate if you have lots of folks working on the codebase or you're letting folks self-host the codebase; neither of these apply to us.)
rm rf **/migrations/*
worked well for speeding up the test suite, but it was insufficient for actually handling things in production. For this, I borrowed a snippet from django-zero-migrations (a library around essentially the same concept):
from django.core.management import call_command
from django.db.migrations.recorder import MigrationRecorder
MigrationRecorder.Migration.objects.all().delete()
call_command("migrate", fake=True)
And voila. No fuss, no downtime. Deployments are faster; CI is much faster; the codebase is 24K lines lighter. There was no second shoe.
If you were like me 24 hours ago, trying to find some vague permission from a stranger to do this the janky way: consider the permission granted. Just take a snapshot of your database beforehand just in case, and rimraf away.
Humane Inc. started in 2018; it raised around $250M over five years before coming out of stealth mode with an AI pin that people did not like very much, and today they announced their sale (or, to be specific, the sale of their patent library) to HP for $116M.
Here is a hype video from July 2022, over a year before they ever announced — let alone released! — a product.
I don't think we draw many interesting lessons from Humane. They feel like a relic from a younger, more Juicero-drenched era: even while they were in stealth mode there was an obvious perfume of vaporwave about them, and I think there's nothing inherently wrong with taking big, ambitious, VC-subsidized swings at gnarly problems that don't quite pan out.
The two relatively novel things that come to mind are:
- "Huge amounts of capital" is a good way to finance infrastructure, and a poor way to finance design.
- Any company that releases a $700 product for consumers and then neuters it with two-weeks' notice for non-existential reasons is, in a meaningful way, evil.

I have a soft spot for these sort of twist-within-a-twist-within-a-twist films, both at a certain intellectual level and at a visceral "oho, they tricked me!" level. It is fun to be hoodwinked by a magician who knows his audience and knows sleight-of-hand.
Last year I watched two of Mamet's entries into this canon — The Spanish Prisoner and House of Games — and of the former (which I liked more of the two) I wrote:
The only fault I can assign it is that it lacks any sort of emotional resonance, which sounds like a more biting criticism than I mean it to be.
The Spanish Prisoner was a perfectly-constructed puzzle of a film that took a brilliant plot (with every final-act twist feeling earned) and added a dagger-sharp script and little else, accomplishing exactly what it set out to do and little else.
Wild Things, on the other hand, feels like a funhouse mirror of the same general thesis. There is no precision, no brilliant script, no asexual cynicism: it is pure, sweaty, roiling id, it is Matt Dillon writing SEXCRIMES on a chalkboard, it is Neve Campbell making out with Denise Richards , it is not thinking about anything too hard.
The reveal of the initial con — Matt and Denise were in on it from the start! — is a great little twist, and I think a more succesful version of this film could have stopped there with the hijinks and then proceed to a more conventional answer to "okay, what happens next?". It is the hubris of the successive twists — the penultimate one, of Kevin Bacon secretly being on it too from the start — that I think takes this film out of its trappings and forces you to realize just how harebrained the entire enterprise is.
And this is a shame, because there are successful moments. The film sells the setting — swampy, overhumid Florida — extremely well, and individual performances (in particular Bill Murray in an early "caricature of a caricature"-type role) work well. But the worst thing a film can do is beggar belief, and Wild Things refuses to let you take it seriously.