Skip to main content

majordomus_cli/execution/
mod.rs

1//! Executions: watching a capability call that takes longer than a request should be held
2//! open for.
3//!
4//! Nothing here is a second way to do anything. An execution runs a capability of the one
5//! registry, through the one executor, and the only thing it adds is that the call has an
6//! identity, a lifecycle, a stream of typed events and a cancellation flag — so that a
7//! browser, an agent or a terminal can watch it happen instead of waiting for a response.
8//!
9//! ```text
10//!   capability!  ──►  CapabilityRegistry  ──►  Context::execute  ──►  the handler
11//!                            │                        ▲                    │
12//!                            │                        │                    │ Progress
13//!                            └──►  ExecutionEngine ───┘                    ▼
14//!                                        │                          ExecutionEvent
15//!                                        ▼                                 │
16//!                                  ExecutionStore ◄─────────────────────────┘
17//!                                        │
18//!                     ┌──────────────────┼───────────────────┐
19//!                     ▼                  ▼                   ▼
20//!            executions.get      executions.events      the WebSocket
21//!            (HTTP · MCP · CLI)  (HTTP · MCP · CLI)     (the Cockpit)
22//! ```
23//!
24//! The layering is the point, and it runs one way. The domain produces events; the store
25//! keeps and fans them out; a transport renders them. [`crate::http::events`] is an
26//! adapter over this module and contains no execution logic, which is what makes an audit
27//! trail, a notifier or a second protocol something that subscribes rather than something
28//! that has to be threaded through the engine.
29//!
30//! One plane per checkout, not one per process. `majordomus run` executes in its own
31//! process, and when a server already serves the checkout it reports the execution there
32//! ([`ExecutionStore::adopt`], [`ExecutionStore::report`]), so the server's listing, the
33//! Cockpit and the live channel show it with the pid that ran it; a server that stops
34//! hearing from it fails it rather than showing it running for ever. With no server, the
35//! run says on stderr that nothing else can see it. A run never starts a server.
36//!
37//! What it is not: a job system. There is no durable queue, no retry, no schedule and no
38//! execution that outlives the process that accepted it. The store says so — its limits
39//! are typed and its behaviour at each limit is defined — and [`store::Limits`] is where a
40//! durable store would be substituted, because nothing above it names a `Mutex`.
41
42pub mod engine;
43pub mod event;
44pub mod model;
45pub mod redact;
46pub mod sink;
47pub mod store;
48
49pub use engine::{ExecutionEngine, SubmitError};
50pub use event::{EventPayload, ExecutionEvent, PROTOCOL_VERSION};
51pub use model::{
52    Actor, ActorKind, Execution, ExecutionDiagnostic, ExecutionError, ExecutionId, ExecutionState,
53    LogStream, ProgressView, RepositoryRef, StepState, StepView,
54};
55pub use redact::redact;
56pub use sink::Progress;
57pub use store::{
58    AdoptError, CancelOutcome, Delivery, EventPage, ExecutionStore, Filter, Limits, ReportOutcome,
59    Seed, REPORT_HEARTBEAT, REPORT_SILENCE,
60};