Roadmap

An honest inventory of what works, what is coming, and what is explicitly out of scope. Capa is released at v1.10.0: the surface is stable under SemVer, the 3127-test suite is green on three operating systems, the discipline is implemented end-to-end, information-flow control (a two-point security lattice with declassification recorded in the SBOM) is enforced end-to-end, the module system is feature-complete, the package manager ships (capa.toml + capa install + capa.lock), the capability manifest, CycloneDX SBOM, SPDX SBOM, CycloneDX VEX, and SLSA L1 provenance are all emitted directly by the compiler, and the Wasm Component Model backend is fully functional for real programs. STABILITY.md describes the compatibility commitment that starts the moment 1.0.0 ships.

Where we are today

Capa is at v1.10.0. It compiles, type-checks, transpiles to Python, lowers to WebAssembly (core and Component Model), and runs. Every example in this site and in the examples directory is executable. The boundary between what is real and what is roadmap is sharp:

Working today

Language core

  • Lexer + parser + analyzer + transpiler (4 stages, ~5K lines of Python)
  • Types: Int, Float, Bool, String, Char, Unit, tuples, List, Map, Set, Option, Result, Fun(...) -> ...
  • Structs, sum types (variants), generics with inference
  • Pattern matching (statement + expression form)
  • Closures and higher-order functions
  • ? operator and Result-based error handling
  • Built-in capabilities: Stdio, Fs, Net, Env, Clock, Random, Db, Proc, Unsafe
  • User-defined capabilities (capability X + impl X for Y)
  • Capability attenuation: restrict_to on every built-in capability (monotonic, fail-closed)
  • consume qualifier with fork/merge tracking
  • Range expressions (a..b exclusive, a..=b inclusive), Range<Int> as a type
  • Python interop via the Unsafe capability boundary
  • Module system: import foo.bar with transitive imports, cycle detection, name conflicts, qualified access (foo.fn(), import foo as F), search paths via CAPA_PATH, and pub visibility enforcement
  • Package manager: capa.toml + capa install + capa.lock, git and path deps, automatic ./vendor/ resolution when a manifest is present

Information-flow control (IFC)

  • Two-point security lattice (@public below @secret) on types, parameters, and fields
  • Automatic label propagation by join; env.get is a secret-by-default source
  • Secret-to-public sink enforcement on Stdio / Net / Fs / Db sinks: warn-then-enforce by default, hard errors under @strict_ifc()
  • declassify(value, reason: "...") as the single auditable bridge, recorded in the SBOM as declassification_sites (with reason and source position)
  • Implicit-flow control under @strict_ifc; anti-laundering through aggregates and mutable containers (intra-procedural, whole-aggregate granularity stated honestly)
  • Flagship example: capa_paymentguard

Tooling

  • CLI: tokenize, --parse, --check, --transpile, --run, --watch, --fmt, --fmt-check, --doc, --manifest, --cyclonedx, --spdx, --vex, --provenance, --wasm, --wasm --component, --prefer-wasm, init, lsp, repl
  • Project scaffolding via capa init
  • REPL (capa repl): every standard capability pre-bound, multi-line if/for/while/match, dot-commands (.exit, .quit, .help, .show, .reset, .types <expr>), stdout-diffing across turns. v2 landed in full: slice A (readline-style line editing + persistent ~/.capa_repl_history), slice B (in-process exec() replacing subprocess, ~100x faster turns on Windows), and slice C (persistent namespace + incremental execution, so bindings persist and side effects fire exactly once). Full re-analysis is retained on each turn deliberately: it costs microseconds and enforces the capability discipline.
  • Watch mode (capa --watch): re-runs on file or imported-module change
  • AST round-trip formatter with comment preservation (v3, default in --fmt), with a v1+v2 line-level fallback for syntactically broken sources. Design doc at docs/formatter-v3-comment-map-design.md.
  • Doc-comment HTML generator (capa --doc) with paragraphs, inline code, fenced code blocks, lists, and a trait section
  • VSCode extension on the Marketplace (syntax highlighting, snippets, bundled LSP client)
  • Language server (LSP): diagnostics, hover, go-to-definition, find-references, document symbols (outline), code actions (Quick Fix for "did you mean?"), rename, completion (keywords + built-ins + module + locals + type-aware methods after .), semantic tokens (type-aware highlighting), documentHighlight (cursor identifier highlighted in-document), foldingRange (gutter +/- for function / type / impl / control-flow bodies), formatting + rangeFormatting (Format Document / Format Selection backed by the v3 formatter). Runs via capa lsp: bundled into the standalone binary (works out of the box), or the optional [lsp] extra on a pip install. One-line config for Helix, Neovim, Zed; a published VSCode extension with a bundled LSP client.

Supply-chain artefacts

  • Audit artefacts: --manifest, --cyclonedx 1.5 SBOM, --spdx 2.3 SBOM, --vex per-function exploitability claims, --provenance SLSA L1 attestation, per-function ineligibility proofs (provably_excluded_capabilities)
  • Eight seed libraries in the signed registry (capa_cli, capa_csv, capa_datetime, capa_hash, capa_http, capa_log, capa_sbom, capa_test), each pinned to a verify_key in the index, with three-layer supply-chain hardening: lockfile SHA pin (catches tag retags) + GPG tag signatures with verify_key pinning (catches account compromise) + SLSA L2 build provenance via Sigstore Rekor (each release fires actions/attest-build-provenance@v1). Consumer side: capa install runs gh attestation verify when a dep declares a verify_key.
  • SBOM and capability audit tooling written in Capa: examples/sbom_diff.capa, examples/sbom_capability_audit.capa, examples/spdx_parser.capa (JSON + tag-value), examples/cyclonedx_parser.capa (incl. services / vulnerabilities + VEX analysis)

Wasm

  • Wasm Component Model backend: capa --wasm --run (core wasm host bridge) and capa --wasm --component --run (Component Model artifact through an external wasmtime.component runtime); capa --wasm --component --output app.wasm produces a standalone Component Model .wasm artifact with the WIT spec embedded. Fully functional for real programs: output is bit-identical with the Python pipeline. Full generics parity (generic structs, sum types, methods, and nested instantiations), trait dispatch (both monomorphic and dynamic multi-impl, with struct and sum impl targets), nested closures, Fun-typed callee inference, and List<Bool> higher-order functions all lower through. pip install -e .[wasm] pulls in wasmtime>=20; the new --prefer-wasm flag (or CAPA_PREFER_WASM=1) makes capa --run try the Wasm backend first with silent fallback to Python.
  • Sound cross-function attenuation on Wasm and the Component Model host: every privileged host import takes a capability handle and enforces the receiver's restriction before the syscall, via host-side capability handle tables. Passing a restrict_to("data") cap to a helper that then tries a denied path is correctly denied at the Wasm runtime, byte-identical to Python.
  • All capabilities run on Wasm with parity: Fs (read / write / exists / is_dir / mkdir / list_dir / allows), Env (get / args / allows), Clock (now_secs / now_monotonic / sleep / allows), Stdio (print / println / eprintln / read_line), Net (get / restrict_to / allows), Random (with_seed / int_range / float_unit, byte-identical seeded output across backends), Db, Proc.
  • Language coverage on Wasm: String.replace / char_at (Option<String>) / index_of (Option<Int>); Map.keys / values; tuples of any arity; range iteration (for i in 0..n); Option / Result higher-order functions (map, and_then, map_err, or_else, ok, err).
  • Generics and traits on Wasm: full generics parity (generic structs, sum types, methods on generic types, and nested generic instantiations) monomorphises through; trait dispatch works both monomorphically and as dynamic multi-impl dispatch over struct and sum impl targets; a trait-typed value flows through a let, function parameter / return, struct field, sum payload, and match binder, then dispatches by dynamic type; trait-typed values are usable inside Option / Result / Map value / List element / tuple component / struct field, and structural equality of trait values is dispatched by type-id wherever they nest. The one remaining limit is deliberate: a trait used as a Map key or a Set element is a precise compile-time error (a sum-typed dynamic value is unhashable on the Python backend, so the two backends cannot agree on a trait key uniformly) rather than a silent divergence.
  • Unsafe is loudly rejected at Wasm emit time (Python-only).

Quality / tests

  • Agda mechanisation of all four soundness theorems for the λcap calculus, lives in proofs/. Capability soundness, attenuation monotonicity, the structural / flow / linear layers each checked by the type-checker in addition to the prose proof in docs/semantics.md.
  • Property-based testing through Phase 4: 50k+ generated programs stress-tested across plain / attenuated / via_helper / consumed call shapes; the Phase 4 strategy lifts the invariant wasm_runtime_classes ⊆ manifest_classes all the way through the Wasm backend.
  • Compile-time benchmarks (benchmarks/compile_bench.py): lex / parse / analyse wallclock measured across three synthetic programs. Baseline on Windows 11 + CPython 3.14: small 10-fn ~3.5 ms, medium 100-fn ~55 ms, large 1000-fn ~450 ms.
  • 3127 unit + end-to-end tests run, green on Ubuntu / macOS / Windows × Python 3.10 / 3.12 / 3.14
  • Soundness-hardening pass (1.2.0): six fixes published as a security advisory, four in the linear / typestate use-once discipline (use-after-consume, anonymous drop, var / re-assignment, partial consume in a match) and two in information-flow control (a declared-@secret field preserves its label on read and on destructure). Every change only rejects more; no previously-rejected program is now accepted.

Public-readiness milestones

The bridge from "working alpha" to "shareable" closed long ago. The repository is public, governance documents are in place, the site is live, and the project has tagged its way from v0.2.0-alpha through v0.8.4-beta to v1.0.0 (the first stable release, 2026-06-03), then on under SemVer to v1.1.0 (2026-06-14), v1.2.0 (2026-06-15), a security-hardening line through to v1.5.1 (2026-06-18), and a further line through to v1.10.0 (2026-06-22) covering full Python/Wasm parity for capability attenuation, per-dependency SLSA provenance verification, and the linearisation of the Wasm backend's String, JSON-serialisation, and JSON-parsing paths.

The road ahead

Design promises still open

EBNF declares but not implemented

Tooling that moves the adoption needle

Wasm Component Model backend

Capa lowers through a typed IR (CIR) into a hand-written WAT emitter and a Component Model packager. The backend exists so a Capa program can ship as a portable, capability-confined .wasm artifact runnable on any wasmtime-component host. Fully functional for real programs: programs run end-to-end via both capa --wasm --run and capa --wasm --component --run with output bit-identical to the Python reference pipeline.

SBOM and supply-chain work

Capa's positioning: a capability-typed language whose distinctive contribution is the integration between the type system and the supply-chain governance stack. The compiler natively emits the artefacts that other capability languages leave to external tools. The roadmap below strengthens exactly that axis.

Help shape the next milestone

Capa is a personal project; it is also an open one. Issues, design discussions, and pull requests are welcome. The fastest way to influence the roadmap is to show up with a real use case.