Docs
Prerequisites
Before you start, make sure you have the following in place.
A host machine
Last Light runs as a single Node process (locally) or a single Docker container
(in production). Each workflow phase runs inside its own isolated sandbox so the
agent cannot touch your host filesystem, credentials, or git identity. The
sandbox backend is selected by LASTLIGHT_SANDBOX:
gondolin (default — QEMU micro-VM via agentic-pi, uses HVF on macOS
and KVM on Linux, no Docker needed), docker (sibling Docker container
per phase), or none (in-process, dev only).
- Node.js 20+ — for local development (
npm run dev). - Docker — required only when
LASTLIGHT_SANDBOX=dockeror for the bundled docker-compose deploy. The default gondolin sandbox does not need it. - KVM (Linux) or HVF (macOS) — required by gondolin for nested virtualisation. Bare-metal Linux and Apple Silicon Macs both have it; most managed container hosts do not.
- Git — for cloning the repo you want to deploy.
A GitHub App
Last Light authenticates to GitHub as its own GitHub App rather than as a personal
access token. This keeps the bot's actions clearly attributed (last-light[bot]),
lets you downscope permissions per workflow, and makes installation per-repo
instead of per-user.
The Create a GitHub App page walks through the exact
permissions and events to request. You'll end up with four values you need to
paste into .env: App ID, Installation ID, webhook secret, and a
.pem private key.
Model provider credentials
The agent runtime is agentic-pi —
it runs on any model the pi coding agent supports
(Claude, GPT, Gemini, Llama, and more — as openai/…, anthropic/… or openrouter/<vendor>/<model> strings). The default is
anthropic/claude-sonnet-4-6. Set the matching API key in .env:
OPENAI_API_KEY— required ifLASTLIGHT_MODELresolves to an OpenAI model.ANTHROPIC_API_KEY— required ifLASTLIGHT_MODELresolves to an Anthropic model.OPENROUTER_API_KEY— required ifLASTLIGHT_MODELresolves to an OpenRouter model (openrouter/<vendor>/<model>). One key gives you access to Claude, GPT, Gemini, Llama, Mistral, DeepSeek, and most others through a single endpoint — at a small per-token markup over going direct. Sign up at openrouter.ai/keys.- You can set all three — phases routed via
LASTLIGHT_MODELSJSON can mix providers freely.
A state database — SQLite or Postgres
Last Light keeps its own state — workflow runs, executions, approvals, cron
history, chat sessions — in a relational database. You choose which at deploy
time, and it is the only piece of infrastructure the harness needs beyond the
host itself. lastlight server setup asks the question directly and
writes the answer for you.
- SQLite (default, recommended) — nothing to install and nothing to run. The database is a single file,
lastlight.db, inside the agent's data volume. This is what production has run on since day one; if you have no reason to prefer otherwise, take it. - Postgres — an external or managed server you supply: self-hosted, RDS, Cloud SQL, Supabase, or serverless Neon. Set
DATABASE_URLto apostgres://URL and the harness runs its Postgres migrations against it at boot. The driver is picked from the host —*.neon.techuses Neon's serverless WebSocket pool, everything else uses node-postgres — and you can force it withDATABASE_DRIVER=pg|neon.
Nothing else in the deployment changes between the two: the same compose stack,
the same overlay, the same workflows. Pick Postgres when the state should
outlive the host, when something else needs to read it, or when your tooling
already assumes Postgres — not for throughput, which is not the constraint at
this write volume. You can also start on SQLite and move later:
lastlight server db migrate copies an existing database across,
verified, in one command.
Optional: a Slack workspace
Slack integration is optional but recommended — it's how you chat with the bot outside GitHub. You'll need permission to create a Slack app and install it in your workspace. See Slack integration.
Optional: a public domain
To receive GitHub webhooks in real-time (instead of relying on cron polling), the harness needs to be publicly reachable over HTTPS. In production this is handled by the bundled Caddy reverse proxy, which provisions TLS automatically — you just point a DNS record at your host. For local testing, use ngrok or Cloudflare Tunnel.