Skip to content

HTTP API: capabilities

The registry seen through itself: every capability with its kind, stability, provenance, exposures, benchmark and cache policy, and one capability in full.

Rendered from docs/generated/openapi.json, which the executable generates from its capability registry and CI refuses stale. The raw document is at /openapi.json; a running server serves the same document at its own /openapi.json and Swagger UI at /swagger.

capabilities

The registry seen through itself: every capability with its kind, stability, provenance, exposures, benchmark and cache policy, and one capability in full.

GET /api/v1/capabilities capabilities.list

List capabilities

Every capability of this executable and this repository, summarised: kind, module, stability, provenance, the projections it declares, its benchmark and cache policy; the schemas are answered by capabilities.describe.

  • query
  • behaviorally_verified
  • benchmark required
  • cache process (max_entries=16)
  • MCP tool majordomus_capabilities
  • $ capabilities list

Query parameters

nametyperequireddescriptionexamples
kind string no Only capabilities of this kind: `query`, `command` or `resource`. queries: "query"
exposure string no Only capabilities exposed through this projection: `mcp`, `http` or `cli`.

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/capabilities?kind=query"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 CapabilityList List capabilities: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/capabilities/projections capabilities.projections

Where each capability is projected

A row per capability with the command line, HTTP route, MCP tool and MCP resource it reaches, whether every exposure it declares is answered by that surface, and the runnable commands no capability claims. Derived from the registry and the clap declaration; nothing is written down.

  • query
  • behaviorally_verified
  • benchmark required
  • cache process (max_entries=8)
  • MCP tool majordomus_projections
  • $ capabilities projections

Query parameters

nametyperequireddescriptionexamples
module string no Only capabilities composed in this module.
unmet boolean no Only the capabilities whose declared exposures are not all answered by their surface. Empty is the closure the rule asks for. all: falseunmet: true

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/capabilities/projections?unmet=false"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 ClosureMatrix Where each capability is projected: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.
GET /api/v1/capability capabilities.describe

Describe one capability

One capability by canonical id: its kind, schemas, provenance, stability, exposures, benchmark and cache policy.

  • query
  • behaviorally_verified
  • benchmark required
  • cache process (max_entries=512)
  • MCP tool majordomus_capability
  • $ capabilities describe

Query parameters

nametyperequireddescriptionexamples
id string yes The canonical id, e.g. `repository.info` or `rule.majordomus.scope-integrity@1`. repository-info: "repository.info"

Try it

The port is whatever the server logged; 8741 is the one it asks for first. The values are the operation's first example.

curl -s "http://127.0.0.1:8741/api/v1/capability?id=repository.info"

Tested by apps/majordomus-cli/tests/http_serve.rs, which replays the route with these values against a server on a real socket.

Responses

statusbodymeaning
200 Capability Describe one capability: the result.
400 ErrorBody invalid_input: The input does not fit the schema: a parameter of the wrong type, an unknown one, or a value the capability rejects.
404 ErrorBody not_found: The input names something the repository does not hold.
500 ErrorBody internal: The capability failed for a reason of its own; the message names it.
default ErrorBody Any other failure the transport reports: 405 method_not_allowed for another method on this path, 400 invalid_input for a body that is not a JSON object.

Schemas

The components only this tag's operations use. Each row is the type's own field, its doc comment the description; a type another page owns links there.

BenchmarkPolicy

one of 3 variants
Whether the capability is a benchmark target. Required is the default and the norm: every executable capability is timed directly and through every transport it is exposed on, with the cases its input type provides.
variant Timed directly and through every exposure; coverage fails without a case.
policy"required"yes
variant Required exactly like Required in a repository where the precondition holds, and reported as inapplicable — never covered, never waived — where it does not. Not a waiver: with the precondition met and no case, the requirement is missing.
preconditionBenchmarkPrecondition → BenchmarkPreconditionyesWhat the repository must hold.
policy"required_when"yes
variant Not timed, for the typed reason; coverage reports it as waived, never as covered.
reasonWaiverReason → WaiverReasonyesWhy.
policy"waived"yes

Used by Capability CapabilitySummary

BenchmarkPrecondition

"plan_holds_an_issue"
What a repository must hold before a conditional benchmark requirement applies to it. Typed, like a waiver's reason, so that the condition is a reviewable statement on the descriptor and never a provider quietly returning nothing.

use majordomus_cli::capability::BenchmarkPrecondition;
let p: BenchmarkPrecondition = serde_json::from_str(r#""plan_holds_an_issue""#).unwrap();
assert_eq!(p, BenchmarkPrecondition::PlanHoldsAnIssue);
  • plan_holds_an_issueThe plan holds at least one issue. A command whose every honest case is a refusal chosen from an issue's own status has no such refusal in a plan with no issue: the only answer there is a lookup miss, which times an error path and is not the operation.

Used by BenchmarkPolicy

CachePolicy

one of 4 variants
Whether, and how, the executor keeps results of this capability. Cache lives in the executor and nowhere else, so MCP, HTTP and the command line share one; the key is the canonical id, the normalised input and the registry fingerprint, so a changed repository never answers from an old entry. The two narrower policies add to the key what the registry fingerprint cannot see: the context's own reading of the repository (CachePolicy::Generation) and the state of the checkout itself (CachePolicy::Checkout).
variant Every call runs the handler.
policy"disabled"yes
variant Results are kept in this process's memory, bounded, for equal inputs.
max_entriesinteger (uint)yesThe most entries kept for this capability; the oldest is evicted first.
ttl_secondsinteger | nullnoSeconds an entry stays valid; None for the life of the process.
policy"process"yes
variant Results are kept for equal inputs while the context that computed them is the one asked: for a capability that is a function of the index and the registry alone, including the git state the index was read at, which the registry fingerprint does not cover. A reload of the repository is a new context, and so a new key.
max_entriesinteger (uint)yesThe most entries kept for this capability; the oldest is evicted first.
policy"generation"yes
variant Results are kept for equal inputs while the context is the same and the checkout is as it was: HEAD, the staging index, the refs and every changed or untracked path of the work tree, fingerprinted again on every call (capability::checkout). For a capability that reads git, the index and the files of the work tree, and nothing that fingerprint cannot see: no ignored file, no other process, no network, no clock. A checkout git cannot fingerprint is not cached.
max_entriesinteger (uint)yesThe most entries kept for this capability; the oldest is evicted first.
policy"checkout"yes

Used by Capability CapabilitySummary

CanonicalSchema

object
A JSON Schema with, when the type has one, a stable component name (the type's title).
propertytyperequireddescription
name string | null no The component name projections use (RepositoryInfo); None for an anonymous schema such as the empty input.
schema any yes The schema itself, without $schema; nested types live under $defs.

Used by Capability

Capability

object
The canonical descriptor. Everything a projection may say about a capability is here.
propertytyperequireddescription
id CapabilityId → CapabilityId yes The canonical identity.
module ModuleId → ModuleId yes The module that composes it: the id's namespace for a builtin, the kind for a declarative object.
kind CapabilityKind → CapabilityKind yes Query, command or resource.
title string yes The short name every projection shows.
description string yes The one-paragraph description every projection shows.
input CanonicalSchema → CanonicalSchema yes The canonical schema of the input; an empty object for a resource.
output CanonicalSchema → CanonicalSchema yes The canonical schema of the output; the object view for a resource.
provenance CapabilityProvenance → CapabilityProvenance yes Where it came from.
exposure Exposure → Exposure yes Where it is projected; absence is explicit.
availability CapabilityAvailability → CapabilityAvailability yes Where it means anything: classified from the kind and the transports above, so that a projection reads a field instead of deciding for itself.
visibility CapabilityVisibility → CapabilityVisibility yes Who it is for: classified from the same transports.
stability Stability → Stability yes Where it stands.
tags array of string no Free tags, from the declarative object's tags or the descriptor.
benchmark BenchmarkPolicy → BenchmarkPolicy yes Whether it is a benchmark target; the cases come from the input type.
cache CachePolicy → CachePolicy yes Whether the executor keeps its results.
execution ExecutionPolicy → ExecutionPolicy yes What running it as an execution means: classified from the kind, so that a client reads a fact rather than deciding for itself.
skill SkillExposure | null → SkillExposure no The short name a person invokes it by from an agent's prompt, when it has one.

Used by capabilities.describe

CapabilityAvailability

"always" | "runtime" | "build_time" | "authenticated"
Where a capability means anything: the environment a caller must be in for it to answer at all.

The published site and the running server are genuinely different places. Without this on the model, every template grows its own idea of what works where — and the usual shape that takes is a condition on the page's own address, which is a rule hidden where nobody will find it and nothing can test it. This is the only thing a projection may ask.

It is classified rather than declared: the facts that decide it — what kind of thing this is and which transports it is projected through — are already on the descriptor, and asking each declaration to restate them would be the same knowledge written twice. Availability::classify is the one place the rule lives.

  • alwaysTrue in every environment, a published page with no server included: the layer's own content, which a build renders and a process serves from the same index.
  • runtimeA process must be running to answer: everything with a handler, whether it is reached over HTTP, over MCP or from the command line.
  • build_timeA value captured when the site was generated, rendered afterwards as the capture it is. Nothing classifies to this yet; the static projection of the graph is what will declare it, and it is on the model so that a captured value can be labelled as captured instead of being shown as current.
  • authenticatedA process must be running and the caller must be one it has authenticated. Nothing in this repository authenticates a caller yet; a surface that does will say so here rather than in the template that renders its link.

Used by Capability

CapabilityList

object
The answer of capabilities.list: the matching capabilities, summarised, and the registry counted.
propertytyperequireddescription
count integer (uint) yes How many capabilities matched the filters.
summary Summary → Summary yes The whole registry, counted by kind, stability and projection.
capabilities array of CapabilitySummary → CapabilitySummary yes The matching capabilities, by id, without their schemas.

Used by capabilities.list

CapabilitySummary

object
One capability as a listing shows it: everything the descriptor says except its two schemas, which capabilities.describe answers for one capability. A listing of a repository's registry runs to hundreds of entries; their schemas would be megabytes of the same object view repeated.
propertytyperequireddescription
id CapabilityId → CapabilityId yes The canonical identity.
module ModuleId → ModuleId yes The module that composes it.
kind CapabilityKind → CapabilityKind yes Query, command or resource.
title string yes The short name.
description string yes The one-paragraph description.
provenance CapabilityProvenance → CapabilityProvenance yes Where it came from.
exposure Exposure → Exposure yes Where it is projected.
stability Stability → Stability yes Where it stands.
tags array of string no Free tags.
benchmark BenchmarkPolicy → BenchmarkPolicy yes Whether it is a benchmark target.
cache CachePolicy → CachePolicy yes Whether the executor keeps its results.

Used by CapabilityList

CapabilityVisibility

"public" | "developer" | "internal"
Who a capability is for, and whether anything offers it.

Internal is a statement, not an omission: a capability nothing projects is invisible either way, and the difference between deliberate and forgotten is exactly what this records.

  • publicOffered to anyone who can reach the process: an HTTP route or an MCP entry.
  • developerOffered to whoever runs the executable, and to nobody over a network.
  • internalProjected nowhere. It exists, it is listed as existing, and no surface offers it.

Used by Capability

CliExposure

object
How a capability appears on the command line: the words after majordomus.
propertytyperequireddescription
path array of string yes The words after majordomus, e.g. ["capabilities", "list"].

Used by Exposure

ClosureMatrix

object
The whole matrix, with the findings and the debt beside it: one value that answers "where does each capability appear, and is any claim unmet".
propertytyperequireddescription
rows array of Row → Row yes One row per capability, in id order.
unbacked array of string yes Runnable commands of the command line that no capability claims, in command order.
unclassified array of string yes Of those, the ones crate::cli::local::LOCAL does not explain either: a command that is neither the projection of a capability nor declared command-line-only with a reason. Empty is the closure the rule asks for; anything here is an operation that left the API by accident rather than by decision.

Used by capabilities.projections

ExecutionConcurrency

"unrestricted" | "serial"
Whether two executions of one capability may overlap.
  • unrestrictedAny number at once. Every read is one of these: the index and the registry are immutable for the life of the process, so concurrent readers cannot interfere.
  • serialOne at a time. A second execution of the same capability waits for the first, which is what a capability that changes anything — this process's own memory included — needs in order to be reasoned about at all.

Used by ExecutionPolicy

ExecutionPolicy

object
What running a capability as an execution means: what it changes, whether asking it to stop achieves anything, and whether two of them may overlap.

The effect and the concurrency are classified from the kind by ExecutionPolicy::classify, for the same reason Availability is: the facts are already on the declaration, and asking each capability! block to restate them would be one more thing that can disagree with itself.

Cancellability is the one thing the kind cannot decide, because it is a fact about the handler: whether it looks at its cancellation flag and stops. A handler that does says so with crate::capability::Executable::cancellable, and a client is then told whether a Cancel button will achieve anything instead of being given one that lies.

propertytyperequireddescription
effect ExecutionEffect → ExecutionEffect yes What it changes.
cancellable boolean yes Whether asking it to stop does anything. A task looks at its cancellation flag; a query and a command do not, and a client is told so rather than being given a button that lies.
concurrency ExecutionConcurrency → ExecutionConcurrency yes Whether two of them may overlap.
signed_input boolean no Whether the input authenticates its caller.

A handler whose input is a signed message, and which verifies the signature against the trust policy before anything changes, admits its caller by that signature and not by the address the request came from. Only such a handler changes state for a caller on another host; see ExecutionPolicy::admits_remote.

Used by Capability

Exposure

object
The projections a capability declares. Absence is explicit: None means not exposed there, and nothing infers an exposure a descriptor did not declare.
propertytyperequireddescription
mcp McpExposure | null → McpExposure no The MCP projection, when declared.
http HttpExposure | null → HttpExposure no The HTTP projection, when declared.
cli CliExposure | null → CliExposure no The command-line projection, when declared.

Used by Capability CapabilitySummary

HttpExposure

object
How a capability appears over HTTP. GET binds every top-level input property as a query parameter; POST binds the input as the JSON request body. Paths are absolute and live under HttpExposure::PREFIX.
propertytyperequireddescription
method HttpMethod → HttpMethod yes The method.
path string yes The absolute path, under HttpExposure::PREFIX.

Used by Exposure

HttpMethod

"GET" | "POST"
The HTTP methods a capability may be bound to.
  • GETRead-only; the input is bound from the query string.
  • POSTThe input is bound from the JSON body. Every mutating capability uses it.

Used by HttpExposure

McpExposure

object
How, if at all, a capability appears to an MCP client.
propertytyperequireddescription
tool string | null no As a tool with this name ([a-z0-9_]+).
resource McpResource | null → McpResource no As a readable resource.

Used by Exposure

McpResource

object
An MCP resource: its URI and the short name a client lists.
propertytyperequireddescription
uri string yes majordomus://<kind>/<identity>, or majordomus://repository.
name string yes The short name a client lists; the identity for a declarative object.

Used by McpExposure

ModuleId

string
A module identity: the namespace of every capability the module composes, matching [a-z][a-z0-9_-]*. Builtin modules declare theirs in module!; a declarative object's module is its kind.

Used by Capability CapabilitySummary

Row

object
Where one capability is projected, and where it is not.

This is the coverage matrix of the rule: a row per capability, a column per interface. It is derived, never written down — a capability that reaches nothing shows as a row of false, which is exactly the "exists but is invisible" case worth seeing.

propertytyperequireddescription
id string yes The canonical id.
module string yes The module that composes it.
kind string yes Query, command or resource.
stability string yes Where it stands.
effect ExecutionEffect → ExecutionEffect yes What a call changes: nothing, this process's memory, or the repository. The same classification every projection reads, so the matrix answers "where is it reachable" and "what does reaching it risk" in one row.
cli string | null no The command line, when it declares one and clap has it.
http string | null no The HTTP route, when it declares one.
mcp_tool string | null no The MCP tool name, when it declares one.
mcp_resource string | null no The MCP resource URI, when it declares one.
closed boolean yes Whether every exposure this row declares is answered by its surface.
source string yes Where the capability is declared; repository-relative.

Used by ClosureMatrix

SkillExposure

object
A capability as a skill a person invokes by a short name from an agent's prompt: /intent <sentence> in Claude Code. The name and the one input field the typed text fills are declared here, once; the file an agent product reads is generated from them (the editors module) and carries no description of what the capability does beyond the capability's own.

use majordomus_cli::capability::SkillExposure;
let s = SkillExposure { alias: "intent".into(), argument: "statement".into() };
assert!(s.validate().is_ok());
// a name an agent product already owns is refused, and so is one that is not a name
let taken = SkillExposure { alias: "review".into(), argument: "x".into() };
assert!(taken.validate().unwrap_err().contains("reserved"));
let shouted = SkillExposure { alias: "Intent".into(), argument: "x".into() };
assert!(shouted.validate().is_err());
propertytyperequireddescription
alias string yes The name typed after the slash: lowercase letters, digits and hyphens, at most 64.
argument string yes The input field the text typed after the name fills, verbatim.

Used by Capability

WaiverReason

"not_executable" | "destructive" | "external_dependency" | "transient_state" | "published_history"
Why an executable capability is not benchmarked. Typed, so that a waiver is a reviewable statement and never a convenience; not_executable is the registry's own reason for resources and is never written by hand.
  • not_executableA resource: read, never executed; nothing to time but objects.get, which is.
  • destructiveThe capability changes something outside this process and cannot be run in a loop.
  • external_dependencyThe capability talks to something the benchmark host cannot provide.
  • transient_stateThe capability starts, or answers about, work that exists only while it is running. A benchmark host cannot stage an execution to read, and running the operation in a loop would measure the work rather than the operation.
  • published_historyThe capability answers about what this repository has published, so its input is a release: a version tag, the commit it points at, and the projection committed there. A benchmark fixture is a repository that has published nothing, and the honest answer in one is a refusal — so the case would time an error path and call it coverage. Distinct from WaiverReason::ExternalDependency: nothing outside this process is consulted, and distinct from WaiverReason::TransientState: the history is durable, it simply does not exist yet where the benchmark runs.

Used by BenchmarkPolicy

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