Architecture

Cloud as source

Cloud projects are owned by Openship Cloud; your self-hosted instance is a gateway in front of it — plus how projects promote up and come back home.

For a Cloud-owned project, Openship Cloud (our hosted service) holds the one true copy — the canonical owner. Its record, deployments, domains, environment variables, and logs all live on the cloud, and the cloud runs its builds and lifecycle. Your self-hosted instance keeps no local copy of that project. Instead it acts as a gateway — a thin pass-through that forwards requests for that project up to the cloud and hands you back the answer.

Think of it like a mailbox on your street. The letters aren't stored in the mailbox; the mailbox just carries them to and from the real post office. Your instance is the mailbox; Openship Cloud is the post office.

One rule to remember

A project lives in exactly one place — fully local, or fully on the cloud. Never half in each. That is the whole idea behind this page.

A gateway, not a mirror

Openship deliberately never keeps two copies of the same project. A mirror would mean two sources of truth that constantly drift apart and need reconciling — and a bug on your box could corrupt cloud data. A gateway avoids all of that: there is nothing to sync, because there is only ever one copy.

Your dashboard can keep talking to your local API. Requests for a Cloud project are forwarded upstream and returned through the gateway. SDK and CLI credentials fixed to an organization must connect directly to that organization's API; a local scoped credential cannot borrow its owner's Cloud session.

Creating a project from Desktop

In the connected dashboard, selecting a managed Cloud server for a new catalog app or Git project creates its configuration through the Cloud API. Capacity checks, installation and subsequent project operations use that Cloud account and organization. The project, services and routes are stored in Cloud; the desktop controller keeps no project copy. An existing verified server link is translated to its canonical Cloud server ID.

Local folders, upload sessions and custom app definitions uploaded to this instance keep their local controller because their source is available there. Existing local projects retain their owner, even when they run on a linked managed server. Use an explicit transfer to move an existing project's ownership. Credentials scoped to the local installation keep their existing execution path; connect SDK and CLI clients directly to the Cloud API to create Cloud-owned projects.

A failed Cloud creation or capacity check remains an error. Openship does not fall back to creating a local project or selecting a different Cloud account.

Your local permission checks still run first

Forwarding does not skip your rules. The local permission plane gates every call — checking the caller's role and access — before anything is proxied. Only then does the gateway forward the request.

How the gateway knows where a project lives

For every project-scoped request, the local API decides "serve this from my own database, or forward it to the cloud?" in this order:

  1. A local lookup. A project ID present in the local database stays local, including a row owned by another tenant. Local authorization still decides whether it is accessible.
  2. A cloud link. No local row, but the caller's organization has a linked Cloud account? The request may be forwarded after local permission and credential checks.
  3. Cloud authorization. Cloud validates that the requested ID belongs to the linked Cloud organization. An unknown or foreign ID remains a 404.
  4. Otherwise, not found. Without a link, an unknown ID is handled locally and returns 404.

A client-provided cloud source hint cannot override a local record or grant Cloud access. An explicit local hint can keep project requests on the local path.

If the cloud can't be reached while forwarding, you get a 503 with code CLOUD_UNREACHABLE — not a 404. That distinction matters: the project does exist, the cloud is just temporarily out of touch.

Actions for Cloud-owned apps

Opening a Cloud project's Actions tab forwards its workflows, runs and deployment rules to Cloud. Workflow and run detail requests, log cursors, artifacts and runner changes follow the same ownership decision. The Actions workflow, project and runner lists include both local and connected Cloud inventory; no Cloud records are copied into your local database.

A workflow's projects and runners must belong to the same instance. An import or policy that mixes local and Cloud targets fails before either side writes anything. Cloud checks its own repository access, destinations and approval policy, and records the mutation there. Local credentials scoped to this instance cannot borrow the owner's Cloud session. Connect your SDK or CLI directly to Cloud when using a fixed Cloud organization scope.

If Cloud cannot be reached, Actions reports a connection error instead of presenting an empty list. Local project requests continue to use the local engine. On Cloud itself, these operations run directly and never proxy back to Cloud.

One cloud identity for the whole team

A cloud connection belongs to the organization owner, not to each person. When the gateway forwards a call, it authenticates as the owner's Openship Cloud session (read server-side from encrypted storage — no cookies or tokens ever travel from the browser).

So teammates do not each need their own cloud account. Your local instance decides who is allowed to act (by their role), then proxies the action as the owner. Because the connection is org-owned, every member sees the same "connected" state and the same list of cloud workspaces.

Promote: sending a project up to the cloud

Promote moves a local project onto Openship Cloud so the cloud becomes its canonical home. Under the hood it copies the project's whole subgraph (the project row plus everything attached to it — deployments, domains, env, and so on) up to the cloud, and then removes the local rows so no shadow copy is left behind.

There are two ways it happens:

  • Born on Cloud. New catalog apps and Git projects created from the connected dashboard with a managed Cloud server are created directly in Cloud. There is no local project to copy or delete.
  • Explicit transfer. You can also promote on demand from the CLI or API (see Doing it yourself).

Auto-deploy follows the project up

Promote keeps the project's GitHub webhook. After promoting, a git push to the repo is forwarded to the cloud copy and redeploys it there — so auto-deploy keeps working without any change on your side. Bring-home reverses this: pushes are handled locally again.

Locally-encrypted secrets aren't carried up as-is

Values encrypted with your instance's key (secret env vars) can't be decrypted by the cloud, so they're stripped during promote. After a project is on the cloud, re-enter those secrets in the cloud project.

Bring home: pulling a project back

Bring-home is the reverse: it exports the project's subgraph from the cloud, restores it into your local database, clears the project's cloud link, and then tears down the leftover rows on the cloud side so a future promote won't collide. From that moment the project is canonical-local again, and pushes to its GitHub repo are handled locally instead of forwarded.

What bring-home moves today

Bring-home moves the project's data. Reconnecting things like custom-domain DNS and bringing the app's containers back up are operator follow-up steps, not part of the data transfer itself.

What your box still does for a cloud project

For a Cloud-owned project, your local instance forwards operations to Cloud. A local project can also use a verified managed server as its execution destination: the local controller owns its configuration and orchestration, while the managed server and its billing belong to Cloud. This supports local-folder sources and credentials scoped to the installation without giving them the owner's Cloud account permissions. See Runtime model for how a runtime target is chosen.

On Openship Cloud itself

There's a neat symmetry here: on the cloud service, every project is already canonical-local — there is nothing upstream to forward to. The exact same code runs on both sides; the gateway simply resolves "local" when it is the cloud, so no request ever loops back on itself.

Doing it yourself

Promote and bring-home are self-hosted-only actions, guarded by the project:admin permission. Your organization also has to be connected to Openship Cloud first — a transfer on an unconnected org is refused.

# Promote a local project up to Openship Cloud
openship project transfer <projectId> to-cloud

# Bring a cloud project back to this instance
openship project transfer <projectId> to-self-hosted

The matching API routes are POST /api/projects/:id/transfer/to-cloud and POST /api/projects/:id/transfer/to-self-hosted. On promote, a transfer that copies up cleanly but can't finish local cleanup returns a partial-success (207) so you can retry the cleanup — the cloud copy is already authoritative.

Errors a transfer can return

  • 412 — your org isn't connected to Openship Cloud yet.
  • 409 — the project is already on the target side, or a leftover cloud copy / a name clash blocks the promote. Openship never overwrites the other copy; it asks you to clean up or rename and retry.
  • 502 — the cloud accepted the call but the transfer itself failed upstream.

On this page