Skip to content

Export, import and share apps ​

Export a complete app from App → Settings → Export and import. The ZIP contains the active release's editable source and served artifact, all app business records and all current managed Files. Exporting leaves the original app in place. Downloads expire after 24 hours; a downloaded ZIP remains usable.

This version supports full packages only. There are no table, row or file filters, and importing never overwrites an existing app. An incomplete or unsupported package fails with an explanation instead of silently omitting data. The existing release source download is still available when you only need code.

Prepare an app for export ​

Publish a release with retained source. Apps with database tables also need an opencloud.portability.json file in that source. This is the author's declaration that the database contains portable business data, has no required state in an external service, and identifies every OpenCloud user ID and managed File ID that must change when copied:

json
{
  "schemaVersion": 1,
  "data": "business",
  "externalState": "none",
  "references": [
    { "table": "tasks", "column": "owner_id", "kind": "user" },
    { "table": "attachments", "column": "file_id", "kind": "file" }
  ],
  "installerIdentities": []
}

References must be ordinary UUID columns. Business primary keys and their foreign keys retain their values; declared OpenCloud user and File references are mapped explicitly. The exporter checks declared references and includes every table and file. It cannot infer references hidden in arbitrary JSON, text, URLs or external systems. Adapt those apps before declaring them portable. It does not classify ownership from column names or replace matching strings throughout the source.

The snapshot briefly blocks database writes and managed File changes while it copies a consistent release, data and file set. If writes cannot be fenced, a file is missing, or a limit is exceeded, retry after correcting the cause.

OpenCloud accounts, platform credentials and sessions, sharing grants, provider connections, custom domains, Agent chats, historical releases, queued deliveries and runtime receipts are excluded. Reconnect services and configure secrets at the destination. App-owned source and records can still contain sensitive data, including credentials stored by app code. Known credential filenames are rejected, but an export is not an automatic anonymization or secret-removal tool.

Import a full package ​

  1. Open Your apps → Import an app or /new-app on the destination installation.
  2. Select a ZIP and choose Check full package. Review its table, record and file counts. Map each original OpenCloud user identity explicitly to yourself or to a confirmed person in your organisation. Mapping identities does not invite people or grant them app access.
  3. Choose a name and Install app. This creates a new private app with an editable draft and copies its managed files. Refreshing the page or retrying a lost response resumes the same import. The page names the destination account.
  4. Inspect the source and open the isolated development preview. Preview uses development data; it never receives the imported production records or files.
  5. Configure required secrets and connections, then choose Publish private app with all data. Publication validates the source, runs migrations under the normal restricted app role, restores all records, checks the copied files, and activates the app. Publish the imported database before editing its migrations.
  6. Review the private app, then explicitly Enable Functions and automation in Settings. All production Functions, including interactive calls, remain held until then, together with schedules and automatic tasks. Static pages and ordinary Data/Files access remain subject to the app's policies. Frontend code is executable too: inspect untrusted source before opening it.

Imported rows replace migration seed rows. Foreign keys are validated after the complete load, sequence values are restored, and ordinary database triggers do not run during row restoration. Managed File IDs are new and declared references follow their mapping. No account or provider permission is inherited.

Uninstalled reviews expire after 24 hours and can be discarded on the review page. Installed drafts keep their staged dataset until publication or deletion of the new app. Each account can retain at most two pending packages, including exports; finish an import, discard an uninstalled review, or use Discard download beside an export to free a slot.

CLI ​

The public CLI adds these commands in version 3.20.0. Both installations must support app portability. Sign in to the source installation to export, then to the destination installation to import. Choose a stable retry key for each action and reuse it if its response is lost.

bash
opencloud --api-url https://api.source.example app export create APP_ID --idempotency-key move-export-001
# The export ID is the completed operation's id.
opencloud --api-url https://api.source.example app export download APP_ID EXPORT_ID --output app.zip
opencloud --api-url https://api.destination.example app import upload app.zip --idempotency-key move-upload-001
opencloud --api-url https://api.destination.example app import get IMPORT_ID
opencloud --api-url https://api.destination.example app import install IMPORT_ID --name "My app" --mappings users.json --idempotency-key move-install-001
# After reviewing the draft and configuring connections and secrets:
opencloud --api-url https://api.destination.example app import publish IMPORT_ID --idempotency-key move-publish-001
opencloud --api-url https://api.destination.example app portability enable NEW_APP_ID --idempotency-key move-enable-001

users.json is an object mapping each source user UUID to a confirmed destination user UUID. Omit --mappings only when the review needs no manual mappings. Uploads stream from disk; downloads stream to a private temporary file, verify the export's size and SHA-256, then save it. Existing files are protected unless --force is supplied; a failed verification still leaves the existing file intact.

For shared examples, run app import inspect MANIFEST_URL, then app import stage INTENT_ID --idempotency-key KEY and review/install as above. For a directly hosted private package, use app import from-url ZIP_URL --sha256 DIGEST --bytes SIZE --idempotency-key KEY. The HTTPS URL must be reachable by the destination server; treat any signed URL as a private credential. Do not make a private export public to transfer it. Local upload works without hosting.

app export get APP_ID EXPORT_ID returns expiry and checksum; app export discard APP_ID EXPORT_ID frees a temporary download. app import discard IMPORT_ID discards an uninstalled review. app portability get APP_ID shows whether Functions and automation remain held. Export, publication and enable commands follow durable operations by default; --no-follow returns their operation coordinate immediately.

MCP ​

The full MCP surface provides the same review and explicit activation steps:

TaskTools
Exportexport_app, poll get_operation, then get_app_export
Import a hosted ZIPimport_app with an HTTPS URL, exact bytes and SHA-256
Import a local ZIPget_app_import_upload returns the signed-in browser upload page
Install an exampleinspect_app_install, then stage_app_install
Review and installget_app_import, then install_app_import with user mappings
Publish and enablepublish_app_import, then explicitly enable_imported_app
Check or discardget_app_portability, delete_app_import, delete_app_export

Mutating preparation, install, publish and enable tools require an idempotencyKey; reuse it for the same action. Export links require the owner's normal sign-in and expire after 24 hours. ZIP bytes never enter tool arguments or results. Hosted MCP cannot read a file on the user's device: after the browser upload, use the import ID from the review page URL, or use the CLI for a complete local transfer. Long transfers can outlast an MCP client's own timeout; the CLI supports longer requests and stable retry keys. None of these steps implicitly publishes or enables an imported app.

Share an installable example ​

Prepare a separate app containing only fictional demo data, or a completely empty app. Export that whole app. Do not publish a real app's private export. No records are removed by choosing the example option.

For a fictional owner that should become the installing person, put its exact UUID in installerIdentities in the source profile and choose the example checkbox when exporting. Only a reviewed example manifest permits this binding; ordinary ZIP uploads require explicit user mappings. This is not a publisher account or a sharing grant.

Host the ZIP, one to six screenshots, and a JSON manifest at public HTTPS URLs. GitHub raw files and release assets, or your own public web hosting, work with the same format. Use a versioned URL for each ZIP and calculate its SHA-256 and exact byte length. The listing is pinned when opened; the installer checks the download against those bytes before creating an app.

json
{
  "schemaVersion": 1,
  "kind": "opencloud.app-install",
  "id": "your-name/project-board",
  "version": "1.0.0",
  "title": "Project board",
  "summary": "Keep a small team's tasks in one place.",
  "description": "A ready-to-customize board with fictional launch tasks.",
  "publisher": { "name": "Your name" },
  "license": "Your chosen license",
  "sourceUrl": "https://example.com/project-board/source",
  "images": [
    { "url": "https://example.com/project-board/board.png", "alt": "Tasks grouped by progress" }
  ],
  "data": { "kind": "demo", "description": "Seven fictional tasks and one setup record." },
  "requirements": { "capabilities": ["data"], "integrations": [], "secrets": [] },
  "archive": {
    "url": "https://example.com/project-board/1.0.1/app.zip",
    "sha256": "REPLACE_WITH_THE_ZIP_SHA256",
    "bytes": 12345
  }
}

data.kind is empty or demo. Requirements must match the actual package: capabilities include data, files, functions, cron, queues, agentTasks and email; integrations and secrets list declaration names, never values. Publisher and license text are publisher claims, not a verified badge. Set the license to terms you are entitled to offer; a download alone grants no new redistribution license. Optional icon and publisher url use HTTPS too.

Generate a button link by encoding the complete manifest URL:

js
const install = new URL("https://opencloud.ai/new-app");
install.searchParams.set("manifest", manifestUrl);

Use that link for Install in OpenCloud in a GitHub README or on a website. For another OpenCloud installation, change the destination origin. The page shows screenshots, title, description, publisher, data and setup requirements. Signed-out visitors return to that pinned listing after signing in and completing account setup. Opening a link never creates or publishes an app; the explicit Install action creates the private draft. Updates to a publisher's manifest do not update existing copies.

The Project Board gallery page includes the first built-in install link. Its versioned files are served at /app-examples/project-board/1.0.1/ (install.json, app.zip, board.jpg). Other gallery entries continue to offer their existing source and remix flows.

Format, API and limits ​

The ZIP contains package.json (format version 1 and complete entry checksums), separate source.tgz and artifact.tgz, database/schema.json, one database/data/<table>.jsonl per table, files/index.json, all files/content/<original-file-id> bytes, and README.md. Each JSONL row is an array in declared column order. Each cell contains PostgreSQL's text encoding or JSON null for SQL NULL; this preserves large integers, decimals, binary values, arrays and JSON numbers without JavaScript number conversion.

Limits are 2 GiB for both the ZIP and its expanded entries, 50 MiB of editable source (10 MiB per source file), 200 ordinary tables, 5,000,000 total rows and 5,000 managed files. Partitioned, foreign and materialized tables are not supported. Packages containing required external service state or references outside the supported profile need adaptation first. App capacity, storage quotas, per-file upload limits and normal publication validation also apply. Each metadata JSON file and each encoded database row is limited to 128 MiB.

Export ZIPs are stored in private object storage. An import is validated once and split into separate source, table-data and file objects with checksums; the original ZIP does not need to be stored again. PostgreSQL keeps the package metadata and progress. Uninstalled imports and exports expire after 24 hours. An installed draft retains its package until successful publication or app deletion. Discarded and expired packages are queued for deletion, with retries when storage is unavailable. Uploads, ZIP validation and export creation use private temporary disk space and streams, so the full ZIP, managed files and database tables do not need to fit in server memory. Source validation, metadata and individual database rows still use bounded memory. Database data and managed files stream from their prepared objects. Completed file transfers and database tables are reused on retry. Publication validates the complete dataset before making it available, rebuilds secondary indexes and updates database statistics. Prepared parts belong to one import; there is no shared example cache.

The control-plane API exposes export operations, binary ZIP upload/download, import review/install/publication, and manifest inspection. Imports require an authenticated person; app-scoped owner credentials may export the app they administer. Browser writes require the installation's origin. The MCP registry exposes the corresponding JSON operations; binary upload/download use authenticated HTTP streams in the CLI and browser. The CLI is released separately; a platform upgrade does not update an already installed CLI.

Other hosting providers can read the ordinary source, migrations, typed data and file bytes. Running there still needs an adapter for OpenCloud authentication, Data/Files, Functions and other runtime services. This release does not claim automatic deployment to an unrelated provider.

Self-hosted infrastructure for agent-built applications.