AI has taken over a large part of programming. Its users fall into two groups. Software engineers review the code and steer the AI technically. People without a technical background hand all of the technical work to the AI.

In the second case, there is no engineer in the loop, and the problems hide behind a good-looking interface: logic errors, security holes, data loss, growing complexity, and fixes that occasionally break something else. Of course, you can ask the AI to fix these problems. But making the software fit for production, keeping it maintainable, and ensuring its security still requires human expertise. Stronger models do not remove these issues. They only show up later, as projects grow, since one or a few architectural mistakes are enough to spoil an entire project.

In this article, I argue that the lever is the programming language itself, and I describe the language we designed for this purpose.

Where AI errors come from

The first cause is the model itself. A language model has hundreds of billions, if not trillions, of parameters. They are initialized randomly and trained by gradient descent, so the remaining error never reaches zero. A further weakness of the transformer architecture is that the model writes token by token, and small errors accumulate along the way. Reasoning, which runs an expensive chain of thought ahead of the answer, alleviates this. Agentic architectures, where the AI gets real feedback from tools and can hill-climb toward a solution, have improved the situation substantially. But by nature, the number of bugs will never be zero.

Take a line that stores a password:

user.password = ...

In the illustration from my launch talk, the model may continue with argon2(input), a proper salted password hash. This is what you want, but it often does not happen. Sometimes the model writes a weaker hash(input), and now and then it writes input, which stores the password in plain text. All three look plausible, and the programming language accepts all of them, but only the first is right. In a business application with thousands of such decisions, it is practically certain that some of them are wrong.

The second cause, and I believe the stronger one, is the training data. The model learns from the whole internet, including GitHub and Stack Overflow, with their many half-baked solutions, partly correct explanations, bugs, and bad patterns. A growing amount of AI-generated slop adds to them. Much of the code is outdated, written for libraries and APIs that are deprecated, insecure, or no longer work. The data is also unbalanced: there is far more Python than Rust, so for languages with little data, the model occasionally fills the gaps by interpolation.

The third cause is the technology the AI writes for, and it deserves a closer look.

The ghosts of the 1970s and 1990s

SQL dates from 1974, HTML from 1993, and JavaScript and PHP from 1995, and Python, C++, and Java are no better. The mainstream programming languages were built for humans, and they all still carry the ghosts of that time. They are low-level and mostly concerned with main memory, with tweaking memory cells through variables and arrays. Persistence, security, data privacy, networking, user interfaces, and many architectural decisions are outside the scope of their design. As a consequence, these concerns only come as additional, second-class libraries and frameworks, which are often error-prone, fast-changing, and complex. The most you get natively from the language, and this is already highly valuable, is memory safety through a proper garbage collector in a managed runtime. As a side note, even the younger Rust allows unsafe code, and safe Rust can still leak memory through reference-count cycles.

Databases and object-relational mappers are second-class concepts. So is concurrency: the language is prone to race conditions, deadlocks, and starvation, and programmers have to make this insecure ground safe and correct explicitly, with synchronization and transactions. Distribution is no better. Keeping several frontends in sync with the same backend data is a painful design problem that programmers solve every time anew, or with non-trivial frameworks.

Security is the clearest example. None of the mainstream languages has application security as a built-in concept. Programmers add frameworks and follow numerous, continuously changing best practices to secure an application. The application is therefore insecure by default and has to be hardened by hand. That is hard for humans, and even harder for today’s AI without an experienced engineer guiding it.

Decades of clutter

On top of that, the languages have collected the waste of decades: bluntly wrong decisions, bloat, and syntactic sugar. Their designers bitterly regret many of these decisions, but they cannot change them without breaking compatibility and causing an uproar in the community. Constructs that seem friendly, because they ease or shorten coding, often turn out to be “syntactic rat poison,” as Tony Hoare called it in his paper “Hints on Programming Language Design” (1973), a twist on Peter Landin’s term “syntactic sugar.”

The examples are everywhere: senseless tricks like x++, horrible notations like x === y, long async/await chains, and pseudo-ergonomics like implicit conversions, which are foot-guns. Most languages also offer several features for achieving the same thing, or concepts that combine disjoint purposes in one, such as class inheritance or object references. All of this was meant to make programming more comfortable for humans, although it is questionable whether it helps more than it harms. AI does not need these ergonomics, and every extra way to write the same thing is another opportunity for a mistake.

A language for AI

Changing the programming language used to mean convincing a community of human programmers. This obstacle is disappearing. Human engineers write less and less code, and they have little appetite for reviewing the masses of AI-generated code. Authorship has changed completely, and the programming language is becoming a tool for the AI rather than for humans. As a consequence, we can change a language for AI at any time, without community consent, as long as we provide a proper migration for existing programs.

A programming language for AI has different goals. It is tailored to what AI is good at, such as broad knowledge and interpreting intent, and designed to prevent the errors AI typically makes, such as inconsistencies and random gaps. It aims for simplicity, abstraction, clarity, and rigor. It offers only a small set of powerful, high-level abstractions, and they are all orthogonal: every combination of them is meaningful.

For this purpose, I designed AI Language (AIL), the language at the core of Lightscale AI. The idea is to raise all the concerns above, and many more, into the language: persistence, security, data privacy, transactions, synchronization across distributed components, and the user interface. At the same time, AIL cleans out the waste of the decades. It is full-fledged and flexible, but it works at a high level of abstraction. Its abstractions rule out whole classes of errors, and the programs stay small.

Security and data privacy are on and strict by default. If the program says nothing, nothing is allowed. Every access has to be granted explicitly, and it is checked again where the data is used. Data counts as sensitive unless it is declared non-sensitive. This is very rigid and no fun for a human programmer. The AI does not mind, and it profits from such rigorous rules.

On the screen: a prompt goes in, a language model writes AIL, and the compiler checks it and generates software that is ready to run.
The new stack: the AI writes a program in AIL, and the compiler checks it and builds the software.

The second half of the idea is the compiler. The user describes what they need, a language model writes the AIL program, and our compiler turns it into the application. The compiler checks the AIL program statically and challenges the AI’s coding decisions in pedantic detail. When it finds problems, it sends the AI precise messages and helps it correct the program. Persistence, transactions, and authentication are solved once, in the runtime, instead of being rewritten by the AI in every application.

What the language covers

In AIL, the language is also the database. Its runtime implements orthogonal persistence: the records a program declares simply persist, without an explicit database, an object-relational mapper, or SQL in the program. A company with its employees is a record that refers to other records, and the runtime stores them in the database the application runs on. When the data model changes, the compiler checks the migration. A static dataflow analysis rules out any unintended loss or reduction of information.

The other concepts follow the same idea:

  • A security model covers sign-in, role-based access control, and data privacy. Nothing is allowed unless granted, data is sensitive unless declared otherwise, and the compiler checks every grant.
  • Workflows and transactions come with checked invariants and strict types.
  • A new, fully featured user interface framework keeps every application consistent. It is as expressive as HTML and CSS, only radically cleaned up and compressed.
  • Integrations connect external databases, CRMs, email, AI services, search, maps, and files, with statically cross-checked type compatibility and well-defined mechanisms for synchronization, error handling, and audit trails.

The compiler also questions the AI about its choices. If the AI makes data public that does not need to be, for example a field called “notes,” the compiler sends it back. If a change would delete stored records, the compiler first challenges the AI, and if the AI keeps the change, the owner is asked, for example “Is it OK to delete the past events?”

What it changes

Compared to AI writing conventional code, this approach offers these benefits:

  • Safety: The compiler checks every program and challenges the AI’s decisions before any application code exists. Security and data privacy are strict by default, so a forgotten rule denies access instead of opening it.
  • Determinism: The AI is stochastic, but the step from AIL to application code is not. The same AIL program always produces the same application. Moreover, many architecturally critical aspects are guaranteed to be correct, because they are implemented only in the compiler, and the AI does not write a single byte of them.
  • Efficiency: Thanks to its higher abstractions, an AIL program is on average ten times shorter than the full code, or more. At the same time, we work with mid-tier models such as Gemini Flash, gpt-oss, Kimi, DeepSeek, or Mistral models, with the lowest possible reasoning effort. Inference becomes around a hundred times cheaper.
  • Flexibility: Code generation is a backend of the compiler, and it targets several standard tech stacks and databases today. More stacks can be added, and companies could even implement their own tech stacks and architectural code styles in the generator backend.

In the longer term, we also aim to post-train our own model, so that it is even faster and needs fewer rounds of compiler fixes.

AI is taking over software engineering, and engineers increasingly spend their time prompting. AI is also inherently unreliable, so bugs, security holes, and technical debt grow with it. I think the answer is a new tech stack built around a programming language for AI.