reoclo run
reoclo run [options] -- <command...>Resolves every Secrets Manager value your credential can read, injects them into a child process as environment variables, and runs it. The credential is an automation key or a machine user token. Values are never written to disk and never printed. The child’s exit code is passed straight through, so reoclo run is transparent to whatever CI system is watching it.
This is how you consume managed secrets in any pipeline: GitHub Actions, Gitea Actions, GitLab CI, Woodpecker, or a local script.
REOCLO_AUTOMATION_KEY=rca_... reoclo run -- ./migrate.shREOCLO_MACHINE_TOKEN=rk_m_... reoclo run -- ./migrate.shEverything after -- is the command. Use -- even when it looks unnecessary. Without it, flags meant for your command are parsed as flags for reoclo.
Options
Section titled “Options”| Flag | Description |
|---|---|
-p, --project <name> | Only inject this project. Repeatable. Omit to inject every project the key can read. |
--env-file <path> | Render a template file of op:// references and inject the resolved values. Cannot combine with -p. See Template files. |
--commit <sha> | Record a commit SHA on the audit entry. |
Authentication
Section titled “Authentication”reoclo run requires one of two credentials: an automation key (rca_, read from REOCLO_AUTOMATION_KEY) or a machine user token (rk_m_, read from REOCLO_MACHINE_TOKEN). An interactive reoclo login session is still rejected: this command exists to hand values to machines, not people. See Machine Users for how the two credentials differ.
REOCLO_AUTOMATION_KEY=rca_... reoclo run -- ./migrate.shREOCLO_MACHINE_TOKEN=rk_m_... reoclo run -- ./migrate.shThe credential needs a read grant on each project you want injected. A tenant admin adds one from the project’s Access tab. See Granting access.
For an automation key, only the grant matters. A key restricted to no servers and no operations still resolves secrets normally. That makes a dedicated, otherwise-powerless key the right thing to put in CI.
A secret project restricted to specific servers cannot be read by reoclo run using a machine user token, whatever its own server scope. Use an automation key for that project.
Selecting projects
Section titled “Selecting projects”With no -p, every project the key is granted is injected. That is usually what you want, and it means adding a secret to a granted project requires no pipeline change.
Pass -p to narrow it. Repeat the flag for more than one:
reoclo run -p payments-production -- ./migrate.shreoclo run -p payments-production -p shared-infra -- ./deploy.shNaming a project the key cannot read is an error, and the command fails without running your child process. A project that exists but is not granted and a project that does not exist are reported identically, so a key cannot be used to probe which projects exist.
Template files
Section titled “Template files”--env-file injects the exact keys a template names, instead of every granted project. The template is a .env file whose values are op:// references:
# app.env.tplDATABASE_URL=op://payments-production/app/DATABASE_URLSTRIPE_API_KEY=op://payments-production/app/STRIPE_API_KEYEach reference is op://<project>/<item>/<field>. Reoclo maps it to the secret <field> in the project <project>. It ignores the <item> segment. That segment keeps the file compatible with 1Password’s op inject.
REOCLO_AUTOMATION_KEY=rca_... reoclo run --env-file app.env.tpl -- ./migrate.shREOCLO_MACHINE_TOKEN=rk_m_... reoclo run --env-file app.env.tpl -- ./migrate.shThe template names its own projects through the reference vaults. So --env-file cannot combine with -p. Passing both is exit code 2.
Only a whole value is a reference. An op:// in a comment, or in the middle of a value, stays as plain text. A value that is not a reference passes through unchanged, so one template can mix references and plain values.
Reoclo resolves the references, never 1Password. The op command does not need to be installed. This is different from secrets import, which reads your real 1Password items.
Precedence
Section titled “Precedence”A resolved value overrides an inherited environment variable of the same name. If your runner already exports DATABASE_URL and the granted project also defines DATABASE_URL, the child sees the managed one.
Audit trail
Section titled “Audit trail”Each run opens a short-lived resolve session (15 minutes) and records two audit entries: the session being opened, and the keys that were resolved. Only key names are recorded, never values.
On GitHub Actions and Gitea Actions, GITHUB_RUN_ID and GITHUB_SHA are picked up automatically, so runs are attributable to a workflow and a commit with no extra wiring. Elsewhere, pass --commit yourself:
reoclo run --commit "$CI_COMMIT_SHA" -- ./release.shFailure behavior
Section titled “Failure behavior”reoclo run fails closed. If resolution fails for any reason (no grant, a project you cannot read, an expired key), the child process does not run. It will never silently execute your command with the secrets missing.
Examples
Section titled “Examples”Run a migration with every granted secret injected:
REOCLO_AUTOMATION_KEY=rca_... reoclo run -- ./migrate.shREOCLO_MACHINE_TOKEN=rk_m_... reoclo run -- ./migrate.shLog in to a registry without the password ever reaching your shell history or the process table:
reoclo run -p shared-infra -- sh -c 'echo "$DOCKERHUB_PASSWORD" | docker login --password-stdin -u "$DOCKERHUB_USERNAME"'Check that a key is present without revealing it:
reoclo run -- sh -c '[ -n "$STRIPE_API_KEY" ] && echo present'Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
| 0 | Success (or the child exited 0) |
| 2 | Bad arguments: no command after --, a bad --env-file path, a malformed op:// reference, --env-file with -p, or a token in the wrong environment variable |
| 3 | Authentication failure: the credential is invalid, expired, or revoked |
| 4 | An interactive session (neither an automation key nor a machine user token) |
| 6 | Resolution failed: no grant, no readable project matched -p, or a template reference did not resolve. The child never started. |
| 7 | The control plane was unreachable: DNS failure, connection refused, or timeout |
| n | Anything else is the child’s own exit code, passed through |
Resolution failure is 6, deliberately not 1. Because run passes the child’s exit code through, a resolution failure sharing code 1 with “my migration script exited 1” would make the two indistinguishable, which is the one branch a pipeline most needs:
reoclo run -- ./migrate.shcase $? in 0) echo "migrated" ;; 6) echo "secrets did not resolve — check the key's grants" ;; 7) echo "control plane unreachable — safe to retry" ;; *) echo "migrate.sh itself failed" ;;esacThe ambiguity is not gone entirely, just moved somewhere it rarely bites: a child that itself exits 6 or 7 is still indistinguishable from Reoclo’s own. Only reoclo run writes to stderr, so that remains the tiebreaker.
Related
Section titled “Related”reoclo secrets: create and manage the values this command injects- Injecting secrets into CI: a full pipeline walkthrough
- CI/CD automation: automation keys and the wider CI surface