Astra is a programming language designed for LLMs and AI agents to write, verify, and maintain code.
Why not just use Python, TypeScript, Go, or Rust? See Why Astra? for the full rationale.
When LLMs generate code, they enter a feedback loop: generate, check for errors, interpret diagnostics, fix, repeat. Existing languages work for this — agents write Rust, TypeScript, Go, and Python every day — but none were designed with this loop as the primary use case.
Three sources of friction slow every mainstream language:
- Side effects are invisible. No mainstream language tracks I/O, network, or clock access in function signatures. Agents must read implementations to know what a function actually does.
- Diagnostics are human-first. Even languages with structured error output (Rust's
--message-format=json, TypeScript's stable codes) don't consistently bundle machine-actionable fix suggestions with exact edit locations. - Test determinism is opt-in. Flaky tests from time, randomness, or I/O are a discipline problem everywhere. The language doesn't prevent them.
Astra is designed around three capabilities that no single mainstream language provides together:
- Mandatory effect tracking - function signatures declare all capabilities (
Net,Fs,Clock); the compiler rejects undeclared effects - Agent-oriented diagnostics - every error includes structured JSON with stable codes and suggested fixes with exact edit locations
- Enforced test determinism - effects must be mocked in tests; seeded randomness and fixed clocks are the default, not opt-in
Plus the building blocks you'd expect:
- No null -
Option[T]with exhaustive matching; compiler catches missing cases - Typed error handling -
Result[T, E]with?and?elsefor concise propagation - Canonical formatting - mandatory built-in formatter, no configuration
- JSON / regex - built into the standard library
- 15 stdlib modules - from
std.mathtostd.datetimeandstd.path
LLM generates code -> astra check -> JSON errors with fix suggestions -> LLM applies fixes -> repeat until passing
# Build the toolchain
cargo build --release
# Add to PATH (or use 'cargo run --' instead of 'astra')
export PATH="$PATH:$(pwd)/target/release"
# Create a new project
astra init my_project && cd my_project
# Run, check, and test
astra run src/main.astra
astra check src/
astra testastra init scaffolds everything you need including a .claude/CLAUDE.md that
makes the project immediately usable with Claude Code
and other AI agents. See Getting Started for the full tutorial.
module payments
type Money = { currency: Currency, cents: Int }
invariant cents >= 0
enum ChargeError =
| InvalidAmount
| NetworkFailure
| Declined(reason: Text)
public fn charge(req: { customer: CustomerId, amount: Money })
-> Result[{ id: ReceiptId, amount: Money }, ChargeError]
effects(Net, Clock)
requires req.amount.cents > 0
ensures result.is_ok() implies result.ok.amount == req.amount
{
let token = Net.env("PAYMENTS_TOKEN") ?else return Err(NetworkFailure)
let res =
Net.post_json("https://api.example/charge", req, headers = { "Auth": token })
?else return Err(NetworkFailure)
match res.status {
200 => Ok({ id = res.json.id, amount = req.amount })
402 => Err(Declined(res.json.reason))
_ => Err(NetworkFailure)
}
}
test "rejects zero amount" {
let req = { customer = "c1", amount = { currency = "EUR", cents = 0 } }
assert charge(req).is_err()
}
- Verifiability First - Wrong code fails early with precise, machine-actionable errors
- Unambiguous Semantics - One obvious way to express things; formatter is mandatory
- Local Reasoning - Modules are explicit; no spooky action-at-a-distance
- Safe Execution by Default - Capability-based I/O; sandbox-friendly
- Fast Incremental Iteration - Check and test are fast, deterministic, and stable
The std.json module provides complete JSON parsing and stringification. Use json_parse(text) to parse any JSON string into Astra values (objects become Records, arrays become Lists), and json_stringify(value) to convert any Astra value to JSON.
let data = json_parse("{\"name\": \"Astra\", \"version\": 1}")
assert_eq(data.name, "Astra")
let json = json_stringify({ items = [1, 2, 3], ok = true })
The std.regex module and text methods support pattern matching. Use regex_match, regex_find_all, regex_replace, regex_split, and regex_is_match as builtins, or use text methods like .matches(), .replace_pattern(), .split_pattern(), and .find_pattern().
import std.regex { is_match, find_all, replace }
let valid = is_match("^\\d{3}-\\d{4}$", "555-1234")
let cleaned = replace("\\s+", " too many spaces ", " ")
let words = "hello world".split_pattern("\\s+")
- Async/Await —
async fnandawaitsyntax is reserved; full implementation coming in v1.1 - Package Manager —
astra pkgcommand exists; dependency resolution coming in v1.1 - See ADR-007 for rationale
| Command | Description |
|---|---|
astra run <file> |
Execute an Astra program |
astra check [files...] |
Parse + typecheck + lint |
astra test [filter] |
Run tests deterministically |
astra fmt [files...] |
Format files canonically |
astra fix [files...] |
Auto-apply diagnostic suggestions |
astra explain <code> |
Explain an error code |
astra repl |
Interactive REPL |
astra init <name> |
Scaffold a new project |
astra doc [files...] |
Generate API documentation |
astra lsp |
Start LSP server |
astra pkg |
Package management (v1.1) |
- Why Astra? — The case for an LLM-native language
- Getting Started — Tutorial for your first Astra program
- Astra by Example — Cookbook of common patterns and idioms
- Language Specification — Complete syntax and semantics reference
- Formal Grammar — EBNF grammar for the language
- Effects System — Guide to Astra's capability-based effects
- Testing Guide — How to write and run tests
- Standard Library — API reference for built-in types and functions
- Error Codes Reference — All error codes with examples and fixes
- Formatting Rules — Canonical formatting specification
- Performance — Performance characteristics and guidance
- Stability Guarantee — v1.0 stability promises
- Changelog — Version history
astra/
├── src/ # Rust source for toolchain
│ ├── parser/ # Lexer + Parser + AST
│ ├── formatter/ # Canonical formatter
│ ├── typechecker/ # Type system
│ ├── effects/ # Effect system
│ ├── interpreter/ # Runtime/VM
│ └── cli/ # Command-line interface
├── stdlib/ # Astra standard library
├── tests/ # Test suites
├── docs/ # Documentation
└── examples/ # Example programs
- Interpreted only — Tree-walking interpreter. Adequate for scripts and tools, not for compute-heavy workloads. See docs/performance.md.
- Traits are runtime-dispatched — The type checker validates trait impl blocks, but trait method calls are resolved at runtime.
- No debugger — Use
println,assert/assert_eq, andtestblocks for debugging. - Async/await not yet functional — Syntax is reserved for v1.1.
- Package manager not yet functional —
astra pkgexists but resolution is not implemented until v1.1.
See docs/stability.md for the v1.0 stability guarantee.
See CONTRIBUTING.md for development guidelines.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.