
Build command-line interfaces using typed spec definitions:

```vary
from cli.cli import run
from cli.model import CliArg, CliCommand, CliOption, CliSpec
import process

let args: List[CliArg] = [CliArg("name", True, False, "string")]
let opts: List[CliOption] = [CliOption("uppercase", "u", "Uppercase output", False, False, False, None, None, "string")]
let no_subs: List[CliCommand] = []
let no_aliases: List[Str] = []
let greet = CliCommand("greet", "Greet someone", None, no_aliases, args, opts, no_subs)

let cmds: List[CliCommand] = [greet]
let global: List[CliOption] = []
let examples: List[Str] = ["mytool greet Alice -u"]
let spec = CliSpec("mytool", "1.0.0", "A greeting tool", None, cmds, global, examples)

let m = run(spec, process.argv())

if m.command() == "greet" {
    mut msg = "Hello, " + m.arg("name") + "!"
    if m.flag("uppercase") {
        msg = msg.upper()
    }
    print(msg)
}
```

Define your CLI structure with `CliSpec`, `CliCommand`, `CliArg`, and `CliOption` data types, then use `run()` or `parse()` to process arguments.

### Core functions

| **Function** | **Returns** | **Description** |
|--------|---------|-------------|
| `run(spec, argv)` | `CliMatch` | Parse args, print errors and exit on failure |
| `parse(spec, argv)` | `Result[CliMatch, CliError]` | Parse args, return Result for manual error handling |
| `parse_env(spec, argv, env)` | `Result[CliMatch, CliError]` | Parse with env var fallback and defaults |

### CliMatch accessors

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `m.command()` | `Str?` | Matched command name |
| `m.arg(name)` | `Str` | Get positional argument (raises if missing) |
| `m.opt(name)` | `Str?` | Get option value |
| `m.flag(name)` | `Bool` | Check if flag is set |
| `m.has(name)` | `Bool` | Check if any arg/opt/flag exists |

### Spec data types

`CliSpec(name, version?, summary?, description?, commands, global_options, examples)` - top-level CLI definition.

`CliCommand(name, summary?, description?, aliases, args, options, subcommands)` - a command or subcommand.

`CliArg(name, required, repeated, parser)` - a positional argument.

`CliOption(long, short?, summary?, takes_value, required, repeated, default_value?, env_var?, parser)` - a named option or flag. Set `takes_value` to `True` for options that accept a value, `False` for boolean flags.

### Value parsers

Set the `parser` field on `CliArg` or `CliOption` to validate values automatically:

| **Parser** | **Description** |
|--------|-------------|
| `"string"` | Accept any string (default) |
| `parser_int()` | Parse integer |
| `parser_float()` | Parse float |
| `parser_bool()` | Parse boolean |
| `parser_one_of(["a", "b"])` | Restrict to allowed values |
| `parser_path_exists()` | Validate path exists |
| `parser_file_exists()` | Validate file exists |
| `parser_dir_exists()` | Validate directory exists |

### Built-in features

| **Feature** | **Behavior** |
|---|---|
| `-h` / `--help` | Always recognized; prints structured help |
| `help <command>` | Shows command-specific help |
| Unknown commands/options | Shows "Did you mean ...?" suggestions |
| Error handling | Exits code 2 with location and suggestion |

### JSON and completion output

| **Function** | **Returns** | **Description** |
|--------|---------|-------------|
| `render_json_error(err)` | `Str` | Stable JSON error for machine parsing |
| `render_json_help(spec, path)` | `Str` | Stable JSON help for automation |
| `completion(spec, shell)` | `Str` | Shell completion script (bash, zsh, fish) |
| `render_help(spec)` | `Str` | Formatted help text |

### Legacy API

The docopt-style `parse_cli(spec_text)` function is still available for simple use cases but the typed spec API above is preferred for new code.
