LemonadeJS for AI agents

LemonadeJS v6 calls itself a micro JavaScript framework for AI agents, and means something specific by it: the primary user is the agent, and every design decision answers to one metric: tokens from intent to a verified component. The agent’s entire existence is one loop:

intent → generate → run → observe → fix → verified component

This chapter is the operating manual: what to fetch, in what order, what each artifact costs, and what still requires escalation. The design rationale lives in PAIN.md in the repository root: seven pains of building frontend as a machine, written in first person.

The problem

An agent building frontend pays costs a human never sees:

  • It is blind. It cannot glance at the screen; it infers reality from DOM queries and error text. Most agent-shipped UI bugs are not logic errors. They are unverified assumptions nothing forced it to check.
  • It pays for every byte it reads. Context is metered working memory. Discovering how a component works by reading its source is the single most wasteful thing agents do, and they do it every session, because nothing cheaper exists.
  • Silent failures burn sessions. Agent debugging is hypothesis-driven from error strings. A thrown error with the fix in the message is repaired in one turn; a stale value with no error can consume the whole context window.
  • Async timing makes verification flaky. When an engine schedules DOM updates, tests need a flush step before asserting. Agents frequently misplace these; misplacements cluster around timers and transitions, and a flaky test erodes trust in the only feedback loop an agent has.
  • Nothing survives the session. The agent maintaining a component is never the agent that wrote it. What persists is not understanding but artifacts, and most frameworks produce none an agent can use.

Designed artifacts

Each cost gets a designed artifact, priced in tokens:

  • llms.txt: the complete API in one request, a few thousand tokens, maintained as a release artifact. Its own first rule is the guarantee: if something is not here, it does not exist. No second request, no source archaeology, and the surface is deliberately small enough for in-context learning to carry it.
  • contract(Component) and contract.json: a published component’s full interface (props, types, defaults, bind, events, api) as JSON: tens to a couple hundred tokens, instead of the hundreds of lines of source it replaces. Every Studio block ships its contract.json in the npm package; components/registry.json aggregates all 40 contracts into one request.
  • verify(Component): the done-signal. Conformance against the contract: every prop (plain and live), every event, bind, the declared api, zero engine warnings tolerated. report.pass === true is the mechanical answer to “am I finished?”, not “it renders without crashing”, and not the author’s optimism (Tests).
  • Error codes as actionable feedback. Every engine failure carries a stable LJS-xxx code with cause and fix in the message, designed to be pattern-matched; explain('LJS-203') prints the long-form diagnosis offline (Errors). Dev builds add tripwires for the known traps: snapshot slots (LJS-202), casing (LJS-305), contract type violations (LJS-401). One accepted exception, named in the docs: mutating without touch() is silent (LJS-201), and the price of free big-data mutation, paid knowingly (State).
  • Synchronous verification. Click, then assert, same line, every time, deterministic (Tests). The flush-timing class of flaky test does not exist here.
  • The zero-build path. One file, one script tag, working app. An agent’s deliverable can be a single HTML file; the toolchain failure surface is zero (Getting started).
  • Artifacts that survive the session. The contract (the promise), verify.json (the proof), the tests (executable memory), the error codes (shared vocabulary). The next agent inherits checkable artifacts, not a dialect to re-learn.

In practice: the fetch order

What to read, in order, to build correctly with minimum tokens:

  1. https://lemonadejs.com/llms.txt: always, first, once per session. It contains the four template rules, the state model, the error-code table and the v5 migration map. Do not fetch individual doc chapters for generation; they explain why, llms.txt is the what.
  2. Using existing blocks? Fetch components/registry.json (all 40 contracts, one request) or the single block’s contract.json from its package. Decide from the contract; never read block source to use a block.
  3. Generate. Four template rules, lowercase events, bind for two-way, state/computed from the tools argument. One idiom per task. Your output should be identical across sessions.
  4. Observe cheaply. lemonadejs/test: render(), query(), snapshot(), inspect(): milliseconds, jsdom, synchronous. Assert on the same line as the action.
  5. On any warning: match the LJS-xxx code; explain(code) if the one-liner is not enough. The codes are stable, so cache the table from llms.txt.
  6. Publishing a reusable component? component(name, contract, fn) and verify().pass === true before you call it done, then follow the full recipe in Building blocks. Search the registry before building: a contract costs tens of tokens, a rebuild costs thousands and produces an unverified clone.

What this loop does not cover. Escalate, do not guess:

  • Layout and visual truth. jsdom does no layout: z-index, overflow, anchoring geometry need a real browser. The repository’s own escalation path is headless-Chrome probes; yours may be a screenshot tool. Either way, geometric claims verified in jsdom are not verified.
  • Visual taste. No framework makes an agent a designer; a passing verify() proves conformance, not beauty.
  • The metric itself, today. The loop metric (agent success rate and tokens-to-verified-component on standard tasks, lemonade vs the field) is the framework’s declared benchmark, and the eval suite that measures it is on the roadmap (TODO.md), not shipped. Until it ships, “shortest verified loop” is a design target with receipts (synchronous tests, one-request context, gated proofs), not a published number.

Reference

The artifact economy, in one table:

ArtifactWhereCostReplaces
llms.txtlemonadejs.com/llms.txtone request, ~few k tokensthe documentation site
contract.jsonin every block’s npm packagetens–hundreds of tokensreading component source
registry.jsoncomponents/ in the repoone request, all 40 contractsdiscovery by browsing
contract(C)runtime, lemonadejsone callsame, without leaving code
verify(C)lemonadejs/testone call → { pass, checks }human review of done-ness
render(C) harnesslemonadejs/testmilliseconds, synchronousbrowser + flush scheduling
inspect(el)runtime, devone call → JSON treeDevTools eyes
LJS-xxx + explain()every dev-build warningone pattern matchhypothesis-driven debugging

Chapters behind this one: Why v6 exists for the thesis, Templates and State for the rules you generate against, Tests for the harness, Contracts for publishing, Studio for the catalog you should search before building, and Building blocks for the recipe, written to be used as a prompt.