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 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.
// 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(())
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.
From a signature to an audit artefact
There is no global Stdio or ambient filesystem: you cannot reference what is not in the signature. The compiler reads the same source three ways.
A pure helper holds no authority
No capability in the signature means the compiler forbids any effect in the body. It is provably pure.
fun classify(score: Float) -> String
if score >= 9.5
return "Excellent"
if score >= 6.5
return "Pass"
return "Fail"
Reading files requires Fs
To open a file the function must name Fs in its signature. The capability is the contract, and it is passed in, never ambient.
fun summarise(stdio: Stdio, fs: Fs, path: String) -> Result<Unit, IoError>
let body = fs.read(path)?
stdio.println("read ${body.length()} bytes")
return Ok(())
The compiler emits the proof
capa --manifest lists every function with the capabilities it declared and the ones it can provably never reach. Same input feeds --cyclonedx, --spdx, --vex and --provenance.
{
"name": "summarise",
"declared_capabilities": ["Stdio", "Fs"],
"provably_excluded_capabilities": [
"Clock", "Db", "Env", "Net",
"Proc", "Random", "Unsafe"
]
}
Narrow what a function holds, and prove where its data goes
Capabilities say which effects a function may use. Attenuation shrinks them on the way down; information-flow control tracks where labelled data is allowed to travel.
Capabilities can only 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.
fun handler(fs: Fs)
let scoped = fs.restrict_to("data/")
load_records(scoped)
# scoped.restrict_to(".."): cannot widen
Where your data can go
Annotate a value @secret and the compiler propagates the label, then rejects any secret that reaches a public sink. env.get is secret by default. The one auditable bridge is declassify(value, reason: "…"); every use is recorded in the SBOM as declassification_sites, so the proof ships with the manifest, not in a code-review thread.
fun main(stdio: Stdio, env: Env)
let key = env.get("API_KEY") # @secret
stdio.println(key) # rejected: secret → public sink
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, and the policy engine dispatches over a List<Rule> via traits and generics. Runs byte-identically on both backends and ships its guarantees as proofs in the SBOM.
widest-coverage showcaseaudit-trail-reporter
AML compliance toolkit. Four detection rules (threshold, watchlist, structuring, velocity), four report sinks, attenuated read+write Fs split.
~1100 lines · 9 filescapa_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.
IFC coresbom-watch
SBOM operationaliser. Cross-references a CycloneDX SBOM against a CVE database and a policy file. CI-friendly exit code.
~700 lines · 5 filespolicy-eval
JSON-encoded policy-as-code engine. Tree-walk interpreter over a recursive Condition AST.
~700 lines · 5 filescapa_dataguard
Data-governance pipeline. Information-flow control proves by construction that PII never reaches a public sink: every path to output runs through an audited declassify.
IFC governancecapa_configbroker
Capability-secured config and secrets resolver. Secrets are provably kept out of logs, and its network reach is attenuated to a single host.
capability-scopedcapa_ci_pipeline
A CI/release orchestrator built as a multi-package product. Four untrusted third-party actions run as sandbox-confined typed foreign Wasm components; the pure core holds no authority; the whole product's capability surface composes into one SBOM. A compromised build action that silently gains Net is caught twice over: by the signed authority diff and by an organization exclusion policy.
supply-chain productUp and running in one line
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.
Get startedStable and on SemVer
The first stable release shipped on 2026-06-03 as 1.0.0. Minor releases since added byte-reproducible SBOMs and attestations via SOURCE_DATE_EPOCH, the capa test runner, selective import, and a security-hardening line that closed further soundness and supply-chain findings.
Surfaces listed in STABILITY.md follow SemVer. The full inventory is in the CHANGELOG and on the roadmap.
Where to go next
- Why Capa exists : the case for capability typing, against ambient authority, against the supply-chain status quo.
- The capability-recall study : Capa measured head-to-head against a dependency SBOM, Semgrep and CodeQL on 25 pairs; 0 false-clearances against CodeQL's 10.
- Learn (14 chapters) : a guided tour from hello world to the audit artefacts.
- The book : Capa: The Capability-Typed Programming Language, a free PDF (~287 pages, ~2 MB) with exercises and three projects, downloaded straight from here. Source on GitHub.
- Language reference : full syntax and semantics.
- Roadmap : what is done, what is next, what is explicitly out of scope.