L lerd geodro/lerd v1.23.1…v1.24.0 ↗
ENGINEERING DIGEST · 2026-06-04 → 2026-06-09

v1.24.0

HOST-PROXY SITES · GROUPED MCP · DASHBOARDS · HARDENING

This release teaches lerd to supervise non-PHP dev servers on the host behind its nginx and HTTPS, collapses the MCP server's ~80 flat tools into ten grouped tools and registers four more AI assistants, and broadens the dashboard with sites and services overviews, site groups, and a drag-reorderable list. Plus db:move, four new service presets, a framework-agnostic Stripe listener, and a round of systemd/quadlet injection hardening.

57
commits
27
merged PRs
240
files
+13.5k
insertions
−3.5k
deletions
2
contributors
cli 38% ui/web · dashboard 22% internal/* services 20% mcp 14% docs 4% tui · podman 2%
01

Host-Proxy Sites

FEAT

A project can declare a proxy command in .lerd.yaml, and lerd supervises that dev server on the host while nginx reverse-proxies the .test domain to it — same HTTPS, same DNS, same worker pipeline as a PHP site. A free port is auto-assigned, git worktrees are supported, and lerd asks for explicit consent before it ever runs a command shipped in a project file.

REQUEST FLOWnode · python · go · any dev server
browser
https://app.test
trusted cert
──►
nginx
reverse proxy
.test vhost
──►
host loopback
127.0.0.1:PORT
auto-assigned free port
──►
supervised unit
your dev server
systemd / launchd
consent-gated — lerd runs the project's proxy command only after you approve it at link time, never unattended.
.lerd.yamlyaml
proxy: npm run dev     # lerd supervises this on the host
domains: [app.test]
secured: true           # nginx terminates TLS, proxies to the free port
02

MCP Rework

BREAKINGFEAT
BREAKING · MCP TOOL SURFACE
The old flat tool names (sites, artisan, db_set, …) no longer exist. Call the matching group with an action instead — for example exec with action: "artisan", or db with action: "set". Re-run lerd mcp:enable-global (or lerd mcp:inject) so your assistant picks up the new manifest and reference.

The MCP server collapses its roughly eighty flat tools into ten resource-grouped tools, each driven by an action routed through one dispatch table. That halves the tools/list payload (~32 KB → ~16 KB) and makes the manifest static, so it no longer reshapes mid-session. Four more assistants register alongside the existing ones, all reading one shared, single-source tool reference.

site
link · domains · group
service
start · presets · config
db
set · move · dump
env
setup · get · set
runtime
fpm ↔ frankenphp
worker
start · heal · mode
exec
artisan · composer · vendor
framework
install · scaffold
diag
status · doctor · xdebug
worktree
add · list · remove
FEAT

Grouped surface #497

~80 flat tools → 10 grouped tools via one dispatch table that reuses every existing handler.

FEAT

Four more assistants #498

Codex CLI, Gemini CLI, GitHub Copilot and Google Antigravity join Claude Code, Cursor, Junie and Windsurf.

REF

One shared reference

Every assistant renders the same single embedded tool reference, so the guidance can't drift between them.

03

Dashboard

FEATUI

The Sites tab gains an overview dashboard when no site is selected, mirroring a redesigned, category-grouped Services dashboard. Related sites can be grouped under one base domain, and the list can be sorted and drag-reordered.

UI

Sites overview #492

A running-vs-total count, a paused tally and a failing-workers indicator, with sites as click-through tiles grouped by framework, favicon, TLS lock and worker dots.

UI

Services dashboard #491

Reorganised into categorized sections with preset cards and a suggestion banner so installable services are discoverable at a glance.

FEAT

Site groups #484

A main owns a base domain and the rest occupy its subdomains, with an optional shared database per secondary, managed from a grouping modal and the site tool's group_* actions.

UI

Sortable, drag-reorderable list #486

Sort the sites list, or drag a row to switch to a persisted manual order that pushes live to other open tabs.

04

Data & Services

FEAT

Databases can move between same-family services without losing data, four services join the preset catalogue, and the Stripe webhook listener works for any framework.

db:movebetween two installed members of one family
1
Dump from source

lerd db:move --from postgres --to postgres-18 dumps each site's database from the source service.

2
Create & restore on target

Creates and restores on the target, then repoints each site's .env and keeps an explicit db.service block in sync.

3
Source left intact

The source data is left untouched, so a move is reversible. #488

AdditionWhat it bringsPR
4 new presetssoketi, opensearch, redisinsight, beanstalkd, installable like any preset#489
Stripe listenerFramework-agnostic: secret from STRIPE_SECRET / _KEY / _API_KEY, configurable forward path#490
Horizon auto-reloadRun Horizon under a file watcher that reloads workers on code changes, toggled per project#471
Framework env.varsDeclare top-level defaults seeded only when a key is absent, so a value in .env is preserved#483
05

Developer Experience

FIXUI

A batch of correctness and polish across worktrees, non-Laravel frameworks, boot ordering, and localisation.

FIX

Per-worktree debug events #481

A worktree's captures no longer mix into the parent site's Debug window.

FIX

Framework-agnostic key gen #482

App-key generation runs through the framework console instead of a hardcoded artisan call.

FIX

Boot ordering #479 #480

MariaDB probed with mariadb-admin, and host Vite workers ordered after FPM so wayfinder doesn't run before PHP is up.

UI

.env editor scroll #485

The dashboard's .env editor scrolls to the bottom instead of cutting off long files.

i18n

Untranslated strings #502

The grouping modal, command palette labels and command run modal are translated across all seven non-English locales.

FIX

macOS overlay recovery #476

lerd start detects podman overlay-storage corruption and heals it, gated to darwin so it never fires on Linux.

06

Hardening

SECFIX

The systemd and quadlet generation is hardened against directive injection from a cloned repo, host-proxy commands stay behind consent on every path, and lerd stop stops raising spurious heal notifications.

THREAT MODEL · cloned repo can't inject#495 · #500
1
Unit / quadlet directive injection

Worker unit generation refuses a newline or NUL in the command at the generation boundary, and custom-service validation runs again at the quadlet boundary after dynamic_env resolves. #495 #500

2
Host-proxy consent on every path

The watcher's worktree setup and lerd unpause honour host_proxy.disabled and only run the command approved at link time, so a cloned .lerd.yaml is never run unattended.

3
No spurious heal on stop

A lifecycle marker records an intentional shutdown, so lerd stop suppresses heal notifications for workers lerd itself stopped; they come back on the next start.