# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Commands ```bash # Run all specs crystal spec # Run a single spec file crystal spec spec/command_spec.cr # Type-check without running crystal build src/cligen.cr --no-codegen # Install dependencies shards install ``` ## What This Is `cligen` is a Crystal **shard (library)** — not a standalone application. It wraps Crystal's built-in `OptionParser` with an annotation- and macro-driven system that auto-generates CLI parsers from class definitions. Users of the shard subclass `CliGen::Command` and annotate methods; the library generates the `OptionParser` wiring at compile time via Crystal macros. ## Architecture ### Entry point: `src/cligen.cr` Defines the `CliGen` module. The `macro finished` hook calls `define_root_parser`, which scans all `CliGen::Command` subclasses at compile time and registers each as a subcommand on the root `OptionParser`. `CliGen.parse` runs the root parser. `ADDITIONAL_DEFAULT_FLAGS` / `add_default_flag` let users inject extra flags into every parser (root and subcommand). ### Command definition: `src/cligen/command.cr` `CliGen::Command` is the base class. When subclassed, `macro inherited` installs a `macro finished` block that triggers four code-generation macros in order: 1. `define_actions` — collects all `@[SubCommand]`-annotated class methods into `ACTIONS : Array(String)` and `@@action : String`. 2. `define_header` — builds the `HEADER` string (banner + examples) from `@[SubCommand]` and `@[CommandSelection]` annotation metadata. 3. `define_runner` (skipped if `@[CommandInfo(def_runner: false)]`) — generates a `self.run` method that dispatches on `@@action` or a selection variable via a `case` statement. 4. `define_action_setter` — generates `self.action=` with bounds-checking against `ACTIONS`. #### Key macros on `Command` - **`define_argument`** — declares a class-level variable (`@@`) and an annotated setter method (`@[CommandArgument]`). Handles `String`, `Bool`, `Int32`, `Array(String|Int32)`, and `Time`. Optional `check:` proc, `logger:` method, and `def_getter:` flag. - **`define_selection`** — like `define_argument` but validates against a fixed list of values; annotated with `@[CommandArgument]` and participates in selection-based dispatch. ### Parser generation: `src/cligen/command/parser.cr` `CliGen::Parser` is `extend`ed by `Command`. It provides `define_parser`, which generates `self.make_parser(parent_parser)`. That method: 1. Creates a subparser `OptionParser` with the command's `HEADER` as banner. 2. Wires `@[CommandSelection]`-annotated methods as `parser.on(name, description)` that set the selection variable. 3. Wires `@[SubCommand]`-annotated methods as subcommand strings that set `@@action`. 4. Wires `@[CommandArgument]`-annotated methods as `parser.on(short, long, description)` flag handlers. 5. Calls `CliGen.define_default_flags` (adds `-h`/`--help`, error handlers). 6. Registers the whole subparser on `parent_parser` under the command's lowercase class name. ### Annotations | Annotation | Applied to | Purpose | |---|---|---| | `@[CommandInfo(description:, def_runner:)]` | Command subclass | Required; provides the description shown in root help; `def_runner: false` skips auto-generating `run` | | `@[SubCommand(description:, examples:)]` | class method on Command | Marks a method as a dispatachable subcommand | | `@[CommandArgument(short:, long:, description:, type:)]` | class method on Command | Generated automatically by `define_argument`/`define_selection`; drives parser wiring | | `@[CommandSelection(selector:, description:, examples:)]` | class method on Command | Alternative to `SubCommand`; dispatches via a named selector variable instead of `@@action` | | `@[CommandPreRun]` | class method on Command | Methods run unconditionally before dispatch inside `self.run` | | `@[DefaultFlag]` | (reserved) | Defined but not currently used in generation | ### Supporting files - `src/cligen/format.cr` — date/datetime format strings used by `Time` argument parsing. - `src/cligen/regex.cr` — regexes for validating date/datetime input strings. ## Spec structure `spec/command_spec.cr` uses Crystal's macro system heavily: most `it` blocks are generated at compile time by inspecting `CommandSubclass` via `@type` introspection. The `macro finished` wrapper around the entire `describe` block is required because `make_parser` and `run` don't exist until all `macro finished` hooks have fired.