Deterministic where it counts
The order, the loops, how many rounds and the deadlines are code you wrote, the same on every run. Every answer is checked against your schema before your code sees it.
Coding agents that follow your process. TypeScript fixes the steps, the agents do the thinking, and runs are durable and event-driven. Your workflow is your code, not a feature of someone's platform.
bun add -g agentswfAn implementer on claude, a reviewer on codex, and a loop until the reviewer's typed answer approves. DONE and VERDICT are TypeBox schemas: { summary } and { approved, changes }.
const implementer = await wf.agents.open({
key: "implementer",
runtime: "claude",
});
const reviewer = await wf.agents.open({
key: "reviewer",
runtime: { harness: "codex", model: "gpt-6-luna", placement: "headless" },
});
let prompt = `Implement this task: ${task}`;
for (let round = 1; round <= 3; round++) {
const work = await implementer.run({ prompt, schema: DONE });
if (!work.outcome.answered)
return wf.stop(`implementer: ${work.outcome.reason}`);
const review = await reviewer.run({
prompt: "Review the change.",
schema: VERDICT,
});
if (!review.outcome.answered)
return wf.stop(`reviewer: ${review.outcome.reason}`);
if (review.outcome.value.approved)
return { approved: true, rounds: round };
prompt = `Make these changes:\n${review.outcome.value.changes.join("\n")}`;
}
return { approved: false, rounds: 3 };The loop and its limit are code; the reviewer's verdict is a checked boolean, not a guess from prose. The implementer works in a pane in Herdr, a terminal multiplexer, where you can watch it and type to it; Herdr is optional, and every agent can run headless instead. The engine handles an agent that goes quiet, answers in the wrong shape, or hangs. Why agents.wf says what this is for.
awf run review-loop.ts runs the same steps every time and records each turn. If a workflow with stages stops part-way, a continue reuses the stages that finished.awf tick on a schedule brings timers due (Hosting events), and between them the run parks. A person can answer it in the terminal, or through a chat app or script you connect.agent.run({ prompt, schema }).wfa result.await returns a typed value, and your code decides what happens next.awf run ./workflow.ts runs the workflow, prints its result, and keeps a record of the run in .awf/runs. How it works has the rest.
Your coding agent writes the workflow. Every page here is also Markdown for it to read, and the API is one page. After a change it runs the typechecker and awf test, which catch its mistakes before any agent starts. What it writes is agents, prompts, schemas and plain for and if, so you can review it in a minute: Quick start says what to check.
Write the workflow with a frontier model, then run it on cheaper or open-weight ones: each agent's model is one line, and Cost shows what the change did to a run.
The quick start takes you from install to a first run and its result.