Let the user edit the copy of an HTML page or web app in the browser while an agent applies each change to the source in real time. Use when the user asks to "make the html editable", "let me edit the text", "live edit", "edit copy in the browser", "watch my edits", or wants to tweak wording on a page, visual, slide or app UI without hunting through the source.
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
The user edits text directly on the rendered page. Each edit is queued to a file. The agent watches the queue and applies the change to the real source, so build steps, templates and generated files stay in sync.
browser (press e, click, type)
│ POST /api/dev/live-edit {oldText, newText, binding, tag, parentText}
▼
scratch/live-edit/edits.jsonl ──watched by──▶ agent edits source files
│
scratch/live-edit/applied.jsonl ◀─────────────────┘ (badge shows "N waiting")Why a queue and not a direct save: the rendered page is rarely the source. Text may come from a template, a script data array, a generator, or a component. The agent knows where it lives; the browser does not.
| Situation | Mode |
|---|---|
| Static HTML file, visual, one-off page | Static: references/live_edit_server.py serves the page with the script injected |
| App with a dev server (Next.js, Vite, etc.) | App: add a dev-only API route and mount the overlay in dev builds |
| Standalone file the user keeps, no agent loop | Download: E to edit, Cmd+S downloads the edited HTML (see dwmkerr:slides conference mode) |
Default to Static unless the project already has a dev server.
references/live-edit.js and references/live_edit_server.py into ./scratch/live-edit/ (gitignored). Never into the shipped page.python3 scratch/live-edit/live_edit_server.py path/to/page.html 8772 scratch/live-edittail), one notification per edit:
f=scratch/live-edit/edits.jsonl; touch "$f"; tail -n 0 -F "$f"http://127.0.0.1:8772/page.htmle to toggle edit mode, click any text, typeEsc or Cmd+S sends the editCopy the shape of the static server into the app:
GET /api/dev/live-edit returns {queued} (lines in edits.jsonl minus lines in applied.jsonl)POST /api/dev/live-edit appends {ts, ...body} to edits.jsonlNODE_ENV === "development": the route writes to the working treelive-edit.js (or a component port of it) only in dev buildsLIVE_EDIT_FILE env var) so a containerised dev server and the host agent share it via a mountNext.js example: ui/app/api/dev/live-edit/route.ts plus a <LiveEdit /> client component rendered when process.env.NODE_ENV === "development".
For each queued line:
edits.jsonl. Monitor notifications truncate long text.oldText in the source. Check every place it lives: the shipped file, templates, generator scripts, data files. Fix all of them, or a rebuild reverts the edit.binding is set, the text comes from script data (e.g. data-text="cap.title"), not the markup. Search the data, not the HTML.' inside a single-quoted JS string ends the string and breaks the page. Use curly quotes or escape it.{ts, result: "applied" | "not found" | "skipped", old, new} to applied.jsonl so the badge count drops.A small apply_edit.py <ts> <old> <new> helper that does steps 2, 4 and 5 across a fixed file list is worth writing when edits are frequent.
data-text="<key>" on the element so edits carry a binding.contenteditable="plaintext-only" stops pasted markup leaking into the queue.&), ’ escapes, text split across elements. Try those forms before giving up.127.0.0.1 only and never ship the script or route. Anything that can POST to it can edit your working tree via the agent.references/live-edit.js: browser overlay (toggle, hover outline, plaintext editing, queue badge)references/live_edit_server.py: static server that injects the overlay and owns the queuedwmkerr/claude-toolkit
e1f3a4d
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.