November 12, 2025
Ask a coding model to add authenticated subscription checkout to an application. It can produce a plausible TypeScript handler in seconds:
export async function POST(request: Request) {
const user = await getCurrentUser(request);
if (!user) return new Response("Unauthorized", { status: 401 });
const body = await request.json();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const session = await stripe.checkout.sessions.create({
mode: "subscription",
customer_email: user.email,
line_items: [
{ price: process.env.ANNUAL_PRICE_ID!, quantity: 1 },
],
success_url: `${process.env.APP_URL}/account?checkout=success`,
cancel_url: `${process.env.APP_URL}/pricing`,
});
await db.pendingOrder.create({
data: { userId: user.id, checkoutId: session.id },
});
return Response.json({ url: session.url });
}
It looks reasonable. It may even work in a demo. But the code does not answer the questions that determine whether the feature is correct:
The problem is not that the model failed to type enough TypeScript. The problem is that TypeScript was never required to represent most of those obligations.
So why should TypeScript be the boundary between probabilistic intent and deterministic machinery?
This is the first post in a series built around a deliberately speculative hypothesis: coding models may need a generation language designed for them to write. Existing languages would remain useful execution targets. They would stop being the one canonical representation that has to carry intent, application behavior, external resources, and evidence about whether the result works.
The language is only one layer. The complete proposal is a loop:
That is a large design space. This post makes one narrower claim: human-oriented programming languages are not obviously the right canonical output format for probabilistic programmers. It does not establish that a new syntax is necessary. A restricted TypeScript profile is the baseline a new language has to beat.
Coding models generate Python, TypeScript, Rust, SQL, shell scripts, and YAML for an obvious reason: that is the material we have.
The original Codex paper describes a model fine-tuned on publicly available code from GitHub and evaluates it by asking for Python functions. The training corpus was existing software, the benchmark expected an existing language, and the surrounding toolchain knew how to execute that language. The shortest path from model output to a useful artifact ran through conventional source code.
That remains an excellent bootstrap strategy. TypeScript has a compiler, an editor ecosystem, libraries for nearly every web API, millions of examples, and engineers who know how to debug it. The TypeScript handbook describes its goal plainly: TypeScript is a static type checker for JavaScript programs. It is a good human interface to the JavaScript ecosystem.
But an explanation of how we arrived somewhere is not an argument that it is the right endpoint.
We should separate two questions:
Today the answer to the first question dominates the second. The model emits a human-oriented language because compilers and runtimes already accept it. A different architecture could preserve those ecosystems while moving the probabilistic boundary upward.
The proposal is not to throw away TypeScript. It is to compile to TypeScript.
A new language begins with almost nothing.
There is no corpus of correct programs. There are no mature compilers, packages, debuggers, formatters, migration tools, deployment guides, Stack Overflow answers, or engineers with ten years of production scars. Meanwhile, coding models are already fluent in TypeScript and Python, and those languages connect directly to enormous ecosystems.
This is not a temporary inconvenience to wave away. It may kill the proposal.
The strongest competing design is restricted TypeScript:
That approach keeps familiar syntax, existing tooling, and most of the training corpus. It may capture nearly all the value of a new semantic language at a fraction of the cost.
There are also real advantages to a new target. It can make canonical forms structural instead of conventional. It can treat application code, external resources, and runtime experiments as parts of one typed graph. It can avoid inheriting compatibility constraints from JavaScript. And if a deterministic compiler can generate executable backends and verify them, successful programs and repair trajectories can gradually produce a grounded synthetic corpus.
But those are possible advantages, not results. "We can generate training data later" is not an answer to the bootstrapping problem. The first version still has to work with models trained mostly on other languages.
A conventional compiler translates one formal representation into another. A coding model does something stranger. It translates an underspecified human request into a formal artifact, while guessing at every fact the request omitted.
The useful part of the compiler analogy looks like this:
ambiguous human intent
→ probabilistic front end
→ canonical semantic program
→ deterministic backends
The model is the probabilistic front end. It interprets intent, chooses an implementation, and produces a candidate program. Everything after that boundary should be as deterministic as practical: parsing, type checking, effect checking, planning, code generation, resource reconciliation, test execution, and diagnostic production.
The analogy is imperfect in three important ways.
First, human intent is not a source language. It is incomplete, contradictory, and full of examples that do not cover the whole behavior. The model cannot merely parse it.
Second, generation is stochastic. The same request can produce several programs, all syntactically valid and all behaviorally different.
Third, programming is not a one-way translation. A programmer runs the system, observes it, changes inputs, reads errors, forms a hypothesis, and edits the program. A useful model-facing substrate must eventually support that loop. We will get there later in the series.
Even with those qualifications, the boundary matters. Once the model has committed to a formal semantic program, deterministic machinery can reject missing obligations without trying to infer them from framework conventions.
TypeScript gives a programmer many legitimate ways to express the same idea.
An operation can report failure by throwing an exception, returning a tagged result, rejecting a promise, calling an error callback, or emitting an event. Authentication can appear in middleware, a decorator, a framework hook, an inline conditional, or a helper several calls away. Configuration can arrive through a global environment variable, an imported singleton, a dependency-injection container, a function argument, or a generated module.
This flexibility is useful. Different programs have different requirements, and people need escape hatches. The claim is not that expressive languages are bad.
The claim is that a probabilistic generator pays for every unnecessary choice.
If a task has ten locally plausible implementation patterns, the model must choose one, reproduce its conventions consistently, and make it compose with choices elsewhere in the repository. The compiler then sees the chosen mechanism, not necessarily the obligation behind it. A middleware call might mean "requires an authenticated customer," but only if the compiler understands that framework, that middleware, its placement in the routing tree, and the ways it can be bypassed.
This is a search-space argument, not yet an empirical result. A model may handle surface variety so well that canonicalization buys little. It may even benefit from redundant representations in its training data. That is why the idea needs a benchmark rather than a manifesto.
Still, the design opportunity is clear: remove choices that do not carry product meaning, and make recurring obligations explicit.
There is already evidence for the modest version of this claim. PICARD constrains model decoding to reject inadmissible SQL tokens and improved text-to-SQL results in its evaluation. More recently, type-constrained code generation applied type information during decoding and reported fewer compilation errors across generation, translation, and repair tasks.
Those results do not prove that a new language helps. They demonstrate that deterministic constraints can remove invalid regions of a model's output space. Syntax and type correctness are also much weaker than application correctness. A perfectly typed payment handler can still charge twice.
What would the checkout operation look like if its important obligations had canonical forms?
The syntax below is provisional. Read it as a sketch of the information available to the toolchain, not a language proposal ready for implementation.
operation begin_checkout(
request: BeginCheckout
) -> CheckoutRedirect
requires customers.authenticated(request.actor)
effects [
commerce.write(PendingOrder),
billing.create_checkout
]
idempotent_by request.id
{
checkout = billing.checkout.create {
purchaser = request.actor
product = AnnualPlan
success_url = web.route("/account?checkout=success")
cancel_url = web.route("/pricing")
}
commerce.PendingOrder.insert {
user = request.actor.id
checkout = checkout.id
}
return checkout.redirect
}
This code does not magically solve checkout. It does something more modest and useful: it exposes facts to deterministic tooling.
requires gives the checker an authorization obligation. effects says that the operation mutates application state and calls an external billing capability. idempotent_by gives retries an identity that can be checked and lowered. AnnualPlan is a semantic resource rather than an arbitrary environment-variable lookup. The two routes are references the planner can verify against the application graph.
A compiler could use this information to:
AnnualPlan is bound in preview and production.begin_checkout, even when the observed failure occurs in generated code or an external provider.Whether a compiler would do those things depends on the language, its domain extensions, and the adapter contracts. The syntax alone guarantees nothing. A declaration such as idempotent_by request.id is useful only if lowerings preserve it and the runtime can observe violations.
That distinction is central to this proposal. High-level declarations are not documentation. They are inputs to deterministic checks and transformations.
Calling this an "AI language" invites the wrong analogy. It sounds like an assembly language for models: terse tokens, numeric opcodes, or a serialization format optimized to save context-window space.
That is backwards. Models do not need more incidental detail. They need less.
The target should sit closer to intent than TypeScript does. It should represent the parts of a system that remain stable when frameworks change: contracts, state transitions, resources, effects, capabilities, failure modes, deployment requirements, experiments, and observable outcomes. A backend can then lower those semantics into verbose framework code.
Compiler infrastructure already benefits from preserving useful abstractions at more than one level. The MLIR rationale describes an intermediate representation that can retain domain-specific structure and lower it progressively toward target-specific code. The point of the comparison is architectural, not evidentiary. MLIR does not show that models need a new source language. It shows why "compile to something higher-level" is not a contradiction.
The model-facing program would occupy an unusual position. It is a source language from the model's perspective and an intermediate representation from the backend compiler's perspective. Humans still need to read it, review it, and sometimes edit it, but human convenience is no longer the only design objective.
Canonical does not mean inflexible. Unusual behavior will still need foreign interfaces and escape hatches. The question is whether common semantic obligations should have one obvious representation, leaving variation for the places where it actually matters.
The experiment should compare three serious alternatives:
The third hypothesis is the subject of this series. The second is the one I currently find hardest to dismiss.
A fair comparison must hold the model, task, runtime access, and evaluation budget constant. It should not give the new language a structured simulator while forcing the TypeScript baseline to debug from raw terminal text. It should not count compilation as success. And it should not benchmark isolated functions if the proposed advantage is cross-layer consistency.
The task suite should include features such as the checkout flow above, where correctness crosses UI state, authorization, database writes, provider configuration, asynchronous events, secrets, and deployment. Existing benchmarks such as SWE-bench demonstrate the value of executable repository-level evaluation. This hypothesis needs an analogous benchmark with external resources and end-to-end invariants, not merely a new set of docstring-to-function prompts.
Useful measurements would include:
The result could be that syntax barely matters. Runtime tools and structured diagnostics may dominate. Or restricted TypeScript may equal the new language on every meaningful metric. If so, do not build the language.
Even a successful generation language would leave most of programming intact.
It would not infer missing product decisions. It would not make domain extensions correct. It would not guarantee that a provider behaves as documented. It would not decide who is allowed to approve a production payment mutation. It would not turn a screenshot into an evaluation. It would not keep project knowledge current. It would not replace the need to run the system and manipulate the world around it.
Those omissions are not peripheral. They are why the master architecture is a loop rather than a compiler diagram.
But the representation at the probabilistic boundary still matters. Today a model repeatedly reconstructs semantic obligations through framework conventions, library calls, configuration strings, and files spread across a repository. A canonical target could make those obligations explicit before deterministic machinery takes over.
The question is not whether a model can write TypeScript. It can. The question is why TypeScript should be the boundary between probabilistic intent and deterministic machinery.