.md

Cloud sync & configuration

Connect your local workspace to a dcupl Console project, then keep the two in sync. The CLI tracks what changed on each side and transfers only the differences — pushes and pulls stay fast, predictable, and never silently clobber edits made on the other side.

Note

Do this first. Every files command needs a project ID and API key. Create a project in the dcupl Console and copy its CLI key (type CLI read/write, see API keys): status, push and pull reject every other key type. Then run dcupl config set once — see Configure credentials below. Without credentials, a command exits 1 with Missing projectId. Set it via `dcupl config set`, the DCUPL_PROJECT_ID env var, or a .env file. (or the same message for apiKey); a key the server refuses gives API key rejected (…). Check your key with `dcupl config set --api-key <key>` ….

How sync works

Sync is a 3-way diff: the CLI compares your local files, the server, and the last-synced baseline to decide what to push, pull, or flag as a conflict. Toggle the mode to see how deletions are handled.

Additive: only new and changed files transfer — nothing is ever deleted.

File Local Server Action
models/Product.dcupl.json modified unchanged Push
workflows/sync.workflow-v3.json added absent Push (new)
models/Order.dcupl.json unchanged modified Pull
data/products.csv modified modified Conflict — stops
data/legacy.csv deleted present Kept on server

The status → review → push loop

files status is read-only — it transfers nothing. Review the diff, then push.

zsh — cloud sync

see what differs between local and server — read-only: dcupl files status --json — output: { "success": true, "versionId": "draft", "hasBaseline": true, "uploads": ["models/Product.dcupl.json", "workflows/sync.workflow-v3.json"], "downloads": ["models/Order.dcupl.json"], "conflicts": [{ "path": "data/products.csv", "reason": "both changed" }], "wouldDeleteOnServerInStrictMode": ["data/legacy.csv"], "wouldDeleteLocallyInStrictMode": [], "unchanged": 0, "needsRepair": [] }

a conflict stops the push — resolve it by choosing a winner: dcupl files push --force --path data/products.csv — output: [1/1] ✓ upload data/products.csv Pushed to version: draft Scope: data/products.csv Uploaded (1) ✓ data/products.csv Force-resolved conflicts (1) ! data/products.csv — both changed Unchanged: 0

now push the rest: dcupl files push --json — output: { "success": true, "versionId": "draft", "uploaded": ["models/Product.dcupl.json", "workflows/sync.workflow-v3.json"], "deleted": [], "failed": [], "conflicts": [], "resolvedConflicts": [], "unchanged": 2, "unverified": [] }

Configure credentials

Run dcupl config set once per workspace. Interactive by default; it writes the project ID to dcupl.config.json (workspace config) and your API key to dcupl.secrets.json when that file exists (a dcupl init workspace has one), otherwise to .env as DCUPL_API_KEY, adding .env to .gitignore. Pass flags to skip the prompts for scripts and CI.

# interactive — prompts for project id + API key
dcupl config set

# non-interactive, for scripts and CI
dcupl config set --project-id my-project --api-key <api-key> --yes

# inspect resolved config (key redacted as ***last4)
dcupl config get
dcupl config get --show-secrets
Note

Credential precedence. The CLI resolves each value in this order: command flag, where the command has one (--api-key / --project-id for a remote source on dcupl validate, dcupl app create --load and dcupl app loaders add; the files commands have none) → environment variable (DCUPL_API_KEY, DCUPL_PROJECT_ID) → a workspace .env (real environment variables win over it) → the stored dcupl.secrets.json / dcupl.config.json. CI should inject the key via the env var or dcupl config set --api-key, never a committed file. consoleApiUrl has no environment variable — set it with dcupl config set --console-api-url <url>.

Watch out

Gitignore dcupl.secrets.json before your first commit — it holds your API key (the .gitignore of a new dcupl init folder already lists it and .env). dcupl config set adds .env to .gitignore itself when it writes the key there, and the CLI writes .dcupl/.gitignore (ignoring everything in .dcupl/) together with the sync state, so that state is never committed.

config set flags

Flag Purpose
--project-id <str>Console project identifier
--api-key <str>API key for the project
--console-api-url <str>Console API base URL (self-hosted only)
--yesNon-interactive; accept defaults and skip prompts

Config files

File Contents Commit?
dcupl.config.jsonWorkspace config (project id, baseFolder, paths, filesUpload include/exclude)Yes
dcupl.secrets.jsonAPI keyNo — gitignore
.envDCUPL_API_KEY (written by config set when there is no secrets file; loaded at startup)No — config set adds it to .gitignore
dcupl/dcupl.lc.jsonLoader config (models, sources)Yes
.dcupl/sync-state/Local sync ledgerNo — ignored by .dcupl/.gitignore, which the CLI writes

Single-file operations (read, write, delete, move, copy, create-folder) and version management (files versions list, copy, delete) are listed with every flag in the Cloud sync commands.

Resolving conflicts

When both sides changed the same file, sync reports the conflict and stops — there is no auto-merge. Choose a winner with --force: push --force keeps local and overwrites the server; pull --force takes the server and overwrites local.

# both sides edited data/products.csv
dcupl files status
# => Conflicts (1)
#      ! data/products.csv — both changed
# (a push now aborts with PUSH_CONFLICTS and exits 1)

# keep your local copy (overwrites the server)
dcupl files push --force --path data/products.csv

# OR take the server copy (overwrites local)
dcupl files pull --force --path data/products.csv

Version resolution

Most commands accept --version (or -v). The CLI resolves the target version in this order:

  1. 1The explicit --version flag, if passed
  2. 2The current HEAD recorded in your sync-state
  3. 3A fallback of draft

Only files pull sets HEAD: on the first pull, and when pull --version switches to another version (--dest leaves it alone). Push never moves it, so a workspace that has never pulled pushes to draft. A switch needs a clean workspace or --force; otherwise the pull aborts with PULL_DIRTY_SWITCH.

Watch out

Pushing to production is rejected. Push to another version, then promote it by copying it: dcupl files versions copy --from draft --to production (this replaces the contents of production).

What can be synced

status, push and pull only see files under the workspace's baseFolder (default dcupl/; paths are relative to it) that match filesUpload.include and not filesUpload.exclude in dcupl.config.json. dcupl init, and dcupl config set when it creates the file, set the include to **/*.json, **/*.csv and **/*.js; add patterns there to sync other allowed files. Run the commands from the workspace root (the folder that holds dcupl.config.json). In a folder without one, they sync dcupl/ with the include patterns **/*.json, **/*.csv and **/*.js and print a notice on stderr, so --json output stays one JSON value.

The dcupl CDN stores text files only. Sync accepts .csv, .json, .txt, .md and .js (scripts, operators, and transformers ship as .js). Any other extension is rejected before a request is sent, and a file whose bytes are not valid UTF-8 is rejected rather than uploaded with mangled content — that applies to files push and to files write --file alike. A rejected file does not stop the rest of the batch; the run exits non-zero.

Large files are handled for you. push uploads files of up to 500 MB each. A larger file fails with File '<path>' is … MB — larger than the 500 MB per-file upload limit. To fix it, split the file. Or leave it out of the push: add it to filesUpload.exclude in dcupl.config.json, or push only the paths you name with --path. On slow links, use --concurrency to lower the default of 4 parallel transfers.

Sync commands

Command What it does
dcupl files status [--version <id>] [--path <p>...]Show local vs. server differences. Read-only.
dcupl files push [--version <id>] [--path <p>...] [--strict] [--yes] [--force] [--concurrency <n>]Upload new and changed files
dcupl files pull [--version <id>] [--path <p>...] [--strict] [--yes] [--force] [--dest <path>] [--concurrency <n>]Download new and changed files (--dest: sandbox copy, no sync state change)
dcupl files list [--search <str>] [--tree]List server files, filtered or as a tree

Single-file operations (read, write, delete, move, copy, create-folder) and version management (files versions list, copy, delete) are listed with every flag in the Cloud sync commands.