Skip to main content

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}