L lerd geodro/lerd v1.25.0…v1.26.0 ↗
ENGINEERING DIGEST · 2026-06-17 → 2026-06-24

v1.26.0

MACOS INSTALLER · MONACO + PHPANTOM TINKER · TABBED TUI · STYLED CLI

The same install.sh one-liner that installs on Linux now installs on macOS, and lerd update self-updates there too. Every dashboard editor moves to Monaco, and Tinker's intelligence now comes from phpantom_lsp reading the real project, with inline SQL and per-line results. lerd tui becomes a mouse-driven tabbed dashboard, the CLI gains a styled feedback layer with responsive tables, and the website moves to its lerd.sh home. Underneath, a focused security pass closes name-injection, root-write and websocket-rebinding holes.

65
commits
42
merged PRs
343
files
+17.2k
insertions
−4.8k
deletions
4
contributors
ui/web · Monaco + landing 30% cli · feedback + tables 22% tui rewrite 14% installer · macOS 11% dns · lsp bridge 8% docs · services · rest 15%
01

macOS in the one-line installer

FEAT

Recent Homebrew releases block third-party taps until you brew trust them, so the tap stopped being a frictionless path. lerd's own install.sh is now cross-platform: the same curl … | bash one-liner installs on macOS the way it already does on Linux. All the heavy lifting, Podman Machine, mkcert, the /etc/resolver entry and the launchd plists, already lives in the cross-platform lerd install, so the script just delivers the right binary and hands off.

ONE-LINER → BINARY → HAND-OFFlinux + darwin
detect_os
linux · darwin
+ arm64 arch map
──►
download
darwin_<arch> asset
release binary
──►
prereqs
podman via brew
no sudo
──►
lerd install
machine · mkcert · resolver
launchd plists
──►
lerd update
self-update
reload agents
PATH is written to .bash_profile on macOS (login shell), .bashrc on Linux. brew stays an alternative, with a brew trust note.
install lerd on macOSbash
# the Linux one-liner, now on macOS too
curl -fsSL https://lerd.sh/install.sh | bash

# or Homebrew, with a trust step on recent brew
brew trust geodro/lerd && brew install geodro/lerd/lerd && lerd install
FEAT

Cross-platform install.sh #549

darwin + arm64 detection, the darwin_<arch> asset, brew-installed prereqs without sudo.

install.sh
FEAT

Self-update on macOS #549

lerd update pulls the darwin archive and reloads launchd agents, deferring to brew upgrade for a Cellar binary.

FIX

Clean uninstall #549

Boots out the launchd agents by their real com.lerd.* Label and removes detached lerd-* containers, BSD-sed safe.

02

Monaco editors & a real Tinker

FEATUI

Every in-browser editor moves from CodeMirror to Monaco, the Tinker REPL, the nginx overrides, php.ini and service tuning, and the site .env editor, lazy-loaded so the always-on bundle actually shrinks. Tinker's autocomplete, diagnostics, hover, quick fixes and formatting now come from phpantom_lsp, a self-contained Rust PHP language server that analyses the real project instead of static lists, so completions resolve actual models, relationships, scopes and vendor classes.

BROWSER ↔ phpantom_lsp/api/lsp/php · per connection
Monaco
headerless PHP buffer
one msg / frame
──►
/api/lsp/php
websocket bridge
synthetic <?php
──►
phpantom_lsp
rooted at site / worktree
stdio Content-Length
──►
intelligence
complete · diagnose · quick-fix
real models & vendor
graceful fallback — if the server can't be reached the editor still works and code still runs; only the live intelligence is unavailable.
tinker, now REPL-gradephp
// "Class not found" → quick fix inserts the use, grouped at the top
User::query()->where('active', true)->count();
// ↳ Line 2  · the executed SQL renders as its own card, bindings inlined
FEAT

Editors → Monaco #552

One lazy-loaded Monaco wrapper across every editor, Monarch grammars for nginx, ini and dotenv. CodeMirror dropped entirely.

ui · MonacoEditor
FEAT

phpantom_lsp #552

A Rust PHP language server lerd manages on the host beside fnm and mkcert, bridged per connection over a websocket.

FEAT

Quick fixes & inline SQL #554

Code-action imports, format on paste, per-line result badges, and every Laravel query as a full-width card.

03

A clickable tabbed TUI

FEATUI

lerd tui is reshaped around a top tab bar with Dashboard, Sites and Services screens, switchable by click or ctrl+left/right. Mouse support runs throughout, clicking a tab, a row, or a dashboard item jumps to its tab with that item selected, and the wheel scrolls whichever pane it is over without moving the selection. The Dashboard is a six-card overview mirroring the web UI, with app, service and worker logs surfaced in context.

SIX-CARD DASHBOARDmirrors the web UI · scrolls per card
Sites
running · paused
Services
by category
Workers
by site
Health
dns · certs
Resources
cpu · mem
Lerd
live activity feed
hot path stays cheap — app-log tail read once per render behind an mtime cache; autostart and LAN state fold into the periodic snapshot, so no fs / systemd work on render.
navigate the tabbed TUItext
lerd tui
  # click a tab, or ctrl+←/→ to switch  ·  Dashboard | Sites | Services
  # click a site/service/worker on the Dashboard → jumps to its tab, selected
  # wheel scrolls the pane under the cursor; keys keep the selection on screen
FEAT

Tabbed screens #574

Three clickable top tabs replace the old combined layout, with the version on the far right of the tab row.

internal/tui
UI

Mouse throughout #574

Clickable rows, tab strips and Debug lenses; wheel scrolls the hovered pane; keyboard selection follows once per move.

UI

Brand-red accent #574

The interactive accent becomes the lerd/Laravel red across both the TUI and the new CLI feedback layer.

04

A styled CLI feedback layer

FEATUI

A new internal/feedback package is the single source of the lerd colour palette (shared with the TUI) and a set of progress primitives, so every command gives consistent terminal feedback, a spinner that a check or cross replaces in place, a live accumulating line, aligned key/value summaries, styled prompts and an amber warning glyph. All of it degrades to plain text when stdout is piped, redirected, or NO_COLOR is set, so the MCP server and scripts keep parsing stable output.

ONE PALETTE, MANY SURFACEStty → styled · pipe → plain
internal/feedback
palette + primitives
shared with TUI
──►
step
spinner → ✓ / ✗
in place
──►
tables
responsive list views
unified errors
──►
NO_COLOR / pipe
plain text
stable for MCP
lerd env keeps a --verbose mode with full per-service detail (what the MCP server invokes); the install/start build TUIs keep their own rendering.
consistent feedback, list views as tablesbash
lerd env                  # each service ticks off on its own line as configured
lerd sites                # renders as a responsive table
lerd doctor | cat         # no leaked ANSI when piped
FEAT

Feedback package #568

The shared palette and progress primitives, with plain-text degradation and several piped-ANSI leaks fixed.

internal/feedback
FEAT

Responsive tables #610

List views render as tables, and error output is unified across commands.

UI

install · start #604

The install and start flows speak the same feedback vocabulary.

UI

service-stop · uninstall #608 #612

Stopping services and the uninstall path come onto the layer too.

05

Linking, DNS & services

FEATFIX

Linking gets friendlier, running a command in an unlinked project offers to link it through the init wizard rather than dead-ending, and lerd link routes through that same wizard and handles non-PHP projects. DNS gains pinnable upstream servers and heals a stale lan:expose mapping when the host LAN IP changes, postgres-timescaledb joins the presets, and the website moves to its lerd.sh home with a rebuilt landing page.

linking · dns · servicesbash
cd ~/Code/some-app && lerd artisan migrate   # unlinked? offers the wizard
lerd link                       # routes through init; non-PHP handled
lerd dns upstream 1.1.1.1        # pin the upstream resolver
lerd db:set postgres-timescaledb # new same-family preset
FEAT

Offer to link #558

An unlinked project is offered the wizard instead of dead-ending; ensureSiteForCwd resolves and links the same directory.

FEAT

link → init wizard #562

lerd link runs the init wizard and handles non-PHP projects.

FEAT

Pin upstream DNS #583

Choose the upstream servers lerd-dns forwards to rather than only the detected resolvers.

FIX

Heal on LAN change #553

A stale lan:expose mapping is repaired when the host LAN IP changes, with a macOS PF_ROUTE watcher.

FEAT

timescaledb & mariadb #572 #551

postgres-timescaledb joins the presets; the MariaDB image list is refreshed, keeping the bare 11 tag.

docs

The site lives at lerd.sh #564

A rebuilt landing page with a live demo on the custom domain, refreshed social and SEO. #559 #587

06

Security & hardening

SECFIX

A focused security pass closes three issues a hostile linked project, a local user, or a malicious site open in the browser could each exploit, alongside a round of reliability fixes to certs, podman startup, DNS and the MCP surface.

SECURITY PASS#613 · three vectors
1
Name injection

Site and worktree-branch names flowed into site_init shell commands and CREATE DATABASE identifiers. SiteSlug now maps every character outside [a-z0-9_] to an underscore, and database create/drop escape the identifiers as a second layer. #613

2
Root-write via symlink

The NetworkManager dispatcher rewrote each user's lerd.conf as root, so a symlink could redirect that write onto a root-owned file. The rewrite now runs through runuser as the owning user, with the upstream list filtered to IP/port tokens first. #613

3
Websocket DNS-rebinding

The dashboard handshake accepted any Origin whose host matched Host, which a rebinding page controls. The same-origin fallback now also requires an IP literal or a reserved local TLD, so a public domain rebound to loopback is rejected; loopback, LAN, and .test are unchanged. #613

FIX

Atomic cert swap #607

TLS certs are swapped atomically so an nginx reload never sees a missing cert; worktree DBs are provisioned and realigned on link and env. #608

FIX

Podman start retry #606

The machine start is retried once before failing the install, and versioned DB alternates no longer leak the bare canonical service. #605

FIX

MCP output visible #550

Worktree, diagnose, service env and check-updates results route through content blocks so the host actually sees them.

FIX

Agent env & tray #555 #585

AI agent detection is forwarded into the container, and the tray uses a dark icon on light desktop panels.

FIX

Legacy frameworks #582

Legacy framework versions resolve to the lowest available definition instead of failing.

SEC

Dependency advisories #566

vite and dompurify bumped to clear open Dependabot alerts.