---
name: rect-view-author
description: Build or edit a reusable Rect app as a bundle-based project using create-rect, @rectsh/rect, the Rect CLI, local checks, and publish/remix workflows. Use when the user asks to create, code, redesign, test, or update an interactive app, dashboard, form, board, or review tool specifically for Rect or rect.sh.
---

# Authoring Rect apps

A Rect is a small, reusable app over a shared JSON view model. A coding agent
authors and publishes the finished template once. An operating AI can then
discover it, issue a tailored live app for each task, keep it updated, and read
the human's work back through MCP or the CLI.

The first-class authoring path is a **bundle-based create-rect project**. Do not
start by hand-writing an upload-only HTML file unless the user explicitly asks
for the low-level vanilla path.

## 1. Start or resume a project

If the current directory already contains `rect.json`, `rect.view.json`, or
`@rectsh/rect`, treat it as an existing Rect project. Read its `AGENTS.md` or
`CLAUDE.md` before changing files and preserve the existing `rect.json` slug
and account unless the user explicitly wants a new template.

For a new view:

```bash
npm create rect@latest my-view
cd my-view
npm install
```

For an existing published template with remix source:

```bash
npx rect remix <template-slug-or-id>
cd <downloaded-folder>
npm install
```

The scaffold is Vite + React and includes the SDK, a mock host, coding-agent
instructions, local CLI tooling, and publish identity.

## 2. Know the project contract

- `rect.view.json` — template discovery metadata, a complete `example` view
  model, and an optional `stateSchema`. `description` says **when to choose the
  Rect**; `stateSchema` describes the complete view-model shape to agents.
- `rect.agent.md` — instructions for agents that issue and update live
  instances. Explain what input to use, what to preserve, and which actions to
  call. Do not turn the discovery description into a long prompt.
- `src/main.tsx` — the React UI over the shared view model.
- `src/actions.ts` — optional named business operations that run host-side in
  a sandbox.
- `rect.json` — stable publish slug and account. Republishing the same slug
  updates the template in place.
- `dev.html` — the local mock host used during development.
- `AGENTS.md` / `CLAUDE.md` — durable instructions for coding agents. Follow
  them; the installed SDK may be newer than model training data.

Keep `rect.view.json.example`, the TypeScript state type, rendering code, and
actions aligned. The example is both default state and executable
documentation for agents.

### Design for repeated issuance

Treat the template as a finished reusable app, not a one-off artifact generated
for one conversation. Put task-specific content in the view model instead of
hard-coding it in the UI source. An operating AI should be able to prepare a
fresh instance by supplying state, without editing or rebuilding the app.

Make the primary human task immediately obvious. Avoid duplicating the AI's
chat inside every Rect; add conversation or comments only when the human
workflow specifically needs them. Use the Rect for the parts that benefit from
a screen: reviewing, editing, comparing, choosing, approving, or handing
completed work back to the AI.

### Keep one source of truth

Store each durable fact exactly once. Derive totals, labels, completion flags,
filtered lists, and other computed values from that canonical state in
selectors or rendering code. Do not mirror the same fact across fields such as
both `items[].done` and `completedCount`; duplicated state drifts and makes
agent updates ambiguous.

Store an otherwise derived value in the view model only when it is
independently edited or must preserve a historical snapshot. Keep ephemeral
presentation state in React state.

### Describe the view model with `stateSchema`

Add `stateSchema` when the state is more than a trivial object. It is JSON
Schema-shaped discovery metadata for agents and tooling; it does **not**
currently validate `rect_issue`, patches, or writes at runtime.

```json
{
  "stateSchema": {
    "type": "object",
    "properties": {
      "title": { "type": "string", "description": "Human-readable title" },
      "status": {
        "type": "string",
        "enum": ["draft", "ready"],
        "description": "Current lifecycle state"
      }
    },
    "required": ["title", "status"],
    "additionalProperties": false
  }
}
```

Use `properties`, `required`, `enum`, nested object/array schemas, and concise
field `description`s so an operating agent can construct the right state. Keep
`example` conformant and representative. `stateSchema` describes stored state;
each named action still needs its own `inputSchema` for dispatch arguments.

## 3. Build the React UI through Rect state

Wrap the app in `RectProvider` and use the published hooks. Do not invent host
APIs.

Keep the screen deliberately simple. Rect already renders the host header. Add
no more than one additional header region inside the view. Do not stack
multiple title bars, heroes, navigation bars, or page-level headers. Ordinary
content headings are allowed when needed.

Add only UI elements and view-model fields required for the human's task. Do
not invent extra panels, filters, metrics, badges, metadata, or configuration
controls without a concrete requirement.

```tsx
import { createRoot } from 'react-dom/client';
import {
  RectProvider,
  useRectField,
  useRectState,
} from '@rectsh/rect/react';

interface NoteState {
  title: string;
  body: string;
}

function Note() {
  const state = useRectState<NoteState>();
  const [body, setBody] = useRectField<string>('body');

  return (
    <main>
      <h1>{state.title}</h1>
      <textarea value={body ?? ''} onChange={(event) => setBody(event.target.value)} />
    </main>
  );
}

createRoot(document.getElementById('root')!).render(
  <RectProvider fallback={<p>Connecting…</p>}>
    <Note />
  </RectProvider>,
);
```

Use:

- `useRectState<T>()` for the full snapshot.
- `useRectValue(selector)` for a derived slice.
- `useRectField(path)` for a two-way field.
- `useRectActions()` for free-form `set`, `update`, and `patch` writes.
- `useRectDispatch()` for named, rule-bearing operations.
- `useRectAttachmentUpload()` when the human needs to upload a file.

Protect focused inputs from destructive full re-renders. Keep ephemeral UI
state such as open panels, filters, and unsaved local drafts in React state;
only shared durable work belongs in the Rect view model.

## 4. Put invariants in named actions

Typing and other unconstrained edits may use patches. Anything with a business
rule belongs in `src/actions.ts` so the human, MCP agent, and CLI all execute
the same validated transition.

```ts
import { defineActions } from '@rectsh/rect/actions';

export default defineActions({
  approve: {
    description: 'Approve the review after every item is resolved.',
    inputSchema: {
      type: 'object',
      additionalProperties: false,
    },
    handler: (state, _input, ctx) => {
      if ((state.items ?? []).some((item) => !item.resolved)) {
        ctx.reject('ITEMS_OPEN', 'Resolve every item before approval.');
      }

      state.completion = { approved: true, at: ctx.now };
    },
  },
});
```

Action handlers are deterministic pure JavaScript over `(state, input, ctx)`:

- no DOM, network, filesystem, `Date.now()`, or ambient randomness;
- use `ctx.now`, `ctx.id()`, and `ctx.reject(code, message)`;
- give every action an agent-facing `description` and `inputSchema`;
- use `patchPolicy: "actions-only"` when agents must not bypass the actions.

Delete `src/actions.ts` only when the view is intentionally patch-only. The
generated dev harness supports both forms.

### Design actions for one dispatch

Assume one named action per dispatch. The SDK does not support dispatching
multiple actions in one request. Do not design around possible future support.
Round-trip-heavy action APIs make Rects slower and more expensive for agents
to operate.

Design array mutations to accept a batch whenever callers may add or change
several records. Prefer one `addItems` action with an input such as
`{ "items": [...] }` over calling `addItem` once per record. Likewise, combine
the steps of one atomic business transition into one named action while
keeping unrelated transitions separate. Document the batch shape in the
action's `inputSchema` and `rect.agent.md`.

## 5. Respect the sandbox

The built view runs in a sandboxed iframe with a host-owned CSP.

- Do not use `localStorage`, `sessionStorage`, cookies, or parent-page access.
- Do not call external APIs from the iframe. State and operations go through
  the Rect bridge.
- Bundle scripts, fonts, images, and styles with the project. Do not load
  frameworks or scripts from a CDN.
- Keep the built bundle under 20 MB.
- Keep the JSON view model small and non-sensitive. Use attachments for file
  bytes and large artifacts.
- Never write the reserved `$attachments` registry directly.

## 6. Audit before testing or publishing

Run the project audit after meaningful changes:

```bash
npx rect check
```

It builds the project and checks the project identity, source and embedded
specs, agent instructions, action metadata, action blocks, example size, and
bundle shape. Every warning or error includes an English `How to fix:` message.
Address errors before publishing and review warnings rather than blindly
ignoring them.

For machine-readable output:

```bash
npx rect check --json
```

The JSON report contains stable check codes, statuses, messages, and fixes.

## 7. Exercise the local agent loop

Run the mock host:

```bash
npm run dev
```

Open `/dev.html`, then inspect and drive the WIP view from another terminal:

```bash
npx rect spec dev
npx rect read dev
npx rect patch dev '{"title":"Draft"}'
npx rect dispatch dev approve '{}'
```

Exercise at least:

1. the initial example state;
2. a human edit in the view;
3. each named action's happy path;
4. each batch action with multiple records in one dispatch;
5. every `ctx.reject` branch;
6. an agent-side state change reflected in the open UI;
7. narrow and wide viewport layouts when a browser tool is available.

Re-run `npx rect check` after fixes.

## 8. Publish only with user approval

Publishing is an external side effect. Do not publish unless the user asks.

```bash
npm run publish
# or publish and immediately issue a live instance
npx rect publish --issue
```

The first publish may run `rect login` in the browser. CI uses
`RECT_API_TOKEN`. Preserve `rect.json`; the slug is how later publishes update
the same template. Prefer publishing with remix source so the template can be
downloaded and edited later.

## 9. Operating a published Rect is a separate workflow

Template authoring uses the project, SDK, checks, and publish CLI. MCP is the
recommended connection for discovering published templates and operating live
instances; terminal-capable agents may use the Rect CLI instead:

```text
rect_list_templates → rect_get_spec → rect_issue
→ rect_dispatch / rect_patch → rect_get_result
```

Template discovery and `rect_get_spec` results include `remixable`. Require
`remixable: true` before promising that `rect remix` can download editable
source.

Do not claim that connecting the MCP server gives an agent access to template
source code or permission to publish source changes. Use `rect remix` plus the
coding workflow for that.

## Reference documentation

- Documentation index: https://docs.rect.sh/llms.txt
- Full documentation when several topics are needed: https://docs.rect.sh/llms-full.txt
- Human-readable docs: https://docs.rect.sh/docs

Fetch only the relevant documentation when the scaffold instructions do not
answer the task. Prefer the local project contract and installed SDK types over
model memory.
