Help System & Commands
This page covers how the gl CLI presents help text and the patterns every command must follow — from flag naming to exit codes.
Help System Design
The CLI exposes three tiers of help output, each progressively more detailed: root, group, and command.
Root Help
Running gl --help displays every command group, global flags, and the version:
Usage: gl [OPTIONS] COMMAND [ARGS]...
GospeLib developer CLI — unified entry point for all GospeLib workflows.
Options:
--no-color Disable colored output
-v, --verbose Increase verbosity (-v info, -vv debug)
-q, --quiet Suppress non-essential output
--log-file PATH Write logs to this file
--version Show version and exit
--help Show this message and exit
Commands:
dev Start, stop, and manage development services
infra Manage infrastructure containers (up, down, reset)
test Run tests across JavaScript, Python, and Go
lint Lint code across all stacks
format Format code with Prettier and Ruff
codegen Generate code from schemas and catalogs
db Database migrations, seeding, and reset
download Download corpus data from external sources
ingest Run the scripture ingest pipeline
health Check health of all services and data stores
setup Run first-time environment setup
config View and manage CLI configuration
doctor Diagnose common environment issues
Group Help
Running gl dev --help shows the group description and its subcommands:
Usage: gl dev [OPTIONS] COMMAND [ARGS]...
Start, stop, and manage development services.
The dev group manages the local development stack — starting services,
tailing logs, and checking status.
Commands:
start Start development services
stop Stop running services
restart Restart services
logs Tail service logs
status Show running service status
Run gl dev <command> --help for details on any command.
Command Help
Running gl dev start --help provides full detail — arguments, options, examples, env vars, and related commands:
Usage: gl dev start [OPTIONS] [SERVICES]...
Start development services.
With no arguments, starts the full stack (all services + infrastructure).
Pass service names to start specific services only.
Arguments:
[SERVICES]... Services to start (default: all)
Choices: gateway, content, auth, billing, ai, notifications, web, admin
Options:
--apps / --no-apps Include Next.js apps (default: --apps)
--infra / --no-infra Start infrastructure first (default: --infra)
--attach Attach to logs after starting
-o, --output FORMAT Output format: human, json (default: human)
--help Show this message and exit
Examples:
gl dev start Start everything
gl dev start content ai Start only content and ai services
gl dev start --no-apps Start services without web/admin
gl dev start --attach Start and tail logs
Environment Variables:
GOSPELIB_DEV_DEFAULT_SERVICES Comma-separated default services
See Also:
gl dev stop Stop running services
gl dev status Check what's running
gl infra up Start only infrastructure
Help Formatting Rules
Every help screen follows a consistent structure:
| Element | Format |
|---|---|
| Usage line | Usage: gl <group> <command> [OPTIONS] [ARGS] |
| Description | One short line, blank line, then 2–4 lines of extended detail |
| Arguments section | Tabular — name, description, choices/type |
| Options section | Tabular — short flag, long flag, description, default |
| Examples section | Indented code block, one example per line |
| Env vars section | Tabular — variable name, description |
| See Also section | Related commands with one-line descriptions |
--help Behavior
gl --help→ root helpgl <group> --help→ group helpgl <group> <command> --help→ command helpgl <group> <command> -h→ identical to--helpgl <invalid>→ error with a did-you-mean suggestion plus a help hint
Command Design Patterns
Subcommand Structure
Every command group follows a Click group/command registration pattern:
import click
@click.group()
def dev() -> None:
"""Start, stop, and manage development services."""
@dev.command()
@click.argument("services", nargs=-1)
@click.option("--apps/--no-apps", default=True, help="Include Next.js apps.")
def start(services: tuple[str, ...], apps: bool) -> None:
"""Start development services."""
...
Groups are registered on the root CLI in main.py:
from gospelib_cli.groups.dev import dev
from gospelib_cli.groups.infra import infra
# ...
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx: click.Context) -> None:
"""GospeLib developer CLI."""
if ctx.invoked_subcommand is None:
show_dashboard()
cli.add_command(dev)
cli.add_command(infra)
# ...
Flag Naming Conventions
| Rule | Example | Avoid |
|---|---|---|
Long flags use --kebab-case | --dry-run, --output-dir | --dryRun, --output_dir |
| Short flags are a single letter | -v, -q, -o, -n | -vv (use counted -v instead) |
Boolean flags use --x/--no-x | --apps/--no-apps | --skip-apps |
Value flags use --key VALUE | --service gateway | --service=gateway (allowed but not preferred) |
Reserved Global Flags
These flags are available on every command via the root group:
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
--help | -h | bool | — | Show help and exit |
--version | bool | — | Show version and exit (root only) | |
--verbose | -v | count | 0 | Increase verbosity (0=normal, 1=verbose, 2=debug) |
--quiet | -q | bool | false | Suppress non-essential output |
--no-color | bool | false | Disable colored output | |
--output | -o | choice | human | Output format (human, json, table, csv) |
--log-file | path | None | Write structured logs to file |
Flag Categories
Commands should organize flags in help output using this order:
- Action flags — what to do (
--dry-run,--force,--check) - Scope flags — what to target (
--service,--stack,--file) - Filter flags — narrow results (
--filter,--status,--label) - Sort/group flags — organize results (
--sort,--sort-desc,--group-by) - Display flags — control output (
--output,--fields,--limit) - Verbosity flags — control logging (
--verbose,--quiet,--log-file)
Positional Arguments Policy
- Use positional arguments only when the meaning is unambiguous from context.
- At most one positional argument per command. Additional selectors must use flags.
- Variadic positional arguments (e.g.,
SERVICES...) are allowed when semantically clear. - Optional positional arguments must have a documented default.
Mutually Exclusive Flags
--verbose and --quiet are mutually exclusive, as are --sort and --sort-desc. The CLI validates this at invocation time and exits with a usage error if both are provided.
Enforce mutual exclusivity with manual validation:
if verbose and quiet:
raise click.UsageError("--verbose and --quiet are mutually exclusive.")
Argument Validation
- Use Click's built-in types for basic validation:
click.Choice,click.Path,click.INT,click.IntRange. - For complex validation, parse CLI options into a Pydantic model and let
ValidationErrorsurface issues. - Display validation errors using the standard error format (see Configuration & Error Handling).
Exit Codes
Every command must return a meaningful exit code:
| Code | Meaning | When to use |
|---|---|---|
0 | Success | Command completed without errors |
1 | General error | Command failed (default for unhandled exceptions) |
2 | Usage error | Invalid flags, missing arguments, bad syntax |
3 | Configuration error | Missing or invalid config file, env var, or dependency |
4 | Dependency unavailable | Docker not running, service unreachable |
5 | Partial failure | Some items succeeded, some failed (batch operations) |
10 | Tests failed | Test suite ran but had failures |
11 | Lint errors found | Linter found violations |
12 | Format check failed | Files need formatting |
130 | Interrupted (SIGINT) | User pressed Ctrl+C |
Exit codes above 2 let scripts distinguish between "the user invoked the command wrong" and "the command ran correctly but found problems." This is especially useful in CI pipelines.