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), [`resume`] (`keel flows resume` —
17//! actually re-invoke a resumable flow's recorded entrypoint through
18//! `keel run`), and [`force`] (`keel flows force` — arm the durable one-shot
19//! KEEL-E033 override, the out-of-process equivalent of `keel exec --force`).
20//!
21//! Every command obeys the DX invariants: a `--json` twin with byte-deterministic
22//! output (sorted keys, no wall-clock timestamps), and stable exit codes —
23//! [`EXIT_OK`], [`EXIT_FAILURE`], [`EXIT_USAGE`]. The command modules are the
24//! testable core; [`main`](../keel/index.html) is a thin clap front.
25
26pub mod agents_cli;
27mod cmd_match;
28pub mod diff;
29pub mod doctor;
30pub mod effective;
31pub mod exec;
32pub mod explain;
33pub mod flows;
34pub mod flows_add;
35pub mod flows_suggest;
36pub mod force;
37pub mod fsck;
38pub mod init;
39pub mod mcp;
40pub mod record;
41pub mod render;
42pub mod replay;
43pub mod resume;
44pub mod run;
45pub mod scan;
46pub mod sim;
47pub mod status;
48pub mod tail;
49
50mod evidence;
51
52/// Success. The command did what was asked.
53pub const EXIT_OK: i32 = 0;
54/// The underlying program or verb failed (a run's child exited non-zero, an
55/// error surfaced by the report). Distinct from a *usage* problem.
56pub const EXIT_FAILURE: i32 = 1;
57/// A usage or policy error: bad arguments, an unknown error code, an invalid
58/// `keel.toml`. The caller must fix the request or the policy.
59pub const EXIT_USAGE: i32 = 2;
60
61/// A fully rendered command result: the two audiences (`human` prose and the
62/// `json` twin) plus the exit code the process should carry. Commands build one
63/// of these; [`emit`](render::emit) prints the right half and the caller exits.
64#[derive(Debug, Clone)]
65pub struct Rendered {
66 /// Human-facing prose (stdout on success).
67 pub human: String,
68 /// The `--json` twin — byte-deterministic, sorted keys.
69 pub json: serde_json::Value,
70 /// The exit code this result carries.
71 pub exit: i32,
72 /// When true, `human`/`json` are diagnostics and belong on stderr.
73 pub to_stderr: bool,
74}
75
76impl Rendered {
77 /// A success result destined for stdout.
78 pub fn ok(human: impl Into<String>, json: serde_json::Value) -> Self {
79 Self {
80 human: human.into(),
81 json,
82 exit: EXIT_OK,
83 to_stderr: false,
84 }
85 }
86
87 /// Carry a non-success exit code on an otherwise-rendered result.
88 #[must_use]
89 pub fn with_exit(mut self, exit: i32) -> Self {
90 self.exit = exit;
91 self
92 }
93
94 /// Route this result to stderr (diagnostics, error reports).
95 #[must_use]
96 pub fn on_stderr(mut self) -> Self {
97 self.to_stderr = true;
98 self
99 }
100}