Candor.

An experiment by Krishna Paul, with the language designed and built by Claude

A programming language designed by a language model, for language models.

Candor's users are models. Its rules are designed so a model writes correct code from a single spec, so the compiler can tell it exactly what to fix, and so the human reviewing the result can trust what they read.

Self-hostingCandor compiles Candor, to a byte-identical fixed point
2 backendsinstant JS dev loop, native C build
~10 msfor the compiler to compile itself
9/9 + 9/9tasks solved first try by two models that only read llms.txt (details)

A taste

type Shape = enum
  Circle(radius: Float)
  Rect(w: Float, h: Float)
end type Shape

# No `effects` clause: this function is provably pure.
fn area(s: Shape) -> Float
  ensures result >= 0.0
  example area(Rect(2.0, 3.0)) == 6.0
  match s
    case Circle(r)
      return 3.141592653589793 * r * r
    case Rect(w, h)
      return w * h
  end match
end fn area

fn convert(amount: Float) -> Float
  let rate: Float = ?exchange_rate   # a typed hole: honest "I don't know"
  return amount * rate
end fn convert

fn main()
  effects io                         # printing must be declared
  print(show(area(Circle(1.0))))
end fn main

Designed around failure modes

How LLM-written code goes wrongWhat Candor does about it
Hidden side effects far from the call siteeffects io, fs, time in the signature, checked through every call. No clause means the function is pure.
Making up a plausible API when unsureTyped holes (?exchange_rate) type-check, list what's in scope, trap if reached, and block build.
Code that looks right but isn'trequires / ensures contracts checked at runtime, plus example clauses run by candor test.
Losing track of nestingLabeled ends: end fn area, end if. A mismatch points at the line that opened the block.
Silent coercion, truthiness, overflowNo implicit conversions. Overflow, out-of-bounds indexes and division by zero trap with the function, file and line.
"Where does this name come from?"use "lexer.cnd". A file can name only what it, or a file it directly uses, declares. The error says which use to add.
Aliasing and mutation at a distanceValue semantics. A callee can change your variable only through inout, and the call site has to say inout too.
Off-by-one loopsExplicit ranges: 0 ..< n (exclusive) vs 1 ..= n (inclusive).
Mixing up ids and plain numberstype UserId = distinct Int. Passing an OrderId where a UserId belongs is a compile error, and the hint gives the fix.
Name confusionNo shadowing, globally unique enum variants, "did you mean" suggestions, --json diagnostics.

Quick start

git clone https://github.com/krishnapaul242/candor && cd candor
node src/cli.js run   examples/tour.cnd          # instant: compiles in memory to JS
node src/cli.js run   examples/tour.cnd --native # clang -O2, then run
node src/cli.js test  examples/tour.cnd          # run every `example` clause
node src/cli.js check examples/tour.cnd --json   # machine-readable diagnostics
node src/cli.js build examples/tour.cnd -o tour  # native binary
selfhost/test.sh                                 # bootstrap the self-hosted compiler

What's in the box

Reference compiler

About 2,000 lines of dependency-free JavaScript: lexer, parser, checker, and two backends held to byte-identical behavior.

Self-hosted compiler

candorc, about 4,200 lines of Candor in six modules, with every diagnostic word for word. It bootstraps to a fixed point.

Differential tests

Every program runs through every compiler path, and stdout, stderr and exit codes must match exactly.

Field notes

An honest record of what hurt while writing a compiler in the language, which drives the roadmap.

Status: experimental (v0.4). Native builds never free memory, and there are no generics yet. See the roadmap for what comes next and why.