# 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 | | ` { const c = new Chart(el); return () => c.destroy(); })}>` | third-party widget lifecycle | | `` | `ref()` | ## API by task - State: `signal`, `computed`, `effect`, `batch`, `untrack`, `reactive`, `store`, `linked`, `persisted`, `selector`, `until`, `watch`, `from`, `history` - Context: `createContext`, `provide`, `inject` - Data: `resource` (`{ cache }`, `{ offline }`, `{ params, loader }`), `mutation`, `streamResource`, `sse`, `prefetch`, `infiniteResource`, `settled`, `seed` - HTTP: `configure({ csrf: 'django' })`, `request`, `api.get|post|put|patch|delete`, `HttpError`, `withRetry` - DOM: `html`, `when`, `list`, `show`, `text`, `attr`, `cls`, `style`, `cssVars`, `bind`, `attach`, `ref`, `clone`, `flushSync` - Islands: `island`, `element`, `register`, `hydrate` (`data-aegis-load="visible(300px)|idle(1500)|interaction(click)"`), `component`, `mount`, `destroy`, `defineElement`, `scaffold` - Server HTML: `swap` (morph), `boost`, `tpl`, `adopt`, `jsonScript` - Router: `router({ '/users/:id': { loader, handler, guard } }, { transition: true })`, `r.search('page', { parse: Number })` - Forms: `wireForm(formEl, { schema, rules })`, `form(defaults, { rules, schema })`, rules `required minLen maxLen pattern email min max matches maxSize mime maxFiles` - Motion: `transition`, `spring`, `springSignal`, `tween`, `flip`, `animate`, `media`, `reducedMotion`, `theme`, `defaults.motion` - Layout: `size`, `inView`, `viewport` - A11y: `trap`, `modal`, `roving`, `announce` - Testing: `reset()`, `root()`, `settled()`, `onWarn()`, `__AEGIS_DEV__ = 'strict'`, `defaults.fetcher`, `flushSync()`, `flush()` - Debugging: `stats()`, `dev.profile()`, `dev.of(el)`, `dev.inspect()`, `dev.graph()`, `trace(sig)`, `effect(fn, { trace: true })`; `recipes/` and `playground.html` hold runnable examples ## Dev codes See `ERRORS.md`. Warnings print `what / why / fix` and appear once per place.