Skip to main content
GitHub Actions runners are Node-capable containers. You can run capy run in any workflow step that needs decrypted secrets - builds, tests, deploys, anything that reads process.env. Unlike a runtime platform, GitHub Actions is a CI vehicle: the two secrets live in your repo’s Actions secret store, and each workflow step wraps its command with capy run. capy deploy has a built-in connector that pushes those secrets for you over the gh CLI - no copy-paste.

Set it up with capy deploy

The connector uses the GitHub CLI you already have authenticated locally - Capy never sees a token. Make sure gh is installed and logged in first:
Then, from inside your repo:
  1. Pick GitHub Actions in the platform picker.
  2. Choose Push SECRETS_BLOB + PROJECT_KEY to GitHub secrets via gh.
  3. Pick a scope:
    • Repository secrets - every workflow and every environment can read them.
    • Environment secrets - scoped to one GitHub Actions environment (e.g. production). Pick an existing environment or create one on the spot.
  4. Capy mints a fresh deploy token, runs gh secret set for SECRETS_BLOB and PROJECT_KEY in the scope you chose, and prints the workflow patch to paste plus the deploy id (for revoking later).
The connector resolves the target repo from your current directory’s git remote (gh repo view), so run it from inside the checkout you’re deploying.
The Actions secrets are named SECRETS_BLOB and PROJECT_KEY - no CAPY_ prefix. If you set them up under different names in the past, update the env: block in your workflow to match, or re-run capy deploy to overwrite them.

Workflow

The connector prints a short patch to paste: an Install Capy CLI step pinned to the CLI version you have installed, plus your deploy step wrapped in capy run -- with a SECRETS_BLOB / PROJECT_KEY env: block. A complete workflow built around it looks like this:
Every step under the job’s env: block inherits SECRETS_BLOB and PROJECT_KEY, so you don’t have to repeat them per step.

Per-environment secrets

When you pick Environment secrets scope, the secrets land on one GitHub Actions environment. Your deploy job must pin to that environment for ${{ secrets.* }} to resolve - the connector reminds you of this in its output:
Each run of capy deploy snapshots the .env in your working directory, so two runs from the same checkout push the same values to both environments. To give production and staging different secrets, check out the matching secret branch first, then deploy:
Point each deploy job at the environment that matches its secret branch.

Non-interactive setup

Every connector prompt has a flag, so you can script the whole setup. You still need a signed-in Capy session on the machine that runs it - capy deploy opens a browser to sign in when it has no valid session - plus an authenticated gh:
capy deploy --help also lists --dry-run, --force, and --edit. Those belong to the adapter-based connectors (Cloudflare, Vercel, AWS SSM); the GitHub Actions connector ignores them, so --dry-run will not stop it from pushing real secrets.

Manual setup (without gh)

If you’d rather not use the connector - or gh isn’t available - choose the token path and set the secrets yourself:
Capy mints the token, then serves a temporary instructions page on 127.0.0.1 and opens it in your browser. Copy SECRETS_BLOB and PROJECT_KEY from there and press Ctrl+C to close it (it also shuts itself down after five minutes). If the local server can’t start, Capy falls back to printing both values in the terminal. Then add them under Settings → Secrets and variables → Actions, or:
The workflow is identical to the one above.

One decrypt per step

Each capy run invocation decrypts on its own: it parses SECRETS_BLOB, fetches its half of the key from the Capy service, and decrypts in memory. There is no cache between steps, so every step that needs secrets gets its own capy run. Nothing decrypted is written to disk, so you can’t decrypt once and hand the values to a later step through a file or an artifact. The one file capy run does write in deployed mode is .capy/next-env.js, and it carries no values - it maps each decrypted variable name to a process.env lookup so next build can inline them. It is only useful inside the same capy run process that produced it:

Pull requests from forks

By default, GitHub Actions doesn’t pass secrets to workflows triggered by PRs from forks - a security baseline. Forked-PR builds can’t decrypt with Capy. Usually fine: run CI without decrypted secrets, use mock values, or gate deploy jobs on github.event.pull_request.head.repo.full_name == github.repository.

Revocation

When the connector finishes it prints a shortened deploy id and the exact revoke command for it. The SECRETS_BLOB + PROJECT_KEY stored in GitHub are long-lived, so revoke the token server-side to cut them off:
Once revoked, the GitHub-stored blob is inert - new builds and cold starts can no longer decrypt. (Already-running processes that have reconstructed the key keep working until they recycle; see Deploying → Revocation.) The secrets stay in GitHub until you delete them; revoking just makes them useless.
Last modified on August 11, 2026