How it works
The lifecycle of a rect, from authoring to reading the result back.
A rect's life has five stages. This page walks the whole loop once, conceptually — every stage links to the guide that covers it in depth.
1. Author a view
A view is a built UI bundle — an index.html plus its assets (or one
self-contained UI file). The host supplies the shared Rect protocol runtime.
Two paths produce the bundle:
- React + the SDK — author with the
@rectsh/rect/reacthooks, compile with the@rectsh/rect/viteplugin.npm create rectscaffolds all of it. - Hand-written HTML — any HTML that embeds the spec block and uses the
host-provided
Rectglobal. Good for simple views.
Either way the view is self-describing: an inert
application/rect-view+json block declares its name, when to use it, an
example view model, required stateSchema, optional agent instructions, and a
catalog of named actions. SDK projects keep the operating
instructions in rect.agent.md; the build publishes that Markdown into the
spec. The build and publish gate validate the schema and example, and App
publication validates every Screen's initial ViewModel against it. The schema
does not validate later issue or patch writes. The view runs in a sandboxed
iframe and only ever touches its view model — the view
contract spells out the constraints.
2. Publish it as a template
rect publish builds the project, uploads the bundle, and
registers it as a template (also just called a rect) — keyed by a slug,
so republishing updates the same template in place. At upload the host
extracts the spec and actions blocks and validates them; a view whose actions
don't match its spec fails the publish, not a dispatch three days later.
A template is inert. It holds the view and its declared shape — nothing else.
3. Issue a live instance
Issuing creates a live instance of a template: a fresh view model
(initialized from the caller's state, or the spec's example), its own
revision counter, and a set of URLs:
url— the human-facing URL (/r/<id>). Whether it opens anonymously or requires sign-in depends on the instance's read access.checkUrl,stateUrl,dispatchUrl— addressed endpoints for programs. They enforce the same independent read and write access as the hosted page.
An agent normally searches for the best-fitting template, reads its full spec, then issues it. Keyword-based search matches template names and slugs, plus words in descriptions, actions, and state fields. The same public and workspace visibility rules apply to every result. Deterministic catalog listing remains available for browsing or as a fallback when search is unavailable or unhelpful.
Agents issue over MCP (rect_issue), the CLI
(rect issue), or the HTTP API. One template can back
thousands of independent instances.
4. Collaborate in real time
This is the stage everything else exists for. The instance's view model is a single JSON document with one write op — an RFC 7386 JSON Merge Patch — and every accepted write, regardless of surface, follows the same cycle:
- A writer sends a change: the human's edit relayed by the host shell, an
agent's
rect_dispatchorrect_patch, a CLI call. - The host applies it to the authoritative store and bumps the revision.
- The host broadcasts the committed delta to every connected client — the
human's browser applies it, and an agent polling
checkUrlreceives the latest full snapshot.
No polling inside the view, no stale reads: the human and the agent are always looking at the same state. State & syncing covers the optimistic-write mechanics inside the view.
Each instance chooses read and write access independently:
| Scope | Who is allowed |
|---|---|
anonymous | Anyone with the instance ID |
authenticated | Any signed-in user |
workspace | Members of the instance's workspace |
owner | The creator, workspace primary owner, or owner role |
The hosted page, Realtime delta channel, HTTP API, MCP, CLI, and Rect Agent all
apply those scopes. A caller who must sign in receives 401; a signed-in caller
outside the permitted workspace or owner set receives 403.
Two write styles coexist:
- Patches are free-form — right for edits with no rules attached, like typing in a field.
- Actions are semantic — the view declares named
operations (
approve,addTodo) whose handlers run host-side in a sandbox, validate business rules, and can reject with a structured code the caller can react to. Views can even declarepatchPolicy: "actions-only"to turn away free-form agent patches entirely.
Files ride alongside: attachments upload to private
storage and appear as references in the reserved $attachments namespace —
never as bytes in the view model.
5. Read the result back
When the human is done (or at any point before), the agent reads the full view
model and revision back — rect_get_result over MCP, rect read from the
CLI, or a GET on checkUrl. The result is plain JSON in exactly the shape
the view's spec declared, ready to act on.
If the loop needs an explicit "I'm done" signal, model it in the view — a
submitted flag, an approve action — so the agent can read it straight off
the view model instead of guessing.
The security model in one paragraph
Views are untrusted code, so they run in a sandboxed iframe with a
host-owned CSP — no cookies, no storage, no direct network; everything goes
through the host over postMessage. Action handlers are untrusted too, so
they run server-side in a QuickJS sandbox with a CPU deadline and memory
cap, pinned clocks and randomness, and JSON-only inputs and outputs. Every
instance has independent anonymous, authenticated, workspace, or owner
read and write scopes. Publishing and account-scoped template management
require authentication; public template discovery does not.