Capa
A programming language where every function declares what it is allowed to do.
Pythonic syntax, with the discipline checked statically: a function that does not list Fs or Net in its signature cannot touch the filesystem or the network. From those same capability signatures the compiler emits a machine-verifiable supply-chain SBOM by construction, a manifest that matches the code, not a scanner's approximation of it.
v1.10.0 · MIT or Apache-2.0 · 3127 tests · hand-written compiler in Python
What Capa is for
Every dependency you install today runs with the full authority of the program that pulled it in. A logging library can read your environment. A date parser can open a socket. Nothing in the language stops it; you read the README and you trust.
Capa puts the authority surface in the type system. A function that needs the filesystem says so in its signature; one that does not cannot reach for it, no matter what its body tries to do. The compiler reads the source and emits a manifest of which functions hold which authorities, automatically.
The 30-second story
A pure helper declares no capabilities; the compiler enforces it. There is no global Stdio or ambient filesystem: you cannot reference what is not in the signature.
fun classify(score: Float) -> String
if score >= 9.5
return "Excellent"
if score >= 6.5
return "Pass"
return "Fail"
A function that reads files needs Fs. The signature is the contract.
fun summarise(stdio: Stdio, fs: Fs, path: String) -> Result<Unit, IoError>
let body = fs.read(path)?
let first = match body.split("\n").get(0)
Some(line) -> line
None -> "(empty)"
stdio.println("first line: ${first}")
return Ok(())
capa --manifest reads the same source and emits JSON listing every function with the capabilities it declared and the ones it can provably never reach (because they are not in scope). A compliance reviewer gets a machine-checkable answer to "which functions can touch the network?".
{
"name": "summarise",
"declared_capabilities": ["Stdio", "Fs"],
"provably_excluded_capabilities": [
"Clock", "Db", "Env", "Net",
"Proc", "Random", "Unsafe"
]
}
Same input feeds capa --cyclonedx / --spdx / --vex / --provenance: standard supply-chain artefacts emitted by the compiler itself, not by a separate scanner approximating them.
Capabilities can be narrowed
fs.restrict_to("data/") hands a callee an Fs that only sees one directory, and the narrowing is monotonic by construction: you can never widen. The full story, including runtime path canonicalisation, is in Why Capa.
Where your data can go
Capabilities control which effects a function can use; information-flow control proves where its data can go. Annotate a value @secret and the compiler propagates the label through the program, then rejects any secret that reaches a public sink (Stdio, Net, Fs, Db). Under @strict_ifc that rejection is a compile error rather than a warning. env.get is secret by default, so an API key never lands in a log line by accident.
fun main(stdio: Stdio, env: Env)
let key = env.get("API_KEY") // @secret by default
stdio.println(key) // rejected: secret reaches a public sink
The one auditable bridge is declassify(value, reason: "..."), and every use is recorded in the SBOM as declassification_sites: a machine-checkable disclosure record, by construction. The proof of where a secret can flow ships with the manifest, not in a code review thread.
Real programs written in Capa
Each lives in its own repository, declares its dependencies in capa.toml, and runs through capa install && capa --run ....
- capa_claimdesk
- An enterprise expense-reimbursement engine that exercises nearly the whole language at once: the claim lifecycle is a typestate, the payment authorization is a linear use-once token, the IBAN is held under information-flow control and reaches the audit ledger only through an audited
declassify, the HMAC chain is re-verified in constant time, and the policy engine dispatches over aList<Rule>via traits and generics. It pulls in seven of the seed libraries (with selective import to resolve aparsecollision betweencapa_cliandcapa_csv), runs byte-identically on both backends, and ships its guarantees as proofs in the SBOM with negative cases that must not compile. The widest-coverage showcase. - audit-trail-reporter
- AML compliance toolkit. Four detection rules (threshold, watchlist, structuring, velocity), four report sinks, attenuated read+write
Fssplit. Around 1100 lines across 9 files. - capa_paymentguard
- Payment-security core. Information-flow control proves card data cannot leave unmasked: the only path to a sink is an audited
declassify, recorded in the SBOM. - sbom-watch
- SBOM operationaliser. Cross-references a CycloneDX SBOM against a CVE database and a policy file. CI-friendly exit code. Around 700 lines, 5 files.
- policy-eval
- JSON-encoded policy-as-code engine. Tree-walk interpreter over a recursive
ConditionAST. Around 700 lines, 5 files.
Install
One-line installers for Linux, macOS, and Windows, a self-contained binary with .sha256 verification, or a source install: everything lives on the Get started page.
Capa is at 1.10.0
The first stable release shipped on 2026-06-03 as 1.0.0. Several minor releases have followed under SemVer: 1.1.0 (2026-06-14) added byte-reproducible SBOMs and attestations via SOURCE_DATE_EPOCH, the capa test runner, and test-only dependencies; 1.2.0 (2026-06-15) hardened the soundness core (six linear-affinity and information-flow fixes, published as a security advisory) and added selective import; a security-hardening line through 1.5.1 (2026-06-18) closed further soundness and supply-chain findings (including build-time vendor re-verification against capa.lock). Since then 1.6.0 (2026-06-21) brought the .allows() capability-attenuation query to full Python/Wasm parity, 1.7.0 (2026-06-21) added per-dependency verify_provenance modes for SLSA verification in the package manager, and 1.8.0 through 1.10.0 (2026-06-22) linearised the Wasm backend's String concatenation, JSON serialisation, and JSON parsing. From the 1.0.0 release on, the surfaces listed in STABILITY.md follow SemVer: breaking changes require a major version bump, and deprecations get one minor release of warning first. The surface in one sentence: the capability discipline with monotonic attenuation, information-flow control with audited declassify, constant-time markers, typestates, linear handles, two backends (Python and the Wasm Component Model) with output byte-identical across the parity harness, and the supply-chain artefacts (manifest, CycloneDX, SPDX, VEX, SLSA provenance) emitted by the compiler itself. The full inventory is in the CHANGELOG and on the roadmap.