Irrational Exuberancehttps://lethain.com/Recent content on Irrational ExuberanceHugo -- gohugo.ioen-usWill LarsonMon, 15 Jun 2026 06:00:00 -0700Revised rules of engineering leadership.https://lethain.com/revised-rules-of-engineering-leadership/Mon, 15 Jun 2026 06:00:00 -0700https://lethain.com/revised-rules-of-engineering-leadership/<p>From early 2014 through late 2020, I was working in <a href="https://lethain.com/productivity-in-the-age-of-hypergrowth/">hypergrowth</a> environments, which are challenging, but also educational. The most valuable feature of hypergrowth is that your mistakes reveal themselves next month rather than next year, because things go wrong very loudly when you&rsquo;re moving fast. I&rsquo;ve been thinking a lot about hypergrowth recently, because Imprint&rsquo;s business is growing quickly and we did a large batch of hiring last year, but also because the AI-tooling shift has changed the pace at which it&rsquo;s possible to work.</p> <p>This post documents the new rules I&rsquo;ve revised my approach to engineering leadership around, and then talks through the specific projects I&rsquo;ve worked on over the past year that caused me to believe in these rules.</p> <h2 id="revised-rules">Revised rules</h2> <ol> <li> <p><strong><a href="https://lethain.com/migrations/">Migrations</a> can be done by an individual rather than a team.</strong> Even complex, large changes can be 95% owned by the driving individual or team, and done in 10% of the time. As the initial cost of migrations goes down, the reward/penalty of each migration&rsquo;s quality goes up: even small sharp edges will break your colleagues&rsquo; mental models about the software you co-maintain. The impact of individual judgment on your company has never been higher.</p> </li> <li> <p><strong>While 1st-pass code is nearly free, the cost of working code depends on your development harness, and is not free.</strong> We&rsquo;re in an era when many companies say that <em>everyone</em> should be writing code, however our experience is that writing code that works well, while avoiding messy edgecases, remains difficult. Just how difficult remains a factor of your development harness, e.g. your tests, CI/CD, validation environments, preview-ability of changes, and so on. While I personally don&rsquo;t imagine it&rsquo;s valuable for most folks at a company to be contributing code, I suspect that most disagreement about that topic is actually a miscommunication: even at a company where &ldquo;everyone codes&rdquo;, the marketing team isn&rsquo;t reducing allocations in your servers, instead it&rsquo;s about whether there is a safe boundary where they <em>can</em> participate. (Much like a SaaS product that allows customization by writing software.)</p> <p>The good news is that this means the things that were most valuable to speed up engineering two years ago are still the things that are most valuable to speed them up today.</p> </li> <li> <p><strong>Optimize the base-case of process for agents.</strong> Most steps of most processes can be fully automated in most cases. With the right harnesses, the right controls, domain context, and good judgment in their designers, you can fully automate the base-case of most processes in modern technology companies. For example, the base case of code review from a human is slower and less effective than a good harness&rsquo; code review. Of course, the harness will miss things, but so will human reviewers, and most areas are relatively safe to make changes. Of course, there are some higher risk areas, where this doesn&rsquo;t hold true. By effectively capturing these distinctions properly, we can go much faster without introducing risk. By failing to capture these distinctions, we&rsquo;ll create innumerable problems for ourselves.</p> <p>As a corollary, I think most planning processes like weekly or bi-weekly sprints are operating at too low an altitude. Humans planning together still matters, but should be operating at a higher level.</p> </li> <li> <p><strong>Durable, high-ownership teams with domain-context are even more important.</strong> One of my biggest lessons at Uber was that <a href="https://lethain.com/durably-excellent-teams/">persistent, durable teams work magic</a> by accumulating domain-context, building a sense of camaraderie, and feeling an increasingly strong sense of ownership over an area as they continue to work in it. Even in an era where specifically doing something is much cheaper, you still have to do <a href="https://lethain.com/judgment-is-all-you-need/">the right thing</a>, which has gotten a bit easier but not much easier, and structural improvements help address this. (As a recent example of that, we had an issue in production where the necessary data to optimize it simply wasn&rsquo;t being captured at all, so the harness&rsquo; ideas to solve it were reasonable but wrong, since the only real path forward was instrumenting the missing information.)</p> <p>As a specific disagreement, there&rsquo;s a prevailing idea that AI-first companies will be run by a small number of genius engineers who create perfect versions of things one by one, doing such a good job that there&rsquo;s nothing to maintain. This is a very compelling vision, but I don&rsquo;t see it happening. High judgment individuals <em>can</em> wander across a company doing remarkable things, but at some point they do get hemmed in by lack of domain context, which is why durable teams are the fundamental building block, even in this era.</p> </li> <li> <p><strong>Quick, good, and durable decision-making is a prerequisite to meaningfully benefit from AI.</strong> Being able to replace a legal review with automation only works if Legal can commit to that change, which depends on designing the automation thoughtfully, and also the teams&rsquo; willingness to collaborate. Implementing a new feature is only valuable if you can decide to launch that feature.</p> <p>Your team and company can only benefit from this increased pace of execution if you can make durable decisions quickly, and those decisions are good. This is the primary reason, in my opinion, why the average CTO role has necessarily become substantially more technical and less bureaucratic than a year ago. In many cases, I am the only person who can make binding decisions when teams disagree on the path forward, and that means I am making decisions constantly in this new world in order to maintain the pace. (That&rsquo;s not an argument that executives are better decision makers, just that binding executive decisions are uniquely powerful to the extent that the executives themselves are aligned enough to honor those decisions.)</p> </li> </ol> <h2 id="what-have-we-done-in-practice">What have we done in practice</h2> <p>So, I genuinely believe the above rules based on my experiences over the past year, and let me try to connect them to specific projects we&rsquo;ve worked on that have convinced me of them:</p> <ol> <li><strong>Migrations</strong> <ol> <li>A year ago, we deployed manually, and deployed ~6 times a week, and now we deploy 200-400 times a week. Our engineering headcount has doubled, but even if we double the prior deploys, we&rsquo;re still up 20-30x year-over-year. This is due to a complete overhaul of how we deploy and run migrations, and this migration was done over two months and done 90% by two folks on our infrastructure team.</li> <li>The first day of January, about 25% of folks on our team used Claude Code or Cursor every day. By the end of February, 100% did. We did this without any top-down mandate, just by making the tooling good and chatting with non-adopters to remove sources of friction. Pretty much every PR is written by harnesses now, at least in the first pass.</li> <li>We migrated from a large number of varied configuration mechanisms to two configuration mechanisms (one for client or server constants that rarely change, a second for product-specific or frequently changing values). This was a large series of changes, which were largely done as a series of isolated projects by individual engineers. First, one engineer cleaned up the architecture to support this approach. Then another engineer did a reference architecture on the new approach. Then several more engineers followed the reference architecture in other areas of our codebase. This might have been a years long project of many people in the prior world, but took less than a quarter to complete, including a new internal tool for managing these values across engineering and non-engineer teams.</li> <li>We unified a multi-repo frontend application architecture into a mono-repo frontend architecture over about a month. This was 95% driven by one frontend engineer. We now have a shared frontend development harness, can maintain libraries cheaply, and entirely moved off using <code>npm</code> for package hosting, which was a source of ongoing friction.</li> <li>We fully statically typed our frontend code, going from a place where the majority of our frontend code was not typed. This was done by one engineer, and a lot of tokens, over the course of a few weeks.</li> <li>We migrated from <code>npm</code> to <code>pnpm</code> for better security defaults and faster deploys. This took one engineer a few hours a day for a few days.</li> </ol> </li> <li><strong>Cost of working code depends on your development harness.</strong> <ol> <li>Where we&rsquo;ve tried to throw design documents and PRs &ldquo;over the wall&rdquo; to engineers on other teams, they&rsquo;ve never gone anywhere. Slop pull requests and design documents are cheap, but are actively harmful. They not only have to be cleaned up and repaired, their context poisons the LLM, leading to worse outcomes than starting over.</li> <li>We&rsquo;ve seen tremendous success in managers contributing software, as long as those managers are validating the work directly, looking at dashboards after their changes go out, and resolving any issues their changes cause. We&rsquo;ve found no positive impact from folks attempting to make changes where they don&rsquo;t do those things.</li> </ol> </li> <li><strong>Optimize the base-case of process for agents.</strong> <ol> <li>We triage all incoming issues from our customer operations team using a harness which knows our team, our open tickets, and has limited access to our data warehouse to size the impact of issues. This is complex, high-skill but not particularly interesting labor that we&rsquo;re now doing better and faster with agents. Yes, there is still a human triage for the edgecases. Importantly, we&rsquo;re also doing this without changing human workflows, it&rsquo;s the same workflow, just with some steps automated.</li> <li>The first pass of code review is done by the same harness that implements the changes, cleared of the context used to write the change, allowing humans to focus on higher value feedback.</li> <li>We rolled out Claude Code and Cowork to all folks in the company last quarter, and have seen them also automate an increasingly large swath of their work as well. Our fraud team has been particularly ambitious in replacing manual workflows with a first-pass of automation&ndash;with attribution to the data itself&ndash;to do the initial investigation on potential attacks automatically.</li> <li>We&rsquo;ve migrated to Linear, and off Jira, to better support this workflow with a more capable MCP and better Slack integration, making it possible for everyone internally to have better infrastructure for building these agent-first workflows. More on this later, but we&rsquo;re almost done alpha-testing our internal harness pulling issues off Linear, and working to resolve them, automatically which is our biggest next step in this direction.</li> </ol> </li> <li><strong>Durable, high ownership teams with domain-context are even more important.</strong> <ol> <li>When I joined, we had a number of areas supported by very talented folks who rotated through them quickly on a per-project basis. This worked, but it meant we were very reactive to issues. Now, we&rsquo;ve been able to dedicate at least a small team to every important area of the company, where they are able to persistently invest. These teams are now wielding all the new techniques afforded by AI themselves. Without them, no one would be capturing these opportunities, because there is simply too much happening.</li> <li>We launched SierraAI, which is quite good, but since then the team has iterated on it relentlessly, getting it truly excellent. This is something we wouldn&rsquo;t have been able to do without a dedicated, focused team.</li> </ol> </li> <li><strong>Quick, good and durable decision making is a prerequisite to benefit from AI.</strong> <ol> <li>Changing how we do configuration was a controversial decision, and I&rsquo;ve had to make repeated clarifications on the approach. This would have been very difficult to do bottom-up, because it impacts every team differently, and the benefit is only experienced at the ecosystem-level (allowing one person to configure all configuration across teams).</li> <li>Reworking our CI/CD pipeline was controversial, as it changed many folks&rsquo; mental models of how we deploy and release (e.g., it forced us to explicitly decouple deploy and release via feature flagging). This was a contentious decision, and would have been slow and difficult to make bottom-up.</li> <li>Unifying into a web mono-repo was also a controversial decision with varied opinions. It benefitted greatly from having a unified decision.</li> <li>Moving to SierraAI was a difficult discussion versus both various competitors, and also not doing it. It needed the executive stamp to finalize the cross-functional debate.</li> </ol> </li> </ol> <p>These are just representative examples, we&rsquo;ve done a lot more than these. The aperture of what&rsquo;s possible has continued to expand every month this year, but the things holding us back haven&rsquo;t changed all that much: organizational misalignment, lack of clarity, and poor technical architecture. It&rsquo;s a wild time to be working in technology.</p>Early and late-stage hypergrowth.https://lethain.com/early-late-stage-hypergrowth/Mon, 27 Apr 2026 06:00:00 -0700https://lethain.com/early-late-stage-hypergrowth/<p>Last week, a colleague asked why I&rsquo;d hired an additional new leader onto an important area rather than expanding an existing leader&rsquo;s scope to incorporate that area as well. The existing leader was a known quantity and doing well, so why not keep expanding them? It&rsquo;s a good question, and depending on the circumstances I might have done either, but explaining why I specifically brought in a new leader this time depends a bit on a distinction I think of as early versus late-stage hypergrowth.</p> <p>In <a href="https://www.amazon.com/Crossing-Chasm-3rd-Disruptive-Mainstream/dp/0062292986">Cross the Chasm</a>&rsquo;s world, early-stage is when you&rsquo;ve proven product market fit, have won the early adopters, and are just starting to win the early majority. In this phase, there are specific problems, and the most important problem is to solve those specific problems. For example, you might be having scalability issues, and solving that is the company&rsquo;s almost sole focus for a few weeks. After scalability is fixed, next you&rsquo;ll need to work on onboarding flows to convert for less technical users, and so on. Not only the executives, but much of the company, serially hunts down solutions to their biggest problem.</p> <p>When you reach late-stage hypergrowth, you are starting to encounter the late majority and laggards cohorts. This reorients the company and executive teams away from only creating an exceptional product, to also having to solve the numerous concerns and checkboxes that a skeptical audience introduces. Sure, your product might save hours a day for our team, but how does your compliance paperwork look? How stable are you? What contractual commitment will you make regarding customer support resolution? At this point, you&rsquo;ll <em>still</em> be in an extremely competitive environment to retain the innovators and early majority, while also having to solve the long list of skeptic-driven requirements. Instead of hunting down solutions, the company&ndash;and the executive team&ndash;now has to solve everything, everywhere, all at once.</p> <p>Going back to my colleague&rsquo;s question, in early-stage hypergrowth, it would have absolutely been preferable to expand the existing leader&rsquo;s scope. In late-stage hypergrowth, expanding their scope would have moved the problem, while reintroducing a previous problem, and that&rsquo;s a losing strategy in that stage.</p> <p>It&rsquo;s been a while since the industry has talked a lot about <a href="https://lethain.com/productivity-in-the-age-of-hypergrowth/">hypergrowth</a>, but a lot of the lessons of hypergrowth are relevant again as we see the productive chaos of the current AI-era, and this is absolutely one of them. In particular, it&rsquo;s extremely clear that you can speedrun the early hypergrowth phase with a small, AI-empowered team, but it&rsquo;s far from clear you can speedrun the late hypergrowth phase with the same approach. Personally, I suspect we will figure that out as an industry, but many of the challenges popping up recently in e.g. Anthropic&rsquo;s messaging to Claude Code power users, feel to me like they&rsquo;re rooted in the challenges of making this transition.</p> <p>Even in the unlikely case that we never solve late-stage hypergrowth using the same AI-staffed mechanisms that support the early-stage case, it&rsquo;s still an economic miracle, since it&rsquo;ll allow a smaller amount of capital to culminate into relatively large and derisked companies, which should underpin substantial productivity for the economy.</p>Agents as scaffolding for recurring tasks.https://lethain.com/agents-as-scaffolding/Sun, 12 Apr 2026 10:00:00 -0700https://lethain.com/agents-as-scaffolding/<p>One of my gifts/curses is an endless fixation with how processes can be optimized. For a brief moment early in my career, that was focused on improving how humans collaborate, but that quickly switched to figuring out how we can minimize human involvement, and eliminate human-to-human handoffs as much as possible. Lately, every time I perform a recurring task&ndash;or see someone else perform one&ndash;I think about how we might eliminate the human&rsquo;s involvement entirely by introducing agents. This both has worked well, but also worked poorly, and I wanted to highlight the pattern I&rsquo;ve found useful.</p> <p>For a concrete example, a problem that all software companies have is patching security vulnerabilities. We have that problem too, and I check our security dashboards periodically to ensure nothing has gone awry. Sometimes when I check that dashboard, I&rsquo;ll notice a finding that&rsquo;s precariously close to our resolution SLAs, and either fix it myself or track down the appropriate team to fix it. However, this feels like a process that shouldn&rsquo;t require me checking on it.</p> <p>Five to six months ago, I added Github Dependabot webhooks as an input into our internal agent framework. Then I set up an agent to handle those webhooks, including filtering incoming messages down to the highest priority issues. About a month ago, when I upgraded from GPT 4.1 to GPT 5.4 with high reasoning, I noticed that it got quite good at using the Github MCP to determine the appropriate owners for a given issue, using the same variety of techniques that a human would use: looking at Codeowners files where available, looking at recent commits on the repository, and so on. The alerts and owners were already getting piped into a Slack channel.</p> <p>So, this worked! However, it didn&rsquo;t actually work that well, because despite repeated iteration on the prompt, including numerous <code>CRITICAL: you must...</code> statements, it simply could not reliably restrict itself to <code>critical</code> severity alerts. It would also include some <code>high</code> severity alerts, and even the occasional <code>medium</code> severity alert. This is a recurring issue with using agents as drop-in software replacement: they simply are not perfect, and interrupting your colleagues requires a level of near-perfection.</p> <p>If I&rsquo;d hired someone on our Security team to notify teams about critical alerts, and they occasionally flagged non-critical alerts, eventually someone would pop into my DMs to ask me what was going wrong. That didn&rsquo;t happen here, because the knowledge that those DMs would show up prevented me from rolling the notifications out more aggressively. Coding agents address this sort of issue by running tests, typechecking, or linting, but less structured tasks are either harder or more expensive to verify. For example, I could have added an eval verifying messages didn&rsquo;t mention medium or high severity tasks before allowing it to send to Slack, but I found that somewhat unsatisfying despite knowing that it would work.</p> <p>Instead, after some procrastination on other tasks, I finally prompted Claude to update this agent to rely on a <a href="https://lethain.com/agents-coordinators/">code-driven workflow</a> where flow-control is managed by software by default, and only cedes control to an agent where ideal. That workflow looks like:</p> <ol> <li>A webhook comes in from Dependabot</li> <li>Script extracts the severity and action (e.g. is it a new issue versus a resolved issue), and filters out low priority or non-actionable webhooks</li> <li>The code packages the metadata into a list of issues and repositories</li> <li>The code passes each repository-scoped bundle to an agent with our internal ownership skill and the Github MCP to determine appropriate folks to notify for each issue</li> <li>The issues and ownership data are passed to a second agent that formats them as a Slack message</li> </ol> <p>This works 100% of the time, while still allowing us to rely on our internal ownership skill to determine the most likely teams or individuals to notify for a given problem. It&rsquo;s now something I can rollout more aggressively.</p> <p>The immediate fast follow was a weekly follow-up ping for open critical issues, relying on the same split of deterministic and agentic behaviors. The next improvement will be automating the generation of the vulnerability fixes, such that the human involvement is just reviewing the change before it automatically deploys. (We <a href="https://lethain.com/dependabot-auto-merge/">already do this for Dependabot generated PRs</a>, but in my experience Dependabot can solve a reasonable subset of identified issues, but far from all of them.)</p> <p>That is the pattern that I&rsquo;ve found effective:</p> <ol> <li>Prototype with agent-driven workflow until I get a feel for the workflow and what&rsquo;s difficult about it</li> <li>Refactor agent-driven control away, increasingly relying on code-driven workflow for more and more of the solution</li> <li>End with a version that narrowly relies on agents for their strengths (navigating ambiguous problems like identifying code owners)</li> </ol> <p>This has worked well for pretty much every problem I&rsquo;ve encountered. The end-result is faster, cheaper, and more maintainable. It&rsquo;s also a cheap transition, generally I can take logs of some recent runs, the agent&rsquo;s prompt, and some brief instructions, throw them into Codex/Claude, and get a working replacement in a few minutes.</p>The agentic passive voice.https://lethain.com/agentic-passive-voice/Sun, 29 Mar 2026 07:30:00 -0700https://lethain.com/agentic-passive-voice/<p>At some point, you will have learned about the passive voice, where the actor in a sentence is unclear. For example, my software didn&rsquo;t compile. That&rsquo;s a good example of the passive voice. However, you might not know the full set of rules, because here are some sentences in the passive voice that you might not recognize:</p> <ul> <li>Claude made an error in my writeup.</li> <li>ChatGPT messed up the commitment.</li> <li>Gemini didn&rsquo;t write tests.</li> </ul> <p>You might think those are active sentences, but those are in fact examples of the <em>agentic passive voice</em>. The rule here is: whenever the actor in a sentence is a model, then it&rsquo;s a passive sentence. I&rsquo;m sorry if your grammar instructor never taught you this rule, but this is just the way it works now.</p> <p>This is an important grammatical distinction to make, because I&rsquo;m increasingly seeing folks say that Claude made a mistake, without recognizing that they&rsquo;re writing unclear, nearly ungrammatical sentences that their grade-school teacher would reject. So please, aspire higher. Write in the active voice, avoiding all passive variants.</p>Judgment and creativity are all you need.https://lethain.com/judgment-is-all-you-need/Wed, 11 Mar 2026 07:30:00 -0700https://lethain.com/judgment-is-all-you-need/<p>When I joined Imprint a little less than a year ago, our deploys were manual, requiring close human attention to complete. Our database migrations were run manually, too. Developing good software is very possible in those circumstances, but it takes a remarkable attention to detail to do it. It was also possible to develop good software using Subversion and developing by ssh&rsquo;ing into a remote server to edit PHP files, but the goal is making things <em>easy</em> rather than <em>possible</em>.</p> <p>Ten months later, the vast majority of our changes, including database migrations, continuously deploy to production without human involvement after the initial pull request is reviewed and merged. Reading aloud the relevant pages from the mandated gospel of continuous deployment, deploying changes this way doesn&rsquo;t make them less reliable, but more so. Each step of validation a human <em>might</em> do, is now consistently done on every deploy, including many steps that are just onerous enough to drop off the standard operating steps like meticulously checking the post-launch health on a production canary every minute for half an hour after each deploy.</p> <p>This migration has reminded me a lot of the Uber service migration, which prompted me to write <a href="https://lethain.com/migrations/">Migrations: the only scalable solution for technical debt</a> back in 2018, and in particular how <em>different</em> this sort of migration feels in the age of coding agents. The more I&rsquo;ve thought about how these two migrations compared, the more it&rsquo;s solidified my thinking a bit about how this technology is going to impact software development over the next few years.</p> <h2 id="migrations-as-metaphor">Migrations as metaphor</h2> <p>Although I really want to talk about how coding agents are changing software development, I want to start by expanding a bit on this recent migration at Imprint and how it compared with the migration at Uber.</p> <p>The Uber migration was:</p> <ol> <li>Spinning up a new self-service service provisioning platform, along the lines of a very minimal Heroku, including the actual scheduling algorithm across clusters, etc. A lot of the edges were rough, including for example I do not remember how we performed service database migrations, but I suspect we simply left that as an exercise for the user. Part of the challenge was that this was a heterogenous environment with Python, NodeJS, Go, and a long-tail of random things (R, Elixir, etc). (For historical context, Kubernetes was sufficiently early that it effectively didn&rsquo;t exist in 2014 when we did this work.)</li> <li>Migrated services iteratively, driven almost entirely by the platform team, without much product engineering support. (Everyone was too busy to help, and our timeline was driven by an upcoming datacenter migration.) A team of ~3 engineers focused on this migrated hundreds of services, although it included Xiaojian Huang who remains a likely contender for the most productive engineer I have worked with in my career, so maybe it&rsquo;s unfair to call it a ~3 engineer team.</li> <li>Shedding a quiet tear for our colleagues on the core product engineering team responsible for deprecating the Python monolith, and migrating it over as a single, heavy service.</li> <li>This took us less than six months start to finish, but I don&rsquo;t think I stopped working at any point in those six months.</li> </ol> <p>The Imprint migration felt fairly differently:</p> <ol> <li> <p>We were building on substantially more powerful infrastructure, with Kubernetes, ArgoCD, etc. Our problem statement was composing our software and workflows with these platforms, rather than building the platforms from scratch.</p> </li> <li> <p>We migrated all our services and databases to a continuous deployment setup, with the majority of the work occurring over 3 months. Once again, the significant majority of it was done by a team of ~3 engineers.</p> </li> <li> <p>In 2014, we spent the vast majority of our time <em>implementing decisions</em>: how the scheduler worked, how the UX for provisioning services worked, etc. In 2026, we spent almost our entire time designing our approach, reviewing coding agent pull requests, and revising our approach when designs and reality didn&rsquo;t come together as cleanly as we hoped.</p> <p>The frenzied sprint was replaced by substantially more time on designing our approach.</p> </li> </ol> <p>All the fundamental challenges of migrations remained true, but in 2026 we got to solely work on solving those challenges, rather than on the essential but mundane minutiae of implementing those decisions. (Ok, I&rsquo;ll be honest, we also had to keep iterating on our approach to using coding agents to get longer working cycles out of them without human involvement, but we&rsquo;re telling a story here, let&rsquo;s not get distracted.)</p> <h2 id="productivity-today-is-is-most-constrained-on-judgment">Productivity today is is most constrained on judgment</h2> <p>What this migration highlighted for me, is that coding agents have already generally solved the problem of <strong>time</strong> for our team. We have, effectively, an unlimited amount of time, at a very affordable price, to complete our work.</p> <p>They have also made substantial progress on the problem of <strong>attention</strong>. After I go beyond five or so concurrent projects, I tend to lose track of the necessary work to shepherd those projects to completion, but increasingly I believe that this, as the LLM community would charmingly frame it, is a skill issue in how I am composing the tools. I&rsquo;m fairly confident that I will evolve my approach to these problems such that the bottleneck on my attention is less important. I don&rsquo;t think this will go to zero, a reality of working on teams is that the work has to be coordinated, but it will go down.</p> <p>The next constraint, which I think is the biggest issue today when it comes to building genuinely important software, is <strong>judgment</strong>. With unlimited time, and with attention increasingly constrained on my personal workflow rather than an inherent limit, I <em>can</em> do anything. But how do I do it in a way that is maintainable, secure, and reliable? How do I do it in a way where it keeps running after a key engineer leaves the company?</p> <p>I developed the idea of datapacks in <a href="https://lethain.com/competitive-advantage-author-llms/">What is the competitive advantage of authors in the age of LLMs?</a>, and this still rings true to me as the core mechanism for scaling judgment in how we approach software: we can supplement judgment by introducing expert context for the task at hand. Today this is defacto happening within the coding agent development layer, in the wider community developing shared agent skills, and internally within companies developing their own skills. My guess is that the industry will develop an ecosystem for high-quality skills, e.g. detailed and maintained skills for security engineering, product engineering, and so on. You can easily imagine O&rsquo;Reilly, or another technology publisher, developing a package manager for blessed skills, which is the first stop for injecting judgment into tasks. (This is the idea I experimented with in creating <a href="https://www.amazon.com/Companion-Crafting-Engineering-Strategy-Thoughtful-ebook/dp/B0FXN2J4PJ">LLM-optimized edition of my latest book</a>, but it&rsquo;s really the distribution platform that&rsquo;s going to be most valuable here.)</p> <p>Once we solve judgment, and I do imagine that we will using a variety of open-source and commercially managed skill package managers that are tightly integrated with coding agents, then the last constraint ahead of us is <strong>creativity</strong>. This is a problem far enough ahead that I&rsquo;m not too worried about it, but I feel like it&rsquo;s a classic entrepreneurship problem that will be amenable to the same solutions as it is today.</p> <hr> <p>I&rsquo;ll admit I&rsquo;m ignoring financial constraints here, but relative to how much companies are spending on software engineering budgets today, this isn&rsquo;t a particularly interesting constraint today. Maybe the financial constraints will get more interesting over time as engineering <em>conceivably</em> gets cheaper, but as we think about injecting judgment, things will get more expensive as well, so the outcomes remain to be seen.</p>Refactoring internal documentation in Notionhttps://lethain.com/refactoring-internal-docs-notion/Thu, 05 Feb 2026 07:00:00 -0700https://lethain.com/refactoring-internal-docs-notion/<p>In our latest developer productivity survey, our documentation was the area with the second most comments. This is a writeup of the concrete steps I took to see how much progress one person could make on improving the organization&rsquo;s documentation while holding myself to a high standard for making changes that actually worked instead of optically sounding impressive.</p> <h2 id="diagnosis">Diagnosis</h2> <p>There were a handful of issues we were running into:</p> <ul> <li> <p>We migrated from Confluence to Notion in January, 2025, which had left around a bunch of old pages that were &ldquo;obviously wrong.&rdquo;</p> <p>These files created a bad smell around our other docs, as folks felt like things weren&rsquo;t well maintained.</p> </li> <li> <p>We had inconsistent approach to what we documented in Git-managed files versus managing in Notion. This led to duplication.</p> </li> <li> <p>Duplication meant that it felt safer to create an <code>N+1</code>th version, rather than debugging why <code>N</code> versions already existed.</p> </li> <li> <p>We&rsquo;ve had a bunch of new folks join over the past year, who weren&rsquo;t sure if <em>they</em> were empowered to update documentation or if someone else was managing any given file</p> </li> <li> <p>We started using Notion AI as the primary mechanism for exposing content, which meant that hierarchical organization was less important, and that having inaccurate snippets was harmful even if they were tucked away into a quiet corner</p> </li> </ul> <p>This was combined with a handful of interesting limitations in Notion itself:</p> <ul> <li>You cannot tell if a non-wiki page is verified or not via API. You <em>can</em> tell if a wiki page is verified via API, but no one uses wiki pages</li> <li>You cannot retrieve all pages in a Notion Teamspace via API, you instead have to manually take list of the top-level pages in that Teamspace, and find the children from those pages</li> <li>There is no &ldquo;archive&rdquo; functionality in Notion that allows you to exclude a document from search results</li> <li>There is no programmatic visibility into views or usage of a page via API <em>except</em> for how recently it was edited</li> </ul> <h2 id="policy">Policy</h2> <p>The policy we adopted for addressing the above diagnosis was:</p> <ol> <li><strong>Optimize for NotionAI results, not manual discovery</strong>: a significant majority of our Notion use is now via either direct links to a specific page, or via Notion AI, not via manual discovery. That means that things like “FAQ” pages that duplicate content and go stale are actively harmful, whereas previously they were very valuable.</li> <li><strong>Duplication and stale content is worse than nothing</strong>: do not write your own guide to a process. Link to it instead, or update the source document</li> <li><strong>Prefer natural documentation in version control</strong>: we’d rather link to a README in Github than duplicate those instructions in Notion, because the README is more likely to be kept current</li> <li><strong>Everyone tidies our documentation</strong>: we’d rather be people who try to clean up a document, even if we make a small mistake, rather than someone who leaves documentation in a poor state</li> <li><strong>Automatic beats manual every time</strong>: we&rsquo;re a busy team doing a lot of things, it&rsquo;s always going to be difficult to consistently find time to manually curate content deeply, focused curation is great, but global is unreasonable</li> </ol> <h2 id="implementation">Implementation</h2> <p>Then the specifics of implementing that policy were:</p> <ol> <li> <p><strong>Create <code>Scheduled to Archive</code> and <code>Archive</code> teamspaces.</strong> The <code>Archive</code> teamspace is a private teamspace, such that documents added there don&rsquo;t pollute the search index. Conversely, <code>Scheduled to Archive</code> is public, where anyone can add documents to its root document.</p> <p>We have a weekly script that migrates everything from <code>Scheduled to Archive</code> to <code>Archive</code>.</p> <p>This was the most effective mechanism we could find to implement archiving within Notion&rsquo;s constraints.</p> </li> <li> <p><strong>Prune expired pages.</strong> Created a script which recursively builds hierarchy from a root page, enriches each page with the <code>last_edited_date</code> for each child, and then prunes all pages where it <em>and all children</em> were last edited more than <code>N</code> days ago.</p> <p>Using this script on 3-4 most relevant top-level pages, we archived about 1,500 pages of expired documentation.</p> </li> <li> <p><strong>Compact stale hierarchies.</strong> Created a second script which identifies current pages deep in stale hierarchies, e.g. the one updated page among 15 inaccurate docs. After finding a &ldquo;buried current page&rdquo;, promotes it to the grandparent page, and move the parent page (and its stale children) to <code>Scheduled to Archive</code>.</p> <p>This ended up as a script that found all the candidates, and then I worked through approving/rejecting each suggestion. The biggest issue being the lack of &ldquo;verification&rdquo; status within the API, such that there&rsquo;s no way to bless given pages and their descendants.</p> </li> <li> <p><strong>Stale link finder.</strong> Created a third script which recursively works through a hierarchy and finds 404s. It&rsquo;s essential that this script <em>does not</em> have access to the <code>Archive</code> so those scripts show up as 404s, otherwise you would have to scan through <code>Archived</code> to find things there. Both approaches would work, just a bit of a matter of preference.</p> <p>Ran this after the mass migrations to ensure we didn&rsquo;t leave a &ldquo;haunted forest&rdquo; of links into archived documents that folks can&rsquo;t see, which would make the documentation still feel bad even though much of the bad content was removed.</p> </li> <li> <p><strong>Manual review of key pages.</strong> After running all of the above steps, I then worked through all new-hire documentation to ensure it was linked to top-level onboarding guide, stated clear prerequisites, indicated the Slack channel to get help if folks ran into trouble, and ensured that instructions did not duplicate our Git-managed READMEs, instead linking to them where appropriate.</p> <p>I did a lighter pass of this approach for our top-level engineering and technology pages, although those were generally in a good place.</p> </li> </ol> <p>Altogether, I think this was about eight hours of my time, but required zero hours of anyone else&rsquo;s, and will have hopefully significantly improved the quality of our documentation. There&rsquo;s still a lot more to be done in specific areas, but I&rsquo;m optimistic that having far fewer duplicates, and more evidence that we&rsquo;re actively maintaining the documentation, will make that easier as well.</p>Should you include engineers in your leadership meetings?https://lethain.com/should-include-eng-in-eng-leadership/Sun, 25 Jan 2026 13:00:00 -0700https://lethain.com/should-include-eng-in-eng-leadership/<p>While <em><a href="https://staffeng.com/">Staff Engineer</a></em> was first and foremost an attempt to pull the industry towards my perspective on staff-plus engineering roles, writing it also changed my opinions in a number of ways. Foremost, it solidified my belief that the industry too often treats engineers like children to be managed, rather than adults to be involved, and that I needed to change some of my own leadership practices that I&rsquo;d inadvertently adopted.</p> <p>When I started writing it, I had already shifted my opinion about reporting hierarchy, believing that it was important to have engineers reporting directly to senior leaders rather than reporting to leaf managers. But I hadn&rsquo;t gone the whole distance to include them in my core leadership meeting. However, for the last six years I have had active engineers in my senior-most leadership group, I&rsquo;m glad that I&rsquo;ve adopted this practice, and I intend to continue it going forward.</p> <h2 id="mechanics">Mechanics</h2> <p>The core approach here is:</p> <ol> <li>Have a weekly meeting with my directs and key cross-functional partners. For example, at Stripe, this was my direct reports, our HRBP, and the recruiter we worked with most closely.</li> <li>Elevate a small number of senior-most engineers to report to me directly as Head of Engineering / CTO, who then naturally start to join that weekly meeting</li> <li>Everyone is included in all discussions, e.g. there are no managerial discussions that the engineers are excluded from unless there&rsquo;s a very specific reason (e.g. excluding engineers from a performance calibration meeting for their peers at the same level)</li> <li>If anyone violates the meeting&rsquo;s trust, whether they are an engineer or a manager, they get in a lot of trouble</li> </ol> <p>This is a simple formula, but has worked well for me the past decade. There absolutely are topics that some people don&rsquo;t care about too much, but I try to push my leadership team to care widely, even if things don&rsquo;t impact them directly.</p> <h2 id="upsides">Upsides</h2> <p>It&rsquo;s easy for managers to get into a mode where they are managing the stuff around reality, without managing reality itself. That is much harder when engineers who write and maintain the company&rsquo;s software are in the room, which is the biggest benefit of including them. Similarly, there are many decisions and discussions that would have to be punted to another forum without effective engineering representation in the room. You might not be able to finalize the technical approach to a complex problem with only a few engineers in the room, but you can at least evaluate the options much further.</p> <p>Another major benefit is that these engineers become a second propagation mechanism for important context. Sometimes you&rsquo;ll have a manager who isn&rsquo;t communicating effectively with their team, and while long-term that has to be solved directly, having these engineers means that information can flow down to their teams through the engineers instead.</p> <p>Finally, this sets an expectation for the managers in the room that they should be in the details of the technical work, just as the engineers in the room should understand the managerial work.</p> <h2 id="downsides">Downsides?</h2> <p>There are relatively few downsides to this approach, but it does serve as a bit of a filter for folks who have a misguided view of what senior leadership entails. For example, there are some engineers who think senior leadership is having veto power over others without being accountable for the consequences of that veto. Those folks don&rsquo;t survive long in this sort of meeting. Some would argue that&rsquo;s a downside, but I wouldn&rsquo;t.</p> <hr> <p>While I can conceive of working in some future role where I am simply <em>not allowed</em> to implement this pattern, I really can&rsquo;t otherwise imagine not following it. It&rsquo;s just been transformative in better anchoring me in the actual work we do as engineers, rather than the &ldquo;work around work&rdquo; that is so much of management.</p>Writing Visualizations with Remotionhttps://lethain.com/blog-recap-2026/Sun, 25 Jan 2026 12:00:00 -0700https://lethain.com/blog-recap-2026/<p><a href="https://www.remotion.dev/">Remotion</a> is having a bit of a moment at the moment, and I decided to play around with the <a href="https://www.remotion.dev/docs/ai/claude-code">Claude Code integration</a>. Here are a couple videos I was able to make in &lt;10 minutes summarizring data on my blog.</p> <p>First, here is published posts over time. I had Claude write some scripts to generate this dataset, and then did a series of prompts to get the right visual. It was pretty straightforward, worked well, and I imagine I could have gotten to the right video much faster if I&rsquo;d had a clearer destination when I started.</p> <video controls width="100%"> <source src="https://lethain.com/static/blog/2026/BlogPostsChart.mp4" type="video/mp4"> </video> <p>Second, here&rsquo;s a video of showing the published blog posts over time, my most frequently used tags at that point in time, and how many posts I published at each employer along the way.</p> <video controls width="100%"> <source src="https://lethain.com/static/blog/2026/BlogPostsTimeline.mp4" type="video/mp4"> </video> <p>Altogether, this was a really fascinating to see how effectively Claude and Remotion together were able to generate fairly complex videos. This is definitely something I could imagine using again.</p>Curiosity is the first-step in problem solving.https://lethain.com/curiosity-first-step-problem-solving/Sun, 25 Jan 2026 10:00:00 -0700https://lethain.com/curiosity-first-step-problem-solving/<p>Despite my best efforts, I have been wrong a lot over the years. I&rsquo;ve been wrong about technology patterns (in 2014, I thought microservices would take over the world), I&rsquo;ve been wrong about management techniques (I used to think systems thinking was <em>the</em> ultimate technique, but I&rsquo;ve <a href="https://lethain.com/how-to-safely-think-in-systems/">seen so many mistakes rooted in over-reliance on systems thinking</a>), and a bunch of other stuff as well.</p> <p>Early on, I spent a lot of time thinking about how to be wrong less frequently. That&rsquo;s a noble endeavor, and one I still aim to improve at today. However, a lot of the problems you encounter later in your career are <a href="https://lethain.com/navigating-ambiguity/">deeply ambiguous</a>, and it simply isn&rsquo;t possible to eliminate bad outcomes. Some examples of this are:</p> <ol> <li>Hiring is always a probabilistic endeavor. Even the best hires can struggle in a given company/role or have a life-changing event that leads to poor fit</li> <li>The 2020 pandemic broke many business models that were doing extremely well before then. Similarly, many companies overindexed on the shifts online driven by the pandemic, overhiring in ways that resulted in significant long-term harm to those companies</li> <li>Pursuing data locality for your product: there&rsquo;s always a cost or capability consequence when you shard your data model more finely across geopolitical regions, and geopolitical regions shift frequently and surprisingly. No matter how accurate your original guess is about the next two years of data locality changes, you will be wrong if you&rsquo;re operating in enough countries</li> </ol> <p>In every one of those examples, you know upfront that you simply don&rsquo;t have all the information you&rsquo;d like to have, and still need to make a decision to move forward. As a result, these days I spend far more time thinking about how to make being wrong <strong>cheap</strong> rather than how to <strong>avoid</strong> being wrong.</p> <p>Of everything I&rsquo;ve tried, demonstrating curiosity is consistently the best technique I&rsquo;ve found to reduce the cost of being wrong. These days, if I regret being wrong about something, it&rsquo;s almost always because I engaged in problem solving before exercising curiosity. I feel this so strongly that &ldquo;curiosity is the first step of problem solving&rdquo; has become a steadfast engineering value in the organizations that I lead.</p> <p>Some examples of demonstrating curiosity well and poorly:</p> <ol> <li> <p>Someone thinks we shouldn&rsquo;t hire someone that I&rsquo;ve worked with closely.</p> <p><strong>(Bad)</strong> Assume they are wrong.</p> <p><strong>(Good)</strong> Explain your mental model of why you think the candidate would work well, and ask them where they do or don&rsquo;t agree with that mental model.</p> <p><strong>(Best)</strong> Spend time upfront aligning with interviewers on the specific fit you&rsquo;re focused on for this specific role.</p> </li> <li> <p>Someone is asking for help logging into an internal dashboard where the internal login steps are extensively documented in your internal wiki.</p> <p><strong>(Bad)</strong> Get slightly snippy with them about not reading the documentation.</p> <p><strong>(Good)</strong> Ask them if they are running into something that isn&rsquo;t covered by the documentation.</p> <p><strong>(Best)</strong> Replace this with a chat bot that uses the <strong>(Good)</strong> approach automatically instead of having a human do this.</p> </li> <li> <p>Someone proposes introducing a new programming language for your internal stack.</p> <p><strong>(Bad)</strong> Tell them that they need to follow the existing architecture document.</p> <p><strong>(Good)</strong> Mention that this seems in conflict with the current architecture doc, and ask them how they&rsquo;re thinking about that conflict.</p> <p><strong>(Best)</strong> Make sure new-hire onboarding includes links to those materials, and create an LLM-driven RFC reviewer that directs RFC writers to existing materials they should reference in their RFC.</p> </li> <li> <p>Someone doesn&rsquo;t show up for an incident that they are on-call for.</p> <p><strong>(Bad)</strong> Tell them they failed to meet on-call expectations.</p> <p><strong>(Good)</strong> Ask them what happened that led them to missing their on-call expectations.</p> <p><strong>(Best)</strong> Create automation to ensure folks going on-call are notified ahead of time, and to detect anyone going on-call whose notification mechanisms aren&rsquo;t appropriately configured.</p> </li> </ol> <p>In each of these cases, showing curiosity is not about being unwilling to hold folks accountable, and it&rsquo;s not about consensus-based decision making. Instead, it&rsquo;s starting each discussion by leaving space for the chance that you&rsquo;re missing important information. Often you&rsquo;re not missing information, and then the next step <em>is</em> to hold folks accountable, but demonstrating curiosity helps you avoid applying accountability without context, which damages relationships without providing any benefit.</p>