A request lerd serves while debug capture is on now carries one id from nginx to PHP to the browser, so it opens on a timeline of everything it ran, its page reports its own errors back, and an assistant reads it over MCP led by what went wrong. The site header learned fetch, pull, push and branch switching, with the installs and migrations a move needs offered and the database snapshotted first. Services sleep when nothing uses them, secrets can come from a manager without touching .env, and the dashboard dropped from over a gigabyte to under 100 MB on a busy machine.
Every captured event already wore a request id, but nothing outside PHP knew it. Now PHP answers with an X-Lerd-Rid header, nginx writes it into its access log and the page carries it, so a recent request opens on a timeline of everything it ran, laid out on the time nginx measured. #2150 #2161
lerd browser-logs on injects a small script that reports uncaught errors, unhandled rejections, console messages and failed fetches, each tied to the request that served the page. Store presets add a frontend library's own events.
request tool that says what went wrong #2169Over MCP an assistant lists recent requests and reads one, and its lenses action leads with N+1 and slow queries, then exceptions, error logs, failed HTTP calls, jobs and browser errors, each counted once.
The inspect dialog, a failing doctor check and an App logs entry copy a short prompt naming the MCP call that reads the full data, rather than a dump that goes stale or gets cut.
The slowest routes list spans seven days, but a bar could only open its request while its events were still in the buffer. The events of each route's slowest request are now kept aside, survive a restart and are let go once it stops being the slowest. A bar with nothing kept says why, and offers to turn capture on when it is off.
Fetch, Pull and Push sit beside the worktree tabs whenever a branch tracks an upstream, a branch with none gets a Publish button, and the main checkout gets a branch switcher. Pull is fast-forward only and push is never forced. Switching or pulling first shows what the move brings in, and offers what it needs. #2177 #2180 #2182
The commits and files coming in, and any uncommitted file the move would overwrite, which holds it back.
Saved as branch-<name> for the branch being left, so a failed migration is one click from undone and coming back offers that copy. #2220
composer install, the project's JS install and the framework's migrate command, each ticked when the incoming changes call for it, with a warning when the target drops migrations.
Idle-suspend could already put a site's workers to sleep. With lerd idle services on it does the same for databases, caches and mail catchers once every site and worktree using them has gone quiet. #2008
env_provider, kept in tmpfs #2069A project whose secrets live in a manager declares a command in .lerd.yaml, such as infisical export --format=dotenv. lerd runs it behind the host command consent gate and keeps the output in a 0600 file under $XDG_RUNTIME_DIR that PHP loads for web requests, workers and the CLI, so the values never touch .env or container storage. The docs carry commands for Infisical, Doppler, 1Password, Bitwarden, sops, Vault and AWS.
lerd-ui held the Debug window's events in memory, and every open tab streamed the whole buffer in and grouped it in the browser. The buffer is a SQLite file now, and each lens reads one page from it, grouped, searched and flagged in SQL. #2188
| On a machine with a few busy sites | before | after |
|---|---|---|
| lerd-ui memory | over 1 GB | under 100 MB |
| opening the Debug window, per tab | over 20 MB | under 1 MB |
| times each page was mounted | 2 | 1 |
lerd-ui, the watcher, the tray and the MCP server aim at 64 MB unless GOMEMLIMIT says otherwise, so one large response no longer keeps a process several times its size for minutes.
dumps.buffer holds between 3,000 and 20,000 events, 5,000 by default, and a running dashboard resizes in place.
Sleeping, waking, pausing and unlinking a site write every unit first and reload once.
The TUI is rebuilt around one sidebar and one main area, drawn in the terminal's own palette, and ctrl+p reaches every page, site, worktree, service, action and setting, matching words in any order. Destructive actions stay in the CLI. #2040
lerd-dns was a dnsmasq container on Linux and a Homebrew dnsmasq on macOS. lerd dns-serve answers the TLD now, which drops the only image lerd built itself. An upgrade swaps it in with no sudo prompt.
Pick VS Code, Cursor, Zed, PhpStorm and others, installed ones first, or a custom command. One not on the PATH opens through its URL scheme, so a JetBrains IDE from Toolbox works.
front_controller: true #2134For apps that route their own .php URLs, like GLPI 11. Every .php request goes through index.php, and it travels in a committed .lerd.yaml.
Outdated services lead the grid with the version they move to, and one button updates each in turn, reporting every result.
nginx.fastcgi_params adds fastcgi_param lines to a site's PHP location, after the ones lerd sets, with {{root}} and {{public}}.
A guide next to the Herd and Laragon ones, covering databases and what happens to .htaccess now that nginx serves the site.
The fixed list covers bugs that shipped in 1.36.0 or earlier. Regressions introduced and fixed inside this cycle never reached anyone, so they are left out. Several of them passed silently: tests green, a status that read fine, a check that said unknown.
Chromium reads its own NSS store, so on a secured site with Vite running no script loaded, while text-only assertions and assertNoJavaScriptErrors stayed green.
The doctor always ran npm audit, which needs a package-lock.json. Each project is audited by its own package manager now.
On Ubuntu or Debian with mysql-server installed, its profile attached to the mysqld in lerd's container too, which then could not read its config.
lerd rebuild took a custom container down #2195It removed the running image before building the new one, while reporting success.
On npm 6 or Yarn 1 the marker the staleness check trusts is never written, so the watcher ran a clean install on every pass.