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.

v1.15.1· MIT or Apache-2.0· over 4,000 tests· hand-written compiler in Python
summarise.capa
// 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(())
the authorities a function can hold
Fs NetStdioEnv ClockDbProc RandomUnsafe
The problem

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.

In 30 seconds

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.

01 Declare nothing

A pure helper holds no authority

No capability in the signature means the compiler forbids any effect in the body. It is provably pure.

classify.capa
fun classify(score: Float) -> String
    if score >= 9.5
        return "Excellent"
    if score >= 6.5
        return "Pass"
    return "Fail"
02 Ask for what you need

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.

summarise.capa
fun summarise(stdio: Stdio, fs: Fs, path: String) -> Result<Unit, IoError>
    let body = fs.read(path)?
    stdio.println("read ${body.length()} bytes")
    return Ok(())
03 Get the manifest free

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.

manifest.json
{
  "name": "summarise",
  "declared_capabilities": ["Stdio", "Fs"],
  "provably_excluded_capabilities": [
    "Clock", "Db", "Env", "Net",
    "Proc", "Random", "Unsafe"
  ]
}
Two more guarantees

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.

Attenuation

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.

attenuate.capa
fun handler(fs: Fs)
    let scoped = fs.restrict_to("data/")
    load_records(scoped)
    # scoped.restrict_to(".."): cannot widen
Information-flow control

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.

leak.capa
fun main(stdio: Stdio, env: Env)
    let key = env.get("API_KEY")  # @secret
    stdio.println(key)  # rejected: secret → public sink
Showcase

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 showcase

audit-trail-reporter

AML compliance toolkit. Four detection rules (threshold, watchlist, structuring, velocity), four report sinks, attenuated read+write Fs split.

~1100 lines · 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.

IFC core

sbom-watch

SBOM operationaliser. Cross-references a CycloneDX SBOM against a CVE database and a policy file. CI-friendly exit code.

~700 lines · 5 files

policy-eval

JSON-encoded policy-as-code engine. Tree-walk interpreter over a recursive Condition AST.

~700 lines · 5 files

capa_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 governance

capa_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-scoped

capa_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 product
Install

Up 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 started
Release · 1.15.1

Stable 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.

Next

Where to go next