DOC_INDEX
THEME
DOCS/Learn OrchStep/Ad-hoc Commands (orchstep do)

Ad-hoc Commands (orchstep do)

Run any shell command or script with your OrchStep vars and environment, without writing a task — inline, piped, as a script, or in an interactive REPL.

Ad-hoc Commands — orchstep do

Pointed at a folder of environment files, orchstep do is also known as OrchShell — dotenv++ for applications.

Sometimes you don't want to write a task — you just want to run one command, but with your project's variables and environment already filled in. That's orchstep do:

orchstep do 'echo "Building v{{ vars.version }} for {{ vars.env }}"' --env prod
# Building v1.2.3 for production

It renders {{ vars.X }} / {{ env.X }} against the same context a run would have — your orchstep.yml defaults, environment groups/environments (--env), dotenv, and --var/--vars-file — then executes the result. Output is bare passthrough and the command's exit code is propagated, so it drops cleanly into scripts and pipelines.

Think of it as the ad-hoc counterpart to orchstep run — like ansible -m shell -a next to ansible-playbook. (And it's the execute sibling of orchstep eval, which only renders a value.)

Four ways to give it a command

1. Inline argument

orchstep do 'kubectl set image deploy/app app={{ vars.image }}'

Quote the whole command so the shell hands it to OrchStep intact.

2. Stdin / pipe — run a whole script

cat deploy.sh | orchstep do --env prod

Anything you pipe in is rendered, then run. Great for one-off scripts you don't want to commit as tasks.

3. A script file (with arguments)

orchstep do --script ./deploy prod canary
#            ^path        ^$1  ^$2

Remaining arguments become the script's positional parameters ($1, $2, …).

4. Shebang — make any script context-aware

Put OrchStep on the shebang line and the whole script becomes a context-aware program:

#!/usr/bin/env -S orchstep do --script
echo "Deploying v{{ vars.version }}"
kubectl set image deploy/app app={{ vars.image }}
chmod +x deploy && ./deploy

The #! line is a shell comment, so it's ignored when the script runs. This turns executable runbooks into things that pull straight from your env config.

Preview without running: --render

See exactly what a command will expand to — a context-aware envsubst:

orchstep do --render --env prod 'flyctl deploy --image {{ vars.image }}'
# flyctl deploy --image registry/app:1.2.3

Switch environments

The same command against different environments is just --env:

orchstep do --env staging 'echo {{ vars.db_host }}'
orchstep do --env prod    'echo {{ vars.db_host }}'

Interactive REPL

Run orchstep do with no command in a terminal to drop into an interactive shell where your vars are already loaded:

$ orchstep do --env prod
orchstep do — interactive shell (vars/env from your OrchStep context). Ctrl-D to exit.
orchstep> echo deploying {{ vars.version }}
deploying 1.2.3
orchstep> cd services/api
orchstep> for s in web api; do echo "restart $s"; done
restart web
restart api
orchstep>

The REPL is statefulcd, export, and multi-line constructs persist across lines, exactly like consecutive lines of a single step's do: block. Your OrchStep vars stay constant for the session; the shell's own state (current directory, exports) carries over. Multi-line commands (for, if, heredocs) show a ...> continuation prompt until they're complete, just like bash.

The REPL uses OrchStep's built-in POSIX shell for its stateful session; one-shot modes use your configured shell (bash by default). POSIX-compatible commands behave the same either way.

No orchstep.yml? Still works

With no workflow file in the directory, orchstep do runs with your OS environment plus any --var you pass:

orchstep do --var name=World 'echo "hello {{ vars.name }} from $USER"'
# hello World from you

It also picks up ambient context from convention-based files in the directory: an environments/ directory (per-environment application vars, used with --env) and the dotenv: declared in an orchstep_config.yml. See OrchShell for that pattern. (A bare .env is not auto-loaded — dotenv must be declared, so an untrusted directory can't slip env vars into your commands.)

Use cases

One-off deploy against an environment

orchstep do --env prod 'helm upgrade app ./chart --set image.tag={{ vars.version }}'

Context-aware runbooks (shebang) — commit an executable script that reads from your env config; teammates run ./rotate-certs and it picks up the right hosts.

CI ad-hoc steps — render a command with the pipeline's vars without adding a task:

orchstep do -f ci.orchstep.yml 'docker push {{ vars.registry }}/app:{{ vars.version }}'

Interactive prod inspectionorchstep do --env prod gives you a shell where {{ vars.db_host }}, {{ vars.namespace }}, etc. are already correct.

Scripting & exit codes

orchstep do propagates the command's real exit code, so it composes:

orchstep do --env prod 'health-check {{ vars.url }}' || rollback

Best practices

  • Quote the command ('…') so your shell passes it to OrchStep unsplit.
  • Use --render first when a command is destructive — confirm the expansion.
  • For anything you run repeatedly or want reviewed, promote it to a task in orchstep.yml; do is for the ad-hoc and exploratory.
  • Secrets resolve into the environment (referenced as $X), not rendered into the command text — same model as a normal step.

See also