OrchStep for agencies and consultancies
Every client repo is a little different, but the delivery dance is the same. Here's how a consultancy turns build-package-ship-handoff into one workflow that travels from client to client.
If you run delivery for an agency, you live in other people's repos. One client is on Kubernetes, one is on a single VPS, one still deploys by SSHing into a box named prod-final-2. The work is different every time. The shape of the work never changes: scaffold the project, build it, package it, ship it to the right place, and leave a handoff the client's own team can run after you're gone.
That last part — "after you're gone" — is the whole problem. A bash script you wrote on a Tuesday is institutional knowledge that walks out the door with the engagement. OrchStep gives you a single readable workflow file you can drop into any client repo, run yourself during the build, and hand off as the deliverable.
What automation looks like for an agency
You are not automating one pipeline. You are automating a pattern across a dozen engagements, each with its own quirks, none of which justify standing up a CI platform you'd then have to maintain for the client. What you want is:
- One file per repo that anyone can read in 60 seconds.
- No daemon, no account, no platform lock-in to explain in the SOW.
- The same commands on your laptop and in whatever CI the client already has.
- A
--dry-runyou can screen-share on a handoff call to prove what ships.
Where OrchStep fits
OrchStep is a single binary that runs shell steps with structure around them — ordered tasks, named variables, retries as syntax, rollback as a catch: block. Your docker and kubectl and rsync commands still do the real work. OrchStep is the part you used to keep in your head.
Here's a delivery workflow that works for one client and travels to the next by changing two defaults:
name: client-delivery
defaults:
client: acme
target: staging
registry: ghcr.io/studio
tasks:
# orchstep run scaffold --var client=globex
scaffold:
steps:
- name: workspace
func: shell
do: echo "creating workspace for {{ vars.client }}"
outputs:
path: "clients/{{ vars.client }}"
- name: report
func: shell
do: echo "scaffolded {{ steps.workspace.path }}"
# orchstep run deliver --var client=globex --var target=production
deliver:
steps:
- name: build
task: scaffold
- name: package
func: shell
do: echo "packaging {{ vars.registry }}/{{ vars.client }}:release"
retry:
max_attempts: 3
interval: "1s"
backoff_rate: 2.0
- name: ship
func: shell
do: echo "delivering {{ vars.client }} to {{ vars.target }}"
catch:
- name: rollback
func: shell
do: echo "rolling back {{ vars.client }} on {{ vars.target }}"
finally:
- name: handoff
func: shell
do: echo "handoff note written for {{ vars.client }}"
- name: gate
if: '{{ eq vars.target "production" }}'
then:
- name: signoff
func: shell
do: echo "client signoff required for {{ vars.client }}"
else:
- name: preview
func: shell
do: echo "staging preview ready for {{ vars.client }}"The client and registry are variables, so the same file serves every engagement. The production branch demands a signoff step; staging just leaves a preview. Nothing here is client-specific code — it's the delivery shape, and it's the same shape every time.
Three workflows worth stealing
1. The new-client scaffold. orchstep run scaffold --var client=globex stands up the workspace, names the artifacts consistently, and emits an output that later steps reuse by name (steps.workspace.path). New engagement, two minutes, same conventions as the last one. See Variables & Outputs.
2. The per-environment deliver. One deliver task, two destinations. The if: gate on the production target means staging and prod are the same workflow with different guardrails — no second script to drift. For clients with genuinely separate config (different registries, regions, hostnames), promote target to a named environment and select it with --env. See Environments.
3. The handoff dry-run. On the last call of the engagement, run orchstep run deliver --var client=globex --dry-run. It resolves every variable and prints the exact plan without executing. The client's team watches the deploy on screen, then owns a file they can read — not a 200-line script with a # do not touch comment. See Previewing with Dry Run.
What you gained
| Concern | Per-client bash scripts | OrchStep |
|---|---|---|
| Reuse across clients | copy-paste, then diverge | one file, change defaults |
| Retry on flaky registry | hand-rolled loop | retry: { max_attempts: 3, backoff_rate: 2.0 } |
| Rollback | || after the command | catch: block |
| Staging vs prod | two scripts | one if: gate, or --env |
| The deliverable | tribal knowledge | a readable workflow file |
| Handoff proof | "trust me" | --dry-run on the call |
OrchStep is not a CI platform and won't replace the client's Jenkins or GitHub Actions — it runs inside whatever they have, identically to how it runs on your laptop. If a client's needs are fully covered by make, use make. The moment you're maintaining the same delivery dance across more than two repos, a portable workflow file pays for itself.
Where to go next
- Quick Start — your first workflow in two minutes
- Environments — per-client config without per-client scripts
- Error Handling — retry, catch, finally, timeouts
- Where It Runs — same binary on your laptop and the client's CI
One delivery dance, every engagement? Drop a single orchstep.yml into your next client repo and hand it over as the deliverable.
curl -fsSL https://orchstep.dev/install.sh | sh