for our React codebase — the same app, but checkable by machines.
pocock · langton · niser · theo
Today · the compiler sees nothing
Invisible until production — and invisible to the agent rewriting this file.
The same function · after
Shape validated, failures typed, retries inherited. One signature reviews the whole behavior.
Delete bug classes · types
A new status becomes a compiler-driven refactor, not a “remember to check” note.
Failures join the contract · errors
Matt Pocock: “the most TypeScript of all TypeScript libraries.”
The program is data · runtime
Ethan Niser: “a tree of effects — then the runtime runs them.”
Composition · TanStack Query stays
Query already made retries sane. The handshake adds a typed domain — and errors the UI must handle.
Why v4 · why now
One API
Schema folded into core. Fewer packages, one style.
Fast checks
v4 targets type-instantiation speed — the old #1 complaint.
Ships today
Kit Langton runs Effect v4 in OpenCode: branded IDs, layers, incremental adoption.
Agent-safe
One canonical surface → agents stop mixing v3/v4 idioms.
“My favorite TypeScript library just got so much better.” — Ben Davis · “batteries-included standard library.” — Matt Pocock
AI writes it · types verify it
tsc --noEmit — the agent's gate
Theo: “We’re not writing the code anymore — we’re reviewing it.”
What the next developer inherits
Docs that can’t rot
Signatures fail CI when stale. The type is the truth, not the wiki.
Architecture as types
UI importing the DB layer is a compile error, not a review note.
On-call by category
Tagged errors group by constructor: expected vs page-worthy.
Refactors that land
Change a type; the compiler lists every broken call site.
No leaked concurrency
Fibers are supervised: no abandoned timers or dangling requests.
Deletion is safe
The graph proves nothing uses a module. The codebase can shrink.
The honest cost · and the evidence
W1–2
TS strict on the JS. Zero rewrites, ratchet on.
W2–4
Effect basics: gen, layers, schemas ≈ 90% of daily use.
Ongoing
AI writes the idiom; humans review intent.
15–40%
fewer defects in large JS→TS migrations
0
swallowed-error paths left to ship
1 line
is the review surface: Effect<A, E, R>
The strongest objections · answered
“The curve will gut velocity.”
→ Two weeks. gen + layers + schemas ≈ the whole daily grammar.
“Strict TS is enough.”
→ Strict TS sees nothing at runtime: rejections, races, unbounded awaits.
“Query already retries.”
→ It stays. Effect types the domain under it and hands the UI real errors.
“AI will outgrow types.”
→ Even perfect generators need a machine-checkable gate.
“We’ll stall in a hybrid.”
→ checkJs makes day one strictly better. We can stop anytime and stay ahead.
The workflow · incremental, stoppable, monotonic
01
Turn on the ratchet
strict + allowJs + checkJs. New untyped code fails CI.
02
Schema the edges
API + forms first: one declaration → validator + types + OpenAPI.
03
Extract services
Wrap payments, webhooks, LLMs with tagged errors.
04
Wire Query
queryFns call Effects; errors reach the UI, exhaustively.
05
Convert on touch
Modules migrate when they change. Delete what dies.
06
Let agents help
Every step is compiler-gated — exactly what AI does best.
One service, one sprint, one team
Done = shipped, zero swallowed errors
The ratchet only tightens
Effect<Codebase, Confidence, Future>