Roadmap

An honest inventory

What works, what is coming, and what is explicitly out of scope. Capa is released at v1.27.0: the surface is stable under SemVer, the test suite of over 4,000 tests is green on three operating systems, the discipline and information-flow control are enforced end-to-end, the package manager ships, all five audit artefacts are emitted by the compiler, and the Wasm Component Model backend is fully functional for real programs.

v1.27.0 · stableover 4,000 tests Linux · macOS · WindowsPython 3.10 / 3.12 / 3.14
Working today

The boundary between real and roadmap is sharp

Capa compiles, type-checks, transpiles to Python, lowers to WebAssembly (core and Component Model), and runs. Every example on this site is executable.

Language core shipped

  • Lexer + parser + analyzer + transpiler: 4 stages, ~5K lines of Python.
  • Full type system: primitives, tuples, List/Map/Set, Option/Result, structs, sum types, generics with inference, pattern matching, closures, the ? operator.
  • Built-in capabilities (Stdio, Fs, Net, Env, Clock, Random, Db, Proc, Serve, Unsafe) plus user-defined ones, with monotonic restrict_to attenuation and the consume qualifier. Serve is the one inbound authority: every other capability reaches out, this one is reached.
  • Module system (import, cycle detection, pub visibility, CAPA_PATH) and a package manager (capa.toml + capa install + capa.lock).

Information-flow control shipped

  • Two-point lattice (@public below @secret) on types, parameters and fields, with automatic label propagation by join.
  • env.get is the secret-by-default source; secret-to-public sinks are warn-then-enforce, hard errors under @strict_ifc(). Serve.recv is the one inbound source and is @public: the lattice models confidentiality, not integrity or taint.
  • declassify(value, reason) as the single auditable bridge, recorded in the SBOM as declassification_sites.
  • Flagship example: capa_paymentguard.

Tooling shipped

  • A 12-feature language server (diagnostics, hover, definition, references, outline, rename, type-aware completion, semantic tokens, folding, formatting).
  • AST round-trip formatter with comment preservation, watch mode, doc-comment HTML generator, capa init scaffolding, the capa test runner, and a REPL with persistent history.
  • VSCode extension on the Marketplace with a bundled LSP client.

Supply-chain artefacts shipped

  • Five emitters: --manifest, --cyclonedx 1.5, --spdx 2.3, --vex (per-function exploitability), --provenance (SLSA L1).
  • Product composition. --compose-sbom rolls the per-function facts up the dependency tree into a per-product capability SBOM over a lattice with a distinguished authority-unknown top: an unanalyzable subtree (native, unvendored, or Unsafe-crossing) composes as authority-unknown and fails closed, never reads as clean. --check-capabilities is the per-package ceiling CI gate against capa.toml [capabilities].
  • Signed authority diffs. --capability-diff old.json new.json with --fail-on-widening: a canonical, signable release-over-release changelog that flags capability widening (the node-ipc 2022 signal, a build step holding Fs that silently gains Net).
  • Compliance policies. An organization capa-policy.toml over the composed graph (exclusion, product-subset, purity, forbid-capability, forbid-dependency, no-unresolved-dependencies, plus the declassification-aware no-declassification and no-secret-egress), fail-closed on authority-unknown: --check-policies gates and --conformance-report emits signable evidence.
  • --manifest-digest emits the canonical, content-addressable manifest wrapped in a content-integrity envelope: a byte-stable sha256 over the canonical bytes with an empty detached-signature slot (SLSA L1; the compiler holds no keys and never signs in-band).
  • All eighteen registry packages carry three-layer hardening: lockfile SHA pin + GPG tag signature + a signed SLSA build-provenance attestation in the public Sigstore Rekor log. Checked on 2026-07-19 across all eighteen at their registry latest tag: every release tag is annotated and GPG-verified, and every release tarball verifies with gh attestation verify <file> --owner nelsonduarte, returning a slsa.dev/provenance/v1 predicate built by a GitHub-hosted workflow. That is the SLSA Build L2 shape (hosted builder, signed provenance); the level itself is GitHub's characterisation of its attestations, not something measured here.
  • The manifest is load-bearing (1.19.0). A capa.toml the compiler cannot parse is refused (capa: broken capa.toml: <path>: <reason>, exit 2) rather than warned about and ignored, and the declared capa = ">=X.Y.Z" compiler floor is enforced: a hard error for the root manifest, a per-package warning for a dependency's floor, with CAPA_IGNORE_CAPA_FLOOR=1 as a loud escape. See Get started.
  • SBOM tooling written in Capa: diff, capability audit, SPDX and CycloneDX parsers.

Wasm backend shipped

  • Component Model backend: capa --wasm --component --output app.wasm produces a standalone artifact with the WIT spec embedded.
  • Generics and trait dispatch are implemented on both backends, and every capability except Serve and Unsafe runs on Wasm, with attenuation enforced at the host boundary. Backend parity is a goal, not a guarantee. The toolchain ships differential tooling for it (capa test --both diffs the two backends per test file, and the suite carries a Wasm parity module), but that coverage is not exhaustive, so treat the Python backend as the reference semantics and do not derive a security conclusion from a Wasm run alone. One class of divergence has been closed: 1.20.0 made the Wasm hosts bind main's capability slots by declared type in declaration order, carried where ordinary tooling cannot strip it, so fun main(conn: Net, stdio: Stdio) narrowing conn and asking allows("example.com") now answers the same under --run and --run --wasm, where earlier it printed true then false.
  • --prefer-wasm tries Wasm first with silent fallback. Unsafe and Serve are loudly rejected, and permanently: Unsafe has no sandboxed Wasm equivalent, and Serve would need wasi:sockets, which is neither vendored in the compiler nor reachable from the wasmtime bindings the hosts are built on. Both capa --wasm and capa --wit refuse a program whose signatures reach Serve, before any lowering, listing every offending site.
  • Typed foreign components. extern component <Name> from "x.wasm" runs an untrusted, separately-compiled Wasm component confined by the sandbox to exactly its declared capabilities: for the capability subset it can carry, static-declared equals runtime-permitted (a child importing an ungranted interface is refused at instantiation, before its code runs). A resource ceiling bounds it too, --foreign-fuel (child CPU), --foreign-memory-cap (child memory), and --foreign-result-cap (a peak bound on the host-side buffer a result crossing allocates). Unsafe stays Python-only and composes as authority-unknown.
  • Experimental --wasi mode. Compiles to a component that runs on stock WASI Preview 2 runtimes (for example wasmtime), instead of the default --component, which targets the dedicated capa:host. It provides mitigation Levels 1 and 2 (a runtime ceiling via --preopen and environment, plus the guest-side proof) but not Level 3, which needs capa:host: a slightly weaker guarantee tier in exchange for running on any stock WASI runtime. Literal filesystem paths pass the static ceiling; dynamic paths (for example from argv) require an operator grant --preopen <dir>, recorded in the SBOM as operator_declared_grants. capa --wasi-surface <file> shows which argv arguments reach Fs or Net sinks. Networking goes through wasi:http; note that wasmtime's wasi:http is allow-all at the host level (its C-API exposes no per-host allowed-hosts control), so the defence (fail-closed on non-2xx responses, anti-SSRF) is done guest-side. A dynamic (argv-derived) URL likewise needs an operator grant --allow-host <host> (append :get or :post to grant read or write only), the Net analogue of --preopen, recorded in the SBOM as an operator-declared grant. Example: capa --wasm --component --wasi --run programa.capa --preopen . -- <args>.

Quality & proofs shipped

  • Agda mechanisation of all four λcap soundness theorems in proofs/.
  • A gated-variant λcap proof (proofs/CapaManifestExact.agda, --safe) closes the introduction dimension of the Capa-vs-λcap gap: in a well-typed program every capability literal is introduced only at the top level, never under a lambda binder. It is introduction confinement only. It does not prove the manifest equals the declared set (the manifest stays a sound upper bound), gated preservation is false by design, and the surface-to-calculus translation is argued informally.
  • Property-based testing through Phase 4 (50k+ generated programs) lifting wasm_runtime_classes ⊆ manifest_classes through the Wasm backend.
  • Over 4,000 unit + end-to-end tests, green across three OSes and three Python versions; a published soundness-hardening advisory (1.2.0).
The road ahead

What is still open

Most of the original design promises have shipped: generic attenuation, the native module system, the package manager, selective import, doc comments, raw strings, named arguments, the LSP, the formatter, and the full SBOM/VEX/provenance triangle are all done. What remains is deliberately small.

  • Refinement types P3. A way to express properties like "this string is non-empty" or "this list is sorted" in the type system. Research-grade; explicitly not in scope for 1.x.
  • A full hosted registry with search and a web publish flow. The signed index covers name resolution and supply-chain anchoring today; the hosted experience is future.
  • Package-manager polish: --frozen and richer transitive resolution remain for future iterations.
  • LSP v2 polish (deferred until a real-user session surfaces a need): signatureHelp, inlayHint, workspace/symbol, codeLens, selectionRange.
  • A dedicated native/LLVM backend is deliberately deferred, with no date: the Wasm Component Model backend emits a component that the runtime (for example wasmtime) can AOT-compile, which is distinct from a dedicated native backend.

Help shape the next milestone

Capa is a personal project, and an open one. The fastest way to influence the roadmap is to show up with a real use case.