Engineering
19 Feb 2026
TypeScript 6.0 Beta: Preparing for the Go Rewrite
TypeScript 6.0 beta dropped on February 11th, and honestly? The release notes read less like a feature announcement and more like a farewell letter. This release wraps up the JavaScript-based TypeScript compiler for good. The next major version — TypeScript 7.0 — ships the native Go compiler Anders Hejlsberg first announced almost exactly a year ago, on February 28, 2025.
The team chose 6.0 as the version to rip out everything that won’t survive the transition. They’re not being gentle about it.
10 Feb 2026
Google Antigravity: Orchestrating the Next Phase of Agency
Full disclosure: I work at Google. Antigravity ships under our logo. Everything here comes through that lens, so calibrate accordingly.
I’m going to be candid about what works, what doesn’t, and where this fits among the growing pile of agentic dev tools. The worst thing I could do — for Google’s credibility and my own — would be writing a product puff piece. Nobody needs another one of those.
What Antigravity Actually Is #
Google announced Antigravity alongside Gemini 3 back in November 2025. The short version: an agent-first IDE. Not an IDE with agent features bolted on (that describes Cursor and Copilot, fundamentally). An IDE designed from scratch around developers defining tasks while agents execute them.
27 Jan 2026
Talk: Architecting Multi-Agent Developer Workflows
I gave a talk recently on multi-agent developer workflows. The prep forced me to organize a lot of scattered thinking into something presentable, and honestly that exercise alone justified the talk. This post distills the core arguments and architectural patterns I covered — not a transcript, more like the cleaned-up version of my speaker notes plus some refinements I’ve made since.
The punchline, for those who want it upfront: multi-agent systems work when the problem genuinely decomposes into specialized roles. But the instinct to split everything into agents? Same instinct that over-decomposed monoliths into too many microservices circa 2016. The pattern helps when it helps; it hurts when applied out of habit.
16 Oct 2025
Node.js 25: Native Stripping of TypeScript Types
Node.js 25 dropped yesterday. V8 14.1, faster JSON.stringify for large payloads, native Uint8Array base64/hex conversion. Solid release. But honestly, the headline for me is the TypeScript type stripping story finally reaching its conclusion.
Type stripping—Node.js natively running .ts files by ripping out type annotations at parse time—shipped unflagged in Node.js 23.6 but still carried the “experimental” label. With 25.2 (landing shortly after this initial release), that label goes away. Stable. No flags, no warnings. You run node script.ts and it just works.
25 Sep 2025
Trillion-Row Creative Insights: Scaling Netflix Muse
Netflix published a deep dive into Muse, their internal platform that helps creative strategists figure out which artwork and video clips land with which audiences. The engineering caught my attention—not because the technology stack is exotic, but because it combines well-understood techniques (probabilistic data structures, precomputed aggregates, columnar storage) into something that serves interactive analytics over a trillion rows.
A trillion rows. Interactive latency. And the use case? Creative decision-making, not ad targeting or fraud detection. That contrast alone makes the architecture worth pulling apart.
1 Sep 2025
MCP: Using Streamable HTTP for Real-Time AI Tool Use
If you’ve been building MCP integrations, you probably noticed the transport layer changed underneath you. The March 2025 spec update—version 2025-03-26—deprecated the HTTP+SSE transport in favor of Streamable HTTP. The change sounds minor. Swapping one HTTP-based approach for another. But the implications ripple through everything from auth middleware to deployment topology.
Let me walk through what actually changed, why it matters, and what you need to know if you’re building or maintaining MCP servers.
29 Apr 2025
Spec-Driven Development at Enterprise Scale
Three weeks ago I wrote about the shift from code-as-truth to intent-as-truth and collaborative intent articulation. The response was interesting: individual developers got it immediately, but engineering managers kept asking the same question.
“How does this work at scale?”
Fair question. And the honest answer is: it’s messy.
Spec-driven development at the single-team level is relatively straightforward. You write an OpenAPI spec, generate client and server stubs, validate implementations against the contract, and iterate. Good tools exist for this. The workflow is well-understood.
31 Jan 2025
Building AI-Native Teams: Lessons from OpenAI Codex
I read about how OpenAI structures their Codex team last week, and something clicked that I struggled to articulate for months. The shift to AI-native engineering goes beyond giving developers better tools—it reorganizes around the assumption that AI participates in every workflow. Not an add-on. Not a plugin. A participant.
The Codex team operates with roughly 40 people: 1 PM, 2 designers, the rest engineers. They ship multiple releases per week, sometimes pushing four internal builds in a single day. Those numbers would sound like chaos at most companies. At OpenAI, that’s just Tuesday.
12 Dec 2024
Done Software: The Future of Sustainable Stewardship
Lately I keep circling back to software that’s done.
Not dead. Not abandoned. Not deprecated. Done. Feature-complete. Stable. Doing exactly what it set out to do, with no urgent need to do anything else. The concept makes most engineers uncomfortable—our entire industry rests on the assumption that software must continuously evolve or die.
That assumption runs wrong, and burns people out.
The Cult of Continuous Development #
Open source has an update problem. We’ve internalized the idea that a healthy project ships frequently—new features, new releases, activity graphs that glow green. GitHub’s contribution graph literally visualizes this: green squares good, gray squares bad. A project with no commit in six months looks neglected, even when stable, secure, and doing the job perfectly.
11 Dec 2024
TypeScript 5.7 Variable Init Logic
TypeScript 5.7 shipped on November 22nd, and buried in the release notes—between the new --target es2024 flag and path rewriting improvements—is a fix that’s bugged me for years. The compiler now detects when you access an uninitialized variable inside a nested function.
If that sounds minor, you haven’t hit this one yet. I have. More than once.
The Problem That Was Always There #
Here’s the setup. You declare a variable, intend to assign it later; then you reference it inside a callback or inner function before the assignment actually runs:
8 Apr 2024
Node.js 22: Experimental ESM Require and V8 v12.4
The Node.js 22 release candidates have been floating around for a few weeks, and the headline feature is exactly what the community’s been screaming for since ESM first showed up: you can finally require() an ES module.
Well. Sort of. Behind a flag. And only if there’s no top-level await. But still — progress.
I’ve been running the RC against our codebase at DreamFlare to see what breaks and what actually gets easier. Here’s what jumped out.
28 Feb 2024
AI-Generated Code: The Trust and Verification Gap
There’s this moment I keep seeing on my team. An engineer gets a Copilot suggestion. It looks right. It passes the quick mental check. They tab-accept and move on.
Twenty minutes later, a test fails. The bug trace leads back to that accepted suggestion — a subtle null handling issue the generated code glossed over.
This happens more than anyone wants to admit. And it scales.
The paradox in numbers #
Three statistics that, taken together, should alarm anyone running an engineering org:
27 Feb 2024
OpenAI Codex: Structuring AI-Native Teams
Six months into building DreamFlare’s engineering team with AI tools baked into the daily workflow, some opinions have formed. A few of them are probably wrong. But the experience turned concrete enough that the lessons on structuring teams — when AI pair programming is the default, not the exception — deserve sharing.
The 55% number and what it misses #
GitHub published a study in September 2023 showing that developers using Copilot completed tasks 55.8% faster than those without it. The earlier academic study from February 2023 (Peng et al., published in collaboration with GitHub Research) found similar results across controlled task scenarios. These numbers get cited constantly; they’re real.
2 Jan 2024
Schema First TypeScript Design with Valibot
Yesterday’s post was about avoiding any. Today I want to talk about the next step: making your types actually work for you.
Here’s the problem. TypeScript gives you compile-time safety. Beautiful, precise types that catch bugs before you run anything. Then the compiler strips them all away. At runtime, that carefully typed User object is just a plain JavaScript object—and nothing stops malformed data from sneaking in through an API boundary.
31 Dec 2023
Avoiding 'Any' in TypeScript: Why it Exists and Remedies
Last day of 2023, and I’m thinking about types. Specifically, the type that undoes all your other types.
I’ve been writing TypeScript since before it was cool (and through the years where it still wasn’t). Every codebase I’ve inherited or built has had any scattered through it like landmines. Some justified. Most not. At DreamFlare, we’ve been slowly de-mining our codebase this quarter, and I figured I’d share the patterns that keep coming up.
25 Aug 2023
TypeScript 5.2: using Declarations and Resource Mgmt
TypeScript 5.2 dropped yesterday. The headline feature is using declarations — automatic resource management via the TC39 Explicit Resource Management proposal. If you’ve ever written a try/finally block just to close a database connection, this one’s for you.
I’ve been tracking this proposal since it hit Stage 3 at TC39 earlier this year. The TypeScript team’s implementation is clean — really clean. Let me walk through what it does, why it matters, and yeah, where it falls short.
31 Jul 2023
Llama 2: Why Local Inference in C Matters for Node Devs
Two weeks ago Meta released Llama 2 with a commercial license. That alone was significant — the first truly open large language model you could legally ship in a product. But the thing that got me out of my chair was what Andrej Karpathy did with it eight days later.
He wrote Llama 2 inference in ~500 lines of pure C. No libraries. No frameworks. No PyTorch, no CUDA, no nothing. Just C and math. The repo is called llama2.c, and it runs the 7B parameter model at about 18 tokens per second on an M1 MacBook Air.
4 Jul 2023
Platform Engineering: Bridging the Dev/Ops Gap
“You build it, you run it.” That was the DevOps promise. Engineers would own the full lifecycle of their services — from writing code to operating it in production. No more throwing things over the wall to an operations team. No more “works on my machine.” Full ownership, full accountability.
In theory, this was liberating. In practice? It buried engineers under a mountain of operational complexity they never asked for and weren’t trained to handle.
20 Apr 2023
TypeScript 5.0: Standard ECMAScript Decorators
Eight years. That’s how long the TC39 decorators proposal took to reach Stage 3.
It started in 2014 — ancient history in JavaScript years — went through multiple complete rewrites, and finally stabilized in March 2022. TypeScript 5.0 shipped last month with support for the standard version.
If you’ve been using --experimentalDecorators (and if you work with Angular, NestJS, or MobX, you almost certainly have), this matters. The new decorators aren’t a drop-in replacement. Not even close.
10 Mar 2023
Smartcast and Null Safety: Influences from Kotlin to TS
Working at Google means living in a polyglot environment. Android teams write Kotlin. Web teams write TypeScript. Backend teams write a mix of Java, Go, and (increasingly) Kotlin. When you cross those boundaries regularly — and in DevRel, crossing boundaries is the job — you start noticing how ideas migrate between language ecosystems.
One migration that doesn’t get discussed enough: the convergence of type narrowing between Kotlin and TypeScript.
Kotlin’s smart casts #
Kotlin shipped smart casts from day one in 2016. The idea was simple and, at the time, felt radical compared to Java: if you check a type at runtime, the compiler should remember that check and narrow the type automatically.
30 Nov 2022
TypeScript 4.9: Narrowing Checks with the 'in' Operator
TypeScript 4.9 shipped a couple weeks ago, and most coverage I’ve seen focuses on the satisfies operator. Fair enough — satisfies is flashier. But the change I’m actually excited about? The improvement to type narrowing with the in operator. It fixes something that’s been bugging me for years.
The problem before 4.9 #
Say you’ve got a value typed as unknown and you want to check if it has a specific property before using it. Your natural instinct is:
21 Aug 2022
TypeScript 4.8: Better Type Inference in bindings
TypeScript 4.8 RC dropped about ten days ago and I’ve been poking at it since. Most of the attention has gone to the {} type intersection improvements, which are legitimately useful. But the change that excites me most is subtler: binding patterns no longer influence type argument inference.
If that sentence didn’t immediately make you say “finally,” you probably haven’t maintained a library with complex generic signatures. Let me explain why this matters.
25 May 2022
TypeScript 4.7: Native ESM Support for Node.js
TypeScript 4.7 shipped yesterday, and the headline feature is one that was supposed to land six months ago: native ESM support for Node.js.
If you’ve been following this saga, you know the backstory. TypeScript 4.5 (November 2021) was supposed to include the node16 and nodenext module resolution settings. The TypeScript team pulled them at the last minute because the implementation wasn’t ready. That delay was frustrating for everyone who’d been waiting — the CJS/ESM interop story in Node.js has been a mess for years, and TypeScript not supporting it natively made everything worse.
30 Apr 2022
Node.js 18: Native Fetch API and Experimental Test Runner
Node.js 18 dropped on April 19th, and for the first time in a while, I’m genuinely excited about a Node release. Not because of performance improvements or security patches — those are table stakes — but because of two features that address long-standing gaps in the platform: a global fetch API and a built-in test runner.
Both are experimental. Both have caveats. And both signal a direction for Node.js that I think is overdue.
14 Feb 2022
TypeScript 4.6: Improved Recursion Depth Checks
TypeScript 4.6 RC dropped on February 11th. Most coverage will focus on the shiny stuff—control flow analysis for destructured discriminated unions, the new --generateTrace flag, ES2022 target. Those are fine. But I want to dig into something most developers won’t notice: improved recursion depth checks.
It’s the kind of change that sounds boring until you realize it’s cutting type-check times in half for some libraries.
The old heuristic #
When TypeScript checks if two types are compatible, it sometimes hits recursive structures. Think Tree<T> = { value: T; children: Tree<T>[] }. Checking compatibility means recursively checking children, which means checking Tree again, and so on.
5 Feb 2022
The Golden Thread: Managing Building Data Integrity
I rarely write about construction. But the concept emerging from the UK Building Safety Bill caught my attention—it maps so precisely to problems I spent years solving in software that I couldn’t ignore it.
The “golden thread” demands that every higher-risk building carry a continuous, authoritative digital record from design through construction through decades of operation. One source of truth, maintained throughout the building’s entire lifecycle because no single handoff point exists where someone else takes over responsibility. That sounds like a data lineage problem. Because it is one.
27 Nov 2021
TypeScript 4.5: The Awaited Type and Promise unwrapping
TypeScript 4.5 dropped on November 17th, and honestly? The feature I’m most excited about is Awaited<T>. Not exactly headline material — it’s a utility type, and utility types don’t exactly trend on Hacker News. But this one fixes a class of problems I’ve been wrestling with for years, and the solution is surprisingly elegant.
The problem Awaited actually solves #
Ever written a generic function that takes a Promise<T> and tried to extract what it actually resolves to? Yeah. Before 4.5, TypeScript had no built-in way to recursively unwrap nested promises — and believe me, I tried.
3 Sep 2021
TypeScript 4.4: Aliased Conditions and Flow Analysis
TypeScript 4.4 shipped last week, and the feature I keep reaching for isn’t the one I expected.
I figured the new strictness flags would dominate my attention. They didn’t. Instead, it’s the control flow analysis of aliased conditions that’s quietly changing how I write type guards. The feature is simple enough to explain in a paragraph, but the downstream effects on code organization are larger than the changelog suggests.
The Problem Before 4.4 #
Here’s a pattern every TypeScript developer has written:
26 Jul 2021
Rethinking Errors, Warnings, and Lints in Large Codebases
Last week I opened a pull request on one of our older services at TaskRabbit and got hit with 347 ESLint warnings. Not errors. Warnings. The build passed, the tests passed, and the PR got merged. Nobody looked at a single one of those 347 signals.
That moment bothered me more than it should have.
I’ve been managing large codebases for a while now, and the way most teams handle the spectrum between errors, warnings, and lints is — to put it politely — chaotic. We tend to treat them as a binary: either something blocks the build or it doesn’t. The nuance in between? Lost. Completely.
25 May 2021
TypeScript 4.3: Mastering the override Keyword
TypeScript 4.3 RC dropped on May 11th, and I’ve been running it on a side project for the past two weeks. The headline feature — the override keyword — fills a gap that’s bitten me more than once in large codebases.
Here’s the scenario. You’ve got a base class. You override a method in a subclass. Six months later, someone renames the base method during a refactor. Your subclass method silently becomes a new method instead of an override. No error. No warning. Just a subtle bug that passes type checking and breaks at runtime.
25 Feb 2021
TypeScript 4.2: Preservation of Type Aliases
TypeScript 4.2 shipped on February 23rd and honestly? The feature that excites me most changes nothing about what your code does. It just changes what the compiler tells you.
Type alias preservation means the compiler finally stops expanding your carefully-named types into gibberish. You know the drill — you write something clean like type BasicPrimitive = string | number | boolean, and then every error message, every tooltip, every .d.ts file insists on showing string | number | boolean instead. As if your alias never existed.
30 Nov 2020
Template Literal Types: Mapping APIs with Precision
TypeScript 4.1 dropped on November 17th and I’ve spent the last two weeks playing with template literal types. They’re one of those features that sounds academic until you see what they unlock for real API modeling.
The short version: you can now use backtick syntax in type positions to construct and manipulate string literal types at compile time.
type EventName = `on${Capitalize<string>}`;
// Matches "onClick", "onHover", "onSubmit", etc.
That’s not a runtime string template—it’s a type-level computation. The compiler evaluates it during type checking and narrows accordingly.
15 Oct 2020
Rosetta 2 and the Architecture of Apple Silicon
Back in 2006, Apple shipped Rosetta — a binary translation layer that let PowerPC apps run on Intel Macs. It was slow. It was imperfect. And it bought them just enough time to pull off one of the most successful architecture transitions in computing history.
Fourteen years later, they’re doing it again.
At WWDC in June, Apple announced the transition from Intel to their own ARM-based silicon. The M1 chip. And alongside it, Rosetta 2.
5 Oct 2020
TypeScript 4.1: Why Recursive Conditional Types Matter
The TypeScript 4.1 beta landed on September 18, and the marquee feature—recursive conditional types—is one of those additions that separates “TypeScript as better JavaScript” from “TypeScript as a serious type-level programming language.”
I’ve spent the last two weeks experimenting with the beta, and I want to walk through what recursive conditional types actually enable, why they matter for real codebases, and how the other 4.1 features complement them.
The Problem Before Recursion #
TypeScript’s conditional types (introduced in 2.8) let you express type-level if/else:
14 Sep 2020
Node.js 15: Introduction to AbortController
If you’ve done any work with fetch in the browser, you’ve probably used AbortController. It’s the standard Web API for cancelling asynchronous operations—pass an AbortSignal to a fetch call, call abort() when you want to cancel, and the browser throws an AbortError. Clean, composable, and it works.
Node.js hasn’t had this. And honestly? The absence of a built-in cancellation primitive has been one of those quiet pain points that every backend developer just… works around. Some use timeouts. Some use custom event emitters. Some reach for p-cancelable or similar libraries. None of it is standardized—every team invents their own slightly different pattern.
1 Aug 2020
TypeScript 4.0: Variadic Tuple Types and Modern Pattern
TypeScript 4.0 beta dropped about five weeks ago, and I’ve been running it against a couple of our internal libraries at work. The headline feature—variadic tuple types—sounds academic until you try to type a function like concat or curry and realize the type system couldn’t express it before.
The stable release should land later this month. Here’s what’s worth paying attention to.
Variadic Tuple Types #
Before 4.0, tuple types were fixed-length. You could write [string, number], but you couldn’t write a generic type that spread one tuple into another. If you wanted to type a function that concatenated two arrays while preserving element types, you were stuck writing overloads. Lots of overloads.
28 Mar 2020
Node.js 14: Diagnostic Reports and Internationalization
Node.js 14 lands April 21. I’ve been poking at the dev branch for a few weeks now, and two things keep standing out: Diagnostic Reports graduating to stable, and full ICU internationalization data shipping by default.
Neither is glamorous. Both are the kind of thing that makes Node.js meaningfully better in production — which is exactly what I care about.
Diagnostic Reports Go Stable #
Diagnostic Reports have been experimental since Node.js 11. The concept is straightforward: when something goes wrong (a crash, a hang, a weird performance cliff you can’t explain), you generate a JSON report that captures the full state of the process. Stack traces, heap statistics, resource usage, libuv handle information, environment variables, loaded native modules. Everything you’d want in a post-mortem.