Imagetype me = "davidblass"type reverse<s extends string> = s extends `${infer head}${infer tail}` ? `${reverse<tail>}${head}` : "" type me = reverse<"ssalbdivad">computed by the compiler at buildTS 6.0.3// types for a living · Boston, MA

David Blass

I make TypeScript's types do things they probably shouldn't- then make them fast. Lately: agents × DX.

author
ArkType (TypeScript's 1:1 validator) · ArkRegex · Attest
co-creator
Standard Schema · one interface for every TS validator
co-founder
Pullfrog · AI agents in GitHub Actions
consultant
TypeScript performance · 2023–25 · for tRPC, Prisma, Convex & more
david@arktype.ioGitHubLinkedIn
arkregex · regex with typeshover any nametap any name
import { 
type regex<pattern extends string = string, ctx extends RegexContext = RegexContext> = Regex<pattern, ctx>

const regex: RegexParser
regex
} from "arkregex"
const
const version: Regex<`${number}.${number}`, {
    captures: [`${number}`, `${number}`];
    names: {
        major: `${number}`;
        minor: `${number}`;
    };
}>
version
=
regex<"^(?<major>\\d+)\\.(?<minor>\\d+)$", "">(src: "^(?<major>\\d+)\\.(?<minor>\\d+)$", flags?: "" | undefined): Regex<`${number}.${number}`, {
    captures: [`${number}`, `${number}`];
    names: {
        major: `${number}`;
        minor: `${number}`;
    };
}>
regex
(
"^(?<major>\\d+)\\.(?<minor>\\d+)$" ) const {
const groups: {
    major: `${number}`;
    minor: `${number}`;
}
groups
} =
const version: Regex<`${number}.${number}`, {
    captures: [`${number}`, `${number}`];
    names: {
        major: `${number}`;
        minor: `${number}`;
    };
}>
version
.
Regex<`${number}.${number}`, { captures: [`${number}`, `${number}`]; names: { major: `${number}`; minor: `${number}`; }; }>.exec(s: string): RegexExecArray<[`${number}.${number}`, `${number}`, `${number}`], {
    major: `${number}`;
    minor: `${number}`;
}, ""> | null (+1 overload)
exec
("2.2")!

inferred from the pattern: real compiler outputTS 6.0.3 · arkregex 0.0.13

01 // work

Things I've made

ArkType

author · 2022–

It started as a question I didn't think had a good answer: how close can you get to TypeScript at runtime? Pretty close, it turns out. If you already know TypeScript, congratulations- you just learned most of ArkType's syntax. The parser is isomorphic: one implementation lives in the type system, checking each character as you type, and its runtime twin compiles the same definition to JIT-friendly validation code. It's downloaded const arktypeDownloads: 8_455_684npm downloads of arktype, Sep 19, 2026 – Oct 18, 2026@see api.npmjs.org/downloads/point/2026-09-19:2026-10-18/arktypeas of · 2026-10-20 00:21 UTCnpm, and the TypeScript team runs it in their regression tests, which gives me a lot of peace of mind.

arktype · the real parser, running livetype anything

✓ (number | string)[]

[1, "2", null] → value at [2] must be a number or a string (was null)

Attest

2023

Type-level benchmarks and assertions. I had to build it to build ArkType. Attest counts type instantiations instead of timing the compiler, so the result is deterministic and CI can catch a PR that makes types slower. It's how I measured the compiler fix below, and how projects like const i18nextType: { before: 218_121; after: 278 }Instantiations for one i18next type, in a contributor's initial attest benchmark of the refactor that shipped as i18next's selector API.@see i18next/i18next#2317 (comment)@see i18next/i18next#2322public recordsourced benchmark their own types.

ArkSchema

The set theory underneath. It knows number > 5 is a subtype of number > 0, and that divisible by 2 and by 3 reduces to divisible by 6, so ArkType can compare, intersect and narrow types at runtime. Finding a type's fully reduced form is one of my favorite problems in the world. If that didn't scare you off, the 13-minute version is my Effect Days talk

Standard Schema

co-creator · 2024–

One small interface every validator and framework can agree on. I co-designed it with the creators of Zod and Valibot. Now tRPC, TanStack, Hono, React Hook Form and dozens more accept whichever validator you use- no adapters, no meta-adapters. Then we wrote Standard JSON Schema, which lets the same validators double as tool input schemas for AI agents and MCP.

Diagram. Without a shared interface, 4 validators and 8 tools need 32 adapters, one per pair. With Standard Schema each implements or accepts one interface, so 12 integrations connect every validator to every tool.

validatorsframeworks & toolsZodValibotArkTypeEffect SchematRPCTanStack FormTanStack RouterHonoReact Hook FormElysiaNuxt UIAI SDK+ more+ more

StandardSchemaV1 · one interface

const email = type("string.email")

email["~standard"].StandardSchemaV1<Input = unknown, Output = Input>.Props<string, string>.validate: (value: unknown, options?: StandardSchemaV1<Input = unknown, Output = Input>.Options | undefined) => StandardSchemaV1.Result<string> | Promise<StandardSchemaV1.Result<string>>validate(
	"david@arktype.io"
)
4 + 8 = 12 integrations, not 4 × 8 = 32 adapters · const standardSchemaEcosystem: { validators: "30+"; tools: "60+" }Libraries listed on standardschema.dev as implementing or accepting the spec.Rounded down from a count of 33 and 64 on the live list.@see standardschema.dev/schemaas of · 2026-10-13sourced
the diagram as a table
Integrations with and without Standard Schema
without a standardwith Standard Schema
validatorsZod, Valibot, ArkType, Effect Schema
toolstRPC, TanStack Form, TanStack Router, Hono, React Hook Form, Elysia, Nuxt UI, AI SDK
integrations4 × 8 = 324 + 8 = 12

Pullfrog🐸

co-founder · 2025–

Coding agents in your GitHub Actions. It runs whichever agent you already use (Claude Code, Codex, OpenCode) with your own keys, on your PRs, issues and failing CI, and it just gets better as your agents do. I started it with Colin McDonnell, who made Zod. I built the agent runtime underneath it, and these days a lot of agents help me build it

02 // perf

Why your types are slow

"our two-step process for fast typescript types: 1️⃣ build a type‑level benchmarking library 2️⃣ spend the prime of your life on cache optimizations" @arktype.io

Most of my consulting happened in private repos. This one ended up in the compiler.

TypeScript 5.92025

Two innocuous-looking useMutation calls took about 2 seconds each to type-check.

  1. the itch

    I was digging into tRPC type performance, and those two calls were in AnswerOverflow, a public tRPC app- so, for once, the trace is still up. Zod schemas derived in chains like theirs are very common in the wild, especially in the repos I investigate.

  2. the hunt

    I minimized it to a chain of merges, the kind Zod's .merge().pick().omit() and tRPC's merge<merge<…>> produce. Each link roughly tripled the compiler's work until, 13 links in, TypeScript declared the chain error TS2589: Type instantiation is excessively deep and possibly infinite.What TypeScript 5.8.2 says about 13 chained .merge() calls: the bench below, reproduced Oct 13, 2026.tsc 5.8.2 · reproducedTS 5.9.3: 0 errors. I counted it with Attest

    "in case anyone was curious what O(3^N) looks like": type instantiations for chained .merge() calls, TypeScript 5.8.2 vs 5.9.3
    show the bench
    bench · chained11 calls
    type merge<base, props> =
    	Omit<base, keyof props & keyof base>
    	& props
    
    type Type<t> = {
    	merge: <r>(r: r) => Type<merge<t, r>>
    }
    
    declare const 
    const a: Type<{
        a: 1;
    }>
    a
    : Type<{ a: 1a: 1 }>
    const
    const c1: Type<merge<{
        a: 1;
    }, {
        b: number;
    }>>
    c1
    =
    const a: Type<{
        a: 1;
    }>
    a
    .merge({ b: 2 })
    const
    const c2: Type<merge<merge<{
        a: 1;
    }, {
        b: number;
    }>, {
        c: number;
    }>>
    c2
    =
    const c1: Type<merge<{
        a: 1;
    }, {
        b: number;
    }>>
    c1
    .merge({ c: 3 })
    const
    const c3: Type<merge<merge<merge<{
        a: 1;
    }, {
        b: number;
    }>, {
        c: number;
    }>, {
        d: number;
    }>>
    c3
    =
    const c2: Type<merge<merge<{
        a: 1;
    }, {
        b: number;
    }>, {
        c: number;
    }>>
    c2
    .merge({ d: 4 })
    const
    const c4: Type<merge<merge<merge<merge<{
        a: 1;
    }, {
        b: number;
    }>, {
        c: number;
    }>, {
        d: number;
    }>, {
        e: number;
    }>>
    c4
    =
    const c3: Type<merge<merge<merge<{
        a: 1;
    }, {
        b: number;
    }>, {
        c: number;
    }>, {
        d: number;
    }>>
    c3
    .merge({ e: 5 })
    const c5 =
    const c4: Type<merge<merge<merge<merge<{
        a: 1;
    }, {
        b: number;
    }>, {
        c: number;
    }>, {
        d: number;
    }>, {
        e: number;
    }>>
    c4
    .merge({ f: 6 })
    const c6 = c5.merge({ g: 7 }) const c7 = c6.merge({ h: 8 }) const c8 = c7.merge({ i: 9 }) const c9 = c8.merge({ j: 10 }) const c10 = c9.merge({ k: 11 }) const c11 = c10.merge({ l: 12 }) const c12 = c11.merge({ m: 13 }) const c13 = c12.merge({ n: 14 }) const c14 = c13.merge({ o: 15 }) const c15 = c14.merge({ p: 16 })
    TS 5.8.2⛳ Result: 1,596,004 instantiations
    TS 5.9.3⛳ Result:       976 instantiations
    type instantiations

    Line chart. As chained .merge() calls increase from 1 to 15, TypeScript 5.8.2's type instantiations roughly triple with each call, from 98 to 4,784,888 at 12 calls, then fail with error TS2589 from 13 calls on. TypeScript 5.9.3 stays under 1,700 throughout: 976 at 11 calls and 1,632 at 15.

    Instantiation counts from @ark/attest 0.57.0: deterministic. Bench from microsoft/TypeScript#61505; re-run on 5.8.2 and 5.9.3, Oct 13, 2026.

    Data
    Type instantiations by number of .merge() calls (attest 0.57.0). "TS2589" means the checker bailed; the count it reported is in parentheses and isn't real work.
    callschained 5.8.2chained 5.9.3functional 5.8.2functional 5.9.3
    198363014
    2250857733
    352414416355
    41,13621336080
    52,734292884108
    67,2623812,383139
    720,5524806,801173
    860,10058919,970210
    9178,39470859,386250
    10532,898837177,537293
    111,596,004976531,887339
    124,784,8881,1251,594,828388
    13TS2589
    (9,785,026)
    1,2844,783,536440
    14TS2589
    (14,785,170)
    1,45314,349,539495
    15TS2589
    (14,785,298)
    1,632TS2589
    (24,349,567)
    553
  3. the fix

    I worked on it with Andarist (Mateusz Burzyński), who wrote the compiler patch: cache instantiations on type mappers. His PR opens: "@ssalbdivad found out that a chain of somewhat trivial operations can easily end up with dreaded 'Type instantiation is excessively deep and possibly infinite'." I tested it on const trpcMonorepo: { before: "13.04s"; after: "6.00s"; runs: 1 }One of the tRPC monorepos I tested, TS 5.8 vs. the #61505 build.A single run.@see microsoft/TypeScript#61505 (comment)public recordsourced: it removed the depth errors, cut check time in half or better, or both.

    "How has this man not been hired by the TypeScript team yet?" — me, about Andarist, 2024

  4. the review

    Anders Hejlsberg's review asked to cache only the expensive instantiations. My reply: "whether or not individual instantiations are expensive, if there are O(3^N) of them, they will eventually dominate the check time of the entire type."

  5. shipped

    It merged in June 2025 and shipped in TypeScript 5.9 as "Cache Instantiations on Mappers"; the release notes name Zod and tRPC. Jake Bailey ported it to the Go compiler.

  6. what repos saw

    Type-checking AnswerOverflow's dashboard dropped from const answerOverflow: { before: "6.66s"; after: "3.29s"; runs: 5 }AnswerOverflow's dashboard, type-checked on TS 5.8 vs. the #61505 build. Mean of 5 runs each; the ranges don't overlap.Jake Bailey (TS team) measured the same repo independently: 7.67s → 3.79s.@see Andarist's runs (comment on #61535)@see typescript-go#1358 (Jake Bailey's run)public recordsourced (5 runs each, no overlap), and Jake Bailey on the TypeScript team independently reproduced the halving on the same repo. At Klarna, an engineer reported their check time dropping from const klarna: { before: "395.48s"; after: "132.09s" }Klarna's app.Third-party and self-reported, in one comment.@see microsoft/TypeScript#61505 (comment)@see microsoft/TypeScript#61505 (Klarna, follow-up)public recordsourced: "This was a game-changer PR for us."

Compiler patch by Mateusz Burzyński (@Andarist) · microsoft/TypeScript#61505 · TS 5.9 notes · typescript-go#1358

a few more, briefly

  • viem

    In MUD's build, TypeScript spent const getVariancesWorker: { ms: 1_866; typeParams: 9 }Time TypeScript spent computing the variance of viem's SimulateContractReturnType, in a trace of MUD's build.@see latticexyz/mud#2956@see wevm/viem#2557public recordsourced just computing the variance of one viem type. I added in/out annotations to viem itself.

  • Prisma

    I built their type benchmarks and helped speed up their generated types, which Prisma kindly wrote up in its 6.16 release notes.

  • Mongoose

    I reworked InferRawDocType; it shipped in 8.19.

Clients have included tRPC, Prisma, Convex, AWS Amplify, Speakeasy, Stately, wevm, Vanta and Cloudinary. Some stuff that looks super expensive is actually irrelevant; some stuff that looks innocuous is actually a massive problem. All you can do is learn heuristics, iterate and pray.

03 // agents

How I keep up with agents

Most days I have more coding agents working on Pullfrog at once than I can pay attention to. I run them from ntwine, the agent orchestrator I'm building: it runs them in parallel and queues up the ones that need me. The rules I've ended up with, for them and for me: size work by scope, never in days; report honest effect sizes; lead with what changed; preserve evidence.

Exhibit A: the first version of this page.

  • research 6
  • design 5
  • build 36
  • review 50
  • thickness = calls/min
22:0023:0000:0001:0002:0003:0004:0005:0006:0007:0008:00perf-case-studies → research-perf.md · 11m · 77 tool callstalks-media → research-media.md · 11m · 79 tool callsvoice-buzz → research-voice.md · 20m · 85 tool callsbrand-local → research-brand.md · 10m · 71 tool callsstats-apis → research-stats.md · 4m 54s · 33 tool callstech-stack → research-stack.md · 14m · 75 tool callsstory → design-story.md · 7m 50s · 16 tool callsdelight → design-delight.md · 9m 46s · 28 tool callsvisual → design-visual.md · 16m · 71 tool callsdataviz → design-dataviz.md · 14m · 31 tool callssynthesis → concept.md · 10m · 22 tool callswork → Work.tsx · 37m · 137 tool callsperf → Perf.tsx · 28m · 104 tool callsagents-talks → Agents.tsx · 27m · 122 tool callseggs → Eggs.tsx · 24m · 129 tool callsdesign review · 40m · 219 tool callsrecruiter review · 18m · 95 tool callshonesty review · 18m · 97 tool callsa11y review · 35m · 180 tool callsinteractions review · 52m · 133 tool calls · stopped without a resultperfcode review · 53m · 72 tool calls · stopped without a resultverifier · 20m · 75 tool callsverifier · 12m · 78 tool callsverifier · 17m · 74 tool calls · stopped without a resultverifier · 12m · 69 tool calls · stopped without a resultinteractions review · 1h 13m · 138 tool callsverifier · 29m · 134 tool callsperfcode review · 45m · 136 tool callsverifier · 11m · 80 tool callsverifier · 16m · 84 tool callsverifier · 18m · 99 tool callswork · fixes → Work.tsx · 4m 19s · 21 tool callsperf · fixes → Perf.tsx · 6m 24s · 43 tool callsagents-talks · fixes → Agents.tsx · 8m 16s · 47 tool callseggs · fixes → Eggs.tsx · 1m 57s · 16 tool callsshell · fixes → styles.css · 33m · 127 tool callseggs · fixes → Eggs.tsx · 6m 01s · 33 tool callsverifier · 20m · 72 tool callswork · fixes → Work.tsx · 24m · 52 tool callsperf · fixes → Perf.tsx · 42m · 166 tool callsagents-talks · fixes → Agents.tsx · 6m 31s · 12 tool callseggs · fixes → Eggs.tsx · 0m 32s · 6 tool callsshell · fixes → styles.css · 24m · 73 tool callsverifier · 15m · 78 tool callseggs · fixes → Eggs.tsx · 1m 02s · 7 tool callsdesign review · round 2 · 1h 00m · 270 tool callsrecruiter review · round 2 · 24m · 108 tool callshonesty review · round 2 · 18m · 105 tool callsa11y review · round 2 · 49m · 172 tool callsinteractions review · round 2 · 1h 42m · 137 tool callsperfcode review · round 2 · 48m · 143 tool callsverifier · round 2 · 8m 26s · 47 tool callsverifier · round 2 · 12m · 45 tool callsverifier · round 2 · 19m · 56 tool callsverifier · round 2 · 28m · 91 tool callsverifier · round 2 · 21m · 91 tool callsagents-talks · fixes → Agents.tsx · 1m 36s · 8 tool callseggs · fixes → Eggs.tsx · 1m 49s · 9 tool callsshell · fixes → styles.css · 13m · 29 tool callsverifier · round 2 · 16m · 56 tool callsshell · fixes → styles.css · 36m · 139 tool callsperf · fixes → Perf.tsx · 17m · 69 tool callswork · fixes → Work.tsx · 18m · 56 tool callsagents-talks · fixes → Agents.tsx · 7m 13s · 27 tool callseggs · fixes → Eggs.tsx · 5m 40s · 23 tool callsdesign review · round 3 · 33m · 208 tool callsrecruiter review · round 3 · 25m · 129 tool callshonesty review · round 3 · 18m · 126 tool callsa11y review · round 3 · 1h 14m · 222 tool callsinteractions review · round 3 · 1h 34m · 150 tool callsperfcode review · round 3 · 1h 09m · 164 tool callsverifier · round 3 · 6m 32s · 48 tool callsverifier · round 3 · 8m 05s · 43 tool callsagents-talks · fixes → Agents.tsx · 25m · 81 tool callseggs · fixes → Eggs.tsx · 6m 20s · 31 tool callsverifier · round 3 · 12m · 79 tool callsshell · fixes → styles.css · 7m 53s · 28 tool callsperf · fixes → Perf.tsx · 2m 13s · 15 tool callsverifier · round 3 · 18m · 53 tool callsverifier · round 3 · 16m · 86 tool callsshell · fixes → styles.css · 8m 08s · 33 tool callsperf · fixes → Perf.tsx · 9m 42s · 15 tool callswork · fixes → Work.tsx · 3m 56s · 18 tool callsagents-talks · fixes → Agents.tsx · 1m 44s · 11 tool callsverifier · round 3 · 18m · 69 tool callsshell · fixes → styles.css · 6m 57s · 27 tool callswork · fixes → Work.tsx · 7m 25s · 21 tool callsperf · fixes → Perf.tsx · 2m 30s · 12 tool callscontent check · 17m · 71 tool callsvisual check · 17m · 94 tool callsinteract check · 53m · 110 tool callssweep check · 34m · 116 tool callsverifier · 6m 04s · 24 tool callsverifier · 2m 15s · 23 tool callsverifier · 8m 11s · 40 tool callsverifier · 22m · 31 tool callsagents-talks · fixes → Agents.tsx · 2m 20s · 7 tool calls27m idle≈27m idleresearch · 6design · 5build · 4review · 10review · 8fixes · 5fixes · 1fixes · 6review · 12fixes · 3fixes · 5review · 12fixes · 4fixes · 4fixes · 3review · 8fixes · 1@personal-page22:0023:0000:0001:0002:0003:0004:0005:0006:0007:0008:00perf-case-studies → research-perf.md · 11m · 77 tool callstalks-media → research-media.md · 11m · 79 tool callsvoice-buzz → research-voice.md · 20m · 85 tool callsbrand-local → research-brand.md · 10m · 71 tool callsstats-apis → research-stats.md · 4m 54s · 33 tool callstech-stack → research-stack.md · 14m · 75 tool callsstory → design-story.md · 7m 50s · 16 tool callsdelight → design-delight.md · 9m 46s · 28 tool callsvisual → design-visual.md · 16m · 71 tool callsdataviz → design-dataviz.md · 14m · 31 tool callssynthesis → concept.md · 10m · 22 tool callswork → Work.tsx · 37m · 137 tool callsperf → Perf.tsx · 28m · 104 tool callsagents-talks → Agents.tsx · 27m · 122 tool callseggs → Eggs.tsx · 24m · 129 tool callsdesign review · 40m · 219 tool callsrecruiter review · 18m · 95 tool callshonesty review · 18m · 97 tool callsa11y review · 35m · 180 tool callsinteractions review · 52m · 133 tool calls · stopped without a resultperfcode review · 53m · 72 tool calls · stopped without a resultverifier · 20m · 75 tool callsverifier · 12m · 78 tool callsverifier · 17m · 74 tool calls · stopped without a resultverifier · 12m · 69 tool calls · stopped without a resultinteractions review · 1h 13m · 138 tool callsverifier · 29m · 134 tool callsperfcode review · 45m · 136 tool callsverifier · 11m · 80 tool callsverifier · 16m · 84 tool callsverifier · 18m · 99 tool callswork · fixes → Work.tsx · 4m 19s · 21 tool callsperf · fixes → Perf.tsx · 6m 24s · 43 tool callsagents-talks · fixes → Agents.tsx · 8m 16s · 47 tool callseggs · fixes → Eggs.tsx · 1m 57s · 16 tool callsshell · fixes → styles.css · 33m · 127 tool callseggs · fixes → Eggs.tsx · 6m 01s · 33 tool callsverifier · 20m · 72 tool callswork · fixes → Work.tsx · 24m · 52 tool callsperf · fixes → Perf.tsx · 42m · 166 tool callsagents-talks · fixes → Agents.tsx · 6m 31s · 12 tool callseggs · fixes → Eggs.tsx · 0m 32s · 6 tool callsshell · fixes → styles.css · 24m · 73 tool callsverifier · 15m · 78 tool callseggs · fixes → Eggs.tsx · 1m 02s · 7 tool callsdesign review · round 2 · 1h 00m · 270 tool callsrecruiter review · round 2 · 24m · 108 tool callshonesty review · round 2 · 18m · 105 tool callsa11y review · round 2 · 49m · 172 tool callsinteractions review · round 2 · 1h 42m · 137 tool callsperfcode review · round 2 · 48m · 143 tool callsverifier · round 2 · 8m 26s · 47 tool callsverifier · round 2 · 12m · 45 tool callsverifier · round 2 · 19m · 56 tool callsverifier · round 2 · 28m · 91 tool callsverifier · round 2 · 21m · 91 tool callsagents-talks · fixes → Agents.tsx · 1m 36s · 8 tool callseggs · fixes → Eggs.tsx · 1m 49s · 9 tool callsshell · fixes → styles.css · 13m · 29 tool callsverifier · round 2 · 16m · 56 tool callsshell · fixes → styles.css · 36m · 139 tool callsperf · fixes → Perf.tsx · 17m · 69 tool callswork · fixes → Work.tsx · 18m · 56 tool callsagents-talks · fixes → Agents.tsx · 7m 13s · 27 tool callseggs · fixes → Eggs.tsx · 5m 40s · 23 tool callsdesign review · round 3 · 33m · 208 tool callsrecruiter review · round 3 · 25m · 129 tool callshonesty review · round 3 · 18m · 126 tool callsa11y review · round 3 · 1h 14m · 222 tool callsinteractions review · round 3 · 1h 34m · 150 tool callsperfcode review · round 3 · 1h 09m · 164 tool callsverifier · round 3 · 6m 32s · 48 tool callsverifier · round 3 · 8m 05s · 43 tool callsagents-talks · fixes → Agents.tsx · 25m · 81 tool callseggs · fixes → Eggs.tsx · 6m 20s · 31 tool callsverifier · round 3 · 12m · 79 tool callsshell · fixes → styles.css · 7m 53s · 28 tool callsperf · fixes → Perf.tsx · 2m 13s · 15 tool callsverifier · round 3 · 18m · 53 tool callsverifier · round 3 · 16m · 86 tool callsshell · fixes → styles.css · 8m 08s · 33 tool callsperf · fixes → Perf.tsx · 9m 42s · 15 tool callswork · fixes → Work.tsx · 3m 56s · 18 tool callsagents-talks · fixes → Agents.tsx · 1m 44s · 11 tool callsverifier · round 3 · 18m · 69 tool callsshell · fixes → styles.css · 6m 57s · 27 tool callswork · fixes → Work.tsx · 7m 25s · 21 tool callsperf · fixes → Perf.tsx · 2m 30s · 12 tool callscontent check · 17m · 71 tool callsvisual check · 17m · 94 tool callsinteract check · 53m · 110 tool callssweep check · 34m · 116 tool callsverifier · 6m 04s · 24 tool callsverifier · 2m 15s · 23 tool callsverifier · 8m 11s · 40 tool callsverifier · 22m · 31 tool callsagents-talks · fixes → Agents.tsx · 2m 20s · 7 tool calls27m idle≈27m idleresearch · 6design · 5build · 4review · 10fixes · 5fixes · 1fixes · 6review · 8fixes · 3review · 12fixes · 5fixes · 4fixes · 4review · 12fixes · 3review · 8fixes · 1@personal-page

A braid of the session that built the first version of this page. One root thread, @personal-page, fans out to 97 sub-agents across research, design, build, review; each strand's length is its real duration and its thickness its tool calls a minute. The table below lists every strand.

08:49:46verifier → findings · 31 tool calls97 sub-agents · 7,900 tool calls · 11h 00m wall clock
UTC · Oct 13–14, 2026
Replay of the agent session that built the first version of this page

Researched, designed, built and reviewed by one agent thread that fanned out to 97 sub-agents: 7,900 tool calls and 34h 05m of agent time, folded into 11h 00m of wall clock. I set the bar in one brief and a follow-up; they did the legwork.

Every change since, this sentence included, went the same way: 4,996 more tool calls across 14 threads.

// scripts/replay.ts reads the session's transcript metadata (labels, timestamps, tool-call counts) into a snapshot taken 2026-10-14 08:49 UTC. It reads message text only to tell mine from automated check-ins, and stores none of it.

Every strand, as a table
strandphaseUTClengthtool callshanded back
@personal-pageroot21:49:19–08:49:4611h 00m438this page
perf-case-studiesresearch21:52:06–22:03:0311m77research-perf.md
talks-mediaresearch21:52:06–22:02:4811m79research-media.md
voice-buzzresearch21:52:06–22:11:3720m85research-voice.md
brand-localresearch21:52:06–22:02:0910m71research-brand.md
stats-apisresearch21:52:06–21:57:004m 54s33research-stats.md
tech-stackresearch21:52:06–22:06:0314m75research-stack.md
storydesign22:14:37–22:22:277m 50s16design-story.md
delightdesign22:14:37–22:24:239m 46s28design-delight.md
visualdesign22:14:37–22:30:3416m71design-visual.md
datavizdesign22:14:37–22:28:5514m31design-dataviz.md
synthesisdesign22:30:35–22:40:5610m22concept.md
workbuild22:54:50–23:32:0437m137Work.tsx
perfbuild22:55:08–23:22:4728m104Perf.tsx
agents-talksbuild22:55:26–23:22:0227m122Agents.tsx
eggsbuild22:55:47–23:19:2624m129Eggs.tsx
design reviewreview23:38:14–00:18:3440m219findings
recruiter reviewreview23:38:15–23:56:1618m95findings
honesty reviewreview23:38:15–23:56:3118m97findings
a11y reviewreview23:38:15–00:13:4335m180findings
interactions reviewreview23:38:15–00:30:2952m133stopped, no result
perfcode reviewreview23:38:15–00:30:5353m72stopped, no result
verifierreview23:56:16–00:16:4120m75findings
verifierreview23:56:31–00:08:0212m78findings
verifierreview00:13:44–00:30:2117m74stopped, no result
verifierreview00:18:34–00:30:1812m69stopped, no result
interactions reviewreview00:57:28–02:10:461h 13m138findings
verifierreview00:57:28–01:26:0629m134findings
perfcode reviewreview00:57:29–01:42:1145m136findings
verifierreview00:57:29–01:08:2811m80findings
verifierreview00:57:29–01:13:5116m84findings
verifierreview00:57:29–01:15:0018m99findings
work · fixesbuild00:59:21–01:03:394m 19s21Work.tsx
perf · fixesbuild00:59:25–01:05:496m 24s43Perf.tsx
agents-talks · fixesbuild00:59:30–01:07:468m 16s47Agents.tsx
eggs · fixesbuild00:59:35–01:01:311m 57s16Eggs.tsx
shell · fixesbuild01:00:01–01:32:5933m127styles.css
eggs · fixesbuild01:38:16–01:44:176m 01s33Eggs.tsx
verifierreview01:42:11–02:02:0420m72findings
work · fixesbuild02:09:40–02:33:4524m52Work.tsx
perf · fixesbuild02:09:45–02:51:3342m166Perf.tsx
agents-talks · fixesbuild02:09:48–02:16:196m 31s12Agents.tsx
eggs · fixesbuild02:09:51–02:10:230m 32s6Eggs.tsx
shell · fixesbuild02:09:56–02:33:3224m73styles.css
verifierreview02:10:46–02:25:4115m78findings
eggs · fixesbuild02:26:15–02:27:181m 02s7Eggs.tsx
design review · round 2review02:53:28–03:53:061h 00m270findings
recruiter review · round 2review02:53:29–03:17:0824m108findings
honesty review · round 2review02:53:29–03:11:5218m105findings
a11y review · round 2review02:53:29–03:42:4149m172findings
interactions review · round 2review02:53:29–04:35:191h 42m137findings
perfcode review · round 2review02:53:29–03:41:5748m143findings
verifier · round 2review03:11:52–03:20:188m 26s47findings
verifier · round 2review03:17:08–03:28:5112m45findings
verifier · round 2review03:41:57–04:01:0719m56findings
verifier · round 2review03:42:41–04:10:1328m91findings
verifier · round 2review03:53:06–04:13:5121m91findings
agents-talks · fixesbuild03:54:38–03:56:141m 36s8Agents.tsx
eggs · fixesbuild03:54:43–03:56:321m 49s9Eggs.tsx
shell · fixesbuild03:54:51–04:07:5113m29styles.css
verifier · round 2review04:35:19–04:51:1116m56findings
shell · fixesbuild04:52:07–05:28:3436m139styles.css
perf · fixesbuild04:52:10–05:08:4617m69Perf.tsx
work · fixesbuild04:52:13–05:10:2518m56Work.tsx
agents-talks · fixesbuild04:52:17–04:59:307m 13s27Agents.tsx
eggs · fixesbuild04:52:19–04:57:595m 40s23Eggs.tsx
design review · round 3review05:30:44–06:03:3933m208findings
recruiter review · round 3review05:30:46–05:56:0325m129findings
honesty review · round 3review05:30:46–05:48:4118m126findings
a11y review · round 3review05:30:46–06:44:401h 14m222findings
interactions review · round 3review05:30:46–07:04:301h 34m150findings
perfcode review · round 3review05:30:46–06:40:081h 09m164findings
verifier · round 3review05:48:41–05:55:136m 32s48findings
verifier · round 3review05:56:03–06:04:088m 05s43findings
agents-talks · fixesbuild06:01:58–06:26:5825m81Agents.tsx
eggs · fixesbuild06:02:06–06:08:256m 20s31Eggs.tsx
verifier · round 3review06:03:39–06:15:2412m79findings
shell · fixesbuild06:27:27–06:35:197m 53s28styles.css
perf · fixesbuild06:27:29–06:29:422m 13s15Perf.tsx
verifier · round 3review06:40:08–06:58:0018m53findings
verifier · round 3review06:44:40–07:00:2516m86findings
shell · fixesbuild07:02:16–07:10:248m 08s33styles.css
perf · fixesbuild07:02:22–07:12:049m 42s15Perf.tsx
work · fixesbuild07:02:27–07:06:233m 56s18Work.tsx
agents-talks · fixesbuild07:02:31–07:04:161m 44s11Agents.tsx
verifier · round 3review07:04:30–07:22:5818m69findings
shell · fixesbuild07:23:15–07:30:126m 57s27styles.css
work · fixesbuild07:23:20–07:30:447m 25s21Work.tsx
perf · fixesbuild07:23:22–07:25:522m 30s12Perf.tsx
content checkreview07:32:47–07:49:2917m71findings
visual checkreview07:32:48–07:50:1317m94findings
interact checkreview07:32:48–08:26:1753m110findings
sweep checkreview07:32:48–08:06:3634m116findings
verifierreview07:49:29–07:55:346m 04s24findings
verifierreview07:50:13–07:52:282m 15s23findings
verifierreview08:06:36–08:14:478m 11s40findings
verifierreview08:26:17–08:47:5022m31findings
agents-talks · fixesbuild08:34:46–08:37:062m 20s7Agents.tsx
04 // talks

Talks

ArkType: Bringing TypeScript to Runtime

TypeScript Congress 2023

How the type-level parser works, top-down to shift-reduce, and what abusing the type system buys you at runtime.

05 // about

Outside the type system

type type loves = "the Mets" | "T1" | "birds" | "my dog, cat and tortoise" | "bow ties" | "my wife's vegan cooking"Adapted from "Predictably, David loves parsers and types, but also bow ties and his wife's vegan cooking." — my speaker bio, 2023computed by the compiler at buildTS 6.0.3 = "the Mets" "birds" "my dog, cat and tortoise" "bow ties" "my wife's vegan cooking"

Diehard Mets fan living in Boston, married to the greatest human on earth. On the side I built beanemachine, which tells me who to start tonight in fantasy baseball.

I'm also an amateur bird watcher, which lately means building look4 to do the watching for me: it goes through my backyard camera's footage looking for birds I haven't seen yet.

When quarantine gave me the chance to spend a day arranging a jazz adaptation of my favorite Hamilton song, I did not throw away my shot.

06 // contact

Say hi

I'm looking for my next team. If you're building something hard in TypeScript or AI, I'd love to hear about it.

david@arktype.io