Documentation

Everything you need to run Paperclip.

Guides, references, and walkthroughs for the people running AI agents at work. Start at the quickstart, or jump anywhere below.

Sync a local company to a Paperclip Cloud upstream

Cloud Upstream sync moves a local Paperclip company — its agents, projects, issues, skills, and portability files — into a connected Paperclip Cloud stack. You preview what would change, resolve any conflicts, push the work, and then decide which entity types (agents, routines, monitors) should activate on the cloud side.

The flow is opt-in, experimental, and gated behind an instance setting. Nothing leaves your local instance until you flip the flag and authorize a connection.

Time to first dry-run push: about 15 minutes.


What you'll need

  • A running local Paperclip instance you can reach as the board user.
  • A Paperclip Cloud stack URL that advertises the cloud_sync transfer feature flag at /.well-known/paperclip-upstream.
  • The local companyId you want to push.
  • Enough rights on the cloud stack to approve the authorization grant — the CLI requests the scopes upstream_import:preview, upstream_import:write, and upstream_import:read.

1. Turn on the experimental setting

Cloud Upstream sync is hidden until you opt in. The server rejects every cloud route with Cloud sync is not enabled and the CLI refuses to push with the same message until the flag flips to true.

The flag lives on the instance experimental settings:

curl -X PATCH "$PAPERCLIP_API_URL/api/instance/settings/experimental" \
  -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enableCloudSync": true }'

You can also flip it through the board Settings panel — the Cloud Upstream entry shows up once the flag is on.


2. Connect to the cloud stack

The CLI generates a fresh source identity (an ed25519 keypair plus a fingerprint), opens a browser to the cloud stack's PKCE authorize URL, and stores the resulting token under ~/.paperclip/<instance>/secrets/cloud-upstream-connections.json. The file is written with mode 0600 — keep it that way.

paperclipai cloud connect https://cloud.example.com

If the host has no browser, fall back to the device-code flow:

paperclipai cloud connect https://cloud.example.com --no-browser

You'll see a verification URL and a one-time user code. Open the URL on a machine that does have a browser, paste the code, approve the grant, and the CLI takes over.

The board UI also has a Connect entry point on the Cloud Upstream page. It calls POST /api/cloud-upstreams/connect/start to mint a pendingConnectionId and an authorizationUrl, then completes through POST /api/cloud-upstreams/connect/finish once the redirect lands.

Either way, you end with a stored connection that the next steps reuse.


3. Preview the push

A preview is a dry run. The CLI exports the local company through the portability service, builds a transfer manifest, and asks the cloud stack what would change. Nothing is written on the remote.

paperclipai cloud push \
  --company "$LOCAL_COMPANY_ID" \
  --dry-run

The output prints the run id, the manifest hash, and a one-line summary:

create=12 update=3 adopt=0 skip=1 conflict=0 staleMapping=0

Any warnings (from the local export or the remote) and the first ten conflicts print below the summary. If you want the full payload, add --json.

From the board, the same preview is available through POST /api/cloud-upstreams/{connectionId}/push-runs/preview. The response is a CloudUpstreamPreview that the Cloud Upstream board page renders into the per-entity-type counts, the warnings list (with severity warning or blocker), and the conflicts list (with plannedAction of create, update, skip, or blocked).

schemaCompatible: false on the preview means the cloud stack is on a different transfer schema major. Stop and upgrade one side — the CLI exits with code 3 in that case and a clear Cloud upstream schema mismatch message.


4. Resolve conflicts before applying

A conflict is the cloud stack saying "I already have something with this natural key, and I won't silently overwrite it." Each CloudUpstreamConflict carries:

  • entityType — which kind of thing collided.
  • sourceLabel / targetLabel — human-readable names for the local and remote rows.
  • plannedAction — what the importer would do if you let it through (create, update, skip, or blocked).
  • reason — the importer's rationale.

Decide per row whether to rename or remove the local entity, then re-run the preview. The dry-run is cheap; run it as many times as you need.

The CLI surfaces conflicts on stderr and exits with code 2 (a non-fatal hint) when at least one conflict or stale mapping is present. Scripts can branch on that exit code without parsing output.


5. Apply the run

Once the preview is clean — or you've accepted the conflicts the importer is allowed to handle — drop --dry-run:

paperclipai cloud push --company "$LOCAL_COMPANY_ID"

The CLI uploads chunked entity payloads (default 100 entities per chunk; tune with --max-entities-per-chunk), tells the remote to apply, and then fetches the trailing event log. The summary line and the last ten events print to stdout.

From the API, the equivalent is POST /api/cloud-upstreams/{connectionId}/push-runs with the local companyId. The response is a CloudUpstreamRun you can poll via GET /api/cloud-upstreams/{connectionId}/push-runs/{runId} until status flips from running to succeeded, failed, or cancelled. The activeStep field walks through connect, scan, preview, push, verify, activate so a board UI can show progress without inventing its own phases.

If you need to abandon a run mid-flight, POST /api/cloud-upstreams/{connectionId}/push-runs/{runId}/cancel marks it cancelled and tells the remote to stop. Retries reference the failed run via retryOfRunId on the create call.


6. Activate entities on the cloud side

A successful push lands everything in a paused state on the remote. Agents don't pick up issues, routines don't fire, monitors don't alert — the cloud stack waits for you to explicitly turn each entity type on.

Activate one type at a time:

curl -X POST \
  "$PAPERCLIP_API_URL/api/cloud-upstreams/$CONNECTION_ID/push-runs/$RUN_ID/activation" \
  -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "companyId": "'$LOCAL_COMPANY_ID'", "entityType": "agents" }'

entityType accepts agents, routines, or monitors — anything else returns a 400. The response is a CloudUpstreamActivationDecision with the count switched and an activatedAt timestamp.

The board's Cloud Upstream page exposes three buttons mapped to the same call. Activating agents first, then routines, then monitors is the safe default: agents are the executors, routines fire work, monitors only matter once there's work to watch.


Verify it landed

The connection's lastRunId points at the most recent run, so a single fetch tells you everything:

curl -sS "$PAPERCLIP_API_URL/api/cloud-upstreams?companyId=$LOCAL_COMPANY_ID" \
  -H "Authorization: Bearer $PAPERCLIP_API_KEY"

The CloudUpstreamsState response contains the connection list and the recent run list for that company. Spot-check that:

  • the connection's tokenStatus is connected (not expired or revoked),
  • the run's status is succeeded,
  • progressPercent is 100,
  • and summary matches the preview you accepted.

Follow targetUrl to land on the run inside the cloud stack and confirm the activation decisions stuck.


Common failures

Symptom What it means
Cloud sync is disabled. (CLI) or HTTP 404 Cloud sync is not enabled The enableCloudSync experimental flag is false. Flip it (step 1) and retry.
Remote URL is not a Paperclip Cloud upstream target. The remote did not serve a valid /.well-known/paperclip-upstream document with schema: "paperclip-upstream-discovery-v1".
Cloud upstream schema mismatch: local major X, remote supports Y. (CLI exit code 3) The two sides are on different transfer schema majors. Upgrade one.
Remote Paperclip Cloud stack does not advertise the cloud_sync transfer flag. The cloud stack is reachable but doesn't enable cloud sync. Ask the stack admin to advertise the cloud_sync feature flag.
CLI exit code 2 after cloud push At least one conflict or stale-mapping row needs human attention. Re-run with --dry-run to inspect, then either resolve locally or accept and re-apply.
No cloud connection found. The CLI couldn't match --remote-url (or the default current connection) in the local store. Re-run paperclipai cloud connect.

See also