Pull a tree
celigo pull downloads the account, or one integration with --integration <id>, as a local tree. Re-pulls are incremental: unchanged files are untouched, a server-side rename becomes a folder move, and a locally edited file is never overwritten without --force.
Required: read mode is enough. A pull writes nothing to the account.
Signature
celigo pull [refs...] [flags]Arguments
[refs...]
file path, type:id, or bare id
No
Only meaningful with --force: reset just these resources to the server copy. Refs without --force are an error.
Flags
--dir <path>
string
.
Tree root directory.
--integration <id>
string
—
Scope the tree to one integration and everything it references. Recorded in the manifest: later pulls stay scoped without repeating the flag.
--with-dependents
boolean
false
Also pull what references the scoped integration — an MCP server publishing its tool, a flow chaining into it. One lookup per owned resource. Needs an integration scope.
--types <csv>
string
all
Only these resource types, for example flows,exports,imports. In a scoped tree the reference walk still sees the whole graph; --types filters what is written.
--prune
boolean
false
Delete the local files of resources that no longer exist on the server.
--force
boolean
false
Overwrite locally modified files with the server copy — every file, or only the refs named on the command line.
--symlinks
boolean
first pull
Write links as real symlinks named like their target.
--no-symlinks
boolean
—
Write links as .link.json pointer files. Recommended for trees shared through git.
--storage-files
boolean
false
Also download each Celigo Storage file's content beside its metadata (may be large or binary).
--neutral
boolean
false
Pull an environment-neutral tree. First pull only; the mode is recorded and permanent. See Neutral trees.
--untrack-orphans
boolean
false
Stop tracking resources a scoped tree's integration no longer references but which still exist on the server.
--allow-account-mismatch
boolean
false
Pull into a tree bound to a different account (host or token owner) anyway.
--concurrency <n>
integer
8
Requests in flight at once (1–16). CELIGO_CONCURRENCY sets the default.
--force-lock
boolean
false
Take the tree lock even if another pull or push appears to hold it.
Example
What a re-pull does
Every document is decided before any is written. A pull:
leaves unchanged files untouched, so a no-op pull leaves a committed tree byte-identical, manifest included;
moves the folder of a resource renamed on the server (two resources that swapped names move in one pull);
reports resources deleted on the server —
deleted on server: <key> (pass --prune to remove locally)— and removes their files only with--prune, naming each:pruned: <key> (deleted on the server; local files removed);keeps locally edited files and names them:
kept local edits: <path>. A dirty file whose content is structurally identical to the server copy is refreshed (its hash and lock token), not kept.--forcetakes the server copy — of every file, or of the refs you name;strips volatile fields (
lastModified, debug timers, sizes) so the files only change when the configuration did.
A file already sitting at a planned path that the tree does not track — a draft authored for push, a leftover of an interrupted pull — is never overwritten by a same-named server document unless the two are identical in substance; otherwise the pull leaves it alone with a warning, and --force overrides.
Pull one integration
--integration <id> scopes the tree to one integration, everything it owns (flows, tools, APIs, MCP servers, its storage root, its registered lookup caches), and everything its resources reference, followed transitively. Placement does not change with scope: a resource sits at the same path whether you pulled one integration or the whole account, which keeps git diffs and promote stable.
References cross integration boundaries, so the closure follows them out. Resources another integration owns that came along because the scope references them are named per owner:
Those resources are recorded as dependencies in the manifest, and push refuses to write them without --allow-dependencies.
The scope is remembered. Every later pull stays narrowed to the integration without repeating the flag, and --types then filters what is written while the reference walk still sees the whole graph. A scope integration that no longer exists on the account is a hard error.
Once a scoped tree tracks a resource, it keeps tracking it — refreshed on every pull — until the server deletes it or you untrack it. A tracked resource the integration merely stopped referencing is an orphan of the scope, kept and reported once:
pull --prune removes only what the server deleted; pull --untrack-orphans removes the orphans' files and manifest entries. The two compose.
Scripts are fetched closure-first. A script's own references live in its source, so a scoped pull hydrates only the scripts its closure reaches, reads the references in their source, extends the closure, and repeats until nothing new appears. A hook that reads another export by URL brings that export in; a script nothing in the integration uses is never requested.
--with-dependents adds the other direction — what references the scope — through GET /v1/<type>/<id>/dependencies on the integration and the resources it owns. It costs one request per owned resource, which is why it is opt-in; a lookup that fails is a warning, not a failed pull.
Links: symlinks or pointer files
Links are real symlinks by default. --no-symlinks writes .link.json pointer files instead, one per referenced resource; use it for trees shared through git across platforms, or on Windows without Developer Mode (where symlink creation fails, warns once, and falls back automatically).
The choice is sticky. The first pull records the style in the manifest, later flagless pulls honor it, and an explicit conflicting flag is an error. Pass the flag together with --force to converge the whole tree to the other style; the report's link counts show the change. Pointer form carries one record per referenced resource, so a referenced script gets a single pointer instead of the .js + .json pair — which is why the link counts differ between the two styles.
Celigo Storage
storage/ mirrors the service's hierarchy: a folder is a directory, a file is a <name>.json metadata stub. --storage-files downloads the contents instead, under the item's real name (storage/docs/report.csv), hash-tracked so status and diff notice tampering, and re-downloaded only when the item changed. A pull without the flag leaves existing content files exactly as they are.
Contents may be large or binary. For a git-tracked tree either skip the flag or ignore the content while keeping the stubs:
The middle line re-includes the folders, without which git never looks inside them for the stubs.
A root storage folder whose metadata carries an integration's _integrationId nests under integrations/<Int>/storage/<Folder>/…; loose root files and everything else stay in the account-wide storage/. Storage is pull-only: push refuses storage items, and the celigo storage commands are the write path. Accounts without the Storage entitlement report the type as skipped, not failed.
What a pull warns about
Dangling references. A reference to a resource that does not exist on the account produces no link, and the pull says so. It stays quiet where absence is normal: types a
--typesnarrowing did not fetch, iClient targets (a stock connector's OAuth app is Celigo's), and non-id template tokens.Hardcoded ids. A
settingsobject or a script body has no schema, so the pull scans them for 24-hex strings that resolve to a resource on this account and reports them ashardcodedRefs— one summary line in text output, full detail (holder, pointer, target) under--format json. Promote rewrites those ids; a standard push does not.Integration App documents, once per app:
note: 154 resource(s) belong to Integration App 'Shopify - NetSuite' (…) — read-only in this tree; edits are withheld from push.A rename onto a kept file. When the server renamed a resource onto the path of a file this pull kept (your local edits), the renamed resource stays at its old path and the warning names both. Resolve the kept file — push it, or
pull --force <path>— and pull again.Unentitled types (Storage, B2B) are reported as skipped.
Account binding
A pull into an existing tree checks the account first: the manifest's API host offline, then the token owner with one GET /v1/tokenInfo, before the first listing. A token for another account is refused before that account is read at all. --allow-account-mismatch is the override. See Teams, git, and CI.
Concurrency and the tree lock
Per-resource requests — script hydration, cache data, datasets, --with-dependents lookups — run through a bounded pool: --concurrency <n> (1–16), else CELIGO_CONCURRENCY, else 8. Storage content downloads stay at three at a time. A 429 Too Many Requests is retried after the server's Retry-After.
pull and push hold .celigo/local/lock for the run, so a second pull or push in the same directory fails fast instead of recording the wrong baseline:
A lock whose process is gone on this machine, or older than six hours, is taken over with a note. --force-lock is for a run that died on another machine sharing the directory. status, diff, lint, resolve, and push --dry-run never lock.
Gotchas
Neutral pulls fetch the whole account even when scoped — the symbol table needs every path and binding name. Budget tens of seconds per pull on a large account.
Large accounts. An unscoped
--no-symlinkstree of 13,000 resources is about 46,000 files, 20,000 of them link pointers. Expect about 90 s for the first pull and 40 s for re-pulls, rungit repack -a -dafter the first commit, and use a scoped tree when you can.Refs need
--force.celigo pull <path>alone is an error; the refs grammar exists to reset named resources.Symlinks are the one kind of link a tree holds. A symlinked content directory or document is refused on every manifest load (
<path> is a symbolic link — the tree must not contain symlinks …), because git tracks symlinks and a committed one could point outside the tree.
Related
Status and diff — what changed locally, and against the account.
Push changes — write the edits back.
Neutral trees —
pull --neutral.Teams, git, and CI — the repository layout and what to commit.
Last updated
Was this helpful?