Latest Posts (20 found)

No Need for Retirement When Utopia Is Around the Corner

I’ve mentioned before my interest in the history and development of nuclear weapons . Currently, I’m reading The Doomsday Machine: Confessions of a Nuclear War Planner by Daniel Ellsberg (of Pentagon Papers renown). In the first chapter, Ellsberg talks about his time working at the RAND Corporation during the missile gap years when the U.S. thought it was falling behind the Soviet Union in nuclear capabilities. Many of his descriptions sound strikingly similar to the rhetoric coming out of places like Anthropic. For example, note the religious overtones of working at a corporation: I loved RAND, where I ended up spending ten years [...] Much, I imagined, like members of a religious order would, I shared with my colleagues a sense of brotherhood, living and working with others for a transcendent cause. They were insiders : burdened with the responsibility of knowledge others did not possess. precisely in my early missile-gap years at RAND and as a consultant in Washington, there was our sense of mission, the burden of believing we knew more about the dangers ahead, and what might be done about them, than did the generals in the Pentagon or SAC, or Congress or the public, or even the president. It was an enlivening burden. And what was their “enlivening burden”? Saving the world: [My colleagues] shared a feeling—soon transmitted to me—that we were in the most literal sense working to save the world. What really stood out was this part, where Ellsberg describes how he and his colleagues truly believed the end was nigh: From the Air Force intelligence estimates I was newly privy to, and the dark view of the Soviets, which my colleagues shared with the whole national security community, I couldn't believe that the world would long escape nuclear holocaust. Alain Enthoven and I were the youngest members of the department. Neither of us joined the extremely generous retirement plan RAND offered. Neither of us believed, in our late twenties, we had a chance of collecting on it. This reminds me of the report that AI researchers have taken up smoking as a way to signal their belief that AI will cure cancer before smoking kills them. At this point, I wouldn’t be surprised to hear a lab like Anthropic announce they’re discontinuing all employer-sponsored retirement benefits. It’d be a small sacrifice on behalf of the employees to demonstrate their faith that universal high income is just around the corner. (The corporate cost savings would just be a nice bonus.) Reply via: Email · Mastodon · Bluesky

0 views

Presented by Stripe

Listen to this post : Stratechery is, starting from today, presented by Stripe. Readers have, over the years, pointed out the paradox of my belief in and advocacy for advertising-based business models being delivered in a format bereft of advertising. In truth, however, there was no paradox, just pragmatism: when I launched the Stratechery business model I intended on having sponsors, and did for a month or two, before I realized that ad sales for a one-person business with a small audience was a waste of time; I was much better served devoting my attention to content and trusting that readers would be willing to pay. And, thankfully, readers were willing to pay, and ultimately, there ended up being far more such readers than I ever dreamed of. In fact, there were so many readers willing to pay that I have, over the subsequent 12 years, been able to build an audience that is uniquely attractive to potential advertisers, along with a team that can help me pursue the multi-faceted business model I always planned on. Stratechery is a business, and subscriptions + advertising is The Unified Content Business Model I have long advocated. That noted, this is a big change, both for you and for me; I’ll start with the latter. I take my ethics policy very seriously, including the fact I am not paid for posts, I do not hold individual stocks, and I pay for all of my own expenses. This has, in all honesty, probably cost me a fair bit of money, but the payoff has been trust from you, and for me the sense of personal integrity this provided. To that end, with this announcement, I am editing my ethics policy to include this paragraph: Stratechery is, as of October 2026, presented by Stripe, and there I make no claims of objectivity. To the extent I analyze not just Stripe but the entire fintech space, I strive to give my honest opinion; my contract with Stripe contains total editorial independence. However, the reality of a conflict is inescapable, and I will disclose my relationship to Stripe in every post where this conflict may be relevant. My ethics policy is going to include a link to this announcement, because there is one more admission to make: if I am honest with myself I have never been truly objective about Stripe specifically, for three reasons. I did always try and set these considerations aside when writing about Stripe; in truth I actually just wrote about Stripe and the fintech space less, as I was cognizant about these informal conflicts. By the same token, this is exactly why I couldn’t be more thrilled to have Stripe as an exclusive sponsor: if I am informally conflicted, why not make it formal? I actually think this gives me more freedom to write about fintech, not less, because the conflict will be on my sleeve; more than that, however, every ad I run or read is going to be heartfelt: I believe in Stripe, love their service, and while I am being paid for those ads, I will have the satisfaction of truly believing in them as well. That leaves the impact on you, the reader, and I’ve made an FAQ: Where are ads going to run? There are three primary places you will see Stripe ads: More on Sharp Tech below. What about sponsored content? There is no requirement that I run sponsored content; however, I’m actually very excited about the potential of occasionally leveraging Stripe content. Stripe has a unique position in terms of working with companies across the entire economy, and that is particularly true when it comes to AI. You see some of the insights that come from this position on both the Stripe blog and the Stripe Economics blog , and I look forward to incorporating those kinds of insights when it makes sense (and I should also call out Stripe’s Works in Progress site ). Just to be clear, however, that will be my call. So Stripe can’t tell you what to write? Absolutely not. More than that, Stripe cannot tell me what not to write either. I could call for Patrick Collison’s firing and I’m still going to get paid. I am not, for the record, going to do that; as I noted I will disclose this relationship whenever it seems relevant. However, my first loyalty is to my readers; that meant absolute editorial independence was a prerequisite for this deal. Can I skip the ads if I’m a subscriber? No. Like I said above, Stratechery is a business, and it’s the quality of my audience that makes this deal possible. Moreover, Stratechery has never promised to be ad-free: what I am selling is access to my paid content, and it’s on me to make that content worthwhile. In fact, I would spin this the other way: my motivation to deliver great content is higher than ever, knowing that it has to be worth not just your money but also the attention that I have chosen to share with a sponsor. That noted, while I don’t make categorical statements about my business, I do not anticipate raising subscription prices again, and certainly not over the course of this deal. Do I get anything out of this deal? This is the part I’m most excited about: I am going to invest the revenue from this deal into making more and better products. I have a bunch of ideas that are now unlocked, and one of them is launching this week: in-person Sharp Tech. I am extremely excited to announce that, starting this week, Sharp Tech will become a video podcast, recorded live and in-person. Over the past couple of months I have been building a small video studio in my home, and Andrew will be flying to Wisconsin every week (when possible) to make what I strongly believe will be a better product. There is no matching the energy and chemistry that comes from recording in person, so we’re going to do exactly that the majority of the time. We will be posting video episodes on YouTube (for clarity, not live as we record, at least to start), as well as through existing feeds; these episodes will be free. In addition, we will be adding a second weekly mailbag-centric audio-only episode — recorded the same day, in-person — for subscribers only. This is the first of what I hope will be many product launches for subscribers; my goal is that this sponsorship is seen as a real unlock and accelerant for what it means to be not just a subscriber but a member of the best audience in the world. That’s what I believe I have, it’s what Stripe believes that I have, and I’m grateful to every one of you for making that a reality and this business possible. First, Stripe is a foundational business for my business. The then-startup launched the Subscription API (what later became Stripe Billing ) in late 2011; Stratechery was predicated on that feature existing (and, I would add, the fact that a novice developer like myself could incorporate the Subscription API spoke to Stripe’s ease-of-use!). Second, Stripe is the foundation of Passport, the access management software that undergirds Stratechery, SemiAnalysis’ institutional offerings , and The Ankler ; we have and continue to work with Stripe closely for both Stratechery and Passport. Third, I have had the good fortune of becoming friends with Patrick and John Collison, who were some of the earliest Stratechery readers and subscribers. There is a “Presented by Stripe” placement on Stratechery, the cover art of the Stratechery, Stratechery Interview, and Sharp Tech podcasts, and in the emails I send. I honestly think it looks pretty great, but I’m biased! There will be occasional ad placements between sections of the Update, in the Interviews, and between Articles; this will apply to the web, email, and the Stratechery podcast (which is, and will continue to be, simply the audio version of what you can get on the web or via email). There will be a segment of Sharp Tech where Andrew and I discuss the Stripe ad topic of the week, along with an acknowledgment at the beginning of an episode, and an ad at the end.

0 views

BazelCon 2026 recap

We are right in the middle of fall, and that means BazelCon 2026 just took place. This time around it was hosted in Amsterdam and spanned three days: one day of tutorials and an overlapping Buildbarn meetup that I wasn’t aware of, and two days of main-conference talks and events. And as the event is behind us, it’s time for the now-traditional recap. Welcome to BazelCon 2026 sign. What follows is a recollection of my notes arranged by topic and intermixed with my own commentary and thoughts. Some sections and topics are more detailed than others because in some cases I didn’t have a seat and couldn’t type enough, and in others I got distracted in the hallways chatting with people. Speaking of people, several of you approached me to praise previous editions of these recaps, so I now feel obliged to write another one. Thanks for the kind comments! As we will see, “scale” was a central theme of the conference: AI is multiplying concurrent builds and tests, artifacts and graphs are growing at an accelerated pace due to new features like configuration transitions, and the ecosystem is responding by making execution, caching, and analysis more efficient. There is a lot to cover but here are a few things that felt memorable to me : The BUILD Foundation is now a reality, giving the Bazel ecosystem a vendor-neutral home. Its goal is to act as a proxy between the community and Google to help Google understand what to prioritize and to fund projects. If your company can spare “a few” dollars, please donate! AI-driven development is having a broad impact on the industry and, in particular, everyone is seeing their CI systems become overloaded. Well, news at 11: I’m dealing with this day in and day out. But what was new to me was that we at Snowflake are not the only ones struggling with local system overload. Lots of people out there have likewise “discovered” Git worktrees as a way to run multiple agents in parallel, which in turn means multiple concurrent Bazel servers. Bazel 10 is shaping up to be a substantial release that will help with the problem right above due to its many performance improvements and memory consumption optimizations. Have you struggled to keep Bazel up-to-date before? These days, if you want to get any platform-related work funded you have to spin it in terms of AI, so this release will be an easy sell. Let’s “Rewrite it in Rust”? I’m impressed. Google is seriously evaluating a progressive rewrite of Bazel in Rust, and this is probably the most exciting news I got out of the conference. You know I’ve been critical of Bazel’s usage of Java since day one so, if this takes off, I’ll be the first in line to evaluate the results (and it will likely push me to actually contribute to Bazel again). Fast and correct sandboxing on macOS remains a problem. This is “interesting” to me because it’s a problem I tried to fix almost ten years ago with the original sandboxfs, but I failed because of unexpected bugs in macOS’s FUSE support and eventually abandoned the idea when FUSE became a dead end on Apple’s platforms. Funnily enough, other folks have now reinvented sandboxfs—and even given it the same name (ugh)—and there is even another implementation of a similar idea in the form of actiondFS. Types are coming to Starlark, but Bazel’s late arrival to the party means that multiple competing approaches now exist. We have at least two LSPs with different annotation mechanisms and Buck 2’s own syntax. Hopefully they can all converge. Platforms and configurations remain difficult to model at scale. Careless use of transitions and build settings can produce an explosion of configured actions. Apparently, as one speaker noted, AI agents love transitions for some reason, which is interesting because they are not a popular feature and they are not particularly easy to use. Let’s dive into the full report now. You’ll find my notes arranged by talk but I’ve tried to group them into higher-level themes for easier navigation. These conference summaries take effort to write, and some of you are waiting for them. Show your true support by subscribing! The two keynotes are usually the most information-packed events but… as you can imagine they are also the most popular. The venue this year was not roomy enough to host BazelCon’s attendance (Helen quoted that we got 600 registrations), so I had to stand for these two events. The recordings and slides are not out yet, so consequently, I can only tell you a few details from memory. The conference opened with the usual Bazel Community Update , presented by Helen Altshuler from EngFlow and Chuck Grindel from Glydways. The biggest announcement is that the BUILD Foundation is now a reality. The effort had been discussed at the previous two BazelCons and likely various meetups, but it had remained mostly invisible while its organizers worked through the legal and financial details. The foundation now provides a neutral organization to support the broader build ecosystem (in their words this is not just for Bazel), and it is looking for both members and concrete proposals to fund. If you want to get involved, get your company pumped up and email [email protected] . Documentation continues to receive attention as it has always been a lowlight in previous surveys. Work is underway to make the docs easier for the community to own and improve by decoupling them from Google’s internal systems. But one must wonder: what exactly is the biggest problem with documentation in today’s world? AI agents used to do terribly with Bazel just a year ago and nowadays do… fine as we shall see in the summary. Maybe the work on documentation needs a different spin now. And as usual, a reminder to fill the annual Bazel user survey . Your input is necessary to quantify ecosystem-wide pain points and influence future work, especially now that the foundation exists. John Field and Tobias Werth from Google followed with the State of the Union , which presents a recap of major improvements during the year and the path ahead for Bazel 10 and beyond. Performance remains a major theme. Google reported improvements of about 15% in some workloads together with reductions in memory consumption. Some of these speedups come from upgrading from Java 25 to 27, while others come from correct action rewinding, optimizations to Skyframe cache pruning, and content-defined chunking. These changes are very relevant because Bazel’s large memory consumption gets in the way of scaling CI and prevents using multiple AI agents in parallel. And here is where we heard about Skymetal: the codename for the Google-internal exploration of rewriting Bazel in Rust. The rationale for this rewrite is obviously performance, and I’m guessing it’s now a real consideration because AI can make such large-scale changes feasible. Tobias acknowledged that Java was a reasonable choice back in 2006 when Blaze started and that the JVM can deliver great throughput performance at scale… but it is not the best choice for a tool like Bazel in this day and age, especially when optimizing for memory efficiency is critical. I called it in 2015. I have been in the BazelCon Program Committee (PC) for 3 years now. I remember that, during last year’s review, we encountered a few AI talks but I think none made the cut: they all looked too hype-y and out of place. But it was impossible to ignore the topic this year, and it was actually important to bring AI-related talks on board to not sound tone deaf. AI is a reality in our industry, and Bazel is a key component to survive the transition. Nicolas Lopez from EngFlow and I, representing Snowflake, presented AI Development: Challenges and Early Learnings for Bazel . Agentic workflows have expanded rapidly throughout 2026, and the effects are visible well beyond code generation. At Snowflake, we were fortunate enough to finish our Bazel migration and to stabilize remote execution by moving from our self-hosted open-source deployment to EngFlow’s fully-managed service before all of this happened. And I say fortunate because the increase in CI load that AI workflows brings can only be handled with a good build system and caching story. But none of that is news, so the core of the talk was to look at how Bazel usage looks different in agent-initiated environments. The key points from my side: Agents run more builds more frequently than humans, discover and invoke targets that were often “internal only”, and explore several approaches in parallel. Your intuition about how to evaluate which builds matter and how to measure them is probably wrong by now. Bazel and IDEs have never played great together and maybe that just doesn’t matter anymore. We are seeing a sharp decline in IDE usage, although developers still want a way to browse code changes and debug them. This means LSPs are key now to support “leaner” IDEs, and maybe standalone debuggers. Short build and test latency is critical when a human must remain focused on a coding task but, in an agentic workflow, the constraints are different. You know that, after you hit “execute this plan”, the agent will take many minutes to return so minimal build latency is not as important. And actually… maybe you now want to trade some latency in exchange for extra validations so that agents have to take fewer turns to converge. And because humans are now waiting for agents to finish for long periods of time, they have to fill that time with other tasks, which has driven them to adopt Git worktrees en masse. This is leading to scalability problems on dev machines because multiple concurrent Bazel server processes are not great for memory and disk usage. The rest of the talk, presented by Nicolas, focused on trying to understand behavioral changes by looking at anonymized backend data across companies. One specific insight was that people’s work days have lengthened over the year. Cynically, the promise of “working less because of AI” has not materialized: in fact, we are all seemingly working longer hours and with fewer chunks of focus time, so the dangers of burnout are higher. Maggie Lou from BuildBuddy presented Taking Humans Out of the Build Loop . The premise was that coding agents have improved quickly, but people still spend too much time copy/pasting logs, triggering builds, explaining failures, and reviewing the results. In her presentation, we witnessed many new features in BuildBuddy to allow agents (and humans!) to interact and diagnose remote builds with ease: to download filtered logs for a build. to answer questions such as “Why was my build slow?” which are extremely common in the Bazel ecosystem. to start a remote Firecracker VM and run Bazel inside of it. The VMs are snapshotted for quick reuse, and the runners can execute arbitrary commands rather than Bazel alone. to diagnose a failed build and either create a pull request or push a commit with the proposed correction. to perform a review and post comments to GitHub. The need for these features is unsurprising this late in 2026, but what’s really useful in their offering is how these features integrate with build data. Inspecting the BEP, profiles, remote execution metadata, and logs in unison via an agent can yield much better diagnostics and automated improvements than staring at just a few lines of console output. One thing that surprised me in chatting with the presenter is that BuildBuddy is not particularly big in terms of headcount but they churn out features at a very high rate—and that was true even before AI. Impressive! Armando Montanez (and Ulf Adams, but he didn’t make it) from EngFlow presented Proving Equivalence in any2bazel Build System Migrations . The talk described a structured way to use AI agents for build system migrations and started with a reflection: AI agents used to be terrible at Bazel less than a year ago, but now they do pretty damn well—especially if you can close the loop with automated validations. However, even if agents do well at writing Bazel builds, the fidelity of a migration leaves a lot to be desired if left unattended. And here is where any2bazel comes into play: it turns the process into a guess-and-verify loop. The initial focus of the tool are CMake-to-Bazel migrations, and the tool comes with a script that extracts reference compiler and linker actions from CMake in a deterministic manner. The agent then writes Bazel build files, runs , and feeds the resulting actions to a differ tool that compares those to the originals. The loop continues until the two action sets are equivalent. The equivalence checks are what’s hard though: there are compiler flags that may have no impact on the result, for example, so they need to be “ignored” to let the agent experiment with different Bazel-native approaches until it gets to bit-for-bit identical outputs. It’s important to focus on comparing outcomes and not internals so that the generated Bazel builds do not necessarily follow ancient idioms, like e.g. a Maven-like project structure in a Bazel build. In the end, though, this approach works surprisingly well. But the question is: “How good are the generated build files?” The presenters evaluated them along four axes: Correctness: Good, because equivalence is the central constraint of the loop. Hermeticity: Good, but you might need to do extra upfront work to remove host-specific behavior from the reference build before starting. Efficiency: Usually good when standard rules can model the build. Complex projects with custom build rules may end up with overly large Bazel actions though. Maintainability: Unsurprisingly, the weakest point. Agents tend to model variation with configuration flags instead of proper platforms and toolchains, which is not idiomatic to Bazel. Expert review of AI outputs remains critical, which is, again, not surprising. As a side note, it seems like the team likes pain because they tried to migrate an MSBuild project too. MSBuild is more painful than others because its binary log requires running through a real build: there is no dry-run mode, so it might be difficult to extract a truly clean log of actions, and the process is slow. Fortunately, the reference needs to be extracted only once before the comparison agentic loop can start, and it works: we saw a POC migration of the Color Picker tool that comes from PowerToys. When optimizing a distributed build system, it’s easy to focus on the costs of the remote execution workers: how many there are, what kinds of hardware they use, how well they auto-scale… but a significant driver in cost comes from the storage systems required to support those workers. In other words: the remote cache is expensive. Let’s look at a few topics that deal with this problem. Tyler French from BuildBuddy and Benjamin Ingberg from Meroton presented Content-Defined Chunking for Bazel . This was one of the most immediately-practical talks for anyone operating a remote cache, and it surely caught my eye because I had just been troubleshooting a problem at work that CDC would have prevented in the first place. The problem is that Bazel has traditionally treated each file as one indivisible blob. If an action produces a one-gigabyte binary (not uncommon these days huh) and this binary only changes by a few bytes from a previous build, the client or remote worker must re-upload the entire new file to the CAS and the CAS must store a full copy of those bytes. This is inefficient network- and storage-wise because the cache has to be overprovisioned so that these very large, rarely reused blobs don’t prematurely evict valuable cache entries. Content-defined chunking (CDC) divides a file into variable-sized pieces that can be cached independently. To compute the chunks, a rolling hash scans the contents and chooses boundaries when the hash matches a particular condition. Because the boundaries depend on the content rather than fixed offsets, inserting a few bytes in the middle of a file shifts only the nearby chunks instead of invalidating every subsequent one. With CDC, Bazel represents the original file as a list of chunk offsets and digests instead of a single digest, and each chunk is uploaded or downloaded independently. The presenters reported average reuse of chunks of 36%, chunks of 40%, chunks of 96%, chunks of 98%, and chunks of 99.5%. Furthermore, BuildBuddy estimates that CDC saves 35% of bytes written, deduplicates 60% of chunked bytes, and avoids about 400 TB of traffic per day across its fleet. Finally, the median project sees about 70% less remote storage, while local disk caches shrink by roughly 40%. Impressive numbers. Almost all of these benefits can be achieved by enabling CDC on the backend alone without changes to Bazel because most savings come from worker-to-CAS communication. But there are improvements to be made on the client too, of course. CDC fits bb-clientd especially well because chunks can be reused across output bases and, to materialize a file, the client needs only its chunk map. This can be much cheaper than reconstructing the whole file on every incremental build. For existing users, the starting point is together with a server that supports remote CDC. You’ll want to use the latest Bazel 8.x or 9.x releases for best results, as earlier versions didn’t perform the necessary validations to ensure that CDC didn’t corrupt data. The talk ended with a plea for tool authors to rethink binary formats: files that contain absolute pointers in them are poison for caching even with CDC because small changes in a file can have cascading effects across it. Wherever possible, relative pointers are better. Lore is Epic Games’ open-source, content-addressed version control system for very large, asset-heavy monorepos. Mattias Jansson from Epic Games came on stage to talk about it. But this was not just a presentation of the version control system. This was also a presentation of how Lore integrates with Bazel to prevent ferrying large assets between Lore repositories, the machine running Bazel, and the remote execution/cache cluster. The insight is that Lore and Bazel’s remote cache are both backed by a CAS… so if they can share the same storage, artifacts don’t need to move around. The idea relies on the fact that Bazel-the-client does not need to know the content of source files. All Bazel needs to know are the digests of those files to detect file changes across builds and to compose Remote Execution (RE) API requests. You’d imagine that computing digests requires reading the files, and you’d be right… but the server (Lore) already has those files, can compute their digests once, and can expose those to Bazel for consumption. So, what Epic Games has built is a translation layer between the RE API and Lore’s chunked content addresses, plus a virtual file system that exposes the precomputed digests to Bazel. In this way, Bazel talks to just one storage system and can leverage digests without computing them itself. Of interest was a brief note that Bazel can now use BLAKE3 instead of SHA-256 for content digests, which can likely be a big deal for performance because the former excels in speed due to parallel chunk processing. TIL. Caleb Froese from Canva presented Diffing Millions of Screenshots a Day, Hermetically . The premise of the talk is that, when developing a UI, you really want to have regression tests for how the UI looks —and doing that at scale is difficult. The idea is simple, though: make the code render a part of your UI, capture a screenshot, and compare it against a known-good image. Check in the golden image into source control, and call it a day. Except… if you do that at Canva’s scale, you end up growing the Git repository by about 20 GB per day , which is obviously untenable due to how Git works. A different approach is to store the images elsewhere and expose them to tests through an external repository rule. This integrates well with Bazel in the sense that the downloads are out of the execution path, but it also scales poorly: too much data must be downloaded to each client just for it to be re-uploaded right away to remote executors. And it also creates friction for developers when defining the build graph. In the end, Canva’s solution is to use the Build Event Service and the remote CAS to keep the assets outside of Git while preserving hermetic tests. This pattern applies to any test suite with large golden artifacts, not screenshots alone. Similar story to what Lore tries to fix. There is one extra wrinkle to worry about: GPU-based rendering introduces tiny output differences that make pixel-perfect image comparisons difficult. Canva’s solution is to pin these tests to a specific hardware class by selecting an execution pool through the execution property. That trades scheduling flexibility for reproducible images, which is a good compromise for their workload. Optimizing the way Bazel handles large artifacts helps with performance, but there are many other things that do too. There were a large number of talks around this topic, so let’s dive into some of them. Guillaume Maudoux from Tweag presented Taming Configurations Explosion , a practical talk addressing problems they’ve seen while supporting builds that target physical hardware boards. Such builds grew to have more than three million configured actions even though only about 500,000 distinct actions needed to run. The root problem is that configuration settings accumulate. A project may begin with a setting for the target platform, then add the board’s operating system, its physical layout, its capabilities, and so on. Every setting creates a new dimension in the configuration space and, because each configuration gets a distinct output-tree hash, apparently-different actions may in fact do identical work. Before you know it, you have blown up the action graph and possibly your disk space too. In the example from the talk, 12 parameters end up representing 72 million possible configurations. Only 856 of those configurations matter, and a particular source file has just 39 meaningful ways to be compiled. The rest is duplication introduced by the model. There are three main tools to fight this: Reset transitions: These discard irrelevant configuration values as early as possible in the graph. The art is to move decisions up the dependency tree so that downstream targets do not carry unnecessary dimensions. The trade-off is that ordinary output can become unmanageable, forcing users toward . But then… requires a configuration, so some targets may not be queryable at all without one. Path mapping: If two actions cannot be made identical during analysis, Bazel can rewrite configuration-specific paths during execution and replace their hashes with a stable component. This should be seen as a measure of last resort, though, because subtle problems arise. For example, if the same logical path comes from different files from different configurations, Bazel disables path mapping silently. Tweag fixed Bazel so that different copies of the same file don’t disable path mapping, but debuggability continues to be a problem when this condition does not apply. Flag scopes: This new feature allows a flag to declare where in the graph it applies and to automatically reset to its default everywhere else. This is similar to a reset transition but requires less manual graph plumbing. On the other hand, describing the correct scope can sometimes be harder than writing the transition directly. Han-Wen Nienhuys from EngFlow presented Horapha: Your Personal Warm Bazel , a clever experiment to avoid repeatedly starting Bazel servers and rebuilding their in-memory state. Several CI systems already offer similar features for efficiency, but Horapha targets developer-initiated workflows. The idea is to snapshot a warmed-up Bazel JVM with a new command and save that to disk. A later either starts a normal server when no checkpoint exists or restores the snapshot and continues from the saved state. The implementation relies on CRIU (Checkpoint/Restore In Userspace) , a Linux-only technology that can serialize a running process to disk. Correct restoration requires preserving process IDs, which can be achieved by placing Bazel in a PID namespace. In other words: a container but without pulling in the full weight of Docker. The prototype is available in the Horapha repository with the corresponding Bazel changes in the horapha branch of Han-Wen’s Bazel fork . Han-Wen is now trying to carve a path to get this integrated into upstream Bazel. Did you know that Emacs works similarly? Your executable is actually a snapshot of the LISP machine computed during the build process and stored to disk by the portable dumper introduced in Emacs 27. John Cater and Antonio Di Stefano from EngFlow presented Persistent Test Runners . For a long time, Bazel has had persistent workers for compilation actions but supporting tests has remained elusive—yet persistent workers for tests promise to increase test performance significantly by reducing JVM startup times, sharing heavyweight fixtures across tests, and sharing state such as container images. The reason I said elusive is because Bazel has tried to solve this before. Twice. Google introduced a persistent test feature back in 2019 but it was rolled back that same day. The roll forward was attempted again a month later, already in 2020, but this time separating the feature flag from the runner. Unfortunately, the whole mechanism was scrapped in 2022 because it never worked reliably. The old design suffered from classpath problems after incremental builds, leaked state between tests, and was tightly coupled to Bazel’s native rule—an unacceptable constraint due to the desire to move all rules to Starlark. More fundamentally, the test protocol and the persistent worker protocol modeled very different things. The new proposal from EngFlow introduces an API that explicitly separates the settings and inputs used to create the runner from the data needed by one test request. That distinction is important because the runner infrastructure must be able to decide whether an existing JVM is still compatible with a new test. The team explored several alternatives along the way: Pre-warming the next JVM instead of keeping the current one alive. This provided more control over when and why to restart a test in a new JVM, but suffered from significant coordination overhead. Forking a JVM. This did not work because, due to POSIX semantics, only the calling thread survives a fork call. The JVM is heavily multithreaded, so if you end up losing all but one thread, the new JVM is just not going to work. Android’s Zygote. This provides a pre-warmed runtime ready to be forked ( , anyone?), but it exists only for ART, not the standard JVM, and it’s just not reasonable to expect a switch to ART. Checkpointing. Instead of forking a running process, why not snapshot it to disk so that it can be re-created again? This might have worked, like Horapha does for Bazel startup, but raised difficult questions about when to capture the process and how to handle state outside the JVM. In the end, the only piece that survived these experiments was the coordinator that asks the runner whether a JVM can be reused. The decision considers the Java executable, JVM options, driver code, plugin configuration, and the digests of all loaded JARs. Configurable hooks run at JVM start/stop events as well as before/after each test. When running Bazel’s own test suite, this approach reduced total test time by 46%. The prototype is available in the branches of TheGrizzlyDev/bazel and TheGrizzlyDev/rules_java . It can be tried with a local module override and . Unconference discussion topic proposals and votes for the second day. Remote execution BoF Chi Wang and Tiago Quelhas led the Remote Execution Birds of a Feather . I only stayed for half of it, and so I only captured the discussion around remote persistent workers. Persistent workers are already part of several commercial remote execution offerings, including BuildBuddy and EngFlow, but their implementation was derived from Bazel’s local persistent worker support, which is not… particularly well designed. For example, we have at least three different variants of the persistent worker protocol: one for “regular” persistent workers, another for multiplex persistent workers, and yet another for multiplex persistent workers that support cancellation. And the protocol does not clearly specify which flags and tools belong to the worker and which belong to the action being executed. In fact, these distinctions are currently determined heuristically, with the worker assuming that flag files correspond to the action and other flags to the worker. There was consensus that this should be cleaned up, but the unsatisfying conclusion is that rehashing these complaints and discussions is not going to lead anywhere until someone sits down and presents a specific proposal for a new API. So, if you are reading this and have… opinions… volunteer to do this. Helen Altshuler from EngFlow and Nikita Chepanov from Plaid presented Where Bazel Clusters Break at Scale: Field Notes from Plaid and the EngFlow Fleet . That’s quite a mouthful to say “load testing”. And the reason is none other than AI once again: Plaid’s build volume doubled during the year due to AI-assisted coding and is on track to reach four times its early-2026 baseline. With a predictable increase in load comes a predictable outage. So, instead of waiting for it to happen organically, Plaid deliberately chose to load-test their CI system. The goal was to reach multiples of the normal load and discover each bottleneck under controlled conditions. They had to go through six rounds of tests and fixes until they were able to sustain their desired target. The previous five uncovered problems in network bursts, AWS quotas, source control, CI autoscaling, and cache infrastructure. The solutions were not magical: find and raise limits, cache everything possible, and reduce demand where it does not add value. Examples of the last category include skipping tests for pull requests in the middle of a PR stack and avoiding uploads for actions when they are unlikely to be reused. An interesting observation is that Plaid runs EngFlow in Plaid’s own AWS account, so the cache cluster is co-managed. But careful: shared ownership can easily turn into ambiguous ownership. The two companies addressed this by agreeing on health metrics and thresholds upfront and putting them on a shared dashboard. Both sides now know who must act before developers notice an outage. Ah, one of my favorite topics. Back in my Google days, I spent at least three years of my so-called 20% time working on improving the performance of the Bazel sandbox on macOS. Those efforts were painful: creating a writable FUSE file system is difficult, and diagnosing mis-interactions with macOS was a horrifying exercise. Today, I’m not scared anymore: I’ve been recently using AI to write yet another file system at work and agents do exceedingly well at handling corner cases. Let’s see how modern solutions do better than what I originally tried. David Zbarsky from OpenAI presented actiond: The Quest for a Better Sandbox , which was the first of at least two talks on improving sandboxing performance and strictness. The project started from frustration with local sandbox escapes on macOS and eventually grew into a custom file system, a local virtual machine, and a Bazel-built Linux kernel. actiond pretends to be a remote executor, but the “remote” worker is a Linux VM running locally on the Mac. Bazel communicates with it over a and actiond implements both execution and a content-addressable store. Funnily enough, leveraging this VM for action execution results in faster Bazel builds on macOS than running actions natively. Inside the VM, actiondFS mounts a directory described by a protocol buffer and creates the action sandbox without building a forest of links. Same idea as my original sandboxfs , but the key difference is that actiondFS is a kernel module rather than a FUSE file system so it solves all performance and deployment problems I originally faced with FUSE. A mind-blowing mention was linux.bzl : a Bazel-native build of the Linux kernel, used in this project to build the actiond VM end-to-end with Bazel. This reminds me that I’ve been saying, since the inception of Bazel, that this build system is the perfect pairing for a monorepo like NetBSD’s or FreeBSD’s; and, in fact, I recently wanted a Bazel-native build of NetBSD to put the EndBOX together. I wonder how difficult it would be to hack something up these days with AI… Oh, and: . This flag finally replaces the super-complex script that Bazel uses to run a test with a native binary. This resolves some compatibility issues across platforms and should result in measurably faster test execution. Borja Lorente from Byte Bard Software presented The Sandbox Is a Filesystem: Content-Addressed Bazel Builds on macOS with FSKit , yet another talk on sandboxing and macOS. The immediate problem they tried to address was sandbox escapes in TypeScript builds. You might not be aware, but there happen to be some tools out there that, when faced with a symlink, decide to resolve the target of the symlink and then perform extra operations on that location, like finding sibling files and the like. The compiler is one such tool, and consequently, escapes the symlink-based sandbox used on macOS and behaves incorrectly. Aspect originally patched the JavaScript rules to intercept Node.js file-system calls and redirect them, but that solution stopped working when was rewritten in Go. Apple’s new FSKit framework should in theory be usable to solve this, as it’s “just” a new way of writing file systems in user space. If we could leverage FSKit, the idea then becomes simple: represent the sandbox as a file system and mount a content-addressed view of the action’s inputs within it. Identical subtrees across actions share nodes, contents are fetched lazily, and outputs write through to the host volume. You know, exactly like my own sandboxfs did back in the day with FUSE. Unfortunately, FSKit comes with its own set of problems: An FSKit extension ships as an application, which must be packaged and notarized. This might be OK, but what’s bad is that, because this comes from an application, macOS displays a TCC (Transparency, Consent, and Control) popup notification when an app such as the Terminal tries to access the FSKit volume. Not cool for automated (CI) deployments. Mounting takes hundreds of milliseconds, making a separate mount per action too expensive. This can be solved by reusing the same mount across actions and making the file system create different subtrees per sandbox. Again, like the original sandboxfs. User space file systems have… unavoidable overheads as most operations have to cross the kernel/user space boundary at least twice. These may or may not be acceptable. With my own FUSE-based solution years ago, I just couldn’t fix some performance issues due to some oddities in OSXFUSE. AMFI and Gatekeeper inspect each executable once , adding substantial latency on first execution. And because any executable exposed through a separate file system looks brand new to the kernel… performance tanks. My original sandboxfs mitigated this by keeping inode numbers stable across different instances of the same file across different sandboxes, but that’s what ultimately led to the blockers I encountered with OSXFUSE. Because of all these problems, FSKit was not the clear choice for a new sandboxfs, so the team evaluated alternatives for performance like pure file copying, the old symbolic links, hard links, and APFS’ . FSKit was best at creating the initial directory structure, but later operations such as , , and were slower than with the alternatives. The conclusion was that there is no perfect answer to a fast and secure sandbox on macOS. Symlinks are fastest but allow some tools to escape. Hard links are the second-best option but they cannot protect source files against writes and only work within one volume. is efficient but limited to APFS and, again, one volume. FSKit provides the right abstraction with frustrating deployment and runtime costs. Because of this, the outcome of the talk is a proposal for a new sandboxfs protocol , not a specific implementation. Namely: a way for Bazel to send a manifest describing the inputs plus settings such as network access to a sandbox service. With that, the service can create the sandbox directory and return its path; Bazel can execute the action; and the service can then report the outputs and tear the sandbox down. Different backends can implement the same protocol using the best mechanism for each machine. I like the proposal and the fact that what was old is new again, but there were two interesting questions from the audience. One was: “What about an NFSv4 server?”, which is how Buildbarn exposes efficient virtual file systems on macOS; and the other was: “Can we not implement a new protocol and instead reuse the RE API?” Switching gears to the more theoretical aspects behind Bazel, we can look at changes to a core piece of the ecosystem: the Starlark language. The star (wink, wink) of the show in this area were type systems. Alexandre Rostovtsev from Google presented Static types in Starlark , an update on the type system first discussed during an unconference session at BazelCon 2025. Bazel 8.8 and 9.3 parse the new annotations but otherwise treat them as no-ops, allowing rulesets to adopt the syntax without breaking those releases. Bazel 10 will check annotated files and type-checking should be enabled by default by the time the final release ships. The syntax is a subset of Python’s type annotations with extensions to support Starlark’s native types like providers and attributes, both of which require typed exhaustive dictionaries. This should make large rulesets easier to navigate and maintain, and it lays the foundation for better automated tooling. Right after Google’s update on native Starlark types, Tamir Duberstein from OpenAI presented Type-checking Starlark without waiting for Bazel . I originally read this title as “type-checking without starting a slow Bazel process”—but no, the “waiting for Bazel” part here refers to the fact that the original type-system feature request was filed six (!!) years ago, not addressed in a timely manner, and the ecosystem could not simply stand still until the Bazel team decided to do something. During these six years, Buck 2 has come up with type annotations and a full-featured LSP for their Starlark variant. On the Bazel side, starpls implements another language server and type checker, but its annotations live in comments and the resulting experience is not ideal. OpenAI’s approach is sty , which combines ideas from with ty , the Python type checker developed by Astral. This new project provides fast cross-file checking, resolution, editor integration, and go-to-definition support while avoiding dependencies on a particular Bazel release. One difficulty is that, even if Starlark looks like Python, it isn’t Python: Bazel gives the language several domain-specific semantics. For example, a rule’s fields have types, mandatory status, and default values derived from the rule declaration. A generic Python checker knows none of this, so has to model it explicitly. By “pure” coincidence, OpenAI’s choices here do not diverge much from Google’s official typing system, so there is a path towards reconciliation. The project also introduces files, which act like external stub files and describe types for dependencies without modifying their source. These are particularly useful for rulesets that must continue to support Bazel versions that cannot parse type annotations, because the annotations can live out of sight from Bazel. The last topic I have notes on are talks about rulesets, but I do not have a lot. Let’s just cover a couple of the talks I did attend and take notes from. David Zbarsky from OpenAI presented : {Fast, Hermetic, Ergonomic} — Pick 3 , a new Rust ruleset built to address the pain points that OpenAI encountered with at scale. The usual dependency flow takes and , creates a synthetic workspace, runs , and generates a Bazel-specific . Repinning is slow—roughly O(n^2) in the size of the dependency graph—and Bazel has to repeatedly ask Cargo to contact registries and download metadata. rules_rs avoids that architecture. Bazel already has a downloader and lockfile, so the new ruleset leverages those directly and performs dependency discovery only once per platform. At OpenAI, repins dropped from about ten minutes to 100 milliseconds and can happen as part of an ordinary . Build configuration is read from , avoiding a separate Bazel lock file and the need to keep generated configuration in sync with Cargo. Rust build scripts remain a challenge because they can perform arbitrary work but appear to Bazel as one opaque action. For example, OpenAI replaced the build script in with a dedicated bzlmod module so that Bazel could see and schedule the underlying work. The ruleset also builds the Rust standard library from source, which enables Tier 3 targets and tools such as Miri . Combined with a hermetic LLVM toolchain, can cross-compile projects such as Selenium to Linux, macOS, and Windows. The question from the audience was simple: “What is the carrot for choosing over Cargo?” And the answer was simple as well: at OpenAI, they observed that everything in CI that did not use Bazel was falling over under agent-generated load. Antonio Di Stefano and Yannic Bonenberger from EngFlow presented No Bytes Left Untracked—Bazel Supply Chain Security . The key message was that, while we have always worried about correct builds and Bazel delivers on them, that’s just not enough anymore. We must also be able to explain where every byte comes from and enforce policy over their provenance in order to defend against security threats. Supply-chain attacks are becoming more frequent, and frameworks such as SLSA cover the complete software development lifecycle rather than compilation alone. They include requirements around review, provenance, and Software Bills of Materials (SBOMs). Bazel has always been in a unique position to provide this provenance information because it has a precise dependency graph and runs actions in controlled environments. But a common difficulty is that, outside of Google, Bazel interacts with other ecosystems: third-party package managers bring their own manifests and lock files and coordinating those with Bazel is difficult. There is no uniform representation of package identity, licensing, or provenance. The supply-chain ruleset addresses this with a standard target. The goal is for every package in the Bazel Central Registry to expose its identity and attributes, including licensing information, through a small JSON representation. The presenters asked for help in achieving this, as annotating packages is tedious and, ultimately, the responsibility of their owners. The processing model looks like this: A “gather” aspect walks the target graph of the artifact that needs to be shipped. Each dependency contributes metadata through a transitive provider, effectively producing a serialized view of the relevant graph. Tools convert that data into standard SBOM formats such as SPDX and CycloneDX. Validation actions enforce organization-specific policy, such as banning a particular license from entering a product. This is useful, but the target graph alone cannot fully account for all bytes in an output. True end-to-end attestation also has to inspect the action graph and the environment in which those actions run. Questions like these are to be expected: Which tools transformed the inputs? Where did the actions run? Did those environments have known kernel vulnerabilities? The project roadmap includes rules, module extensions, macro definitions, and stricter build-level enforcement. The 1.0 release was scheduled to happen during BazelCon, but unfortunately they’ll be a few days late due to last-minute issues with documentation and the like. And that’s all I captured this year. There were many other sessions—including talks on hermetic LLVM, Zig package integration, Gazelle v2, CUDA compilation, and richer platforms—but I either did not attend them or did not take enough notes to write anything of substance. Apologies if I did not cover yours here. Check the official BazelCon 2026 schedule for the complete program and stay tuned for the production-grade recordings . Photo while running towards Amsterdam Centraal. The common thread across the conference was scale. AI agents are multiplying the number of builds, tests, and changes that our infrastructure must process, while Bazel users continue to push larger graphs through increasingly-specialized execution environments. The good news is that the ecosystem is responding: Bazel 10 brings meaningful core improvements, remote execution keeps getting smarter, and the BUILD Foundation gives community work a place to grow. But even if the ecosystem is responding, you must too. Bazel is positioned to be a great answer to scalability issues in development workflows thanks to its safe cross-machine, cross-user caching features. And Bazel is also a good way to remain secure amid the unprecedented number of changes to your third-party dependencies. If you have not yet considered Bazel, the best time to do so is today. Stay tuned for the next article! I got some really cool swag from one of the vendors and I promised them I’d write something up once I had a chance to evaluate it. Welcome to BazelCon 2026 sign. What follows is a recollection of my notes arranged by topic and intermixed with my own commentary and thoughts. Some sections and topics are more detailed than others because in some cases I didn’t have a seat and couldn’t type enough, and in others I got distracted in the hallways chatting with people. Speaking of people, several of you approached me to praise previous editions of these recaps, so I now feel obliged to write another one. Thanks for the kind comments! As we will see, “scale” was a central theme of the conference: AI is multiplying concurrent builds and tests, artifacts and graphs are growing at an accelerated pace due to new features like configuration transitions, and the ecosystem is responding by making execution, caching, and analysis more efficient. My highlights There is a lot to cover but here are a few things that felt memorable to me : The BUILD Foundation is now a reality, giving the Bazel ecosystem a vendor-neutral home. Its goal is to act as a proxy between the community and Google to help Google understand what to prioritize and to fund projects. If your company can spare “a few” dollars, please donate! AI-driven development is having a broad impact on the industry and, in particular, everyone is seeing their CI systems become overloaded. Well, news at 11: I’m dealing with this day in and day out. But what was new to me was that we at Snowflake are not the only ones struggling with local system overload. Lots of people out there have likewise “discovered” Git worktrees as a way to run multiple agents in parallel, which in turn means multiple concurrent Bazel servers. Bazel 10 is shaping up to be a substantial release that will help with the problem right above due to its many performance improvements and memory consumption optimizations. Have you struggled to keep Bazel up-to-date before? These days, if you want to get any platform-related work funded you have to spin it in terms of AI, so this release will be an easy sell. Let’s “Rewrite it in Rust”? I’m impressed. Google is seriously evaluating a progressive rewrite of Bazel in Rust, and this is probably the most exciting news I got out of the conference. You know I’ve been critical of Bazel’s usage of Java since day one so, if this takes off, I’ll be the first in line to evaluate the results (and it will likely push me to actually contribute to Bazel again). Fast and correct sandboxing on macOS remains a problem. This is “interesting” to me because it’s a problem I tried to fix almost ten years ago with the original sandboxfs, but I failed because of unexpected bugs in macOS’s FUSE support and eventually abandoned the idea when FUSE became a dead end on Apple’s platforms. Funnily enough, other folks have now reinvented sandboxfs—and even given it the same name (ugh)—and there is even another implementation of a similar idea in the form of actiondFS. Types are coming to Starlark, but Bazel’s late arrival to the party means that multiple competing approaches now exist. We have at least two LSPs with different annotation mechanisms and Buck 2’s own syntax. Hopefully they can all converge. Platforms and configurations remain difficult to model at scale. Careless use of transitions and build settings can produce an explosion of configured actions. Apparently, as one speaker noted, AI agents love transitions for some reason, which is interesting because they are not a popular feature and they are not particularly easy to use. Agents run more builds more frequently than humans, discover and invoke targets that were often “internal only”, and explore several approaches in parallel. Your intuition about how to evaluate which builds matter and how to measure them is probably wrong by now. Bazel and IDEs have never played great together and maybe that just doesn’t matter anymore. We are seeing a sharp decline in IDE usage, although developers still want a way to browse code changes and debug them. This means LSPs are key now to support “leaner” IDEs, and maybe standalone debuggers. Short build and test latency is critical when a human must remain focused on a coding task but, in an agentic workflow, the constraints are different. You know that, after you hit “execute this plan”, the agent will take many minutes to return so minimal build latency is not as important. And actually… maybe you now want to trade some latency in exchange for extra validations so that agents have to take fewer turns to converge. And because humans are now waiting for agents to finish for long periods of time, they have to fill that time with other tasks, which has driven them to adopt Git worktrees en masse. This is leading to scalability problems on dev machines because multiple concurrent Bazel server processes are not great for memory and disk usage. to download filtered logs for a build. to answer questions such as “Why was my build slow?” which are extremely common in the Bazel ecosystem. to start a remote Firecracker VM and run Bazel inside of it. The VMs are snapshotted for quick reuse, and the runners can execute arbitrary commands rather than Bazel alone. to diagnose a failed build and either create a pull request or push a commit with the proposed correction. to perform a review and post comments to GitHub. Correctness: Good, because equivalence is the central constraint of the loop. Hermeticity: Good, but you might need to do extra upfront work to remove host-specific behavior from the reference build before starting. Efficiency: Usually good when standard rules can model the build. Complex projects with custom build rules may end up with overly large Bazel actions though. Maintainability: Unsurprisingly, the weakest point. Agents tend to model variation with configuration flags instead of proper platforms and toolchains, which is not idiomatic to Bazel. Expert review of AI outputs remains critical, which is, again, not surprising. Reset transitions: These discard irrelevant configuration values as early as possible in the graph. The art is to move decisions up the dependency tree so that downstream targets do not carry unnecessary dimensions. The trade-off is that ordinary output can become unmanageable, forcing users toward . But then… requires a configuration, so some targets may not be queryable at all without one. Path mapping: If two actions cannot be made identical during analysis, Bazel can rewrite configuration-specific paths during execution and replace their hashes with a stable component. This should be seen as a measure of last resort, though, because subtle problems arise. For example, if the same logical path comes from different files from different configurations, Bazel disables path mapping silently. Tweag fixed Bazel so that different copies of the same file don’t disable path mapping, but debuggability continues to be a problem when this condition does not apply. Flag scopes: This new feature allows a flag to declare where in the graph it applies and to automatically reset to its default everywhere else. This is similar to a reset transition but requires less manual graph plumbing. On the other hand, describing the correct scope can sometimes be harder than writing the transition directly. Pre-warming the next JVM instead of keeping the current one alive. This provided more control over when and why to restart a test in a new JVM, but suffered from significant coordination overhead. Forking a JVM. This did not work because, due to POSIX semantics, only the calling thread survives a fork call. The JVM is heavily multithreaded, so if you end up losing all but one thread, the new JVM is just not going to work. Android’s Zygote. This provides a pre-warmed runtime ready to be forked ( , anyone?), but it exists only for ART, not the standard JVM, and it’s just not reasonable to expect a switch to ART. Checkpointing. Instead of forking a running process, why not snapshot it to disk so that it can be re-created again? This might have worked, like Horapha does for Bazel startup, but raised difficult questions about when to capture the process and how to handle state outside the JVM. Unconference discussion topic proposals and votes for the second day. Remote execution BoF Chi Wang and Tiago Quelhas led the Remote Execution Birds of a Feather . I only stayed for half of it, and so I only captured the discussion around remote persistent workers. Persistent workers are already part of several commercial remote execution offerings, including BuildBuddy and EngFlow, but their implementation was derived from Bazel’s local persistent worker support, which is not… particularly well designed. For example, we have at least three different variants of the persistent worker protocol: one for “regular” persistent workers, another for multiplex persistent workers, and yet another for multiplex persistent workers that support cancellation. And the protocol does not clearly specify which flags and tools belong to the worker and which belong to the action being executed. In fact, these distinctions are currently determined heuristically, with the worker assuming that flag files correspond to the action and other flags to the worker. There was consensus that this should be cleaned up, but the unsatisfying conclusion is that rehashing these complaints and discussions is not going to lead anywhere until someone sits down and presents a specific proposal for a new API. So, if you are reading this and have… opinions… volunteer to do this. Where Bazel clusters break at scale Helen Altshuler from EngFlow and Nikita Chepanov from Plaid presented Where Bazel Clusters Break at Scale: Field Notes from Plaid and the EngFlow Fleet . That’s quite a mouthful to say “load testing”. And the reason is none other than AI once again: Plaid’s build volume doubled during the year due to AI-assisted coding and is on track to reach four times its early-2026 baseline. With a predictable increase in load comes a predictable outage. So, instead of waiting for it to happen organically, Plaid deliberately chose to load-test their CI system. The goal was to reach multiples of the normal load and discover each bottleneck under controlled conditions. They had to go through six rounds of tests and fixes until they were able to sustain their desired target. The previous five uncovered problems in network bursts, AWS quotas, source control, CI autoscaling, and cache infrastructure. The solutions were not magical: find and raise limits, cache everything possible, and reduce demand where it does not add value. Examples of the last category include skipping tests for pull requests in the middle of a PR stack and avoiding uploads for actions when they are unlikely to be reused. An interesting observation is that Plaid runs EngFlow in Plaid’s own AWS account, so the cache cluster is co-managed. But careful: shared ownership can easily turn into ambiguous ownership. The two companies addressed this by agreeing on health metrics and thresholds upfront and putting them on a shared dashboard. Both sides now know who must act before developers notice an outage. Sandboxing and local execution Ah, one of my favorite topics. Back in my Google days, I spent at least three years of my so-called 20% time working on improving the performance of the Bazel sandbox on macOS. Those efforts were painful: creating a writable FUSE file system is difficult, and diagnosing mis-interactions with macOS was a horrifying exercise. Today, I’m not scared anymore: I’ve been recently using AI to write yet another file system at work and agents do exceedingly well at handling corner cases. Let’s see how modern solutions do better than what I originally tried. actiond: the quest for a better sandbox David Zbarsky from OpenAI presented actiond: The Quest for a Better Sandbox , which was the first of at least two talks on improving sandboxing performance and strictness. The project started from frustration with local sandbox escapes on macOS and eventually grew into a custom file system, a local virtual machine, and a Bazel-built Linux kernel. actiond pretends to be a remote executor, but the “remote” worker is a Linux VM running locally on the Mac. Bazel communicates with it over a and actiond implements both execution and a content-addressable store. Funnily enough, leveraging this VM for action execution results in faster Bazel builds on macOS than running actions natively. Inside the VM, actiondFS mounts a directory described by a protocol buffer and creates the action sandbox without building a forest of links. Same idea as my original sandboxfs , but the key difference is that actiondFS is a kernel module rather than a FUSE file system so it solves all performance and deployment problems I originally faced with FUSE. A mind-blowing mention was linux.bzl : a Bazel-native build of the Linux kernel, used in this project to build the actiond VM end-to-end with Bazel. This reminds me that I’ve been saying, since the inception of Bazel, that this build system is the perfect pairing for a monorepo like NetBSD’s or FreeBSD’s; and, in fact, I recently wanted a Bazel-native build of NetBSD to put the EndBOX together. I wonder how difficult it would be to hack something up these days with AI… Oh, and: . This flag finally replaces the super-complex script that Bazel uses to run a test with a native binary. This resolves some compatibility issues across platforms and should result in measurably faster test execution. The sandbox is a filesystem Borja Lorente from Byte Bard Software presented The Sandbox Is a Filesystem: Content-Addressed Bazel Builds on macOS with FSKit , yet another talk on sandboxing and macOS. The immediate problem they tried to address was sandbox escapes in TypeScript builds. You might not be aware, but there happen to be some tools out there that, when faced with a symlink, decide to resolve the target of the symlink and then perform extra operations on that location, like finding sibling files and the like. The compiler is one such tool, and consequently, escapes the symlink-based sandbox used on macOS and behaves incorrectly. Aspect originally patched the JavaScript rules to intercept Node.js file-system calls and redirect them, but that solution stopped working when was rewritten in Go. Apple’s new FSKit framework should in theory be usable to solve this, as it’s “just” a new way of writing file systems in user space. If we could leverage FSKit, the idea then becomes simple: represent the sandbox as a file system and mount a content-addressed view of the action’s inputs within it. Identical subtrees across actions share nodes, contents are fetched lazily, and outputs write through to the host volume. You know, exactly like my own sandboxfs did back in the day with FUSE. Unfortunately, FSKit comes with its own set of problems: An FSKit extension ships as an application, which must be packaged and notarized. This might be OK, but what’s bad is that, because this comes from an application, macOS displays a TCC (Transparency, Consent, and Control) popup notification when an app such as the Terminal tries to access the FSKit volume. Not cool for automated (CI) deployments. Mounting takes hundreds of milliseconds, making a separate mount per action too expensive. This can be solved by reusing the same mount across actions and making the file system create different subtrees per sandbox. Again, like the original sandboxfs. User space file systems have… unavoidable overheads as most operations have to cross the kernel/user space boundary at least twice. These may or may not be acceptable. With my own FUSE-based solution years ago, I just couldn’t fix some performance issues due to some oddities in OSXFUSE. AMFI and Gatekeeper inspect each executable once , adding substantial latency on first execution. And because any executable exposed through a separate file system looks brand new to the kernel… performance tanks. My original sandboxfs mitigated this by keeping inode numbers stable across different instances of the same file across different sandboxes, but that’s what ultimately led to the blockers I encountered with OSXFUSE. A “gather” aspect walks the target graph of the artifact that needs to be shipped. Each dependency contributes metadata through a transitive provider, effectively producing a serialized view of the relevant graph. Tools convert that data into standard SBOM formats such as SPDX and CycloneDX. Validation actions enforce organization-specific policy, such as banning a particular license from entering a product.

0 views

Widespread PHP Flaw May Cause Many Site Outages Today

Expect to see quite a few websites serving error pages today: Nearly 70 percent of websites need to update their core software to fix a pair of vulnerabilities that allow an attacker to seize full control over affected servers. Experts say there are working exploits for the flaws, and that these critical bugs are already being exploited in the wild. Image: Shutterstock.com, Sashkin. The flaws at issue are present in PHP , the programming language that powers sites running on a large number of web publishing systems, including Drupal , Magento , Joomla and WordPress . Earlier today, PHP released an emergency security update to fix two critical bugs that can allow an attacker to execute code of their choosing on a vulnerable server. Reuters reports that government websites in Europe and elsewhere went offline today after the PHP vulnerabilities were disclosed. Cloudflare said it has already detected some exploitation of the flaw, and that at 3:02 am (UTC) it implemented web application firewall rules to protect websites from attack traffic seeking to exploit the bugs, which could cause a denial of service condition, remote code execution, and data exposure. OpenAI , which was involved in the vulnerability research and outreach, said “given the severity of these flaws and PHP’s widespread use, we consider this one of the most impactful security issues in recent memory.” Censys , a company that tracks the technology used by Internet hosts, said a recent scan identified approximately 2.58 million Internet facing hosts and 54.9 million web properties running PHP. Security experts at Wiz said every PHP version released in the last decade is affected by at least one of these vulnerabilities [full disclosure: Wiz is an advertiser on this blog]. “These findings rank among the most severe vulnerabilities discovered in PHP, and arguably in software history,” reads a blog post published today by a team of researchers at Wiz, which was one of several organizations credited with discovering the vulnerabilities. “The underlying flaws had been present for decades, but demonstrating their exploitability required an exceptionally complex chain of steps, at the edge of what human researchers could practically achieve. Frontier AI models substantially reduced that barrier, turning a longstanding flaw into an exploit.” The Wiz researchers say it is likely the PHP vulnerabilities will be mass-exploited to install web-based backdoors or “web shells,” which give attackers a web-based panel that allows them to remotely control infected sites. Wiz said that prior to the PHP bugs being publicly disclosed, the company worked with the PHP team, Calif and OpenAI to measure the size of the problem and coordinate patch verification and disclosure. The PHP zero-day vulnerabilities are being tracked by their CVE numbers, CVE-2026-109618 and CVE-2026-109619 , and they affect all web servers running PHP 5.4 or later. The bugs are fixed in PHP 8.5.12 , 8.4.27 , 8.3.36 , and 8.2.35 . According to Wiz, PHP is so deeply embedded in many web applications that we are likely to see organizations struggling to patch these vulnerabilities for some time to come, comparing this PHP vulnerability pair with the Log4Shell weakness that emerged in 2021 — a widespread, severe-as-it-gets security flaw in Log4j, a popular Java logging framework. “A vulnerability in core PHP reaches far beyond a single application,” the Wiz researchers wrote. “PHP runs across clouds, hosting providers, content-delivery networks and millions of independently managed servers. Reducing exposure before the technical details became public required coordinated work across that entire ecosystem.” The SANS Internet Storm Center is keeping an eye on major software platforms that are shipping updates to deal with these PHP flaws. For example, Ubuntu just released updated PHP packages. For a technical deep-dive on these vulnerabilities that tells the timeline of the discovery of these bugs in a comic book style, check out this post from Calif , another technology company credited with finding the PHP flaws. This is a fast-moving story. Updates will be noted here with timestamps. Update, 2:30 pm ET: Add figures from Censys and a link to Calif’s writeup.

0 views
Unsung Today

Before pixels: Speed-Minder

As you could probably tell, I was driving a bit recently, and once in a while saw this kind of a sign , often equipped with a (beloved) segmented font, reporting your current speed as detected by radar: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/1.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/1.1600w.avif" type="image/avif"> Just today, I learned of an early version of this idea: = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/2.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/2.1600w.avif" type="image/avif"> = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/3.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/3.1600w.avif" type="image/avif"> = 2x) and (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/4.2096w.avif" type="image/avif"> = 3x) or (width >= 700px)" srcset="https://unsung.aresluna.org/_media/before-pixels-speed-minder/4.1600w.avif" type="image/avif"> This was a “Speed-Minder” deployed by Illinois State Police in the late 1950s or early 1960s. The car didn’t have a radar, it just reported its own speed , which I thought was clever. I am not even sure if it was as much to prevent drivers going too fast – I guess that’s what the name suggests – or just to help you calibrate your car’s own speedometer. I can’t find a lot of information whether this was effective in any way, but I just liked this visual of a non-digital speedometer mounted atop an old police car. (Before Pixels is an occasional foray into design ideas before screens came around, shared for context, amusement, and inspiration.)

0 views
Unsung Today

“No results” doesn’t mean “no results,” pt. 1

This is something I see time and again in Google Maps when plotting directions: = 3x)" srcset="https://unsung.aresluna.org/_media/no-results-doesnt-mean-no-results-pt-1/1-framed.1600w.avif" type="image/avif"> You might be thinking “this feels like a genuine error – not every two places on earth can be connected,” but that’s not it. I am in a good traffic corridor and, ten seconds later, doing the same exact thing again shows proper directions: = 3x)" srcset="https://unsung.aresluna.org/_media/no-results-doesnt-mean-no-results-pt-1/2-framed.1600w.avif" type="image/avif"> The clue as to what’s going on is elsewhere in both screenshots. My cell signal is low, and the Google Maps misrepresents no results arriving because of slow connection, with no results being there at all . Just to get Google Maps off the hook, here’s a similar thing in a Mastodon client Ivory: = 3x)" srcset="https://unsung.aresluna.org/_media/no-results-doesnt-mean-no-results-pt-1/3-framed.1600w.avif" type="image/avif"> There are 123 posts to be seen here, as the page itself conveys elsewhere. But at this moment, the internet is slow, and Ivory jumps to a wrong “no posts found” conclusion, instead of saying “cannot retrieve the posts because of a bad connection.” I believe what’s happening in these moments is that one kind of “no results” (software asked for posts, but the database results came empty) gets bundled with another (software asked for posts, but the database results didn’t come back in time, or transmission was interrupted). This feels important to me, because the wrong kind of an error can really confuse people and make them jump to the wrong conclusions – I guess Mark Simonson isn’t active on social! I guess I can’t drive there! – or even create bad mental models. Also, while this was a temporary situation for me, for a lot of people bad connection is a constant fact of life, so they might encounter this kind of confusion on a daily basis. Software should differentiate between different ways something can be zero , and in this case, communicate that back to the user. What’s really strange is that Google Maps has a separate “no internet connection” state that you can see in other moments – incl. an extra thoughtful and important manual try again button… = 3x)" srcset="https://unsung.aresluna.org/_media/no-results-doesnt-mean-no-results-pt-1/4-framed.1600w.avif" type="image/avif"> …but apparently still fails to use it in all the cases.

0 views

Upgrade your PHP installs immediately to protect against php2shell

This morning, two critical PHP Security Advisories were published: If you're running PHP for any service, you need to upgrade immediately to 8.2.35, 8.3.36, 8.4.27, or 8.5.12. And if you use Remi's repos on RedHat-derivative Linux distros, you need to switch to official repos temporarily as Remi's on vacation and can't update his community repo. (Reminds me of xkcd 2347 ). I'm glad I finished migrating this website from a PHP-based CMS to Hugo earlier this year—having a static website and a minimal commenting system saves on hosting costs and dramatically reduces attack surfaces. Especially in this era of AI tooling making exploit discovery easier. RCE via OOM corruption (9.2/10) RCE via stale global state (9.2/10)

0 views

Forcing and detouring

A standard career ladder document is often aggressively detailed, listing out competencies, delivery outcomes, behavioral qualifications, technical achievements, and more, for what it takes to reach each level in an organization. What is usually missing from those same documents is any sense of the pyramidal shape of the structures they define. That is, at each level of the ladder, there are fewer and fewer opportunities. If a team of ten engineers each work hard and meet the requirements of a senior engineer, but the organization only has budget for two senior engs, only two people are getting promoted. Promotions are both scarce and competitive; they create winners and losers. What happens to the losers? Christian Gläßel and Adam Scharpf ask this question of military dictatorships, digging into historical data from Argentina and elsewhere. While it’s often presumed that dictatorships operate on nepotism rather than merit, they find that merit-based systems are in fact common among authoritarian regimes, even existing alongside flagrant patronage. This is perhaps not unexpected, as a regime that operated purely on nepotism would surely collapse from incompetence sooner rather than later. Perhaps more surprising is that a merit-based system can still give rise to horrific violence. The reasons for that emerge as an answer to the above question: those who don’t make it up the ladder in the usual way must find other avenues to succeed. Gläßel and Scharpf write: By career pressure, we understand an individual’s fear resulting from any impediment to their continued employment or advancement within an organization. In order to salvage their careers, pressured individuals have an incentive to pursue one of two extreme strategies. First, they may force their way up. By forcing , we understand officers’ participation in a coup attempt in the hope of commending themselves to successor regimes. Second, they may detour and go the extra mile. By detouring , we refer to officers applying for unpopular assignments where they can stand out and demonstrate their value in the hope that their loyalty will be rewarded by the current regime. Gläßel and Scharpf, Making a Career in Dictatorship, page 12 The unpopular assignments are the dirty work of surveillance, intimidation, detention, torture, extrajudicial murders, and so on. The usefulness of the detouring path offers one reason for why authoritarian regimes often have vast security apparatuses: the dirty work gives pressured officers a path to continued employment that looks like a better bet than fomenting a coup. In other words, the security apparatus is a good place for the regime to park surplus workers, directing them to turn their ire on the people instead of the regime itself. The mechanism by which both detouring and forcing are produced? The lowly career ladder. We argue that three basic characteristics of security organizations influence the career opportunities of officers with important implications for their incentives and behaviors. First, security organizations are hierarchical. Each step on the career ladder brings additional power, pay, and prestige. This is why most individuals seek to climb up in the hierarchy. Second, security organizations are pyramid-shaped. There is an abundance of positions at the bottom but only few lucrative posts at the top. Individuals who want to climb up thus face organizational bottlenecks and competition for promotions. Third, in the organizations, promotion systems define the requirements that individuals have to meet in order to climb up. These requirements can be formal qualifications, individual traits, or personal connections. What unifies them is that those who fail to meet the requirements have little chances of improving their position. These are the individuals who face career pressure, and who are most likely to either detour or force their way up. Gläßel and Scharpf, Making a Career in Dictatorship, page 12 Obviously, the same mechanisms exist in corporate environments, where detouring may take the form of fraud, embezzlement, bribery, or the pursuit of any number of unethical business practices. Someone who has been routinely turned down for a promotion in a more-or-less above ground organization may be willing to take a job with the startup that sees breaking the law as the fastest route to product-market fit. Or they may see it as entirely rational for them to volunteer for the new product line which is moving at a rapid pace but which is definitely not following best practices for keeping kids safe. You get the idea: career pressure in any context drives people to places we would rather they not go. This is not an exculpatory revelation. People are responsible for their choices, even in an unequal and unfair world. No one who chooses the work of disappearing my neighbors gets my sympathy. But surely we need to also acknowledge the systems that make those choices appealing, and work to undo them. Gläßel and Scharpf note that one of the ways to interrupt this pattern is to offer people a viable escape path; that is, give them stable, decently-paid, and respectable jobs they could flee to as an alternative to doing the dirty work. To which, yes, of course. We already had plenty of reasons to make good work a major policy goal. But if good work also keeps people from joining the secret police? All the better. But I’ll go a step further: if one of the outcomes of pyramid-shaped hierarchical systems is a group of losers who may, out of desperation, be recruited into doing harm in order to save face or provide for their family, then maybe that system has to go. Over the past many years, there’s been a concerted effort across industries to revise career ladders to be more equitable. That effort has included attempts to rigorously define and measure competencies and achievements in order to rule out (or, at the least, drastically reduce) inherent biases that reward privileged groups while punishing minoritized ones. But is any system that routinely creates winners and losers really equitable? If one outcome of a hierarchy is that there are always some people who fear for their livelihood, what exactly have we achieved? Maybe all the energy put into making better career ladders should instead be used to figure out how we should work together once we tear every last ladder down. View this post on the web , reply via email , or become a supporter .

0 views

Making a Career in Dictatorship

What if the standard career path was a driver of authoritarianism? That’s the theory put forth by Christian Gläßel and Adam Sharpf, who draw on copious historical data from Argentina’s army, as well as case studies from Hitler’s Germany, Stalin’s Soviet Union, and Jawara’s Gambia. What they find is that two of the defining characteristics of dictatorships—huge security apparatuses engaging in surveillance, intimidation, detention, torture, and worse; and the ever present threat of a violent coup—emerge from structures that produce career pressure. Officers left at the bottom of the career ladder will do whatever it takes to improve their lot, even if that means taking on the dirty work or leading a revolt. The comparisons to authoritarianism in the present-day US administration are striking and instructive, as are the very discomfiting comparisons to corporate environments that mimic the same. When a system creates losers, the losers don’t merely vanish into the background—they fight. And we all suffer the consequences. View this post on the web , reply via email , or become a supporter .

0 views

Fragments: October 21

Gergely Orosz is frustrated at those that entered his explicitly “No AI” essay competition and used AI. He goes on to say: When I start to suspect some part is AI about someone I don’t know: how can I tell how much of it is? And how much time and effort do I want to invest to figure out? I fear most people do not realize this last part: that when it takes time and effort from others to figure out what % is AI, and what % is YOU, then I will simply assume it’s probably 100% AI and 0% you So when producing anything that is meant for other humans, if you use even a little AI, you risk the assumption that it is all AI and pointless to pay attention to In general, I agree with him, and react much the same. Once I hear LLM Voice, I flip the bozo bit and check out of the post. But as I do this I have caveats. How accurate is my neural net at AI-detection, are humans taking on AI-ish elements in their normal communication? And more seriously there are some valid uses for AI. Jim Highsmith’s story of his second brain helping him deal with Parkinson’s is one. Another is folks who don’t know English well, using AI to translate. Am I being unfair when I flip the AI voice bit when I read/listen to them? ❄                ❄                ❄                ❄                ❄ I was sad to hear that the Grace Hopper Celebration is canceled this year. It’s an event run by Anitab.org to promote women and non-binary technologists in the software industry. Many of my colleagues have been encouraged and inspired by going to this event, which makes a refreshing change to what is often a male-dominated world. It seems the current crusade against diversity initiatives has had a big impact on funding. We are still a long way from where we should be on gender diversity in our profession, and losing an event like this only makes things more difficult. ❄                ❄                ❄                ❄                ❄ I’ve always found Cindy Sridharan’s writing to be worth reading, and she’s broken a quiet period with a monster of an article: How to effectively debug when you no longer understand the code . Since Medium estimates it as a 64 minute read, I didn’t jump in lightly, but settled down on a flight from Amsterdam to Stuttgart. I’m glad I did, because there’s lot of good material in there, and I’d struggle to find anything to cut. In the article she uses three recent bug hunts to surface principles for how to best use an AI tool for debugging. Much of this is governed by this wise observation: Agents are not humans. They’re far more capable than humans when it comes to many things, and we should be leaning into these strengths, rather than trying to get agents to replicate human patterns of problem solving which might be suboptimal in agentic contexts. One conclusion from her experiences is that the code often isn’t the best thing for agents to look at having an agent start an investigation by first reading the code is an anti-pattern. In fact, reading the code first to formulate hypotheses about a bug should always be the very last resort of the agentic investigation process, not the starting point. An agent should first collect all available evidence about the bug, and only then formulate the hypotheses from the code that might best explain what’s being observed. She distinguishes between a bottom tier of facts: raw data that agent can find about the behavior of the system - and an upper tier of hypotheses: inferences that the agents make based on that data. Diagnosing a bug now becomes a problem of finding the hypothesis in the top tier that satisfies every fact from the bottom tier. The agents need to be steered towards the hypotheses that are the likest cause of the bug and then subject these hypotheses to validation. She has a three-step process to do this. First she identifies the most important facts, the signals that might explain or identify the bug. The factual tier has many data points. Not all of them are equally valuable. In fact, some of it might be active noise that doesn’t help an agent to be steered towards most promising hypothesis. The agent first needs to identify the data points in the factual tier that are actually related to the bug. Agents do this best when they are given a high-quality control A control is a behavior of the system that doesn’t exhibit the bug. This may be requests that trigger the bug compared to those that don’t, or different builds of the product, or the same build in different environments. With signals highlighted, she then focuses on the hypotheses that are most promising, because they fit best with the signals. A hypothesis should satisfy all the facts, the most valuable signals are those that are only satisfied by a few hypotheses. A table of hypotheses and signals helps visualize the strength of the signals and the likelihood of the hypotheses. The third step is then validating the promising hypotheses against every fact, treating each fact as constraint on the solution. Across the three bugs chronicled in this post, my most valuable contributions weren’t knowledge of the code. They were picking a control, choosing a constraint, and rejecting a hypothesis that hadn’t been validated. The engineers who thrive in an agent-native world will be the ones who are good at designing such verification loops, whether or not they understand the code it verifies. This directing has to remember the opening point that agents have different capabilities to humans. A human wants to deal with less data. All abstractions we currently have (aggregation, visualizations etc) are designed to help humans deal with less data. An agent, however, needs more raw data; its strength lies in processing huge volumes of data at a rapid clip. Aggregation — the thing that makes a dashboard useful to a human — is often the thing that destroys the value of the signal for an agent Agents’ ability to consume lots of raw data also affects how we build systems. More logging gives agents more data to chew on. And thus far, the human is still necessary to direct the agent In each of the three bugs chronicled in this post, the agent was more than capable of getting to the root cause by itself, but it didn’t do so. It didn’t set up a control in the “latency bug” until I asked it to While it’s a long post, it’s engagingly written and full of useful details. I hope my little summary encourages you to give it the read it deserves.

0 views

Netflix Earnings, Business or Franchise, Disney’s Deal

Netflix has a solid business, which is exactly the problem: the company increasingly seems like a business and not a franchise, at least in terms of growth.

0 views
Unsung Yesterday

“Because most users do not use dates before March 1, 1900, this problem is rare.”

There are really only three contenders for the most popular spreadsheet software: VisiCalc, the first computer spreadsheet and a system-seller for some home computers in the late 1970s, Lotus 1-2-3 dominating early PCs in the 1980s, and then Microsoft Excel (preceded very briefly by Multiplan). Excel dominated the market since the 1990s – so long it’s easy to assume it has always been there, but even hiding within Excel are some quirks of its predecessors. One of them is documented in an official Microsoft Excel troubleshooting document : When Lotus 1-2-3 was first released, the program assumed that the year 1900 was a leap year, even though it actually was not a leap year. This made it easier for the program to handle leap years and caused no harm to almost all date calculations in Lotus 1-2-3. When Microsoft Multiplan and Microsoft Excel were released, they also assumed that 1900 was a leap year. This assumption allowed Microsoft Multiplan and Microsoft Excel to use the same serial date system used by Lotus 1-2-3 and provide greater compatibility with Lotus 1-2-3. Treating 1900 as a leap year also made it easier for users to move worksheets from one program to the other. Yes, even in today’s version of Excel, you can easily get to Feb 29, 1900 – a date that never existed: I find what follows in the same doc really funny, as you can sense perhaps a frustration of someone needing to answer this over and over again, or held to blame for the decision that wasn’t even theirs to begin with: Although it is technically possible to correct this behavior so that current versions of Microsoft Excel do not assume that 1900 is a leap year, the disadvantages of doing so outweigh the advantages. If this behavior were to be corrected, many problems would arise, including: If the behavior remains uncorrected, only one problem occurs: But I also appreciate the details of what is a great example of bug-for-bug compatibility . Almost all dates in current Microsoft Excel worksheets and other documents would be decreased by one day. Correcting this shift would take considerable time and effort, especially in formulas that use dates. Some functions, such as the function, would return different values; this might cause formulas in worksheets to work incorrectly. Correcting this behavior would break serial date compatibility between Microsoft Excel and other programs that use dates. The function returns incorrect values for dates before March 1, 1900. Because most users do not use dates before March 1, 1900, this problem is rare.

0 views
Unsung Yesterday

“We find many users write to us in a spirit of collaboration.”

From software company Linear, a blog post from last year titled Why we committed to a zero-bugs policy : When we tell people that Linear maintains a zero-bug policy a common response is disbelief. It may sound like a ridiculous approach, but we do it because no other way makes sense. The zero-bug stance means that we address bugs immediately, with the exact number of days depending on the severity: low-priority bugs need to be addressed within 7 days, high-priority bugs within 2. We formalized this approach two years ago. The impetus was actually a bug in a popular consumer app that I had reported to their team. Finally two years ago—and five years after I first reported the bug—I saw that it got fixed. I thought to myself, “wow, millions of users suffered through this bug for years for no reason.” If the company was going to fix the bug eventually, it would have been so much better to fix it right away. That’s the big idea behind our zero-bug policy. We want Linear to be a solid, high-quality product, which means we’re going to address any bug that comes in. Fixing a bug takes the same amount of work whether we do it right away or put it off. But it’s not a zero-sum game: fixing it immediately gives us a higher-quality product and spares users unnecessary pain for the same overall effort. It’s worth a read – especially if you’re a software quality process wonk – with some interesting observations on context switching and other things, for example: I’ve heard stories of companies whose backlogs grow to thousands of bugs. Eventually, instead of fixing the bugs, they just delete the whole thing and start over. It’s a reflection of how when you put bugs in a backlog, in most cases what you’re really saying is you’re never going to get to them. I also applaud the team for recognizing and pointing to the momentum boost and virtuous cycle on both sides – makers and their customers – when something gets fixed quickly after being reported: It’s not uncommon for Customer Support to file a bug in the morning—often through our Intercom integration—and have it fixed by lunch. That kind of turnaround allows us to turn a bad experience—an encounter with a bug—into an excellent one that changes their whole perspective on what it’s like to reach out to a company when something is broken. Over time these experiences have molded the way our user base reacts to imperfections in the product. Instead of coming to us angry or frustrated, we find many users write to us in a spirit of collaboration—working hand in hand with us to make Linear a better product because they trust we’ll respond quickly. It also often turns them into Linear advocates. However, there’s one thing that feels unresolved. The post says “low-priority bugs need to be addressed within 7 days, high-priority bugs within 2” – but what if a bug cannot be fixed within these time limits? I can think of a few reasons: I know getting deeper into the weeds would not make for a nice post with a punchy ending, but I also think the system feels incomplete this way – as with every process, a careless application of a “zero-bugs policy” could fall prey to a sibling of Goodhart’s Law , as the team starts deluding itself into categorizing things as “not bugs,” or find other ways to avoid bigger challenges if they cannot be fixed within the given time limits. Black-and-white systems struggle with shades of gray, and I’d be curious what is Linear’s answer to tackling this tricky part. a bug has a dependency on another, slower-moving piece of software (e.g. the browser or the operating system), the fix is a bigger systemic or change management challenge that will take months if not years to complete (e.g. a keyboard shortcut change or an internal migration), the fix requires a redesign larger than initially suspected, the team disagrees internally on the fix and needs time to hash it out.

0 views
Michael Lynch Yesterday

Refactoring English: Month 22

Hi, I’m Michael. I’m a software developer and founder of small, indie tech businesses. I’m currently working on a book called Refactoring English: Effective Writing for Software Developers . Every month, I publish a retrospective like this one to share how things are going with my book and my professional life overall. At the start of each month, I declare what I’d like to accomplish. Here’s how I did against those goals: This is finally complete! I got caught in a loop because there’s a one-week turnaround between ordering a print and getting to see what a physical copy looks like. So, I’d order a print and make some improvements while I was waiting. By the time I received the test print, I wanted to include the last week of improvements, so I had to order another test print and wait another week. And while I was waiting, I made more improvements… Finally, I had to decide that a version was good enough and that it was ready for customers, but I’m continuing to make small tweaks on a rolling release basis. I ended up spending a lot more time than I expected touching up the print version, so I had less time to pitch to podcasts. Both posts reached the front page of Hacker News, Lobsters, and /r/programming. I was happy with these results, especially because one of my selling points of the book is that writing helps customers find you. It was nice to prove that with blog posts that led readers to purchase the book. September was the second-best month of visitors for the book, though I didn’t directly cause it. Most visitors arrived because a reader submitted my “How to Write an Effective Software Design Document” post to both /r/programming and Hacker News, and the post took off in both places. The post’s success was surprising because the same article had been submitted to Hacker News nine times before and never took off. Tenth time’s the charm, as they say. And I’d submitted the post to /r/programming a few months ago, and it did take off, but I guess everyone forgot or was happy to read it again two months later . I normally cover the previous month in these retros, which would be September, but since I’m late and the October launch is fresh in my mind, I’ll cover it here. I officially launched my book! Launch week was October 4th to 11th. I offered a print version for the first time and offered a limited-time 30% discount on both the print and digital versions. Here were my launch week promotional activities, in decreasing order of impact on sales: Unique visitors to book site during launch week Here are some high-level metrics comparing launch week sales to the prior week for reference: I initially planned not to put much effort into the print version. The PDF version already looked pretty good, and customers have been buying it for over a year with no complaints about the design, so I wasn’t about to become a typography wonk over a print version. Then, a reader named Alexey Zubkov reached out to me with a few suggestions for my book and offered to help me with the typography. Once Alexey pointed out the issues, they felt like huge, glaring errors, even though I’d been staring at this book for years and never noticed them. One of my blind spots was that I wasn’t using my font’s pair-specific kerning. Without pair-specific kerning, Asciidoctor gives each letter a fixed slot of horizontal space regardless of which letter follows it. When it honors pair-specific kerning, Asciidoctor adjusts the horizontal spacing for certain combinations like “Yo”: Without kerning (top) vs. with kerning (bottom) Notice that with pair-specific kerning, part of the “o” appears directly under the “Y.” The two letters can share that space because the font designer knows the combination works, whereas if it was lowercase “yo,” the letters would collide. And that’s just one change! I made a little slideshow to show how a single page evolved over about 30 different typography improvements, and this still excludes many that had no impact on the example page: Add GOOD/BAD prefix and icons to examples Enable JavaScript to browse the remaining revisions. I’m selling the print copies of the book through Lulu, using a feature they recently added called Direct Buy Button. The basic idea is that you upload your book as a PDF, and they give you a link where people can buy a print version. Lulu offers print on demand, so they print a new copy for the customer and ship it directly to them. Lulu Direct Buy Button is significantly simpler than Shopify or WooCommerce, where you have to manage a whole ecommerce platform. Its closest parallel is Amazon Kindle Direct Publishing, though without the pain of dealing with the giant Amazon machine. My overall experience with Lulu has been okay. They deliver on the core promise, which is that they make it easy to sell a book through a link, but there are still a lot of rough edges. I wrote my book in Asciidoc because it was the only tool I could find that outputs to PDF, EPUB, and HTML. By the end, I got so tired of Asciidoc syntax that I spent a day writing (largely with AI) a Markdown to Asciidoc compiler so that I could stop writing in Asciidoc. Here’s an example of the difference. My book contains a lot of example callouts like this: Before, to render a callout like the above, I had to write gross Asciidoc that looked like this: The syntax above is especially annoying because most of that is boilerplate that appears in every example, but Asciidoc doesn’t support templates, so I have to repeat all the boilerplate every time. I wrote my own Markdown compiler that supports Hugo-style templates. Now, when I want to generate a bad example callout, I write this simpler and more readable shortcode: I also wrote an Asciidoctor plugin to improve the callouts to look like this instead of what I was limited to with native Asciidoctor: The example callouts were where the Markdown syntax was most obviously cleaner, but it also allowed me to stop thinking about Asciidoc’s confusing and inconsistent rules like when a straight quote becomes a curly quote . I’ve set it up so that I just write straight quotes everywhere, and my compiler worries about translating them to the right Asciidoc syntax for curly quotes. I’ve been meaning to try out Atuin for about a year. It’s a tool that collects your full terminal history and can sync it across machines. Every time I’m struggling to remember a command I typed a few days ago and I’ve lost it to bash’s confusing history management rules, I think, “I should really look into Atuin…” And then I keep putting it off. I finally set aside a few hours to set up Atuin, and it took me less than five minutes to install. I use NixOS, so a basic configuration just looked like this: The biggest decision I had to make was whether to let Atuin take over my up arrow. I didn’t realize Atuin took over the up arrow by default, so when it first started happening, I found it jarring. I couldn’t decide if Atuin’s up-arrow takeover was a worse workflow or if I just needed to adjust, but after about a week of trying to use it, I disabled Atuin from hijacking the up arrow. Now, the way I search my shell history is: I’m enjoying Atuin. It does exactly what it says. If I know that I’ve ever typed a command on the terminal, Atuin lets me find it quickly. My final Atuin config looks like this: Code a simple bug fix: 30 minutes. Get it code reviewed by the peer next to you: 5 hours… AI’s direct impact on this problem is minimal. Okay, so Claude can code it in 3 minutes instead of 30? That’s super, Claude, great work. Now you either get to spend 27 minutes reviewing the code yourself in a back-and-forth loop with the AI (this is actually kinda fun); or you save 27 minutes and submit unverified code to the code reviewer, who will still take 5 hours like before, but who will now be mad that you’re making them read the slop that you were too lazy to read yourself. Another participant said he was confused by two slides that seemed to contradict each other. I thanked him for showing the group how quickly men become hostile when asked to hold complexity. He said he wasn’t hostile. I asked everyone to notice that he had now interrupted a woman twice. He put his hand down. I said withdrawal is also a form of domination. He put it up again. We took an unscheduled break so I could regulate after what he had put me through. I launched my book and made lots of typography improvements to it. I’ve had mixed experiences with Lulu Direct Buy Button. I created a Markdown to Asciidoc compiler so I can stop writing in Asciidoc. Result : Launched the book (a week late) Result : Pitched to just one podcast Result : Published “Anti-Patterns in Software Blogging” and “Why are Agent Harnesses so Dumb?” during my book’s launch week Published “Anti-Patterns in Software Blogging” Went to #1 on Lobsters and /r/programming and peaked at #8 on Hacker News Published “Why are Agent Harnesses so Dumb?” It got a decent response on Hacker News and Lobsters Submitted an announcement to Hacker News Never made it to the front page Announced launch to my book email list Announced launch to my personal blog email list Fees are transparent and clear. Print quality is good. Lulu handles fulfillment, so the book goes straight from the printer to the customer. It’s easy to get up and running. The integration with Stripe Connect means authors don’t pay double fees for the sales platform and the payment platform. Customers haven’t reported any issues checking out. It’s print-on-demand, so you can order in any quantity, down to a single book. It’s easy to update the contents of the book, and the changes go live instantly for all future orders. There’s no programmatic way to see order information. Direct Buy Button doesn’t support webhooks or any kind of order query API. I reached out to support to see if I was missing something, and they said that the dev team intentionally designed Lulu Direct Buy Button as “a closed ecosystem” but did not elaborate on why anyone would want that. This is the biggest headache because it means I can’t programmatically react to purchases, like giving the customer access to the PDF version or the web version. Confusingly, there is an API for order status, but it only works for orders created through the API, so I’d have to reimplement all the server-side logic of Buy Button myself. There’s an undocumented GraphQL API for fetching the orders as a CSV, but Lulu invalidates sessions daily and makes every login go through a CAPTCHA, so it would be a pain to try to build automation on top of that API. Each product can have exactly one price. I wanted to offer a discounted price for customers who pre-ordered the ebook, but there’s no way to offer different prices or discount codes. As a workaround, I created a second, identical book with a lower price, but now any time I update the content of my book, I have to apply the change to two different products. There’s no built-in support for ordering a test print before releasing a version to customers. If I make a change to the book that could affect the print, I want to do a test print first. I can’t mark a draft as “not ready for customers.” As soon as I update a draft, that’s the draft that ships to customers. I worked around this by creating a third copy of the book that I use for test prints. Lulu’s CSV export omits important information. You can export order information as a CSV, but you have to do that manually. Bizarrely, the order export has no information about when the orders occurred. There’s no date or timestamp column. The CSV export also hides customer information like name and email unless the customer opted in to marketing. And I appreciate Lulu fighting spam, but it’s annoying that Lulu views these as Lulu customers rather than my customers. And Lulu exposes the customers’ information anyway in the dashboard, but you just can’t dump it in aggregate. You need to provide a return address even if you don’t accept returns. I ended up having to register a virtual mailbox, which is a whole other pain in the butt. I wish Lulu just offered a “recycle the book if you don’t want it” refund option. The current setup means customers have to ship a book to me across the country, but I’m just going to recycle it because I can’t do anything with a used copy of my book. Lulu makes it hard for authors to understand their earnings. They show “Revenue” in a lot of places, but my earnings dashboard said I’d earned $0 even after $2k in sales. I was able to calculate my earnings manually by downloading all my orders as a spreadsheet. Customer support is pretty bad. It took several days to respond to my questions, and the answers were unsatisfying. : Triggers , bash’s built-in search for the current session : Triggers Atuin to search over all commands across all sessions. Cryptic Comments on an NPR Spotify Show This is a recent episode of This American Life about a producer who found strange comments on an interview with author Elizabeth Gilbert. I read the transcript and then listened to the audio, but I wish I’d listened to the audio first because it was more fun that way. Spoiler: it’s the real-life manifestation of The Onion’s 2014-but-still-timely video: “Teens Migrating From Facebook To Comments Section Of Slow-Motion Deer Video.” Every layer of review makes you 10x slower This post is the best articulation I’ve found about the cognitive dissonance of the speedup I expect from AI vs. how much I experience in practice: Code a simple bug fix: 30 minutes. Get it code reviewed by the peer next to you: 5 hours… AI’s direct impact on this problem is minimal. Okay, so Claude can code it in 3 minutes instead of 30? That’s super, Claude, great work. Now you either get to spend 27 minutes reviewing the code yourself in a back-and-forth loop with the AI (this is actually kinda fun); or you save 27 minutes and submit unverified code to the code reviewer, who will still take 5 hours like before, but who will now be mad that you’re making them read the slop that you were too lazy to read yourself. A Marginal-Utility Case for Stealing My Grandmother’s Pain Pills This is a parody of LessWrong (popular rationalist site) that I thought was pretty funny. I saw JeffTK describe it as AI-written and thought it was too funny to be AI-generated. The only thing that makes me think it’s AI-written is the number of articles (68) that seem to have appeared out of nowhere. It also links to a Substack parody called Smugstack featuring gems like “I’m an Anti-Racist Educator. It’s Not My Job to Educate You” : Another participant said he was confused by two slides that seemed to contradict each other. I thanked him for showing the group how quickly men become hostile when asked to hold complexity. He said he wasn’t hostile. I asked everyone to notice that he had now interrupted a woman twice. He put his hand down. I said withdrawal is also a form of domination. He put it up again. We took an unscheduled break so I could regulate after what he had put me through. I don’t know what to make of the site because all the articles are like two or three orders of magnitude funnier than anything I’ve seen AI produce, which suggests human writing, but I can’t imagine this author was privately writing stuff this good for this long, and nobody noticed until now. My best guess is that the author has a good sense of humor and is injecting the core jokes but is using AI to flesh out the specifics. Officially launched my book. Improved a lot of design aspects of the book website, especially the purchase flow. Published “Anti-Patterns in Software Blogging” Published “Why are Agent Harnesses so Dumb?” Publishing print books is both harder and easier than I expected. It’s easier in that print on demand eliminates a lot of the hassle I anticipated of having to carry inventory and manage logistics. It’s harder in that selling a print copy means integrating with another sales platform, and the options are either complex platforms with lots of integration options or simple platforms with no integration options. Finish remaining typography improvements for the book. Publish one new blog post.

0 views
Karan Sharma Yesterday

Explicit Account Routing in OpenCode with CLIProxyAPI

I juggle between personal and work accounts for both Claude and Codex, and I wanted all of them available in OpenCode . Most people set up local LLM proxies to pool their accounts into one bucket and auto-failover when a rate limit hits. I wanted the exact opposite. If I’m working on a company repo and hit a usage cap, the request should just fail. It should never quietly fall back to my personal account in the background. I use CLIProxyAPI to handle the OAuth logins, token refreshes, and upstream requests. It supports account-specific prefixes, so I can give each login a clear label like or . Pointing OpenCode at the proxy is easy enough, but OpenCode doesn’t query to discover what an endpoint actually serves. It only shows the models you hardcode in its config file. Maintaining that list by hand across multiple accounts gets old fast. To fix that, I wrote a small local OpenCode plugin ( ) in TypeScript using . In my OpenCode config, I pass the plugin the list of account prefixes I want exposed and whether each one speaks Anthropic or OpenAI under the hood: Instead of storing a bearer token in , the plugin fetches the local proxy key at runtime by shelling out to a small helper script ( ). With that key, it polls every 60 seconds to get the list of prefixed routes currently active in CLIProxyAPI (like or ). The catch with is that it only returns model IDs. It says nothing about context windows, tool-calling support, or reasoning effort variants. To fill those in, the plugin uses . For each route returned by the proxy, it strips the account prefix ( ), looks up the base model ( ) in OpenCode’s built-in or catalog, and clones its metadata into a new per-account provider: This is what makes the setup feel native. OpenCode sees a normal model ID under a dedicated provider for each account: Meanwhile, (along with any reasoning variants cloned from the template) is rewritten to the full string that CLIProxyAPI expects on the wire. Claude accounts get wired to (Anthropic Messages API), and Codex accounts use (OpenAI Responses API). On each 60-second tick, the plugin compares the sorted model list against the previous snapshot and only calls when something actually changes. If the proxy is briefly unreachable during a restart, it catches the error and keeps the last known model inventory rather than wiping out the active providers. Because the proxy requires an explicit prefix on every request and the plugin never registers a pooled route, each provider is locked to a single credential. When an account hits a 429 rate limit, the proxy returns the error straight back to OpenCode without touching any other account. Registering a separate provider per account also makes subagents nice to use. Because the provider IDs are descriptive ( , ), I can just tell OpenCode in plain English which account a subagent should run on. The main agent maps that request to the right provider ID on its own, with no custom parsing needed in the plugin. CLIProxyAPI runs as a user service that starts on login, with both its API and web UI bound to . The OAuth tokens sit outside my dotfiles repo so I don’t accidentally commit credentials to Git. (If you’re setting it up, make sure the proxy binary is on V8+; the newer web UI won’t talk to a V7 backend.) The split works well in practice: CLIProxyAPI deals with auth and token lifecycles, and the OpenCode plugin turns each account into an explicit route I can pick deliberately.

0 views
fLaMEd fury Yesterday

Hilary Duff at the Spark Arena

What’s going on, Internet? Just got back from seeing Hilary Duff at the Spark Arena (on a Tuesday night, whooo). Great show. I wish I knew her music more as I would have loved to be belting out the lyrics with the rest of the crowd. Definite millenial energy in the crowd. Loved it. Hey, thanks for reading this post in your feed reader! Want to chat? Reply by email or add me on XMPP , or send a webmention . Check out the posts archive on the website.

0 views

Battle Drones - a vibe coded RTS with audio-based multiplayer

My latest vibe coded game experiment is a Command & Conquer style RTS (Real Time Strategy) game called Battle Drones ( play it here ). Unlike my previous experiments , this one is actually fun to play . I'm somewhat embarrassed to admit that I got there by telling Claude to "Make it a LOT more fun". It also supports multiplayer between nearby devices using audio to synchronize game state! Here's what I've built so far, and some of the things I learned along the way. My initial goal was to build an RTS game I could play on my phone, in the style of Command & Conquer . I have fond memories of the 1995 original (I liked Red Alert too) and wanted to recapture a little bit of the magic. After 12 major iterations (and 321 commits by coding agents, mainly Claude Code) I now have a browser-based game that works on mobile and desktop, has multiple play modes, several maps (including a random map generator) and even supports multiplayer for two devices within microphone range of each other. Here's a video demo of Battle Drones running in a desktop browser: Features so far include: Battle Drones is heavily vibe coded - I've reviewed almost none of the code, and it's built in a language (TypeScript) that I've hardly used myself. I've playtested it quite a bit though, and it's been through a large number of iterations since I started the project. Here's a rough history of the project so far, including key prompts and links to transcripts. I started out with Claude Fable 5 back in July: Here's a shared transcript . I'd given Claude Code for Web an environment variable with an OpenAI API key and told it to use the OpenAI Image Generation API for assets, which got me some basic sprites. You can try v1 here - it looked like this: It's recognizable as an RTS, has building mechanics and the ability to select and direct units, and a basic AI to play against. This first version was barely a proof of concept, and it wasn't any fun to play. Claude used the Phaser 2D game framework for these early versions. I didn't even realize this until several iterations later! The second version ( try v2 here ) added sprites for all of the vehicles and the "AI vs. AI" mode, so I could watch the game playing without having to directly control it myself. Claude proved reasonably competent at prompting OpenAI's image models to generate sprites. You can browse the v2 sprites in the public/assets/sprites folder. It still wasn't much fun, and the graphics were boring. It was now October, and I had upgraded to Claude Opus 5.5. I told it: This resulted in five new maps with generated background tiles in a variety of styles, visible here . Opus also regenerated the sprites, making them much more visually appealing. You can try v3 here - it looks like this: This is starting to feel like a real game! It still wasn't very fun to play though - I found myself getting bored pretty quickly. So far my Battle Drones experiment was confirming my previous belief that coding agents can build a thing that looks like a game but can't actually make something that's genuinely compelling to play. I shared this theory with someone over dinner, and then thought to myself that I should give the models a proper chance to prove me wrong. I prompted Opus 5.5 on my phone: This time I was running in Ultracode mode , where Claude Code (in this case Claude Code for Web) runs "dynamic workflows", described in their docs as: A dynamic workflow is a JavaScript script that orchestrates many subagents at once. This kicked off many hours of work. I started it in the evening and didn't get a playable result back until late into the next morning. But the results were spectacular. You can try v4 here - it looks like this: I had Claude write its own release notes - here are the highlights: Every skirmish and Daily Op now opens with a choice, gives the side that's losing a way back, and pulls the armies into the middle of the map. There are also two new ways to play. Fights run longer and swing more. In 1,200 AI-vs-AI test matches on Normal, games still undecided after 25 minutes fell from 14% to 0.9%. The share of wins by a side that had been 800+ scrap behind rose from 24% to 46%. Part of the reason Claude took so long was that it ran over a thousand simulated playtest sessions, and used the results to rebalance the existing units, add new ones, and introduce new features. After the success of Ultracode at "Make it a LOT more fun", I decided to be more ambitious: That was another overnight run. I woke up to this v5 version : The new 3D models were entirely constructed by Claude in TypeScript code. v6 ( play v6 here ) added some more visual polish. v7 ( play v7 ) added robot infantry (troopers, rocket squads, snipers) and a "Condor" troop carrying aircraft. I was beginning to feel guilty at how little actual design input I had into the game - it really had been a case of me saying "make it more fun" and "add visual polish" for the past few releases. I'd noticed that the AI didn't use the new infantry and troop carrying aircraft from v7 very often - there wasn't a great strategic reason to use them. It would be neat if we had a new map with a new game mechanic that actively encouraged players to load up Condors with infantry robots and send them out into the map. This resulted in my longest prompt yet: The result was the tropical Archipelago map, with seven island uplinks that players can only capture by flying out infantry in a Condor. It's definitely the most fun map to play, once you've got the hang of the basic game mechanics from the simpler maps. The v9 edition made that map a little more interesting - it now looks like this: I decided to add giant robot mechs to the game - think Jaegers from Pacific Rim , or Titans from Warhammer 40,000. Here are some of the prompts I used to brainstorm with Claude: The end result is really cool . Goliaths can be constructed using a Gantry - a building that can only be created after first building a Fab, Bay, Airpad, and Tech Lab. You can see the Goliath under construction, and it then walks out from the Gantry and can march around the map. Goliaths can "anchor", which digs them into the ground. In their anchored state they can act as a new HQ, constructing infantry units and additional buildings in a new area. Two Condor aircraft can hook onto a Goliath, at which point it can be flown around the map! The game now ends when you destroy the enemy's HQ building and any Goliaths they might have built. There are also a couple of mutators relating to Goliaths: The other v10 feature is agent battles . In musing about how multiplayer could work I had an idea: what if different LLMs could fight it out in the game? Opus 5.5 went to work on this, producing this AGENT-BATTLES.md proposal and then implementing and testing it. The feature also includes the ability to record and replay these battles - here's a replay of Claude Haiku 5.5 vs. GPT-6 Luna , and here's that same battle in a separate debug tool that shows the underlying prompt responses. The prompt that drives agent battles can be seen here . There are a few more replays like this linked in the README . I hope to turn this into a full league table at some point in the future. This version exists purely because I glanced at my Claude Usage page one day and saw that I'd only used 75% of my weekly allowance and it was resetting in 45 minutes. I decided to see if I could get an extra Battle Drones feature from my remaining tokens, and picked "random map" as the target: Here's the transcript , and an image Claude generated to show me its work: I only just got this working, so I've not had much time to actively test it yet. The latest Battle Drones now supports multiplayer via two devices sat within microphone distance of each other! This feature started out as my Chirp Pong experiment from last week. I pointed Claude Code at that working proof of concept: Opus built this Radio Probe tool to measure how much bandwidth we could get between two devices and, based on positive results from that, implemented a full audio modem system. I've tried it between laptops, iPhones and iPads so far and it seems to work really well! Why use sound for this? Because I love static HTML that costs nothing to run, and I don't want to spin up a server somewhere and then stay responsible for keeping it operating for as long as anyone might want to play the game. I know almost nothing about game development. This makes it a great opportunity to try out coding agents in a field where my existing software engineering experience has less impact on the results. Games are also super low stakes. The worst that can happen is one of my silly game experiments suffers a bug. This morning ( via Hacker News ) I found Steam Fans Are Begging for a No-AI Filter as Steam Next Fest Is Filled With Slop . I wouldn't personally dream of submitting Battle Drones to an event like this - it's still way too low effort to warrant consideration as a legitimate indie gaming project. ... but I can now see a path to vibe coded games like this being taken seriously. Battle Drones is fun, it looks good, it has innovative features (the multiplayer-over-audio thing is a first for an RTS as far as I can tell). I'd love to see what someone with better taste than me and a driving passion to produce something truly exceptional could build! A few other observations from this project: Earlier in this article I said: Games are also super low stakes. The worst that can happen is one of my silly game experiments suffers a bug. Then I tried playing the multiplayer version with Natalie... and the high pitched modem sounds gave her a nasty headache! That's a pretty bad bug. I added a warning and was then inspired to build proper network multiplayer. I tried getting WebRTC to work but couldn't get a connection going between two of my own devices even on my own WiFi network, so I had Claude build a simple, stateless WebSockets relay server instead: Here's the resulting server . Since this scales to zero and runs on a single Fly.io instance it should cost me no more than $2.19/month - and that's if it stays hot and serving connections the whole time. Battle Drones now supports online multiplayer. Click "Duel a friend online", then either share the resulting room URL via your messaging app of choice or have them snap a picture of the displayed QR Code. I also added a feature where you can copy JSON of the match once it has ended and then feed that into the replay feature to rewatch your game. I didn't expect to introduce online multiplayer this soon, but the headache bug felt like it warranted an urgent alternative. You are only seeing the long-form articles from my blog. Subscribe to /atom/everything/ to get all of my posts, or take a look at my other subscription options . Battle Drones How I built this v1: the initial prototype v2: full sprites v3: varied terrain v4: the fun update v5: Battle Drones goes 3D v8: Archipelago v10: Goliath, and agent battles Agent battles v11: Random Maps v12: Multiplayer via sound Some thoughts Update: Online multiplayer support 9 buildings, 7 ground vehicles, 6 aerial vehicles, 3 infantry units - all 3D models, which you can browse here Different weapons are needed to target aerial or ground vehicles Six maps , across five biomes - temperate, desert, arctic, volcanic, tropical A random map generator Skirmish mode - red vs. blue on a rotationally symmetrical map Last Stand mode - one player holds out against as many waves of enemies as possible Area effect weapons: Barrage, EMP, Drop Pod, Sky Hammer Crate drops with bonus resources In-game music that responds to events - it gets more intense as fighting breaks out Different in-game AI personalities (Balanced, Rush, Air Swarm, Boom, Skyforce, Ironclad) AI vs. AI mode, to watch those personalities play each other The Goliath - a giant stomping mech with laser eyes and arm cannons and the ability to establish a new base Mutators that add extra rules or twists A "Daily Op" challenge Ranks and achievements ( Medals ) Agent vs. Agent mode where two LLMs can play Battle Drones against each other A multiplayer mode based on two nearby phones communicating via audio messages, an extension of my earlier experiment with Chirp Pong Openers : pick Blitz, Industry or Air Wing before the clock starts. Call-down powers : Barrage, EMP, Drop Pod and the Sky Hammer orbital strike. Objectives and salvage : Uplink relays, supply drops and wrecks worth scrap. Feel : combat juice, adaptive music, unit voices and an announcer. Command : battle alerts, game speed, saved squads and touch placement. New modes : Last Stand survival waves and an 8-mission Ops campaign. Progression : heroes, an after-action report with awards, a career, 7 mutators and a Daily Op. Goliath Armada starts each side with four airborne Goliaths (each with a pair of Condors) and no other units. Robot Love adds a special rule: if enemy Goliaths get close to each other on the battlefield they fall in love and the game ends in a draw. (Thank Natalie for that one). Static HTML and JavaScript is a fantastic medium for games development. WebGL works great, and Three.js (and Phaser before it) are excellent platforms to build on that the current models know inside out. This also lets them run as Progressive Web Apps - I didn't ask for it, but Battle Drones works offline. I was able to play it on a plane despite never having directly installed it - my phone had it cached. Giving Claude an OpenAI API key and telling it to generate images using OpenAI's models works really well. It can view the images it has generated and iterate on the prompts. Opus 5.5 is spectacular at 3D modeling using Three.js (and Blender, and no doubt other 3D applications as well). The same is true of GPT-6 Astra. They are absolutely capable of building models for 3D game projects. For features like replay and multiplayer it's useful to have a deterministic simulation engine. At one point Claude had to replace calls to and and friends with custom versions because different browsers (Chrome vs. Safari, for example) returned very slightly different numbers, desynchronizing the replay. Opus 5.5 can write music! There are no audio files in this project - the soundtrack is entirely generated through code, varies across different maps, and even gets more intense as the battle heats up. See Scrimshaw Jukebox for a previous experiment with Claude for music composition. I still can't get over how well the prompt "Make it a LOT more fun" worked. Tools are effectively free. I prompted up the Radio Probe , the Model browser , the Agent vs. Agent debug tool , and Claude Code built a bunch of tools for itself that I haven't even explored myself. Audio-based multiplayer between static HTML games works! I hope to see a whole lot more games use this same pattern - in digging around today I've not found much prior art beyond Siner by Alon Horesh and ggwave by Georgi Gerganov (also of fame). Claude Code "Ultracode" burns tokens like there's no tomorrow, but it can also solve complex problems (like adding audio-based multiplayer) from a single prompt. I'm still not quite over the guilt of building software in this way. I don't feel like I've earned the right to create something this good, in a field in which I have so little prior experience! At this point I've shown it to enough people in private that it felt wrong not to publish it for everyone else to see and learn from.

0 views

AI Had Better Work Out

If you liked this piece, you should subscribe to my premium newsletter, and you can subscribe on the following links: $70 a year , $18 a quarter , or $7 a month . In return, you get a weekly premium newsletter that dives deep into the finances of the AI bubble. Over the past few months, I’ve published a two part guide to the world of AI debt, an analysis of the (dubious) impact of generative AI on the global economy , deep analyses of the biggest players in the AI infrastructure space like NVIDIA (part one and two ) and Oracle (part one and two ), how OpenAI will eventually kill Oracle , and how venture capital is killing itself .  Friday’s piece will be the Hater's Guide to Blackstone — one of the most loathsome companies in existence, and one that’s staked its entire existence on the AI bubble.  If you want to get in touch — and especially if you have any juicy information about Anthropic, OpenAI, Blackstone or any other companies in the AI bubble — hit me up on Signal at ezitron.76. I’m also on IB on your Bloomberg Terminal.  Soundtrack: Royal Blood — Pull Me Through At the end of July, Apollo Chief Economist Torsten Slok gave a blunt warning to the Washington Post : Today, I’m going to quantify exactly how difficult it will be for the “AI thing” to “work out.” As I’ve said before : The theoreticals and hypotheticals of this industry are so powerful that they’ve created one of the (if not the) largest equities bubbles in modern history, all heavily-centralized around the valuations of a handful of names related to the so-called AI trade, which translates to “buying or selling stuff to do with AI GPUs.”  This has led to the single-highest inflow of foreign investments into US equities in history — larger than the Dot-Com Bubble, the leadup to the Great Financial Crisis, and even the dying gasps of the Zero Interest Free Era in 2021, per Apollo : However you might hand-wave away the AI bubble’s economic issues by saying it’s “just like the Dot-Com Bubble” — when the NASDAQ 100 fell 77% from its peak — the consequences are now global, at a scale unseen in history, flowing into both direct stocks and indices. As of typing this sentence, NVIDIA alone makes up 11.31% of the NASDAQ 100, with the combined weight of NVIDIA, Google, Amazon, Meta, Microsoft, Broadcom, Micron, AMD and CoreWeave representing about 46.5% of the index’s value, or 39.3% of the entire 3000-company NASDAQ composite.  These same names — replacing CoreWeave with Oracle — represent around 28.9% of the value of the S&P 500.  To sustain the valuation of these stocks — let alone continue growing — will require every company involved to either spend or make hundreds of billions of dollars in perpetuity, increasing every single quarter, without fail. This will come from either selling ever-increasing amounts of AI chips and related hardware, or buying and using them to generate revenue either through rentals or building their own software products.  While the centralization was more severe at the top of the Dot-Com era NASDAQ — with Cisco, Intel and Microsoft accounting for roughly 74% — the total value of the index was a mere $1.82 trillion ($3.58 trillion adjusted for inflation).  Today’s top three — NVIDIA, Google and Microsoft — account for around 29% of the NASDAQ 100, for a total market capitalization of $13.5 trillion. I’m afraid things only get worse. Per Goldman Sachs ( via Reuters ), "...equity gains have been the dominant driver of household wealth accumulation ​and the main contributor to a positive wealth ​effect on consumer spending," and per data from the Fed , corporate equities accounted for 37.9% of all household wealth in Q2 2026, the highest number on record since Q4 2000.  Economist Paul Kedrosky told me it might actually be higher: While the Fed’s data only goes back to Q4 2000, corporate equities as a share of household wealth only sat at 25.9% ($11.5 trillion, or $22.7 trillion adjusted for inflation), back at a time when total household wealth sat at $44.4 trillion, or about $85.2 trillion in today’s money. In Q2 2026, total household wealth sits at about $195.8 trillion, with corporate equities sitting at roughly $74 trillion, or roughly 86.8% of the entire US household wealth 26 years ago. Retails are also making up an historically-large amount of the volume of trades on the market, per Bloomberg Intelligence, making up 20.3% of trading in 2026 to date, approaching the dangerous heights of the worst excesses of the end of the Zero Interest Rate Policy era. Retail investors also directly own about 29% of Amazon’s, 26.2% of NVIDIA’s, 22.6% of AMD’s, 21.8% of Microsoft’s, and 18.6% of Meta’s stocks, though these numbers are not inclusive of index funds like SPY or QQQ (a fund tied to the NASDAQ). In totality, retail investors own equity assets (at least as of May) equivalent to about 10% of the market . In fact, Goldman Sachs had retail volumes significantly higher: By comparison, Dot-Com era retail trading was much, much lower — less than 2% of the NYSE’s trading volume according to the University of Michigan’s Alicia J. Davis in a paper that begins with the phrase “the American retail investor is dying.”  When all of this is over, I think retail investors might wish they were dead, as they directly own somewhere in the region of $4.65 trillion worth of NVIDIA, Amazon, Microsoft, Google, Meta, Broadcom, AMD, Micron, Oracle, and CoreWeave stocks. The number is likely much smaller than the true exposure retail investors have, as it isn’t inclusive of investments in index funds. On April 14, 2000 , the NASDAQ composite dropped 9.67% and the S&P 500 5.78%, with a little under 97% of the S&P 500 constituents falling on the day , per TIME and The Washington Post, led by hot inflation numbers and overall anxiety over the tech sector’s valuations: Yet the Post had one telling quote, emphasis mine: While it seems unlikely, a drop of around 20% across NVIDIA, Amazon, Google, Meta, Broadcom, AMD, Oracle, Micron, and CoreWeave would have the same effect as the entire market downturn on the worst day of the Dot-Com Bubble crash.  In truth, it wouldn’t even have to be that bad.  Per CNN Moneyline News Hour transcript from April 14, 2000 , Qualcomm fell 21%, Yahoo fell 20%, Intel a little over 10%, and Microsoft a mere 5% — and that’s all it took to make the market bottom out.  Brief NVIDIA selloffs have already caused big market declines: Anyway, remember that quote about momentum investing, overvaluations and growth? Here’s a quote from Bloomberg from last week (October 14), emphasis mine : And here’s another quote from CNN from a day later, emphasis mine: History may not repeat, but it rhymes. Every problem that burst the Dot-Com Bubble is here, but it’s worse, bigger and uglier, with global contagion risk that I basically never see discussed. For example, the ongoing equity price of TSMC on the Taiwanese Stock Exchange makes up about 40% of the entire market, with the ODMs that have seen booming earnings making AI servers for hyperscalers representing another 3% or so. On The Tokyo Stock Exchange, the combined weight of SoftBank, RAM maker Kioxia, and the two major banks (SMBC and MUFG) backing AI data centers make up approximately 11.24% of the TOPIX Index. Samsung and SK Hynix, both of whom have seen remarkable RAM sales ( see my Hater’s Guide To The Memory Crisis for more ), make up more than 50% of the entire value of Korea’s KOSPI. Their elevated valuations come from a belief that they’ll grow in perpetuity, much like the American markets. And let’s be clear about something: all it takes is the vibe souring to the point that people lose faith in the AI trade for everything to start to collapse. So, what will it take to keep the party going? The answer is simple: perpetual, parabolic growth in both AI revenues and AI capex. Per CNBC , well, exactly what I’ve been saying, emphasis mine: Are…are you sure about that? Isn’t AI the biggest, most hugest thing ever? It’s transformative! It’ll change everything! Aren’t we all excited- Okay, well, check out Doctor Doom over here , I bet he’s gonna be so surprised when those profitable returns come in- Well, at least there’s a diverse revenue base for GPU sales- OH MY GOD ! NVIDIA has guided to a 70% increase in its next fiscal year — I assume FY2028, starting February 2027 — or over $670 billion in annual revenue, over three times its FY 2026 sales , with said sales dependent on whether Microsoft, Google, Amazon, Oracle, Meta, SpaceX ( who collectively make up 50% to 60% of NVIDIA’s data center revenues ), and the various neoclouds like CoreWeave, Nebius, and Nscale keep buying more of them every quarter, or at the very least that a willing vessel can step in to pick up the slack if they stop. If demand wavers, NVIDIA, Broadcom, Micron, AMD, and any associated silicon or hardware counterparties will see their revenue growth stumble, which will have a brutal knock-on effect on their stocks.  NVIDIA already has its own revenue concentration problem — 44% of its first half FY2027 revenues came from three customers, and in Q2 FY2027, 70% of its accounts receivables were from three customers, with 16% of its revenues coming from one. One. How is this not more worrying to people? Anyway, to buy those GPUs (or TPUs, in Broadcom’s case), everyone outside of Microsoft will have to raise tens of billions of dollars of debt at a time when underlying interest rates are growing and the overall debt markets have chilled around AI data center debt.  Said chill comes from the world finally waking up to what I said in March 2025 — that CoreWeave is a time bomb of expensive debt that’s now selling off as people realize that making any of its supposed $104 billion in backlog (at least 50% of which is OpenAI and Anthropic) will require, per UBS , about $102 billion in debt in the next three years. CoreWeave’s long-dated bonds (by which I mean maturing in 2031) had an effective yield of as much as 16% in the last week.  With endless delays and hundreds of billions of dollars of chips sitting in storage , AI data centers have dramatically turned from the panacea for all infrastructure investment to fixed-income nightmare fuel. For whatever reason, nobody thought that lending hundreds of billions of dollars to a selection of different dodgy SPVs and neoclouds to build the world’s most ambitious infrastructure projects was a problem until, well, everybody, per the WSJ : Per the Journal, this debt heavily relies on both the continued value of the data center and critical IT gear and whether the bloody thing actually gets built: In other words, the value of that data center debt is heavily contingent on whether the underlying assets retain their value, which in turn is contingent on whether there are customers that exist. For whatever reason, nobody wants to consider the most obvious problem: that if one customer can’t pay, other customers can’t pay, and if other customers can’t pay, there’s going to be less demand for AI data centers in general, which means there will be a glut of data center infrastructure, which will mean those assets you intend to resell if everything goes poorly won’t be worth as much. I sure hope that financial institutions have a plan… Oh okay, the problem with overly-expensive AI data center debt is simply that the markets will feel better when the underlying data centers ( which are overwhelmingly delayed ) get built? Awesome! It’s just that simple! I’m sure somebody out there will deal with the massive delays for the talent, materials and power connections necessary to complete them !   As of writing this sentence, CoreWeave’s bonds are trading somewhere between 14.1% and 15.1%, and the only way it can calm investor anxiety will be building AI data centers at a rate that has proven next to impossible. Part of the problem is that recent pushes by smaller and somehow-dodgier neoclouds like Firmus ( which just pulled its IPO ) and Nscale ( whose investors are pushing for it to nearly halve its IPO float to $16 billion and just lost Microsoft as a client due to power delays ) have made investors intimately aware of the overpromises of AI data center companies.  Both Nscale and Firmus have the same customer concentration problems as CoreWeave, with 85% of Nscale’s backlog coming from Anthropic and Microsoft, and 90% of Firmus’ coming from Meta and OpenAI. Again, these are problems that CoreWeave, IREN and Nebius have had for years, but for whatever reason everybody has decided to wake up. Everybody has the same backlog customers — Microsoft (for OpenAI), Meta, OpenAI, Google (for Anthropic and OpenAI), Amazon (for Anthropic), and, of course, Anthropic.  All this ire towards AI data centers means that the price of borrowing for them is skyrocketing on top of ten-year-dated Treasuries stubbornly sitting above 5%, which makes the overall economics of AI data centers increasingly problematic, as nobody can seem to measure A) how much they make and B) how much they cost. Or, indeed, how any of this will pay off. Congratulations to Eugene Kim of Business Insider for getting one of the biggest scoops of the AI bubble, confirming my estimate that billions of dollars of NVIDIA GPUs were being warehoused in this incredible story , emphasis mine: If you’re wondering exactly how much it’s warehousing… One Amazon email projected the company would take delivery of about $5 billion of Nvidia GB300 racks in August, followed by another roughly $3 billion each month "for the foreseeable future." That’s right folks — Amazon, which spent $54 billion in capex last quarter — is taking $3 billion worth of GPU deliveries every month “for the foreseeable future,” despite having such a supply glut that it cannot install them, and in some cases lacks an idea of when it may do so. As I discussed a few weeks ago , neoclouds and hyperscalers have over $374 billion in “construction in progress” assets, and I estimate that $200 billion or more of them are GPUs, primarily from NVIDIA. One quote from the piece stood out to me, emphasis mine: It appears that NVIDIA is channel stuffing. The phrase “compete more for scarce resources” doesn’t make sense in the context of GPUs that you don’t have enough power or space to install…unless, of course, NVIDIA is saying that if you don’t order and take delivery right now, the GPUs won’t be available by the time you actually build that data center. The booster counter-argument will be that “Amazon is just planning ahead,” but riddle me this — if Amazon, Google, Microsoft ( CEO Satya Nadella said he had chips “sitting in inventory he couldn’t plug in ) and many other companies do not have the power to plug in the chips… why are they scarce? What’s making them scarce? If companies cannot install the chips (or, put another way, do not need them yet) what is creating the scarcity, other than something that NVIDIA itself is demanding its partners do? Then there’s that curious matter of the whole “Amazon doesn't pay for racks until the gear is put into a data center.” How long has that been the case?  Let’s get specific about the verbiage — “...suppliers…carry the cost of the equipment in transit…” heavily suggests that these racks (which had GPUs in them, by the way!) were not actually shipped to customers until the customers needed them…until some indeterminate point at which the “Early Rack Receipt” program took place. This, if anything, proves that the “demand for AI chips” is far more a result of NVIDIA’s deliberate channel stuffing and antagonistic approach to doing business than anything about how many chips the world needs right now. Anyway, even if hyperscalers installed all the fucking things, it’s unclear who would actually pay for them at a volume that would match analyst expectations. Per Slok at Apollo , financial analysts covering the tech sector seem to be pricing in cash flows that do not match with reality, emphasis mine:  So, in case you didn’t know, every time a company reports earnings, financial analysts at big financial institutions set expectations — sometimes years in advance — of their expected revenues and cashflows. Right now, the analysts covering tech companies are guiding towards them adding $1.2 trillion in operating cash flows, all as the rest of the S&P 500 (ostensibly its customer base) doesn’t add anywhere near that much money. This is one of those very simple points that nobody seems to be able to answer about AI: where will all the money come from to pay for those revenues?  As Torsten said, tech analysts are expecting a parabolic surge of revenues across the entire tech stack, but the analysts covering them are saying the cash won’t be there. What’s the plan, exactly? The answer, it appears, is “Anthropic and OpenAI,” and maybe “open source” sales of indeterminate value. Sadly, there’s another wrinkle in the plan. Japanese financial services firm Nomura put out a worrying take a few days ago , emphases mine and from the poster I found it from: To simmer it down, Nomura is saying based on how much a data center costs both to build and operate, you shouldn’t spend more than $60 billion given the amount of revenue you could hope to generate.  It’s hard to get a precise measurement of how much one costs. The CEO of IBM said $80 billion a gigawatt at the end of 2025. Foxconn said $47 billion per gigawatt in September 2026. Back in June , Jensen Huang said future data centers could cost $80 billion to $100 billion a gigawatt. It is completely insane we do not have a consensus here. Nomura also throws cold water on the many people excitedly suggesting that Anthropic could make $50 billion to $75 billion a gigawatt, suggesting instead that the number is around $20 billion. In other words, if Anthropic is paying anything more than $20 million a megawatt, it’s losing money hand over fist just on the compute alone. Anyway, I sure hope that the people building these data centers aren’t dependent on Anthropic’s revenues… More-importantly, outside of the companies selling the hardware, we know very little about the actual revenue generated from renting AI GPUs. Amazon, Google, Microsoft, and Meta refuse to disclose their actual AI revenues — but analysts estimate that more than 70% of Amazon, Google and Microsoft’s AI revenues come from Anthropic and OpenAI’s compute spend , which is contingent on their continued ability to raise tens of billions of dollars.  As I’ve discussed in the past, I see around $22 billion in non-OpenAI/Anthropic compute spend globally, with an indeterminate amount of that coming from AI startups that, well… Said billions are contingent on the AI labs’ continued revenue growth, and considering that 80% of Anthropic and OpenAI’s enterprise revenues come from loss-making AI startups allowing their customers to burn many times their subscription price in AI tokens ( as much as $1,300 on Cognition’s $200-a-month plan , for example), meaning that Anthropic and OpenAI’s revenue growth is contingent on venture capital’s continued ability to fund their customers. This is one of the core issues with measuring AI demand — that the vast majority of it comes from selling services that do not make any economic sense. And their spend is contingent on their backers funding them in perpetuity. That won’t be easy. This, in turn, is contingent on venture capital’s continued ability to fund raise, and as I discussed in last week’s premium , VC has been on an historic losing streak since 2017, with the median net TVPI (total value put in, as how much you get in return on a per-dollar basis) sitting between 92 cents and a dollar, with 2025 fundraising dropping by 35% , and 2026 fundraising for first-time funds at its lowest rate in over a decade, per Murph Capital , which adds that despite representing only 6% of funds closed, funds of $500 million or more took 78.1% of all capital raised in 2026 to date. AI startups, which are predominantly unprofitable, unsustainable, and require near-constant flow of venture capital, represented 64% of all venture capital investment in Q3 2026 , with 50% of all global venture flowing into AI in 2025 .  As discussed both last year in the Enshittifinancial Crisis and last week’s premium , AI startups represent a devil’s deal for venture — by virtue of being buzzy “AI” companies, their valuations are naturally high, and by virtue of their capital-intensive businesses, they require more rounds of venture capital, with each round increasing valuations to unsustainable heights that make their IP-light, EBITDA-negative businesses impossible for either an IPO or potential acquisition. In fact, both venture capital and private equity are having real problems selling their investments, with IPOs becoming effectively non-existent as a share of exits for PE, per S&P Global . Meanwhile, per DealRoom , venture-backed from 2026 seem high, but are inflated by SpaceX’s IPO ($75 billion), the PE-backed take-private of gaming company Electronic Arts ($55 billion), SpaceX’s acquisition of Cursor (all stock, $60 billion), NVIDIA’s acquisition of Hugging Face ($13 billion), and Google’s acquisition of Wiz ($29 billion).  And since 2015, the $2.7 trillion in venture capital invested has only managed to increase its value by about 1.6x — to around $4.4 trillion in value ( not returns), or around a third of what you’d get if you’d have invested in the S&P 500. In other words, venture capital is not particularly good at creating value, and has, in a period of poor value creation, centralized the majority of its investments in a single industry, with the majority of those investments going to companies related to or powered by Large Language Models that have yet to prove their economic worth. And in this historically-low period of fundraising and exits, venture capital has invested a historically large amount of money , with the vast majority of it going into one bet: AI. What’s that phrase? “You should always keep your eggs in one basket, so that you know where they all are”? I think that’s it, right? At this point, the sheer scale of the AI bubble is too large and unwieldy for things, to quote Mr. Slok, “work out,” and yes, I believe we “have a problem.” I say this with no sarcasm, as I think Torsten has done fantastic work posing reasonable, logical questions that nobody seems to want to answer, like “how does this work out?” and “where does the money come from?” even as most media outlets and analysts nod and smile at basically any statement said by an AI lab, hyperscaler, or neocloud. For everything to “work out,” the current equities surge will have to continue in perpetuity, which requires both hyperscaler AI revenues — which are already depressingly small — and hyperscaler capex to expand infinitely, along with neoclouds, sovereign clouds and AI labs’ vague infrastructure plans to also expand infinitely.  All the while, there can be no perceptual shift against generative AI, because any further souring of the debt markets will have neoclouds and would-be data center operators paying 12% to 15% in interest to build data centers sometime three years in the future for a customer base that’s pretty much entirely made up of Anthropic and OpenAI.  As we’ve seen in the last few weeks, AI debt markets can quickly sour even without any bad news, and conditions will only improve in connection to an incredible earnings season for CoreWeave and other AI infrastructure players. Said “incredible” earnings would require A) data centers to be built and B) said customers to actually pay for them, which roughly translates to “OpenAI and Anthropic’s continued ability to spend more and more money.” Anthropic’s 47% quarter-over-quarter growth rattled the markets because this company has to grow fast enough to cover $413 billion of non-cancellable compute contracts over the next few years , and everybody kind of knows deep down that the bubble can only continue with parabolic growth , which is why everybody freaked out when OpenAI reported a lower annualized run rate (a made up number) than expected, because growth is the only thing keeping this going. And said growth rate is predominantly based on whether AI startups continue to let their customers spend anywhere from $2 to $10 in tokens per dollar of subscription, which in turn is dependent on venture capitalists’ continued status as the world’s most braggadocious paypigs, and at some point that venture money will run out, much like it did during the Dot Com Bubble. I didn’t expect this piece to be so sobering, but when I sat down to write it it just kinda flowed out of me how profoundly difficult the AI industry’s future has become. The fundamental disconnection between the perception of AI growth inflating the value of hyperscaler stocks and the worrying fact that we don’t really know exactly how much AI revenue they make means that the S&P 500 and NASDAQ are held up by a kind of childish excitement that will, at some point, turn to existential fear. Those reflexively responding with “they’ll get bailed out!” neither understand the markets nor the situation at hand. The AI bubble was inflated by hyperscaler revenue growth (without any disclosure of AI revenue) and NVIDIA’s GPU sales , meaning that the moment one of those slows, everybody freaks out. The US government cannot bail out NVIDIA, Microsoft, Google, Amazon, CoreWeave or Meta’s future misses of analyst expectations, nor can it cover every single bankrupt data center, nor can it bail out investor sentiment when it realizes the AI “boom” was yet another tech-based bust. I went into significantly more detail about it in my premium piece about how AI Isn’t Too Big To Fail . Remember: even with the bank bailout in 2008, the market still crumbled, and that was before we had over $40 trillion in debt, stubborn inflation, and a stock market that has fundamentally disconnected from reality.  The underlying weakness of the AI trade is that it isn’t really related to anything other than NVIDIA and the hyperscalers’ earnings.  We don’t know how many GPUs are in operation, we don’t know how much money the hyperscalers make from using them or renting them, we don’t know how many active gigawatts of AI capacity they have, we don’t know their actual customer concentration outside of analyst estimates, we don’t really know how much people pay to rent GPUs , and we don’t even know how much it costs to run a GPU on an hourly basis.  OpenAI and Anthropic are horrifyingly unprofitable, deeply unstable, and as I’ve discussed, 80% of their revenues come from companies that literally can’t afford to pay them , and yet the markets never react, because this information doesn’t really matter as long as the right numbers keep going up. This is why Anthropic’s IPO travails are so profoundly dangerous for the AI trade. Investors are now suggesting that it prices its IPO at $1.5 trillion , meaning a significantly lower payoff for investors and much less capital raised on listing, meaning that it will have to take on more and more debt — like its 10% interest chip financing deal with Broadcom and Blackstone — that will provide a brutal education in what a high-burn-rate, negative-EBITDA company really looks like when you remove the layers of annualized run rates and hype. And, per Irrational Analysis , Anthropic’s investor day didn’t go particularly well: Any further delays to Anthropic’s IPO will be somewhere between catastrophic and fatal, and at this point I think it’s fair to question whether it ever makes it to the public markets. If it does, a $1.5 trillion valuation would spell disaster for OpenAI, which has (as mentioned above) been trying to raise $30 billion at a $1.4 trillion valuation . Closing that round will be difficult to impossible at that price even without Anthropic’s drooping numbers, and if it somehow IPOs at something approaching $1 trillion, I have no idea how Clammy Sammy and OpenAI make it out of this one alive.  And really, does any of this look like the future? Does any of this feel like the next industrial revolution? Or does it feel like the run-up to another burst bubble and resulting financial crisis? The difference here is that AI has, for the most part, been sold as a panacea for the rich and powerful — a way to control, to steal, to acquire and to expand, to take and take and take as they always have, occasionally vaguely muttering something about “abundance” as both the media and financial institutions help force through yet another doomed cycle of “innovation.”  The people to blame are the tech CEOs — Sam Altman, Dario Amodei, Sundar Pichai, Andy Jassy, Elon Musk, Hock Tan, Jensen Huang, Sanjay Mehrotra to name a few — and the financiers that have helped them pump this bubble, with the worst of them being that rat fuck Stephen A. Schwarzman, CEO of Blackstone, a private equity (or “alternative asset”) firm that has funded basically every name I just wrote down on some level, funded by everyone from the Saudis to the California state pension system .  This week’s premium will be the Hater’s Guide To Blackstone, a company that vibrates with evil, and has staked its entire future on whether AI works out. It’s a stupid fucking bet from an evil fucking company, and I can’t wait to tell you all about it on Friday. If you liked this piece, you should subscribe to my premium newsletter. It’s $70 a year , $18 a quarter , or $7 a month , and in return you get a weekly newsletter that’s usually anywhere from 10,000 to 18,000 words and provides vast, detailed analyses of the biggest events and companies in the AI bubble. If you want to get in touch — and especially if you have any juicy information about Anthropic, OpenAI, or any other companies in the AI bubble — hit me up on Signal at ezitron.76. I’m also on IB on The Terminal. On Jan 27, 2025 , NVIDIA dropped 17%, its worst daily percentage loss (per Forbes) since March 2020, with the S&P 500 dropping 1.5% and the NASDAQ 3.1%, though its share of the S&P 500 at the time was about 1.9% smaller. On June 5, 2026 , NVIDIA dropped about 6.2%, with the NASDAQ ending the day down 4.18% and the S&P 500 down 2.64%.

0 views

Unleashing agents inside the workshop

I recently learned of Ubuntu Workshops . In short, Workshops allow you to create an isolated development environment to safely work with AI agents. You get a configured (via YAML) sandbox where you can safely run an agent without the need for permission checks and guardrails. Workshops allow you to expose or block certain parts of your system as needed (for example, you can expose your GPU for local models or block access to your webcam). As an example, let's build a simple Rust app that converts images from the HEIC format (bane of my existence) to JPEG. We'll use Iced to provide a simple GUI that supports drag and drop. First, install the Workshops Snap from the Ubuntu App Store. I also had to install the LXD subsystem for virtualization : To setup the workshop, create an empty directory and run the following commands: This will give a workshop named "dev" with Codex and Rust ready to go. On first run, we'll need to login to Codex using the following: Next, we want to define an "auto-mode" for Codex so we don't have to deal with permission check prompts. We'll do this by defining an "action" in the file. We've added two actions, to define a non-interactive session, and for an interactive one. Both have the flag which bypasses permission checks. As an added benefit, actions make it easy to standardize how we pass instructions to agents. We could easily define a Claude action that accepts the same arguments as Codex. Now let's define our prompt, instructing the agent to build our Rust application. This could of course also be done interactively via the Codex TUI inside the workshop, or through a a AI software factory . For now, we'll create a file and add the following: Finally, we'll setup Git for version controlling. Time for the fun part! We'll use the command to build the application in the folder without needing any input from the user. The agent will now run completely autonomously with no need to press "enter" on permission checks. Our host system remains protected as the agent is sandboxed away from our filesystem and devices. In fact, you'll notice in the prompt we specified that the agent should not try running the application. This is because we didn't provide access to a Wayland or X11 display server, so the agent cannot run a GUI application. Here's what I got as a result: The UI isn't great, but it works and successfully converted some photos from my iPhone! After putting together this article and testing out workshops, I'd say it's definitely a tool worth using. Workshops add minimal overhead, provide a composable/reusable environment for development and safeguard your host system from agents going rogue. Between this and Myna , Canonical is doing a lot to support the new development workflows that are becoming common

0 views
Farid Zakaria Yesterday

No quarter for gaps

The advent of large language models has changed the economics of closing gaps in software stacks. This is in the nixpkgs manual, in the Ruby section, under “Platform-specific gems” [ref] . The pull request ( PR#68 ) it points to was opened in October 2019 and closed, unmerged, in August 2026, with: “Closing as stale. I no longer work with bundix. Feel free to take it over.” [cite] Aside There are alternatives that have sprung up but they all have unique gaps or are not widely communicated as blessed solutions. The manual itself also does recommend a workaround for the issue, but I found it to not work in practice. Every ecosystem has gaps everyone has learned to step around. They survive because there is just too much stuff to do. We live with these warts and gaps because the cost of fixing them is either too high or there are more important things to do. That economics is gone. We can have and expect amazing perfectly correct software stacks, because the cost of fixing gaps is now low enough that it is worth doing. The economics of software have changed. The multiple days of typing are now an afternoon, or less , of directing and reading to an AI agent. In the case of Nix and Ruby, I wrote the Nix side of a Bundler lockfile solution, gemlock.nix , within an hour, removing days of misery I hit while running this blog. While AI generated code may suffer from slop, it is a growing skill how to wield AI to produce correct verifyable code. Nix is amazingly well-suited as it gives the agents a reproducible test-bed with which to verify the correctness of the code they produce. The economics of software have changed, and we can now expect to have no quarter for gaps in our stacks.

0 views