mesh.state
The state every linked runtime converges on
What it is
The journal folded. The default `summary` view is bounded whatever the history: sessions and claims counted by standing, each runtime with its liveness, its counts and its newest live claim, the open review requests and the handovers nobody has taken, and the digest two runtimes compare. `view=full` is every session, every claim with its standing (held, released, expired, conflicted with its winner), the advisory overlaps, every handover with who consumed it, every review request with its answers, and every stream's liveness on this runtime's clock. `claims=live`, `after` (a Lamport stamp), `session` and `runtime` narrow either view; the digest is always the whole fold's.
Descriptor
- Canonical id
mesh.state- Module
mesh- Kind
- query
- Stability
- experimental
- Provenance
- declared
- Source
apps/majordomus-cli/src/capability/builtin/mesh.rs- Cache
disabled- Benchmark
required- Tags
- meshcoordinationcooperation
Run
queryProjections
| Interface | As | Where |
|---|---|---|
| MCP tool | majordomus_mesh_state | - |
| MCP resource | not exposed | - |
| HTTP | GET /api/v1/mesh/state | Swagger |
| Command line | not exposed | - |
Schemas
Input · MeshQuery
{
"type": "object",
"additionalProperties": false,
"properties": {
"view": {
"anyOf": [
{
"$ref": "#/$defs/MeshView"
},
{
"type": "null"
}
],
"description": "`summary` (the default) or `full`."
},
"claims": {
"anyOf": [
{
"$ref": "#/$defs/MeshClaimFilter"
},
{
"type": "null"
}
],
"description": "`all` (the default) or `live`: whether ended claims are kept."
},
"after": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0,
"description": "Only sessions, claims and handovers whose latest Lamport stamp is above this. Reviews\nand overlaps carry no stamp of their own and are kept or dropped with their sessions."
},
"session": {
"type": [
"string",
"null"
],
"description": "Only what belongs to this session: its key (`<stream>/<session>`) or its bare id."
},
"runtime": {
"type": [
"string",
"null"
],
"description": "Only what belongs to this runtime: `<node>-<runtime>`, or a node id for every runtime\nof that machine."
},
"kind": {
"anyOf": [
{
"$ref": "#/$defs/MeshKind"
},
{
"type": "null"
}
],
"description": "Only this collection; the others are answered empty."
},
"limit": {
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0,
"description": "At most this many of each collection: the newest by Lamport stamp where it has one,\nkept in the fold's own order."
},
"open": {
"type": [
"boolean",
"null"
],
"description": "Only what is still open: active sessions, live claims, review requests nobody has\nanswered and handovers nobody has taken."
},
"matching": {
"type": [
"string",
"null"
],
"description": "Only what mentions this text, ignoring case: a path, a branch, an issue, a pull\nrequest, a word of an intent or a subject."
}
},
"description": "What a reader asks of the folded state. Every filter narrows; none changes a shape, and\nan input it does not know is refused rather than ignored.\n\n```\nuse majordomus_cli::mesh::page::{ClaimFilter, Query, View};\n\nlet q: Query = serde_json::from_str(r#\"{\"view\":\"full\",\"claims\":\"live\",\"limit\":5}\"#).unwrap();\nassert_eq!(q.view(), View::Full);\nassert_eq!((q.claims, q.limit), (Some(ClaimFilter::Live), Some(5)));\nassert!(serde_json::from_str::<Query>(r#\"{\"views\":\"full\"}\"#).is_err());\n```",
"title": "MeshQuery",
"$defs": {
"MeshView": {
"oneOf": [
{
"type": "string",
"const": "summary",
"description": "Counts, each runtime's newest live claim, the open reviews and the untaken handovers:\nbounded, whatever the history."
},
{
"type": "string",
"const": "full",
"description": "Everything, narrowed only by the filters."
}
],
"description": "How much an answer about the mesh carries. The summary is the default because it is the\nanswer a worker can read whole whatever the mesh's history; the full fold is one word\naway when a reader needs every record.\n\n```\nuse majordomus_cli::mesh::page::View;\n\nassert_eq!(View::default(), View::Summary);\nassert_eq!(serde_json::to_value(View::Full).unwrap(), \"full\");\n```"
},
"MeshClaimFilter": {
"oneOf": [
{
"type": "string",
"const": "all",
"description": "Every claim, ended ones included."
},
{
"type": "string",
"const": "live",
"description": "Only claims that are still live: held, or conflicted and still held."
}
],
"description": "Which claims a full answer keeps: all of them, the ended ones included, or only those\nstill live — the question an executor asks before it takes a lease.\n\n```\nuse majordomus_cli::mesh::page::ClaimFilter;\n\nassert_eq!(ClaimFilter::default(), ClaimFilter::All);\nassert_eq!(serde_json::from_str::<ClaimFilter>(r#\"\"live\"\"#).unwrap(), ClaimFilter::Live);\n```"
},
"MeshKind": {
"oneOf": [
{
"type": "string",
"const": "sessions",
"description": "The sessions."
},
{
"type": "string",
"const": "claims",
"description": "The claims."
},
{
"type": "string",
"const": "overlaps",
"description": "The advisory overlaps."
},
{
"type": "string",
"const": "handovers",
"description": "The handovers."
},
{
"type": "string",
"const": "reviews",
"description": "The review requests."
}
],
"description": "One collection of the folded state, as `kind` names it: a reader that wants only the\nreviews is not sent the claims.\n\n```\nuse majordomus_cli::mesh::page::Kind;\n\nassert_eq!(serde_json::from_str::<Kind>(r#\"\"reviews\"\"#).unwrap(), Kind::Reviews);\nassert!(serde_json::from_str::<Kind>(r#\"\"everything\"\"#).is_err());\n```"
}
}
}Output · MeshStateAnswer
{
"type": "object",
"properties": {
"active": {
"type": "boolean",
"description": "Whether cooperation runs."
},
"view": {
"$ref": "#/$defs/MeshView",
"description": "What the answer carries: `summary` or `full`."
},
"reason": {
"type": [
"string",
"null"
],
"description": "Why not."
},
"summary": {
"anyOf": [
{
"$ref": "#/$defs/MeshSummary"
},
{
"type": "null"
}
],
"description": "The summary, in the summary view: counts, each runtime's newest live claim, the\nopen reviews and the untaken handovers."
},
"state": {
"anyOf": [
{
"$ref": "#/$defs/CooperationState"
},
{
"type": "null"
}
],
"description": "The folded state narrowed by the filters, in the full view; its digest is the whole\nfold's."
},
"streams": {
"type": "array",
"items": {
"$ref": "#/$defs/StreamView"
},
"description": "Every stream's liveness."
}
},
"required": [
"active",
"view",
"streams"
],
"description": "The answer of `mesh.state`.",
"title": "MeshStateAnswer",
"$defs": {
"MeshView": {
"oneOf": [
{
"type": "string",
"const": "summary",
"description": "Counts, each runtime's newest live claim, the open reviews and the untaken handovers:\nbounded, whatever the history."
},
{
"type": "string",
"const": "full",
"description": "Everything, narrowed only by the filters."
}
],
"description": "How much an answer about the mesh carries. The summary is the default because it is the\nanswer a worker can read whole whatever the mesh's history; the full fold is one word\naway when a reader needs every record.\n\n```\nuse majordomus_cli::mesh::page::View;\n\nassert_eq!(View::default(), View::Summary);\nassert_eq!(serde_json::to_value(View::Full).unwrap(), \"full\");\n```"
},
"MeshSummary": {
"type": "object",
"properties": {
"digest": {
"type": "string",
"description": "The whole fold's digest: equal digests, equal state."
},
"sessions": {
"$ref": "#/$defs/MeshSessionCounts",
"description": "Every session by standing."
},
"claims": {
"$ref": "#/$defs/MeshClaimCounts",
"description": "Every claim by standing."
},
"overlaps": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Advisory overlaps between live claims."
},
"runtimes": {
"type": "array",
"items": {
"$ref": "#/$defs/MeshRuntimeSummary"
},
"description": "Each runtime counted, the living first; at most `SUMMARY_LIST`."
},
"runtimes_not_listed": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Runtimes past the list, counted."
},
"open_reviews": {
"type": "array",
"items": {
"$ref": "#/$defs/MeshReviewBrief"
},
"description": "Review requests nobody has answered; at most `SUMMARY_LIST`."
},
"open_reviews_not_listed": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Open reviews past the list, counted."
},
"untaken_handovers": {
"type": "array",
"items": {
"$ref": "#/$defs/MeshHandoverBrief"
},
"description": "Handovers nobody has consumed; at most `SUMMARY_LIST`."
},
"untaken_handovers_not_listed": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Untaken handovers past the list, counted."
}
},
"required": [
"digest",
"sessions",
"claims",
"overlaps",
"runtimes",
"runtimes_not_listed",
"open_reviews",
"open_reviews_not_listed",
"untaken_handovers",
"untaken_handovers_not_listed"
],
"description": "The mesh in an answer a worker reads whole: counts, each runtime, the open reviews and\nthe untaken handovers, every list bounded by `SUMMARY_LIST` with the rest counted.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{ClaimMode, EventBody, Journal, SessionInfo, StreamLiveness};\nuse majordomus_cli::mesh::state::fold;\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::SessionOpened { info: SessionInfo::named(\"s1\", \"claude-code\") })\n .unwrap();\nfor (claim, path) in [(\"c1\", \"apps/a\"), (\"c2\", \"apps/b\")] {\n j.append_own(EventBody::ClaimAcquired { claim: claim.into(), session: \"s1\".into(),\n scope: vec![path.into()], intent: Some(\"work\".into()), mode: ClaimMode::Exclusive,\n issue: Some(\"#1\".into()) }).unwrap();\n}\nj.append_own(EventBody::ClaimReleased { claim: \"c1\".into() }).unwrap();\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nuse majordomus_cli::mesh::page::{summarize, Summary};\n\nlet summary: Summary = summarize(&state, &[]);\nassert_eq!((summary.claims.held, summary.claims.released), (1, 1));\nassert_eq!(summary.digest, state.digest);\n```"
},
"MeshSessionCounts": {
"type": "object",
"properties": {
"active": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Open, on a runtime that beats."
},
"closed": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Closed by their own runtime."
},
"expired": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Never closed, on a runtime that stopped beating."
}
},
"required": [
"active",
"closed",
"expired"
],
"description": "Sessions by standing: how many are active, closed and expired. A count stays the same\nsize however many sessions the mesh has seen, which is why the summary carries counts.\n\n```\nuse majordomus_cli::mesh::page::SessionCounts;\n\nlet none = SessionCounts::default();\nassert_eq!(serde_json::to_value(&none).unwrap(),\n serde_json::json!({ \"active\": 0, \"closed\": 0, \"expired\": 0 }));\n```"
},
"MeshClaimCounts": {
"type": "object",
"properties": {
"held": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Live and, for an exclusive claim, the winner of its scope."
},
"conflicted": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Live, exclusive, and beaten to its scope."
},
"released": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Released by the holder."
},
"expired": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Ended without a release."
}
},
"required": [
"held",
"conflicted",
"released",
"expired"
],
"description": "Claims by standing: held, conflicted, released and expired. Held and conflicted are\nlive; the other two are history, counted rather than listed.\n\n```\nuse majordomus_cli::mesh::page::ClaimCounts;\n\nlet counts = ClaimCounts { held: 2, released: 5, ..ClaimCounts::default() };\nassert_eq!(serde_json::to_value(&counts).unwrap()[\"released\"], 5);\n```"
},
"MeshRuntimeSummary": {
"type": "object",
"properties": {
"runtime": {
"type": "string",
"description": "`<node>-<runtime>`."
},
"liveness": {
"$ref": "#/$defs/StreamLiveness",
"description": "Own, live or expired."
},
"last_beat_ms": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0,
"description": "Milliseconds since its beat last rose, on this runtime's clock."
},
"sessions": {
"$ref": "#/$defs/MeshSessionCounts",
"description": "Its sessions by standing."
},
"claims": {
"$ref": "#/$defs/MeshClaimCounts",
"description": "Its claims by standing."
},
"newest_claim": {
"anyOf": [
{
"$ref": "#/$defs/MeshClaimBrief"
},
{
"type": "null"
}
],
"description": "Its newest live claim."
}
},
"required": [
"runtime",
"liveness",
"sessions",
"claims"
],
"description": "One runtime, counted: its liveness and beat, its sessions and claims by standing, and its\nnewest live claim. The summary lists these, the living runtimes first.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{ClaimMode, EventBody, Journal, SessionInfo, StreamLiveness};\nuse majordomus_cli::mesh::state::fold;\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::SessionOpened { info: SessionInfo::named(\"s1\", \"claude-code\") })\n .unwrap();\nfor (claim, path) in [(\"c1\", \"apps/a\"), (\"c2\", \"apps/b\")] {\n j.append_own(EventBody::ClaimAcquired { claim: claim.into(), session: \"s1\".into(),\n scope: vec![path.into()], intent: Some(\"work\".into()), mode: ClaimMode::Exclusive,\n issue: Some(\"#1\".into()) }).unwrap();\n}\nj.append_own(EventBody::ClaimReleased { claim: \"c1\".into() }).unwrap();\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nuse majordomus_cli::mesh::page::{summarize, RuntimeSummary};\n\nlet summary = summarize(&state, &[]);\nlet runtime: &RuntimeSummary = &summary.runtimes[0];\nassert_eq!((runtime.sessions.active, runtime.claims.held, runtime.claims.released), (1, 1, 1));\n```"
},
"StreamLiveness": {
"oneOf": [
{
"type": "string",
"const": "own",
"description": "This runtime's own current stream."
},
{
"type": "string",
"const": "live",
"description": "Its beat rose within the expiry."
},
{
"type": "string",
"const": "expired",
"description": "Its beat has not risen within the expiry, or was never heard."
}
],
"description": "Whether a stream is speaking now, on this runtime's clock. It is a verdict about a\nstream and not about a link: a runtime reachable only through a relay is alive, and a\nruntime that crashed stops beating for everyone at once. `Own` is kept apart from `Live`\nbecause a runtime's own stream needs no evidence — it is the thing doing the beating.\n\n```\nuse majordomus_cli::mesh::journal::StreamLiveness;\n\nassert!(StreamLiveness::Own.is_alive() && StreamLiveness::Live.is_alive());\nassert!(!StreamLiveness::Expired.is_alive());\nassert_eq!(\n serde_json::to_value(StreamLiveness::Expired).unwrap(),\n serde_json::json!(\"expired\"),\n);\n```"
},
"MeshClaimBrief": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "`<stream>/<claim>`."
},
"session": {
"type": "string",
"description": "The holding session's key."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue it is for."
},
"intent": {
"type": [
"string",
"null"
],
"description": "What it is for, cut to `SUMMARY_TEXT` characters."
},
"paths": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "How many paths it claims."
},
"mode": {
"$ref": "#/$defs/ClaimMode",
"description": "Exclusive or advisory."
},
"acquired_lamport": {
"type": "integer",
"format": "uint64",
"minimum": 0,
"description": "The Lamport stamp of the acquisition."
}
},
"required": [
"key",
"session",
"paths",
"mode",
"acquired_lamport"
],
"description": "One live claim, told briefly: whose it is, what it is for and how many paths it holds,\nwith its intent cut to `SUMMARY_TEXT` characters — enough to know whom to ask.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{ClaimMode, EventBody, Journal, SessionInfo, StreamLiveness};\nuse majordomus_cli::mesh::state::fold;\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::SessionOpened { info: SessionInfo::named(\"s1\", \"claude-code\") })\n .unwrap();\nfor (claim, path) in [(\"c1\", \"apps/a\"), (\"c2\", \"apps/b\")] {\n j.append_own(EventBody::ClaimAcquired { claim: claim.into(), session: \"s1\".into(),\n scope: vec![path.into()], intent: Some(\"work\".into()), mode: ClaimMode::Exclusive,\n issue: Some(\"#1\".into()) }).unwrap();\n}\nj.append_own(EventBody::ClaimReleased { claim: \"c1\".into() }).unwrap();\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nuse majordomus_cli::mesh::page::{summarize, ClaimBrief};\n\nlet summary = summarize(&state, &[]);\nlet newest: &ClaimBrief = summary.runtimes[0].newest_claim.as_ref().unwrap();\nassert_eq!((newest.issue.as_deref(), newest.paths), (Some(\"#1\"), 1));\n```"
},
"ClaimMode": {
"oneOf": [
{
"type": "string",
"const": "exclusive",
"description": "Exclusive: a second exclusive claim meeting this scope is refused while this one\nlives, on every runtime that knows of it."
},
{
"type": "string",
"const": "advisory",
"description": "Advisory: an announcement, like the peer board's. Overlaps are reported, never\nrefused."
}
],
"description": "Whether a claim excludes others or only tells them. Both are useful and they answer\ndifferent questions: an exclusive claim is a worker saying \"do not edit this while I\nam\", an advisory one is saying \"I am here\". Exclusive is the default because a claim\ntaken without a thought about the mode is a claim somebody expects to be respected.\n\n```\nuse majordomus_cli::mesh::journal::ClaimMode;\n\nassert_eq!(ClaimMode::default(), ClaimMode::Exclusive);\nassert_eq!(serde_json::to_value(ClaimMode::Advisory).unwrap(), serde_json::json!(\"advisory\"));\n```"
},
"MeshReviewBrief": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "`<stream>/<review>`."
},
"subject": {
"type": "string",
"description": "What is to be reviewed, cut to `SUMMARY_TEXT` characters."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue."
},
"reviewer": {
"type": [
"string",
"null"
],
"description": "The runtime asked, when one was."
}
},
"required": [
"key",
"subject"
],
"description": "An open review request, told briefly: its key, what is to be reviewed and whom it asks.\nOnly requests nobody has answered are listed in the summary.\n\n```\nuse majordomus_cli::mesh::page::ReviewBrief;\n\nlet brief = ReviewBrief { key: \"s/r1\".into(), subject: \"feature/x\".into(), issue: None,\n reviewer: None };\nassert!(serde_json::to_value(&brief).unwrap().get(\"issue\").is_none(), \"absent, not null\");\n```"
},
"MeshHandoverBrief": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The content digest: what `mesh.handover.consume` takes."
},
"runtime": {
"type": "string",
"description": "`<node>-<runtime>` of the publisher."
},
"branch": {
"type": [
"string",
"null"
],
"description": "The branch it continues."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue it continues."
},
"published_lamport": {
"type": "integer",
"format": "uint64",
"minimum": 0,
"description": "The Lamport stamp of the first publication."
}
},
"required": [
"id",
"runtime",
"published_lamport"
],
"description": "A handover nobody has taken, told briefly: the id `mesh.handover.consume` takes, who\npublished it and what it continues. Its body stays in the full view.\n\n```\nuse majordomus_cli::mesh::page::HandoverBrief;\n\nlet brief = HandoverBrief { id: \"ab12\".into(), runtime: \"n-r\".into(),\n branch: Some(\"feature/x\".into()), issue: None, published_lamport: 7 };\nassert_eq!(serde_json::to_value(&brief).unwrap()[\"branch\"], \"feature/x\");\n```"
},
"CooperationState": {
"type": "object",
"properties": {
"sessions": {
"type": "array",
"items": {
"$ref": "#/$defs/SessionView"
},
"description": "Every session."
},
"claims": {
"type": "array",
"items": {
"$ref": "#/$defs/ClaimView"
},
"description": "Every claim."
},
"overlaps": {
"type": "array",
"items": {
"$ref": "#/$defs/ClaimOverlap"
},
"description": "Advisory overlaps between live claims."
},
"handovers": {
"type": "array",
"items": {
"$ref": "#/$defs/HandoverView"
},
"description": "Every handover."
},
"reviews": {
"type": "array",
"items": {
"$ref": "#/$defs/ReviewView"
},
"description": "Every review request."
},
"opaque_events": {
"type": "integer",
"format": "uint",
"minimum": 0,
"description": "Events of kinds this executable does not interpret."
},
"digest": {
"type": "string",
"description": "32 hex of the SHA-256 of the canonical JSON of everything above."
}
},
"required": [
"sessions",
"claims",
"overlaps",
"handovers",
"reviews",
"opaque_events",
"digest"
],
"description": "The whole folded state, every collection in key order, and its digest: two runtimes\nthat agree print the same digest.\n\nThe digest is the point. Convergence is otherwise a claim nobody can check from one\nmachine; with it, two operators compare one short string and know whether their\nruntimes are looking at the same world. `opaque_events` is the other half of that\nhonesty: events of kinds this executable does not interpret are counted and relayed\nrather than dropped, so a newer peer's traffic is visible instead of silently missing.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{EventBody, Journal, SessionInfo, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, CooperationState};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::SessionOpened { info: SessionInfo::named(\"s1\", \"cli\") }).unwrap();\n\nlet events = j.events();\nlet state: CooperationState = fold(&events, &|_| StreamLiveness::Own);\nassert_eq!(state.digest.len(), 32);\n\n// the same events in another order, and twice over, are the same state\nlet mut shuffled = events.clone();\nshuffled.reverse();\nshuffled.extend(events);\nassert_eq!(fold(&shuffled, &|_| StreamLiveness::Own).digest, state.digest);\n```"
},
"SessionView": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "`<stream>/<session>`: unique across the mesh."
},
"stream": {
"$ref": "#/$defs/StreamId",
"description": "The writing stream."
},
"runtime": {
"type": "string",
"description": "`<node>-<runtime>`."
},
"node": {
"type": "string",
"description": "The node (machine)."
},
"info": {
"$ref": "#/$defs/SessionInfo",
"description": "What the session last said about itself."
},
"state": {
"$ref": "#/$defs/SessionState",
"description": "Its standing."
},
"updated_lamport": {
"type": "integer",
"format": "uint64",
"minimum": 0,
"description": "The Lamport stamp of its latest word."
}
},
"required": [
"key",
"stream",
"runtime",
"node",
"info",
"state",
"updated_lamport"
],
"description": "One session anywhere in the mesh, as the fold sees it: what the session said about\nitself, where it is writing from, and whether it still counts. The key is\n`<stream>/<session>` rather than the session's own id, because two runtimes may both\ncall a session `s1` and the mesh has to hold them apart.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{EventBody, Journal, SessionInfo, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, SessionView};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::SessionOpened { info: SessionInfo::named(\"s1\", \"claude-code\") })\n .unwrap();\n\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nlet view: &SessionView = &state.sessions[0];\nassert!(view.key.ends_with(\"/s1\"), \"qualified by the stream that wrote it: {}\", view.key);\nassert_eq!(view.info.client, \"claude-code\");\nassert_eq!(view.runtime, view.stream.runtime_key());\n```"
},
"StreamId": {
"type": "string",
"description": "One stream: a run of one runtime of one node. `<node 32 hex>-<runtime 16 hex>-<instance\n16 hex>`. The node is the machine's key, the runtime is one checkout's server on that\nmachine, the instance is one process run of that server — so two worktrees on one\nmachine are two streams, and a restart is a new stream of the same runtime.\n\nNumbering events within a stream rather than globally is what makes replication cheap\nand unambiguous: a gap in one stream is visible without coordinating with anyone, and\n`(stream, seq)` identifies an event on every machine that holds it.\n\n```\nuse majordomus_cli::mesh::journal::StreamId;\n\nlet id = StreamId::new(&\"a\".repeat(32), &\"b\".repeat(16), &\"c\".repeat(16)).unwrap();\nassert_eq!(id.node(), \"a\".repeat(32));\nassert_eq!(id.runtime(), \"b\".repeat(16));\n\n// a restart is a new stream, and the same runtime\nlet after = StreamId::new(&\"a\".repeat(32), &\"b\".repeat(16), &\"d\".repeat(16)).unwrap();\nassert_ne!(after, id);\nassert_eq!(after.runtime_key(), id.runtime_key());\n```"
},
"SessionInfo": {
"type": "object",
"properties": {
"session": {
"type": "string",
"description": "The session's id within its stream."
},
"client": {
"type": "string",
"description": "The client: `claude-code`, `codex`, `cli`, ..."
},
"worker": {
"type": [
"string",
"null"
],
"description": "The worker's own name for itself, when it gave one."
},
"intent": {
"type": [
"string",
"null"
],
"description": "What the session says it is doing."
},
"task": {
"type": [
"string",
"null"
],
"description": "The task id (`t-...`) the session works under."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue (`I0001`, `#184`) the work belongs to."
},
"milestone": {
"type": [
"string",
"null"
],
"description": "The milestone the work belongs to."
},
"checkout": {
"type": [
"string",
"null"
],
"description": "The checkout id (a digest, never a path)."
},
"branch": {
"type": [
"string",
"null"
],
"description": "The branch checked out."
},
"head": {
"type": [
"string",
"null"
],
"description": "The commit checked out."
},
"dirty": {
"type": [
"boolean",
"null"
],
"description": "Whether the working tree had uncommitted changes when this was said."
},
"context": {
"type": [
"string",
"null"
],
"description": "The context revision the session works from (a digest the context compiler names)."
}
},
"required": [
"session",
"client"
],
"description": "What a session tells the mesh about itself. Every field is a public fact about work in\nprogress; none is a path on the author's disk, a secret or a credential.\n\nAlmost everything here is optional, and that is the design: a session says what it\nknows, and a field it leaves out is omitted rather than carried empty, so a reader can\ntell \"no task\" from \"a task called nothing\". Opening the same session id again replaces\nthis record, which is how a session that learns its branch later tells the mesh.\n\n```\nuse majordomus_cli::mesh::journal::SessionInfo;\n\nlet mut info = SessionInfo::named(\"s1\", \"claude-code\");\nassert_eq!(info.task, None);\nassert!(serde_json::to_value(&info).unwrap().get(\"task\").is_none(), \"unsaid, not empty\");\n\ninfo.branch = Some(\"feature/mesh-cooperation\".into());\nassert_eq!(serde_json::to_value(&info).unwrap()[\"branch\"], \"feature/mesh-cooperation\");\n```"
},
"SessionState": {
"oneOf": [
{
"type": "string",
"const": "active",
"description": "Open, and its runtime is alive."
},
{
"type": "string",
"const": "closed",
"description": "Closed by its own runtime."
},
{
"type": "string",
"const": "expired",
"description": "Never closed, but its runtime stopped beating: gone, as far as anyone can tell."
}
],
"description": "A session's standing, as every runtime of the mesh reads it. The distinction that\nmatters is between `Closed` and `Expired`: the first is a session that said it was\nfinished, the second one whose runtime stopped beating and can no longer say anything.\nBoth end the session's claims, but only the second is a machine nobody should expect an\nanswer from.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{EventBody, Journal, SessionInfo, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, SessionState};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::SessionOpened { info: SessionInfo::named(\"s1\", \"cli\") }).unwrap();\nassert_eq!(fold(&j.events(), &|_| StreamLiveness::Own).sessions[0].state, SessionState::Active);\n\n// the same events, read on a runtime that no longer hears the writer\nlet gone = fold(&j.events(), &|_| StreamLiveness::Expired);\nassert_eq!(gone.sessions[0].state, SessionState::Expired);\n```"
},
"ClaimView": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "`<stream>/<claim>`."
},
"stream": {
"$ref": "#/$defs/StreamId",
"description": "The writing stream."
},
"runtime": {
"type": "string",
"description": "`<node>-<runtime>`."
},
"session": {
"type": "string",
"description": "The holding session's key."
},
"scope": {
"type": "array",
"items": {
"type": "string"
},
"description": "The claimed paths."
},
"intent": {
"type": [
"string",
"null"
],
"description": "What it is for."
},
"mode": {
"$ref": "#/$defs/ClaimMode",
"description": "Exclusive or advisory."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue it is for."
},
"acquired_lamport": {
"type": "integer",
"format": "uint64",
"minimum": 0,
"description": "The Lamport stamp of the acquisition."
},
"acquired_seq": {
"type": "integer",
"format": "uint64",
"minimum": 0,
"description": "The sequence of the acquisition within its stream: with the stamp and the stream,\nthe total order in which exclusivity is decided."
},
"state": {
"$ref": "#/$defs/ClaimState",
"description": "Its standing."
}
},
"required": [
"key",
"stream",
"runtime",
"session",
"scope",
"mode",
"acquired_lamport",
"acquired_seq",
"state"
],
"description": "One claim anywhere in the mesh: who took what, for what, and where it stands. The\nacquisition's Lamport stamp and sequence are carried rather than derived on demand,\nbecause they are what exclusivity is decided by — every runtime ranks two competing\nclaims by the same triple and so names the same winner, with no message passing and no\n\"last packet wins\".\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{ClaimMode, EventBody, Journal, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, ClaimState, ClaimView};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::ClaimAcquired { claim: \"c1\".into(), session: \"s1\".into(),\n scope: vec![\"apps/majordomus-cli\".into()], intent: Some(\"document the mesh\".into()),\n mode: ClaimMode::Exclusive, issue: Some(\"#184\".into()) }).unwrap();\n\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nlet claim: &ClaimView = &state.claims[0];\nassert_eq!(claim.scope, [\"apps/majordomus-cli\"]);\nassert_eq!(claim.state, ClaimState::Held);\nassert!(claim.acquired_lamport > 0, \"the order exclusivity is decided in\");\n```"
},
"ClaimState": {
"oneOf": [
{
"type": "object",
"properties": {
"state": {
"type": "string",
"const": "held"
}
},
"required": [
"state"
],
"description": "Live; for an exclusive claim, the winner of its scope."
},
{
"type": "object",
"properties": {
"state": {
"type": "string",
"const": "released"
}
},
"required": [
"state"
],
"description": "Released by its holder."
},
{
"type": "object",
"properties": {
"state": {
"type": "string",
"const": "expired"
},
"detail": {
"type": "string"
}
},
"required": [
"state",
"detail"
],
"description": "Ended without a release: the holder's session closed or its runtime expired."
},
{
"type": "object",
"properties": {
"state": {
"type": "string",
"const": "conflicted"
},
"detail": {
"type": "string"
}
},
"required": [
"state",
"detail"
],
"description": "Live, exclusive, and beaten to its scope by the claim whose key this names."
}
],
"description": "A claim's standing, and — where it ended or lost — what ended it. The two variants that\ncarry a string exist because the bare verdict is not actionable: a worker told its claim\nexpired needs to know whether its session closed or its runtime stopped beating, and one\ntold its claim is conflicted needs the key of the claim that beat it, which is the same\nkey on every runtime.\n\n```\nuse majordomus_cli::mesh::state::ClaimState;\n\nassert!(ClaimState::Held.is_live());\nassert!(ClaimState::Conflicted(\"s/c1\".into()).is_live(), \"still held, and not the winner\");\nassert!(!ClaimState::Released.is_live());\n\n// the detail travels with the verdict, so a reader is never left asking who won\nlet value = serde_json::to_value(ClaimState::Conflicted(\"s/c1\".into())).unwrap();\nassert_eq!(value[\"state\"], \"conflicted\");\nassert_eq!(value[\"detail\"], \"s/c1\");\n```"
},
"ClaimOverlap": {
"type": "object",
"properties": {
"first": {
"type": "string",
"description": "The earlier claim's key."
},
"second": {
"type": "string",
"description": "The later claim's key."
},
"paths": {
"type": "array",
"items": {
"type": "array",
"prefixItems": [
{
"type": "string"
},
{
"type": "string"
}
],
"minItems": 2,
"maxItems": 2
},
"description": "The paths that meet, as `first ↔ second` pairs."
}
},
"required": [
"first",
"second",
"paths"
],
"description": "Two live claims of different sessions whose scopes meet, at least one advisory:\nreported, never refused.\n\nAn overlap is information, not a verdict — it is how two workers find out they are in\nthe same place without either being stopped. The meeting paths are listed pairwise\nrather than summarized, because the useful question is which path of mine meets which\npath of theirs.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{ClaimMode, EventBody, Journal, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, ClaimOverlap};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nfor (claim, session, mode) in [\n (\"c1\", \"s1\", ClaimMode::Exclusive),\n (\"c2\", \"s2\", ClaimMode::Advisory),\n] {\n j.append_own(EventBody::ClaimAcquired { claim: claim.into(), session: session.into(),\n scope: vec![\"apps\".into()], intent: None, mode, issue: None }).unwrap();\n}\n\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nlet overlap: &ClaimOverlap = &state.overlaps[0];\nassert_ne!(overlap.first, overlap.second, \"two claims, two sessions\");\nassert_eq!(overlap.paths, [(\"apps\".to_string(), \"apps\".to_string())]);\n```"
},
"HandoverView": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The content digest."
},
"stream": {
"$ref": "#/$defs/StreamId",
"description": "The stream that first published it."
},
"runtime": {
"type": "string",
"description": "`<node>-<runtime>` of the publisher."
},
"published_lamport": {
"type": "integer",
"format": "uint64",
"minimum": 0,
"description": "The Lamport stamp of the first publication."
},
"handover": {
"$ref": "#/$defs/HandoverBody",
"description": "The record's facts and body."
},
"consumed_by": {
"type": "array",
"items": {
"type": "string"
},
"description": "Every session that consumed it, by key, in Lamport order."
}
},
"required": [
"id",
"stream",
"runtime",
"published_lamport",
"handover",
"consumed_by"
],
"description": "A handover anywhere in the mesh, with everyone who has taken it. The id is the digest\nof the body, so the same handover published twice — by a retry, or by two runtimes that\nboth saw it — is one handover here; and `consumed_by` is what keeps two workers from\nsilently picking up the same continuity, since the list is folded from events every\nruntime holds.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{EventBody, HandoverBody, Journal, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, HandoverView};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nlet body = \"# Objective\\nship\\n\".to_string();\nlet handover = HandoverBody { id: HandoverBody::digest_of(&body), task: None, issue: None,\n milestone: None, branch: Some(\"feature/x\".into()), head: None, created_at: None,\n name: None, body };\nlet id = handover.id.clone();\nj.append_own(EventBody::HandoverPublished { handover }).unwrap();\nj.append_own(EventBody::HandoverConsumed { handover: id.clone(), session: \"s1\".into() })\n .unwrap();\n\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nlet view: &HandoverView = &state.handovers[0];\nassert_eq!(view.id, id, \"identified by what it says, not by who said it\");\nassert_eq!(view.consumed_by.len(), 1, \"somebody has picked this one up\");\n```"
},
"HandoverBody": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The content digest (32 hex): the same handover published twice is one handover."
},
"task": {
"type": [
"string",
"null"
],
"description": "The task the handover closes or continues."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue it belongs to."
},
"milestone": {
"type": [
"string",
"null"
],
"description": "The milestone it belongs to."
},
"branch": {
"type": [
"string",
"null"
],
"description": "The branch it was written on."
},
"head": {
"type": [
"string",
"null"
],
"description": "The commit it was written at."
},
"created_at": {
"type": [
"string",
"null"
],
"description": "When it was written, RFC 3339, as its author's clock said."
},
"name": {
"type": [
"string",
"null"
],
"description": "The record's file name at its origin, informational."
},
"body": {
"type": "string",
"description": "The Markdown body (`# Objective`, `# Current State`, `# Next Action`, ...)."
}
},
"required": [
"id",
"body"
],
"description": "A handover as the mesh carries it: the record's facts and its body, bounded.\n\nWhat travels is the writing, plus the few facts that let a receiver file it — the task,\nthe issue, the branch, the commit. No path of the author's disk is among them, because\nthe checkout that reads this is somewhere else and a path from another machine is at\nbest noise. Identity is the digest of the body, so a handover published twice by a\nretry or by two runtimes is one handover everywhere.\n\n```\nuse majordomus_cli::mesh::journal::HandoverBody;\n\nlet body = \"# Objective\\nship the mesh\\n\".to_string();\nlet handover = HandoverBody {\n id: HandoverBody::digest_of(&body),\n task: Some(\"t-1\".into()),\n issue: Some(\"#184\".into()),\n milestone: None,\n branch: Some(\"feature/mesh-cooperation\".into()),\n head: None,\n created_at: None,\n name: None,\n body,\n};\nassert_eq!(handover.id, HandoverBody::digest_of(&handover.body));\n\nlet wire = serde_json::to_value(&handover).unwrap();\nassert!(wire.get(\"milestone\").is_none(), \"what it does not say is omitted\");\n```"
},
"ReviewView": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "`<stream>/<review>`."
},
"session": {
"type": "string",
"description": "The requesting session's key."
},
"subject": {
"type": "string",
"description": "What is to be reviewed."
},
"scope": {
"type": "array",
"items": {
"type": "string"
},
"description": "Paths it covers."
},
"issue": {
"type": [
"string",
"null"
],
"description": "The issue."
},
"reviewer": {
"type": [
"string",
"null"
],
"description": "The runtime asked, when one was."
},
"body": {
"type": [
"string",
"null"
],
"description": "What the reviewer needs beyond the subject, when the requester wrote it."
},
"state": {
"$ref": "#/$defs/ReviewState",
"description": "Its standing."
},
"answers": {
"type": "array",
"items": {
"$ref": "#/$defs/ReviewAnswer"
},
"description": "The answers, in Lamport order."
},
"result": {
"type": [
"string",
"null"
],
"description": "The requester's own result or reason, written when it withdrew the request. Never an\nanswer: a review is another session's verdict."
}
},
"required": [
"key",
"session",
"subject",
"scope",
"state",
"answers"
],
"description": "One review request anywhere in the mesh, with every answer it has drawn. A request with\nno `reviewer` is an offer to the whole mesh rather than to nobody, which is why the\nanswers are a list: any linked runtime carrying the `reviews` feature may add one, and\nthey are kept in Lamport order so that every runtime reads them in the same sequence.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{EventBody, Journal, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, ReviewView};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::ReviewRequested { review: \"r1\".into(), session: \"s1\".into(),\n subject: \"feature/mesh-cooperation\".into(), scope: vec![\"src/mesh\".into()],\n issue: Some(\"#184\".into()), reviewer: None, body: None }).unwrap();\nlet request = fold(&j.events(), &|_| StreamLiveness::Own).reviews[0].key.clone();\nj.append_own(EventBody::ReviewAnswered { request, session: \"s2\".into(),\n verdict: \"approved\".into(), note: Some(\"reads well\".into()) }).unwrap();\n\nlet state = fold(&j.events(), &|_| StreamLiveness::Own);\nlet review: &ReviewView = &state.reviews[0];\nassert_eq!(review.subject, \"feature/mesh-cooperation\");\nassert_eq!(review.reviewer, None, \"offered to the mesh, not addressed\");\nassert_eq!(review.answers[0].verdict, \"approved\");\n```"
},
"ReviewState": {
"oneOf": [
{
"type": "string",
"const": "open",
"description": "Nobody has answered."
},
{
"type": "string",
"const": "answered",
"description": "At least one answer."
},
{
"type": "string",
"const": "withdrawn",
"description": "The runtime that asked ended the request: done, void or superseded. Whatever was\nanswered before stays with it."
},
{
"type": "string",
"const": "expired",
"description": "Nobody answered and the runtime that asked stopped beating. A reading of liveness,\nlike a claim's expiry, decided from the journal and the streams' beats so that no\nruntime needs another's clock — a runtime that beats again reads open again."
}
],
"description": "A review request's standing: whether anybody has answered it yet. There is deliberately\nno `Approved` or `Rejected` here — a request may be answered by several runtimes and the\nverdicts are the answers' own, so collapsing them into one state would throw away the\ndisagreement that makes a second reviewer worth asking.\n\n```\nuse std::sync::Arc;\nuse majordomus_cli::mesh::identity::NodeIdentity;\nuse majordomus_cli::mesh::journal::{EventBody, Journal, StreamLiveness};\nuse majordomus_cli::mesh::state::{fold, ReviewState};\n\nlet j = Journal::open(Arc::new(NodeIdentity::ephemeral().unwrap()), \"0000000000000001\",\n \"repo\".into(), None).unwrap();\nj.append_own(EventBody::ReviewRequested { review: \"r1\".into(), session: \"s1\".into(),\n subject: \"feature/x\".into(), scope: vec![], issue: None, reviewer: None, body: None }).unwrap();\nlet asked = fold(&j.events(), &|_| StreamLiveness::Own);\nassert_eq!(asked.reviews[0].state, ReviewState::Open);\n\nlet request = asked.reviews[0].key.clone();\nj.append_own(EventBody::ReviewAnswered { request, session: \"s2\".into(),\n verdict: \"approved\".into(), note: None }).unwrap();\nassert_eq!(fold(&j.events(), &|_| StreamLiveness::Own).reviews[0].state, ReviewState::Answered);\n```"
},
"ReviewAnswer": {
"type": "object",
"properties": {
"session": {
"type": "string",
"description": "The answering session's key."
},
"verdict": {
"type": "string",
"description": "The verdict."
},
"note": {
"type": [
"string",
"null"
],
"description": "The note."
}
},
"required": [
"session",
"verdict"
],
"description": "One answer to a review request: who answered, what they decided, and why. The verdict\nis one of the three declared words, so a requester can act on it without reading the\nnote; the note is where the reasoning goes and is optional, because \"approved\" often\nneeds none.\n\n```\nuse majordomus_cli::mesh::state::ReviewAnswer;\n\nlet answer = ReviewAnswer {\n session: \"a1b2c3d4-r1-0f/s2\".into(),\n verdict: \"changes_requested\".into(),\n note: Some(\"the fold is not deterministic\".into()),\n};\nassert_eq!(answer.verdict, \"changes_requested\");\n\n// the note is omitted rather than carried empty when there is nothing to say\nlet bare = ReviewAnswer { note: None, ..answer };\nlet value = serde_json::to_value(&bare).unwrap();\nassert!(value.get(\"note\").is_none());\n```"
},
"StreamView": {
"type": "object",
"properties": {
"stream": {
"$ref": "#/$defs/StreamId",
"description": "The stream."
},
"liveness": {
"$ref": "#/$defs/StreamLiveness",
"description": "Own, live or expired."
},
"last_beat_ms": {
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0,
"description": "Milliseconds since its beat rose."
}
},
"required": [
"stream",
"liveness"
],
"description": "One stream's liveness."
}
}
}Examples
These are the capability's own benchmark cases: the same inputs the benchmark runs and the OpenAPI document shows.
summary
{}full
{
"view": "full"
}