Appearance
Getting started
What you'll learn: how to install orch, scaffold a project, write a one-step workflow, and run it.
Prerequisites
- Bun ≥ 1.2.0 — orch is a Bun project and ships TypeScript directly.
- At least one agent CLI on your
PATH: - Optional:
tmux≥ 3.2 for the interactive two-pane mode. Without it, orch falls back to plain mode.
There is no orch login — each runner uses its own auth (claude via its own login, codex login).
Install
The recommended path is Homebrew, which installs a standalone binary — no Bun is required for orch itself (you still need Bun only if you run workflows that import Bun APIs):
bash
brew tap futuredapp/orch
brew trust futuredapp/orch # Homebrew 5.1+ only — see note below
brew install orch
orch --helpHomebrew 5.1+ requires trusting third-party taps. Since Homebrew 5.1, formulae from taps outside the official set are not loaded until you trust the tap, so
brew install orchfails withRefusing to load formula … from untrusted tap futuredapp/orch. Runbrew trust futuredapp/orchonce, then re-run the install. On older Homebrew versions thetrustcommand does not exist — skip that line ifbrew trust --helperrors.
Upgrade later with brew upgrade orch.
Alternatively, run orch through bunx without installing it (requires Bun from the prerequisites above):
bash
bunx orch --helpScaffold a project
From your project root:
bash
orch initThis creates a single .orch/ directory and registers state files in .gitignore:
my-project/
├── .gitignore # `.orch/state/` appended by orch init
└── .orch/
├── orch.config.ts # workflow manifest (name → file path)
├── workflows/
│ └── hello.ts # the hello-world workflow scaffolded for you
└── state/ # per-run state — gitignored
└── <run-id>/
├── state.json
└── logs/orch.config.ts and everything under workflows/ are committed to your repo. .orch/state/ is gitignored. orch init is safe to re-run — it prompts before touching an existing .orch/.
Your first workflow
A workflow is a TypeScript file that default-exports a workflow(...). Here is a complete one-step program — read it top to bottom:
ts
// .orch/workflows/hello.ts
import { workflow, step, claude } from 'orch'
import { fileProduced } from 'orch'
const CREATE_FILE = step.define('create-hello-file', {
agent: claude(),
prompt:
'Create a file at ./hello.txt containing exactly the text "Hello World" ' +
'(no trailing newline, no code fences, no extra explanation).',
validate: fileProduced('hello.txt'),
})
export default workflow('hello', async (run) => {
await run(CREATE_FILE)
})Three things are happening:
step.define('create-hello-file', { ... })declares a reusable step. The name is its memoization key — keep it stable and meaningful.agent: claude()says this step runs the Claude Code CLI.prompt:is the default instruction.validate: fileProduced('hello.txt')asserts the file exists after the step. If it does not, the step fails.
Register and run it
Add the workflow to your config so orch run can find it by name:
ts
// .orch/orch.config.ts
import { defineConfig } from 'orch'
export const config = defineConfig({
workflows: {
hello: './workflows/hello.ts',
},
})Then run it:
bash
orch run helloWhat happens:
- orch creates
.orch/state/<run-id>/and picks a run mode (two-pane if you have a TTY and tmux, otherwise plain). - It spawns the
claudeCLI with your prompt and streams the transcript. - When Claude exits, orch runs the
fileProducedvalidator, persists the result tostate.json, and reports success.
If the run is interrupted, resume it:
bash
orch resume --latestThe workflow function re-executes from the top; the finished step returns its cached value, and execution picks up where it stopped.
Where to go next
- Core concepts — understand steps, runs, modes, and resume.
- Writing a workflow — chaining steps, passing data, and looping.
- Authoring API reference — every export from the
orchpackage.