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 a List<Rule> via traits and generics. It pulls in seven of the seed libraries (with selective import to resolve a parse collision between capa_cli and capa_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 Fs split. 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 Condition AST. 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.

Where to go next