Tray Sync CLI
CLI tool to clone Tray projects and related assets to a local directory, and promote them between Tray environments
CLI tool to clone tray projects and related assets on local machine which then can be used with version control system or promoted to different tray environment
Requirements
- Node.js >= 22
Install
npm install -g @trayai/tray-sync-cli
CLI Commands
| Command | Description |
|---|---|
tray init -r <region> -w <workspace-id> | Scaffold a new tray-sync-cli repository |
tray pull | Export tracked projects from Tray and materialise them on disk |
tray promote <env> | Reconstruct local projects and import them into a target Tray environment |
tray status | Local checksum-based drift detection (zero API calls) |
tray project remove <project-id> | Untrack a project and delete its local directory (project scope only) |
tray project list | List managed projects with directory names and last-pulled timestamps |
tray env add <name> | Add a target environment |
tray env list | List source and target environments with connectivity status |
tray env remove <name> | Remove a target environment and its per-project mappings |
tray env discover [env] | List an env's projects (id + name, default) and/or matching authentications — env defaults to source |
tray env resolve <env-name> | Report unresolved auth requirements for a target env, with candidate matches |
tray auth set -w <workspace-id> -r <region> -t <token> | Set (or overwrite) a workspace's token |
tray auth remove -w <workspace-id> | Remove a workspace's stored token |
tray auth list | List workspaces with stored credentials |
tray --version | Print the installed CLI version |
tray --help | Show help for the CLI or a specific command |
Getting started: a first promotion, end to end
This is a concrete, step-by-step walkthrough of the most common workflow: pull a project from a source workspace, and promote it to a target workspace. It uses a two-org example (DEV_ORG → PROD_ORG) since that's the realistic setup for most customer pipelines, but everything here works identically for two workspaces within the same org.
1. Pick a source and a target environment
Decide which workspace you're pulling from (the source) and which one you're promoting to (the target). For this guide:
- Source:
DEV_ORG - Target:
PROD_ORG
You'll need each workspace's ID and region, and a Tray API token with access to it.
2. Create a local directory for this project
mkdir -p ~/tcli-projects/my-first-tcli-project
cd ~/tcli-projects/my-first-tcli-project
Everything the CLI manages — tray.yaml, environments.json, and every pulled project — lives under this directory.
3. Initialize the repository against your source workspace
tray init -r <region> -w <your-SOURCE-workspace-id> -t <your-token> -p <project-id-to-pull>
Example:
tray init -r us1 -w 11111111-1111-1111-1111-111111111111 -t <token> -p <project_id>
Don't know the project ID yet? Run init without -p (an empty scaffold is fine), then:
tray env discover
lists every project in your source workspace — id + name — so you don't have to dig it out of Tray's UI.
A few notes on the flags:
-p <project-id>pulls that project immediately after scaffolding. Omit it andinitjust scaffolds an empty repository — you can pull specific projects later withtray pull -p <project_id>, which tracks and pulls it in one step.-s workspace(i.e.tray init -s workspace -r <region> -w <id> -t <token>, omitting-p) switches to workspace scope: every project in the workspace is pulled automatically, andtray pullkeeps that mirror in sync going forward (including removing projects deleted from Tray).-pis ignored in this scope.-t <token>is optional atinittime. If you skip it (or need to replace it later — tokens expire), set or refresh it any time with:tray auth set -w <workspace-id> -r <region> -t <token>tray auth setalways overwrites whatever token was stored for that workspace — no separate "force" flag needed.
At this point you have a local mirror of your source project(s), configured against DEV_ORG.
4. Add your target environment
Now register where you want to promote to:
tray env add <env-name> -r <region> -w <target-workspace-id> -t <target-token>
Example:
tray env add PROD_ORG -r us1 -w 22222222-2222-2222-2222-222222222222 -t <prod-token>
You can add more than one target environment this way (e.g. STAGING_ORG, PROD_ORG) — each gets its own entry in environments.json.
Same as init, providing -t here stores the token in ~/.tray/credentials.json immediately. You can always set or refresh it independently with tray auth set -w <target-workspace-id> -r <region> -t <token>.
5. Promote
You're ready to import your local projects into the target environment. A few common invocations:
# Recommended first: see what would happen without changing anything.
tray promote --to PROD_ORG --dry-run
# Promote a single project.
tray promote --to PROD_ORG -p <project-id>
# Promote multiple specific projects.
tray promote --to PROD_ORG -p <project-id-1> <project-id-2>
# Promote every project tracked in this directory (see them with `tray project list`).
tray promote --to PROD_ORG
Important: every project needs a target_project_id per environment
target_project_id per environmentThe first time you promote a given project to a given environment — or whenever the target project changes — you need to tell the CLI which project in the target workspace this should import into.
Each pulled project has its own mappings.json, at:
projects/<project-id>--<project-name>/mappings.json
You don't have to create this file by hand — tray pull / tray init already scaffold it for you (with a placeholder entry showing the full shape) the first time a project is pulled. What you do need to do is edit the target environment's entry and fill in the real target_project_id:
{
"version": 1,
"environments": {
"PROD_ORG": {
"target_project_id": "<project-id>",
"authentications": {},
"config": {},
"connectors": [],
"services": []
}
}
}
target_project_id here is the ID of the project in PROD_ORG that this local project should be imported into.
Authentications
If any workflow in the project you're promoting uses an authentication, you'll also need to map it. Tray tracks this per authentication group — a logical "auth slot" a workflow step references — not the authentication ID itself. When tray promote finds one it doesn't recognize, it tells you and scaffolds a placeholder into mappings.json for you:
{
"version": 1,
"environments": {
"PROD_ORG": {
"target_project_id": "<project-id>",
"authentications": {
"<source_authentication_id>": "MISSING_TARGET_AUTHENTICATION"
},
"config": {},
"connectors": [],
"services": []
}
}
}
The key (<source_authentication_id>) is the source-side auth group ID — leave it as-is. Replace the placeholder value with the ID of the actual authentication in your target environment (PROD_ORG) that should serve that slot — you can find this in Tray's app, under that workspace's authentications. For example:
"authentications": {
"<source_authentication_id>": "<resolved_target_authentication_id>"
}
If you get it wrong
If a required field is missing or still holds a placeholder value, tray promote refuses the attempt and tells you exactly what's outstanding and where to fix it — it won't silently promote a project into the wrong target, or with an unresolved authentication.