Skip to content

CLI Reference

Command-line interface reference for cosalette applications. The CLI is built automatically by App.run() using Typer, aligning with the framework's type-hint-driven philosophy (see ADR-005).

Usage

myapp [OPTIONS]

The executable name depends on your project's entry point configuration (see Build a Full App for packaging details).

Options

Flag Type Default Description
--version flag — Show application name and version, then exit
--show-devices flag — Show all registered devices, telemetry, commands, and adapters as a table, then exit
--show-devices-json flag — Show all registrations as JSON, then exit
--dry-run bool False Enable dry-run mode — swaps all registered adapters to their dry-run variants
--log-level str from settings Override the log level (see Log Levels below)
--log-format str from settings Override the log format (see Log Formats below)
--env-file str ".env" Path to the .env file used for settings loading
--help flag — Show the help message and exit

Exit Codes

Code Constant Description
0 EXIT_OK Application completed successfully
1 EXIT_CONFIG_ERROR Configuration validation failed (pydantic ValidationError)
3 EXIT_RUNTIME_ERROR Unhandled exception during the async lifecycle
4 EXIT_TASK_FAILURE The task supervisor shut the app down: a framework-started task failed under on_task_failure="exit", exhausted its restart budget, or a framework loop died (TaskSupervisionError, ADR-081)
5 EXIT_STALE A telemetry entity or stream stayed stale for App(exit_after_stale=...) seconds (StaleTelemetryError, ADR-083)
6 EXIT_LOOP_STALL The event loop did not run for COSALETTE_LOOP_STALL_TIMEOUT seconds; the watchdog dumped every thread's stack to stderr and ended the process without a graceful shutdown (ADR-088)

EXIT_CONFIG_ERROR also covers an invalid COSALETTE_LOOP_STALL_TIMEOUT. A loop stalled inside C code that holds the GIL ends through the watchdog's faulthandler backstop instead, after twice the timeout and with code 1, not 6. On stderr it shows faulthandler's Timeout (H:MM:SS)! header (Timeout (0:10:00)! for a 300 s timeout) followed by every thread's stack, with no CRITICAL cosalette: event loop stalled line. restart: on-failure and unless-stopped still restart the container on code 1.

The health subcommand has its own exit codes: 0 healthy, 1 unhealthy.

Log Levels

Valid values for --log-level (case-insensitive):

Value Description
DEBUG Verbose output for development and troubleshooting
INFO Normal operational messages (default)
WARNING Something unexpected that is not an error
ERROR An error occurred but the application continues
CRITICAL A severe error — the application may not recover

Log Formats

Valid values for --log-format (case-insensitive):

Value Description
json Structured JSON lines for container log aggregators (Loki, Elasticsearch, CloudWatch) — default
text Human-readable timestamped lines for local development

Example

# Run with defaults (loads .env, JSON logging at INFO)
myapp

# Development mode: text logs at DEBUG level
myapp --log-level DEBUG --log-format text

# Dry-run with a custom env file
myapp --dry-run --env-file config/staging.env

# Check the version
myapp --version

# Show all registered devices as a table
myapp --show-devices

# Show registrations as JSON (useful for AI agents and scripts)
myapp --show-devices-json

Introspection Flags

The --show-devices and --show-devices-json flags are eager — they run immediately after argument parsing and exit before settings validation. This means they work even when the .env file is missing or contains invalid values, making them useful for debugging configuration problems.

--show-devices renders a human-readable table sourced from the app's AsyncAPI document (app.asyncapi()), grouped by channel archetype (devices, telemetry, commands). It is not the registry snapshot and carries no adapters section — despite the flag name. Empty sections are omitted. To render the registry snapshot instead — including periodic tasks and per-entity trigger sources — use cosalette manifest --registry. See Registry Introspection for the snapshot structure.

--show-devices-json outputs the same AsyncAPI data as indented JSON, suitable for piping into jq or consumption by AI coding agents. When both flags are given, --show-devices-json takes precedence.

Health Probe

cosalette-health, cosalette health and myapp health check the health file that the app writes when the COSALETTE_HEALTH_FILE environment variable names a path (ADR-083, Health File). None of them loads settings or connects to the broker. Use them only where an orchestrator acts on the result: a Kubernetes liveness probe, a Docker Swarm service or an autoheal container. Plain Docker only marks a container unhealthy, so most deployments watch the MQTT signals and rely on a restart policy instead.

Prefer cosalette-health in probe commands. It is a native binary in the platform wheels and a stdlib-only Python script elsewhere (ADR-087), so a run costs about 1 ms instead of the Python interpreter start and framework import that cosalette health and myapp health pay (about 390 ms on a desktop CPU, seconds on a Raspberry Pi). All three take the same options and give the same result.

Flag Default Description
--file $COSALETTE_HEALTH_FILE Health file to check
--max-age 3 x the file's write interval Seconds after which the file counts as too old, which means the app is hung or dead
--fail-on stale Device status that fails the check; repeat the flag to give more than one, for example --fail-on stale --fail-on error

The probe exits 0 and prints the file's age when the file is fresh and no device has a failing status. It exits 1 and prints the reason on stderr when the file is missing, unreadable or too old, or when a device has a failing status. A usage error in the health arguments, such as --max-age -1 or an unknown option, also exits 1, with unhealthy: usage error: <message> on stderr, because Docker reserves exit code 2. cosalette-health --help exits 0. See Health Checks.

Errors before health still exit 2

Options placed before the subcommand, as in myapp --bogus health, are parsed by the app's own CLI rather than by health, so a usage error there exits 2. Put no options before health in a probe command, or use cosalette-health, which has no subcommand.

Registry Snapshot

The app-runtime --show-devices flags above are AsyncAPI-sourced. To inspect the registry snapshot — the flat view of registrations that also covers periodic tasks (which have no AsyncAPI channel by construction, ADR-041) and each entity's trigger_source / min_interval — use the cosalette package CLI:

# Registry snapshot as JSON
cosalette manifest myapp.main:app --registry

# Registry snapshot as a human-readable table
cosalette manifest myapp.main:app --registry --table

The table adds Trigger and Min interval columns to the Devices and Telemetry sections, showing an em-dash for non-triggerable entities. Without --registry, manifest and manifest --table emit the AsyncAPI document exactly as before.