This walks you from a fresh install to a real run in a few commands, using nothing but the published relayflows CLI. No scaffolder, no project template.
Just want to see it work first, with nothing to install? Skip straight to agentrelay.com/cloud and run a flow in the browser — come back here when you're ready to author your own.
1. Install
npm init -y
npm install @relayflows/surface relayflowsTypeScript flows import @relayflows/surface at runtime, so it's a project dependency. YAML is data — the global relayflows install is all you need.
2. Write a flow
// hello.flow.ts
import { flow } from '@relayflows/surface';
export default flow('hello', async (f) => {
const greeting = await f.run('printf "Hello from Flows"');
console.log(greeting.trim());
f.done('success');
});TypeScript is the default way to write a flow: the same primitives, called imperatively, with ordinary if/for control flow around each await. The YAML form (pick it from the language switch) is the canonical data the compiler checks without running anything — the shape a CI gate or a generator emits.
3. Run it
npx flows run hello.flow.ts --input '{}'flows check works on the TypeScript flow too — npx flows check hello.flow.ts — and flows run repeats the same preflight before its first step.
This is a real, captured run:
Hello from Flows
RUN 01M26JC2VPAGFVTCVWFT3GSCXQ completed (2 steps) completionReason: successEvery step's outcome is in the journal now, keyed by that run ID — the 01M26JC2VPAGFVTCVWFT3GSCXQ in the RUN ... completed line above. That's the ID everything below refers back to.
4. If it gets interrupted
flows run starts a background daemon, relayflowd. The journal lives there, not in the CLI process you typed the command into. Close the terminal, lose power, or kill the daemon itself mid-run: nothing is lost.
flows resume 01M26JC2VPAGFVTCVWFT3GSCXQThat's the same run ID flows run printed in step 3 — copy it from your own terminal's RUN ... line (or, on a failure, from the Inspect: flows replay <id> ... line the CLI prints). If you didn't capture it, there's no flows list-style lookup today: the journal for each run lives at <data-dir>/runs/<run-id>.sqlite3 (default data dir is .relayflowd in the directory you ran flows from), so ls .relayflowd/runs/ recovers it by filename.
resume starts a fresh daemon if none is up, reads the journal from disk, and continues from the first step that never recorded a completionReason — the step already marked done doesn't run again.