lmhtml script authoring skill

Purpose

Write, compile and verify lmscript programs that inspect or transform HTML documents through the lmhtml host API.

When to use it

Use lmhtml for checking internal links, auditing CSS classes and IDs, comparing page structure, finding shared markup, or applying consistent edits across pages.

Install

Download the latest lmhtml binary from Releases. For DSL scripts, install Node.js 24.15 or newer, then use the published compiler package with npx --yes --package=@lmctl-ai/lmctl -- lmscript. Source builds need C++17, CMake, Ninja and the project setup described in the README.

Commands

lmhtml --dsl-schema
lmhtml --dsl-schema --json
lmhtml --dsl-signatures
npx --yes --package=@lmctl-ai/lmctl -- lmscript check.lms build/check.dslb
lmhtml --dsl build/check.dslb

Markdown notes use the same document tree. Native commands need only the host:

lmhtml md2html notes/chapter.md build/chapter.html
lmhtml index notes
lmhtml index notes --check
lmhtml mdcheck notes
lmhtml site notes build/notes --template shell.html

Raw HTML is disabled by default. Front matter may override title and summary. Use html.from_markdown or html.render_markdown for DSL post-processing, then html.save. Index drift and broken links fail with non-zero status. Web output must stay below the working directory and must not overlap its input.

Inputs and outputs

Safety rules

Worked examples

  1. Link audit: loop over html.load_dir("site"), then each document's links(); skip policy-approved kinds with html.link_kind(doc, url), and report missing internal destinations with html.link_exists(doc, url).
  2. Class audit: compare pages.classes_used() with pages.css_classes() using str_difference; call suggest(name, candidates) for near matches.
  3. Structural comparison: html.diff(before, after) ignores normalized whitespace, comments, attribute order and data-* noise.
  4. Template extraction: html.write_template(pages, minimum_count, output_path) emits shared subtrees and slot markers.
  5. Shared edit: select a node, call replace_with or set_attr, and save a copy with html.save(doc, output_path).

Errors and exit codes

Exit 0 means success. Exit 2 reports usage or bytecode compilation problems; exit 3 reports bytecode load or host runtime errors; exit 4 reports an application failure such as a report explicitly marked as failed. A missing file, invalid selector, or out-of-range collection access is a runtime failure. Compile errors point to a source location.

How to verify

  1. Compile using the embedded schema bytes from lmhtml --dsl-schema --json.
  2. Compare lmscript --dsl-signatures schema.json with lmhtml --dsl-signatures when validating a host adapter.
  3. Run the bytecode against a synthetic site first and inspect both the JSON result line and report file.
  4. For edits, use --dry-run, review the destination files, then run normally and re-diff.
  5. Repeat the run and compare outputs when deterministic reports matter.

Plain content for agents

Use lint to measure unnecessary decoration and entities, normalize to remove them without changing the text, and clean to extract main content for agents. Plain prose has no inline code or emphasis. Copyable commands belong in blocks. Text needs only ampersand and less-than escapes; attributes need only ampersand and quote escapes.

lmhtml lint --stats --json skills tools durable-memory
lmhtml lint --stats --compare BEFORE_DIRECTORY AFTER_DIRECTORY
lmhtml normalize skills tools
lmhtml lint durable-memory
lmhtml clean page.html --base https://example.org/docs/page.html
lmhtml clean page.html --check
lmhtml clean https://example.org/docs/page.html --markdown

clean is deterministic and offline for files. URL input uses curl and requires network access; it runs no JavaScript. Extraction removes navigation, forms, scripts, styles and common advertising/cookie containers, resolves links and prints byte counts and a bytes/4 token estimate on stderr. Heuristics can miss unusual site layouts: inspect extracted content before relying on it. clean --check compares extraction with the page's main content and fails with a diff if content would be dropped.

normalize preserves code-block alignment, removes inline typography, repairs entities and unfolds prose. lint counts violations per file and in total, with densities per 100 words; --config FILE accepts DIRECTORY METRIC MAX_COUNT rows. Defaults are zero, with h2/h3 anchors retained. The DSL equivalents are Doc.normalize() and Doc.clean(base_url).