# Aegis — contract for AI assistants
Aegis is a zero-build reactive UI engine: one ES module (`aegis.js`), no dependencies, no compiler.
Server renders HTML; Aegis hydrates islands (`[data-aegis]`) and adds fine-grained reactivity with signals.
Read `aegis.d.ts` for exact types, `ERRORS.md` for warning codes, `test.html` for working examples.
## Rules (the mistakes assistants make most)
- Reactive text is a signal or a function: `${count}` or `${() => count.value * 2}`. NEVER `${count.value}` — that is a one-time snapshot (E019).
- Same for helpers: `text(el, count)` / `show(() => open.value, …)` / `cls(el, 'on', isOn)`. A plain value renders once.
- Never build HTML from data with `innerHTML`. Data goes through `${}` in `html``` (text nodes, never parsed). Server HTML goes through `swap()`.
- Everything that subscribes (effects, listeners, timers, resources) must be created inside a component setup or `scope.run()`; it is disposed with the scope. Outside a scope you get E001.
- `on(el, 'click', fn)` — not `addEventListener`; `interval`/`timeout`/`observe` — not the raw APIs. They clean themselves up.
- Islands: `island(name, ({ props, html }) => html`…`, { types })` + server `
`; the same component function works as a custom element via `element(tag, Component, { props })`. `hydrate(document)` runs automatically after `island()`/`register()`. `register(name, (el, data, ctx) => …)` is the positional form.
- `data-*` props are strings; declare `{ types: { count: Number, on: Boolean } }` in `register()` to coerce. Big JSON goes in `
```
## Template syntax (html``)
| Syntax | Meaning |
|---|---|
| `${sig}` / `${() => expr}` | reactive text |
| `${() => cond ? html`…` : null}` | reactive child (node, template, array, text) |
| `${list(items, row => html`
…`, { key: 'id' })}` | keyed list, rows are exactly what you return |
| `${show(open, () => html`…`, null, { transition: 'fade' })}` | conditional branch with its own scope |
| `@click=${fn}` `@submit.prevent` `@keydown.enter` `@click.outside` `@input.debounce.300` | events with modifiers |
| `.value=${sig}` `?disabled=${sig}` `bind:value=${sig}` `:title=${sig}` | property / boolean attribute / two-way / reactive attribute |
| `class=${{ active: sig }}` `style=${{ '--x': sig }}` | class objects, style objects, custom properties |
| `