Nick Hoff

Build the Dumbest AI Language That Could Possibly Work

June 3, 2026

Six essays of language design can easily become an excuse not to implement anything. The fastest way to improve this idea is to build a version crude enough to fail.

The first prototype should be designed to disprove the need for a new language as cheaply as possible. It needs one complete vertical slice, matched conventional baselines, a protected evaluation, and enough ablations to identify which component produced any improvement.

It does not need a universal compiler platform.

Minimum vertical slice for falsifying the language hypothesisA narrow stack runs from a tiny grammar through a typed graph, effect checker, TypeScript lowering, local Storefront runtime, browser scenario, structured diagnostic, and benchmark result. Real providers, cloud deployment, extra backends, and more domains sit in a grayed-out future ring.NOT REQUIRED FOR FIRST FALSIFICATIONreal Clerkreal Stripecloud deploymentPythonWasmextra domainsTiny grammarTyped semantic graphEffect checkerTypeScript loweringLocal Storefront runtimeBrowser scenarioStructured diagnosticBenchmark resultOne complete loop is enough to produce a useful negative result.
The first implementation needs one complete loop, not broad feature coverage.

The previous posts proposed a semantic language, provider reconciliation, an experiment runtime, structured evidence, and protected evaluation. This post turns that architecture into a falsifiable engineering plan.

Start with one local Storefront

The minimum vertical slice implements only what authenticated checkout requires.

The core language gets records, variants, named operations, preconditions, postconditions, capabilities, effects, resources, state updates, typed failures, idempotency metadata, event handlers, scenarios, observations, and assertions.

The domain layer gets minimal HTTP, relational storage, identity, and payment interfaces.

The adapters are deliberately fake at first:

Real Clerk, real Stripe, cloud deployment, Python, WebAssembly, plugin frameworks, and additional domains are not required to answer the first question. Add real sandbox adapters only after the semantic path works locally.

The fake payment provider is not a toy if it can reproduce the obligations under test: idempotent checkout, signed events, delayed delivery, duplicate delivery, decline, and eventual entitlement. It is a controlled instrument.

The strongest objection: the benchmark can be rigged

Any favorable result can be manufactured by giving PromptIR a better runtime, better diagnostics, and task-specific primitives while giving TypeScript a terminal and a test suite.

If PromptIR receives billing.create_checkout with idempotency and a fake provider built in, while the baseline has to discover an SDK from documentation, the result says nothing about syntax. It measures tool allocation.

The benchmark must separate at least five variables:

That requires ablations, not one winner-take-all comparison.

Benchmark ablation gridOrdinary TypeScript, restricted TypeScript, and PromptIR are compared while sharing the same experiment runtime. Ablations vary representation, diagnostics, effect enforcement, and canonical form so gains are not automatically attributed to syntax.CONDITIONRepresentationDiagnosticsRuntimeEffectsCanonicalOrdinary TypeScriptoptionalsharedlibrarynoRestricted TypeScriptcanonical subsetstructuredsharedrulesyesPromptIRnew syntaxnativesharedcompileryesAdd and remove one feature at a time. Do not compare a language plus a laboratory with code plus a terminal.
A fair comparison must isolate the value of the language from the value of better tools.

Both language conditions should use the same provider simulators, browser runtime, task intent, model, token budget, and protected evaluator. Restricted TypeScript should be allowed explicit capability wrappers, canonical project rules, and structured annotations. PromptIR must earn the additional cost of parsing and lowering.

Useful ablations include PromptIR with weak diagnostics, restricted TypeScript with full structured diagnostics, both languages without the experiment runtime, and both with it. If the runtime supplies all the gain, keep the runtime.

Build the baselines first

The three primary conditions are:

  1. Ordinary TypeScript. Normal libraries, repository conventions, tests, and agent tooling.
  2. Restricted TypeScript. Explicit dependencies, one error model, capability wrappers, canonical module patterns, effect annotations, and import restrictions.
  3. PromptIR. Canonical semantic source with deterministic TypeScript lowering.

Building the conventional baselines first has two advantages. It produces tasks and fixtures before the new language can be tailored to them, and it makes the burden of restricted TypeScript concrete. Perhaps a small ESLint plugin and runtime library already solve the problem.

The baseline implementations should not be intentionally ugly. A serious competitor gets the best design we can give it under its stated constraints.

Keep the compiler boring

The first compiler needs:

That is already enough work. The parser should use a conventional generator or hand-written recursive descent. The graph can live in memory and serialize to JSON. The TypeScript backend can prioritize readability over optimization. There is no need for incremental compilation, distributed builds, a general optimizer, or an extension marketplace.

Program       := Use* Declaration*
Declaration   := TypeDecl
               | ResourceDecl
               | CapabilityDecl
               | OperationDecl
               | EventHandler
               | ScenarioDecl

OperationDecl := "operation" Name Signature
                 Requires? Effects? Idempotency?
                 Ensures? Block

Requires      := "requires" "[" Predicate* "]"
Effects       := "effects" "[" Effect* "]"
Idempotency   := "idempotent_by" Expression
Ensures       := "ensures" Predicate

The grammar is intentionally unimpressive. The hypothesis concerns semantics and the probabilistic boundary, not punctuation.

Use tasks that cross layers

Isolated algorithm problems are the wrong benchmark. The proposed advantage is making obligations consistent across application code, effects, runtime state, and environment bindings.

The first task suite should include:

Include greenfield generation, feature addition, code repair, and environment repair. Each task begins from the same repository state in every condition and ends at the same protected assertions.

Repository-level executable benchmarks such as SWE-bench are a better precedent than docstring completion, but this suite needs controlled external systems and cross-layer invariants. The benchmark should publish task fixtures, evaluator versions, model settings, raw trajectories, and failures.

Measure the loop, not just the final patch

The primary metric is end-to-end protected-evaluation pass rate. It needs supporting measurements:

Secondary costs matter too: human review time, generated backend size, compiler complexity, adapter cost, and the fraction of diagnostics that support a legal automatic repair.

A language that improves pass rate by two points while requiring a year of adapter work may be a bad result. A runtime that cuts failure-localization time in half across all three conditions may be the real product.

Generate programs and known failures

A new language has a cold-start corpus problem. The compiler can help bootstrap, but only if generated examples are filtered by independent checks.

Sources of candidate data include:

This is established compiler-testing territory, not magic synthetic data. QuickCheck popularized generating test cases from executable properties. Csmith generated randomized C programs and used differential testing to find compiler bugs. A PromptIR generator can produce typed programs, lower them, execute scenarios, and retain only artifacts supported by compiler or runtime evidence.

Verified synthetic data flywheelGrammar and typed generators produce candidate programs that compile and execute. Faults are injected and repaired. An independent deterministic verification filter retains only grounded trajectories, which train models that produce better candidates.Grammar + generatorsCandidate programsCompile + executeMutate + repairVerified trajectoriesTrain modelsBetter candidatesDeterministic verificationcompiler · runtime · protected evaluatorSynthetic volume is useful only after independent evidence filters it.
Synthetic volume is useful only when an independent compiler, runtime, or evaluator filters it.

The useful training record is not only a source/target pair:

intent
  → initial program
  → compiler result
  → execution
  → observation
  → hypothesis
  → experiment
  → failed patch
  → successful patch
  → verification evidence

That trajectory teaches how to recover, which is most of what an autonomous programmer does after its first generation fails.

Mutate the semantics deliberately

The mutation library should inject faults the system claims to detect:

mutation RemoveDeclaredEffect {
  input = valid_operation

  select effect from input.observed_effects
  transform delete(input.declared_effects, effect)

  expect diagnostic {
    code = EFFECT_NOT_DECLARED
    operation = input.identity
    observed_effect = effect
  }
}

Each mutation has an expected compile-time diagnostic or protected runtime failure. Mutation testing is useful here because the fault is known. If the system reports success, either the evaluator is weak or the claimed semantic guarantee is false.

Do not retain only successful repairs. Failed patches, rejected hypotheses, and unlocalized faults expose where the feedback protocol is insufficient.

Test a second domain early

After the Storefront slice works, resist adding more web features. Implement one narrow non-web task.

A spreadsheet repair task is a strong candidate. It stresses file ingestion, uncertain schemas, tabular transformation, formula provenance, rendered verification, and a human projection that is not ordinary source code. A small ML experiment with checkpoints and plots is another option.

The goal is not feature parity. It is to determine whether most of the core and experiment protocol survive. If the second domain needs a different resource model, observation model, and evaluator architecture, "universal core" may be an empty label.

Decide in advance what failure means

The project should continue only if the results justify its complexity.

Evidence in favor would include materially higher end-to-end success under matched runtime conditions, smaller and more local repairs, fewer hidden effects and cross-layer mismatches, stable diagnostics for synthetic mutations, and substantial core reuse in a second domain.

Evidence against would include:

If syntax loses but diagnostics and runtime win, keep the winning pieces. Do not defend a language as an identity project.

Only after the vertical slice demonstrates value should the project discuss Python lowering, WebAssembly, native code, database plans, accelerator kernels, or specialized distributed runtimes. TypeScript is a bootstrap backend, not a permanent semantic boundary—but it is enough to test the claim.

Architecture of a programming substrate for probabilistic programmersHuman intent passes through a probabilistic model, a canonical semantic program, deterministic compilation, running systems, runtime tools, structured observations, protected evaluation, and project knowledge. Knowledge loops back to the model. Domain extensions and concrete adapters connect to several stages. The active region for this article is highlighted.MAIN LOOPDOMAIN LAYERSHuman intentProbabilistic modelCanonical semantic programCompiler, planner, reconcilerExecutable code and external resourcesRuntime and manipulation toolsStructured observationsProtected evaluationProject knowledge and verified trajectoriesevidence-bearing feedbackDomain extensionstypes · effects · observationsConcrete adaptersproviders · backends · devicesprobabilistic generation or inferencedeterministic flow or control
Part 6 turns the full architecture into a prototype and returns only independently verified trajectories to future model training.

The series began with a question: what should coding agents compile to? The honest answer remains: we do not know.

If restricted TypeScript plus the same runtime performs just as well, do not build the language. If the semantic target wins, we will know which parts earned their complexity.

Previous: Debugging Software No Human Wrote.