Publishing and remix
Three operations turn a bundle into a living, shareable, forkable app: publish, snapshot, and remix. Apps are built as widgets, so the tools are widget_publish, widget_snapshot, and widget_remix. This page covers what each does and how they relate. For arguments and return shapes, see MCP build tools.
Publish
widget_publish takes a bundle folder you own and deploys it as an app. It runs as a single transaction, so a mid-pipeline failure rolls back cleanly (no orphan agents, no half-wired functions). It is idempotent per (author, folder): republishing updates in place.
In one pass it:
- validates that you own the folder and that it has the entry HTML named by
widget.json, - reads and validates
widget.json(file-path safety, CSP allowlist), - mints (or reuses) a dedicated agent for the app, user-scoped to you,
- wires each declared tool as a custom function on that agent: it adds an HTTP endpoint when
exposeincludeshttp, and an agent-callable tool when it includestool, and share-stamps the source so a clone can re-read it, - stamps the app's command interface (so it is drivable on the canvas and over
workspace_widgets_*), - upserts the catalog row and the post row.
It returns { postId, agentId, widgetContentId, publicMcpAppUrl }. The publicMcpAppUrl is the app's own outbound MCP App manifest at /api/widgets/<postId>/mcp: every published app is itself reachable as an MCP App. A republish replaces stale tool wiring rather than merging it, so a tool you remove actually disappears.
To put the published app on a canvas, call widget_instantiate with the widgetContentId and open the returned canvasUrl.
Snapshot: immutable versioned releases
Publishing keeps a single working app you edit in place. widget_snapshot cuts an immutable, content-addressed version of that working app, so you have a frozen release that does not change when you keep editing.
Snapshotting freezes the bundle tree by cloning it. The clone shares each file's storage pointer with the live folder; a later edit to the live folder diverges (copy-on-write) and leaves the snapshot frozen. So a snapshot is cheap, and unchanged files dedup across versions. Each version records its Merkle treeHash and its parent version, forming an immutable version DAG.
Publishing a version is decoupled from listing it:
listed: falseproduces an unlisted share: a public app row, no marketplace post.listed: trueadditionally creates or repoints a marketplace post.
Snapshotting is idempotent: if the tree is byte-identical to the last version (same treeHash), it is a no-op that reuses the prior artifacts and just clears the dirty flag. On an update you can omit listed to reuse the prior choice (inferred from whether a post already exists), and pass a message for a commit-style version note.
It returns { versionId, widgetContentId, treeFolderId, treeHash, postId, deduped }.
Remix: fork a published app
widget_remix forks any published app (including your own) into your account. For a folder-bundle app it:
- clones the bundle subtree onto your account,
- replays the publish pipeline on the clone, minting a fresh dedicated agent for your fork and creating its own catalog and post rows,
- stamps the remix lineage on your copy (source content id, source post id, source author), and
- bumps the source post's remix count.
It returns { newPostId, newAgentId, newWidgetContentId, ordinal }. You then edit and publish the fork as your own.
Lineage
A remix is attributed to its source. The fork's display name is composed as "<base> - Remix by @<username>", and the remix-of pointers thread the chain so a remix-of-a-remix re-attributes to the latest remixer rather than stacking suffixes. When you later snapshot the fork, the version records a best-effort fork link back to the source's published version, so the version graph spans forks too.
What is not remixable
Some kinds reject a remix:
- passive and native external widgets,
- system widgets,
- live canvas items (a running instance, not a bundle).
These return a remix error rather than forking.
Earning from your app
Listing a snapshot in the marketplace is how your app reaches people, and app usage is how you earn: makers earn through usage-based revenue sharing. See Earn.
Next
- Quickstart: the full loop, including remix.
- App authoring: how
tools[]andexposedrive the wiring above. - MCP build tools: exact arguments and return shapes.
Local dev server
Run a Robutler app bundle on localhost with the experimental dev server: serve your folder, proxy the platform API with a dev token, and preview and debug.
MCP build tools
Reference for the app build and authoring MCP tools (widget_*) and the live-app control tools (workspace_*): arguments, return shape, and notes.