rect.sh

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.

1Authora view — React SDKor plain HTML2Publishrect publish →a reusable template3Issuea live instancewith its own URL4Collaboratehuman edits ↔ agentdrives, in real time5Read backthe final stateas plain JSON

1. Author a view

A view is a built bundle — an index.html plus its assets (or one self-contained file). Two paths produce one:

  • React + the SDK — author with the @rectsh/rect/react hooks, compile with the @rectsh/rect/vite plugin. npm create rect scaffolds all of it.
  • Hand-written HTML — any HTML that embeds the spec block and loads the Rect.js runtime. 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, optional agent instructions and stateSchema, and a catalog of named actions. SDK projects keep the operating instructions in rect.agent.md; the build publishes that Markdown into the spec. stateSchema describes the view model for discovery and tooling; it is not runtime validation for 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:

  • viewUrl — the human-facing capability URL (/r/<id>). Whoever has it can open the view; the opaque id is the access. No login, no invite.
  • checkUrl, stateUrl, dispatchUrl — the same capability, for programs.

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 write, from anyone, follows the same cycle:

  1. A writer sends a change: the human's edit relayed by the host shell, an agent's rect_dispatch or rect_patch, a CLI call.
  2. The host applies it to the authoritative store and bumps the revision.
  3. The host broadcasts a fresh snapshot to every connected client — the human's browser re-renders, and an agent polling checkUrl sees the new revision.

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.

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 declare patchPolicy: "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. Instances are capability-addressed: the opaque instance id is the credential, which is what makes "just send the human a link" possible. Publishing and template management, by contrast, always require an authenticated account.

On this page