# How the orx CLI Uses the clap-derive Command Tree in OpenResearch

> Discover how the orx CLI leverages clap-derive for a type-safe command tree, dispatching commands to handler modules for efficient Rust CLI development.

- Repository: [alphaXiv/OpenResearch](https://github.com/alphaXiv/OpenResearch)
- Tags: internals
- Published: 2026-09-13

---

**The orx CLI uses clap-derive to build a type-safe command hierarchy where a top-level `Cli` struct with a `Command` subcommand enum dispatches to individual handler modules in `src/commands/`.**

The [alphaXiv/OpenResearch](https://github.com/alphaXiv/OpenResearch) repository implements its `orx` command-line interface using **clap-derive**, Rust’s declarative macro system for CLI parsing. This approach encodes the entire command tree—global flags, subcommands, and positional arguments—directly into Rust’s type system. The result is a compile-time validated parser that automatically generates help text and enforces argument constraints without manual boilerplate.

## Top-Level Parser Definition in src/main.rs

### The Cli Struct

The entry point resides in [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs) (lines 38–55), where the `Cli` struct defines the root parser. The `#[derive(Parser)]` attribute instructs clap to generate the argument parser from struct fields.

```rust
#[derive(Parser, Debug)]
#[command(
    name = "orx",
    about = "OpenResearch CLI",
    version,
    disable_help_subcommand = true
)]
struct Cli {
    #[command(subcommand)]
    command: Option<Command>,
    #[arg(long, global = true)]
    no_telemetry: bool,
}

```

`Cli` contains two critical components: an optional `command` field marked with `#[command(subcommand)]` that holds the subcommand enum, and global flags available to all nested commands.

### Global Flag Propagation

The `no_telemetry` field demonstrates clap’s **global argument** feature. By setting `global = true`, this flag becomes available on every subcommand regardless of where it appears in the argument string. The parser automatically recognizes `--no-telemetry` whether it follows the binary name or appears after a subcommand verb.

## Subcommand Enum Hierarchy

### The Command Enum

Lines 57–71 of [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs) define the `Command` enum using `#[derive(Subcommand)]`. Each variant represents a top-level CLI verb and wraps a concrete arguments struct.

```rust
#[derive(Subcommand, Debug)]
enum Command {
    Login(LoginArgs),
    Projects(ProjectsArgs),
    Run(RunArgs),
    Serve(ServeArgs),
    Up(UpArgs),
    // internal hidden commands
    #[command(name = "plan-gate", hide = true)]
    PlanGate,
    #[command(name = "mcp-gate", hide = true)]
    McpGate,
}

```

This pattern creates a discriminated union where each variant carries its own strongly-typed payload. The compiler enforces that every subcommand has defined arguments, preventing runtime parsing errors for missing fields.

### Hidden Internal Commands

Certain variants like `PlanGate` use `#[command(hide = true)]` to suppress them from public help output. These internal commands support Claude plan-mode plumbing and internal tooling without polluting the user-facing interface. The `name` attribute overrides the default kebab-case variant name, allowing commands like `plan-gate` while using the `PlanGate` identifier in Rust.

## Argument Structs and Type Safety

### Args Derive Macro

Each subcommand variant wraps a struct annotated with `#[derive(Args)]`, typically defined in [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs) (lines 81–100) or within dedicated command modules. These structs declare command-specific flags and positionals:

```rust
#[derive(Args, Debug)]
struct LoginArgs {
    #[arg(long)]
    api_url: Option<String>,
}

#[derive(Args, Debug)]
struct ProjectsArgs {
    #[arg(long)]
    json: bool,
}

```

Because these are distinct types, the **type system guarantees** that `LoginArgs` can only be accessed when the `Login` variant is matched. This eliminates an entire class of errors where arguments from one command might be confused with another.

## Dispatch Pattern and Execution

### The Main Match Block

The async entry point in [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs) (lines 150–180) uses a `match` statement on `cli.command` to route execution. This dispatch pattern cleanly separates parsing from execution logic.

```rust
let cli = Cli::parse();

match cli.command {
    Some(Command::Login(args)) => commands::login::run(args).await,
    Some(Command::Projects(args)) => commands::projects::run(args).await,
    Some(Command::Serve(args)) => commands::serve::run(args).await,
    // ... additional variants
    None => print_usage(),
}

```

Each arm destructures the enum variant to extract its specific `Args` struct and calls the corresponding handler function.

### Command Module Structure

Every top-level verb has an implementation file under `src/commands/`:

- **[`src/commands/login.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/commands/login.rs)** – Handles authentication flows using the `LoginArgs` struct
- **[`src/commands/projects.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/commands/projects.rs)** – Lists local projects, consuming the `--json` flag from `ProjectsArgs`
- **[`src/commands/serve.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/commands/serve.rs)** – Starts the local HTTP/SSE daemon
- **[`src/local/harness/plan_gate.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/local/harness/plan_gate.rs)** – Implements the hidden `plan-gate` internal command

Each module exposes an async `run` function accepting the specific args struct and returning `anyhow::Result<()>` for consistent error handling across the CLI.

## Help Generation and CommandFactory

The codebase leverages `clap::CommandFactory` for programmatic help generation. At line 831 in [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs), the code invokes `Cli::command().print_help()` to output the help text programmatically. This is useful for testing the clap-derive output and for implementing custom help behavior while retaining the automatically generated documentation from struct doc comments and `#[command(about = "...")]` attributes.

## Summary

- **Root Structure**: The `Cli` struct in [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs) acts as the top-level parser, holding global flags like `no_telemetry` and an optional `Command` subcommand field.
- **Subcommand Tree**: The `Command` enum uses `#[derive(Subcommand)]` to declare the CLI verb hierarchy, with each variant wrapping a specific `Args` struct.
- **Type Safety**: `#[derive(Args)]` structs ensure compile-time validation of command-specific arguments, preventing cross-command pollution.
- **Dispatch Mechanism**: A `match` statement in the async `main()` function routes each variant to its dedicated handler in `src/commands/`.
- **Hidden Commands**: Internal tools use `#[command(hide = true)]` to remain accessible but invisible in `--help` output.
- **Global Flags**: The `global = true` attribute automatically propagates flags like `no_telemetry` to all subcommand contexts.

## Frequently Asked Questions

### How does clap-derive differ from the builder-based clap API?

**clap-derive** uses procedural macros to generate parser implementations from struct and enum definitions, while the builder API requires manually constructing `Command`, `Arg`, and `ArgGroup` objects. The derive approach reduces boilerplate and keeps argument definitions co-located with the data structures that consume them. In `orx`, this means adding a new command only requires adding a variant to the `Command` enum and a handler to `src/commands/`, with clap automatically generating the help text and validation logic.

### Why are some orx commands hidden from the help output?

Internal commands like `plan-gate` and `mcp-gate` are marked with `#[command(hide = true)]` in the `Command` enum definition. These support internal Claude plan-mode operations and MCP (Model Context Protocol) integrations that end users should not invoke directly. Hiding them cleans up the public interface while keeping the functionality accessible for internal tooling and automation scripts.

### How does the global `no_telemetry` flag work across subcommands?

The `no_telemetry` field in the `Cli` struct uses `#[arg(long, global = true)]`, which tells clap to treat this argument as available on every subcommand. When clap builds the command tree, it injects this flag into the definition of every subcommand automatically. This allows users to run `orx --no-telemetry login` or `orx login --no-telemetry` with identical results, providing flexibility in argument ordering without requiring each command module to explicitly declare the flag.

### Where should new subcommands be added in the orx codebase?

To add a new subcommand, you must modify three locations: First, add a variant to the `Command` enum in [`src/main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/main.rs) (around line 57–71) wrapping a new `Args` struct. Second, define the `Args` struct with `#[derive(Args)]` to declare its specific flags. Third, create a new file in `src/commands/` (e.g., [`src/commands/newcmd.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/src/commands/newcmd.rs)) implementing the async `run` function, and add the corresponding match arm in [`main.rs`](https://github.com/alphaXiv/OpenResearch/blob/main/main.rs)’s dispatch block (lines 150–180) to route the variant to your new module.