Micro JavaScript Framework for AI Agents
Reactive components with a React-like API in ~9 KB gzip: zero dependencies, no build step. Designed for both human developers and AI agents.
- Zero dependencies
- MIT licensed
- No build step
- TypeScript types
import { html, mount } from 'lemonadejs';
const Counter = (props, { state }) => {
const count = state(0);
return html`<div>
<h1>${count}</h1>
<button onclick="${() => count.value++}">+1</button>
</div>`;
};
mount(Counter, document.getElementById('app')); ● live: this exact code, running on this page
Open in the playgroundVerified, not assumed.
Every component is published with a typed contract and checked against it. The result is machine-readable JSON, consumable by humans, agents, and CI.
Publish with a contract
component('switch', {
bind: false,
label: '',
onchange: Function,
api: { toggle: Function },
}, fn); The schema is the interface
contract(Switch)
// { name: "switch",
// props: { label: …},
// bind, events, api }
// agents read THIS, not source verify() enforces it
verify(Switch)
// { pass: true, checks: [
// 'mounts with defaults',
// 'prop label (live state)',
// 'bind', 'api via ref' ] }
All 43 Studio blocks pass this check before release; a failing verify()
cannot enter the registry. How contracts work
A small core with strong guarantees.
The entire framework: four template rules, one file, an API that fits in 2k tokens. An agent reads all of it in one prompt; you read it in an afternoon.
Four template rules
The entire template language: live state, live expression, snapshot, and loops/conditionals as expressions. Everything else follows.
Contracts, verified
component(name, contract, fn) publishes a typed schema;
verify() proves the implementation honors it. Agents read
interfaces, not source.
Keys that move state
Keyed lists move DOM and component state on reorder; changed values patch living instances instead of rebuilding them.
Lifecycle managed by the engine
listen() cleans up listeners automatically;
resource() cancels stale fetches and discards out-of-order
responses. Entire classes of bugs are prevented by design.
Causality as data
trace() answers “why didn’t my update happen?” with plain
JSON: every write, who wrote it, what re-ran. No devtools UI required.
Actionable errors
Stable error codes with the fix in the message. An exception in one expression is contained, so the rest of the page keeps updating.
Designed for agent-authored code
An agent reads llms.txt (~2k tokens, the complete
API), generates a component, and verifies it with verify()
in a single loop. On failure, errors carry stable codes and
trace() reports the causality.
> count.value++ write counter.s0 old: 0 value: 1 run counter#slot cause: counter.s0 > trace() // causality, as plain JSON
43 blocks, every one contract-verified
The Studio: datagrids, calendars, modals, published with their schema and their proof. Explore the catalog
Battle-tested across the Jspreadsheet ecosystem
LemonadeJS powers extensions shipped with our commercial products. Not a side project: production code, maintained by the team behind the suite.
Your agent reads the whole API in 2k tokens.
Then
verify proves the code it wrote.
Point it at llms.txt and start building. No tutorial, no scaffold, no afternoon spent reading.