I caught an agent inventing a customerId: number field on a tool that has always taken customer_id: string. It compiled in the model's head. It exploded in production's face.
That is when I stopped treating TypeScript as "the language the UI happens to use" and started treating it as the contract layer for anything an agent is allowed to touch.
Agents generate API surface all day
Humans write a handful of endpoints a week and argue about names in PR review.
Agents propose tool calls constantly: search, create, update, deploy, comment, refund. Every call is a tiny API. If the inputs are vibes, you get vibes-shaped outages.
Zod (or an equivalent runtime schema) is how you make the model fail closed:
The schema is not bureaucracy. It is the fence at the cliff edge.
Why TypeScript specifically
Because the same types can serve three audiences without a translation layer:
That triple duty is rare. OpenAPI can do some of it. JSON Schema can do some of it. In a TS shop shipping Eve tools, MCP servers, and Next.js route handlers, Zod-in-TypeScript is the boring centre of the Venn diagram.
I favour boring centres. They survive reorgs.
Shared schemas beat duplicated truth
Pattern I keep pushing:
One CreateIssueInput. Three consumers. When the agent invents a field, it invents it against a wall that already exists in git.
If your UI form accepts summary as required and your agent tool secretly makes it optional "for flexibility", you do not have flexibility. You have drift.
Generated surface still needs handwritten edges
Agents will happily generate tool wrappers. Let them draft. Do not let them own the schema without review.
Rules of thumb that have saved us pain:
The mischievous bit
Once you do this well, you will notice something awkward: a lot of "prompt engineering" was compensating for missing types.
Tighten the contract and the prompts get shorter. The model spends fewer tokens apologising for malformed JSON and more tokens doing the job.
Thoughts
If agents are going to generate your API surface all day, TypeScript is not a preference. It is the seatbelt.
&w=3840&q=75)


