Team plan and above

Site platform API (`window.atrio`)

Site platform API (window.atrio)

Team plan and above. Use this for new agent-built apps that keep state in JSON (trackers, forms, timeline data).

Migrating Vincent-style Circulon review sites (copy-edit-in-place, devclient.js, /capi/comments, devlog + undo) is not this API — see CIRCULON_HOST.md. Those pages need HTML + a same-origin /api/circulon adapter on Atrio; do not rewrite them to atrio.store unless rebuilding the UX.

Sites opt in with platformApi: true (push_site sets this). The viewer injects a bridge; the iframe calls window.atrio, the parent posts to /api/site, and every call re-checks access.

Quick start

const { signedIn, email } = await atrio.user();

// Shared state for everyone allowed to edit (org members on an org-scoped link, etc.)
const doc = await atrio.store.get("circulon-timeline", { scope: "shared" });
let revision = doc.revision ?? 0;
let state = doc.value ?? { rows: [] };

state.rows.push({ id: 1, label: "Milestone A" });
const saved = await atrio.store.set("circulon-timeline", state, {
  scope: "shared",
  ifRevision: revision,
});
if (saved.error === "conflict") {
  // Another editor saved first — reload and merge, or prompt the user.
  const fresh = await atrio.store.get("circulon-timeline", { scope: "shared" });
  revision = fresh.revision;
  // ...
} else {
  revision = saved.revision;
}

// Undo last change to this key (server-side history, up to 50 steps per key)
await atrio.store.undo("circulon-timeline", { scope: "shared" });

Store (atrio.store)

MethodDescription
get(key, { scope })Returns { value, revision }. Missing key → { value: null, revision: 0 }.
set(key, value, { scope, ifRevision })Saves JSON (max 64 KB). Returns { ok: true, revision } or HTTP 409 { error: "conflict", revision, value } if ifRevision does not match.
list({ scope }){ items: [{ key, value, revision }] } (up to 1000 keys).
delete(key, { scope })Removes a key.
history(key, { scope, limit })Prior snapshots { items: [{ revision, value, at, by }] } for undo UI.
revert(key, { scope, revision })Restores a historical revision as a new head (append-only).
undo(key, { scope })Restores the previous revision (convenience wrapper).

Scopes

  • shared — one namespace per site. Writes require a member (or a link with store writes enabled).
  • me — per signed-in user. Requires sign-in.

Simultaneous edits: There is no live merge/cursor sync. Use ifRevision on set for optimistic concurrency; on conflict, reload get and reconcile. This matches “editable tool with shared data,” not Google Docs co-editing.

Data (atrio.data.query)

Read-only SQL over attached datasets (same DuckDB sandbox as Ask the data). Requires data access on the link.

const rows = await atrio.data.query(
  "select region, sum(amount) as total from data group by 1",
);

User (atrio.user)

{ signedIn: boolean, email: string | null }

The iframe cannot read the Atrio session cookie; this is the supported way to know who is signed in.

HTML / agent versions (separate from store)

  • Each MCP push_site / push_dashboard creates a new content version (what you see under History in the library).
  • publish_version chooses which version viewers see.
  • Undo for the whole page = restore an older content version in the library, or republish via MCP.
  • Undo for in-app edits = atrio.store.undo / revert on your state keys.

Migrating from Cloudflare / Dots

Pick one:

SourceDoc
Circulon Worker (devclient.js, /capi/*, pin comments, copy publish)CIRCULON_HOST.md (spec; host on Atrio with circulon-compat API)
New interactive app (state in JSON, no /capi)This file (window.atrio.store + MCP below)

New apps (this API):

  1. Connect MCP to https://app.atrio.cc/api/mcp; call atrio_whoami with Global Meyer workspace_id.
  2. Publish with push_site (multi-file) or push_dashboard (single HTML). Use set_audience (org for all of Meyer, private for Restricted).
  3. Move persisted state from Workers KV / localStorage into atrio.store (scope: "shared").
  4. On load: get → render; on save: set with ifRevision; wire Undo to store.undo or history + revert.
  5. Point Dots at https://app.atrio.cc/site-api and MCP_TOOLS.md.

Security

Iframe is sandboxed; only the bridge can call the API. Values are JSON only; no arbitrary server code from the site.