Skip to content

Pull & Push

cliq pipelines often need content that lives outside the project — data rooms in Google Drive, policy documents in SharePoint, market reports on the web — and need to deliver results back to those same systems when work is done. Pull and Push handle both directions declaratively, so you wire up external file access once in team.yml and every run just works.

The design mirrors Git terminology: pull fetches content inward, push sends content outward. And like Git, the working tree (your local workspace) is the only thing agents ever touch.

The local-file contract. Pull phases fetch external content into .cliq/pull/ before downstream phases run. Push phases deliver local files to external destinations. The agent never knows where files came from or where they’re going — it only sees local files. This keeps role prompts portable and integration-agnostic.

Both Pull and Push support $(inputs.varname) template variables for dynamic inputs, so URLs and file names can adapt to each run without changing team.yml.


Pull is a dedicated phase type (type: pull) that fetches external content into the local workspace. Declare pull phases in team.yml with a sources array. The orchestrator executes pull phases like any other phase in the DAG — downstream phases see local files by the time they start.

FieldTypeRequiredDefaultDescription
urlstringyesSource URL. Supports plain HTTP(S), Google Docs/Sheets/Drive, and SharePoint/OneDrive.
namestringyesSlug for the pulled content. Must be lowercase alphanumeric + hyphens. Determines the output path under .cliq/pull/.
format"auto" | "raw"no"auto"auto converts HTML to Markdown and extracts PDF text. raw stores the original binary unchanged.

cliq inspects the URL to determine the source type and applies the appropriate conversion:

URL patternSource typeauto outputraw output
Any HTTP(S) URLurl.md (HTML→Markdown)Original binary
*.pdfpdf.md (extracted text).pdf binary
docs.google.com/document/d/{id}google-doc.md (exported).txt (plain text)
docs.google.com/spreadsheets/d/{id}google-sheet.csv.csv
gdrive://{folder_id}google-drive-folderRecursive download preserving structureSame
*.sharepoint.com/... or sharepoint://...sharepointConverted if possibleRaw binary

All pulled files land under .cliq/pull/, named by the name slug:

.cliq/pull/
├── market-report.md # single file pull
├── data-room/ # folder pull (Google Drive)
│ ├── financials.csv
│ ├── contracts/
│ │ ├── msa.md
│ │ └── sow.md
│ └── deck.md
└── manifest.json # pull manifest

Single-file pulls produce .cliq/pull/{name}.ext. Folder pulls (e.g., gdrive://) produce .cliq/pull/{name}/ with the remote directory structure preserved.

Every pull run writes .cliq/pull/manifest.json — a record of what was fetched, when, and how large it was:

[
{
"name": "market-report",
"url": "https://example.com/market-report",
"type": "url",
"format": "auto",
"output": ".cliq/pull/market-report.md",
"size_bytes": 48210,
"pulled_at": "2026-03-28T10:15:00.000Z"
},
{
"name": "data-room",
"url": "gdrive://1a2b3c4d5e",
"type": "google-drive-folder",
"format": "raw",
"output": ".cliq/pull/data-room/",
"size_bytes": 2540000,
"pulled_at": "2026-03-28T10:15:03.000Z"
}
]

Pull URLs support template variables that are resolved at runtime:

VariableSourceExample
$(inputs.key)Team input value$(inputs.data_room_id)
$(req_key)Requirement keyPROJ-123
$(team_name)Team namedue-diligence
$(date)Current date (YYYY-MM-DD)2026-03-28
$(timestamp)Current date-time (YYYY-MM-DDTHH-MM-SS)2026-03-28T14-30-15

Variables use the same resolution pipeline as the rest of cliq — see Inputs and Template Variables below.

phases:
- name: fetch-research
type: pull
sources:
- url: "https://example.com/market-report"
name: market-report
- url: "gdrive://$(inputs.data_room_id)"
name: data-room
format: raw
- name: researcher
type: standard
depends_on: [fetch-research]

The researcher’s role file can then reference these files as local paths:

Review the market report at `.cliq/pull/market-report.md` and the data room
contents under `.cliq/pull/data-room/` to produce your analysis.

You can run a one-off pull outside a pipeline:

Terminal window
cliq tool run pull <url> --name <slug> [--format raw]

This is useful for testing URL access, debugging conversion, or ad-hoc file fetching.


Push is a dedicated phase type (type: push) that delivers local files to external destinations. Declare push phases in team.yml with a targets array. Push phases participate in the DAG and execute when their dependencies complete.

FieldTypeRequiredDefaultDescription
filestringyesLocal file path relative to project root (e.g. reports/report.md).
tostringyesDestination URI or URL. Accepts protocol URIs (gdrive://, gdoc://, sharepoint://) and standard web URLs (https://drive.google.com/..., https://docs.google.com/..., https://*.sharepoint.com/...). Supports template variables.
mode"create" | "append" | "replace"no"create"Create a new file, append to an existing document, or replace its content.
namestringnoName for the created file. Required when mode: create. Supports template variables.
URI patternServiceSupported modes
gdrive://{folder_id}/Google Drivecreate
https://drive.google.com/.../folders/{id}Google Drivecreate
gdoc://{doc_id}Google Docsappend, replace
https://docs.google.com/document/d/{id}Google Docsappend, replace
sharepoint://{site}/{path}/SharePointcreate
https://{tenant}.sharepoint.com/...SharePointcreate, append, replace
sharepoint://{site}/{path}/{file}SharePointappend, replace

The trailing slash convention distinguishes containers from documents:

  • create requires a trailing / — the URI points to a container (folder), and a new file is created inside it. The name field is required.
  • append and replace require no trailing / — the URI points to an existing document, and its content is modified in place.

Place push phases after gate phases in the DAG using depends_on. This ensures deliverables are only published after quality checks pass:

- name: publish
type: push
depends_on: [quality-gate]
targets:
- file: reports/report.md
to: "gdrive://output-folder/"
mode: create
name: "$(team_name)-report-$(date)"
phases:
- name: reviewer
type: gate
depends_on: [developer]
commands:
- name: tests
run: npm test
max_iterations: 3
- name: publish-docs
type: push
depends_on: [reviewer]
targets:
- file: reports/final-report.md
to: "gdoc://abc123"
mode: replace
- name: publish-archive
type: push
depends_on: [reviewer]
targets:
- file: reports/final-report.md
to: "gdrive://output-folder/"
mode: create
name: "$(team_name)-report-$(timestamp)"

In this example:

  1. publish-docs is a push phase that replaces the content of Google Doc abc123 with the final report when that phase runs after the reviewer completes.
  2. publish-archive is a separate push phase that creates a new file in Google Drive with a templated name. Both push phases list depends_on: [reviewer] so they are sequenced after the gate in the DAG; adjust dependencies (for example, add intermediate phases) to control exactly when each destination receives files.

You can run a one-off push outside a pipeline:

Terminal window
cliq tool run push <file> --to <dest> --mode <mode> [--name <title>]

This is useful for testing destination access, debugging authentication, or manually delivering files.


Pull URLs and push names often need dynamic values — a Google Drive folder ID that changes per client, a company name for the output file, or today’s date. Team inputs provide these values, and template variables inject them into your declarations.

Declare expected inputs at the top level of team.yml:

name: "@local/due-diligence"
description: "Comprehensive due diligence analysis for M&A transactions"
inputs:
- name: data_room_id
description: "Google Drive folder ID containing the target data room"
- name: company_name
description: "Name of the target company"

Run cliq req with no arguments after assembling a team to see what inputs it needs:

Terminal window
cliq req

This prints a list of missing items and a copy-paste example command with <value> placeholders. You can also provide partial inputs to see what’s left:

Terminal window
cliq req requirements.md --input data_room_url=1a2b3c

Inputs are resolved from two sources, checked in order:

  1. CLI flags: --input data_room_url=1a2b3c4d5e --input company_name=Acme
  2. Interactive prompts: if a required input is still missing and the session is not headless, cliq req prompts for it

Inputs are not parsed from the requirement text. They must be explicitly provided via --input flags or interactive prompts.

Resolved inputs are saved to .cliq/inputs.json so subsequent cliq run commands (including re-runs) use the same values without re-prompting.

After resolving inputs, cliq req scans all pull/push template strings for $(inputs.*) references and verifies each one has a resolved value. If any variables are unresolved, the command fails with a clear error listing the missing --input flags needed. This catches misconfigured teams early — before any agent runs.

cliq run also performs a pre-flight check: if the team defines inputs, it verifies that inputs.json exists and contains all required values. If inputs are missing (e.g., because you added new inputs to the team after a previous cliq req), it fails with instructions to re-run cliq req with the appropriate flags.

VariableResolves toAvailable in
$(inputs.key)Value of input named keyPull URLs, push destinations, push names
$(req_key)Requirement key (e.g., PROJ-123)Pull URLs, push destinations, push names
$(team_name)Current team namePull URLs, push destinations, push names
$(date)Current date in YYYY-MM-DD formatPull URLs, push destinations, push names
$(phase)Current phase namePush destinations, push names
$(timestamp)Current date-time as YYYY-MM-DDTHH-MM-SSPush destinations, push names
$(instance_id)Cliq instance ID (e.g., cliq-271d9c)Pull URLs, push destinations, push names
name: "@local/due-diligence"
description: "Due diligence pipeline with external data room access"
inputs:
- name: data_room_id
description: "Google Drive folder ID for the data room"
- name: company_name
description: "Target company name"
workflow:
phases:
- name: fetch-sources
type: pull
sources:
- url: "gdrive://$(inputs.data_room_id)"
name: data-room
- url: "https://sec.gov/cgi-bin/browse-edgar?company=$(inputs.company_name)&output=atom"
name: sec-filings
- name: researcher
type: standard
depends_on: [fetch-sources]

Running cliq req --input data_room_id=1a2b3c --input company_name=Acme resolves the URLs to gdrive://1a2b3c and the SEC EDGAR search for “Acme” before any agent starts.


Pull and push need credentials to access external services. Configure them in the integrations block of settings.json — see the Integrations page for step-by-step setup for each provider:

Verify connectivity with cliq doctor test google, cliq doctor test microsoft, or cliq doctor test all.


External file access introduces a surface area for accidental data leaks and unauthorized writes. cliq enforces multiple layers of protection.

All pulled files land exclusively under .cliq/pull/. The pull system rejects any name that would resolve outside this directory. Agents cannot use pull to overwrite role files, settings, or other project files.

Before uploading, the push system checks the file path against a hardcoded deny list. Matching files are blocked with a clear error:

PatternDescription
**/settings.jsonCliq settings
**/resolved_settings.jsonMerged settings
**/.env*Environment files
**/*.key, **/*.pem, **/*.secretKey and certificate files
**/.git/**Git internals

Before push, file contents are scanned for sensitive patterns:

  • API keys (e.g., sk-..., AKIA..., ghp_...)
  • Bearer tokens and authorization headers
  • Private keys (-----BEGIN RSA PRIVATE KEY-----)
  • Connection strings with embedded credentials

If sensitive content is detected, the push is blocked and an error is logged with the matched pattern. Remove the secret from the file (or move it to an environment variable) and re-run.

The push.allowed_modes setting restricts which push modes teams can use at the global or project level:

{
"push": {
"allowed_modes": ["create", "append"]
}
}

Default: ["create", "append", "replace"] (all modes allowed). Removing "replace" from the list prevents any team from overwriting existing documents — useful in regulated environments.

  • Absolute paths in file fields are rejected.
  • Path traversal (../) is rejected.
  • Symlinks are resolved and validated against the project root.

In Docker mode, credentials are injected via environment variables — not mounted files. The container never has direct access to the host’s credential files. Token exchange happens inside the container using the injected values.


Pull and push emit notification events so you can track external file operations in Slack or other channels.

EventWhen it firesContext available
on_pullAfter each pull completes (success or failure), before the phase activatesname, url, type, status, error
on_pushAfter each push completes (success or failure), after the phase completesfile, to, mode, status, error

Add the events to your notifications block in settings.json:

{
"notifications": {
"on_pull": { "channels": ["slack"] },
"on_push": { "channels": ["slack"] }
}
}

on_pull (success):

:inbox_tray: Pull succeeded: market-report Source: https://example.com/market-report Output: .cliq/pull/market-report.md (47 KB)

on_pull (failure):

:warning: Pull failed: data-room Source: gdrive://1a2b3c4d5e Error: Google integration not configured

on_push (success):

:outbox_tray: Push succeeded: reports/final-report.md Destination: gdoc://abc123 Mode: replace

on_push (failure):

:warning: Push failed: reports/final-report.md Destination: gdrive://output-folder/ Error: Push blocked: sensitive content detected


Here is a full team.yml for a due diligence pipeline that uses a pull phase for the Google Drive data room and public financial report, runs three analysis phases, gates the report, then uses separate push phases to publish to Google Docs and archive to Drive.

name: "@local/due-diligence"
description: >
Comprehensive due diligence pipeline. Pulls external data room contents
and public financial data, runs multi-phase analysis, and delivers
the final report to Google Docs.
version: "1.0.0"
cliq_version: ">=1.0.0"
tags: [research, finance, due-diligence]
inputs:
- name: data_room_id
description: "Google Drive folder ID containing the target data room"
- name: company_name
description: "Name of the target company"
- name: report_doc_id
description: "Google Doc ID for publishing the final report"
use_when:
- Evaluating a company for investment or acquisition
- Performing regulatory compliance review
not_for:
- Real-time market trading decisions
- Personal tax preparation
workflow:
phases:
- name: fetch-data
type: pull
sources:
- url: "gdrive://$(inputs.data_room_id)"
name: data-room
- url: "https://finance.example.com/reports/$(inputs.company_name)/annual"
name: financial-report
- name: researcher
type: standard
depends_on: [fetch-data]
- name: analyst
type: standard
depends_on: [researcher]
- name: writer
type: standard
depends_on: [analyst]
- name: reviewer
type: gate
depends_on: [writer]
commands:
- name: report-exists
run: "test -f reports/final-report.md"
- name: word-count
run: "test $(wc -w < reports/final-report.md) -ge 2000"
max_iterations: 3
- name: publish-report
type: push
depends_on: [reviewer]
targets:
- file: reports/final-report.md
to: "gdoc://$(inputs.report_doc_id)"
mode: replace
- name: archive-report
type: push
depends_on: [reviewer]
targets:
- file: reports/final-report.md
to: "gdrive://$(inputs.data_room_id)/"
mode: create
name: "$(inputs.company_name)-due-diligence-$(date)"

Run it:

Terminal window
cliq req -m "Perform due diligence on Acme Corp" \
--input data_room_id=1a2b3c4d5e \
--input company_name=Acme \
--input report_doc_id=abc123
cliq run

What happens:

  1. cliq req resolves inputs and validates template variables. During cliq run, the fetch-data pull phase runs first in the DAG and pulls the Google Drive data room into .cliq/pull/data-room/ and the financial report into .cliq/pull/financial-report.md before downstream phases start.
  2. The researcher reads the pulled files and produces research notes.
  3. The analyst synthesizes findings into structured analysis.
  4. The writer drafts the final report at reports/final-report.md.
  5. The reviewer gate checks the report exists and meets the word count minimum.
  6. After the reviewer completes, the publish-report push phase replaces the target Google Doc with the final report.
  7. The archive-report push phase creates a dated copy in the data room’s Google Drive folder.

ErrorCauseFix
Pull name invalidName contains uppercase or special charactersUse lowercase alphanumeric + hyphens only (e.g., market-report)
Google integration not configuredMissing credentialsSet integrations.google.credentials_file (service account) or auth_mode: "oauth" + cliq auth google (OAuth) in settings.json
Microsoft integration not configuredMissing Azure AD credentialsSet integrations.microsoft.tenant_id, client_id, and client_secret
Push blocked: sensitive content detectedContent scanner found API keys or secretsRemove secrets from the file before pushing
Push file not foundLocal file does not exist at the specified pathVerify the file path is correct and the phase produced the expected output
Push blocked by deny listFile matches a blocked pattern (e.g., .env, *.key)Use a different file path that doesn’t match the deny list
Mode 'replace' not permittedpush.allowed_modes restricts this modeUpdate push.allowed_modes in settings.json to include "replace"
HTTP 401/403 on pullAuthentication failed for the source URLCheck credentials in integrations for Google or Microsoft URLs
Pull boundary violationPull name resolves outside .cliq/pull/Use a simple slug without path separators or traversal
Destination URI invalidMalformed to fieldCheck the URI format — create needs a trailing /, append/replace must not have one