keel_cli/lib.rs
1//! `keel` — the command-line face of the product (dx-spec §1–2, §5–6).
2//!
3//! Subcommands: [`run`] (dispatch a script into a language front end),
4//! [`init`] (evidence-merged policy generation), [`doctor`] (the honesty
5//! report; `--effective-policy` prints the composed `defaults < packs < user`
6//! policy via [`effective`]), [`status`] (the "what is Keel doing for me" screen),
7//! [`explain`] (the frozen error taxonomy), [`tail`] (the live Tier 1 event
8//! view), [`fsck`] (journal integrity check/repair and retention pruning),
9//! the Tier 2 flow inspectors [`flows`] (list durable flows), [`flows::trace`]
10//! (`keel trace`), and [`replay`] (`keel replay` — a journal-driven dry run of
11//! what a re-entry would substitute vs. re-execute), [`mcp`] (`keel mcp`: the
12//! CLI doubles as an MCP server over stdio whose six tools return the same
13//! bytes as the corresponding `--json` twins), and the Level 2 on-ramp
14//! [`flows_suggest`] (`keel flows suggest`, a replay-safety analysis over
15//! candidate entrypoints), [`flows_add`] (`keel flows add <entrypoint>`,
16//! one-command durability designation), and [`resume`] (`keel flows resume` —
17//! actually re-invoke a resumable flow's recorded entrypoint through
18//! `keel run`).
19//!
20//! Every command obeys the DX invariants: a `--json` twin with byte-deterministic
21//! output (sorted keys, no wall-clock timestamps), and stable exit codes —
22//! [`EXIT_OK`], [`EXIT_FAILURE`], [`EXIT_USAGE`]. The command modules are the
23//! testable core; [`main`](../keel/index.html) is a thin clap front.
24
25pub mod agents_cli;
26pub mod diff;
27pub mod doctor;
28pub mod effective;
29pub mod exec;
30pub mod explain;
31pub mod flows;
32pub mod flows_add;
33pub mod flows_suggest;
34pub mod fsck;
35pub mod init;
36pub mod mcp;
37pub mod record;
38pub mod render;
39pub mod replay;
40pub mod resume;
41pub mod run;
42pub mod scan;
43pub mod sim;
44pub mod status;
45pub mod tail;
46
47mod evidence;
48
49/// Success. The command did what was asked.
50pub const EXIT_OK: i32 = 0;
51/// The underlying program or verb failed (a run's child exited non-zero, an
52/// error surfaced by the report). Distinct from a *usage* problem.
53pub const EXIT_FAILURE: i32 = 1;
54/// A usage or policy error: bad arguments, an unknown error code, an invalid
55/// `keel.toml`. The caller must fix the request or the policy.
56pub const EXIT_USAGE: i32 = 2;
57
58/// A fully rendered command result: the two audiences (`human` prose and the
59/// `json` twin) plus the exit code the process should carry. Commands build one
60/// of these; [`emit`](render::emit) prints the right half and the caller exits.
61#[derive(Debug, Clone)]
62pub struct Rendered {
63 /// Human-facing prose (stdout on success).
64 pub human: String,
65 /// The `--json` twin — byte-deterministic, sorted keys.
66 pub json: serde_json::Value,
67 /// The exit code this result carries.
68 pub exit: i32,
69 /// When true, `human`/`json` are diagnostics and belong on stderr.
70 pub to_stderr: bool,
71}
72
73impl Rendered {
74 /// A success result destined for stdout.
75 pub fn ok(human: impl Into<String>, json: serde_json::Value) -> Self {
76 Self {
77 human: human.into(),
78 json,
79 exit: EXIT_OK,
80 to_stderr: false,
81 }
82 }
83
84 /// Carry a non-success exit code on an otherwise-rendered result.
85 #[must_use]
86 pub fn with_exit(mut self, exit: i32) -> Self {
87 self.exit = exit;
88 self
89 }
90
91 /// Route this result to stderr (diagnostics, error reports).
92 #[must_use]
93 pub fn on_stderr(mut self) -> Self {
94 self.to_stderr = true;
95 self
96 }
97}