AI Workflow
A few things the compiler can't generate on its own: a clear field label, a friendly error message, a believable sample name. Those have to be written, by a person or these days an AI agent.
So RunTypes splits the work cleanly. The compiler writes the code; the agent fills in the blanks. From your type, the compiler generates a real, committed source file. Every field is already in place and correctly typed, with the spots that need a human touch left blank and marked. The agent just fills those blanks. It can't get the shape wrong, because the compiler built it.
How it works
Three steps, and the compiler does two of them:
1The compiler scaffolds
From your type, gen writes a real source file: one entry per field, correctly typed, with each blank marked @todo. The structure is correct by construction.
2The agent fills the blanks
It can describe any type for context, then writes the labels, messages and sample values into the blanks, clearing each @todo as it goes.
3The compiler checks & keeps in sync
It validates every value against the type, and as the type changes it updates the scaffold: new fields get new blanks, removed ones are flagged, and your edits are preserved.
The compiler never calls an AI model during a build, so builds stay fast and predictable. Filling the blanks is a separate, opt-in step the agent runs on its own. The result is always a reviewable, committed diff you approve like any other change.
Enrich Skill
There's a ready-made agent skill that teaches an AI agent the whole enrichment workflow plus the JSDoc tags it relies on (@rtType, @rtIds, @rtOrphan, @rtOrphanChild and @todo), so it can drive gen, check, update and prune correctly.
Install it into your project's skills folder with a single command:
npx ts-runtypes-skills --claude
npx ts-runtypes-skills --agent
--claude writes the skill into .claude/skills/; --agent writes it into .agent/skills/. Use --dir <path> to install into a custom folder instead.
Once installed, the agent picks the skill up automatically whenever it works on an enrichment task. No extra prompting needed.
What the compiler generates
gen produces an ordinary TypeScript file, committed next to your code and safe to hand-edit. Every field is already there and fully typed. The blanks are marked, so the agent (or you) knows exactly what's left to fill:
// generated by the compiler, the @todo marks what's left to fill in
// @todo: add realistic sample data
export const userMock: MockData<User> = {
name: { pool: [] }, // ← believable names go here
age: { pool: [] }, // ← a realistic range
email: { pool: [] }, // ← real-looking addresses
};
The agent fills the empty pools; the type annotation keeps it honest. When your type gains a field, the compiler adds a new blank for it. When a field changes type, it flags the old value as stale. When a field is removed, it tidies up. You never regenerate by hand, and your filled-in values are never clobbered.
Commands
A small CLI drives the loop, for an agent or for your CI. The same checks also run during your normal build.
| Command | What it does |
|---|---|
describe <file> <Type> | Print a type's shape as context for the agent. |
gen <file> <Type> | Scaffold the source file with the blanks the agent fills. |
gen … --update | Re-sync the file after a type change, keeping your filled-in values. |
gen … --prune | Clean up entries left behind by deleted types or fields. |
check [files] | Validate the filled-in data against your types. Good for CI and pre-commit. |
These map cleanly onto MCP tools, so any agent (Claude Code, Cursor, your own) can drive the whole thing.
FriendlyType<T> / MockData<T> types (checked against your type by your own TypeScript compiler), the createFriendly renderer, and the createMockType({ data }) integration. The CLI and the always-on build diagnostics described here are in active development.Next, the two kinds of data themselves: human-readable labels & errors and real-world mock data.