Skip to content

What a provider's adapter can do is declared, never observed from the filesystem

What a provider's adapter can do is declared, never observed from the filesystem

majordomus://rule/project.provider-support-is-declared@1active providerssessionscontinuitycapabilities

referenced by

Nothing in the layer names it. Backlinks are derived, so an empty list is an answer rather than an omission.

Rationale

"Does Claude Code fire PreCompact?" has one correct answer and two tempting wrong ones.

Reading the provider's hook directory answers a different question — did somebody run majordomus capture install in this checkout? — and presents the answer as though it were a statement about the provider. A clean clone would be told the provider has no lifecycle at all; a checkout where somebody hand-wrote a shim would be told it has one the tool cannot drive. Both are confidently wrong, which is the failure mode this repository is most often bitten by.

Writing the list into a page, a table or a Rust constant is the second source of truth that goes stale the day an adapter changes. project.providers-are-data already settled this for what a provider is; this rule extends it to what the tool's adapter for it can do, which is the half a surface outside the shell has no other way to learn.

Required behaviour

share/providers.yaml declares, per provider, lifecycle: — the events the adapter drives, in the provider's own vocabulary — and prompt_capture:. A provider with no lifecycle is one the tool ships no lifecycle adapter for; that is a fact, not an omission, and it is reported as itself.

Every surface reads it there. lifecycle.providers in apps/majordomus-cli is the capability, and the Cockpit's Continuity page, GET /api/v1/lifecycle/providers and the MCP tool are its projections. No page, document or generator carries its own list, and no reader stats a hook path to decide the answer.

The adapter table the shell drives — MJ_CAPTURE_LIFECYCLE and MJ_CAPTURE_ADAPTERS in lib/capture.sh — keeps the columns only the shell needs: the shim paths, the configuration file, the payload keys, the environment variable naming the provider session. It is not a second answer to this question; it is the wiring behind the declared one, and the two must agree.

Failure behaviour

test/cases/170_provider_lifecycle_declared.sh reads both halves and fails when they disagree: a provider whose shell adapter drives an event the YAML does not declare, a provider that declares a lifecycle no shell adapter drives, or prompt capture declared where it is not adapted. It runs in the shell-suite gate with every other case, and it has been shown to fail against a deliberately removed event rather than passing regardless.

Verification

bash test/run.sh 170_provider_lifecycle_declared, and curl -s $URL/api/v1/lifecycle/providers | jq '[.providers[] | {id, lifecycle, prompt_capture}]' against a checkout with no provider hooks installed, which must still report the declared events. test/cases/171_session_observability.sh asserts exactly that, in a fixture that carries no provider hook directory at all.

The duplication is deliberate and temporary. ADR 0052 settles the direction — one canonical session domain service in the executable, with the shell an adapter over it — and when lib/capture.sh reads share/providers.yaml instead of carrying its own table, this rule's gate becomes a tautology and can be retired. Until then it is what makes the duplication safe rather than silent.

Where this comes from

canonical file
.ai/repo/rules/project/provider-support-is-declared.v1.md
identity
project.provider-support-is-declared@1
also served as
MCP resource majordomus://rule/project.provider-support-is-declared@1 · majordomus entity show rule/project-provider-support-is-declared-1 · GET /api/v1/entity?uri=majordomus://rule/project.provider-support-is-declared@1
in the Cockpit
/cockpit/objects/rule/project-provider-support-is-declared-1

This page is generated from the file above by scripts/generate-site-data; editing the page changes nothing, editing the file changes every surface. The relations above are edges of docs/generated/graph.json, which the executable writes from the same index.

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