Skip to main content

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:

ElementFormat
Usage lineUsage: gl <group> <command> [OPTIONS] [ARGS]
DescriptionOne short line, blank line, then 2–4 lines of extended detail
Arguments sectionTabular — name, description, choices/type
Options sectionTabular — short flag, long flag, description, default
Examples sectionIndented code block, one example per line
Env vars sectionTabular — variable name, description
See Also sectionRelated commands with one-line descriptions

--help Behavior

  • gl --help → root help
  • gl <group> --help → group help
  • gl <group> <command> --help → command help
  • gl <group> <command> -h → identical to --help
  • gl <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

RuleExampleAvoid
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:

FlagShortTypeDefaultDescription
--help-hboolShow help and exit
--versionboolShow version and exit (root only)
--verbose-vcount0Increase verbosity (0=normal, 1=verbose, 2=debug)
--quiet-qboolfalseSuppress non-essential output
--no-colorboolfalseDisable colored output
--output-ochoicehumanOutput format (human, json, table, csv)
--log-filepathNoneWrite structured logs to file

Flag Categories

Commands should organize flags in help output using this order:

  1. Action flags — what to do (--dry-run, --force, --check)
  2. Scope flags — what to target (--service, --stack, --file)
  3. Filter flags — narrow results (--filter, --status, --label)
  4. Sort/group flags — organize results (--sort, --sort-desc, --group-by)
  5. Display flags — control output (--output, --fields, --limit)
  6. 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

warning

--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 ValidationError surface issues.
  • Display validation errors using the standard error format (see Configuration & Error Handling).

Exit Codes

Every command must return a meaningful exit code:

CodeMeaningWhen to use
0SuccessCommand completed without errors
1General errorCommand failed (default for unhandled exceptions)
2Usage errorInvalid flags, missing arguments, bad syntax
3Configuration errorMissing or invalid config file, env var, or dependency
4Dependency unavailableDocker not running, service unreachable
5Partial failureSome items succeeded, some failed (batch operations)
10Tests failedTest suite ran but had failures
11Lint errors foundLinter found violations
12Format check failedFiles need formatting
130Interrupted (SIGINT)User pressed Ctrl+C
tip

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.