OrchStep for tech leads
The merge bar you enforce in code review by memory — format, vet, tests, coverage — written down once as a gate anyone can run locally and CI can run identically.
blog/tech-lead-pr-gateAs a tech lead you carry a merge bar in your head. Did they run the formatter? Did the linter pass? Are there tests, and does coverage still clear the threshold? You re-check it on every PR, leave the same three comments you left last week, and become the bottleneck the team routes around when you're busy.
The bar isn't the problem. The bar living in your review comments is. If it's written down as something people can run before they ask for review, you stop being the gate and the gate stops being you.
This post writes that merge bar as an OrchStep workflow built from small, reusable tasks — the same gate a developer runs locally and CI runs identically.
Compose the gate from reusable checks
lint and unit are standalone tasks. gate calls them as steps, then adds a coverage check with a retry. No copy-paste — the same lint runs whether you invoke it directly or as part of the gate.
name: pr-gate
# The merge gate a tech lead would otherwise enforce by memory in review.
defaults:
branch: feature
tasks:
# Shared, reusable checks - called by `gate`.
lint:
steps:
- name: format
func: shell
do: echo "format check clean"
- name: vet
func: shell
do: echo "static analysis clean"
unit:
steps:
- name: run
func: shell
do: echo "unit tests passed"
# `orchstep run gate --var branch=feature/new-api`
gate:
steps:
- name: lint
task: lint
- name: unit
task: unit
- name: coverage
func: shell
do: echo "coverage 87% (>= 80% threshold)"
retry:
max_attempts: 2
interval: "1s"
backoff_rate: 2.0
- name: verdict
func: shell
do: echo "{{ vars.branch }} is mergeable"Two design choices worth calling out:
task:composition.gateis built fromlintandunit, not a wall of duplicated steps. Add avetrule once inlintand every caller gets it.retry:on the flaky bit. A coverage upload or a tool that occasionally hiccups gets two attempts with backoff — as syntax, not a hand-rolled loop.
The same gate, both places
A developer runs it before opening the PR:
orchstep run gate --var branch=feature/new-apiCI runs the exact same task — no separate, drifting CI script to maintain:
orchstep run gate --output jsonBecause it's one workflow file, "what the gate checks" can't diverge between someone's laptop and the pipeline. The review comment you used to leave — "please run the formatter and add a test" — becomes a check that already ran.
What you gained
| Concern | Before | With OrchStep |
|---|---|---|
| Merge bar | in your review comments | a gate task anyone runs |
| Local vs CI | two scripts that drift | one workflow, run both places |
| Shared checks | copy-pasted per pipeline | task: composition |
| Flaky uploads | red build, manual re-run | retry: with backoff |
| You as bottleneck | every PR waits on you | the gate runs without you |
This won't review architecture or judge whether the abstraction is right — that's still your job, and the good news is it's the only part left for you, because the mechanical bar runs itself. If your repo already has a tidy CI config and nobody fights it, you may not need this. When the gate is tribal knowledge you re-explain in comments, write it down.
Where to go next
- Composition — building workflows from reusable tasks
- Error Handling —
retry,catch,finally - The Same Workflow in CI — run the gate in your pipeline
- Variables & Outputs — scoping and
--var
Take the comment you leave most often in review, turn it into a step in gate, and let the bar enforce itself.
curl -fsSL https://orchstep.dev/install.sh | sh