Docs

CLI

lastlight is a thin client for a running Last Light instance. It doesn't run agents itself — it authenticates once, then POSTs triggers and reads the instance's admin API over HTTP. That makes it the primary way to drive and debug an instance (including production) without SSHing to the host.

In development run it as npm run cli -- <args> (or npx tsx src/cli.ts <args>). Installed from the package, the binary is just lastlight. All examples below use the bare binary.

Connecting

lastlight login opens your browser to authenticate against the instance (password, Slack, or GitHub — whatever that instance has enabled) and saves the token to ~/.lastlight/config.json. Every later command runs against that saved instance.

lastlight login                       # prompts for the instance URL
lastlight login https://ll.example.com
lastlight login https://ll.example.com --password   # headless fallback (no browser)
lastlight logout                      # forget the saved instance + token
lastlight status                      # instance URL, server health, token validity

Target resolution for every command, highest priority first: --url / --token flags → LASTLIGHT_URL / LASTLIGHT_TOKEN env vars → the saved ~/.lastlight/config.jsonhttp://localhost:8644. So env vars override the saved file, which lets CI and scripts target a different instance without touching disk.

Chat

Chat with the bot from your terminal — the same in-process chat skill that answers Slack threads, no messaging platform required. With a message it's one-shot; with no message it opens an interactive REPL (type exit to quit). Each conversation is a stable thread, so context carries across turns, and the turn shows up in the dashboard Chat tab tagged cli.

lastlight chat "what does the build workflow do?"
lastlight chat                        # interactive REPL

Triggering work

Point the CLI at a GitHub issue or PR. A bare reference is the cheap default (triage an issue / review a PR); a full build cycle is always an explicit opt-in via build.

lastlight <github-url>                 # default: triage that issue
lastlight owner/repo#42               # shorthand for the same
lastlight build owner/repo#42         # FULL build cycle (architect → executor → reviewer → PR)
lastlight triage owner/repo           # scan a repo for issues to triage
lastlight triage owner/repo#42        # triage one issue
lastlight review owner/repo           # scan a repo's PRs to review
lastlight review owner/repo#99        # review one PR
lastlight verify owner/repo#42 -- "the rate limiter blocks"   # test a claim → CONFIRMED/REFUTED
lastlight qa-test owner/repo#42 -- "login, create a project"  # drive a flow → step pass/fail
lastlight health owner/repo           # weekly health report
lastlight security owner/repo         # security review

Un-sticking a pull request

When Last Light gives up on a PR it labels it requires-human, comments once explaining what it tried, and stops. pr retry is how you tell it to have another go: it re-arms both budgets — the attempt counter and the cost window — and re-runs the workflow that got stuck. The reason you type is recorded against the retry and reaches the next attempt as a note, so the agent knows what you knew.

lastlight pr retry owner/repo#42
lastlight pr retry owner/repo#42 the arm64 runner was flaky

It is the same act as commenting @last-light retry on the PR or removing the requires-human label — all three write one record, so none of them produces a second escalation comment. What a retry does not override: the lastlight-ignore hold label (which beats it outright), a run already working that PR, a fork PR, a red base branch, or a PR the harness could not read. Those exit non-zero with the reason. If the gate skips for a transient reason the ask is still recorded, and the next event honours it.

Debugging a running instance

These read the same data the dashboard shows, so you can investigate a remote instance from the terminal instead of SSHing in. Add --json to any of them for machine-parseable output (pipe into jq). Where an id is omitted, the CLI fetches the relevant list and lets you pick interactively.

Workflow runs

lastlight workflow list [--status failed] [--workflow pr-review] [--limit 20]
lastlight workflow log <run-id> [--follow]    # phases + per-phase status; --follow tails live

Agent sessions

lastlight session list [--limit 30]
lastlight session log <session-id> [--follow] [--since N] [--full]

session log renders the transcript like the dashboard timeline — tool calls paired with one-line result summaries. --follow streams it live; --full dumps the raw, unformatted transcript.

Log search

lastlight logs search "ECONNREFUSED"                   # search execution errors (default)
lastlight logs search "rate limit" --scope all         # errors + transcript content
lastlight logs search "could not clone" --scope messages --limit 20

Server / container logs

Read the raw docker logs of the instance's containers (the agent harness plus the egress sidecars) over the API — for crashes before any session was written, or a misbehaving sidecar.

lastlight server list                                  # the lastlight-* containers + status
lastlight server logs                                  # the agent harness (default)
lastlight server logs --tail 500 --since 10m --follow
lastlight server logs coredns-strict                   # a specific service/container

Approvals & stats

lastlight approvals list                               # pending approval gates
lastlight approvals approve <id> [--reason "..."]
lastlight approvals reject  <id> [--reason "..."]
lastlight stats                                        # totals + per-skill success/fail
lastlight stats --daily 14                             # cost / token rollups

Crons

List the instance's scheduled jobs, or fire one on demand — handy for testing a cron's behaviour without waiting for its schedule. trigger is fire-and-forget on the server: the cron fans out one workflow run per managed repo (or per discovered PR), so watch it land with lastlight workflow list. The same Run now button is on the dashboard's Crons tab.

lastlight cron list                                    # schedule, next/last run, status
lastlight cron trigger <name>                           # run a cron now (fire-and-forget)
lastlight cron enable <name>                            # enable a disabled cron (idempotent)
lastlight cron disable <name>                           # disable a cron (idempotent)

Server lifecycle (host-local)

Unlike the commands above (which target a remote instance over HTTP), these run on the server: they shell out to git and docker compose in a working directory (a full repo checkout + the instance/ overlay + the compose override symlink). The working dir resolves from --homeLASTLIGHT_HOME → the saved serverHome~/lastlight.

lastlight server setup                # scaffold/adopt the working dir (clone core + overlay)
lastlight server start [service]      # docker compose up -d
lastlight server stop  [service]      # stop one service, or the whole stack (down)
lastlight server restart [service]    # restart a service (default: agent)
lastlight server update               # pull core + overlay, build, recreate, restart sidecars, health-check
lastlight server status               # compose state + core/overlay version drift + forked-asset overrides

server update is the CLI equivalent of the production deploy.sh; it accepts --no-core, --no-overlay, --no-build, and --yes. The dashboard shows an "update available" banner when the running instance is behind the latest core or overlay.

Forking built-in assets

The instance/ overlay can override any built-in workflow, prompt, skill, or persona file — it wins by logical name at startup. lastlight fork (host-local) copies the built-ins you want to customise into the overlay so you can edit them per-deployment, instead of hand-copying files.

lastlight fork                        # list forkable workflows + agent-context (marks what's forked)
lastlight fork <workflow>              # copy a workflow YAML + every prompt & skill its phases reference
lastlight fork agent-context [file]   # copy soul.md / rules.md / security.md (all, or one named file)
lastlight fork classifier             # copy the base intent-classifier prompts (classifier.md + adds-info)

It writes into the overlay resolved from --home (else the cwd if it's an overlay or checkout, else the server home); pass --force to overwrite assets already present. Forked assets then show up as overrides — in lastlight server status and in the dashboard's Config → Overrides pane — each tagged "shadows default" or "added".

A repo's own .lastlight/ layer

The mirror image of forking: instead of an operator customising the instance, a managed repo commits a .lastlight/ directory that overrides a bounded subset of config for runs against itself. These commands run inside your own code repo and write to <git repo root>/.lastlight/ — they never fall back to a server's instance/ overlay, and refuse to run outside a git repo. See Per-repo config for the full contract.

lastlight repo fork                      # list what a repo may override
lastlight repo fork all                  # every workflow's prompts + skills + agent-context + classifier
lastlight repo fork <workflow>           # one workflow's PROMPTS + SKILLS — never its YAML
lastlight repo fork agent-context [file] # persona files (ADDITIVE — rename before committing)
lastlight repo fork classifier           # the base intent-classifier prompts [--home dir] [--force]
lastlight repo config validate           # check ./.lastlight/ offline, exactly as the server would [--json]
lastlight repo config show <owner/repo>  # the effective post-bounds config + provenance [--refresh] [--json]

repo config validate is fully offline — it runs the same validators the server runs, against the shipped default bounds — and exits non-zero if anything in the layer would be rejected, so it drops straight into CI. repo config show asks a connected server what it actually applies for that repo, tagging each value with the layer it came from; --refresh makes the server bypass its 60-second cache.

Claude Code skills

Last Light ships a Claude Code plugin that teaches Claude Code to install, configure and operate Last Light and Last Light Evals — ask it e.g. "set up a Last Light server" or "scaffold an evals workspace". lastlight skills install (host-local) installs the skills: when the claude CLI is present it registers the nearform/lastlight plugin marketplace and installs from GitHub — so the skills auto-update (claude plugin update) rather than being pinned to the CLI — otherwise it copies the bundled skills into ~/.claude/skills. Pass --local to use the copy bundled with this CLI instead of the remote.

lastlight skills install              # → ~/.claude/skills (user) [--scope project] [--local] [--no-marketplace]
lastlight skills list                 # bundled skills + where they're installed
lastlight skills uninstall            # remove them [--scope user|project]

The bundle includes lastlight-server, lastlight-client, lastlight-overlay and lastlight-evals. You can also register the marketplace directly: claude plugin marketplace add nearform/lastlight then claude plugin install lastlight@lastlight-skills.

Setup wizard

lastlight setup                       # first-run wizard — asks: client (login) or server (stack)
lastlight setup --client              # skip the prompt: configure this machine as a client
lastlight setup --server              # skip the prompt: run the full server config wizard

Global flags

FlagApplies toEffect
--jsonall read commandsPrint raw JSON instead of formatted tables — for scripting / jq.
--url <u>allOne-shot instance URL override (beats env + saved config).
--token <t>allOne-shot bearer token override.
--follow / -fworkflow/session/server logsStream live via server-sent events until interrupted.
--fullsession logRaw, unformatted transcript dump (no summarization).
The debug commands are read-only except approvals approve/reject and the trigger commands — investigating an instance never mutates it.