Skip to content

HTTP API: observatory

What the Observatory may carry to a place where no mesh runs: the mesh scenes this process has live, pseudonymized for publication, and the recording the repository carries, which the published Observatory replays and labels as a replay.

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.

observatory

What the Observatory may carry to a place where no mesh runs: the mesh scenes this process has live, pseudonymized for publication, and the recording the repository carries, which the published Observatory replays and labels as a replay.

GET /api/v1/observatory/capture observatory.capture

Observatory capture

The mesh scenes of the Observatory as this process has them live, fit for publication: machines, runtimes, sessions and events by ordinal, an event by its kind, logical clock and time only. Writes nothing; committing the answer to .ai/repo/observatory/recording.json is what publishes it.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_observatory_capture

No parameters.

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/observatory/capture"

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 ObservatoryRecording Observatory capture: 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/observatory/events observatory.events

Observatory events

The events of the mesh journal above a cursor, as the Observatory's activity scene draws them: identity, kind, node, logical clock and time, newest first, at most a page. The answer's cursor is the next request's `after`; a cursor this journal never reached is expired, and the reader takes a fresh projection. Without a cursor, the newest page.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_observatory_events

Query parameters

nametyperequireddescriptionexamples
after integer (uint64) no The cursor: only events whose logical clock is above it. Absent is the newest page. after a cursor: 0
limit integer (uint64) no At most this many (default 200, at most 1000). after a cursor: 50

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/observatory/events?after=0&limit=50"

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 ObservatoryEvents Observatory events: 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/observatory/replay observatory.replay

Observatory replay

The recording of the mesh scenes the repository carries at .ai/repo/observatory/recording.json, which the Observatory draws, labelled as a replay, where no mesh runs. Absent is present: false; a file that cannot be read is an error.

  • query
  • behaviorally_verified
  • benchmark required
  • cache disabled
  • MCP tool majordomus_observatory_replay

No parameters.

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/observatory/replay"

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 ObservatoryReplay Observatory replay: 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.

ObservatoryEvents

object
The Observatory's events above a cursor, as the activity scene draws them.

use majordomus_cli::capability::builtin::observatory::ObservatoryEvents;
let e: ObservatoryEvents = serde_json::from_value(serde_json::json!({
    "active": true, "after": 9, "cursor": 12, "expired": false, "events": [{ "id": "s:3" }],
})).unwrap();
assert!(e.cursor > e.after.unwrap(), "the next request resumes past what was read");
propertytyperequireddescription
active boolean yes Whether a mesh runs in this process; without one there is no journal to follow.
after integer | null no The cursor that was asked, when one was.
cursor integer (uint64) yes The cursor to ask next: the logical clock of the newest event read, or the journal's newest clock when the cursor had expired.
expired boolean yes The cursor names a clock this journal never reached (another runtime's journal, or one that restarted): nothing above it can be read, and the reader takes a fresh projection.
events array of any yes The events above the cursor, newest first, as marks: identity, kind, node, logical clock and time, never a body.

Used by observatory.events

ObservatoryRecording

object
The mesh scenes of one process at one moment, fit for publication.

use majordomus_cli::capability::builtin::observatory::ObservatoryRecording;
let r: ObservatoryRecording = serde_json::from_value(serde_json::json!({
    "schema": "observatory-recording/v1", "recorded_at": "2026-10-14T05:00:00Z", "scenes": {},
    "manifest": { "sources": [], "removed": [] },
})).unwrap();
assert!(r.scenes.is_empty() && r.revision.is_none());
propertytyperequireddescription
schema string yes RECORDING_SCHEMA.
recorded_at string yes When the scenes were read.
revision string | null no The commit the recording process stood at, short; absent when it could not say.
scenes object yes Each recorded scene's model, by scene id; a scene the process had nothing live for is absent, never empty.
manifest RecordingManifest → RecordingManifest yes What the recording is a record of, and what it leaves out.

Used by observatory.capture ObservatoryReplay

ObservatoryReplay

object
The recording the repository carries, or that it carries none.

use majordomus_cli::capability::builtin::observatory::{replay_at, ObservatoryReplay, RECORDING};
let dir = tempfile::tempdir().unwrap();
let none: ObservatoryReplay = replay_at(dir.path()).unwrap();
assert!(!none.present && none.recording.is_none());
assert_eq!(none.path, RECORDING);
propertytyperequireddescription
present boolean yes Whether the repository carries a recording.
path string yes The file it is read from.
recording ObservatoryRecording | null → ObservatoryRecording no The recording.

Used by observatory.replay

RecordingManifest

object
What a recording is a record of: the capabilities read, the window of events it holds, and what was removed from what they answered, with the reason.

use majordomus_cli::capability::builtin::observatory::RecordingManifest;
let m: RecordingManifest = serde_json::from_value(serde_json::json!({
    "sources": ["mesh.events"], "removed": ["event bodies"],
})).unwrap();
assert!(m.window.is_none(), "a recording that holds no event has no window");
propertytyperequireddescription
sources array of string yes The capabilities whose answers the recorded scenes were projected from.
window RecordingWindow | null → RecordingWindow no The first and last event the recording holds, by time and by logical clock; absent when it holds none.
removed array of string yes Every kind of thing removed before publication, and why.

Used by ObservatoryRecording

RecordingWindow

object
The events a recording holds, from first to last.

use majordomus_cli::capability::builtin::observatory::RecordingWindow;
let w = RecordingWindow { events: 2, from_at: Some(100), to_at: Some(160), from_lamport: Some(9), to_lamport: Some(10) };
assert_eq!(w.to_at.unwrap() - w.from_at.unwrap(), 60, "a minute of the journal");
propertytyperequireddescription
events integer (uint) yes How many events.
from_at integer | null no The earliest event's time, in seconds since the epoch.
to_at integer | null no The latest event's time, in seconds since the epoch.
from_lamport integer | null no The smallest logical clock.
to_lamport integer | null no The largest logical clock.

Used by RecordingManifest

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