product.providers
Every provider the tool has an adapter for — one per template the distribution ships — with the bootstraps this repository's policy renders through it, the client configuration it carries for the shared MCP server, and the hooks the policy wires. The set is the templates; nothing here is a list of vendors.
Every provider the tool has an adapter for — one per template the distribution ships — with the bootstraps this repository's policy renders through it, the client configuration it carries for the shared MCP server, and the hooks the policy wires. The set is the templates; nothing here is a list of vendors.
- query
- behaviorally_verified
- module product
- #product
- #providers
Exposure
Where this one definition is reachable. Absence is explicit: a surface not listed does not carry it.
| surface | as |
|---|---|
| MCP | tool majordomus_providers resource majordomus://product/providers |
| HTTP | GET /api/v1/product/providers operationId product.providers |
| command line | majordomus product providers |
Schemas
The canonical input and output, from the Rust types; the MCP tool schema and the OpenAPI parameters and responses are derived from these.
input · Empty
No properties: the capability takes no input.
JSON Schema
{
"additionalProperties": false,
"description": "No input.",
"title": "Empty",
"type": "object"
}output · ProviderList
| property | type | required | description |
|---|---|---|---|
| count | integer | yes | How many. |
| providers | array | yes | Each, in id order. |
JSON Schema
{
"$defs": {
"BrowserSource": {
"description": "Whether one provider's client drives a browser in the same session as this repository's\nMCP server.\n\nA bridge is the one way a single session both works on a page and reads and changes the\nlive mesh (`docs/MCP.md`, \"Claude in the browser\"). It is a vendor capability like the two\nabove, so it is declared with its citation; whether *this machine* has the bridge is a\ndifferent fact, which preflight reads from the machine and never from here. A browser\nagent of the vendor's own — a side panel that reaches only the vendor's cloud — is not a\nbridge: nothing it does arrives in a session that holds this repository's server.\n\n```\nuse majordomus_cli::share::BrowserSource;\nassert_eq!(serde_json::from_str::<BrowserSource>(\"\\\"bridge\\\"\").unwrap(), BrowserSource::Bridge);\nassert!(serde_json::from_str::<BrowserSource>(\"\\\"extension\\\"\").is_err(), \"one word for it\");\nassert_eq!(BrowserSource::default(), BrowserSource::None, \"undeclared reads as none\");\nassert_eq!(BrowserSource::Bridge.as_str(), \"bridge\");\n```",
"oneOf": [
{
"const": "bridge",
"description": "The client drives a browser through a vendor extension whose tools arrive in the same\nsession as this repository's MCP server.",
"type": "string"
},
{
"const": "none",
"description": "It does not, or not in a session that holds this repository's server.",
"type": "string"
}
]
},
"EpisodeSource": {
"description": "How an episode boundary can be drawn for one provider.\n\nThree words, because three things are true of different providers and collapsing them\ninto \"supported / not supported\" is what let this tool report one provider and stay\nsilent about five others. A provider that fires its own events is not the same as one\nthat fires none but speaks MCP, and neither is the same as one that can do nothing.\n\nThe words are the declaration's own, and a word outside them is refused rather than read\nas `none`:\n\n```\nuse majordomus_cli::share::EpisodeSource;\nlet read: EpisodeSource = serde_json::from_str(\"\\\"connection\\\"\").unwrap();\nassert_eq!(read, EpisodeSource::Connection);\nassert_eq!(EpisodeSource::default(), EpisodeSource::None, \"undeclared reads as none\");\nassert!(serde_json::from_str::<EpisodeSource>(\"\\\"hook\\\"\").is_err(), \"hooks, plural\");\n```",
"oneOf": [
{
"const": "hooks",
"description": "The provider fires its own session events and a hook this tool installs draws the\nboundary from them. The strongest form: it sees a window somebody closed.",
"type": "string"
},
{
"const": "connection",
"description": "The provider fires no session event, but its client attaches to this repository's\nshared MCP server, and the connection is the boundary (ADR 0103).",
"type": "string"
},
{
"const": "none",
"description": "Neither. Nothing can say when this provider's episode began or ended, and the tool\nreports that rather than implying a capability nobody has.",
"type": "string"
}
]
},
"ProductProvider": {
"description": "One provider the tool has an adapter for, discovered from the templates the distribution\nships and decorated with what this repository does with it.",
"properties": {
"bootstraps": {
"description": "The bootstraps this repository's policy renders through it: target, mode, whether\nevery worker loads it.",
"items": {
"$ref": "#/$defs/ProviderBootstrap"
},
"type": "array"
},
"client_config": {
"description": "The client configuration at the repository root that starts the shared MCP server\nfor this provider, when the repository carries it.",
"type": [
"string",
"null"
]
},
"hooks": {
"description": "The enforcement entries of the policy wired by this provider's hooks.",
"items": {
"type": "string"
},
"type": "array"
},
"id": {
"description": "The provider id: the template's file stem.",
"type": "string"
},
"offers": {
"$ref": "#/$defs/ProviderOffers",
"default": {
"browser": "none",
"browser_evidence": "",
"episode": "none",
"episode_evidence": "",
"prompts": "none",
"prompts_evidence": "",
"usage": [],
"usage_evidence": ""
},
"description": "What it can do about the session lifecycle, and where each answer was verified\n(`share/providers.yaml`, ADR 0103). The capability, never the wiring: `hooks` says\nthe vendor fires session events, not that this repository has installed anything to\nreceive them. The other half — what is wired here, and whether driving it produced\nanything — is `majordomus capture status`, which reads this same declaration and\njoins it with the tree. It is not restated here because only the shell tool holds\nthe adapter table and can run a shim, and a second account it could not compute\ncorrectly is worse than one reader more."
},
"scratch_roots": {
"default": [],
"description": "The scratch roots this provider creates checkouts of its own under, as declared:\nthe worktree topology reports a checkout there as a session's scratch checkout and\nnever moves it (ADR 0024).",
"items": {
"type": "string"
},
"type": "array"
},
"title": {
"description": "The name a person knows it by.",
"type": "string"
}
},
"required": [
"id",
"title",
"bootstraps",
"hooks"
],
"type": "object"
},
"PromptSource": {
"description": "Whether the person's raw prompt can be captured below the model for one provider.\n\nThere is no `connection` here and there must not be: an MCP server is handed tool calls,\nnever the prompt that produced them. Prompt capture is provider-specific and the\ndeclaration says so rather than pretending the connection can stand in for it.\n\n```\nuse majordomus_cli::share::PromptSource;\nassert_eq!(serde_json::from_str::<PromptSource>(\"\\\"hook\\\"\").unwrap(), PromptSource::Hook);\nassert!(serde_json::from_str::<PromptSource>(\"\\\"connection\\\"\").is_err(),\n \"no connection can observe a prompt\");\nassert_eq!(PromptSource::default(), PromptSource::None);\n```",
"oneOf": [
{
"const": "hook",
"description": "The provider hands the raw prompt to a command before the model runs.",
"type": "string"
},
{
"const": "none",
"description": "It does not. Nothing this tool can do makes the prompt observable.",
"type": "string"
}
]
},
"ProviderBootstrap": {
"description": "One bootstrap a provider renders.",
"properties": {
"always_loaded": {
"description": "Loaded by every worker without asking.",
"type": "boolean"
},
"mode": {
"description": "`file` or `region`.",
"type": "string"
},
"target": {
"description": "The target file, repository-relative.",
"type": "string"
}
},
"required": [
"target",
"mode",
"always_loaded"
],
"type": "object"
},
"ProviderOffers": {
"description": "What one provider can do about the session lifecycle, and where that was verified.\n\n**Every cell carries its evidence.** A capability asserted with no citation is the defect\nthis type exists to make impossible: before it, a provider absent from a shell table was\nsilently unsupported and a provider present in one was silently capable, and no surface\ncould tell a reader which vendor page either answer came from — `capture status`\nenumerated the one provider that had an adapter and said nothing whatever about the\nother five this distribution declares. The rule\n`project.a-provider-capability-cites-its-evidence` refuses a declaration without one.\n\nA provider that declares nothing is `none` on both axes with empty evidence — the state\nthat rule refuses, so the gap is a finding rather than a silent \"unsupported\":\n\n```\nuse majordomus_cli::share::{EpisodeSource, PromptSource, ProviderOffers};\nlet undeclared = ProviderOffers::default();\nassert_eq!((undeclared.episode, undeclared.prompts), (EpisodeSource::None, PromptSource::None));\nassert!(undeclared.episode_evidence.is_empty() && undeclared.prompts_evidence.is_empty());\nlet generic: ProviderOffers = serde_json::from_value(serde_json::json!({\n \"episode\": \"connection\", \"episode_evidence\": \"ADR 0103\",\n \"prompts\": \"none\", \"prompts_evidence\": \"MCP carries no prompt\",\n})).unwrap();\nassert_eq!(generic.episode, EpisodeSource::Connection);\n```",
"properties": {
"browser": {
"$ref": "#/$defs/BrowserSource",
"default": "none",
"description": "Whether the client drives a browser beside this repository's server. Absent in a\nvalue written before the axis existed, and read as `none` there."
},
"browser_evidence": {
"default": "",
"description": "Where `browser` was verified, on the same terms as `episode_evidence`.",
"type": "string"
},
"browser_host": {
"description": "The native messaging host a bridge registers with the browser, which is how a\nmachine is seen to have it. Declared for a `bridge` only.",
"type": [
"string",
"null"
]
},
"browser_setup": {
"description": "What a person does, once, to install the bridge on a machine, in the vendor's terms.\nDeclared for a `bridge` only.",
"type": [
"string",
"null"
]
},
"episode": {
"$ref": "#/$defs/EpisodeSource",
"description": "How the episode boundary is drawn for this provider."
},
"episode_evidence": {
"description": "Where `episode` was verified: a vendor documentation URL, or the statement that no\nsuch documentation exists and what was searched for it.",
"type": "string"
},
"prompts": {
"$ref": "#/$defs/PromptSource",
"description": "Whether the raw prompt can be captured below the model."
},
"prompts_evidence": {
"description": "Where `prompts` was verified, on the same terms as `episode_evidence`.",
"type": "string"
},
"usage": {
"default": [],
"description": "The official seams through which the provider reports what a session consumed (I3287,\nADR 0213), every one it offers: `none` alone when it offers nothing a receiver could\nread. Empty in a value written before the axis existed, which declares nothing.",
"items": {
"$ref": "#/$defs/UsageSource"
},
"type": "array"
},
"usage_evidence": {
"default": "",
"description": "Where `usage` was verified, on the same terms as `episode_evidence`.",
"type": "string"
}
},
"required": [
"episode",
"episode_evidence",
"prompts",
"prompts_evidence"
],
"type": "object"
},
"UsageSource": {
"description": "One official seam through which a provider reports what a session consumed.\n\nUsage is read only where the provider itself reports it (ADR 0213): an official\nOpenTelemetry export, a protocol notification of the client's own server, or the usage a\nnon-interactive run prints in its structured output. Never a transcript, a proxy, or a\npatched client. `none` is the declared answer for a provider that offers no such seam,\nand it stands alone.\n\n```\nuse majordomus_cli::share::UsageSource;\nassert_eq!(serde_json::from_str::<UsageSource>(\"\\\"otel\\\"\").unwrap(), UsageSource::Otel);\nassert_eq!(serde_json::from_str::<UsageSource>(\"\\\"app-server\\\"\").unwrap(), UsageSource::AppServer);\nassert!(serde_json::from_str::<UsageSource>(\"\\\"transcript\\\"\").is_err(), \"no transcript seam\");\nassert_eq!(UsageSource::StreamJson.as_str(), \"stream-json\");\n```",
"oneOf": [
{
"const": "otel",
"description": "The provider's own OpenTelemetry export, which the person enables.",
"type": "string"
},
{
"const": "app-server",
"description": "A notification of the client's own app server protocol.",
"type": "string"
},
{
"const": "stream-json",
"description": "The usage a non-interactive run reports in its structured (`stream-json`) output.",
"type": "string"
},
{
"const": "none",
"description": "No official seam reports usage.",
"type": "string"
}
]
}
},
"description": "Every provider.",
"properties": {
"count": {
"description": "How many.",
"format": "uint",
"minimum": 0,
"type": "integer"
},
"providers": {
"description": "Each, in id order.",
"items": {
"$ref": "#/$defs/ProductProvider"
},
"type": "array"
}
},
"required": [
"count",
"providers"
],
"title": "ProviderList",
"type": "object"
}Policies
- benchmark
- required — a target on every transport the exposure declares; the cases are the input type's
- cache
- process — up to 2 entries in the process, scoped by the registry fingerprint
Benchmark targets
Derived from the registry for this repository: one requirement per transport, and the cases the input type provides. The whole matrix is on the benchmarks page.