CLI (plugsync-cli)
The plugsync command-line client manages connectors and plugins like code: pull a connector’s configuration to a local directory, edit it, diff it against a published version, validate it, preview a publish, push it back to the draft, and author plugins — all against the plugsync API, with no checkout of the plugsync repository required.
It ships as a standalone package on PyPI (plugsync-cli), on its own release cadence, independent of the backend release train (issue #957).
Install
pip install plugsync-cliRequires Python 3.12+. Verify with plugsync --version.
Working from a checkout of the plugsync repository instead (e.g. to test an unreleased CLI change)? pip install -e cli/ installs the local copy in editable mode.
Configure and authenticate
plugsync auth login -e you@example.com-
api_urldefaults tohttps://app.plugsync.com(the hosted platform) — nothing to configure for the common case. Point it elsewhere withplugsync config set api_url <url>(internal/dev-only:http://localhost:8013for a local backend). -
plugsync auth loginwith email/password saves the returned JWT asapi_keyin~/.plugsync/config.yaml; every subsequent command reuses it as aBearertoken. That JWT expires in 15 minutes — fine for an interactive session, wrong for scripts. -
For scripts and CI, use a long-lived org API key (
ps_org_..., created from Settings → API Keys in the dashboard, owner-only) instead:plugsync auth login --token ps_org_... -
PLUGSYNC_API_URL/PLUGSYNC_API_KEYenvironment variables override the config file on every command — the cleanest option for CI, no config file involved:export PLUGSYNC_API_KEY=ps_org_... plugsync pull my-connector
Org keys authenticate the config plane only: they do not work against the Event Ingestion API (/api/v1/events), which requires a per-connector ps_live_... key. See Getting started for the full key-type breakdown.
Connector-as-code workflow
plugsync pull <name> downloads a connector’s draft config into a local directory. The directory is the config v3 blob: plugsync.yaml carries every top-level key, and the two collections become one file per named item.
my-connector/
├── plugsync.yaml # version, settings, conflicts, pipelines
├── entities/
│ ├── contacts.yaml # one file per entity
│ └── orders.yaml
└── flows/
└── shop-orders.yaml # one file per event flow.plugsync.yaml is written alongside it, recording which connector the directory tracks and which draft version it was pulled from. Keep it: push uses it.
Edit the files, then round-trip:
plugsync diff my-connector # local files vs. the newest published version
plugsync validate my-connector # preflight the draft, non-zero exit on an error
plugsync preview my-connector # what a publish would change, plus findings
plugsync push my-connector # upload to the connector's draftpush writes to the connector’s draft and stops — same write side as the dashboard and the AI agent (draft → publish workflow). Publishing is a separate, explicit act: plugsync push --publish -m "Added phone", which runs preflight first and refuses to publish while any error stands.
push also guards the write with the draft version recorded at pull time: if someone edited the connector in the dashboard meanwhile, the push is rejected rather than overwriting their work. Re-pull and reapply, or push --force to overwrite deliberately.
Preflight findings are printed with their severity: error, warning or info, each counted in a summary line. Only validate treats an error as a failure (non-zero exit, for pipelines); preview reports and always exits 0.
History is available too: plugsync log <name> lists published versions, plugsync pull <name> --revision N pulls an old one (read-only history, not the draft), plugsync rollback <name> restores a previous version into the draft (again: restores, does not publish).
Command reference
| Command | Purpose |
|---|---|
plugsync auth login / logout | Authenticate (email/password JWT, or --token ps_org_... for a long-lived org API key) |
plugsync config set/get/show | Manage ~/.plugsync/config.yaml (api_url, api_key) |
plugsync pull <name> | Download a connector’s draft as a local directory (--revision N for a published version) |
plugsync push <name> | Upload a local connector directory to the draft (--publish to also publish, --force to overwrite a concurrent edit) |
plugsync diff <name> | Diff local files vs. a published version (--revision N, default newest) |
plugsync validate <name> | Preflight the draft; non-zero exit on an error (--push to validate local files) |
plugsync preview <name> | Preview a publish’s effects and its preflight findings |
plugsync log <name> | Show a connector’s published version history |
plugsync rollback <name> | Restore a previous revision into the draft |
plugsync plugin init/push/list/status/logs/metrics/invoke/promote/publish/rollback | Author and manage plugins |
Run plugsync --help or plugsync <command> --help for the full option list.
Plugins
The plugsync plugin command group is the authoring surface for the plugin runtime: scaffold with init, deploy with push, inspect with status/logs/metrics, test with invoke, and move through environments with promote/publish/rollback. The full walkthrough, including what happens server-side on every push, is the plugin dev loop.
Plugin endpoints require an org tier with plugin_system_enabled (Enterprise and above); otherwise they return 402 Payment Required. The connector-as-code commands above have no tier gate.
Compatibility and releases
The CLI declares the minimum API version it expects and checks it against GET /api/version at the start of any command that talks to the API, warning (never failing outright) if the API is older than expected. An API that answers but does not expose GET /api/version is reported the same way: it predates the version endpoint, so compatibility cannot be verified and the warning names the minimum version this CLI expects.
Releases are cut by tagging the plugsync repository with cli-vX.Y.Z; the version in the tag must match cli/pyproject.toml. Install a specific version with pip install plugsync-cli==X.Y.Z.