Vera (v-EER-a) is a programming language designed for large language models (LLMs) to write, not humans.
The name comes from the Latin veritas (truth). In Vera, verification is a first-class citizen, not an afterthought.
Programming languages have always co-evolved with their users. Assembly emerged from hardware constraints. C emerged from operating system needs. Python emerged from productivity needs. If models become the primary authors of software, it is consistent for languages to adapt to that.
The evidence suggests the biggest problem models face isn't syntax — 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.
Vera addresses this by making everything explicit and verifiable. The model doesn't need to be right — it needs to be checkable.
- Checkability over correctness. Code that can be mechanically checked. When wrong, the compiler provides a natural language explanation of the error with a concrete fix — an instruction, not a status report.
- Explicitness over convenience. All state changes declared. All effects typed. All function contracts mandatory. No implicit behaviour.
- One canonical form. Every construct has exactly one textual representation. No style choices.
- Structural references over names. Bindings referenced by type and positional index (
@T.n), not arbitrary names. - Contracts as the source of truth. Every function declares what it requires and guarantees. The compiler verifies statically where possible.
- Constrained expressiveness. Fewer valid programs means fewer opportunities for the model to be wrong.
- No variable names — typed De Bruijn indices (
@T.n) replace traditional variable names - Full contracts — mandatory preconditions, postconditions, invariants, and effect declarations on all functions
- Algebraic effects — declared, typed, and handled explicitly; pure by default
- Refinement types — types that express constraints like "a list of positive integers of length n"
- Three-tier verification — static verification via Z3, guided verification with hints, runtime fallback
- Diagnostics as instructions — every error message is a natural language explanation with a concrete fix, designed for LLM consumption
- Compiles to WebAssembly — portable, sandboxed execution
Every function declares what it requires, what it guarantees, and what effects it performs. Even a one-liner has a full contract. Effects are declared before use, and effect operations use qualified calls (IO.print). effects(<IO>) tells the compiler (and the model) that this function interacts with the outside world.
effect IO {
op print(String -> Unit);
}
fn main(@Unit -> @Unit)
requires(true)
ensures(true)
effects(<IO>)
{
IO.print("Hello, World!")
}
There are no variable names. @Int.0 refers to the most recent Int binding — a typed positional index, like De Bruijn indices but namespaced by type. The ensures clause is a machine-checkable promise: the result is non-negative and equals the absolute value of the input. The compiler verifies this via SMT solver.
fn absolute_value(@Int -> @Nat)
requires(true)
ensures(@Nat.result >= 0)
ensures(@Nat.result == @Int.0 || @Nat.result == -@Int.0)
effects(pure)
{
if @Int.0 >= 0 then {
@Int.0
} else {
-@Int.0
}
}
requires(@Int.1 != 0) means this function cannot be called with a zero divisor. The compiler checks every call site to prove the precondition holds. If it cannot prove it, the code does not compile. Division by zero is not a runtime error — it is a type error.
fn safe_divide(@Int, @Int -> @Int)
requires(@Int.1 != 0)
ensures(@Int.result == @Int.0 / @Int.1)
effects(pure)
{
@Int.0 / @Int.1
}
Algebraic effects — explicit state, no hidden mutation
Vera is pure by default. State changes must be declared as effects. effects(<State<Int>>) says this function reads and writes an integer. The ensures clause specifies exactly how the state changes: the new value equals the old value plus one. Handlers (not shown) provide the actual state implementation — an in-memory cell in production, a mock in tests.
fn increment(@Unit -> @Unit)
requires(true)
ensures(new(State<Int>) == old(State<Int>) + 1)
effects(<State<Int>>)
{
let @Int = get(());
put(@Int.0 + 1);
()
}
Traditional compilers produce diagnostics for humans: expected token '{'. Vera produces instructions for the model that wrote the code.
Every error includes what went wrong, why, how to fix it with a concrete code example, and a spec reference. The compiler's output is designed to be fed directly back to the model as corrective context.
Error in main.vera at line 12, column 1:
fn add(@Int, @Int -> @Int)
^
Function "add" is missing its contract block. Every function in Vera
must declare requires(), ensures(), and effects() clauses between the
signature and the body.
Add a contract block after the signature:
fn add(@Int, @Int -> @Int)
requires(true)
ensures(@Int.result == @Int.0 + @Int.1)
effects(pure)
{
...
}
See: Chapter 5, Section 5.1 "Function Structure"
This principle applies at every stage: parse errors, type errors, effect mismatches, verification failures, and contract violations all produce natural language explanations with actionable fixes.
Vera is in active development. The language specification, parser, AST, type checker, contract verifier, and WASM code generator are functional. Programs compile to WebAssembly and execute via wasmtime.
| Component | Status |
|---|---|
| Language specification | Draft |
| — Ch 0: Introduction and Philosophy | Draft |
| — Ch 1: Lexical Structure | Draft |
| — Ch 2: Types | Draft |
| — Ch 3: Slot References | Draft |
| — Ch 4: Expressions and Statements | Draft |
| — Ch 5: Functions | Draft |
| — Ch 6: Contracts | Draft |
| — Ch 7: Effects | Draft |
| — Ch 8: Modules | Not started |
| — Ch 9: Standard Library | Draft |
| — Ch 10: Formal Grammar | Draft |
| — Ch 11: Compilation Model | Draft |
| — Ch 12: Runtime and Execution | Draft |
| Parser (Lark LALR(1)) | Working |
| AST (typed syntax tree) | Working |
| Type checker | Working |
| Contract verifier (Z3) | Working |
| WASM code generation | Working |
| Runtime contract insertion | Working |
Development follows an interleaved spiral — each phase adds a complete compiler layer with tests, docs, and working examples before moving to the next.
| Phase | Version | Layer | Status |
|---|---|---|---|
| C1 | v0.0.1–v0.0.3 | Parser — Lark LALR(1) grammar, LLM diagnostics, 13 examples | Done |
| C2 | v0.0.4 | AST — typed syntax tree, Lark→AST transformer | Done |
| C3 | v0.0.5 | Type checker — decidable type checking, slot resolution, effect tracking | Done |
| C4 | v0.0.8 | Contract verifier — Z3 integration, refinement types, counterexamples | Done |
| C5 | v0.0.9 | WASM codegen — compile to WebAssembly, vera compile / vera run |
Done |
| C6 | v0.0.10–v0.0.24 | Codegen completeness — ADTs, match, closures, effects, generics in WASM | Done |
| C6.5 | v0.0.25– | Codegen cleanup — handler fixes, missing operators, String/Array support | In Progress |
| C7 | — | Module system — cross-file imports, public/private visibility | Planned |
| C8 | v0.1.0 | End-to-end — all examples compile and run, spec complete, polish | Planned |
Before starting the module system, C6.5 addresses residual gaps in single-file compilation — handler bugs, missing operators, and type support limits. Each sub-phase closes a tracked issue.
| Sub-phase | Scope | Issue |
|---|---|---|
resume not recognized as built-in in handler scope |
v0.0.25 | |
with clause for state updates not in grammar |
v0.0.26 | |
| C6.5c | Pipe operator (|>) compilation |
#44 |
| C6.5d | Float64 modulo (%) — WASM has no f64.rem |
#46 |
| C6.5e | String and Array types in function signatures | #69 |
| C6.5f | old()/new() state expressions in contracts |
#70 |
C6 — Codegen Completeness (v0.0.10–v0.0.24) ✓
C6 extended WASM compilation to all language constructs, working through the dependency graph from simplest to most complex. All 14 examples now compile.
| Sub-phase | Scope | Version |
|---|---|---|
| C6a | Float64 — f64 literals, arithmetic, comparisons |
v0.0.10 |
| C6b | Callee preconditions — verify requires() at call sites |
v0.0.11 |
| C6c | Match exhaustiveness — verify all constructors covered | v0.0.12 |
| C6d | State<T> operations — get/put as host imports | v0.0.13 |
| C6e | Bump allocator — heap allocation for tagged values | v0.0.14 |
| C6f | ADT constructors — heap-allocated tagged unions | v0.0.15 |
| C6g | Match expressions — tag dispatch, field extraction | v0.0.16 |
| C6h | Closures — closure conversion, call_indirect |
v0.0.18 |
| C6i | Generics — monomorphization of forall<T> functions |
v0.0.17 |
| C6j | Effect handlers — handle/resume compilation | v0.0.19 |
| C6k | Byte + arrays — linear memory arrays with bounds | v0.0.21 |
| C6l | Quantifiers — forall/exists as runtime loops | v0.0.22 |
| C6m | Refinement type alias compilation | v0.0.23 |
| C6n | Spec chapters 9 (Standard library) and 12 (Runtime) | v0.0.24 |
C7 will implement cross-file imports, public/private visibility, and multi-module compilation. Tracked in #14 and #50. Spec Chapter 8 (Modules) will be written alongside the implementation.
- Python 3.11+
- Git
The install step pulls in several dependencies via pip — Lark (parser generator), Z3 (SMT solver for contract verification), and wasmtime (WASM runtime for compilation and execution). These all install into the virtual environment and don't require separate system packages.
git clone https://github.com/aallan/vera.git
cd vera
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"$ vera check examples/absolute_value.vera
OK: examples/absolute_value.vera
vera check parses the file, builds the AST, and runs the type checker. vera typecheck is an explicit alias for the same command.
$ vera verify examples/safe_divide.vera
OK: examples/safe_divide.vera
Verification: 2 verified (Tier 1)
vera verify runs the type checker and then verifies contracts using Z3. Tier 1 contracts (decidable arithmetic, comparisons, Boolean logic) are proved automatically. Contracts that Z3 cannot decide are reported as Tier 3 (runtime checks) with a warning.
$ vera compile examples/hello_world.vera
Compiled: examples/hello_world.wasm (1 function exported)
vera compile runs the full pipeline (parse → typecheck → verify → compile) and writes a .wasm binary. Add --wat to print the human-readable WAT text instead:
vera compile --wat examples/hello_world.vera$ vera run examples/hello_world.vera
Hello, World!
vera run compiles and executes the program. By default it calls main. Use --fn to call a different function, and pass arguments after --:
$ vera run examples/factorial.vera --fn factorial -- 5
120
vera parse examples/safe_divide.veraThis prints the parse tree, useful for debugging syntax issues.
vera ast examples/factorial.veraThis prints the typed abstract syntax tree. Add --json for JSON output:
vera ast --json examples/factorial.verapytest tests/ -vFor contributors, install pre-commit hooks to catch issues before they reach CI:
pre-commit installThis runs mypy, pytest, trailing whitespace checks, and validates all examples on every commit.
Create a file hello.vera:
fn double(@Int -> @Int)
requires(true)
ensures(@Int.result == @Int.0 * 2)
effects(pure)
{
@Int.0 * 2
}
Then check it:
vera check hello.veraSee examples/ for more programs, and the language specification for the full language reference.
Vera ships with three files for LLM agents:
SKILLS.md— Complete language reference for agents writing Vera code. Covers syntax, slot references, contracts, effects, common mistakes, and working examples.AGENTS.md— Instructions for any agent system (Copilot, Cursor, Windsurf, custom). Covers both writing Vera code and working on the compiler.CLAUDE.md— Project orientation for Claude Code. Key commands, layout, workflows, and invariants.
If you're working in this repo, Claude Code discovers SKILLS.md and CLAUDE.md automatically. For other projects, install the skill manually:
mkdir -p ~/.claude/skills/vera-language
cp /path/to/vera/SKILLS.md ~/.claude/skills/vera-language/SKILL.mdThe skill is now available across all your Claude Code projects. Claude will read it automatically when you ask it to write Vera code.
- Create a folder called
vera-languagecontaining a single file namedSkill.md(copySKILLS.mdinto this folder and rename it toSkill.md) - Compress the folder into a ZIP file — the structure should be
vera-language.zip → vera-language/ → Skill.md - In Claude.ai, go to Settings > Capabilities > Skills and upload the ZIP file
- The skill is now available in your conversations — Claude will use it automatically when you ask it to write Vera code
from anthropic.lib import files_from_dir
client = anthropic.Anthropic()
skill = client.beta.skills.create(
display_title="Vera Language",
files=[("SKILL.md", open("SKILLS.md", "rb"))],
betas=["skills-2025-10-02"],
)
# Use in a message
response = client.beta.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
betas=["code-execution-2025-08-25", "skills-2025-10-02"],
container={"skills": [{"type": "custom", "skill_id": skill.id, "version": "latest"}]},
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
messages=[{"role": "user", "content": "Write a Vera function that..."}],
)Point the model at SKILLS.md by including it in the system prompt, as a file attachment, or as a retrieval document. The file is self-contained and works with any model that can read markdown.
If you are an LLM agent, read SKILLS.md for the full language reference. Here is the minimal workflow:
Install (if not already available):
git clone https://github.com/aallan/vera.git && cd vera
python -m venv .venv && source .venv/bin/activate && pip install -e .Write a .vera file, then check, verify, and run it:
vera check your_file.vera # type-check
vera verify your_file.vera # type-check + verify contracts
vera compile your_file.vera # compile to .wasm binary
vera run your_file.vera # compile + execute
vera run your_file.vera --fn f -- 42 # call function f with argument 42
vera verify --json your_file.vera # verify with JSON diagnosticsIf the check or verification fails, the error message tells you exactly what went wrong and how to fix it. Feed the error back into your context and correct the code. Use --json for machine-readable output that includes structured diagnostics with location, rationale, and fix suggestions.
Essential rules:
- Every function needs
requires(),ensures(), andeffects()between the signature and body - Use
@Type.indexto reference bindings —@Int.0is the most recentInt,@Int.1is the one before that - Declare all effects —
effects(pure)for pure functions,effects(<IO>)for IO, etc. - Recursive functions need a
decreases()clause - Match expressions must be exhaustive
vera/
├── SKILLS.md # Language reference for LLM agents
├── AGENTS.md # Instructions for any AI agent system
├── CLAUDE.md # Project orientation for Claude Code
├── CONTRIBUTING.md # Contributor guidelines
├── CHANGELOG.md # Version history
├── pyproject.toml # Package configuration
├── spec/ # Language specification (12 chapters)
│ ├── 00-introduction.md # Design goals and philosophy
│ ├── 01-lexical-structure.md # Tokens, operators, formatting rules
│ ├── 02-types.md # Type system with refinement types
│ ├── 03-slot-references.md # The @T.n reference system
│ ├── 04-expressions.md # Expressions and statements
│ ├── 05-functions.md # Function declarations and contracts
│ ├── 06-contracts.md # Verification system
│ ├── 07-effects.md # Algebraic effect system
│ ├── 09-standard-library.md # Built-in types, effects, functions
│ ├── 10-grammar.md # Formal EBNF grammar
│ ├── 11-compilation.md # Compilation model and WASM target
│ └── 12-runtime.md # Runtime execution and host bindings
├── vera/ # Reference compiler (Python)
│ ├── grammar.lark # Lark LALR(1) grammar
│ ├── parser.py # Parser module
│ ├── ast.py # Typed AST node definitions
│ ├── transform.py # Lark parse tree → AST transformer
│ ├── types.py # Internal type representation
│ ├── registration.py # Function signature registration
│ ├── environment.py # Type environment and slot resolution
│ ├── checker.py # Type checker
│ ├── smt.py # Z3 SMT translation layer
│ ├── verifier.py # Contract verifier
│ ├── wasm.py # WASM translation layer
│ ├── codegen.py # Code generation orchestrator
│ ├── errors.py # LLM-oriented diagnostics
│ └── cli.py # Command-line interface
├── examples/ # 14 example Vera programs
├── tests/ # Test suite (858 tests)
├── scripts/ # CI and validation scripts
│ ├── check_examples.py # Verify all .vera examples
│ ├── check_spec_examples.py # Verify spec code blocks parse
│ ├── check_readme_examples.py # Verify README code blocks parse
│ └── check_version_sync.py # Verify version consistency
└── runtime/ # WASM runtime support (future)
For compiler architecture, pipeline internals, design patterns, and how to extend the compiler, see vera/README.md.
| Decision | Choice | Rationale |
|---|---|---|
| Representation | Text with rigid syntax | One canonical form, no parsing ambiguity |
| References | @T.n typed De Bruijn indices |
Eliminates naming coherence errors |
| Contracts | Mandatory on all functions | Programs must be checkable |
| Effects | Algebraic, row-polymorphic | All state and side effects explicit |
| Verification | Z3 via SMT-LIB | Industry standard, decidable fragment |
| Memory | Managed (bump allocator; GC planned — #51) | Models focus on logic, not memory |
| Target | WebAssembly | Portable, sandboxed, no ambient capabilities |
| Compiler | Python reference impl | Correctness over performance — see architecture docs |
| Evaluation | Strict (call-by-value) | Simpler for models to reason about |
| Diagnostics | Natural language with fix examples | Compiler output is the model's feedback loop |
Vera draws on ideas from:
- Eiffel — Design by Contract (the originator of
require/ensure) - Dafny — full functional verification with contracts
- F* — refinement types, algebraic effects, and SMT verification
- Koka — row-polymorphic algebraic effects
- Liquid Haskell — refinement types via SMT
- Idris — totality checking and termination proofs
- SPARK/Ada — contract-based industrial verification
- bruijn — De Bruijn indices as surface syntax
See CONTRIBUTING.md for guidelines on how to contribute to Vera. For compiler internals — pipeline architecture, module map, design patterns, and how to extend the compiler — see vera/README.md.
See CHANGELOG.md for a history of changes.
Vera is licensed under the MIT License.
Copyright © 2026 Alasdair Allan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
