Using skret from a script or agent
Exit codes, non-interactive flags, and copy-paste recipes for running skret from CI, cron, or an AI agent.
Every skret command is non-interactive by default — the exceptions are skret delete and skret rollback without --confirm/--force (both prompt y/N) and --from-stdin at a real terminal (blocks until you send EOF, see below). Output streams are deliberate: stdout carries data (secret values, JSON, rendered templates), stderr carries status (“Set KEY”, warnings, progress). Every failure exits with a distinct, documented code you can branch on instead of parsing stderr text.
Exit codes
Section titled “Exit codes”skret returns a distinct exit code per failure class, defined in pkg/skret/errors.go:
| Code | Constant | Meaning |
|---|---|---|
| 0 | ExitSuccess | Operation completed successfully |
| 1 | ExitGenericError | Unclassified error |
| 2 | ExitConfigError | .skret.yaml missing or invalid |
| 3 | ExitProviderError | Backend provider call failed (e.g. AWS SSM) |
| 4 | ExitAuthError | Authentication failed |
| 5 | ExitNotFoundError | Secret does not exist |
| 6 | ExitConflictError | Key already exists (import --on-conflict=fail) |
| 7 | ExitNetworkError | Network/connectivity failure |
| 8 | ExitValidationError | Invalid input — bad flag combination, missing required value, experimental command not enabled |
| 9 | ExitDrift | skret diff --exit-code found a difference between the two sides |
| 10 | ExitLeakFound | skret scan found a managed secret value in a tracked (or --staged) file |
| 125 | ExitExecError | skret run -- could not exec the command (not found on $PATH, or exec failure) |
Two of these are the ones you’ll branch on most in automation:
skret scanexits 10 when a managed secret value shows up in a file — wire it into a pre-commit hook or a CI leak-guard step. It exits 0 when nothing is found.skret diff A B --exit-codeexits 9 when the two secret sets differ, the same non-zero-on-difference contract asgit diff --exit-code. Without--exit-code,diffalways exits 0 — it’s a report, not a gate, unless you ask it to be one.
See the Error Codes reference for the full table plus provider-specific error mappings and remediation per code.
Non-interactive checklist
Section titled “Non-interactive checklist”- Exact bytes out:
skret get KEY --plain. The defaultget(no--plain) appends one trailing newline for terminal readability;--plaingives you the value’s exact stored bytes with nothing added — use it whenever a script or agent needs the byte-exact value (skret get TOKEN --plain > token.bin). - Parseable dump:
skret env --format=json(alsoyaml,export, or thedotenvdefault) — all four formats round-trip byte-exact; pickjsonwhen a script needs to parse the whole environment. - Multi-line value in:
skret set KEY --from-stdin < file.pemorskret set KEY --from-file path. Both read the entire stream/file (not just the first line), so a PEM key or multi-line JSON blob survives with every embedded newline intact. - A value that starts with
-: pass--before the key, or it’s parsed as a flag:skret set -- KEY '-----BEGIN PRIVATE KEY-----...'. - Secrets are byte-exact everywhere except
run:get,env,template, andsync/importpreserve every byte, including NUL, CR, and embedded newlines.skret run/skret run --watchsanitize control bytes on the way into the child process’s environment, because an OS process environment can’t carry a NUL or embedded newline. Full detail: Value fidelity. - Multiple config namespaces from one process: the global
--config <path>flag loads a specific.skret.yamldirectly, bypassing directory discovery entirely — useful for a single cron container serving several projects, each declared in its own config file. If the file does not exist the command fails with a config error; it never silently falls back to discovery. See Configuration.
Recipes
Section titled “Recipes”Read one value
Section titled “Read one value”DB_URL=$(skret get DATABASE_URL --plain)Inject secrets into a command
Section titled “Inject secrets into a command”skret run -- ./serverEvery secret in the resolved environment is injected as a real process environment variable; skret forwards the child’s exit code (or exits 125 if the command itself can’t be found/exec’d).
Dump everything for a script to parse
Section titled “Dump everything for a script to parse”skret env --format=json | jq -r '.DATABASE_URL'Sync to CI/CD targets
Section titled “Sync to CI/CD targets”skret sync --to=github,cloudflaregithub needs GITHUB_TOKEN in the environment. cloudflare has no flags-only path — it must be declared under sync.targets in .skret.yaml (worker or pages) and needs CLOUDFLARE_API_TOKEN. Preview first with no writes: skret sync --to=github --dry-run prints the exact secret names it would push and exits without writing anything, saving sync state, or touching a dotenv file. Add --no-overwrite to only fill keys absent at the target (existing values are never overwritten) — the safer default for an agent driving sync unattended. See Sync.
Leak-guard in a pre-commit hook
Section titled “Leak-guard in a pre-commit hook”skret scan --staged || { echo "a managed secret would be committed" >&2; exit 1; }Exits 10 on a match, 0 when clean. --staged scans only staged content (git diff --cached), which is what a commit hook wants. See Scan.
Migrate an existing .env in
Section titled “Migrate an existing .env in”skret import --from=dotenv --file=.env --on-conflict=skip--on-conflict defaults to skip (silently skip keys that already exist); pass --on-conflict=fail to exit 6 (ExitConflictError) instead the first time a key collides, or --on-conflict=overwrite to replace it.
Gotchas
Section titled “Gotchas”-
Leading-dash values.
skret set KEY -----BEGIN...fails — skret’s flag parser reads-----BEGIN...as a flag, not a value. Useskret set -- KEY value, or avoid the problem entirely with--from-stdin/--from-file. -
--from-stdinat an interactive terminal blocks until EOF. It reads the whole stream, not one line, so with no pipe or redirect it will hang waiting for input — type the value, then send EOF yourself: Ctrl-D on macOS/Linux, Ctrl-Z then Enter on Windows. In a script, always pipe or redirect:... --from-stdin < fileorecho -n "$VALUE" | skret set KEY --from-stdin. -
Trailing newlines are stripped; embedded ones are not.
--from-stdinand--from-fileremove only a trailing run of\nbytes (so a value saved by a text editor round-trips without gaining an extra newline). A trailing\r, or any newline in the middle of the value, is left untouched. See Value fidelity for the exact byte-level rules. -
skret historyandskret rollbackare experimental and gated. Both requireSKRET_EXPERIMENTAL=1in the environment; without it they exit 8 (ExitValidationError) with an explanatory message instead of running:Terminal window SKRET_EXPERIMENTAL=1 skret history DATABASE_URLSKRET_EXPERIMENTAL=1 skret rollback DATABASE_URL 3 --confirm