Last Light

Self-hosted MIT-licensed Enterprise-ready Evals on your own code

An autonomous AI software factory, working after dark

A self-hosted, MIT-licensed software factory for your GitHub org: triaging issues, reviewing PRs, and shipping fixes on a production line you own, while you're away. And because it's your factory, you measure it on your code: evals built from your own repos, not someone else's benchmark.

Everything the line runs

Issue triage, PR review, security scans, on-request builds, a weekly Slack digest, Slack chat. Every job on the line is a YAML workflow you can fork and edit.

Issue Triage

Labels, deduplicates, and chases missing info. Real-time with webhooks, or every 15 minutes via cron.

PR Review

Reads the diff, leaves honest feedback. Instant via webhooks, or polled every 30 minutes. Critical issues first, nits last.

Weekly Digest

Monday morning summary, per repo, of what shipped and what Last Light did about it — merged PRs, the review queue, anything waiting on a human, what it cost. Posted to a Slack channel each repo picks. The numbers are computed, not written by a model.

Build on Request

@mention the bot on an issue and it runs the full Guardrails → Architect → Executor → Reviewer line with fix-feedback loops, then opens a PR. See how it works.

Slack Chat

DM the bot or @mention it in a channel. Every thread becomes a growing conversation: the agent resumes the same session on every turn, so context holds for hours or days. Every turn persisted.

Approval Gates

Workflows can pause at human-in-the-loop checkpoints. Approve or reject from a GitHub comment, a Slack slash command, or the dashboard, and the run resumes exactly where it stopped.

YAML Workflows

Every behavior (triage, review, build, health) is a YAML workflow you can fork. Phases run linear or as a DAG. The runner knows nothing about "build" vs "triage"; it just executes what you declare.

Permission Profiles

Every workflow runs with a downscoped GitHub App token: read, issues-write, review-write, or repo-write. A triage run literally cannot push code.

Feedback Signals

A 👍 or 👎 on something the bot wrote is scored against the run that wrote it. So when you change a prompt you can measure whether quality moved, instead of guessing.

Per-Repo Config

A repo can commit its own .lastlight/ to tune models, prompts and skills for itself. Always read from the default branch, so a PR can't reconfigure the agent reviewing it, and clamped so a repo can only ever be more conservative than you.

Dependency Automation

Dependency-update PRs get assessed for impact, broken CI gets the smallest fix pushed, and the trivially safe ones get auto-merge enabled. The risky ones wait for you.

Inside the dashboard

Every agent session (sandbox runs, Slack chats, cron jobs, approval gates) is logged, browsable, and streamable. The dashboard at /admin has eleven tabs, from runs and sessions to crons, feedback, logs and a router playground. Here are the ones you will live in. If you would rather watch it from somewhere else, every run also exports an OpenTelemetry trace with per-turn tokens and cost, which renders as a proper agent tree in Phoenix or Langfuse.

Home Live activity, rolling execution / token / cost stats, running containers, and the most recent workflow runs at a glance.
Workflow Runs The pipeline DAG for every run: Context → Guardrails → Architect → approval gate → Executor → Reviewer → PR, with fix-feedback loops stacked under the reviewer. Click any phase for its full message stream.
Sandbox Sessions Drill into any sandboxed agent run. Full agent conversation (assistant thinking, tool calls, reviewer verdicts) filterable by skill, repo, and time range.
Chat Sessions DB-backed history for every Slack thread. The bot rehydrates the same pi-ai conversation each turn, so one thread = one growing, coherent conversation.
Feedback Every 👍 and 👎 scored against the run that earned it, broken down by workflow and plotted over time. This is how you tell whether a prompt change actually helped.
Repos → Config The effective config for one repo with a default / overlay / repo badge on every single key, the commit its .lastlight/ layer was read from, and the operator bounds it has to live inside.

How it works

Built on agentic-pi, it runs on any model the pi coding agent supports: Claude, GPT, Gemini, Llama, and more (default anthropic/claude-sonnet-4-6). Each workflow phase runs in its own sandbox, and five backends sit behind one interface: a gondolin micro-VM by default, or Docker, smolvm, Kubernetes, or none. Authenticates as its own GitHub App, so every action is clearly from the bot, not you.

1
Point it at your repos

List what you want watched in agent-context/rules.md

2
You move on to other things

Cron jobs keep running, scanning for new issues, unreviewed PRs, stale items

3
Last Light gets to work

Labels, reviews, closes duplicates, writes reports

4
The repo stays healthy

Everything happens on GitHub: comments, labels, reviews. No extra dashboard to check

Build requests move down a role-based Architect→Executor→Reviewer production line. Read how it works for the full picture. Already have an AGENTS.md or CLAUDE.md in your repo? Last Light reads those automatically, so your coding conventions, testing requirements, and architectural guardrails carry over.

Prove it on your own code

A factory you can't measure is a factory you can't trust. Last Light ships an eval harness that runs the real production workflows (the same triage, review, and build YAML that runs in prod) against a mocked GitHub, and scores them. The difference from every leaderboard you've seen: the benchmark is yours.

Built from your repos

Author eval cases straight from your own merged PRs and resolved issues. add-case --pr / --issue pins the real base/head SHAs, extracts the test diff, and derives the red→green gold. Not SWE-bench. Not someone else's code. Yours.

Pick the model that earns it

Run every workflow across Claude, GPT, Gemini, Llama and more, or replay your real per-phase config, for a deterministic, side-by-side scorecard: precision, recall, cost, tokens. Know which model can work your floor before you trust it.

Close the loop

Evals feed calibration: mine the failures, add repo context, re-run under a blind held-out gate, keep only what improves. The line gets measurably better at your codebase over time. Explore the evals harness.

Light it up

Two ways to get going. Let Claude Code stand it up for you (recommended), or run the steps by hand. For the full walkthrough (creating the GitHub App with the right permissions, deploying to production with Caddy TLS, wiring up Slack chat + OAuth login, and every env var the harness reads) start with the quick start.

Option A: set it up with Claude Code recommended

Last Light ships Claude Code skills that install, configure and launch the whole stack for you. Install the CLI and the skills:

npm i -g lastlight          # or run it via npx
lastlight skills install    # adds the bundled Claude Code skills

Then open Claude Code in an empty directory and ask:

"set up a Last Light server"

The lastlight-server skill checks prerequisites, scaffolds the working directory, walks you through the GitHub App, model and managed repos, launches the docker stack, and verifies it's healthy. Sibling skills cover the rest: lastlight-client (point a CLI at a server), lastlight-overlay (customize workflows & persona), and lastlight-evals (scaffold an evals workspace). See the quick start or the CLI reference for details.

Option B: set it up by hand

Step 1 Set a model API key

Last Light runs on any model the pi coding agent supports: Claude, GPT, Gemini, Llama, and more. Set the key matching your chosen model in .env:

ANTHROPIC_API_KEY=sk-ant-...
# or
OPENAI_API_KEY=sk-...
# or use one OpenRouter key for Claude / GPT / Gemini / Llama / ...
OPENROUTER_API_KEY=sk-or-v1-...

The default model is anthropic/claude-sonnet-4-6. Override it, globally or per-phase, via LASTLIGHT_MODEL / LASTLIGHT_MODELS.

No API key? You can pay with a subscription you already have instead. lastlight oauth login signs you in with Claude Pro/Max, ChatGPT Plus/Pro, or GitHub Copilot. All three work on the default gondolin sandbox, where the model call runs host-side against your credential store. The one exception is Codex on the Docker and smolvm backends: the call happens inside the guest there, and Codex has no in-guest token route.

Step 2 Clone Last Light

git clone https://github.com/nearform/lastlight.git
cd lastlight
npm install

Step 3 Create a GitHub App

Head to github.com/settings/apps/new and create an app with these permissions:

Generate a private key, save the .pem file into the lastlight folder, and install the app on your repos.

Step 4 Configure

cp .env.example .env

Fill in your GitHub App credentials in .env:

GITHUB_APP_ID=123456
GITHUB_APP_PRIVATE_KEY_PATH=./your-app.private-key.pem
WEBHOOK_SECRET=your-secret-here

Then add your repos to agent-context/rules.md:

## Managed Repositories
- yourname/your-repo
- yourname/another-repo

Step 5 Run it

# Start the server (with hot reload)
npm run dev

Then trigger work via the CLI in another terminal:

# Build cycle for a specific issue
npx tsx src/cli.ts https://github.com/owner/repo/issues/42
npx tsx src/cli.ts owner/repo#42          # shorthand

# Run maintenance tasks
npx tsx src/cli.ts triage owner/repo      # triage scan
npx tsx src/cli.ts review owner/repo      # PR review scan
npx tsx src/cli.ts health owner/repo      # health report

The CLI talks to the running server. It does not execute agents directly, so start the server first.

Step 6 Set up GitHub webhooks

Make Last Light react to repo events in real time: new issues, PRs, comments. The webhook listener is built into the server and starts automatically on port 8644.

In your GitHub App settings, set:

Subscribe to events: Issues, Pull requests, Issue comments, Check runs, Check suites (the last two power the "Re-run checks" buttons), and optionally PR reviews.

The endpoint must be publicly reachable. Use ngrok or Cloudflare Tunnel for testing, or deploy with the included Caddy reverse proxy for automatic TLS. See Run It for Real for production setup.

The deterministic event router handles the logic. issue.opened triggers triage, pr.opened triggers review, @mention from a maintainer triggers the full build cycle. No configuration needed beyond the webhook URL and secret.

Step 7 Connect Slack optional

Talk to Last Light from Slack. Uses Socket Mode (WebSocket), so no public URL is needed. The bot responds to DMs and @mentions in channels, with multi-turn conversation support.

Create an app at api.slack.com/apps with Socket Mode enabled and bot token scopes for messaging, then add to .env:

SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...

Optionally restrict access and set a delivery channel for cron reports:

SLACK_ALLOWED_USERS=U01ABC,U02DEF    # limit who can interact
SLACK_DELIVERY_CHANNEL=C01XYZ        # channel for health reports

Chat interactions are read-only by default. The bot can answer questions and create issues, but won't make code changes from Slack. Build requests go through GitHub.

Tricks up its sleeve

/pr-review

Precision-first PR review: only Critical & Important findings, posted as line-anchored inline comments

/issue-triage

Label, deduplicate, request missing info, and manage stale issues

/repo-health

Weekly health report: open/stale issues, PR velocity, and action items

/security-review

Scan with npm audit, semgrep & gitleaks plus AI review, filed as one grouped issue

/verify

Test a behaviour claim in the sandbox, reporting CONFIRMED / REFUTED / INCONCLUSIVE with evidence

/qa-test

Drive a CLI or running app through a flow, with step-level pass/fail evidence

/demo

Record a short demo video of a PR: headless-browser capture composited to an mp4

/answer

Research repo docs + the web and post a single sourced answer to a question

/explore

A Socratic Q&A loop that shapes a half-formed idea into a detailed spec, pausing to ask you questions

/pr-fix

Lightweight fix-and-push for issues raised on a PR, skipping the full architect/reviewer cycle

/security-feedback

Act on your verdict on a security finding: file it, accept the risk, mark it false-positive, or reopen

/dependabot

Bring a failing dependency PR up to date and push the smallest fix, then auto-merge it if it is trivially safe

Want more?

Check the roadmap for what's coming next

Pick your mode

Webhooks and cron handle the same jobs, so use one or the other, not both.

Webhooks recommended

Real-time. GitHub sends events as they happen: issues triaged instantly, PRs reviewed on open. Requires a public endpoint.

Event Response
Issue opened Instant
PR opened Instant
@mention from maintainer Architect→Executor→Reviewer build line

Cron

Periodic sweeps. No public endpoint needed, because the agent polls GitHub on a schedule. Simpler to set up, but slower to respond.

Job Frequency
Triage new issues Every 15 min
Check PRs awaiting review Every 30 min
Weekly health report Mondays 9am

The weekly health report runs regardless of mode, and it's useful either way.