locode_exec/cli.rs
1//! clap surface (plan §3.1 + the positional-prompt addendum).
2//!
3//! The prompt is the **positional** argument — the field convention (Claude
4//! Code's `-p/--print` is a mode flag with the prompt positional; `codex exec
5//! "…"` likewise), and `locode-exec` is always headless so it needs no mode
6//! flag at all. `-` or omitted → read stdin (Codex's convention).
7
8use std::path::PathBuf;
9
10use clap::{Parser, ValueEnum};
11
12/// Minimal headless runner for the locode engine: one JSON report on stdout
13/// (ADR-0009), diagnostics on stderr, exit code from the run's status.
14#[derive(Parser, Debug)]
15#[command(name = "locode-exec", version, about)]
16pub struct Cli {
17 /// The task prompt. `-` or omitted reads the prompt from stdin.
18 pub prompt: Option<String>,
19
20 /// Workspace root / working directory (the path-jail root). Defaults to
21 /// the current directory.
22 #[arg(long)]
23 pub cwd: Option<PathBuf>,
24
25 /// Harness pack selecting the toolset + system prompt.
26 #[arg(long, value_enum, default_value_t = Harness::Grok)]
27 pub harness: Harness,
28
29 /// Provider wire schema: `anthropic`, `openai-responses`, or `mock`
30 /// (keyless CI) — plus any custom providers the binary registered
31 /// (ADR-0015). Unknown names fail pre-run listing the available set.
32 #[arg(long, env = "LOCODE_API_SCHEMA", default_value = "anthropic")]
33 pub api_schema: String,
34
35 /// Hard ceiling on sample→dispatch turns. **Unlimited when omitted**
36 /// (ADR-0005 amendment — no studied harness caps turns by default).
37 #[arg(long)]
38 pub max_turns: Option<u32>,
39
40 /// stdout contract: `json` = one Report; `stream-json` = Event JSONL;
41 /// `text` = the final message.
42 #[arg(long, value_enum, default_value_t = OutputFormat::Json)]
43 pub output_format: OutputFormat,
44
45 /// Disable the path jail (`PathPolicy::Unrestricted`). The shell's
46 /// timeout/output caps stay on (ADR-0008 amendment).
47 #[arg(long, visible_alias = "yolo")]
48 pub dangerously_skip_permissions: bool,
49
50 /// Strip harness identity sentences from the rendered system prompt
51 /// (A/B contamination control; default = faithful reproduction).
52 #[arg(long)]
53 pub strip_identity: bool,
54}
55
56/// The registered harness packs (a closed set — clap validates and lists them).
57#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
58#[value(rename_all = "kebab-case")]
59pub enum Harness {
60 /// Grok Build's toolset + system prompt (ADR-0012).
61 Grok,
62}
63
64impl Harness {
65 /// The pack name for `locode_core::resolve`.
66 #[must_use]
67 pub fn as_str(self) -> &'static str {
68 match self {
69 Harness::Grok => "grok",
70 }
71 }
72}
73
74/// The stdout artifact selector (ADR-0014; Claude Code's three-way shape).
75#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
76#[value(rename_all = "kebab-case")]
77pub enum OutputFormat {
78 /// One `Report` JSON object (the default).
79 Json,
80 /// The final assistant message only.
81 Text,
82 /// The live JSONL `Event` stream (`init` → `message`… → `result`).
83 StreamJson,
84}