Docs

Build a riff

A riff is a small full-stack web app: a set of plain text files that runs live in an isolated sandbox on its own subdomain — no build step, no deploy, saving a file is live. Build riffs from your AI assistant over theruncurve MCP server, or by hand in the studio.

A riff fits a single-purpose tool with an anonymous URL or embed, isolated backend code, and perhaps a secret, state, or file. See the fit guide and examples before starting something that needs accounts, payments, custom domains, packages, a team, or a release process.

The model

A riff splits into a frontend (runs in the visitor's browser) and a backend (runs server-side in the sandbox). The file boundary is the trust boundary — secrets exist only on the backend.

  • index.html, frontend.js, style.css — served as-is; the frontend runs in the browser and holds no secrets.
  • backend/routes/** — server-side code, one route per file.

File-based routes

A file under backend/routes/ becomes a route. Export handlers by method:

api/hello.js
/api/hello
users/[id].js
/users/:id
[...rest].js
catch-all
export async function GET(ctx) {
  return ctx.json({ ok: true });
}

The handler context

Every handler receives one argument, ctx:

  • ctx.req / ctx.params — the request and matched route params.
  • ctx.store — this riff's private key/value store, plus a sql() escape hatch.
  • ctx.db — this riff's private JSON document store: create/get/put/update/replace/delete/query/list/count, with no schema or migrations.
  • ctx.blob — this riff's private object storage: put/get/head/delete/list, signed browser uploads/downloads, and same-origin public file URLs.
  • ctx.secrets — frozen, backend-only; set them in the studio or with set_secret.
  • ctx.session — a stable per-visitor id + per-visitor storage (get/set/delete). Soft one-per-browser, works inside embeds — "once per visitor" without auth.
  • ctx.json / ctx.html / ctx.text / ctx.redirect — responders (html auto-escapes).

Outbound fetch is off by default. To call a public API from the backend, set network_mode toallowlist and add its exact bare hostname, such asapi.example.com withupdate_riff. Only HTTPS, listed public hosts are permitted; redirects are checked too. The browser remains separate and can call its own origin.

Documents and files

Use ctx.db when a tool has records to collect or query: check-ins, form entries, tracker items, or poll choices. Each document lives in this riff's own SQLite-backed store; collections appear when you write to them, so there is no schema or migration to manage.

const item = await ctx.db.create("checkins", { name, status: "open" }, {
  userId: ctx.session.id,
});

const { docs } = await ctx.db.query("checkins", {
  order: { field: "createdAt", dir: "desc" },
  limit: 20,
});

Use ctx.blob for files belonging to the tool, such as an uploaded avatar, receipt, or generated export. Small files can pass throughput and get;uploadUrl and downloadUrl let a browser transfer files directly. publicUrl(key) serves a file at the riff's own origin and still honors the riff's visibility.

await ctx.blob.put(`avatars/${item.id}`, await file.arrayBuffer(), {
  contentType: file.type,
  userId: ctx.session.id,
});

Version history and rollback

Every source save is live at the same riff URL and becomes an immutable version. Open the studio’s History tab to compare an older version with the live source, then restore it if an edit breaks the riff. Restoring only changes the live version; later versions stay available.

AI assistants have the same recovery path through list_versions,diff_versions, androllback_version.

Embed a riff

Make a riff public and it embeds anywhere — a site, your docs, a notion page. Drop in the <iframe>(or ask the AI for one with get_riff_embed):

That poll above is a live public riff in an <iframe> — here's the markup:

<iframe src="https://brave-otter-7x2q.run.runcurve.com/"
  title="my riff" loading="lazy"
  style="width:100%;height:600px;border:0;border-radius:12px"></iframe>

For AI agents

Connecting an assistant for the first time? Start with thetested Claude Code setup for the exact remote-MCP command, OAuth handoff, and a safe first riff. Once connected, it can create, edit, run, debug, and embed riffs through these tools.

MCP server:mcp.runcurve.com/mcp

runcurve publishes a discoverable Agent Skill that teaches the runtime contract after connection, following the/.well-known/agent-skills standard: