---
name: agentbyte-handoff-orchestration
description: Guide for creating Handoff multi-agent orchestration in Agentbyte (Chapter 7.6). Use this when agents should explicitly transfer control to named colleagues with `HANDOFF: <agent_name>` instead of the orchestrator centrally selecting every next turn.
license: MIT
---

Use this skill when implementing multi-agent collaboration where the currently speaking agent should decide which specialist goes next.

## Inputs to confirm
- Which agent should start first
- What exact handoff signal agents should emit
- What should happen when no valid handoff signal is present
- What termination condition should actually stop the run
- Whether colleagues should be injected into agent context automatically

## Pattern: Basic Handoff Orchestration

```python
import asyncio

from agentbyte import Agent, HandoffOrchestrator, UserMessage
from agentbyte.llm import OpenAIChatCompletionClient
from agentbyte.termination import MaxMessageTermination, TextMentionTermination


async def main() -> None:
    client = OpenAIChatCompletionClient.from_api_key(model="gpt-4o-mini")

    researcher = Agent(
        name="researcher",
        description="Research specialist for concise factual context",
        instructions=(
            "Research the topic and gather the key facts. "
            "When the writer should continue, write exactly: HANDOFF: writer"
        ),
        model_client=client,
    )

    writer = Agent(
        name="writer",
        description="Writing specialist for clear user-facing drafts",
        instructions=(
            "Write a concise draft using the available context. "
            "When the reviewer should inspect it, write exactly: HANDOFF: reviewer"
        ),
        model_client=client,
    )

    reviewer = Agent(
        name="reviewer",
        description="Review specialist for clarity and correctness",
        instructions=(
            "Review the draft. If it is ready, say APPROVED. "
            "If it needs revision, give concise feedback and write exactly: HANDOFF: writer"
        ),
        model_client=client,
    )

    termination = TextMentionTermination("APPROVED") | MaxMessageTermination(12)

    orchestrator = HandoffOrchestrator(
        agents=[researcher, writer, reviewer],
        termination=termination,
        entry_agent_name="researcher",
        fallback_strategy="round_robin",
        handoff_signal_prefix="HANDOFF:",
        inject_colleagues_context=True,
        max_iterations=10,
    )

    task = UserMessage(
        content="Write a short note about solar energy benefits.",
        source="user",
    )
    result = await orchestrator.run(task)

    print(f"Stop reason: {result.stop_message.content}")
    print(f"Handoffs: {result.pattern_metadata['handoff_counts']}")
    print(f"Last target: {result.pattern_metadata['last_handoff_target']}")


asyncio.run(main())
```

## Pattern: Streaming Handoff Orchestration

```python
from agentbyte.messages import Message
from agentbyte.types import OrchestrationEvent, OrchestrationResponse

async for item in orchestrator.run_stream(task, verbose=True):
    if isinstance(item, Message):
        print(f"[{item.source}] {item.content}")
    elif isinstance(item, OrchestrationEvent):
        print(f"[EVENT] {item}")
    elif isinstance(item, OrchestrationResponse):
        print(f"Complete: {item.stop_message.content}")
```

## How Handoff Routing Works

1. The first turn goes to the entry agent.
2. The current agent may emit `HANDOFF: <agent_name>` in its response.
3. The orchestrator parses the latest assistant response for that signal.
4. If the target agent exists, control transfers there.
5. If no valid signal is present, the configured fallback strategy is used.

This means:
- agents own the routing intent
- the orchestrator still owns validation, execution safety, and shared state

## Constructor Surface

```python
orchestrator = HandoffOrchestrator(
    agents=[agent1, agent2, agent3],
    termination=termination_condition,
    entry_agent_name="agent1",
    fallback_strategy="round_robin",   # or "entry"
    handoff_signal_prefix="HANDOFF:",
    inject_colleagues_context=True,
    max_iterations=50,
    history_policy=...,
)
```

## Fallback Strategies

Use `fallback_strategy="round_robin"` when:
- you want forward progress even if an agent forgets to hand off
- multiple specialists can still contribute usefully

Use `fallback_strategy="entry"` when:
- one lead agent should always re-triage the task
- the entry agent acts like a hub/router

## Colleagues Context Injection

When `inject_colleagues_context=True`, each agent receives a short block listing:
- the other agents it can hand off to
- their descriptions
- the reminder to use `HANDOFF: <name>`

Keep this enabled unless you already embed the routing protocol clearly in agent instructions and need tighter context control.

## History Policy

`HandoffOrchestrator` still uses `HistoryContextPolicy` for execution context:

```python
from agentbyte import AgentHistoryPolicy, HistoryContextPolicy

history_policy = HistoryContextPolicy(
    default=AgentHistoryPolicy(window="full", format="text"),
    per_agent={
        "reviewer": AgentHistoryPolicy(
            window="recent",
            message_limit=4,
            format="markdown",
        )
    },
)
```

Important mental model:
- handoff chooses who acts next
- history policy chooses what that agent sees

## Recommended Termination Patterns

### Basic reviewer approval flow

```python
termination = TextMentionTermination("APPROVED") | MaxMessageTermination(12)
```

### Reviewer-specific approval in the same message

```python
from agentbyte.termination import MaxMessageTermination, PredicateTermination

termination = (
    PredicateTermination(
        lambda msgs: any(
            getattr(m, "source", None) == "reviewer"
            and "APPROVED" in str(getattr(m, "content", ""))
            for m in msgs
        ),
        reason="Reviewer approved",
    )
    | MaxMessageTermination(12)
)
```

### Production-oriented safety bundle

```python
from agentbyte.termination import (
    MaxMessageTermination,
    PredicateTermination,
    TimeoutTermination,
    TokenUsageTermination,
)

termination = (
    PredicateTermination(...)
    | TimeoutTermination(120)
    | TokenUsageTermination(8_000)
    | MaxMessageTermination(12)
)
```

## Pattern Metadata

After completion, `result.pattern_metadata` includes:
- `entry_agent`
- `fallback_strategy`
- `handoff_signal_prefix`
- `handoff_counts`
- `last_handoff_target`
- inherited base metrics like `iterations_completed` and `message_count`

## Guardrails

- **Termination Still Required:** Handoff decides who goes next, not when to stop.
- **Stable Agent Names:** Keep agent names short and unambiguous because routing depends on matching text.
- **Explicit Protocol:** Tell agents to emit the exact signal, e.g. `HANDOFF: reviewer`.
- **Fallback Is Important:** Missing or malformed handoff text should not end the run or crash the orchestrator.
- **Colleague Descriptions Matter:** The injected colleagues block is more useful when agent descriptions clearly explain specialization.
- **Text-Based Routing:** This pattern is lighter than AI-driven selection, but also less strict than structured-output routing.

## When to Use Handoff vs Other Patterns

| Use Handoff When | Use AI-Driven When | Use Round-Robin When | Use Plan-Based When |
|------------------|--------------------|----------------------|---------------------|
| The current agent usually knows the best next specialist | A central selector model should reason over the whole state | All agents should contribute in fixed order | The task has explicit sequential phases |
| You want decentralized routing | You want selector reasoning as a separate coordination call | Deterministic sequencing matters most | You need evaluator-driven retries and explicit step structure |
| You want specialist chaining like research -> write -> review -> revise | You want more robust routing than a text signal | You want the simplest possible coordination | You want decomposition before execution |

## Common Use Cases

1. Research -> write -> review workflows
2. Reviewer -> writer revision loops
3. Support triage -> billing specialist -> support resolution flows
4. Specialist chains where the current agent can naturally identify the next specialist
5. Lower-cost adaptive routing without a separate selector model
