kunchenguid/lavish-axi

▲ 133 stars today★ 3,663⑂ 320

HTML is the new markdown. Lavish is the new editor for your HTML artifacts.

3,663Star
320Fork
15Watch
45Issue
JavaScriptLanguage
MITLicense
Created 2026-05-11 · last push 2026-09-15 · repository size 82843 KB · default branch main

README

lavish-axi

https://github.com/kunchenguid/lavish-axi/blob/HEAD/CI https://github.com/kunchenguid/lavish-axi/blob/HEAD/Release https://github.com/kunchenguid/lavish-axi/blob/HEAD/npm https://github.com/kunchenguid/lavish-axi/blob/HEAD/Platform https://github.com/kunchenguid/lavish-axi/blob/HEAD/X https://github.com/kunchenguid/lavish-axi/blob/HEAD/Discord

For when a rich editor is not rich enough.

https://github.com/kunchenguid/lavish-axi/blob/HEAD/Lavish Editor demo

HTML is the new markdown. Lavish is the new editor for your HTML artifacts.

Agents are good at producing rich HTML artifacts, but the human-agent collaboration loop on such artifacts is lacking and falls back into screenshots and long responses for “tell me what to change.” That loses the thing HTML is best at: interactivity.

Lavish Editor opens agent-generated HTML files in a local browser, lets you pinpoint elements and selected text, edit diagrams your agent authored as Mermaid whiteboards, and send feedback to the agent to address.

Lavish Editor is an AXI, which means -

Quick Start

Install the Lavish skill in the Agent Skills format with npx skills:

npx skills add kunchenguid/lavish-axi --skill lavish

That is the entire setup - no npm install needed. The skill teaches your agent to run Lavish through npx -y lavish-axi, so the CLI comes along on demand. It stays a short stub and sends the agent to npx -y lavish-axi --help, design, and playbook for current instructions, so an installed copy cannot go stale against a newer CLI. Its frontmatter also includes Hermes Agent metadata, so Hermes-compatible harnesses can categorize and surface it as a first-class productivity skill. This installs the public lavish skill. The repository also contains an internal lavish-design brand skill for maintainers; default npx skills add ... --list and skills.sh discovery hide it unless INSTALL_INTERNAL_SKILLS=1 is set.

Then, in agents that expose skills as slash commands (Claude Code, for example), invoke it directly:

/lavish let's discuss our plan here

Or just ask for anything that is easier to grasp visually - a plan, comparison, diagram, table, code view, or report - and the agent loads the skill on its own when it recognizes the task.

By default the skill lands in the current project's skills directory (.claude/skills/, for example); add -g to install it for all projects (~/.claude/skills/).

Other Ways to Use Lavish

The skill is the recommended path, but it is not the only one.

Zero setup

Lavish is an AXI, so any capable agent can run the CLI directly with nothing installed at all. Just tell your agent:

Use npx -y lavish-axi to write a product or technical plan for what we discussed.

Session hook

Want Lavish's ambient context - including your live open sessions - fed into every agent session instead of loading on demand? Install the CLI globally and opt into the hook:

npm install -g lavish-axi
lavish-axi setup hooks

This installs a SessionStart hook for Claude Code, Codex, OpenCode, and GitHub Copilot CLI that surfaces open sessions, visualization playbooks, and usage guidance at the start of each session. Unlike the skill, the hook also shows your live open sessions, so a fresh agent session can resume an in-flight review. Restart your agent session after running this so the new hook takes effect.

Agent Plugin

Lavish also ships as an Agent Plugin - the vendor-neutral packaging standard for skills and MCP servers - so clients that speak that format can load it directly.

No marketplace is involved. The installed npm package _is_ the plugin: plugin.json sits at the package root next to the skills/ directory, so whatever npm install already put on disk is a complete, conformant plugin. Install the CLI, then register it:

npm install -g lavish-axi
lavish-axi setup plugin

That registers the installed package with every supported client it finds - VS Code, Cursor, and GitHub Copilot CLI - and reports which ones were absent. It is opt-in and idempotent, and it repairs the registered path after a reinstall or relocation. Reload each client afterward.

Each client is registered independently: one that cannot be registered is reported with what to do about it, and never blocks the others or fails the command.

To register by hand instead, point any client at the package directory (npm root -g/lavish-axi):

| Client | Register with | | ------------------ | ------------------------------------------------------------------------------------------------------------------ | | VS Code | "chat.pluginLocations": { "": true } in user settings | | Cursor | link the package dir at ~/.cursor/plugins/local/lavish-axi (setup plugin handles Windows link compatibility) | | GitHub Copilot CLI | copilot plugin install (or copilot plugin install kunchenguid/lavish-axi straight from the repo) |

Codex and ChatGPT install plugins only from marketplace sources, so Codex users should use the session hook above instead. Lavish declares no MCP server - the CLI itself is the agent interface - so a plugin install brings the same lavish skill, and the skill and plugin are alternatives rather than a stack.

From source

git clone https://github.com/kunchenguid/lavish-axi.git
cd lavish-axi
pnpm install --frozen-lockfile
pnpm run build
pnpm link

How It Works

┌───────────────┐
│ Agent writes  │
│ artifact.html │
└───────┬───────┘
        ▼
┌────────────────────────┐
│ lavish-axi <file_path> │
│ opens local browser UI │
└───────┬────────────────┘
        ▼
┌────────────────────────┐
│ Human annotates text   │
│ or elements, sends     │
│ chat, or queues layout │
│ issues from the inbox  │
└───────┬────────────────┘
        ▼
┌────────────────────────┐
│ lavish-axi poll waits  │
│ and returns prompts    │
│ the user queued        │
└────────────────────────┘
Author-defined links and popups can open in top-level tabs, while artifact documents remain sandboxed without same-origin access. Lavish does not inject any design system, so the saved HTML file renders identically whether you open it through lavish-axi or directly in a browser. Run lavish-axi design for the single source of agent-facing design guidance, including optional CDN snippets and the whiteboard (Mermaid) opt-in snippet. The check fails open - any stylesheet link, @import, Tailwind runtime script, color-scheme, or html/body/:root background signal suppresses it - and it never blocks the open. The first completed client-side check reveals the artifact, whatever it found and even if reporting that check to the server fails; the gate never holds the review hostage waiting for a repair or a network round-trip. The user can click Show anyway, and a bounded safety timeout fails open from every gate state. If the review cannot load at all - the chrome's own script never runs, or the server does not answer the artifact's load request after several retries - the mask names the problem and offers Check and reload without removing the independent Show anyway escape. A review already loaded in another browser tab is named the same way, with a Take over here button that moves it into the current tab, because Lavish loads an artifact in one tab at a time. Explicit ellipsis and line clamp, standard visually hidden accessibility text, intentional scrollers or masks, parent overhang, generic element scroll geometry, decorative overlap, and uncertain motion do not produce findings by themselves. Proven failures are filed in a Layout issues button in the top bar, which is hidden while nothing is unresolved and otherwise shows the unresolved count. Its drawer lists each issue with severity, a plain-language explanation, the affected viewport, the target/component identity, when it was last seen, and its lifecycle state, plus per-issue Reveal (highlight it in the artifact) and Dismiss actions. Nothing is selected by default. The user picks issues (or Select all) and Queue selected fixes turns that whole group into one ordinary queued prompt, tagged layout-warnings, that reaches the agent through the normal feedback path when they send. Detection never returns lavish-axi poll and never wakes an agent; only the user queueing a fix does. The one exception is a fatal artifact_failures response, for failures that make the review itself unusable, such as the artifact document or one of its own local assets failing to load. Open means the latest completed check for its viewport still detects it. Queued for fix means the user asked for a repair - it stays unresolved and counted, and cannot be queued again while that request is outstanding. Resolved requires a newer successful artifact load plus a complete check at the same viewport that no longer detects it; it then leaves the count but keeps a bounded history. Still present (recurring) means a queued issue survived a newer revision, so it is selectable again with its earlier attempt retained. Unverified means a reload or check failed or was incomplete, so the prior issue was preserved rather than cleared. Returned means a resolved issue came back on a later revision. Dismissal applies only to the current artifact revision; a later revision surfaces the issue again if it is still detected. A check at one viewport never clears an issue found at another, and a viewport removed from the configured diagnostic set (LAVISH_AXI_DIAGNOSTIC_VIEWPORTS, default all) is marked obsolete with an explicit reason rather than reading as fixed. lavish-axi share publishes the same local-inlined HTML to ht-ml.app, a third-party hosting service not part of Lavish. Publishing sends the artifact to ht-ml.app's servers, public by default, or private and password-protected with --private (Lavish generates the password and returns it once, in the command output and in the browser publish dialog) or --password (one you supply, never echoed back). A generated password is a shared secret: give it to whoever should read the page, and expect it to appear in your agent's transcript, because the agent has to relay it. Lavish does not store it. The response includes a secret update_key shown once. Keep it to republish the same URL later with --site <site_id> --update-key , which replaces the HTML in place and leaves the password alone unless you pass --private (rotate to a new generated one) or --password (set one). Locking a page that was public is not instant - it can keep answering from ht-ml.app's CDN cache for minutes after the password is set - while a page that was already private has no such cached copy. A page's password cannot be removed: ht-ml.app accepts a request to clear one and silently ignores it, so Lavish offers no way to make a private page public rather than telling you it did something the host did not do. Republish as a new page if you need a public URL. ht-ml.app has no delete endpoint, so --unpublish --site <site_id> --update-key replaces the page with a short placeholder and locks it behind a discarded random password rather than removing it: the URL still resolves and the host still holds what was published. The content swap is immediate, but the lock is not: a page that was public can keep serving the placeholder to uncredentialed visitors from ht-ml.app's CDN cache for minutes afterwards. The update_key plus --private republishes real content behind a new password you can share. Bundling never fetches remote URLs, Lavish itself does not set a CSP, local reads stay confined and size-capped, and absolute file:// paths outside safe inlined asset references are redacted before output. Per-asset and per-bundle inline caps default to 10 MB and 25 MB, overridable with LAVISH_AXI_EXPORT_MAX_ASSET_BYTES and LAVISH_AXI_EXPORT_MAX_BUNDLE_BYTES. Unresolved local assets or export notices such as author-set CSP meta tags and redacted file URLs are surfaced in command or browser output. Use --token or LAVISH_AXI_HTML_APP_TOKEN for an optional bearer token when publishing a new page (a republish or --unpublish authorizes with the update_key instead and rejects --token); set LAVISH_AXI_HTML_APP_API_URL to override the ht-ml.app API base and point share at a backend you control (see Self-hosting the share backend for the contract it must implement). If the element an unsent annotation was attached to is gone from the artifact for good, Lavish cannot reopen that card, so it writes your text into the conversation panel under Unsent annotation - selectable, never written over anything you have typed, and kept there across reloads; no note is ever dropped to make room for a newer one, and a note the browser refuses to store says so where it is shown. For reversible choices, let option clicks update local state, then queue exactly one final answer from a per-question submit or Queue answer button with window.lavish.queuePrompt(). Mark only custom (non-native) clickable elements with data-lavish-action so Lavish does not annotate them, and use data-lavish-question or queueKey when pre-send updates for the same question should replace each other. On wider screens, queued annotation preview pills and chat history share a scrollable Conversation panel above a sticky composer, so long feedback queues do not push the text box or send controls off screen. The browser chrome keeps editing actions in the overflow menu (copy path, reload artifact, copy DOM snapshot, export standalone HTML, publish link, end session), while the composer exposes Send & End beside Send to Agent to submit queued prompts and user-ended attribution together. Once Send & End starts, Lavish pauses new feedback, waits up to 5 seconds for feedback preparation already underway, keeps any open annotation draft intact until delivery succeeds, then holds that exact terminal batch. A completed reservation survives a page reload, including when its prompts were already delivered and only the pending end remains; incomplete preparation is not restored. If preparation times out, Lavish keeps the review open and its existing queue editable with a visible error. A transient delivery failure permits only retrying the same terminal batch through Send & End until it succeeds. If a snapshot makes the request too large (HTTP 413), Lavish retries that exact batch once without the optional snapshot. An actionable attachment rejection (HTTP 400), recoverable layout-selection conflict (HTTP 409), or unrecoverable 413 instead cancels the terminal reservation without ending the session, keeps the prompts queued, and restores editing, removal, Send to Agent, Send & End, and End session so the reviewer can revise or remove stale feedback before submitting again. Composer feedback is visibly queued before the text box clears and stays queued until acknowledged. Send waits up to 5 seconds for the artifact's DOM snapshot, then delivers without that optional context if the frame no longer answers; a late snapshot cannot submit the batch twice. A failed or still-unacknowledged POST keeps the queue and shows persistent recovery guidance. In the annotation card, Enter queues the annotation, Shift+Enter inserts a newline, and Ctrl+Enter (Cmd+Enter on macOS) queues it and sends all queued prompts immediately. Escape closes the card, same as Cancel, but only while it is empty (no text, no attachment); with unsent text or an attachment present, Escape does nothing rather than risk discarding it. Cmd+I or Ctrl+I toggles between annotate and explore mode from either the browser chrome or the artifact iframe, including while focus is in a textarea or control. Closing the last review tab while a poll is active starts a 10-second reconnect grace period. A reload or quick reconnect keeps an active poll waiting; if every review stays disconnected, the poll returns browser_disconnected without ending the resumable session, and the agent asks whether to reopen or end it instead of acting uninvited. The no-timeout poll always writes an immediate stderr banner so it is visibly not hung; it adds the periodic stderr wait ticks only in an interactive terminal, so when stderr is piped (as under agent harnesses) the captured output carries no tick noise. Stdout always stays reserved for the final response; if the poll is interrupted or times out before feedback arrives, re-run it because feedback remains queued until delivery. Poll delivery consumes the response, so read the complete response before truncating or filtering it. Codex-specific guidance keeps that poll attached to the active turn instead of hiding it in a background task, because completed background tasks may not resume the agent. When either side ends the session, every open review tab becomes visibly read-only and disables its feedback controls; feedback submitted after the end is refused instead of being accepted without an agent to receive it. A plain lavish-axi after a user-initiated end refuses to reopen the browser and returns guidance instead; pass --reopen only when the user asks for further review or something important needs their visual attention. Agent-initiated ends keep reopening normally, same as before. lavish-axi poll's ended response and the feedback response for the final batch before an end both carry next_step guidance telling the agent to stop polling and deliver remaining updates in chat instead of reopening.

More Today's Trending projects

1

alibaba / open-code-review

Go★ 28,122⑂ 2,023▲ 2,751 stars
2

debpalash / VoiceStudio

Python★ 30,697⑂ 3,683▲ 2,081 stars
3

JustVugg / colibri

C★ 33,539⑂ 3,522▲ 2,035 stars
4

tt-a1i / archify

JavaScript★ 63,354⑂ 4,208▲ 1,407 stars
5

cloudflare / security-audit-skill

JavaScript★ 4,982⑂ 310▲ 1,210 stars
6

Panniantong / Agent-Reach

Python★ 81,982⑂ 7,140▲ 1,094 stars