Strategies¶
Strategies control two things: which agent speaks next (selection) and when the run ends (termination).
Selection strategies¶
Configured under Selection.Type.
sequential¶
Agents take turns in the order they are declared in Agents. When the last agent finishes its turn, the cycle repeats from the first.
Use this for simple pipelines where the flow is always the same, or for single-agent configs.
keyword¶
An agent's message is scanned for routing keywords to determine who speaks next. If no keyword matches, the DefaultAgent is selected (falls back to the first agent if DefaultAgent is not set).
Selection:
Type: keyword
DefaultAgent: Planner
Routes:
- Keyword: "HANDOFF TO DEVELOPER"
Agent: Developer
Validator: RequireBrief
SourceAgents:
- Planner
- Keyword: "HANDOFF TO TESTER"
Agent: Tester
Validators:
- RequireWriteFile
- RequireShellPass
RequiredCommandPattern: "go build|go test"
SourceAgents:
- Developer
- Keyword: "HANDOFF TO REVIEWER"
Agent: Reviewer
Validator: TestReportValid
SourceAgents:
- Tester
- Keyword: BUGS FOUND
Agent: Developer
SourceAgents:
- Tester
- Keyword: REVISION REQUIRED
Agent: Developer
SourceAgents:
- Reviewer
- Keyword: REPLAN REQUIRED
Agent: Planner
SourceAgents:
- Reviewer
- Keyword: APPROVED
Agent: Reviewer
Validators:
- RequireShellPass
- RequireReviewJudgement
SourceAgents:
- Reviewer
How routing works
- The response text is scanned for every keyword configured in
Routes. - Strict matching — a keyword matches only when it appears alone on its own line (after stripping markdown formatting characters
*and_). A keyword embedded in a sentence or used as a prose section header (e.g.BUGS FOUND: 3 failures) does not match. This prevents accidental routing when agents reference another role's keyword in their output. - If multiple keywords appear on their own lines in the same response, the response is rejected as ambiguous and a correction is injected asking the agent to use exactly one keyword. This prevents silent first-match bias from config ordering.
- The single matched keyword is checked against
SourceAgents— the route only fires if the message author is in that list (or ifSourceAgentsis omitted). - If a route has validators (
ValidatororValidators), they run before the route fires. If validation fails, the source agent is re-invoked with an error message injected. - If the route has
RequireHumanApproval: true, the operator is prompted to approve before the route fires. If rejected, the source agent is re-invoked with a "route blocked" message. - If no keyword matches,
DefaultAgenthandles the next turn.
Phase-break keywords
Some keywords end the current pipeline phase and restart from a different agent (BUGS FOUND, REVISION REQUIRED, REPLAN REQUIRED). Others terminate the session (APPROVED). These are called phase-break keywords and are identified by the self-routing convention: when a route's SourceAgents list includes the same agent as Agent, it is treated as a terminal route (session ends when the keyword is emitted).
- Keyword: APPROVED
Agent: Reviewer
SourceAgents:
- Reviewer
Validators:
- RequireShellPass
- RequireReviewJudgement
Here Agent: Reviewer and SourceAgents: [Reviewer] — the agent routes to itself — which signals termination. All other phase-break routes (BUGS FOUND → Developer, REVISION REQUIRED → Developer, REPLAN REQUIRED → Planner) use different source and target agents and trigger a phase restart rather than session end.
Phase-break keywords must be declared in Selection.Routes even if they are also referenced in Termination.Strategies. The routing engine reads agent ownership from Selection.Routes exclusively — a keyword absent from there will not be recognized when an agent emits it.
Route fields
| Field | Type | Default | Description |
|---|---|---|---|
Keyword |
string | — | Case-insensitive. Must appear alone on its own line in the response to match — not as part of a sentence or section header. |
Agent |
string | — | Agent to activate when the keyword fires. When Agent matches one of the SourceAgents, the route is terminal (session ends). |
Validator |
string | — | Optional. Single validator name. Blocks the route until validation passes. |
Validators |
array | — | Optional. Multiple validators (AND semantics — all must pass). Use instead of Validator when multiple checks are needed. |
SourceAgents |
array | any | Optional. If set, the route only fires when the message author is in this list. Use to prevent agents from triggering routes intended for other roles. |
RequiredCommandPattern |
string | — | Optional. When Validator is RequireShellPass, the passing command must contain at least one of these pipe-separated substrings. |
RequireHumanApproval |
bool | false |
Optional. When true, the operator must explicitly approve (y) before the route fires. If rejected, the source agent is re-invoked. Works independently of --hitl — approval gates fire in normal mode too. |
Built-in validators
| Validator | What it checks |
|---|---|
RequireBrief |
Blocks unless brief.json exists on disk with a non-empty goal, files_to_change, and acceptance_criteria. Ensures the Planner did its job before the Developer starts. |
RequireWriteFile |
Blocks unless the current agent called write_file this turn. Prevents fabricated "I wrote the file" claims. |
RequireAllFilesWritten |
Blocks unless every file in brief.json's files_to_change has been written — in the current turn or in a prior turn recorded in changes.json. Prevents partial implementations from passing handoff. |
RequireShellPass |
Blocks unless a shell command exited 0 this turn (optionally matching RequiredCommandPattern). |
TestReportValid |
Blocks unless a valid test-report.json exists and passes all structural checks. |
See Validators for details.
structured¶
Routes the next agent based on JSON field conditions evaluated against the last agent's response. Use this when agents produce structured output and routing depends on the content of that output rather than a fixed keyword.
Selection:
Type: structured
DefaultAgent: Drafter
StructuredRoutes:
- Agent: Reviewer
Condition:
Field: draft_content
Exists: true
SourceAgents:
- Drafter
- Agent: Publisher
Condition:
Field: review_result
Is: "Yes"
SourceAgents:
- Reviewer
- Agent: Drafter
Condition:
Field: review_result
Is: "No"
SourceAgents:
- Reviewer
How routing works
- After each agent turn, the strategy locates the most recent assistant text message.
- It tries to extract a JSON object from the text (raw JSON, a
```jsoncode fence, or the first{…last}substring — whichever parses first). - Each route is evaluated in order. The first route whose
Conditionevaluates totrueand whoseSourceAgentsrestriction is satisfied fires. The matched agent handles the next turn. - If the response is not valid JSON, or no condition matches, the strategy re-invokes the last agent with a correction message naming the required field(s). After 3 consecutive failures a
ValidatorStuckExceptionis thrown and the session stops. - If no route has fired yet (the very first turn),
DefaultAgentstarts.
Condition operators
Exactly one operator should be set per condition. Evaluated in the order listed:
| Operator | YAML | Evaluates to true when… |
|---|---|---|
Is |
Is: "value" |
The field's string value equals value (case-insensitive). |
IsNot |
IsNot: "value" |
The field's string value does NOT equal value (case-insensitive). |
Contains |
Contains: "text" |
The field's string value contains text as a substring (case-insensitive). |
Exists |
Exists: true |
The field is present and non-null. |
Exists |
Exists: false |
The field is absent or null. |
Field paths
Field supports dot-notation for nested objects. For example, Field: data.status navigates {"data": {"status": "ok"}}.
StructuredRoute fields
| Field | Type | Default | Description |
|---|---|---|---|
Agent |
string | — | Agent to route to when the condition is true. |
Condition |
object | — | Condition to evaluate against the parsed JSON. |
SourceAgents |
array | any | Optional. Route only fires when the message author is in this list. |
Termination with structured routing
Structured routing has no built-in terminal convention (unlike keyword routing's self-routing APPROVED). Session end is always handled by Termination strategies. A typical pattern is a regex strategy on the last agent in the pipeline:
Termination:
Type: composite
Strategies:
- Type: regex
Pattern: PUBLISHED
AgentNames:
- Publisher
- Type: maxiterations
MaxIterations: 15
Agent instructions for structured routing
Agents in a structured workflow should be instructed to return JSON. The routing is invisible to them — they just need to know what fields to include:
You are a content reviewer. Evaluate the draft and return your decision as a JSON object:
{"review_result": "Yes", "reason": "..."} if the draft meets requirements, or
{"review_result": "No", "reason": "..."} if it needs revision.
Your entire response must be valid JSON.
llm¶
An LLM call picks the next agent each turn based on the conversation history. Useful when routing logic is too complex to express as keywords, or when the handoff decision should be context-sensitive.
Selection:
Type: llm
Model:
ModelId: gpt-4o-mini
Prompt: |
You are an orchestrator. Given the agents: {{$agents}}
And the conversation:
{{$history}}
Which agent should respond next? Reply with only the agent name.
| Field | Required | Description |
|---|---|---|
Model |
yes | The model used for the selection call. Can be a lightweight/fast model since the task is just picking a name. |
Prompt |
no | Custom prompt. Available placeholders: {{$agents}} (list of agent names and descriptions), {{$history}} (recent conversation). Defaults to a built-in prompt if omitted. |
magentic¶
A two-level orchestration loop driven by a dedicated manager LLM. The manager gathers facts about the task, creates a plan, and then coordinates participant agents round by round — selecting the right agent each turn, detecting stalls, and replanning when progress stops. No routing keywords or JSON conditions are required; the manager reasons about the conversation history to decide what happens next.
Selection:
Type: magentic
Magentic:
Model:
ModelId: gpt-4o
MaxRoundCount: 20
MaxStallCount: 3
MaxResetCount: 2
EnablePlanReview: false
How it works
- Orientation (outer loop — once): before the first inner-loop round the manager reads the conversation history and calls
magentic_orientationto produce a brief: a task summary, known facts, an initial plan, an immediate next step, and an initial completion check. - Coordination (inner loop — each round): the manager:
- Calls
magentic_ledger_updateto assess progress: checks whether the task is complete, whether the team is stalling, and which facts have been established. - Selects the best participant for the next step via
magentic_select_speaker. - Invokes the selected participant with a focused, concrete instruction.
- Detects stalls: if
MaxStallCountconsecutive rounds make no forward progress, a replan is triggered. AfterMaxResetCountreplans the session ends with a stall message. - Detects completion: if the ledger update sets
task_complete: true, the session ends cleanly.
Agent instructions
Unlike keyword or structured strategies, Magentic participants do not need to emit special keywords or JSON objects — they just do the work. The manager reads their output and decides what happens next. Keep agent instructions focused on capabilities and behavior, not on routing signals.
Termination is ignored
For Selection.Type: magentic, the entire Termination section is ignored. Session end is controlled exclusively by MaxRoundCount, MaxStallCount, and MaxResetCount in the Magentic block. A Termination section may be present in the config (e.g. to satisfy tooling or document intent) but has no effect. fuseraft validate emits a warning if it finds a non-default Termination config alongside a Magentic selection.
MagenticManagerConfig fields
| Field | Type | Default | Description |
|---|---|---|---|
Model |
string or object | — | Required. Model for the manager LLM. A reasoning-capable model (o3, claude-opus-4-6, gemini-2.5-pro) is strongly recommended — the manager drives all planning and evaluation. |
Instructions |
string | built-in | Optional system instructions for the manager. A well-tested default prompt is used when omitted. |
MaxRoundCount |
int | 20 |
Hard cap on inner-loop coordination rounds before the session terminates. |
MaxStallCount |
int | 3 |
Consecutive rounds without forward progress before a replan is triggered. |
MaxResetCount |
int | 2 |
Maximum number of replanning cycles. After this limit the session terminates with a stall message rather than looping indefinitely. |
EnablePlanReview |
bool | false |
When true, the session pauses after the initial plan is generated and waits for HITL review before proceeding to the coordination loop. |
Termination strategies¶
Configured under Termination.Type. The run stops when any enabled strategy fires.
regex¶
Stops when a message content matches a regular expression.
| Field | Required | Description |
|---|---|---|
Pattern |
yes | .NET regex pattern applied to message content. |
AgentNames |
no | If set, only messages from these agents are evaluated. Useful to restrict the termination check to a specific role (e.g. only the Reviewer can approve). |
Common patterns
| Pattern | Matches |
|---|---|
\bAPPROVED\b |
Word "APPROVED" (whole word) |
TASK COMPLETE |
Literal substring |
\b(DONE\|COMPLETE\|FINISHED)\b |
Any of three words |
maxiterations¶
Stops after a fixed number of agent turns, regardless of content.
All strategy types also respect MaxIterations as a hard safety cap. The maxiterations type only fires on that count; the others also respect it.
composite¶
Stops when any child strategy fires. This is the recommended type for most configs because it combines a content-based check (the task is done) with a safety cap (prevent infinite loops).
Termination:
Type: composite
MaxIterations: 40
Strategies:
- Type: regex
Pattern: \bAPPROVED\b
AgentNames:
- Reviewer
- Type: maxiterations
MaxIterations: 40
Child strategies can themselves be composite.
Choosing a strategy¶
Sequential¶
Use sequential when the flow never changes: the same agents always run in the same order. Good for single-agent configs and simple two-agent pipelines where there is no branching and no conditional routing.
Avoid it once you need any of: loops, early exit, conditional next-agent, or evidence-gated handoffs. Sequential has no routing logic — it cycles unconditionally.
Keyword¶
Use keyword for role-based pipelines where each agent has a defined phase and the handoff is a deliberate signal ("I am done, next phase"). The keyword is noise-free, unambiguous, and easy to enforce — it either appears on its own line or it doesn't.
Keyword is the right default for development teams, review pipelines, and any workflow where:
- The routing decision is predetermined ("when the Developer finishes, always go to Tester")
- You need validators to gate handoffs with real evidence before the route fires
- You want
SourceAgentsto enforce role boundaries mechanically - Loop-back paths exist (bugs found → developer, revision required → developer)
- Stuck detection and HITL escalation matter
The cost is that agents must be reliably instructed to emit the exact keyword. Models generally do this well — a keyword on its own line is a simpler constraint than producing valid structured JSON under pressure.
Structured¶
Use structured when the routing decision is a content decision — when the agent's output itself carries the answer and routing is a consequence of what that answer says, not a side-channel signal added on top.
Structured routing fits naturally when:
- The agent already produces JSON for downstream use and the routing field is part of that output (e.g. a classifier returning
{"category": "billing"}) - The next agent depends on a computed value, not a predetermined phase (e.g. route to an escalation agent when
confidence < 0.7, route to different specialists based onentity_type) - Multiple conditions combine to determine the route (field A exists AND field B equals a value)
- The workflow is a decision tree or triage pipeline, not a sequential team of roles
What structured routing trades away: validators. Structured routes have no Validator field — there is no mechanism to block a route until evidence is present on disk. Enforcement must come entirely from agent instructions. For workflows where evidence gating matters (write a file, run a test, pass a build) keyword routing with validators is more reliable.
The ambiguity risk: if an agent produces multiple JSON-looking blocks in a single response (tool call results, echoed file contents, intermediate data), the strategy takes the first parseable object. Keyword routing has no equivalent ambiguity — a keyword on its own line is unambiguous regardless of what else appears in the response.
LLM¶
Use LLM selection when the routing logic is too complex or context-dependent to express statically. The orchestrator calls a separate model each turn to decide which agent speaks next, based on the conversation history.
It is the most flexible strategy but also the least predictable and the most expensive — every agent turn incurs an additional LLM call. Use it when keyword or structured routing would require an unwieldy number of routes to cover all cases, or when the right next agent genuinely depends on nuanced conversation context that cannot be captured by a field value or keyword.
Magentic¶
Use Magentic when you want a fully autonomous, self-directing team where the orchestrator — not the config — decides the plan and execution order. Rather than declaring routes or conditions, you describe the agents' capabilities and hand the task to the manager.
Magentic fits naturally when:
- The task is exploratory or open-ended and you cannot predict the right execution order in advance
- You want the manager to adapt automatically when agents get stuck, rather than requiring you to encode every failure path as a loop-back route
- Agents are specialists with distinct capabilities (researcher, developer, analyst) and the manager should choose the right one each round based on what has already been done
- You want built-in replanning: if three consecutive rounds make no progress, the manager rethinks the plan rather than repeating the same stuck agent
What Magentic trades away: the determinism and evidence-gating of keyword routing. There are no validators, no SourceAgents restrictions, no RequireHumanApproval on routes. The manager decides everything. If correctness gates matter (e.g. "the developer must actually run the build before handing off to the tester"), keyword routing with validators is more reliable.
Magentic is also more expensive than keyword routing per round: each inner-loop iteration makes at least two manager LLM calls (magentic_ledger_update + magentic_select_speaker) in addition to the participant's call.
Choosing between keyword and structured for the same pipeline¶
The same four-agent dev team can be built with either strategy. The practical difference:
| Keyword | Structured | |
|---|---|---|
| Handoff signal | HANDOFF TO TESTER on its own line |
{"next": "tester"} JSON block |
| Evidence gating | Validators block routes until disk artifacts exist | Instructions only — no mechanical blocking |
| Role enforcement | SourceAgents on every route |
SourceAgents on every route |
| Ambiguity risk | Low — keyword on own line is unambiguous | Moderate — first parseable JSON object wins |
| Stuck detection | Built in — fires after 3 consecutive bad turns | Built in — fires after 3 consecutive non-JSON turns |
| Best for | Phased pipelines, dev teams, review workflows | Classifiers, triage, evaluation-driven routing |
For a human-like team of roles (Planner, Developer, Tester, Reviewer), prefer keyword. The handoff is a declaration, not a data value, and validators give you a safety net that structured routing cannot provide.
For a pipeline where an agent computes a value and routing follows from it, prefer structured. The JSON is already the output — the routing field costs nothing to add.
Designing agent handoff flows¶
The combination of keyword routing, validators, and source-agent restrictions lets you build deterministic pipelines where agents can only advance when they have real evidence, and role boundaries are enforced mechanically.
User task
↓
Planner ──HANDOFF TO DEVELOPER [RequireBrief]──→ Developer
←──────────────REPLAN REQUIRED────────────────────────────────────┐
│ │
(RequireWriteFile + RequireShellPass)
│ │
Tester ←──BUGS FOUND──┐
│ │
(TestReportValid validator) │
│ │
Reviewer ──REVISION REQUIRED──┘
│
(RequireShellPass + RequireReviewJudgement)
│
APPROVED → session ends
Each arrow is a keyword route. Guards in parentheses are validators that block the route until evidence is present. SourceAgents restrictions enforce role boundaries — for example, Developer cannot emit BUGS FOUND (only the Tester can), and the Tester cannot emit REVISION REQUIRED (only the Reviewer can).
Stuck detection is built in: if an agent produces no valid keyword — or a keyword that belongs to a different role — for 3 consecutive turns, a ValidatorStuckException is raised and the session stops with a descriptive error. The same counter covers validator failures, missing keywords, and ambiguous multi-keyword responses; the counters do not reset each other, so alternating failure modes are caught at the same threshold.