Skip to content

CLI reference

Every lich command. The same content is what lich --help and lich <command> --help print — when you're at a terminal, the CLI itself is the most up-to-date source.

lich up

Bring the current worktree's stack up.

Usage: lich up [profile]

Bring the current worktree's stack up. Starts every compose service
and owned process declared by the active profile, runs lifecycle
hooks, and prints a summary with the resolved URLs.

With no argument, activates the default profile. Pass a profile
name to activate it explicitly.

Flags:
  --json          Emit machine-readable progress on stdout.
  --quiet         Suppress progress; print final summary only.
  --no-browser    Skip opening the dashboard in the browser.
  --raw           Print raw localhost URLs in the summary.

Exit codes: 0 on success, non-zero on any failure.

lich down

Stop the current worktree's stack and release resources.

Usage: lich down [--worktree <id-or-name>]

Stop the current worktree's stack. Tears down every compose service
and owned process, runs before_down lifecycle hooks, and releases
allocated host ports. State directory is preserved.

Flags:
  --json                  Emit machine-readable progress on stdout.
  --quiet                 Suppress progress; print final summary only.
  --worktree <id-or-name> Target a stack by ID or worktree name instead
                          of the current directory (see `lich stacks`).

Exit codes: 0 on success, non-zero on failure.

lich restart

Restart the stack (or selected services).

Usage: lich restart [service ...] [--worktree <id-or-name>]

Restart the whole stack, or the named services only. Respects
depends_on ordering.

Flags:
  --json                  Emit machine-readable progress on stdout.
  --quiet                 Suppress progress; print final summary only.
  --worktree <id-or-name> Target a stack by ID or worktree name instead
                          of the current directory (see `lich stacks`).

lich logs

Stream logs from the stack's services.

Usage: lich logs [service] [--tail=N] [--no-follow] [--worktree <id-or-name>]

Stream logs from the stack's services. Defaults to tailing all
services with --follow. Pass a service name to filter to one.

Flags:
  --tail=N                Show the last N lines (default 50 with --follow,
                          200 with --no-follow).
  --no-follow             Print existing logs and exit; do not stream.
  --worktree <id-or-name> Target a stack by ID or worktree name instead
                          of the current directory (see `lich stacks`).

lich urls

Print the reachable URLs for the running stack.

Usage: lich urls [--raw] [--worktree <id-or-name>]

Print every reachable URL for the running stack. By default emits
the friendly <service>.<worktree>.lich.localhost:<proxy-port>
form; --raw prints the underlying localhost:<allocated-port> URLs.

Flags:
  --raw                   Emit raw localhost URLs instead of friendly form.
  --worktree <id-or-name> Target a stack by ID or worktree name instead
                          of the current directory (see `lich stacks`).

lich dashboard

Open the lich dashboard in the default browser.

Usage: lich dashboard [--no-browser]

Open the lich dashboard (http://lich.localhost:<proxy-port>/) in
the default browser. Auto-starts the daemon if needed; can be run
from any directory.

Flags:
  --no-browser    Print the URL only; skip the browser open.
                  (Also honored via LICH_NO_BROWSER=1.)

Exit codes: 0 on success; non-zero if the daemon fails to start
or its reverse proxy is unavailable.

lich stacks

List every running lich stack on this machine.

Usage: lich stacks [--json]

List every lich stack currently running on this machine, with
worktree name, status, and uptime. --json emits machine-readable
output.

Both renderers read from the same in-memory snapshot — every value
shown in the table is derivable from --json.

JSON shape (array; one entry per stack, sorted by worktree_name):
  [
    {
      "stack_id": string,            // opaque ID, stable across `up`s
      "worktree_name": string,       // basename of the worktree dir
      "status": "starting" | "up" | "partial" | "stopping" |
                "stopped" | "failed",
      "lifecycle"?: {                // present iff lifecycle hooks ran
        "before_up"?: PhaseStatus,
        "after_up"?:  PhaseStatus,
        "before_down"?: PhaseStatus,
        "after_down"?:  PhaseStatus
      },
      "started_at": string,          // ISO 8601 timestamp
      "uptime_seconds": number,
      "services": [
        {
          "name": string,
          "kind": "owned" | "compose",
          "state": "starting" | "healthy" | "initializing" |
                   "ready" | "stopping" | "stopped" | "failed"
        }
      ],
      "primary_url"?: string,        // first service with allocated ports
      "active_profile"?: string      // omitted if no profile was active
    }
  ]

PhaseStatus =
  { "status": "ok" }
  | { "status": "not_run" }
  | {
      "status": "failed",
      "failed_index": number,        // zero-based
      "total": number,
      "failed_cmd": string,          // truncated to 80 chars + "..."
      "log_path": string             // per-phase log file
    }

Types live in packages/lich/src/state/snapshot.ts:
  StackSnapshot, ServiceSnapshot, StackStatus, ServiceState,
  LifecyclePhaseStatus, LifecycleSnapshotStatus

lich top

Live per-service CPU + memory view (table or JSON).

Usage: lich top [--no-follow] [--json] [--all] [--worktree <id-or-name>]
                [--tree <service>] [--sort cpu|mem|name] [--interval N]

Live per-service CPU + memory view. Follows by default, refreshing
every 2s; Ctrl-C exits cleanly. Owned services aggregate the full
process tree (parent + forked workers); compose services pull from
`docker stats`.

Flags:
  --no-follow             Print one snapshot and exit (default: follow).
  --json                  Machine-readable; implies --no-follow.
  --all                   Every running stack on this machine.
  --worktree <id-or-name> Target another worktree's stack.
  --tree <service>        Expand the process tree for one owned service.
  --sort cpu|mem|name     Service sort order (default: cpu).
  --interval N            Refresh interval in seconds (default: 2).

JSON shape:
  {
    "stack_id": string,
    "sampled_at": string (ISO 8601),
    "total": { "cpu_pct": number, "mem_bytes": number },
    "services": [
      {
        "name": string,
        "kind": "owned" | "compose",
        "state": string,
        "pid"?: number,                  // owned only
        "container_id"?: string,         // compose only
        "cpu_pct": number,
        "mem_bytes": number,
        "mem_limit_bytes"?: number,      // compose only
        "uptime_seconds": number,
        "process_count"?: number         // owned only
      }
    ]
  }

Note: the first sample of any owned service shows 0% CPU until the
second sample lands (ps's CPU% is cumulative; the daemon diffs across
two samples to derive current).

Exit codes: 0 on success; 1 if the daemon is unreachable; 2 on usage
error.

lich nuke

Stop every lich stack on this machine and clean state.

Usage: lich nuke [--yes] [--rescue]

Stop every lich stack on this machine and clean their state
directories. --rescue scans ~/.lich/started.log and runs idempotent
cleanup for resources state.json no longer references. --yes skips
the confirmation prompt.

lich validate

Statically analyse a lich.yaml without running anything.

Usage: lich validate [path] [--json]

Statically analyse a lich.yaml without running anything. Catches
schema errors, unknown depends_on references, dependency cycles,
broken regexes, and bad ${...} interpolations.

Exit 0 if clean, 1 otherwise.

lich init

Write a starter lich.yaml in the current directory.

Usage: lich init [--force] [--no-gitignore]

Write a starter lich.yaml in the current directory. Also appends
.lich/ to .gitignore unless --no-gitignore is passed. --force
overwrites an existing lich.yaml.

lich exec

Run an ad-hoc command with the stack's resolved env loaded.

Usage: lich exec [--env-group=<group>] [--no-preflight] [--worktree <id-or-name>] <cmd> [args...]

Run an ad-hoc command with the resolved env loaded. Defaults to
the built-in `stack` env_group; --env-group=<name> picks another.
Stdio is inherited so output streams live.

If the stack isn't up, a one-line warning is printed to stderr but
the command still runs. Use --no-preflight to suppress the warning
(handy in scripts).

Flags:
  --env-group=<group>     Resolve env from the named env_group (default: stack).
  --no-preflight          Suppress the stack-not-up warning.
  --worktree <id-or-name> Target a stack by ID or worktree name instead
                          of the current directory (see `lich stacks`).
                          The command runs in that worktree's directory.

Example: lich exec sh -c 'echo $DATABASE_URL'

Exit codes: 0 on success; child's exit code on failure; 2 on
usage error; 130 on SIGINT.

lich env

Print a named env_group as dotenv-format on stdout.

Usage: lich env <group> [--worktree <id-or-name>]

Print the named env_group as dotenv-format on stdout. Keys are
emitted in sorted order; values are quoted as needed so the
output round-trips through `source <(lich env <group>)`.

Flags:
  --worktree <id-or-name> Resolve the env_group against the named stack
                          instead of the current directory.

Example: source <(lich env stack)

Exit codes: 0 on success; 1 when the group is unknown; 2 on
usage error (no group name given).

lich routing

Print the daemon's in-memory routing table (friendly-URL debug).

Usage: lich routing [--worktree <id-or-name>]

Print the daemon's in-memory routing table as JSON. Useful when
a friendly URL (host:port from `lich urls`) 404s — compare what
the daemon has loaded against the routing entries in state.json.

Flags:
  --json                  Emit the table as JSON (default: table form).
  --worktree <id-or-name> Filter to entries from the named stack only.

Exit codes: 0 on success; non-zero if the daemon is unreachable.

Released under the MIT License.