lean-html
| Install | |
|---|---|
npm install lean-html |
|
| Latest Version: | 0.1.3 |
| License: | MIT |
| Last Updated: | Oct 7, 2026 |
| Links: | npm |
Lean HTML
A compact syntax for HTML that AI agents write with about 15% fewer output tokens, converted losslessly to normal HTML.
<nv c=nav a:label=Main> <nav class="nav" aria-label="Main">
<u> <ul>
<l><a h=/ c=active>Home>> <li><a href="https://github.com/yotamsaad12/lean-html/blob/HEAD/" class="active">Home</a></li>
<l><a h=/docs>Docs>> <li><a href="https://github.com/yotamsaad12/lean-html/blob/HEAD/docs">Docs</a></li>
> </ul>
<bt t=button ds>Menu> <button type="button" disabled>Menu</button>
> </nav>
Short names for frequent elements and attributes, > instead of named end tags, and no quotes where none are needed. It's a different spelling of the same HTML, so nothing changes in your project: files on disk stay normal HTML.
For AI agents
Install the agent skill into your project (Claude Code picks it up automatically):
npx lean-html skill install # ./.claude/skills/lean-html
npx lean-html skill install --global # ~/.claude/skills/lean-html, for every project
From then on, when the agent creates a sizeable HTML file or template, it writes LHTML to a .lhtml file and converts it:
npx -y lean-html to-html --replace src/card.lhtml # writes src/card.html, removes the .lhtml
npx -y lean-html to-html --dialect angular --replace src/app/x/x.lhtml # Angular template
The repository only ever contains normal HTML. If the LHTML has a mistake, no HTML is written and the .lhtml file is kept; the agent gets file:line:col: CODE: message, fixes that spot and reruns. For small templates the agent writes HTML directly, since loading the skill would cost more than it saves.
For other agents, copy the skill folder (npx lean-html skill path prints where it is) or point them to its SKILL.md.
Does it work?
Measured with AI sessions that wrote each answer once, without checking (o200k tokenizer; details in benchmarks/generation/SUMMARY.md). The latest runs used only the bundled skill, in fresh sessions that knew nothing else about LHTML:
| Answers | Valid and equivalent on the first try | Output tokens saved | |
|---|---|---|---|
| Plain HTML, skill only | 14 | 14 | 16.1–16.3% |
| Plain HTML, all runs | 31 | 30 | 15.5–18.1% |
| Vue templates | 4 | 4 | 15.3% |
| Handlebars templates | 4 | 4 | 13.8% |
| Angular templates | 8 | 8 | 12.6–13.1% |
Equivalent means the LHTML converts to the same DOM (or the same template) as the model's own HTML answer.
In a live Claude Code session in an Angular project, with the skill installed and a request that never mentioned LHTML, the agent chose LHTML by itself for an 80-line dashboard (12.2% fewer tokens) and skipped it for a 9-line card, where it wouldn't pay off (benchmarks/realworld). A working Angular app built this way is in examples/angular.
Caveats: the samples are small, all generators so far were Claude models, and Claude's own tokenizer isn't available offline to measure.
Platforms
| Dialect | For | Status |
|---|---|---|
html (default) |
HTML pages, components and emails; Alpine.js; htmx | stable |
vue |
Vue templates in separate files | experimental. In single-file components (.vue) the template is a minority of the file and LHTML saves only ~5% of it, so it isn't worth using there |
handlebars |
Handlebars, Mustache | experimental, passed its first test |
angular |
Angular 17+ templates | experimental, passed its first test |
thymeleaf |
Thymeleaf | experimental, untested with models |
jinja |
Jinja2, Django, Nunjucks, Twig, Liquid | experimental; saves only ~9% |
Template code ({{ }}, {% %}, @if (…) {) passes through untouched:
npx lean-html to-html --dialect angular list.component.lhtml -o list.component.html
React/JSX is not supported. A measurement showed at most 8.5% savings for typical React components, because their JavaScript and Tailwind classes can't be shortened (jsx/PHASE0.md).
CLI
lean-html to-html [file] LHTML → HTML
lean-html to-lhtml [file] HTML → canonical LHTML
lean-html validate [file] exit code 1 with file:line:col diagnostics when invalid
lean-html stats [file] chars, bytes and tokens, HTML vs LHTML
lean-html skill install|path agent skill
Options: -o <file>, --replace, --dialect <name>, --fragment, --collapse-whitespace,
--global / --dir <path> / --force (skill install)
Files may be omitted or - to read stdin. to-lhtml --collapse-whitespace is useful for feeding existing pages to a model in fewer tokens.
API
import { toHTML, toLHTML, parse, parseHTML, validate, serialize } from 'lean-html';
toHTML('<d c=card><p>Hello>>'); // '<div class="card"><p>Hello</p></div>'
toLHTML('<div class="card"><p>Hello</p></div>'); // '<d c=card><p>Hello>>'
toHTML('<p>{{ n > 1 }}>', { dialect: 'vue' }); // '<p>{{ n > 1 }}</p>'
parse(lhtml); // LHTML → AST (throws LHTMLError with code, line and column)
parseHTML(html); // HTML → AST (spec-compliant, via parse5)
validate(lhtml); // { valid, errors: [{ code, message, line, column }] }
Requires Node.js 20.19 or later.
The language
skill/SKILL.md: the one-page version the agents use03-language.md: grammar and rules04-platforms.md: dialects for frameworks and template engines
License
MIT
Related Packages
One package to add GIX Copilot to an existing project: `npm add @gixcopilot/sdk`...
Create In-APP AI agents that answers question and performs actions. Works with R...
Version History
| Version | Released | License |
|---|---|---|
| 0.1.3 | MIT | |
| 0.1.2 | MIT | |
| 0.1.1 | MIT | |
| 0.1.0 | MIT |
Pre-releases (1)
| Version | Released | License |
|---|---|---|
| 0.0.0-stage |