feat(dev): hot-reload the web UI from disk + live reload (debug only)#154
Merged
Conversation
Editing the web client meant recompiling the daemon (assets are `include_str!`'d), restarting it, and reconnecting the browser. Now a running debug daemon can serve `index.html` + `static/*` from a worktree's assets dir, with a live-reload poller injected so browser edits show up on save — no rebuild, no restart. - `webui_hot_reload(<dir>)` MCP tool (debug builds only) so any dev session on any worktree can point the daemon at its own assets; `dir: null` reverts to embedded. Backed by the `dev.set_assets` IPC method / `client.dev_set_assets()`; `AGENTD_ASSETS_DIR` sets it at boot. - The web server prefers the dev dir over the embedded copy when set (`web_asset` / `web_index_html`); the injected poller hits `/dev/version` (a combined mtime of the served files) every 700ms and reloads on change. - All of this is `#[cfg(debug_assertions)]`-gated: release builds ignore the env var, reject the IPC override (no-op), drop the `/dev/version` route and the MCP tool, and always serve the embedded, tamper-proof assets. Tests: web_asset disk-vs-embedded + missing-file fallback; index injection only when served from disk; version tracks mtime; MCP catalog gates the tool to debug. Verified end-to-end over HTTP (set dir → custom HTML + poller served → /dev/version changes on edit → revert → embedded). Documented in AGENTS.md.
web_asset already serves the embedded copy per-file when a file is missing; keep the live-reload poller injected whenever dev mode is on (even on the embedded fallback) so the page auto-recovers to the dev assets the moment the file reappears — handles editor atomic-saves and a removed/empty worktree without leaving the page stuck. Test covers: dir with index.html (dev + poller), removed file and nonexistent dir (embedded + poller), dev off (embedded, no poller).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fast change→refresh loop for the web client. Asks: "give me options to hot-reload webui changes" → implemented disk serving + live reload, runtime-settable so an already-running daemon can be pointed at a worktree's assets (no rebuild/restart), exposed as a debug-only MCP tool.
The problem
crates/daemon/assets/index.html+static/*areinclude_str!/include_bytes!'d into the daemon, so editing the web UI means: edit →cargo build(~20s) → restart daemon → reconnect browser. The recompile dominates.What this adds (all
#[cfg(debug_assertions)]-gated)index.html/static/*from it instead of the embedded copies (web_asset/web_index_html), falling back to embedded per-file.index.htmlgets a tiny poller injected that hits/dev/version(a combined mtime fingerprint of the served files) every 700ms andlocation.reload()s on change. Edit → save → browser reloads itself.webui_hot_reload(<dir>)MCP tool (debug only) — any dev session in any worktree can point the daemon at its owncrates/daemon/assets;dir: nullreverts to embedded.dev.set_assetsIPC method /client.dev_set_assets().AGENTD_ASSETS_DIR=<dir>at boot.So the loop becomes: build a debug daemon once, then iterate on
index.htmlforever with just an auto-refresh.Safety
Release builds ignore the env var, treat the IPC override as a no-op, drop the
/dev/versionroute and the MCP tool, and always serve the embedded, tamper-proof assets. No arbitrary-path serving in production.Tests
web_asset_prefers_dev_dir_then_embedded,web_index_html_injects_livereload_only_from_disk,dev_assets_version_tracks_mtime(daemon);webui_hot_reload_tool_is_debug_only(mcp)./dev/versionchanges on edit, revert → embedded. Full workspace green (the one failing test is the pre-existing debug-only timing flakemany_pinned_sessions_resize_within_budget).🤖 Generated with Claude Code