For the complete documentation index, see llms.txt. This page is also available as Markdown.

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

Argument
Type
Required
Description

[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

Flag
Type
Default
Description

--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. --force takes 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 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 --types narrowing did not fetch, iClient targets (a stock connector's OAuth app is Celigo's), and non-id template tokens.

  • Hardcoded ids. A settings object 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 as hardcodedRefs — 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-symlinks tree 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, run git repack -a -d after 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.

Last updated

Was this helpful?