helix ci init generates the CI pipeline that deploys your project, so a merge or a button press ships it instead of a laptop. It asks which CI service you use (GitHub Actions is the only option today) and how deploys should be triggered, writes the workflow file, and prints the one-time setup to do on GitHub. The workflow itself runs helix deploy --wait, so the job fails with the build errors when a deployment fails.
Generate the workflow
Run it from the project root, in a terminal:
helix ci init
You answer two questions. The first is the CI service. The second is how deploys should be triggered:
| Strategy | Files written | When it deploys |
|---|---|---|
| Manual production deploys (default) | deploy-production.yml | On demand only, from the Actions tab or gh workflow run deploy-production.yml |
| Deploy production on merge | deploy-production.yml | On every push to your default branch, and on demand |
| Staging on merge, production manually | deploy-staging.yml, deploy-production.yml | Staging on every push to your default branch; production on demand, behind an approval gate |
The files land in .github/workflows/. The command asks before overwriting one that already exists.
Without a terminal, for example when an agent runs it, pass the answers as flags:
helix ci init --provider github --strategy manual-production
The strategy ids are manual-production, production-on-merge, and staging-on-merge. Add --force to overwrite existing files without asking.
What the command checks first
The command reads your project before it writes anything, and stops with the fix when a target isn’t ready:
- A config file per target. The production target uses
helix.production.config.tswhen it exists, otherwisehelix.config.ts. The staging strategy needs bothhelix.staging.config.tsandhelix.production.config.ts, so a merge never deploys your development target by accident. See one config file per target. - A provisioned project. Every target the workflow deploys must already have a
projectIdandworkspaceIdin its config file. A first deploy writes the project ID it provisions back into the file, and a CI runner throws that write away, so an unprovisioned target would create a new project on every run. Deploy the target once from your machine, or set the ids withhelix project setandhelix workspace set, then runhelix ci initagain. - A lockfile.
helix deployneedspackage-lock.jsonorpnpm-lock.yaml; the workflow installs with the matching package manager.
The workflow pins @trayai/helix-cli to your project’s @trayai/helix-sdk version. The two are released together, and a CLI ahead of the SDK breaks deploys, so bump both at once.
Create the token
The workflow authenticates with a secret named TRAY_CLI_TOKEN: a Tray API user token for the workspace the target deploys to. Create one in Tray:
- Go to Account Settings, then Tokens, then Create API user. Organization admins can do this for any workspace; workspace admins can when an organization admin has allowed it.
- Name the API user, pick the workspace your target deploys to, and give it a workspace role.
- Name the token and set its expiry. Copy it when it’s shown: it isn’t shown again, and it’s deleted when it expires.
Tokens are scoped to one workspace. When staging and production are different workspaces, create one API user and token for each.
Check a token before saving it on GitHub:
TRAY_CLI_TOKEN=<token> helix whoami
When TRAY_CLI_TOKEN is set, every helix command uses it instead of a saved helix login session. Nothing is written to disk and the token is never refreshed. A rejected token is reported as such, rather than as an expired login.
Set up GitHub
For the single-workflow strategies, add TRAY_CLI_TOKEN as a repository secret (Settings, Secrets and variables, Actions). The recommended upgrade is a GitHub environment named Production with required reviewers, with the secret moved onto it and environment: Production added to the job, so every deploy waits for approval.
The staging strategy sets that up from the start: each job runs on its own environment, Staging or Production, and reads TRAY_CLI_TOKEN from that environment’s secrets. Add required reviewers on Production and a production deploy waits for one of them.
The exact steps are printed when helix ci init finishes, and repeated in a comment at the top of each generated file.
What the workflow does
Each generated workflow, in order:
- Checks out the repository.
- Sets up Node.js 24 and installs your dependencies from the lockfile.
- Installs
@trayai/helix-cliat the pinned version. - Runs
helix deploy --wait(with--config <target file>for a named target), withTRAY_CLI_TOKENsupplied from the secret.
--wait keeps polling after the upload until the platform finishes rolling out. The job passes once the deployment is ready, and fails with the build errors printed in the log when it isn’t. A deployment still rolling out after 10 minutes fails the job with a “still deploying” message; check it later with helix deployment get <id>.
One deploy runs at a time per target, and a running deploy is never cancelled by a newer one. Each job has a 20 minute limit and read-only repository permissions.
Add your own steps, such as tests, before the deploy step. The generated file marks where.
Use another CI service
The generator writes GitHub Actions workflows today. On any other service, the same two pieces make a deploy job:
npm install -g @trayai/helix-cli@<your @trayai/helix-sdk version>
helix deploy --config helix.production.config.ts --wait
Supply TRAY_CLI_TOKEN from your service’s secret store as an environment variable on that step. Everything in Create the token applies unchanged.