From zero to a running program in five minutes
Capa is a Python 3.10+ package that transpiles .capa source into Python and executes it with a small runtime. Three ways to install; pick one.
Three paths
The one-line installer if you just want capa on your PATH; the manual binary if you prefer to verify the asset yourself; from source if you intend to contribute.
Option A: one-line installer recommended
Downloads the latest pre-built binary into ~/.local/bin/capa (Linux / macOS) or %LOCALAPPDATA%\capa\capa.exe (Windows). Open a new shell and capa --version should answer.
# Linux / macOS
$ curl -fsSL https://github.com/nelsonduarte/capa-language/releases/latest/download/install.sh | bashPS> irm https://github.com/nelsonduarte/capa-language/releases/latest/download/install.ps1 | iexOption B: manual binary download
Each tagged release publishes a standalone PyInstaller binary that bundles the compiler and a Python interpreter into one file. No pip install, no Python required. The language server is bundled too, so capa lsp works straight from it.
$ curl -L -o capa \
https://github.com/nelsonduarte/capa-language/releases/latest/download/capa-linux-x86_64
$ chmod +x capa
$ ./capa --run hello.capa$ curl -L -o capa \
https://github.com/nelsonduarte/capa-language/releases/latest/download/capa-macos-arm64
$ chmod +x capa
$ xattr -d com.apple.quarantine capa # bypass Gatekeeper
$ ./capa --run hello.capaPS> Invoke-WebRequest `
-Uri "https://github.com/nelsonduarte/capa-language/releases/latest/download/capa-windows-x86_64.exe" `
-OutFile capa.exe
PS> .\capa.exe --run hello.capaOption C: from source
Requirements: Python 3.10+ and git. Tested on 3.10, 3.12 and 3.14 across all three platforms. Zero runtime dependencies outside the standard library.
$ git clone https://github.com/nelsonduarte/capa-language
$ cd capa
$ pip install -e .
$ python -m unittest discover tests # over 4,000 tests, a couple of minutesThe editable install registers the package and adds a capa command on your PATH, so both capa <args> and python -m capa <args> work from any directory. The Wasm backend is optional: pip install -e '.[wasm]' unlocks capa --wasm --run.
Dependencies in capa.toml
Projects declare dependencies in a capa.toml at the root. The same file pins the source: a git URL with an exact tag, or a relative path. A signed registry index maps short names to git sources and is GPG-verified before any name is trusted.
[package]
name = "my-project"
version = "0.1.0"
capa = ">=0.8.4"
[dependencies]
capa_log = { git = "https://github.com/nelsonduarte/capa_log", tag = "v0.1.2" }
[dev-dependencies]
capa_test = { git = "https://github.com/nelsonduarte/capa_test", tag = "v0.1.1" }$ capa install # resolve, fetch deps into ./vendor/, write capa.lock
$ capa --run main.capa
$ capa install # idempotent: rerun to refresh against capa.lockThe capa.lock pins the resolved git SHA plus a SHA-256 of the fetched tarball, so installs are bit-reproducible. When a dependency carries a verify_key, capa install verifies the GPG tag signature or Sigstore SLSA attestation before unpacking. Full guide in docs/packages.md.
Seed libraries
The signed registry currently lists eight libraries. Each declares its own capability surface, visible in the SBOM before you read its code. A library marked none is provably pure.
| Package | What it does | Capability |
|---|---|---|
| capa_cli | Command-line argument parsing: flags, positionals, subcommands | none |
| capa_csv | RFC 4180 CSV parser, header view, and writer | none |
| capa_datetime | Date and time values plus formatting | none |
| capa_hash | SHA-256, SHA-224 and HMAC-SHA256, constant-time compare | none |
| capa_http | HTTP client: request and response handling | Net |
| capa_log | Structured logging with levels and formatters | Stdio |
| capa_sbom | CycloneDX / SPDX JSON parsing with capability queries | none |
| capa_test | A tiny assertion library for the capa test runner | Stdio |
Hello, Capa
The fastest path is to let the compiler scaffold one for you.
$ capa init my-project
$ cd my-project
$ capa --run main.capa
Hello from Capa!Or type it yourself; create hello.capa:
// hello.capa
fun main(stdio: Stdio)
stdio.println("Hello, Capa!")The stdio: Stdio parameter is the language asking explicitly for the right to write to standard output. The runtime hands one to main, and main can hand it further down, or not. This is the whole language in one line.
Pipeline modes and tooling flags
Each pipeline mode subsumes the previous: --run implies --transpile, which implies --check.
| Flag | What it does |
|---|---|
| init [name] | Scaffold a new project: main.capa, README.md, .gitignore, .capa-version. |
| (none) | Tokenize: print the lexer token stream. |
| --parse | Parse to AST and print a structured dump. |
| --check | Full analyzer: name resolution, types, capability discipline. Prints errors or OK. |
| --transpile | Emit equivalent Python 3.10+ source to stdout. |
| --run | Transpile and execute. The everyday flag. |
| --fmt / --fmt-check | Rewrite in canonical style, or verify only. |
| --doc | Emit a self-contained HTML page from /// doc comments. |
| --manifest … --provenance | Emit the authority graph in five formats: Capa JSON, CycloneDX 1.5, SPDX 2.3, VEX, SLSA L1 provenance. |
| --watch | Re-run on every change. Implies --run. |
| lsp | Start the language server on stdio. |
$ capa --check examples/io.capa
OK
$ capa --run examples/grades.capa
=== Roster ===
Ana: 17.5 (Excellent)
Bruno: 13.0 (Pass)Every invocation also works as python -m capa <args> if capa is not on your PATH.
An LSP server in the box
Any LSP-capable editor (Helix, Neovim, Zed, VSCode, JetBrains, Emacs…) gets diagnostics, hover, go-to-definition, find-references, outline, completion, semantic highlighting, rename and Quick Fixes: the server runs the same lexer / parser / analyzer the CLI runs.
[[language]]
name = "capa"
language-servers = ["capa"]
file-types = ["capa"]
[language-server.capa]
command = "capa"
args = ["lsp"]The VSCode extension is on the Marketplace, with syntax highlighting, snippets, and a bundled LSP client that auto-connects to capa lsp:
$ code --install-extension nelsonduarte.capa-languageWhere to go next
Read the case →
Why Capa exists, the problem it addresses, and what it does not claim to solve.
Migrate from Python →
Move an existing program into Capa one function at a time, shrinking the Unsafe surface.
Tour the language →
A guided pass through the syntax: types, control flow, generics, capabilities, attenuation.
Read the examples →
Over fifty runnable programs, from hello.capa to SBOM parsers and the CVE case studies.