Skip to content

A capability of the Rust executable is declared once and composed into its module, the root composes modules, and the registry refuses a capability outside its module's namespace

Adding an executable capability is one capability! block in the file of the module it belongs to, with its typed input and output and the input's benchmark cases. The module's module() lists its capabilities; compose_modules! at the root lists the modules and nothing else. MCP, HTTP, OpenAPI, Swagger UI, the command line, the benchmark targets, the cache behaviour, the generated reference and the registry manifest follow from the block; no other file changes. A capability whose id namespace is not its module, a module composed twice, an invalid module id, a cache policy that keeps nothing, a cached command or a benchmark policy that contradicts the kind stops the registry from building, with the id and the provenance named.

declared statusdeclared status: guaranteed Declared deterministic and blocking, implemented, and naming the behavioural test that is to prove it. Whether a recorded run supports it is the evidence verdict, shown beside it.

recorded evidencerecorded evidence: not run Declared guaranteed, and not supported by a recorded run: the test is named, and no passing run of the current inputs is recorded. how evidence is recorded

capability!, module! and compose_modules! build plain values handed to the registry builder; adding a capability to an existing module touches that module's file alone, and MCP, HTTP, OpenAPI, Swagger UI, the CLI, the benchmark targets, the cache and the generated reference follow. The crate's tests/registry.rs holds the invariants, tests/projections.rs the propagation.

What it means

Adding an executable capability is one capability! block in the file of the module it belongs to, with its typed input and output and the input's benchmark cases. The module's module() lists its capabilities; compose_modules! at the root lists the modules and nothing else. MCP, HTTP, OpenAPI, Swagger UI, the command line, the benchmark targets, the cache behaviour, the generated reference and the registry manifest follow from the block; no other file changes. A capability whose id namespace is not its module, a module composed twice, an invalid module id, a cache policy that keeps nothing, a cached command or a benchmark policy that contradicts the kind stops the registry from building, with the id and the provenance named.

How it works

apps/majordomus-cli/src/capability/handler.rs holds capability!, which builds the descriptor (id, kind, title, description, schemas from the types, provenance, exposure, stability, tags, benchmark and cache policy) with its handler and the input type's case provider; capability/module.rs holds module! and compose_modules!, plain macro_rules! that build values; capability/builtin/mod.rs is the one root composition; capability/registry.rs keeps the modules (composed, derived from a namespace, or one per declarative kind) and enforces the invariants at build time, before anything serves.

How to see it

apps/majordomus-cli/target/debug/majordomus capabilities validate      # OK   modules … every executable composed in the module its namespace names
apps/majordomus-cli/target/debug/majordomus capabilities describe objects.search --format json | jq '{module, kind, cache, benchmark}'
sed -n '/compose_modules!/p' apps/majordomus-cli/src/capability/builtin/mod.rs

What it does not cover

The shell tool's commands are not capabilities of the Rust executable and keep their own registry (share/commands.yaml). Declarative objects are composed by the repository through sources.yaml, not by a Rust module; their module is their kind. A new module still needs one name in compose_modules!: that is the one manual composition, and it is a module, never a capability.

Why it exists

The operator's invariant: one canonical declaration, modules compose capabilities, the root composes modules, projections derive everything else. ADR 0004 records it; project.rust-canonical-declaration is the rule. apps/majordomus-cli/tests/registry.rs proves the module invariants, tests/projections.rs that a change to one descriptor reaches every projection, tests/bench.rs that it reaches the benchmark targets, and test/cases/91_canonical_architecture.sh reads the registry, the generated files and the live executable back against each other in a repository init wrote.

Detail rendered from docs/claims/capability-modules.md.

From the statement to the proof

  1. 1 · the public statement

    A capability of the Rust executable is declared once and composed into its module, the root composes modules, and the registry refuses a capability outside its module's namespace

    No feature or README responsibility names it; this page is where it is stated.

  2. 2 · the canonical claim

    capability-modulesdeclared status: guaranteed in docs/CLAIMS.yaml

    Defined in read it on this site · docs/CAPABILITIES.md

  3. 3 · the implementation

    apps/majordomus-cli/src/capability/module.rs

  4. 4 · the test and the scenarios

    Test: apps/majordomus-cli/tests/registry.rs

    Executed in Extend what the executable serves by adding a file, never by rebuilding it.

  5. 5 · the recorded runs

    recorded evidence: not run how evidence is recorded

Verify it yourself

The test runs in a disposable temporary repository and asserts the behaviour, not a string in the source.

from a clone of the repository
bash test/run.sh apps/majordomus-cli/tests/registry.rs

Searches the titles and descriptions of every page this site publishes.