CLI Reference
Every orchstep command, its flags, and a verified example for each.
OrchStep is a single binary. Everything runs through one command:
orchstep [command] [flags]Run orchstep [command] --help at any time for the authoritative, version-matched
help. This page is the same surface, with a runnable example and real output for
each command.
Command overview
| Command | What it does |
|---|---|
run | Execute a task from a workflow |
list-tasks | Print the callable (non-internal) task names |
menu | Interactive task picker (TUI) |
serve | Local web dashboard (run tasks, live logs, history) |
eval | Evaluate a template/JS expression against the variable context |
validate | Statically check that a task's {{ vars.X }} resolve under each environment |
lint | Check a workflow for anti-patterns |
init | Scaffold a starter orchstep.yml |
module | Manage modules (resolve, lock, verify, cache) |
context | Inspect captured execution data |
version | Show the installed version |
Global flags
These apply to every command:
| Flag | Description |
|---|---|
--log-level <level> | silent, error, warn, info, debug, trace |
-v, --verbose | Verbose output |
--config <file> | Config file (default orchstep_config.yml) |
-h, --help | Help for the command |
run
Execute a task. With no task name, the main task runs (or your top-level
steps:). With no --file, OrchStep uses orchstep.yml in the current directory.
orchstep run [task] [flags]| Flag | Description |
|---|---|
-f, --file <file> | Workflow file to execute (default orchstep.yml) |
--env <name> | Environment to use (dev, staging, production, ...) |
--var key=value | Set a runtime variable (repeatable) |
--vars-file <file> | Load variables from a YAML file |
--dry-run | Show what would execute without running anything |
--open | With --dry-run: write the visual plan and open it in the browser |
--output <fmt> | pretty, plain, json (auto-detects TTY). With --dry-run: text, json, html |
--json-file <file> | Also write the structured run result (JSON) to this file |
--stdin-var <name> | Inject piped stdin as a named variable |
--ignore-version-check | Run even if the workflow requires a different engine version |
--break-before <step> | Pause before the named step and open the inspector (repeatable). See Interactive breakpoints |
Examples:
orchstep run # run "main" from orchstep.yml
orchstep run deploy # run the "deploy" task
orchstep run -f release.yml publish # a different workflow file
orchstep run deploy --env production --var replicas=10
orchstep run deploy --env staging --vars-file overrides.yml
orchstep run report --output json --json-file result.json
echo '{"env":"prod"}' | orchstep run deploy # pipe JSON onto stdin
curl -s api/health | orchstep run check --stdin-var respRunning a task prints each step, its command, and a status marker:
Workflow: my-service
Task: build
Step: compile
$ echo "go build -o bin/my-service ./cmd/..."
go build -o bin/my-service ./cmd/...
[ok] compile
Result: successExit codes:
0success,1runtime failure (also bad flags),2usage error (no subcommand in a non-TTY pipeline),3load/validation error,4failedassert. See Output & Exit Codes for the full table and the--output jsonshape.
Interactive breakpoints
Stop mid-run to inspect live state — the gap eval --explain (before a run) and
context inspect (after) don't cover.

Two ways to set one:
--break-before <step>(repeatable) — ad-hoc, no file edit. A bare name matches any step so named; atask.stepname targets one task's step (handy when two tasks share a step name):orchstep run deploy --break-before ship # any step named "ship" orchstep run deploy --break-before deploy.ship # only deploy's "ship"- the
breakpointflag on a step — a declarative marker in the workflow:- name: ship func: shell flags: [breakpoint] # pause right before this step runs do: "deploy {{ steps.build.image }}"
Either one pauses right before that step runs, after the step's own
vars: / env: / dotenv: are applied, and opens a read-only inspector:
⏸ BREAKPOINT before step 'ship'
[c]ontinue [a]bort [v]ars [e]nv [o]utputs [h]elp | or type an expression to evaluate
break> o # outputs of steps run so far
break> vars.region # evaluate against live state
break> c # resume (a = abort)The inspector is read-only (it never changes state, preserving capture/replay
determinism) and secret values are masked. It is a no-op in a non-TTY context
(CI, pipelines), during --dry-run, or when ORCHSTEP_SKIP_BREAKPOINT is set — so
breakpoints never hang an unattended run.
breakpoint is a step flag alongside the logging flags (log_result,
log_outputs, log_context) — see Step Flags.
Preview without running: --dry-run
--dry-run resolves variables, conditions, task calls and modules, then prints the
plan - nothing executes:
orchstep run --dry-runDRY RUN workflow=my-service task=main
Build, test, and deploy my-service
STEPS
1. build_stage [task call] executes
calls: build
1. compile [shell] executes
| echo "go build -o bin/my-service ./cmd/..."
2. test_stage [task call] executes
calls: test
1. unit [shell] executes
| echo "unit tests passed (42/42)"
3. deploy_stage [task call] executes
calls: deploy
1. smoke [shell] executes
| echo "GET /health -> 200"
SUMMARY 6 steps, 6 execute
No steps were executed.Add --open (or --output html) to get the interactive visual plan. See
Previewing with Dry Run.
list-tasks
Print the callable task names, one per line (internal _-prefixed tasks are
omitted). Script-friendly; pairs well with the tasks/ directory.
orchstep list-tasks [file]orchstep list-tasksbuild
db-migrate
deploy
main (default)
testmenu
Launch the interactive task picker (TUI). Press a task's hotkey to run it; /
enters fuzzy search; f cycles filters (all / a-z / public / internal); q quits.
In a non-TTY context (CI, a pipe) it exits with a clear error instead of hanging.
orchstep menu [flags]Accepts --file, --env, --var, and --vars-file (same meaning as run).
orchstep menu # pick a task from orchstep.yml
orchstep menu --file release.yml # pick from a different workflowserve
Start a local-first web dashboard (HTTP + SSE) for the workflow: run tasks on
click, watch live logs and a live step-flow graph, and browse run history. The
whole UI is embedded in the binary and runs offline; history is a single SQLite
file. Binds 127.0.0.1 by default. Full walkthrough: The Web Dashboard.
orchstep serve [flags]| Flag | Default | Description |
|---|---|---|
--port | 7777 | Bind port |
--host | 127.0.0.1 | Bind host (use 0.0.0.0 with --token for LAN sharing) |
--token | (none) | Shared token required on every request (opt-in auth) |
-f, --file | orchstep.yml | Workflow file to serve |
--db | .orchstep/serve.db | SQLite store path for run history |
orchstep serve # http://127.0.0.1:7777
orchstep serve --port 8000 # custom port
orchstep serve --host 0.0.0.0 --token "$(openssl rand -hex 16)" # share on a trusted networkeval
Evaluate an expression exactly the way workflow conditions do - against the same
merged variable context a run would have, without executing any steps. Great for
debugging a condition. Input fully wrapped in {{ }} evaluates as a Go template;
anything else as JavaScript (override with --lang).
orchstep eval [expression] [flags]| Flag | Description |
|---|---|
-f, --file <file> | Workflow file providing the variable context |
--env <name> | Environment to use |
--var key=value | Set a variable (repeatable) |
--vars-file <file> | Load variables from a YAML file |
--lang <lang> | auto (default), template, or js |
-q, --quiet | Print only the value (no language/truthy annotation) |
--explain | Show effective variables with the precedence layer that won (provenance); pass a key to drill into one |
Examples:
orchstep eval '{{ add 2 3 }}' # Go template -> 5
orchstep eval '2 + 3 > 4' # JavaScript -> true
orchstep eval 'vars.replicas > 4'
orchstep eval --env production --var replicas=99 '{{ vars.replicas }}'
orchstep eval # interactive REPL (:vars, :tpl, :js, :q)Variable provenance
eval answers "what is the value"; --explain answers "why is it that value —
which precedence layer won." With no key it prints every effective variable and
its winning layer (like git config --show-origin); the (over ...) column shows
which lower-precedence layers it shadowed.
$ orchstep eval --explain --env production --var replicas=9
VARIABLE SOURCE VALUE
db_host environment prod-db (over defaults)
region environment eu-west-1 (over defaults)
replicas runtime 9 (over defaults)Pass a key (a bare name or vars.X) to see the full layer-by-layer breakdown,
with * marking the winner:
$ orchstep eval --explain --env production region
region = eu-west-1 (from environment)
precedence (low -> high; last wins):
defaults us-east-1
* environment eu-west-1Precedence order (low to high): defaults < group < environment < module < task < step < runtime.
It also reports the OS environment variables the workflow's top-level env: sets
(values masked; {{ secrets.X }} shown as a placeholder — secrets are never
resolved here), flagging when one overrides an inherited OS variable:
# OS environment set by the workflow's env: (masked; task/step env: not shown)
ENV VAR SOURCE VALUE
API_TOKEN workflow env: ***
AWS_REGION workflow env: us-east-1
HOME workflow env: /custom/home (over inherited (os))A key that names an env var drills into it the same way. Task/step-level env:
and dotenv-vs-OS attribution aren't shown (they need a task/step context).
See Expression Playground for a live, in-browser version.
validate
Statically check a task's variable references without running it. validate
scans every {{ vars.X }} a task uses and reports which would be unresolved -
supplied by no layer in the merge chain (defaults -> group -> environment ->
task/step vars: -> --var; see Environments for how the
layers stack) - for a given environment. An unresolved reference renders to an
empty <no value> at run time; this catches that before you ship.
orchstep validate [task] [flags]| Flag | Description |
|---|---|
-f, --file <file> | Workflow file (default orchstep.yml) |
--env <name> | Validate ONE environment in detail (per-step report) |
--all-tasks | Validate every non-internal task |
--var key=value | Treat a runtime variable as supplied (repeatable) |
--vars-file <file> | Load runtime variables from a YAML file |
--json | Structured JSON output (for tooling / CI) |
--strict | Exit 1 if any referenced variable is supplied by no environment |
The example used below
The examples on this page run against this workflow (external
env_config
style). The deploy task references three variables; the environment files
supply them at different layers:
# orchstep.yml
env_config: { env_dir: environments }
tasks:
deploy:
steps:
- { name: build, func: shell, do: 'echo "building {{ vars.version }}"' }
- { name: ship, func: shell, do: 'echo "deploy {{ vars.version }} to {{ vars.target }} ({{ vars.monitoring }} monitoring)"' }environments/
defaults.yml version: "2.4.0" # baseline for every environment
nonprod.yml monitoring: basic # GROUP layer — shared, no target
nonprod-dev.yml target: dev-cluster # concrete environment
prod.yml monitoring: full # GROUP layer — shared, no target
prod-production.yml target: prod-cluster # concrete environmentSo version comes from defaults.yml (present everywhere), monitoring from
each group file, and target only from the concrete *-dev / *-production
files - never from the nonprod / prod group layers. validate makes that
visible:
The coverage matrix (default)
With no --env, validate prints an environment x variable matrix: which
environment supplies each referenced variable, which environments are complete,
and which variables are referenced but supplied nowhere (a likely typo or a
forgotten declaration).
$ orchstep validate deploy
validate · workflow "shop" · task "deploy"
referenced variables (3): monitoring target version
coverage matrix (✓ supplied · – absent):
variable (none) nonprod nonprod-dev prod prod-production
monitoring – ✓ ✓ ✓ ✓
target – – ✓ – ✓
version ✓ ✓ ✓ ✓ ✓
findings:
⚠ nonprod : 1 unresolved (target)
⚠ prod : 1 unresolved (target)
3 complete environment(s): nonprod-dev, prod-productionThe (none) column is the baseline a run with no --env would see. A group
layer like nonprod showing – for target just means that group is a shared
layer that doesn't itself set every value - which is fine when you deploy the
concrete nonprod-dev, and worth knowing before you try to deploy nonprod
directly. (If your group file does supply everything - e.g. one shared config
applied to many instances - it shows complete, and is a perfectly valid target.)
Focused mode (--env)
Pass --env for a per-step report of one environment:
$ orchstep validate deploy --env nonprod
validate · task "deploy" · env "nonprod"
✓ deploy.build version
⚠ deploy.ship target⚠
⚠ 1 unresolved under "nonprod": target
→ pick a complete environment or pass the missing vars with --var.In CI
--strict makes validate a gate: it exits non-zero when a referenced variable
is supplied by no environment at all (the typo/forgotten-declaration case).
orchstep validate deploy --strict # fail the build on a never-supplied var
orchstep validate deploy --env prod --strict --var build_id=$CI_SHALimits: references guarded by | default are never reported missing; dynamic
accesses (index .vars, vars[expr]) are reported as unverifiable rather than
guessed; v1 scans the task's own steps and does not descend into called
tasks/modules.
lint
Check a workflow file for common anti-patterns and get suggestions.
orchstep lint [file]orchstep lintNo issues found in orchstep.ymlinit
Scaffold a complete, runnable starter orchstep.yml with explanatory comments.
orchstep init [flags]| Flag | Description |
|---|---|
-t, --template <name> | minimal (default), env, or ci |
-f, --file <name> | Output file name (default orchstep.yml) |
--list | List available templates |
--force | Overwrite an existing file |
orchstep init --listAvailable templates:
minimal Hello-world starter with a verified assert (default)
env Environment-aware workflow (env_groups + environments, run with --env)
ci Build/test/package pipeline passing outputs between stepsorchstep init # minimal starter as orchstep.yml
orchstep init -t ci -f build.yml # CI starter under a custom namemodule
Manage remote and local modules. Subcommands:
| Subcommand | What it does |
|---|---|
resolve | Resolve a module version from remote tags |
lock | Generate or update orchstep.lock |
update | Refresh orchstep.lock to the newest allowed versions |
verify | Verify modules match their pinned commit + hash (CI gate) |
info | Show information about a remote module |
cache | Manage the local module cache |
orchstep module lock # pin module versions into orchstep.lock
orchstep module verify # fail if anything drifted from the lock (use in CI)Full walkthrough: Lockfile & Supply Chain and Registry & Scopes.
context
Inspect captured execution data (when context collection is enabled).
| Subcommand | What it does |
|---|---|
inspect | Launch the interactive context inspector (TUI) |
report | Generate execution reports |
clean | Clean up old context data |
orchstep context inspect # browse the last run's variables, outputs, logsversion
Show the installed version.
orchstep versionOrchStep v0.11.0
Workflow execution engine with contextual data managementTips
- Discover anything inline:
orchstep <command> --helpprints version-matched flags and examples - this page mirrors that output. - Shell completion:
orchstep completion bash|zsh|fish|powershellgenerates a completion script for your shell. - Quieter or louder:
--log-level silentfor scripts;--log-level debug(or-v) when something misbehaves.
Where to go next
- Quick Start - your first
orchstep run. - Output & Exit Codes - machine-readable output and exit-code contract.
- Task Files -
list-tasks,menu, and thetasks/directory.