CLI
Publish templates, issue rects, and drive their state from your terminal or a script.
@rectsh/cli is the terminal surface for rect.sh — the same loop agents run
over MCP, speakable from any shell, script, or CI job. It covers
publishing templates (reusable views), issuing rects (live instances),
injecting and reading back state — and driving the view you're still
developing.
npm install -g @rectsh/cli
rect login # authorize this machine via your browser (once)Account plumbing: rect accounts lists the teams you can publish to,
rect members --account <slug> lists one team's members for shaping into Rect
state, rect whoami shows who this machine is logged in as, and rect logout
removes stored credentials. rect host prints the effective default host, and
rect host set <url> stores a new default.
Apps — compose and run jobs
rect app publish app.json --account acme # Markdown job + ordered Screens
rect app list --account acme # visible Apps
rect app spec <app-id> # instructions and pinned Screens
rect app launch <app-id> --account acme --open
rect app launch <shared-app-id> --account acme --confirm-third-party --open
rect app read <run-id> # job + ordered Screen handles
rect app select-screen <run-id> --screen request --expected-revision 2An App specification may use instructionsMd directly or
instructionsFile relative to the JSON file. Each ordered Screen accepts a
screen slug/id plus initialViewModel; the CLI resolves and pins its stable
Screen id and immutable version id during publication. See
Apps and Screens for the complete format and external-agent
loop.
rect app read intentionally keeps child ViewModels out of the aggregate
response. Use rect read <instance-id> for the Screen you are about to work on,
then rect dispatch its named actions.
rect members --account acme --json \
| jq '{members: .members}' \
| rect issue team-directory --account acme --state - --read-access workspaceMember output includes names, emails, roles, and profile image URLs. Prefer
workspace access for Rects containing member email addresses unless broader
access is explicitly intended.
Templates — publish & explore
rect publish # build, bundle, and deploy the view in this directory
rect check # build + actionable project audit [--json]
rect publish --issue # publish, then issue one live instance
rect search "project planning dashboard" # find matching templates [--account <slug>] [--limit <n>] [--json]
rect list # visible templates [--account <slug>] [--limit <n>|--all] [--cursor <cursor>] [--json]
rect spec <ref> # one template's spec — always JSON
rect remix <ref> # download a template's source into a new folderrect publishis keyed by the project's slug (rect.json), so republishing updates the same template in place. See Compile & publish.- Teams: everything belongs to a team. With nothing pinned, a single team
resolves itself and multiple teams are prompted for;
--account <slug>targets one explicitly (rect accountslists them). Publishing remembers the choice inrect.json. <ref>is a template slug or id. Without an account pin,rect listshows visible templates from your teams first, then official and other public templates. It returns 20 by default; increase--limitor pass--allfor the complete catalog.rect list --account <slug>lists only templates owned by that account. JSON output includesnextCursor, which can be passed back with--cursorto resume. Template references resolve across the visible catalog; use an id when public templates share a slug. Forrect issue,--accountselects the destination workspace, not the template owner.
Audit before publishing
Run rect check from a bundle-based Rect project before handing it back or
publishing it:
rect check
rect check --json
rect check --no-build --dir distThe audit checks the build, stable project slug, source and embedded specs,
the required stateSchema, schema validity and example conformance,
rect.agent.md, Codex/Claude Code instruction files, action metadata and
handler block, example size, entry file, and the 20 MB bundle limit. Problems
are written for a coding agent to act on:
WARN Action "approve" has no inputSchema.
How to fix: Add an inputSchema for "approve" so agents can construct
valid arguments and the host can reject malformed input before the
handler runs.--json returns stable check codes, statuses, messages, and fixes. Warnings do
not fail the command; errors exit non-zero.
Rects — issue & drive
rect issue <ref> # issue a rect from a template
rect issue <ref> --state '{"title":"A"}' # …with an initial view model
rect issue <ref> --state input.json --open # …from a file, then open it
rect issue <ref> --read-access anonymous --write-access owner
rect find # issued rects, newest issued first
rect find --account <slug> --template <ref> --status open
rect find --sort updated # most recently updated first
rect find --all # every accessible issued rect
rect read <rect-id> # full state + revision — always JSON
rect patch <rect-id> '{"done":true}' # RFC 7386 merge patch
rect patch <rect-id> --file patch.json --expected-revision 4
rect dispatch <rect-id> addTodo '{"title":"Ship it"}' # run a named action
rect open <rect-id> # open in the browser
rect delete <rect-id> # permanently delete a Rect
rect attachment upload <rect-id> ./report.pdf # signed upload into $attachments
rect app attachment link <run-id> <attachment-id> --screen <key>read,open,patch,dispatch, and attachment mutations all follow the instance's independent read and write scopes. The CLI sends your configured login orRECT_API_TOKENwhen available; protected access returns401when sign-in is required and403when that identity lacks permission.- Authenticated issuance defaults both scopes to
workspace. Use--read-accessand--write-accessto choose a different audience. - Without an account pin,
rect findsearches issued Rects across every account you can access.--account <slug>narrows the results to that account. The CLI follows pagination automatically up to--limit(default 20); pass--allfor every result. JSON output includesnextCursor, which can be passed back with--cursorto resume. Results default to newest issued; pass--sort updatedfor most recently updated. - When the view declares actions, prefer
dispatchoverpatch: the view's handler runs host-side and a rule violation comes back as its code (✖ Rejected (TODOS_OPEN): …) instead of corrupted state. --expected-revisiongives optimistic concurrency: a stale patch fails with the current revision so you can re-read and retry.--stateand patches accept inline JSON, a file path, or-(stdin).rect deleteasks for confirmation and defaults to “No.” Scripts and other non-interactive sessions must pass--yes.
The agent loop
rect search "sales report" # what best fits?
rect spec <template-id> # what shape does it want?
rect issue <template-id> --state '{...}' # issue + inject
# … the human works in the view …
rect read <rect-id> # read their edits back
rect patch <rect-id> '{"note":"reviewed"}' # respondUse rect list when you want to browse the catalog, or when keyword-based search is
unavailable or does not return a useful candidate. Without an account pin,
both commands include public templates; rect list --account <slug> narrows
the listing to templates owned by that account. Listing defaults to 20 results;
increase --limit or pass --all to retrieve the complete catalog.
This is the same loop agents run over MCP (rect_issue /
rect_patch / rect_dispatch / rect_get_result) and any program can run
over the HTTP API — the CLI speaks it from any terminal or
script.
Drive the view you're developing
While npm run dev is running, the @rectsh/rect/vite plugin plays the Rect host
locally. The reserved id dev targets it — the CLI finds the dev server on
its own (ports 5173–5180; --dev <port> for anything else):
rect spec dev # the spec of the view being developed
rect read dev # the dev store's current state
rect patch dev '{"title":"draft"}' # applies live in the open /dev.html
rect dispatch dev stamp '{"text":"x"}' # runs src/actions.ts (hot-reloaded)Changes land in the browser over Vite's HMR socket — no reload — and edits made
in the page flow back, so rect read dev always sees the latest. It's a full
rehearsal of the agent loop against your work-in-progress view, before any
publish.
CI
Create an account API token in account settings and set RECT_API_TOKEN
instead of rect login, then pass --account <slug> (or commit it in
rect.json).
export RECT_API_TOKEN=rect_api_...
rect publish --account acmeIn GitHub Actions, store the token as a repository secret and expose it only to the publish step:
- run: rect publish --account acme
env:
RECT_API_TOKEN: ${{ secrets.RECT_API_TOKEN }}Host precedence is
--host > RECT_HOST > rect host set <url> > https://rect.sh.