writing-agent-relay-workflows
SkillAI & modelsThis skill gives your AI the know-how to build multi-agent workflows with Relay. Once added, your AI can create workflows where steps pass results from one agent to the next, with verification gates and review loops that catch problems and only call work done when there is evidence it is complete.
Available today. Use it from your connected AI after setup.
No other account needed.
After adding the skill, describe a task you want split across agents and ask your AI to build the workflow. It will set up the steps, checks, and review loops as it goes.
Then ask your AI: use the writing-agent-relay-workflows skill
What your AI can do with it
- Build multi-step workflows that coordinate several agents
- Run agents in a conversational flow or as a step-by-step pipeline
- Pass each step's output directly into the next step
- Add verification gates that catch problems and repair them
- Require evidence before a workflow is marked complete
- Run review loops where a second AI checks the work with fresh eyes and fixes issues
What this skill tells your AI
The instructions your AI receives, as published by agentworkforce/relay in .agents/skills/writing-agent-relay-workflows/SKILL.md and read by ahel’s review.
Overview
The @relayflows/core workflow system orchestrates multiple AI agents (Claude, Codex, Gemini, Aider, Goose) through typed DAG-based workflows. Workflows can be written in TypeScript (preferred), Python, or YAML.
Language preference: TypeScript > Python > YAML. Use TypeScript unless the project is Python-only or a simple config-driven workflow suits YAML.
Pattern selection: Do not default to dag blindly. If the job needs a different swarm/workflow type, consult the choosing-swarm-patterns skill when available and select the pattern that best matches the coordination problem.
When to Use
- Building multi-agent workflows with step dependencies
- Orchestrating different AI CLIs (claude, codex, gemini, aider, goose)
- Creating DAG, pipeline, fan-out, or other swarm patterns
- Needing verification gates, retries, or step output chaining
- Designing product-contract workflows where failing checks should route to agents for repair instead of stopping the run
- Dynamic channel management: agents joining/leaving/muting channels mid-workflow
Non-Negotiable Workflow Checklist
Every generated workflow should satisfy this checklist before it is considered complete:
- Start with a deterministic, resumable preflight for repository state, credentials, and declared write scope.
- Pick the coordination shape deliberately: Conversation for non-trivial coordination, Pipeline only for linear one-shot handoffs.
- Use repairable validation gates: capture red output with
failOnError: false, hand it to a repair owner, then rerun the same check. - Run the mandatory fresh-eyes loops in order: Claude review/fix/final review/final fix, then Codex review/fix/final review/final fix.
- Require review fixers to add or update appropriate tests, fixtures, assertions, or deterministic proofs for testable findings.
- Run final deterministic acceptance after the Codex loop and before commit, PR creation, or handoff.
- If a real blocker remains, write
BLOCKED_NO_COMMITwith exact evidence and skip commit/PR creation instead of crashing the workflow. - If the workflow owns shipping, model branch, commit, push, PR creation, and PR URL verification as explicit deterministic steps.
Default Principle: Workflows Repair Before They Fail
- Run deterministic checks as evidence-capturing gates with
captureOutput: true. - Prefer
failOnError: falsefor intermediate validation gates so the workflow can pass the output to a repair agent. - Add a repair step immediately after each red-prone gate. The repair agent reads
{{steps.<gate>.output}}, fixes source/tests/config, reruns the same command locally, and exits only after the gate is green or the blocker is external. - Keep final acceptance deterministic, but still put an agent repair step before commit/PR creation. If the repair budget is exhausted or a true external blocker remains, write a blocked artifact and skip commit/PR creation; do not let the workflow end as
FAILED. - Use
.reliable()or.repairable()on SDK versions that support it, especially for product-contract workflows. As of AgentWorkforce/relay#827, retry-mode workflows with agents are repair-aware by default, repair agents run before retrying malformed/failed agent steps, and the SDK covers DAG, pipeline, fan-out, worktree-backed, deterministic-only, and agent-plus-gate shapes.
Mandatory Fresh-Eyes Review Loops
Every workflow must include two comprehensive fresh-eyes review/fix loops before final acceptance, commit, PR creation, or handoff: first Claude, then Codex. This applies even to small workflows and even when deterministic tests pass. Tests prove commands passed; the fresh-eyes loops make independent agents read the actual resulting files and artifacts as if they did not author them.
verdict: FINDINGS | NO_ISSUES_FOUND | BLOCKED
finding_id: short stable id
severity: blocker | high | medium | low
file: path/to/file
issue: what is wrong
fix_required: concrete change needed
test_required: test, fixture, assertion, or proof command needed
status: open | fixed | wontfix | blocked
evidence: commands run, file paths, or blocker details
Choose Your Coordination Style — Conversation vs Pipeline
Before writing the workflow, decide how the agents will coordinate. The relay primitive supports two very different shapes, and picking the wrong one wastes the most valuable thing the SDK gives you.
| Shape | What it is | Use when |
|---|---|---|
| Conversation (chat-native) | Interactive agents share a channel; messages, @-mentions, and ambient awareness drive coordination. Lead and workers spawn in parallel and self-organize. The relay is the coordination layer, not just transport. | Multi-file work, peer review loops, cross-agent feedback, dynamic re-planning, multi-PR coordination, anything with a human-in-the-loop escape, swarms where workers pick up each other's output. |
| Pipeline (one-shot DAG) | Each step runs as a one-shot subprocess (claude -p, codex exec); steps hand off via {{steps.X.output}} text injection. No agents are alive at the same time; no chat happens. | Linear, well-specified transformations; deterministic data passing; no live agent-to-agent coordination during implementation. The mandatory final Claude-then-Codex review/fix loops still apply. |
Default to Conversation for any non-trivial work. Pipeline DAGs are simpler to reason about but they do not exercise the relay primitive — they are a Unix pipe with extra steps. If you would happily write the same task as a single shell pipeline, pipeline-shape is fine. Otherwise, you almost certainly want a Conversation shape.
The two shapes can mix within one workflow: pipeline-style deterministic preflight → conversation in the middle → pipeline-style commit-and-PR at the end. See Quick Reference (Conversation) below and Common Patterns → Interactive Team for the canonical recipe.
A blunt rule of thumb: if your workflow only uses
agentsteps withpreset: 'worker'chained by{{steps.X.output}}, you are not using the relay — you are usingclaude -p | codex exec. That may still be the right answer; just make it a deliberate choice.
Quick Reference (Pipeline shape)
> Use this when steps are linear, well-specified, and need no agent-to-agent feedback. For anything with iteration, review, or coordination, jump to Quick Reference (Conversation shape) below.
import { workflow } from '@relayflows/core';
async function runWorkflow() {
const result = await workflow('my-workflow')
.description('What this workflow does')
.pattern('dag') // or 'pipeline', 'fan-out', etc.
.channel('wf-my-workflow') // dedicated channel (auto-generated if omitted)
.maxConcurrency(3)
.timeout(3_600_000) // global timeout (ms)
.repairable()
.agent('lead', { cli: 'claude', role: 'Architect', retries: 2 })
.agent('worker', { cli: 'codex', role: 'Implementer', retries: 2 })
.agent('claude-reviewer', {
cli: 'claude',
role: 'First-pass fresh-eyes reviewer',
retries: 1,
preset: 'reviewer',
})
.agent('claude-fixer', { cli: 'claude', role: 'First-pass review-finding fixer', retries: 2 })
.agent('codex-reviewer', {
cli: 'codex',
role: 'Second-pass fresh-eyes reviewer',
retries: 1,
preset: 'reviewer',
})
.agent('codex-fixer', { cli: 'codex', role: 'Review-finding fixer', retries: 2 })
.step('preflight', {
type: 'deterministic',
command: 'git rev-parse --show-toplevel >/dev/null && echo PREFLIGHT_OK',
captureOutput: true,
failOnError: true,
})
.step('plan', {
agent: 'lead',
dependsOn: ['preflight'],
task: `Analyze the codebase and produce a plan.`,
retries: 2,
verification: { type: 'output_contains', value: 'PLAN_COMPLETE' },
})
.step('implement', {
agent: 'worker',
task: `Implement based on this plan:\n{{steps.plan.output}}`,
dependsOn: ['plan'],
verification: { type: 'exit_code' },
})
.step('claude-review', {
agent: 'claude-reviewer',
dependsOn: ['implement'],
task: `Fresh-eyes review the completed workflow output. Read the actual files, diff, repo rules, and available evidence.
Write findings to .workflow-artifacts/my-workflow/claude-review.md.
If there are no actionable issues, write NO_ISSUES_FOUND.`,
verification: { type: 'exit_code' },
})
.step('claude-fix', {
agent: 'claude-fixer',
dependsOn: ['claude-review'],
task: `Read .workflow-artifacts/my-workflow/claude-review.md.
Fix every valid issue, add or update appropriate tests/proofs for the fix, rerun relevant checks, and update .workflow-artifacts/my-workflow/claude-fix.md.
If the review says NO_ISSUES_FOUND, record that no fix was needed.`,
verification: { type: 'exit_code' },
})
.step('claude-review-final', {
agent: 'claude-reviewer',
dependsOn: ['claude-fix'],
task: `Fresh-eyes review the post-fix state from scratch. Do not rely on the prior review or fix summary.
Write .workflow-artifacts/my-workflow/claude-review-final.md with either actionable findings or NO_ISSUES_FOUND.`,
verification: { type: 'exit_code' },
})
.step('claude-fix-final', {
agent: 'claude-fixer',
dependsOn: ['claude-review-final'],
task: `If .workflow-artifacts/my-workflow/claude-review-final.md contains findings, fix them, add or update appropriate tests/proofs, and rerun relevant checks.
If no fix is possible, write .workflow-artifacts/my-workflow/BLOCKED_NO_COMMIT.md with exact evidence.
If it says NO_ISSUES_FOUND, record Claude review signoff.`,
verification: { type: 'exit_code' },
})
.step('codex-review', {
agent: 'codex-reviewer',
dependsOn: ['claude-fix-final'],
task: `Second-pass fresh-eyes review of the post-Claude-fix state. Read the actual files, diff, repo rules, and available evidence.
Write findings to .workflow-artifacts/my-workflow/codex-review.md.
If there are no actionable issues, write NO_ISSUES_FOUND.`,
verification: { type: 'exit_code' },
})
.step('codex-fix', {
agent: 'codex-fixer',
dependsOn: ['codex-review'],
task: `Read .workflow-artifacts/my-workflow/codex-review.md.
Fix every valid issue, add or update appropriate tests/proofs for the fix, rerun relevant checks, and update .workflow-artifacts/my-workflow/codex-fix.md.
If the review says NO_ISSUES_FOUND, record that no fix was needed.`,
verification: { type: 'exit_code' },
})
.step('codex-review-final', {
agent: 'codex-reviewer',
dependsOn: ['codex-fix'],
task: `Fresh-eyes review the post-Codex-fix state from scratch. Do not rely on the prior review or fix summary.
Write .workflow-artifacts/my-workflow/codex-review-final.md with either actionable findings or NO_ISSUES_FOUND.`,
verification: { type: 'exit_code' },
})
.step('codex-fix-final', {
agent: 'codex-fixer',
dependsOn: ['codex-review-final'],
task: `If .workflow-artifacts/my-workflow/codex-review-final.md contains findings, fix them, add or update appropriate tests/proofs, and rerun relevant checks.
If no fix is possible, write .workflow-artifacts/my-workflow/BLOCKED_NO_COMMIT.md with exact evidence.
If it says NO_ISSUES_FOUND, record final review signoff.`,
verification: { type: 'exit_code' },
})
.step('acceptance-after-review', {
type: 'deterministic',
dependsOn: ['codex-fix-final'],
command: 'test ! -f .workflow-artifacts/my-workflow/BLOCKED_NO_COMMIT.md && echo ACCEPTANCE_OK',
captureOutput: true,
failOnError: true,
})
.onError('retry', { maxRetries: 2, retryDelayMs: 10_000 })
.run({ cwd: process.cwd() });
console.log('Result:', result.status);
}
runWorkflow().catch((error) => {
console.error(error);
process.exit(1);
});
Quick Reference (Conversation shape)
> Use this for any non-trivial work — peer review, multi-file edits, cross-agent feedback, dynamic re-planning. Lead and workers spawn in parallel on a shared channel and self-organize via messages. The relay primitive does the coordinating; verification gates downstream of the lead close the workflow.
import { workflow } from '@relayflows/core';
import { ClaudeModels, CodexModels } from '@agent-relay/config';
async function runWorkflow() {
const result = await workflow('my-workflow')
.description('Multi-file change with peer review')
.pattern('dag')
.channel('wf-my-feature') // dedicated channel — agents share it
.maxConcurrency(4)
.timeout(3_600_000)
.repairable()
// Interactive agents — no preset, they live on the channel
.agent('lead', {
cli: 'claude',
model: ClaudeModels.OPUS,
role: 'Architect + reviewer. Plans, assigns, reviews, posts feedback.',
retries: 1,
})
.agent('impl-a', {
cli: 'codex',
model: CodexModels.GPT_5_4,
role: 'Implementer. Listens on channel for assignments and feedback.',
retries: 2,
})
.agent('impl-b', {
cli: 'codex',
model: CodexModels.GPT_5_4,
role: 'Implementer. Listens on channel for assignments and feedback.',
retries: 2,
})
.agent('claude-reviewer', {
cli: 'claude',
model: ClaudeModels.OPUS,
preset: 'reviewer',
role: 'First-pass fresh-eyes reviewer. Reads the final diff and artifacts from scratch.',
retries: 1,
})
.agent('claude-fixer', {
cli: 'claude',
model: ClaudeModels.SONNET,
role: 'First-pass review-finding fixer. Repairs valid findings, adds tests/proofs, and reruns checks.',
retries: 2,
})
.agent('codex-reviewer', {
cli: 'codex',
model: CodexModels.GPT_5_4,
preset: 'reviewer',
role: 'Second-pass fresh-eyes reviewer. Reviews the post-Claude-fix state from scratch.',
retries: 1,
})
.agent('codex-fixer', {
cli: 'codex',
model: CodexModels.GPT_5_4,
role: 'Review-finding fixer. Repairs valid findings, adds tests/proofs, and reruns checks.',
retries: 2,
})
// Deterministic context — pre-reads files once, posts to the channel for everyone
.step('preflight', {
type: 'deterministic',
command: 'git rev-parse --show-toplevel >/dev/null && echo PREFLIGHT_OK',
captureOutput: true,
failOnError: true,
})
.step('context', {
type: 'deterministic',
dependsOn: ['preflight'],
command: 'git ls-files src/',
captureOutput: true,
})
// Lead and workers all depend on `context` — they start CONCURRENTLY.
// They coordinate over #wf-my-feature, not via {{steps.X.output}}.
.step('lead-coordinate', {
agent: 'lead',
dependsOn: ['context'],
task: `You are the lead on #wf-my-feature. Workers: impl-a, impl-b.
Post the plan. Assign files. Review their PRs/diffs. Post feedback in-channel.
Workers iterate based on your feedback. Exit when both files pass review.`,
})
.step('impl-a-work', {
agent: 'impl-a',
dependsOn: ['context'], // SAME dep as lead → starts in parallel, no deadlock
task: `You are impl-a on #wf-my-feature. Wait for the lead's plan.
Implement your assigned file. Post a completion message. Address feedback.`,
})
.step('impl-b-work', {
agent: 'impl-b',
dependsOn: ['context'], // SAME dep as lead
task: `You are impl-b on #wf-my-feature. Wait for the lead's plan.
Implement your assigned file. Post a completion message. Address feedback.`,
})
// Downstream gates on the lead — lead exits when satisfied.
// Capture failures, then hand them to an agent for repair.
.step('verify', {
type: 'deterministic',
dependsOn: ['lead-coordinate'],
command: 'npm run typecheck && npm test 2>&1',
captureOutput: true,
failOnError: false,
})
.step('repair-verify', {
agent: 'lead',
dependsOn: ['verify'],
task: `If verification passed, summarize evidence.
If it failed, use this output to assign and fix issues, then rerun the command until green:
{{steps.verify.output}}`,
verification: { type: 'exit_code' },
})
.step('verify-final', {
type: 'deterministic',
dependsOn: ['repair-verify'],
command: 'npm run typecheck && npm test 2>&1',
captureOutput: true,
failOnError: false,
})
.step('claude-review', {
agent: 'claude-reviewer',
dependsOn: ['verify-final'],
task: `First-pass fresh-eyes review of the post-implementation state.
Read the actual changed files, git diff, repo instructions, task spec, and verification output:
{{steps.verify-final.output}}
Write .workflow-artifacts/my-feature/claude-review.md with:
- actionable findings, each with file paths and required fix
- or NO_ISSUES_FOUND if there are no remaining issues`,
verification: { type: 'exit_code' },
})
.step('claude-fix', {
agent: 'claude-fixer',
dependsOn: ['claude-review'],
task: `Read .workflow-artifacts/my-feature/claude-review.md.
If there are findings, fix every valid one and add or update appropriate tests/proofs. After each fix, rerun the relevant check and review the changed files again.
Keep iterating locally until this round has no remaining valid issues.
Write .workflow-artifacts/my-feature/claude-fix.md with fixes and commands run.
If the review says NO_ISSUES_FOUND, write that no fix was needed.`,
verification: { type: 'exit_code' },
})
.step('claude-review-final', {
agent: 'claude-reviewer',
dependsOn: ['claude-fix'],
task: `Perform a fresh post-fix review from scratch. Do not rely on previous review text or the fixer's summary.
Read files, diff, repo rules, task spec, and evidence. Write .workflow-artifacts/my-feature/claude-review-final.md.
Use NO_ISSUES_FOUND only if there are no actionable issues left.`,
verification: { type: 'exit_code' },
})
.step('claude-fix-final', {
agent: 'claude-fixer',
dependsOn: ['claude-review-final'],
task: `If the final Claude review found issues, fix them, add or update appropriate tests/proofs, and rerun the relevant checks until green.
If no fix is possible, write .workflow-artifacts/my-feature/BLOCKED_NO_COMMIT.md with exact evidence and do not commit.
If the final review says NO_ISSUES_FOUND, record signoff in .workflow-artifacts/my-feature/claude-signoff.md.`,
verification: { type: 'exit_code' },
})
.step('verify-after-claude-review', {
type: 'deterministic',
dependsOn: ['claude-fix-final'],
command:
'test ! -f .workflow-artifacts/my-feature/BLOCKED_NO_COMMIT.md && npm run typecheck && npm test 2>&1',
captureOutput: true,
failOnError: false,
})
.step('codex-review', {
agent: 'codex-reviewer',
dependsOn: ['verify-after-claude-review'],
task: `Second-pass fresh-eyes review of the post-Claude-fix state.
Read the actual changed files, git diff, repo instructions, task spec, and verification output:
{{steps.verify-after-claude-review.output}}
Write .workflow-artifacts/my-feature/codex-review.md with:
- actionable findings, each with file paths and required fix
- or NO_ISSUES_FOUND if there are no remaining issues`,
verification: { type: 'exit_code' },
})
.step('codex-fix', {
agent: 'codex-fixer',
dependsOn: ['codex-review'],
task: `Read .workflow-artifacts/my-feature/codex-review.md.
If there are findings, fix every valid one and add or update appropriate tests/proofs. After each fix, rerun the relevant check and review the changed files again.
Keep iterating locally until this round has no remaining valid issues.
Write .workflow-artifacts/my-feature/codex-fix.md with fixes and commands run.
If the review says NO_ISSUES_FOUND, write that no fix was needed.`,
verification: { type: 'exit_code' },
})
.step('codex-review-final', {
agent: 'codex-reviewer',
dependsOn: ['codex-fix'],
task: `Perform a fresh post-Codex-fix review from scratch. Do not rely on previous review text or the fixer's summary.
Read files, diff, repo rules, task spec, and evidence. Write .workflow-artifacts/my-feature/codex-review-final.md.
Use NO_ISSUES_FOUND only if there are no actionable issues left.`,
verification: { type: 'exit_code' },
})
.step('codex-fix-final', {
agent: 'codex-fixer',
dependsOn: ['codex-review-final'],
task: `If the final Codex review found issues, fix them, add or update appropriate tests/proofs, and rerun the relevant checks until green.
If no fix is possible, write .workflow-artifacts/my-feature/BLOCKED_NO_COMMIT.md with exact evidence and do not commit.
If the final review says NO_ISSUES_FOUND, record signoff in .workflow-artifacts/my-feature/codex-signoff.md.`,
verification: { type: 'exit_code' },
})
.step('verify-after-review', {
type: 'deterministic',
dependsOn: ['codex-fix-final'],
command:
'test ! -f .workflow-artifacts/my-feature/BLOCKED_NO_COMMIT.md && npm run typecheck && npm test 2>&1',
captureOutput: true,
failOnError: true,
})
.onError('retry', { maxRetries: 2, retryDelayMs: 10_000 })
.run({ cwd: process.cwd() });
console.log('Result:', result.status);
}
runWorkflow().catch((error) => {
console.error(error);
process.exit(1);
});
Default For Serious Implementation: Shadowed Squad Review Loop
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 822
- Forks
- 64
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
writing-agent-relay-workflows- Source
- github.com/agentworkforce/relay