# What Framework — full agent guide > What is a signal-based reactive web framework built for AI agents. Components run once — no re-renders, no virtual DOM. The compiler lowers JSX to fine-grained DOM operations. A live MCP server (29 tools) lets agents inspect a running app, and core runtime errors are structured with a code, fix, and example. This file inlines the essentials an agent needs to write, debug, and ship correct What code. --- ## Mental model - **Signals are functions.** `const count = signal(0, 'count')`. Read with `count()`. Write with `count(5)` or `count(c => c + 1)`. `count.set(...)` is the same write, and `count.peek()` reads without subscribing. - **Components run once.** The component function body executes a single time. It never re-runs on state change. Reactivity comes from signals creating fine-grained DOM effects, not from re-rendering. - **`computed()`** is lazy, cached derived state: `const doubled = computed(() => count() * 2)`. - **`effect()`** auto-tracks the signals it reads. No dependency array. Return a function to clean up. - **`batch()`** groups writes so effects flush once. - Import everything from `'what-framework'`. --- ## Quickstart ```bash npm create what@latest my-app cd my-app npm install npm run dev ``` Open `http://localhost:5173`. `create-what` wires up Vite and the compiler, so you rarely touch bundler config. Bun works too: `bun create what@latest my-app && bun run dev`. Minimal component: ```jsx import { signal, computed, mount } from 'what-framework'; function Counter() { const count = signal(0, 'count'); const doubled = computed(() => count() * 2); return (

Count: {count()}

Doubled: {doubled()}

); } mount(, '#app'); // returns a dispose function ``` Signal reads inside JSX children and attributes are auto-wrapped by the compiler — you do not write `{() => count()}` manually. Manual setup without the scaffolder: ```js // vite.config.js import { defineConfig } from 'vite'; import what from 'what-compiler/vite'; export default defineConfig({ plugins: [what()] }); ``` --- ## Signals API ```js import { signal, computed, effect, batch, onMount, onCleanup, mount } from 'what-framework'; // Create state. The second arg is an optional debug name (recommended — it // makes the signal traceable in DevTools and MCP). const count = signal(0, 'count'); count(); // read -> 0 (subscribes the current effect) count(5); // write -> sets to 5 count(c => c + 1); // updater write -> increments count.set(10); // same as count(10) count.peek(); // read WITHOUT subscribing // Derived state — lazy and cached. const doubled = computed(() => count() * 2); // Side effects — auto-track reads, run on change. Return a cleanup function. effect(() => { const id = setInterval(() => count(c => c + 1), 1000); return () => clearInterval(id); }); // Batch multiple writes so effects run once at the end. batch(() => { count(0); /* ...other writes... */ }); // Lifecycle. onMount(() => { /* runs after first mount; good for browser-only APIs */ }); onCleanup(() => { /* runs on dispose */ }); ``` Lists: use `.map()` with a `key` prop. The compiler lowers it to keyed reconciliation. ```jsx ``` Immutable updates for objects/arrays — never mutate in place: ```js items(prev => [...prev, newItem]); // add items(prev => prev.filter(i => i.id !== targetId)); // remove items(prev => prev.map(i => i.id === id ? { ...i, done: true } : i)); // update one ``` --- ## Common errors and fixes What's core runtime emits structured `WhatError` objects that serialize to JSON with a `code`, `message`, `suggestion`, and `codeExample`. The codes below are the ones the runtime detects and reports in dev mode. ### ERR_INFINITE_EFFECT — effect cycle An effect writes to a signal it also reads, creating a loop (capped at 25 flush iterations). ```js // Bad — reads and writes count in the same effect: effect(() => { count(count() + 1); }); // Good — read without subscribing: import { untrack } from 'what-framework'; effect(() => { count(untrack(count) + 1); }); ``` ### ERR_MISSING_SIGNAL_READ — signal used without calling it Renders `[Function]` instead of the value. ```jsx {count} // Bad — renders "[Function]" {count()} // Good — call the signal ``` ### ERR_SIGNAL_WRITE_IN_RENDER — write during render The component body should read signals, not write them. Move writes into handlers, effects, or `onMount`. ```jsx // Bad: function Counter() { count(count() + 1); return {count()}; } // Good: function Counter() { return ; } ``` ### ERR_UNSAFE_INNERHTML — raw innerHTML Raw HTML must be opted into with the `__html` marker. ```jsx
// Bad — XSS risk, refused
// Good — explicit opt-in ``` ### ERR_HYDRATION_MISMATCH — server/client HTML differ Avoid reading browser-only APIs (`window`, `localStorage`) during the initial render; use `onMount` for client-only values. ### ERR_ORPHAN_EFFECT / ERR_MISSING_KEY Create effects inside components or a `createRoot()` so they are cleaned up; give list items a stable `key`. Tip for agents: the MCP tool `what_fix({ errorCode })` returns the diagnosis, fix, and example for any code offline — use it as your first move when you hit a What error. --- ## MCP DevTools usage What ships an MCP server (`what-devtools-mcp`) that bridges an agent to a running app over the Model Context Protocol. It exposes 29 tools. Wire it into your MCP client: ```json { "mcpServers": { "what-framework": { "command": "npx", "args": ["what-devtools-mcp"] } } } ``` Enable live inspection by adding the Vite plugin: ```js import what from 'what-compiler/vite'; import whatDevToolsMCP from 'what-devtools-mcp/vite-plugin'; export default defineConfig({ plugins: [what(), whatDevToolsMCP({ port: 9229 })], }); ``` First five minutes — run in order: 1. `what_connection_status` — am I connected? how big is the app? 2. `what_diagnose` — one-call health check (errors + perf + reactivity). 3. `what_page_map` — visual structure and accessibility. 4. `what_components({ filter })` → `what_explain({ componentId })` — deep-dive a leaf component. 5. `what_signals({ filter: "...", named_only: true })` — check key state (always filter; never dump all). Useful workflows: - **Trace reactivity:** `what_signals({ filter })` → `what_dependency_graph({ signalId, direction: "downstream" })`. - **Before/after a change:** `what_diff_snapshot({ action: "save" })` → make the change → `what_diff_snapshot({ action: "diff" })`. - **Test a fix live:** `what_set_signal({ signalId, value })` then re-check with `what_diff_snapshot`. - **Validate code offline:** `what_lint({ code })`, `what_scaffold({ type, name })`, `what_fix({ errorCode })` work without a browser. Notes for agents: - Component and signal IDs are ephemeral — re-query `what_components` after any `what_set_signal` that may remount the tree. - `what_eval` is disabled by default (security); enable only with `--unsafe-eval` / `WHAT_UNSAFE_EVAL=1`. - Module-scope signals are not attributed to any component; use `what_signals` directly rather than per-component counts. --- ## React compatibility `what-react` runs many React ecosystem libraries inside What components. It is a secondary feature — prefer native What APIs for new code. The tested library matrix in REACT-COMPAT.md is the source of truth. ```bash npm install what-react ``` --- ## More - Repository: https://github.com/CelsianJs/what-framework - Docs site: https://whatfw.com/docs - Agent patterns: https://github.com/CelsianJs/what-framework/blob/main/docs/AGENT-PATTERNS.md - MCP DevTools reference: https://github.com/CelsianJs/what-framework/blob/main/docs/MCP-DEVTOOLS.md - Compatibility matrix: https://github.com/CelsianJs/what-framework/blob/main/REACT-COMPAT.md