lmhtml recipes
Each recipe uses the synthetic pages under the tutorial scratch directory. Compile from the directory containing schema-lmhtml.json; the snippets save reports and outputs below build/ or output/.
Check broken links on a site
Walk each page and each link. Skip external, special and outside-root targets by policy, and ignore a generated noise pattern.
npx --yes --package=@lmctl-ai/lmctl -- lmscript build/check-links.lms
(no output; exit 0)
lmhtml --dsl build/check-links.dslb
{"ok": true, "result": null}
cat build/links.txt
broken-link site/index.html:0: missing.html not found
Find class and ID typos
Compare classes used in markup to CSS selectors and flag selectors that do not match a used ID. Suggestions help locate one-character spelling mistakes.
npx --yes --package=@lmctl-ai/lmctl -- lmscript build/check-classes.lms
(no output; exit 0)
lmhtml --dsl build/check-classes.dslb
{"ok": true, "result": null}
cat build/classes.txt
class-undefined site:0: heding (did you mean heading?)
id-unused site:0: teem (did you mean team?)
Diff two pages
Compare before and after snapshots. The host reports a changed paragraph and a newly added paragraph, ignoring incidental markup noise.
npx --yes --package=@lmctl-ai/lmctl -- lmscript build/diff.lms
(no output; exit 0)
lmhtml --dsl build/diff.dslb
{"ok": true, "result": null}
cat build/diff.txt
diff-changed compare/before/page.html:0: html > body:nth-child(2) > p.intro:nth-child(2): text differs
diff-added compare/after/page.html:0: html > body:nth-child(2) > p:nth-child(3)
summary page:0: 2 differences
Extract common parts into a template
Find repeated subtrees in four sample pages and write a template with slot markers for page-specific content.
npx --yes --package=@lmctl-ai/lmctl -- lmscript build/template.lms
(no output; exit 0)
lmhtml --dsl build/template.dslb
{"ok": true, "result": null}
cat build/template.txt
summary template:0: 2 slots for 4 pages
Change a shared header or footer across pages
Apply one navigation and footer fragment to copies of all four pages. The source files remain untouched.
npx --yes --package=@lmctl-ai/lmctl -- lmscript build/rewrite.lms
(no output; exit 0)
lmhtml --dsl build/rewrite.dslb
{"ok": true, "result": null}
ls output/page*
output/page0.html
output/page1.html
output/page2.html
output/page3.html
Ignore generated noise with link_kind and str_match
Link checks should state what is deliberately outside scope. This version ignores external/special/outside-root targets and a synthetic noise-*.html pattern, while still reporting a missing local page.
npx --yes --package=@lmctl-ai/lmctl -- lmscript build/check-links.lms
(no output; exit 0)
lmhtml --dsl build/check-links.dslb
{"ok": true, "result": null}
cat build/links.txt
broken-link site/index.html:0: missing.html not found
Generate and check a Markdown chapter index
Give each note an h1 and introductory paragraph, then generate its chapter entry once.
lmhtml index durable-memory lmhtml index durable-memory --check lmhtml mdcheck durable-memory
Build a templated Markdown site
Save this shell as shell.html. Metadata is escaped; the required content placeholder inserts the converted document body.
<!doctype html><html lang="en"><head><meta charset="utf-8"><title>{{title}}</title></head><body><nav>{{toc}}</nav><main>{{content}}</main></body></html>
lmhtml site durable-memory build/memory-web --template shell.html
Post-process a Markdown document with DSL
The conversion returns the same Doc type used by every existing selector and mutation. Save this as build/plan.lms:
p = _dsl_ schema="schema-lmhtml.json";
let doc = html.from_markdown("# Release plan\n\nChecks before publishing.");
doc.select("h1").at(0).set_attr("id", "release-plan");
html.save(doc, "build/plan.html");
end _dsl_
savedsl(p, "build/plan.dslb");
lmhtml --dsl-schema --json > build/schema-lmhtml.json lmscript build/plan.lms lmhtml --dsl build/plan.dslb
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).