Code export
The code behind your app is yours: export it anytime and reuse it anywhere.
What you can do
The code behind your app is yours. It has three parts: the module is the app’s business logic, the ui is the interactive interface, and the styles are the visual look. You can export all three at any time and reuse them: move an app between agents, back it up, or hand it to a different tool. Anyone who can edit the app can export its code; someone with view-only access can’t.
Copy an app in one step. Your agent can make you a private copy of an app you can edit, with or without its stored data, without reading the code out and sending it back. Use it for a demo twin of a real app, a copy to try a risky change on, or a fresh start.
Technical
Exporting source is an agent action. Ask your agent rather than looking for it in App settings.
Copy this prompt for your agent
Export the source for one of my Charming apps so I can reuse it (back
it up or move it to a different agent), or copy it into a new app. Read
https://charm.ing/docs/capabilities/code-export.md first. List my
apps and ask me which one, or if I've only got one, use that. To make a
new app from it, copy it with copy_app and ask me whether to include
its data; otherwise export the source.
How an agent performs this job
To export source, an agent calls GET /app/<id>/source over HTTP or get_app_source({ app_id }) over MCP. Both return id, url, manifestId, displayName, a server-owned revision, capabilities, and source: { module, ui, styles }. The MCP tool also returns sourceSize, the character count of each bucket. When the source is too large for your client, read one bucket at a time with get_app_source({ app_id, bucket, offset, expected_revision }): each call returns up to 20,000 characters of whole lines in chunk.text; pass chunk.next_offset as offset until it is null, and pass the revision from the first read as expected_revision so a change between reads fails with revision_mismatch instead of mixing revisions. To turn an app into a new one, copy it instead of exporting and re-sending its source.
Copy an app
An agent calls copy_app({ app_id, manifest_id?, display_name?, include_data?, idempotency_key? }) over MCP or POST /app/<id>/copy over HTTP with the same optional fields as a JSON body. The caller gets a new private app they own, and the source never passes through the agent’s context.
- What the copy keeps. The module, UI, styles, icon, description, and network settings, exactly as the source has them.
- What stays behind. Shares, Public, signed-in access, Template and Listed state, tokens, secrets, Routines, Webhooks, the custom domain, and version history. The copy starts at revision 1.
- Manifest id. Without
manifest_id, the copy takes the next free id for the caller: the source’s id if they hold no app with it, otherwise<id>-2,<id>-3, and so on. An id still holding data or secrets from a deleted app counts as held. Amanifest_idthe caller already holds fails withmanifest_id_conflictand changes nothing; a copy never replaces an app. The error names the app holding the id inexistingAppId. The copy keeps the authored id assourceManifestId, so the UI’swindow.charming.api('<manifest-id>')calls keep working without an edit. - Data.
include_data: truealso copies the source’s stored data and assets. Per-visitor data on a public custom domain never copies. Only the owner of a personally owned source can copy its data; anyone else getscopy_data_forbidden. A team app’s data is not copied, even by a team admin, because a copy always lands in a personal account; copy a team app withoutinclude_data. A copy carries at most 24 MiB of stored data and assets together (copy_data_too_large), and must also fit the per-app caps (storage_full,asset_count_exceeded,asset_quota_exceeded) and the caller’s plan storage allowance (storage_limit_exceeded). The data copies in the same step that creates the copy, so a copy has all its data or does not exist, and a refused copy creates nothing. The result reportscopiedData: { keys, assets }, except on an idempotency replay, which returns the earlier copy without it. - Secrets. Secrets never copy. When the caller can manage the source’s secrets,
secretsNotCopiedlists their names so the agent can set them on the copy. - Templates. Someone who can copy a Template but not edit it gets a Template copy (
copyKind: "template"): it records the Template as its source, takes the starter prompt, and never carries data. - ESM apps. An app on the ESM contract copies through a build. When the build publishes at once, the result is the copy, as for any app. Otherwise it is the build status (HTTP 202) to poll with
get_app_build; the copy and its data appear together when the build publishes. An ESM copy takes its name frommanifest.meta.name, sodisplay_nameis refused. - Retries. Pass an
idempotency_key(8–100 visible ASCII characters) to make a retry safe: the same key returns the copy, or the pending build, that the first call made instead of making another. If that copy was deleted or its build failed, the retry makes a new copy. The same key with a different source,include_data, ormanifest_idfails withidempotency_conflict. Without a key, every call makes a new copy.
The contract
get_app_source and GET /app/<id>/source require the same edit access as update_app: the caller must be the owner or hold a collaborator (or team-member) grant on the app; get_app_source fails with not_found for anyone else. copy_app and POST /app/<id>/copy need that edit access too, or a Template the caller may copy, and a signed-in user: an app token or render token is refused. A caller who cannot open the app gets not_found; one who can open it but not copy it gets forbidden. The HTTP route accepts the original chrm_app_* edit token (unclaimed apps) or a signed-in chrm_user_* token with that access (claimed apps); a render token or claim cookie is rejected.
Limits and access
- Who can export. The owner, a collaborator, or a team member with write access can call
get_app_source; anend-userorviewershare (read/run only, no edit) can’t. - Who can copy. Anyone who can export can copy, without data. Copying data needs the owner of a personally owned app.
- Copies for other people. To let people who can only view the App make their own copy, enable Template. Publish it as Listed if anyone should be able to discover and copy it without access to the source App or its data.
Related
- Templates: let existing App readers copy, or publish a Listed Template for anyone
- Data storage: what does and doesn’t carry over into a copy
- How Charming works
- Docs home
- llms-full.txt