Skip to content

Add rust - #17

Merged
geodro merged 2 commits into
lerd-env:mainfrom
mtolhuys:add-rust
Nov 9, 2026
Merged

geodro merged 2 commits into
lerd-env:mainfrom
mtolhuys:add-rust

Conversation

@mtolhuys

@mtolhuys mtolhuys commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Plugin

What it does

Lerd's host proxy already serves a Rust app with cargo run, but it never rebuilds on save, and a compile error takes the site down. This plugin makes lerd rust:dev the site's dev command. It builds each change while the running app keeps serving, and swaps to the newly built program only when the build succeeds. A failed build leaves the previous one serving and says so in the Dev Server log, on a Rust tab and, if the user allows it, in a notification. It also warns when the app runs but nothing answers on the HOST and PORT Lerd proxies to, which is the usual reason a Rust app is unreachable behind the proxy.

It follows up on Lerd's invitation on X to bring this Rust workflow to Lerd as a plugin. The companion fix for Lerd itself, putting cargo and version-manager toolchains on the dev server PATH, is lerd-env/lerd#2496.

What it adds to Lerd

  • Commands: lerd rust:dev (the dev command), lerd rust:setup (sets proxy.command in .lerd.yaml, after showing the change and asking), lerd rust:status.
  • Site commands: Cargo check, Cargo test, Cargo clippy, Cargo fmt --check, Cargo fmt (confirm: true, since it changes files).
  • MCP tools: rust_status and rust_check (timeout 10m), plus SKILL.md.
  • API endpoints: status (GET, reads only), project (GET, loopback_only, runs cargo metadata), check (POST, loopback_only, runs cargo check, timeout 10m).
  • A site tab: Rust.
  • Notifications: declared. One "Build failed" message per run of failed builds, tagged per site, saying whether the previous build is still serving. Nothing about progress or success.
  • No hooks, rail page, Overview card, page script, services, frameworks or provides jobs.

What it reads, changes and sends

  • Reads: the project's manifests through cargo metadata --no-deps --offline; the sizes and modification times of the project's files, to notice saves; .lerd.yaml; Lerd's /api/sites, to find a worktree's path by branch and to pick a free port for a new .lerd.yaml. It never reads the contents of .env (a change to it restarts the app) or any file outside the site.
  • Changes: .lerd.yaml, only through lerd rust:setup after a yes or --yes, and only its proxy.command line, or a new file when there is none. Lerd's own consent gate still applies at the next lerd link. Cargo fmt formats the code after the site command's confirmation. Each dev server's last build is kept as a small JSON file in the plugin's data folder. Running cargo writes the project's target/ as it always does.
  • Sends over the network: nothing beyond Lerd's API on $LERD_API_URL. Cargo itself may download dependencies when it builds, as it does in any terminal.

Requirements

  • lerd: ">=1.38", platforms: [linux]; WSL covers Windows. macOS is untested, so it is not listed yet.
  • Every script is standard-library Python 3.9+, so python3 is read from the shebangs and nothing else is required.
  • cargo is deliberately not under requires. The dashboard service and dev server units run with a fixed PATH without ~/.cargo/bin, where rustup's installer puts cargo, so Lerd would mark the plugin broken for most rustup users. The scripts find cargo themselves on PATH, in $CARGO_HOME/bin and in ~/.cargo/bin, or at LERD_RUST_CARGO, and fail with a clear message when it is missing. fix: find rustup, version manager and go.dev toolchains for host dev servers lerd#2496 closes the same gap for dev servers.

Images

The Rust tab after a failed build, with the previous build still serving

Checklist

  • The repository is public and has an open source license.
  • The README says what the plugin adds, reads, changes and sends.
  • plugin.yaml declares lerd as a lower bound, and platforms if it runs on only one.
  • Everything it runs is readable source in the commit, in shell, Python, Node or similar but not PHP: no binaries, no minified code without its source, nothing downloaded and run.
  • It asks for no privilege and writes only to its own folder, its data folder and the sites it is run against, changing Lerd only through its API.
  • It reads no secrets it has no stated need for, and a site's .env only when the README says why.
  • Lerd's token never leaves the machine and is never written outside the plugin's data folder.
  • Hooks finish quickly and fail without leaving a site, service or database half changed. (It has no hooks.)
  • Nothing leaves the machine without an opt-in the user turns on, and there are no analytics, tracking, ads or mining.
  • Any notifications are declared in plugin.yaml and only tell the user something they need to know or act on.
  • Pages bundle their own assets, nothing loads from third-party servers, and page scripts talk only to the plugin's own endpoints.
  • Any service image comes from a public registry, is pinned to a version tag or a digest, never latest, and is named in the README with its source. (It ships no services.)
  • No service or framework reuses a name Lerd, its stores or another plugin already has. (It ships none.)
  • The name, description and images describe what it actually does.
  • The images show the plugin itself, are mine to publish, and are at most 6, each a PNG, JPEG or WebP under 1 MB and at most 2560 px wide.

How it was checked

  • 53 tests run against real processes, including a real cargo build. CI is green on Python 3.9 and 3.13.
  • The app is started again with backoff when it exits on its own, so sites come back after a boot where a database or network address was not ready yet.
  • On Lerd 1.38.0 on Linux, a real HTTPS site was set up with lerd rust:setup and lerd link, then edited, broken and fixed. The previous build kept serving, and nothing was left running after restart, pause and unlink.
  • Every surface was called through the dashboard API and lerd mcp. Hostile input (paths with ../, quotes, markup and $(...) as site, branch and package) only produced errors, ran nothing and wrote nothing outside the plugin's folders.
  • The registry's scan rules were applied to the commit: no binaries, minified code, pipes to a shell, privilege or remote URLs in ui/.

Category: none of the existing categories (AI, Migration, Services) fits language support, so this proposes Languages. Happy to use another one.

Created with Claude Opus 5.5 in Claude Code (desktop app); an independent review pass ran on the same model.

@mtolhuys
mtolhuys requested a review from a team as a code owner November 9, 2026 20:43
@geodro
geodro merged commit 41a43fe into lerd-env:main Nov 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants