CLI Interface Design
Feature Definition
Section titled “Feature Definition”The command-line interface is the primary surface through which users interact with an AI coding agent. It’s also the first place architectural decisions become visible. Every flag, subcommand, and option group is a commitment: it reveals what the tool considers important, how it thinks about workflow, and what internal subsystems exist. A well-designed CLI surface isn’t just UX — it’s a contract that shapes the internal module structure.
The hard problems in CLI design for an AI coding agent are:
- Headless vs interactive duality: Users need both a REPL-style interactive session and a scriptable one-shot mode for CI pipelines, editor integrations, and automation. These modes share state machinery but differ in how they emit output, handle input, and manage lifecycle.
- Server/client separation: Modern AI tools run a background server and attach multiple clients (TUI, web, IDE plugin). The CLI must expose this topology: commands to start a server, commands to attach to a running one, and commands to query server state without a full UI.
- Session continuity: Sessions aren’t ephemeral. Users need to resume, fork, and export them. The CLI surface for session management defines how the persistence layer must work.
- Sandboxing controls: When an AI agent can execute shell commands, users need explicit, visible controls over what it’s allowed to do. These can’t be buried in a config file — they must be first-class CLI flags with clear semantics.
- Provider and model abstraction: Multiple LLM providers, local models, and fallback chains all need to be selectable at the command line without a config file edit, while still respecting layered config.
- Debugging and introspection: Users diagnosing unexpected behavior need to inspect internal state (resolved config, LSP diagnostics, snapshot history, ripgrep file lists) without reading source code.
Aider Implementation
Section titled “Aider Implementation”Aider uses a flat argparse-based CLI defined in references/aider/aider/args.py. There are no subcommands — every option is a flag on the single aider command. Argument groups organize the flags conceptually but don’t create any subcommand hierarchy. This is a deliberate single-process design: Aider doesn’t have a background server.
Key argument groups and what they reveal:
Main model / API Keys — --model, --openai-api-key, --anthropic-api-key, --api-key, --openai-api-base, --openai-api-type, --set-env. Every supported provider is explicit. The --api-key flag is the generic form: --api-key provider=keyvalue.
Model settings — --edit-format, --chat-mode, --architect, --weak-model, --editor-model. This group is where the multi-model architecture surfaces. Aider has named edit formats (diff, udiff, whole, search-replace, editor-diff, editor-whole) that correspond to different coder classes in aider/coders/. The --architect flag activates a two-step flow where one model plans and a separate editor model executes.
--reasoning-effort/--thinking-tokens— expose model-level thinking controls.--max-chat-history-tokens— sets the token budget for rolling chat history before summary/truncation.--cache-prompts/--cache-keepalive-pings— prompt caching controls for providers that support it.
Repomap settings — --map-tokens, --map-refresh, --map-multiplier-no-files. Direct control over the repo mapping subsystem. --map-tokens is the budget; --map-refresh controls when the map is rebuilt (auto, always, files, manual); --map-multiplier-no-files scales the budget up when no files are in context (more map headroom needed).
Git settings — --auto-commits, --dirty-commits, --attribute-author, --attribute-committer, --attribute-commit-message-author, --commit-prompt, --dry-run, --watch-files. Aider’s git integration is deep: it auto-commits after every accepted change, attributes commits to both the user and the AI, and can watch the filesystem for external changes to pull into context.
Fixing and committing — --lint, --lint-cmd, --auto-lint, --test-cmd, --auto-test, --test. Built-in lint and test loop. --auto-lint (default: on) runs configured linters after every edit. --auto-test (default: off) runs tests. Both feed failures back to the model for another pass.
Modes — --message/-m, --message-file/-f, --gui, --apply, --show-repo-map, --show-prompts. This group is what makes Aider scriptable. --message sends a single prompt and exits — headless one-shot mode. --show-repo-map and --show-prompts are debug inspection flags that print internal state and exit; useful for understanding what the model actually sees.
Voice settings — --voice-format (wav|mp3|webm), --voice-language. Aider supports voice input via the microphone.
The flat structure is Aider’s main constraint: adding a new major feature requires adding more global flags, which creates a long help page with everything visible at once. There’s no way to hide experimental or advanced functionality in a subcommand tree. The upside is zero discovery friction — aider --help shows everything.
Codex Implementation
Section titled “Codex Implementation”Codex uses clap in Rust, parsed in codex-rs/cli/src/main.rs. It has a full subcommand tree with deep nesting and a global config override system.
Architecture Revealed by the CLI
Section titled “Architecture Revealed by the CLI”The -c, --config <key=value> pattern is the most important design decision in Codex’s CLI. Every setting in ~/.codex/config.toml is overridable at the command line using TOML dotted path syntax: -c model="gpt-5.2-codex", -c 'sandbox_permissions=["disk-full-read-access"]', -c shell_environment_policy.inherit=all. If TOML parse fails, the raw string is used as a literal fallback. This means there’s no special-case argument for every config key — just one escape hatch that covers everything.
Feature flags as first-class CLI — --enable <FEATURE> and --disable <FEATURE> are available on every command. They map to -c features.<name>=true/false. Features carry explicit stages (for example under development, experimental, stable, deprecated, removed) and can be inspected with codex features list.
Sandbox as non-negotiable surface: Three modes are exposed directly as CLI flags, not buried in config:
read-only— agent can only read.workspace-write— agent can write inside the project.danger-full-access— no isolation.
These map to OS-level enforcement: Landlock+seccomp on Linux, Seatbelt on macOS, restricted token on Windows. The codex sandbox <platform> subcommand lets users test arbitrary commands inside these isolation layers without starting an agent session.
Approval policy as a separate axis from sandbox:
untrusted— run only “safe” commands (ls, cat, sed) without asking; escalate otherwise.on-failure— run everything, ask if a command fails.on-request— model decides when to ask.never— never ask; failures go straight back to the model.
In interactive TUI mode, --full-auto combines on-request approval + workspace-write sandbox. In codex exec (headless), default approval remains never unless explicitly overridden. --dangerously-bypass-approvals-and-sandbox is for CI environments that are externally sandboxed.
Non-interactive exec mode:
codex exec [PROMPT] --json JSONL event stream (machine-readable) --output-schema <FILE> JSON Schema for structured final response --ephemeral don't persist session to disk --skip-git-repo-check run outside a git repo -o, --output-last-message write final agent message to fileThe --json flag emits the same internal event stream the TUI renders, but as JSONL to stdout. --output-schema forces structured JSON output from the model via a JSON Schema constraint — the model’s final response must conform or it retries.
Review mode as a first-class command: codex review is not a prompt template — it’s a distinct CLI entry that accepts --uncommitted (staged+unstaged+untracked), --base <BRANCH> (full branch diff), or --commit <SHA> (single commit review). This is a separate agent mode with different context construction.
Session management:
codex resume [SESSION_ID]— resume interactive session;--lastskips picker;--allshows all sessions regardless of CWD.codex fork [SESSION_ID]— branch a new session from a prior one’s state; same flags.codex apply <TASK_ID>— apply the latest diff from an agent session asgit applyto the working tree. This is the “bring cloud changes local” primitive.
App server / IDE integration:
codex app-server --listen stdio:// | ws://IP:PORT codex app-server generate-ts # TypeScript bindings for the protocol codex app-server generate-json-schema # JSON Schema for the protocolThe generate-ts and generate-json-schema subcommands produce typed protocol definitions from the Rust types — they exist specifically to keep the VSCode extension in sync. --analytics-default-enabled is a flag for first-party integrators (e.g., the VSCode extension) to opt into analytics by default.
Codex as MCP server: codex mcp-server runs Codex itself on stdio as an MCP server. Other tools (editors, agents) can call Codex as a tool provider. This is the inverse of Codex managing external MCP servers.
--no-alt-screen: Runs the TUI in inline mode, preserving scrollback history instead of using an alternate screen buffer. Necessary in Zellij, which follows strict xterm semantics and disables scrollback in alternate screen buffers.
OpenCode Implementation
Section titled “OpenCode Implementation”OpenCode uses yargs (TypeScript), parsed in packages/opencode/src/index.ts. The command tree is wide and shallow: most commands are top-level, with only mcp, debug, auth, agent, session, and github having subcommands.
Architecture Revealed by the CLI
Section titled “Architecture Revealed by the CLI”Every mode is a client to the same server: opencode tui, opencode run, opencode attach, and opencode web all connect to the same Hono HTTP/SSE/WebSocket server. The TUI starts the server internally; opencode serve starts it without a TUI; opencode attach connects to a server that’s already running somewhere. The --port, --hostname, --cors, and --mdns flags appear on every server-starting command because they control that embedded server.
mDNS for LAN discovery: --mdns broadcasts the server on the local network as opencode.local (or a custom --mdns-domain). This lets the opencode attach command find a running instance without hardcoding a port.
The run command as the headless interface:
opencode run [message..] --format default | json # json = raw JSONL event stream --file # attach files --title # session title --attach <url> # attach to existing server instead of starting one --variant # model reasoning variant (high, max, minimal) --thinking # show thinking blocks in output--format json emits the same SSE event bus data the TUI consumes, as JSONL. This is the machine-readable interface for CI, scripts, and editor plugins.
ACP (Agent Client Protocol): opencode acp starts an ACP server — a distinct protocol layer separate from the main HTTP/SSE server. ACP adds --cwd as a flag (sets the working directory for the ACP server instance), which the main commands don’t expose because they derive CWD from the project context.
MCP with OAuth lifecycle: The mcp subcommand tree exposes that OpenCode handles the full OAuth flow for OAuth-enabled MCP servers:
opencode mcp add # add a server (stdio or remote)opencode mcp list # list servers + connection statusopencode mcp auth [name] # run OAuth login for a server opencode mcp auth list # list OAuth-capable servers + auth stateopencode mcp logout [name] # remove OAuth tokensopencode mcp debug <name> # debug OAuth connection issuesThis is not just stdio MCP management — it includes remote StreamableHTTP/SSE transports with OAuth PKCE flows.
Debug tree mirrors internal module boundaries exactly:
opencode debug config # resolved config (all layers merged)opencode debug paths # data/config/cache/state global pathsopencode debug scrap # list all known projectsopencode debug skill # list all available skillsopencode debug lsp ... # LSP diagnostics, workspace symbols, document symbolsopencode debug rg ... # ripgrep tree, files list, pattern searchopencode debug file ... # VFS read, status, list, search, treeopencode debug snapshot ... # snapshot track, patch, diffopencode debug agent <name> # show agent config detailsopencode debug wait # wait indefinitely (for process attachment)The lsp, rg, file, snapshot, agent, and skill namespaces directly correspond to the internal src/lsp/, src/tool/ (ripgrep), src/snapshot/, and src/agent/ modules. This makes the debug tree the clearest map of OpenCode’s internal subsystem boundaries.
Stats with project and model filters:
opencode stats --days N last N days (default: all time) --tools N top N tools (default: all) --models [N] show model stats (default: hidden) --project <name> filter by project; empty string = current projectPersistent token/cost tracking per project and model, not just session.
Session import/export: opencode export [sessionID] dumps to JSON; opencode import <file or URL> restores from JSON or a share URL. The share URL format implies a hosted sharing service built into the protocol.
GitHub agent: opencode github install / opencode github run — a named agent configuration specifically for GitHub PR-level automation. opencode pr <number> is a convenience that fetches a PR branch and launches the TUI pointed at it.
Auth with provider URL: opencode auth login [url] — the optional url argument supports custom provider endpoints (useful for self-hosted Anthropic proxies, corporate gateways, or the OpenCode hosted service).
Claude Code Implementation (Inferred)
Section titled “Claude Code Implementation (Inferred)”Source: Public documentation at code.claude.com/docs/ (closed source — architecture inferred from docs, not inspected code).
Claude Code uses a flat CLI with no subcommands — everything is a flag on the single claude command, plus a few subcommands for specific operations (claude mcp, claude update, claude commit). This is closer to Aider’s flat model than Codex’s subcommand tree, but the flag set is significantly richer.
Architecture Revealed by the CLI
Section titled “Architecture Revealed by the CLI”Dual-mode execution is the central design axis. Two execution modes share the same flag surface:
- Interactive REPL:
claudeorclaude "initial prompt"— starts a TUI session - Headless/print mode:
claude -p "query"— runs query, prints response, exits
Most flags work in both modes. A handful are headless-only: --max-budget-usd, --max-turns, --json-schema, --no-session-persistence, --fallback-model, --system-prompt-file, --append-system-prompt-file.
System prompt composition is more granular than any reference implementation. Four flags on two axes:
| Flag | Behavior | Modes |
|---|---|---|
--system-prompt | Replace entire default prompt | Interactive + Print |
--system-prompt-file | Replace from file | Print only |
--append-system-prompt | Append to default prompt | Interactive + Print |
--append-system-prompt-file | Append from file | Print only |
Replace and append are orthogonal — you can combine --system-prompt with --append-system-prompt-file. This enables composable prompt construction in CI pipelines.
Inline agent definition via --agents accepts a JSON object defining custom subagents at the command line:
{ "code-reviewer": { "description": "Expert code reviewer. Use proactively after code changes.", "prompt": "You are a senior code reviewer.", "tools": ["Read", "Grep", "Glob", "Bash"], "model": "sonnet" }}Each agent can specify: description, prompt, tools, disallowedTools, model, skills, mcpServers, maxTurns. This is a runtime composition mechanism — no config file edits needed. Neither Codex nor OpenCode supports this level of inline agent definition.
Permission as a modal axis, not a binary flag. --permission-mode selects a named mode (e.g., plan for read-only). This is combined with tool-level permissions via --allowedTools and --disallowedTools which accept glob patterns:
--allowedTools "Bash(git log *)" "Bash(git diff *)" "Read"--tools is a separate axis that controls which tools are available (not just which are auto-approved). Setting --tools "" disables all tools; --tools "Bash,Edit,Read" restricts to a specific set.
Permission delegation for headless mode. --permission-prompt-tool specifies an MCP tool that handles permission prompts when no human is available. This enables CI/CD pipelines where an external system (approval bot, policy engine) handles tool authorization.
Session management as flags, not subcommands. Unlike Codex (codex resume, codex fork) and OpenCode (opencode session list), Claude Code handles sessions entirely through flags on the main command:
--continue,-c— resume most recent session in CWD--resume,-r— resume by ID or name, or open picker--fork-session— create new session from resume point (used with--resumeor--continue)--from-pr— resume sessions linked to a specific GitHub PR number--session-id— use a specific UUID--worktree,-w— start in an isolated git worktree at<repo>/.claude/worktrees/<name>--no-session-persistence— don’t save to disk (headless only)
The --from-pr flag is notable: sessions are automatically linked to PRs when created via gh pr create, creating a natural audit trail. No other reference implementation has this.
Budget guardrails for automation:
--max-budget-usd— dollar spending cap (headless only)--max-turns— turn limit (headless only) Both exit with an error when the limit is reached. These are essential for cost control in CI.
MCP configuration control:
--mcp-config— load MCP servers from JSON files (space-separated, can specify multiple)--strict-mcp-config— ignore ALL other MCP configs except the ones specified This is important for reproducible CI runs where you need exact control over which external tools are available.
Setting source control. --setting-sources user,project,local controls which config layers are loaded. This enables isolated sessions that ignore project-level or user-level settings.
Additional working directories. --add-dir ../apps ../lib adds extra directories Claude can access beyond the CWD. Validates each path exists.
Cloud/cross-device handoff:
--remote— create a web session on claude.ai with a task description--teleport— resume a remote web session locally--teammate-mode auto|in-process|tmux— control how agent team members display
Interactive Mode Features
Section titled “Interactive Mode Features”Claude Code’s interactive mode has a richer feature set than any reference implementation:
Input modes:
- Normal text input
!prefix for direct bash execution (output added to conversation context, no agent interpretation)/prefix for built-in commands and skills@for file path mentions with autocomplete
Notable shortcuts:
- Shift+Tab cycles permission modes (default -> auto-accept -> plan)
- Alt+P switches model without clearing prompt
- Alt+T toggles extended thinking
- Ctrl+B backgrounds running tasks (press twice in tmux)
- Ctrl+T toggles task list
- Ctrl+G opens prompt in default text editor
- Esc+Esc rewinds to previous checkpoint
- Ctrl+R for reverse history search (with highlighted matching)
Prompt suggestions: After Claude responds, a grayed-out follow-up suggestion appears based on conversation context and git history. Tab to accept. Uses the parent conversation’s prompt cache for minimal additional cost. Skipped when cache is cold.
Task list tracking: For multi-step work, Claude creates a task list visible in the terminal status area (Ctrl+T to toggle). Up to 10 tasks shown. Persists across context compactions. Shareable across sessions via CLAUDE_CODE_TASK_LIST_ID environment variable.
PR review status: Clickable PR link in the footer with colored underline indicating review state (green=approved, yellow=pending, red=changes requested). Auto-updates every 60 seconds. Requires gh CLI.
Background tasks: Commands can run in the background while the user continues interacting. Output is buffered and retrievable. Disableable via CLAUDE_CODE_DISABLE_BACKGROUND_TASKS.
Built-in Commands (Architecture-Revealing)
Section titled “Built-in Commands (Architecture-Revealing)”| Command | What it reveals |
|---|---|
/compact [focus] | Compaction is user-controllable with directional focus |
/context | Context usage is visualized as a colored grid |
/cost | Token/cost tracking is per-session |
/debug [description] | Session debug logs are readable by the agent itself |
/doctor | Installation health checking is a first-class feature |
/init | CLAUDE.md creation is guided, not manual |
/mcp | MCP management includes OAuth flow handling |
/model | Model switching is mid-session, includes effort level control |
/plan | Plan mode is enterable from the prompt, not just via Shift+Tab |
/stats | Usage tracking includes daily stats, streaks, model preferences |
/teleport | Cross-device session handoff is built-in |
/desktop | CLI-to-desktop-app handoff is a native operation |
Pitfalls and Hard Lessons
Section titled “Pitfalls and Hard Lessons”Flat CLI doesn’t scale: Aider’s single-level argparse produces a help page with ~100 flags organized only by comment groups. Once feature count crosses ~30 significant knobs, discoverability collapses. Users learn flags from docs or other users, not --help.
Subcommand nesting has its own tax: Codex’s codex exec resume and codex app-server generate-ts are three-level commands. Most shells have good completion support, but discoverability still requires codex exec --help to find what exec accepts. There’s a friction cliff at depth 3.
Headless mode must emit structured events from day one: Both Codex and OpenCode expose a --json / --format json flag that emits the internal event stream. Adding this retroactively means the format wasn’t designed for machines — it was designed for terminals and then bolted on. OpenOxide should design the event format first, then render it for the terminal.
Sandbox mode must be unhideable: Codex’s explicit -s, --sandbox <MODE> flag that shows on every command makes the security posture visible. Tools that bury sandbox config in a settings file get security surprises when users run in unexpected environments (CI, shared machines, remote sessions).
Config override at the CLI is mandatory: Power users always need to change a single setting without editing a file. Codex’s -c key=value pattern (TOML dotted path) handles every case with one mechanism. OpenCode uses per-command yargs flags that must be kept in sync with the config schema manually.
Session picker UX: Both Codex (codex resume) and OpenCode (opencode session list) have session management. The --last shortcut in Codex is heavily used in practice — the picker is too many keystrokes for the common case of “just continue where I left off.”
mDNS is fragile on corporate networks: OpenCode’s --mdns discovery relies on multicast DNS, which is often blocked by enterprise network policies, VPNs, and Docker’s default bridge networking. It’s a good feature on a home LAN; it silently fails in most professional environments. Any network discovery system needs a fallback (explicit URL, service file, port file).
Feature flag proliferation: Codex’s features list command shows stage labels. Without visible stages, users can’t distinguish “stable enough for automation” from “experimental and likely to change.” Stage labels should be part of CLI output, not hidden metadata.
Flat CLI can work at scale with good grouping. Claude Code’s flat model has 50+ flags but remains usable because: (a) flags cluster around clear concepts (session, permission, system prompt, output), (b) most flags have short aliases (-p, -c, -r), and (c) the interactive mode handles discovery through /help and prompt suggestions rather than --help. This partially refutes the “flat CLI doesn’t scale” lesson from Aider — the issue with Aider is not flatness itself but lack of conceptual grouping and in-session discovery.
System prompt composition is underserved in open-source tools. Claude Code’s four-flag system prompt surface (replace/append x inline/file) is significantly more flexible than any reference implementation. Codex and OpenCode have no append mechanism — it’s replace-or-nothing. The append pattern enables layered prompt construction (base prompt + project rules + CI-specific instructions) without losing the tool’s default capabilities.
Session-PR linking creates natural audit trails. Claude Code’s --from-pr flag ties sessions to PRs automatically. This is absent from all open-source references and is valuable for team workflows where you need to trace what the agent did for a specific PR.
Permission delegation is required for production CI. Claude Code’s --permission-prompt-tool (delegating permission decisions to an MCP tool) solves a problem that Codex and OpenCode ignore: how does a headless agent handle permission prompts in CI? The alternatives (skip all permissions, or never ask) are both security risks. Delegating to an external tool enables policy-driven approval.
OpenOxide Blueprint
Section titled “OpenOxide Blueprint”OpenOxide’s CLI will use clap (Rust) with the derive macro pattern for compile-time checked argument definitions. The structure should prioritize scriptability and composability over interactive UX — the TUI handles interactive concerns; the CLI handles automation.
[dependencies]clap = { version = "4", features = ["derive", "env", "color"] }Subcommand Tree (Proposed)
Section titled “Subcommand Tree (Proposed)”openoxide [OPTIONS] [PROMPT] # start interactive TUI (default)openoxide serve # headless server onlyopenoxide run [message..] # non-interactive single-turn --format text|json # json = JSONL event stream --session <ID> # continue a specific session --file <FILE>... # attach files --max-budget-usd <AMOUNT> # dollar spending cap --max-turns <N> # turn limit --json-schema <SCHEMA> # validated structured output --permission-prompt-tool <TOOL> # MCP tool for permission delegation --fallback-model <MODEL> # fallback when primary is overloadedopenoxide attach <url> # connect to running serveropenoxide session # session management openoxide session list # list sessions openoxide session resume [ID] # resume (--last shortcut) openoxide session fork [ID] # fork openoxide session export [ID] # dump JSON openoxide session import <file> # restore from JSONopenoxide mcp # MCP server management openoxide mcp add # add server openoxide mcp list # list servers + status openoxide mcp remove <name> # remove serveropenoxide auth # provider credentials openoxide auth login # interactive login openoxide auth logout # remove credentials openoxide auth list # list configured providersopenoxide models [provider] # list available modelsopenoxide stats # token + cost statisticsopenoxide debug # internal diagnostics openoxide debug config # resolved config dump openoxide debug paths # data/config/cache locations openoxide debug snapshot <hash> # inspect snapshot state openoxide debug lsp <file> # LSP diagnostics for a file openoxide debug map # print repo map and exit openoxide debug prompts # print system prompt and exitopenoxide upgrade # self-updateopenoxide completion <shell> # shell completionsGlobal Flags (Available on Root and run)
Section titled “Global Flags (Available on Root and run)”# Session control-c, --continue # resume most recent session in CWD-r, --resume <ID|NAME> # resume by ID or name--fork-session # fork when resuming--from-pr <NUMBER> # resume sessions linked to a PR-w, --worktree [NAME] # start in isolated git worktree
# System prompt composition--system-prompt <TEXT> # replace entire default prompt--append-system-prompt <TEXT> # append to default prompt--system-prompt-file <FILE> # replace from file (headless only)--append-system-prompt-file <FILE> # append from file (headless only)
# Agent definition--agent <NAME> # select a named agent--agents <JSON> # define custom subagents inline
# Permission control--permission-mode <MODE> # plan | default | auto-accept--allowed-tools <PATTERNS>... # tools that skip permission prompts--disallowed-tools <PATTERNS>... # tools removed from context entirely--tools <LIST> # restrict available tool set
# Model and thinking--model <NAME|ALIAS> # set model for session--effort <LEVEL> # low | medium | high (thinking budget)
# MCP--mcp-config <FILE>... # load MCP servers from JSON--strict-mcp-config # ignore all other MCP configs
# Config-c, --config <key=value> # override config (TOML dotted path)--setting-sources <SOURCES> # user,project,local--settings <FILE|JSON> # load additional settings
# Directories--add-dir <DIR>... # additional working directories
# Debugging--verbose # full turn-by-turn output--debug [CATEGORIES] # debug mode with category filterKey Design Decisions
Section titled “Key Design Decisions”Use Codex’s -c key=value pattern for config overrides. Don’t replicate every config field as a CLI flag. One generic override mechanism handles power users; named flags handle the common cases (model, sandbox, session).
/// Override config key (TOML dotted path format, e.g. -c model="claude-4-6-opus")#[arg(short = 'c', long = "config", value_name = "key=value")]pub config_overrides: Vec<String>,Sandbox as a mandatory visible flag. Every command that can execute shell actions gets -s, --sandbox:
#[arg(short = 's', long, default_value = "workspace-write")]pub sandbox: SandboxMode,
pub enum SandboxMode { ReadOnly, WorkspaceWrite, DangerFullAccess,}Map WorkspaceWrite to Landlock on Linux (following Codex’s codex-rs/linux-sandbox/ model), Seatbelt on macOS, and file ACLs or AppContainer on Windows.
JSON event output from the first line of code. The internal event bus emits typed events. The --format json flag on run is not a hack — it’s the primary machine interface. Design event types as serde-serializable enums first:
#[derive(Serialize)]#[serde(tag = "type")]pub enum AgentEvent { MessageStart { session_id: String }, TextDelta { delta: String }, ToolCall { id: String, name: String, input: Value }, ToolResult { id: String, output: String }, TokenUsage { input: u32, output: u32, cost_usd: f64 }, Done,}Debug subcommands as module health checks. Each internal subsystem gets a debug subcommand that directly queries its state without a full agent session. debug lsp <file> calls into crate::lsp directly. debug map runs the repo mapper and prints output. This is the equivalent of OpenCode’s opencode debug lsp diagnostics <file>.
Feature flags with stage labels visible in CLI. Use a features list equivalent that shows:
FEATURE STAGE ENABLED DESCRIPTIONstreaming-edits stable true Stream file edits as patchestree-sitter-map beta false Use tree-sitter for repo mappinglsp-inline alpha false Inline LSP completionsStage labels prevent users from relying on alpha features in automation.
--last shortcut for session operations. The most common case (continue last session) should be one flag:
openoxide session resume --lastopenoxide --continue # global alias for the same thingSystem prompt composition (from Claude Code). Support both replace and append operations on the system prompt. Append preserves the default agent behavior while adding project- or CI-specific instructions:
#[arg(long)]pub system_prompt: Option<String>,
#[arg(long)]pub append_system_prompt: Option<String>,
#[arg(long, requires = "print")]pub system_prompt_file: Option<PathBuf>,
#[arg(long, requires = "print")]pub append_system_prompt_file: Option<PathBuf>,Replace and append are composable. --system-prompt sets the base, --append-system-prompt adds to it. File variants are headless-only because interactive users can modify prompts through CLAUDE.md or the TUI.
Inline agent definition (from Claude Code). Support --agents with a JSON object defining subagents at runtime. This enables ad-hoc specialization without config file edits:
#[arg(long, value_parser = parse_agents_json)]pub agents: Option<HashMap<String, AgentSpec>>,
pub struct AgentSpec { pub description: String, pub prompt: String, pub tools: Option<Vec<String>>, pub disallowed_tools: Option<Vec<String>>, pub model: Option<String>, pub max_turns: Option<u32>,}Permission delegation for headless mode (from Claude Code). In CI/CD, support --permission-prompt-tool to delegate permission decisions to an external MCP tool:
#[arg(long, requires = "print")]pub permission_prompt_tool: Option<String>,This enables policy-driven approval without --dangerously-skip-permissions. The MCP tool receives the permission request and returns approve/deny.
Budget guardrails (from Claude Code). Hard spending and turn limits for automation:
#[arg(long, requires = "print")]pub max_budget_usd: Option<f64>,
#[arg(long, requires = "print")]pub max_turns: Option<u32>,PR-linked sessions (from Claude Code). Automatically link sessions to PRs and support resume by PR number:
#[arg(long)]pub from_pr: Option<u32>,Sessions are linked when the agent creates a PR (via gh pr create). This creates a natural audit trail.
Worktree as a first-class flag (from Claude Code). Create an isolated git worktree for the session:
#[arg(short = 'w', long)]pub worktree: Option<Option<String>>, // None = no worktree, Some(None) = auto-name, Some(Some(name)) = namedWorktrees are created at <repo>/.openoxide/worktrees/<name> with branch worktree-<name>. Auto-cleanup on exit if no changes were made.
Setting source control (from Claude Code). Control which config layers are loaded for isolated/reproducible sessions:
#[arg(long, value_delimiter = ',')]pub setting_sources: Option<Vec<SettingSource>>,
pub enum SettingSource { User, Project, Local }Crates for Session/State
Section titled “Crates for Session/State”clapwithderivefeature for the full command tree.directoriesfor XDG-compliant data/config/cache paths.serde+serde_jsonfor JSON event serialization.tokiofor the async server runtime thatopenoxide servestarts.
Appendix: Raw CLI Help Output
Section titled “Appendix: Raw CLI Help Output”Raw --help output from each reference implementation, captured for direct comparison.
Claude Code
Section titled “Claude Code”$ claude --help
Usage: claude [options] [command] [prompt]
Claude Code - starts an interactive session by default, use -p/--print fornon-interactive output
Arguments: prompt Your prompt
Options: --add-dir <directories...> Additional directories to allow tool access to --agent <agent> Agent for the current session. Overrides the 'agent' setting. --agents <json> JSON object defining custom agents (e.g. '{"reviewer": {"description": "Reviews code", "prompt": "You are a code reviewer"}}') --allow-dangerously-skip-permissions Enable bypassing all permission checks as an option, without it being enabled by default. Recommended only for sandboxes with no internet access. --allowedTools, --allowed-tools <tools...> Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit") --append-system-prompt <prompt> Append a system prompt to the default system prompt --betas <betas...> Beta headers to include in API requests (API key users only) --chrome Enable Claude in Chrome integration -c, --continue Continue the most recent conversation in the current directory --dangerously-skip-permissions Bypass all permission checks. Recommended only for sandboxes with no internet access. -d, --debug [filter] Enable debug mode with optional category filtering (e.g., "api,hooks" or "!1p,!file") --debug-file <path> Write debug logs to a specific file path (implicitly enables debug mode) --disable-slash-commands Disable all skills --disallowedTools, --disallowed-tools <tools...> Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit") --effort <level> Effort level for the current session (low, medium, high) --fallback-model <model> Enable automatic fallback to specified model when default model is overloaded (only works with --print) --file <specs...> File resources to download at startup. Format: file_id:relative_path (e.g., --file file_abc:doc.txt file_def:img.png) --fork-session When resuming, create a new session ID instead of reusing the original (use with --resume or --continue) --from-pr [value] Resume a session linked to a PR by PR number/URL, or open interactive picker with optional search term -h, --help Display help for command --ide Automatically connect to IDE on startup if exactly one valid IDE is available --include-partial-messages Include partial message chunks as they arrive (only works with --print and --output-format=stream-json) --input-format <format> Input format (only works with --print): "text" (default), or "stream-json" (realtime streaming input) (choices: "text", "stream-json") --json-schema <schema> JSON Schema for structured output validation. Example: {"type":"object","properties":{"name":{"type":"string"}},"required":["name"]} --max-budget-usd <amount> Maximum dollar amount to spend on API calls (only works with --print) --mcp-config <configs...> Load MCP servers from JSON files or strings (space-separated) --model <model> Model for the current session. Provide an alias for the latest model (e.g. 'sonnet' or 'opus') or a model's full name (e.g. 'claude-4-6-sonnet'). --no-chrome Disable Claude in Chrome integration --no-session-persistence Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print) --output-format <format> Output format (only works with --print): "text" (default), "json" (single result), or "stream-json" (realtime streaming) (choices: "text", "json", "stream-json") --permission-mode <mode> Permission mode to use for the session (choices: "acceptEdits", "bypassPermissions", "default", "dontAsk", "plan") --plugin-dir <paths...> Load plugins from directories for this session only (repeatable) -p, --print Print response and exit (useful for pipes). Note: The workspace trust dialog is skipped when Claude is run with the -p mode. Only use this flag in directories you trust. --replay-user-messages Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json) -r, --resume [value] Resume a conversation by session ID, or open interactive picker with optional search term --session-id <uuid> Use a specific session ID for the conversation (must be a valid UUID) --setting-sources <sources> Comma-separated list of setting sources to load (user, project, local). --settings <file-or-json> Path to a settings JSON file or a JSON string to load additional settings from --strict-mcp-config Only use MCP servers from --mcp-config, ignoring all other MCP configurations --system-prompt <prompt> System prompt to use for the session --tmux Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux. --tools <tools...> Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read"). --verbose Override verbose mode setting from config -v, --version Output the version number -w, --worktree [name] Create a new git worktree for this session (optionally specify a name)
Commands: agents [options] List configured agents auth Manage authentication doctor Check the health of your Claude Code auto-updater install [options] [target] Install Claude Code native build. Use [target] to specify version (stable, latest, or specific version) mcp Configure and manage MCP servers plugin Manage Claude Code plugins setup-token Set up a long-lived authentication token (requires Claude subscription) update|upgrade Check for updates and install if availableclaude mcp
Section titled “claude mcp”$ claude mcp --help
Usage: claude mcp [options] [command]
Configure and manage MCP servers
Commands: add [options] <name> <commandOrUrl> [args...] Add an MCP server to Claude Code. add-from-claude-desktop [options] Import MCP servers from Claude Desktop (Mac and WSL only) add-json [options] <name> <json> Add an MCP server (stdio or SSE) with a JSON string get <name> Get details about an MCP server list List configured MCP servers remove [options] <name> Remove an MCP server reset-project-choices Reset all approved and rejected project-scoped (.mcp.json) servers within this project serve [options] Start the Claude Code MCP server$ claude mcp add --help
Usage: claude mcp add [options] <name> <commandOrUrl> [args...]
Add an MCP server to Claude Code.
Options: --callback-port <port> Fixed port for OAuth callback (for servers requiring pre-registered redirect URIs) --client-id <clientId> OAuth client ID for HTTP/SSE servers --client-secret Prompt for OAuth client secret (or set MCP_CLIENT_SECRET env var) -e, --env <env...> Set environment variables (e.g. -e KEY=value) -H, --header <header...> Set WebSocket headers (e.g. -H "X-Api-Key: abc123" -H "X-Custom: value") -s, --scope <scope> Configuration scope (local, user, or project) (default: "local") -t, --transport <transport> Transport type (stdio, sse, http). Defaults to stdio if not specified.$ claude mcp serve --help
Usage: claude mcp serve [options]
Start the Claude Code MCP server
Options: -d, --debug Enable debug mode --verbose Override verbose mode setting from configclaude auth
Section titled “claude auth”$ claude auth --help
Usage: claude auth [options] [command]
Manage authentication
Commands: login [options] Sign in to your Anthropic account logout Log out from your Anthropic account status [options] Show authentication status$ claude auth login --help
Usage: claude auth login [options]
Sign in to your Anthropic account
Options: --email <email> Pre-populate email address on the login page --sso Force SSO login flowclaude plugin
Section titled “claude plugin”$ claude plugin --help
Usage: claude plugin [options] [command]
Manage Claude Code plugins
Commands: disable [options] [plugin] Disable an enabled plugin enable [options] <plugin> Enable a disabled plugin install|i [options] <plugin> Install a plugin from available marketplaces (use plugin@marketplace for specific marketplace) list [options] List installed plugins marketplace Manage Claude Code marketplaces uninstall|remove [options] <plugin> Uninstall an installed plugin update [options] <plugin> Update a plugin to the latest version (restart required to apply) validate [options] <path> Validate a plugin or marketplace manifest$ claude plugin marketplace --help
Usage: claude plugin marketplace [options] [command]
Manage Claude Code marketplaces
Commands: add [options] <source> Add a marketplace from a URL, path, or GitHub repo list [options] List all configured marketplaces remove|rm [options] <name> Remove a configured marketplace update [options] [name] Update marketplace(s) from their source - updates all if no name specifiedOther Subcommands
Section titled “Other Subcommands”$ claude agents --help
Usage: claude agents [options]
List configured agents
Options: --setting-sources <sources> Comma-separated list of setting sources to load (user, project, local).$ claude doctor --help
Usage: claude doctor [options]
Check the health of your Claude Code auto-updater$ claude install --help
Usage: claude install [options] [target]
Install Claude Code native build. Use [target] to specify version (stable, latest, or specific version)
Options: --force Force installation even if already installed$ claude setup-token --help
Usage: claude setup-token [options]
Set up a long-lived authentication token (requires Claude subscription)$ claude update --help
Usage: claude update|upgrade [options]
Check for updates and install if availableObservations from Help Output
Section titled “Observations from Help Output”Flat root with shallow subcommands. The root claude command carries all agent-session flags (40+ options). Subcommands (mcp, auth, plugin) are shallow (1-2 levels deep) and handle infrastructure concerns, not agent behavior. This is a deliberate split: agent behavior is configured via root flags, infrastructure via subcommands.
Permission mode names reveal internal architecture. --permission-mode accepts acceptEdits, bypassPermissions, default, dontAsk, plan. The camelCase naming suggests these are internal enum variants exposed directly. dontAsk is a separate mode from bypassPermissions — the former likely still enforces sandbox constraints while skipping interactive prompts; the latter skips everything.
mcp serve exposes Claude Code as an MCP server. Like Codex’s codex mcp-server, Claude Code can itself be called as a tool by other agents. This is the inverse of mcp add (adding external servers). OpenOxide should support this bidirectional MCP pattern.
Plugin system with marketplace model. Claude Code has a full plugin lifecycle: install from marketplaces, enable/disable, update, validate manifests. Marketplaces are themselves manageable (add from URL/GitHub, update, remove). This is more mature than any open-source reference. OpenOxide should plan for a plugin registry but can defer marketplace infrastructure.
OAuth built into MCP management. mcp add supports --client-id, --client-secret, --callback-port for OAuth PKCE flows on HTTP/SSE transport MCP servers. This isn’t just stdio process management — it’s a full credential lifecycle for remote MCP servers.
--tmux for worktree sessions. The --tmux flag (requires --worktree) creates a tmux session for the worktree, with iTerm2 native pane detection. This enables multi-agent visual layouts where each worktree gets its own terminal pane.
--effort as a top-level flag. Thinking budget is controlled via --effort low|medium|high rather than a raw token count. This is a higher-level abstraction than Aider’s --thinking-tokens — it delegates token allocation to the model/provider rather than hardcoding a number.
--file for remote resource download. --file file_id:relative_path downloads file resources at startup. The file_id format suggests integration with a file storage service (likely Anthropic’s Files API). No open-source reference has this.