Expand description
The session_domain module: the typed session domain, projected.
The module is session_domain and not session because the registry composes builtin
modules and declarative kinds into one namespace, and session is already a kind —
the closed episode records under .ai/repo/sessions/. The registry refuses the
collision rather than letting one shadow the other, which is how this was found: twelve
“module 'session' is composed twice” diagnostics, one per record. The capability ids
carry the module's name; the tool names and routes are the short ones, because a tool
name is a projection and not the identity.
Two capabilities, and deliberately only two.
session.machine answers the lifecycle state machine as data. It exists because the
same machine is currently drawn three times — in docs/CONTINUITY.md, in
lib/session.sh’s comments and in the Cockpit — and three drawings of one machine
drift. The lib/session.sh drawing still had the task guard in it after ADR 0052
removed the guard from the code. The answer here is derived from
crate::session::EpisodeState and crate::session::Transition and from nothing
else, so a transition that is added to the type appears in every surface and a diagram
that disagrees with the code becomes impossible rather than merely discouraged.
session.identity answers the six identities of this checkout, each with the canonical
value this executable computes and each store’s own spelling beside it. It exists
because a forensic read on 2026-09-11 found the repository recorded as an absolute
.git path and as a remote URL, the worktree as an absolute path and as a digest,
and the session as an episode id and as a provider’s UUID — three words over six
things — and no surface anywhere said so.
There is no third episode listing here. episodes.* (the MCP connection’s episode)
and lifecycle.* (session observability) are being added in the same week by two other
workers, and a third projection over the same store would be this subsystem’s own
favourite defect committed by the module written to stop it. What this module adds is
the domain those projections should eventually read from; ADR 0047 records that
repointing as a step of the cutover, not of this change.
use majordomus_cli::capability::builtin::session_domain;
let module = session_domain::module();
let ids: Vec<&str> = module.capabilities.iter().map(|e| e.capability.id.as_str()).collect();
assert_eq!(ids, ["session_domain.machine", "session_domain.identity"]);
// every one of them reads: the domain's write path reaches no surface (ADR 0047)
assert!(module.capabilities.iter().all(|e| e.capability.kind.is_read_only()));Structs§
- Identity
Report - The identities of this checkout: one facet per subject, with a standing note about what a reader must not do with them.
- Machine
Report - The lifecycle machine, with the decision it implements, so that a reader meeting it in a projection can go and read why it is shaped this way.
Constants§
- IDENTITY_
URI - The URI under which
session.identityis read as an MCP resource. - MACHINE_
URI - The URI under which
session.machineis read as an MCP resource.
Functions§
- module
- The module: two read-only capabilities over the typed session domain, declared once and projected to MCP and HTTP from that declaration alone.