Docs
Run it locally
Local dev runs the harness on your host (so you get hot reload) but spawns every agent task in a real per-phase sandbox, exactly like production. This is deliberate: it's the only honest way to develop against the bot's actual execution model.
The default sandbox backend is gondolin — agentic-pi's QEMU
micro-VM, using HVF on macOS or KVM on Linux. No Docker needed. Switch to
LASTLIGHT_SANDBOX=docker if you'd rather run sibling Docker containers
(useful for prod-like smoke testing), or none for in-process dev runs.
1. Clone and install
git clone https://github.com/cliftonc/lastlight.git
cd lastlight
npm install 2. Create .env
cp .env.example .env Edit .env and fill in the four values you collected in the previous step:
GITHUB_APP_ID=123456
GITHUB_APP_PRIVATE_KEY_PATH=./your-app.private-key.pem
GITHUB_APP_INSTALLATION_ID=789012
WEBHOOK_SECRET=your-webhook-secret
Drop the .pem file into the project root (or wherever
GITHUB_APP_PRIVATE_KEY_PATH points). It's already in
.gitignore, so you won't accidentally commit it.
3. (Docker mode only) Build the sandbox image
docker compose --profile build-only build sandbox
Only needed if you set LASTLIGHT_SANDBOX=docker. The default gondolin
sandbox runs from the harness directly and needs no image build. Rebuild when
sandbox.Dockerfile changes.
4. Set a model API key
The agent runtime is agentic-pi —
provider-agnostic. Drop the matching key into .env:
# Default model is anthropic/claude-sonnet-4-6
ANTHROPIC_API_KEY=sk-ant-...
# Or, if you'd rather route to OpenAI
OPENAI_API_KEY=sk-...
LASTLIGHT_MODEL=openai/gpt-5.5
# Or use OpenRouter — one key, many models
OPENROUTER_API_KEY=sk-or-v1-...
LASTLIGHT_MODEL=openrouter/anthropic/claude-sonnet-4.5
# Sandbox backend — gondolin (default), docker, or none
# LASTLIGHT_SANDBOX=gondolin No interactive login step. pi-ai reads the API key from the harness env and forwards it into each sandbox.
5. Start the harness
# Server + dashboard, with hot reload
npm run dev
# Or individually
npm run dev:server
npm run dev:dashboard Under the hood, npm run dev:server calls scripts/dev-local.sh, which:
- When
LASTLIGHT_SANDBOX=docker, verifies Docker is running and the sandbox image exists. - Copies your
GITHUB_APP_PRIVATE_KEY_PATHinto./data/sandbox-data/secrets/app.pem(mode 600) so sandboxes can authenticate to GitHub. -
Sets safe defaults:
LASTLIGHT_LOCAL_DEV=1,STATE_DIR=./data,LASTLIGHT_SESSIONS_DIR=./data/agent-sessions. - Launches the harness with
tsx watch src/index.ts.
LASTLIGHT_LOCAL_DEV=1 tells the harness not to
touch your personal ~/.gitconfig or keychain. Everything
sandbox-related stays inside ./data/. Safe to run on a dev laptop.
6. Trigger work via the CLI
The CLI is a thin HTTP client — it POSTs to the running server. Open a second terminal:
# Cheap defaults — single agent invocation
npx tsx src/cli.ts owner/repo#42 # triage one issue
npx tsx src/cli.ts https://github.com/owner/repo/pull/99 # review one PR
npx tsx src/cli.ts triage owner/repo # scan repo for new issues
npx tsx src/cli.ts review owner/repo # scan repo for PRs to review
npx tsx src/cli.ts health owner/repo # weekly-style health report
# Expensive, opt-in — full Architect → Executor → Reviewer → PR cycle
npx tsx src/cli.ts build owner/repo#42
The default action for a single-issue or single-PR shorthand is the cheap one
(triage / review). Build cycles are always opt-in via the explicit build
subcommand.
7. Open the dashboard
The admin dashboard is served at http://localhost:8644/admin. It has four tabs: Home, Workflows, Sandbox Sessions, and Chat Sessions. You can watch sessions stream live, drill into any run, and resolve approval gates.
If you set ADMIN_PASSWORD in .env, the dashboard will
prompt for it. Otherwise it's open.
Optional: receive real webhooks
To receive real GitHub webhooks in local dev, expose port 8644 with
ngrok or cloudflared and point your GitHub App's webhook
URL at the public tunnel. Without webhooks you can still trigger every workflow
via the CLI.