The new programmers?

Alasdair Allan
12 January 2026

Writing code is a huge bottleneck. Software started out custom-developed within companies for their own use. It only became a mass-produced commodity when demand grew past available supply. However, no matter what vibe coding enthusiasts might argue, large language models (LLMs) are bad at programming. They can build a prototype; but production code is different, and AI-built prototypes don’t scale.

However it’s arguable that programming languges exist to enable the creation of powerful libraries; and a language’s features directly determine what libraries can be built. While many developers think they only really care about libraries, and not core language features, they’re unknowingly benefiting from sophisticated features like first-class functions, meta-programming, and garbage collection through the libraries they use. In the end, different languages are ultimately differentiated by what can and cannot be practically implemented as libraries and frameworks.

So should we look at building a language optimised for AI?

Languages have always co-evolved with their users and tooling. Assembly emerged from hardware constraints. C emerged from operating system needs. Python emerged from productivity needs. If models become the primary users and main authors of the software we build, it would be consistent for languages to adapt to that. So perhaps the real question should be what needs to change to make a language suited for models to use, rather than humans?

The evidence suggests it’s not syntax or even logic in isolation: instead it’s coherence over scale. Models struggle with maintaining invariants across a codebase, understanding the ripple effects of changes, and reasoning about state over time. They’re pattern matchers optimising for local plausibility, not architects holding the entire system in mind. Those token windows will always get you in the end, no matter how big you make them.

So what would a models-first language designed from the ground up look like? What things need to change?

Human languages tolerate ambiguity because humans resolve ambiguity through context. AI often lacks that context, or hallucinates it. A language with no syntactic flexibility, with only one canonical way to express each concept, might produce more reliable output. Reducing ambiguity could reduce failure modes.

While it isn’t their biggest problem, models struggle with reasoning about state. A language that made all state explicit, and all side-effects declared, might play to AI’s strengths rather than its weaknesses. Models are just bad at inferring implicit behaviours, but they’re much better at pattern-matching on explicit structures.

Likewise, if we make it so that our language’s type system and structure radically constrain what’s expressible, the AI has fewer opportunities to be wrong. The code either type-checks against a specification, or it doesn’t compile. The language could even be designed so that verification is a first-class citizen. In a language designed from the ground up for formal verification, a model can generate candidate code, and then an entirely separate system can verify it. You don’t need the model to be right: you just need it to be checkable.

So what would this language look like? If we integrate formal specification, you would have to write both specifications and implementations together, and the language could check consistency. Something like a merger of a normal programming language with TLA+ or Alloy. Every function should declare not just types but contracts: preconditions, postconditions, invariants, effects on external state. The language wouldn’t let you write something without specifying what it’s supposed to do. This is how languages like Dafny and SPARK work.

It might emphasis structure over syntax. The “source code” might not be text at all. It could be a graph structure: essentially an AST without the parsing step. The model could emit structured data directly, eliminating an entire class of syntax errors. Humans would interact through a visualisation of this structure, not through the structure itself.

This all means we can kill off variable names. Naming variables is something we do as humans, to allow us to track meaning through the structure of the code. A model doesn’t need that: structural position and type information could be sufficient. The resulting code would look alien to humans, but might reduce one avenue of confusion for models.

We can also try to constrain the space of valid programs by expanding on the concept of types, so that they can express concepts like “a list of positive integers of length n” or “a string that matches this regular expression”. By doing this, many bugs just become type errors.

Beyond that we could further constrain things by making state changes explicit and managed, perhaps through something like algebraic effects. The model wouldn’t need to track implicit mutation, because there wouldn’t be any to track.

There’s a huge problem here: the lack of training data. With no training data, how does the model use the language you have designed? You’d need to either hand-write an enormous corpus of examples in this new language, which is going to be expensive, defeating the purpose of building a new language in the first place; or alternatively generate synthetic data, which embeds whatever biases and errors the system that generates the data maintains. You end up with a feedback loop problem.

This is where the work already done on Model Context Protocol (MCP) might prove crucial.

The feedback loop problem assumes that models need to learn from examples. But if we look at MCP-style contracts that suggest an alternative, learning from constraints, the model doesn’t need a corpus of code in the new language. Instead, it needs to generate outputs that satisfy contracts, with immediate feedback on success or failure.

This shifts the paradigm from “code generation” toward “program synthesis”: and program synthesis doesn’t require training data in the target language. It requires a specification and a search process.

We could even imagine that a language optimised for AI to use isn’t text at all. Instead it’s a composition of MCP-style tool calls. Each primitive operation in the language is a tool with a schema defining valid inputs and outputs, preconditions and postconditions as part of the contract, and declaration of effects defining what external state it touches.

In this case, programming becomes selecting and composing tools in ways that satisfy the contracts. The model proposes a composition, the contract system validates it, and the model learns from the feedback. The contracts become both the language specification and the verification system. There’s no separate “code” and “tests”: instead, the contracts are executable specifications that constrain what the model can generate.

Contract validation is binary: there is immediate and unambiguous feedback. Code either satisfies the constraints or it doesn’t. This is a cleaner signal than “does this code compile”, because as we all know, the fact that code compiles doesn’t mean that it will do what we expect.

While type systems promise invariance, contracts can can do this in a richer fashion. If each tool call satisfies its contract, and the contracts compose, you get verification of the whole program from verification of parts. Instead of learning what valid code look like from training data, the model learns what satisfies this contract through trial and feedback. This is closer to how humans learn, by trying things and seeing what works.

But that brings us back to who writes the contracts. If humans write them, all we’ve done is to have moved the bottleneck to contract specification, which requires understanding the problem deeply enough to specify it formally. Which is the opposite of how most software gets written. But if instead we rely on a model that writes the contracts, we’ve returned to the original problem.

Beyond that, and perhaps more fundamentally, a contract can only check what it specifies: contracts reduce the space of wrong answers, but don’t eliminate it. They feel like they could be part of the solution, but not a solution in themselves.

You could imagine humans writing high-level specifications in something that resembles TLA+ or a simplified formal language. This is the “what” rather than the “how”.

A model then takes that specification and generates a composition build from a library of verified, contract-constrained operations. Each of these primitives would need to be formally verified, with the contracts defining valid composition.

The model-written composed program can checked against the human-written specification. If it fails, the model gets feedback and tries again. If it passes, the program is correct by construction, at least relative to the specification.

So perhaps what we’re discussing isn’t a language in the traditional sense: it’s a verified component ecosystem with a formal composition system. The “language” is the composition rules, the “programs” are compositions of pre-verified components, and the “compiler” is a contract checker: this is far closer to how contemporary hardware design works than how software development works.

But if we pursue this idea are we just optimising for current limitations, rather than solving the underlying problem? If models can’t reason about state and coherence, building a programming language that makes those things explicit doesn’t teach them to reason. Instead, it offloads the reasoning to the language’s constraints. Then when the next architectural leap happens, if it happens, you’ve built infrastructure around the wrong bottleneck.

Or perhaps the question itself is wrong. Instead of asking what language AI should write code in, maybe we should ask what AI’s role in programming should actually be.

The most successful AI coding tools right now work with humans in human languages. They’re accelerators, not replacements. Using an AI-optimised language implies that the model is the sole author, which may be optimising for a future that isn’t coming, or that shouldn’t come at all. The hard part about writing software is the messy iterative process of figuring out what you actually want: that’s not a problem a new language can solve.

View all postsBack to top