L lerd lerd-env/lerd v1.35.0…v1.36.0 ↗
ENGINEERING DIGEST · 2026-09-16 → 2026-10-01

v1.36.0

A DASHBOARD THAT LIVES ON YOUR DESKTOP · and a Debug window that hears the rest of the app

Omarchy, Plasma, GNOME and macOS all publish colours the user picked on purpose, so the dashboard offers the desktop as a theme of its own and repaints every window when it changes, and the admin dashboards it embeds stop wearing their own greys inside lerd's frame. The Debug window learned logs, exceptions and the messages a site sends that are not mail, each declared in the store against the package that owns it. Worktrees pick their own database from their migrations, and the store learned to change shape without breaking a binary already installed.

114
commits
114
merged PRs
843
files
+35,838
insertions
−3,701
deletions
4
contributors
web UI 27% cli 17% config 10% podman 9% tests 7% rest 30%
01

Desktop

FEATUI

A desktop already says which colours its user wants, so the dashboard reads them rather than asking. The desktop appears in the theme picker as one entry named after what it is wearing, taking the place of the built-in theme that imitated it, and every open window repaints when the desktop changes. A theme chosen on purpose is never overridden. #1864 #1924 #1940 #2042

WHERE EACH DESKTOP KEEPS ITS COLOURSread by lerd-ui, watched for changes
Omarchy
colors.toml
the active theme
Plasma
kdeglobals
accent and scheme
GNOME
accent-color
Yaru tones on Ubuntu
macOS
AppleAccentColor
the system swatch
──►
dashboard
one theme
every open window
A desktop publishes one accent tuned for its own surfaces, so in light mode it is stepped toward black until it reads at 4.5:1 on white, and the label on every filled accent button is measured against the accent in use rather than always written in white.
FEATUI

Asked once per install, not once per browser #1978

A banner suggests the desktop's theme to an install that never chose one, and the answer, use it or keep, is kept in the config, so the desktop app and every browser agree and nobody is asked twice.

FEATUI

The embedded dashboards wear it too #1875 #1845 #1960 #2025

pgAdmin, Kafbat UI and RedisInsight are asked for their own dark design and then have their greys laid over lerd's. phpMyAdmin, Mongo Express and RabbitMQ have none, so their stylesheets are turned around. Mailpit wears the accent through Bootstrap's own variables, and each one is handed the dashboard's language.

FEATUI

Following window focus on Plasma #2021

Breeze draws a focused window's header in its own tone, so next to every other KDE window the dashboard looked unfocused. The rail and headers lift to the scheme's header colour while the window has focus and drop back when it moves away.

FEAT

A chromeless app window on Linux #1938

lerd dashboard, the launcher and the tray open it as a Chromium --app window when the desktop app is not installed, and on Hyprland and Plasma an open window is focused rather than a second one opened.

FEAT

Glance in place of the tray on Omarchy #1944 #2067

The bar already shows lerd's state through the Lerd Glance plugin, so a fresh install on Omarchy turns the tray off and adds the plugin. lerd uninstall takes it off the bar again.

FEATUI

Get started, then out of the way #1982

A fresh install opens on a card whose steps tick themselves off from state the dashboard already reads: a first site, a running service, notifications, the desktop's theme, starting with the dashboard and idle-suspend. It hands its slot back when the last one ticks.

FEATUI

Driven without a mouse, or without sight #2027

Dialogs take focus, keep Tab inside and hand it back on close, a Skip to content button is the first stop, toggles are switches that say whether they are on, detail tabs move with the arrow keys, and every view has a heading and a title naming what is open. Secondary text and the accent as link text reach WCAG AA on every theme, derived per theme rather than hand tuned. The same pass moved the status banner into the header as a pill, gave each worktree tab its git state the way a shell prompt shows it #1949, offers to initialise git on a site that has no repository #1988, and lets the System page register lerd with AI assistants from a switch #2016.

02

Debug

FEAT

The Debug window's wire format has carried log, exception and message kinds since it was built, with nothing ever emitting them. Each now has a source declared in the store against the composer package that owns it, so the Go side knows no framework by name and a new reporter is a YAML file away.

WHAT AN APP SAYS, AND WHERE IT LANDSobserved on the way out, never intercepted
ray()
Dumps
no Ray app, no licence
Monolog
App log
grouped by request
Sentry · Inspector
Exceptions
the line that threw
SMS · Slack · notify
Messages
nothing catches these
A message really leaves the machine and is really billed, unlike mail, which Mailpit answers for. That is why a message raises a desktop notification even while a dashboard window has focus.
FEAT

ray() without Ray #1887

Inside a container ray() reaches no desktop app, so the value was simply lost. The payload is taken on its way out and shown as the dump it wraps, labelled by the kind of call.

FEAT

An App log lens #1889

Records come from Monolog with level, channel and context, grouped by the request that wrote them, and are taken where they are written, so a line the app's handlers drop still shows.

FEAT

Exceptions, from either reporter #1891 #1893

Locally Sentry and Inspector catch everything and send it nowhere anyone looks. The report is observed, so a configured DSN still sends, and the row names the line the exception was thrown from, not the one that reported it.

FEAT

Messages, and the lens a click opens #1900 #1903

Symfony Notifier covers Twilio, Vonage and Slack with one declaration, and Laravel notifications are reported on every channel but mail. Clicking a notification opens the lens it is about rather than whichever one the tab last showed.

FEAT

Caught mail, scored #1839 #2078

The SpamAssassin backend is a store preset Mailpit finds on its own, and the templates a request rendered travel on the message as X-Lerd-View. Mailpit's page offers the preset until it is installed or dismissed.

FEAT

Large logs, a page at a time #2064

The App logs tab opens on the newest entries and fetches older ones as you scroll up, keeping your place, so a log of hundreds of megabytes no longer takes the browser tab down.

03

Worktrees

FEAT

A worktree's database used to be a question that a script or an assistant could not answer. A framework can now name its migrations folder, and a worktree set up with nobody to ask, from the MCP tool, a script or lerd worktree setup, compares it with the parent checkout and decides, then says which and why. At a terminal and in the dashboard the question is still yours. #1969

THE BRANCH'S MIGRATIONS AGAINST THE PARENT'Sunattended, with no database chosen
same set
share
the parent's database
branch adds some
clone-main
a copy, then migrate
branch lacks some
empty
a new one, migrated
A branch missing the parent's migrations is behind it, and pointing it at the parent's schema would run code against tables it does not know. An explicit choice, or a required isolation, still wins.
FEAT

SQLite gets its own copy #1936

The file is gitignored, so a worktree had none while its env pointed at the same relative path. The parent's file and its write-ahead log are copied in before dependencies install.

FEAT

Ready when the tool says so #1965

The MCP server points worktree work at its tool rather than plain git, and add finishes setup the way the dashboard does: assets built, database wired, the definition's commands run.

FEAT

Worktrees other tools made #2051

A worktree created with plain git worktree add is finished by lerd worktree setup run inside it, and the flag that isolates its database stays in the untracked .lerd.local.yaml rather than the committed config (#1968).

three branches, three answers, from a scriptbash
lerd worktree add ../app-same same
Database: share, since the migrations match the parent checkout's.

lerd worktree add ../app-extra extra
Database: clone-main, since this branch adds migrations the parent checkout lacks (1), so it gets a copy of the parent's database to run them on.

lerd worktree add ../app-fewer fewer
Database: empty, since the parent checkout has migrations this branch lacks (1), so its database is ahead of this code.
04

Store

FEAT

Definitions reach every install within a day with no version gate, so the store may only grow. This cycle gave it a way to change shape anyway: a tree per definition schema, read newest first by the binaries that understand it, and left alone by those that do not.

FEAT

Fetched at the schema it reads #1912

This binary asks for its own schema's tree first and falls back to the path every older binary reads, so a definition can be introduced to new binaries only, the way SpamAssassin was.

FEAT

A value it cannot honour is refused #1911

A restart policy systemd cannot parse is silently dropped, and a schedule it cannot parse stops the timer loading. Both are checked before the unit is written, naming the value and asking for an update.

FEAT

An installed service sees its definition change #1913 #1919

A service kept what its preset said on the day it was installed. The definitions behind installed services are refreshed, so a dashboard a preset gained later actually reaches it.

FEAT

Services suggested from what a project requires #1986 #2006

A package names the services it points at, so a Drupal site requiring search_api_solr gets Solr ticked at setup and suggested on its Overview, with the reason. A dismissal stays with that site.

FEAT

A framework's own installer #1986

A definition declares its installer with the file it writes, so a scaffolded Drupal site is offered its site install at setup, ticked while that file is missing and gone once it exists.

FEAT

Setup brings up what its workers need #2076

A worker that needs a service, a Redis queue say, used to fail setup with a hint to start it by hand. Setup starts it first, and asks only when there is a terminal to ask on.

FEAT

Admin consoles that let you straight in #1841 #1849 #1873

An admin tool can front several engines now, which is how Adminer serves MySQL, MariaDB and PostgreSQL from one preset. The RustFS console opens already logged in, on the bucket you clicked, and logs in again once its session runs out rather than leaving you at its login form.

05

Projects

FEAT

The rest of the cycle widened what a project can be and what it can run on, each one declared in the store or detected from the project rather than taught to the binary by name.

FEAT

Node through mise #1915 #2051

macOS remembers a folder grant against the signature of the binary that asked, and fnm ships unsigned, so a project under Documents was asked for again after every version bump. mise is notarized, so the grant holds. Versions pinned in mise.toml and .tool-versions are read too.

FEAT

ODBC in every PHP image #1854

unixODBC with ext-odbc and pdo_odbc ships in the images, and lerd php:odbc add registers a licensed vendor driver, checking from inside the image that it will load and naming the cause when it will not.

FEAT

Vite+, Mix, Rack and Rails #1971 #2012 #2010

The Laravel starter kits start through vp dev, now served on the site's own domain like vite, and Laravel Mix gets a watcher worker. A config.ru is a Rack app, Rails runs through bin/rails server, bound where nginx can reach it.

FEATUI

Streaming mode #1950 #1953 #1973

Mark a workspace private and, while the mode is on, its sites leave every snapshot the dashboard and the TUI receive. On Wayland it follows screen shares through PipeWire on its own. It draws nothing until enabled.

FEATUI

Services on a site's Overview #2044

A declared service carries an X that takes it out and points the env back at the example values, and the removal is remembered so the next lerd env does not wire it back.

FEAT

Unattended uninstall that keeps data #2060 #2067

lerd uninstall --keep-data removes lerd without prompts and keeps the config, the databases and the images, and install.sh --uninstall now runs it, so there is one uninstall to keep right.

06

Fixes

FIX

The fixed list covers bugs that shipped in 1.35.0 or earlier. Regressions introduced and fixed inside this cycle never reached anyone, so they are left out. The release closed on scripted passes of the test plan across the distro guests and a Mac, and the ones that cost a new user the most all sat on a first run: the first link, the first start, the first download.

WHAT A FIRST RUN METordered by how early it bit
1
lerd link reported done before the site was served #1989

Linking reloads nginx and returns, and the previous generation of workers goes on serving while it drains, so the request made straight after linking answered Site Not Found. Every site change now waits for the old workers to retire, the way a domain change already did.

2
A first start stopped halfway failed every start after it #2060

A database initialises its data directory on the very first start, and an interrupted one left a half written directory that every later start read as an existing database. A first start that does not finish now moves its directory aside, so the next one initialises cleanly.

3
A service's first download said nothing #2058

The first start of a built-in service pulled its image silently, which on a slow line looks exactly like a hang. It names the image and its size first, on the CLI, the dashboard and over MCP, and fails cleanly offline.

4
A service whose port was taken while it was down could not start #1920

The guard that moves a service off a contested port trusted a port already in the config, so the service failed at the bind and sat in a restart loop, which then read as the port's owner. It probes the port it would actually publish now and moves it the way it always moved a busy default.

FIX

lerd stripe:listen restart looped #2060

The Stripe CLI release of September 29 started refusing a bare listen, and lerd ran the unpinned latest image, so every listener on every install went into a restart loop overnight.

FIX

A MySQL 9.7 snapshot restore emptied the database #2053

The dump carried GTID state and the server's own schema, which 9.7 refuses on the way back in, so a restore reported success over an empty database.

FIX

A LAN share broke links and form posts #2014

The rewrite missed URLs escaped inside JSON and passed Secure cookies over plain http, so a shared site rendered and then fell apart at its first client-side link or login.

FIX

Containers had no route out after a late network #2054

A network created before the host had a route left every container offline until it was rebuilt by hand. lerd notices and rebuilds the container network itself.

FIX

A private package's auth was never read #1993

lerd composer pointed composer at its own home, so the auth.json a private repository needs was not where it looked.

FIX

A removed service came back #2000

Install restored service units from every site's .lerd.yaml, so a service removed on purpose was back after the next start. A removal is remembered now.