Getting Started
Prerequisites
Cure requires:
- Elixir ~> 1.18 and Erlang/OTP (the version compatible with your Elixir)
- Git for cloning the repository
- Z3 SMT solver (optional) -- needed only for refinement type verification. Install via your package manager (
apt install z3,brew install z3, etc.). If Z3 is not present, the compiler skips SMT-backed checks and emits a warning.
Installation
Clone the repository and fetch dependencies:
git clone https://github.com/am-kantox/cure-lang.git
cd cure-lang
mix deps.get
mix compile
Building the escript
Cure v0.33.0 ships with a standalone CLI. Build it with the dedicated Mix task:
mix cure.escript
This compiles the project and produces a cure binary in the project root.
Move it somewhere on your $PATH to use it globally:
cp cure ~/.local/bin/
Verify the installation:
cure version
# Cure 0.33.0
Hello World
Create a file examples/hello.cure:
mod Hello
fn greet(name: String) -> String = "Hello, " <> name <> "!"
fn main() -> Int = 42
Every Cure module starts with mod ModuleName. Functions are declared with fn, typed parameters, a return type annotation, and a body after =. The last expression in a block is its return value.
Compiling
cure compile examples/hello.cure
This runs the full pipeline -- lexer, parser, bidirectional type checker, BEAM code generation -- and writes a .beam file to _build/cure/ebin/. You can specify a different output directory:
cure compile examples/hello.cure --output-dir ./out
Compile an entire directory at once:
cure compile examples/ --output-dir _build/cure/ebin
Running
cure run examples/hello.cure
This compiles the file, loads the module into the VM, and calls main/0 if it exists. The return value is printed to stdout (unless it is :ok or nil).
Type checking
To type-check without generating BEAM output:
cure check examples/hello.cure
This runs the lexer, parser, and bidirectional type checker, then reports any type errors or warnings. No .beam file is produced.
Compiling the standard library
The standard library is self-hosted -- written in Cure under lib/std/. Compile it with:
cure stdlib
Or via the Mix task:
mix cure.compile_stdlib
This compiles all .cure files in lib/std/ and writes the resulting .beam files to _build/cure/ebin/. The stdlib ships 33+ modules (Std.Core, Std.List, Std.Math, Std.String, Std.Pair, Std.Show, Std.Io, Std.System, Std.Map, Std.Set, Std.Option, Std.Functor, Std.Equal, Std.Refine, Std.Match, Std.Proof, Std.Gen, Std.Iter, Std.Access, Std.Json, Std.Http, Std.Actor, Std.Process, Std.Supervisor, Std.App, Std.Time, Std.Regex, Std.CRDT, and more). As of v0.29.0 every module carries a module-level ## Examples block; browse the rendered docs at cure-lang.org/stdlib or run cure doc locally to produce the same two-pane layout under _build/cure/doc/.
Other CLI commands
cure version # Show the Cure version
cure help # Show usage information
cure explain E011 # Show a detailed explanation for an error code
cure new myproject --lib # Scaffold a new library project
cure new myapp --app # Scaffold a new OTP app (v0.26.0): app + sup
# root, matching [application] / [release] in
# Cure.toml
cure deps # List dependencies
cure deps tree # Inspect dependency graph
cure deps update # Refresh Cure.lock
cure test --doctests # Run tests, including doctests
cure test --cover # Emit _build/cure/cover/index.html
cure release # Build a bootable BEAM release under
# _build/cure/rel/<name>/ (v0.26.0)
cure release --include-erts # Bundle ERTS into the release
cure repl # Raw-mode REPL with syntax highlighting,
# persistent history, Ctrl+R reverse search,
# Tab completion, :history / :bench / :time / :save
cure watch lib/ # Recompile / check / test on every save
cure fmt lib/ # Format Cure sources
cure bench # Run bench/**/*.cure benchmarks
cure doctor # Environment + project + source health report
cure fix # Apply safe project-wide rewrites
cure publish --dry-run # Preview what `cure publish` would upload
cure publish --hex # Build a Hex-compatible tarball
cure search <query> # Search the registry
cure info <name>[:ver] # Inspect a package manifest
cure keys generate <h> # Generate an Ed25519 signing keypair
Editor setup
Neovim (LSP)
Cure includes a Language Server Protocol implementation. Start it with cure lsp (or mix cure.lsp from the project directory). Configure Neovim to use it:
vim.api.nvim_create_autocmd("FileType", {
pattern = "cure",
callback = function()
vim.lsp.start({
name = "cure-lsp",
cmd = { "cure", "lsp" },
root_dir = vim.fs.root(0, { "mix.exs", ".git" }),
})
end,
})
You also need filetype detection. Add to your Neovim config:
vim.filetype.add({
extension = {
cure = "cure",
},
})
The LSP provides:
- Real-time diagnostics (type errors, parse errors, exhaustiveness warnings, pattern coverage)
- Hover information with function signatures, inferred effects, unification traces, and hole goals
- Go-to-definition,
prepareRenameand rename - Document symbols (hierarchical module / function outline)
- Workspace symbols
- Code actions (add missing match arms, did-you-mean suggestions)
- Completion (triggered by
.and:) - Inlay hints, signature help, code lenses, semantic tokens
- Formatting routed through the round-trip-tested
Cure.Compiler.Printer
MCP server for AI assistants
Cure provides an MCP (Model Context Protocol) server so AI coding assistants can compile, type-check, parse, and analyze Cure code directly:
mix cure.mcp
This starts a JSON-RPC 2.0 server over stdio, compatible with any MCP client (Claude, Warp, etc.). Available tools:
compile_cure-- compile source, return module name or errorsparse_cure-- parse source, return AST summarytype_check_cure-- type-check source, return errors and warningsanalyze_fsm-- analyze an FSM definition (states, transitions, verification)validate_syntax-- quick lex + parse validationget_syntax_help-- get help on a syntax topicget_stdlib_docs-- get documentation for a stdlib module
Using from Elixir
You can also use Cure as a library from Elixir:
# Compile and load into the running VM
{:ok, module} = Cure.Compiler.compile_and_load(source)
module.my_function(args)
# Compile with type checking
{:ok, module} = Cure.Compiler.compile_and_load(source, check_types: true)
# Compile to disk
{:ok, module, warnings} = Cure.Compiler.compile_file("hello.cure")
Next steps
- Language Guide -- full syntax reference
- Type System -- bidirectional checking, refinement types, SMT verification
- Dependent Types -- Sigma, Pi, equality, implicit arguments, holes, totality
- Finite State Machines -- first-class FSMs with compile-time verification
- Actors -- typed supervision trees, the Melquiades Operator,
actorandsupcontainers (v0.25.0) - Applications -- first-class OTP applications and BEAM releases, the
appcontainer,Cure.toml[application]/[release]sections,cure release,Std.App(v0.26.0) - REPL -- the raw-mode REPL (v0.24.0): key bindings, meta-commands, themes, history, reverse search
- Standard Library -- auto-generated docs for every
Std.*module, extracted from.curesources with the same two-pane layoutcure docproduces locally (v0.29.0) - Tooling -- CLI reference including
cure doc(ExDoc-like two-pane layout,[doc]config,--title/--main/--extrasflags), LSP, and MCP docs/DOC.md-- on-disk reference for thecure docpipeline,Cure.Doc.Markdown, placeholder interpolation, and the REPL Markdown renderer (v0.29.0)