Open Source · v0.1.0 · 430 Tests Passing · PyPI Live

Zero Context Loss
Between AI Agents

When Agent A hands off to Agent B, the full context — decisions, actions, conversation state — survives the transition intact. No repetition, no dropped threads.

430
Tests Passing
19
API Endpoints
3
Framework Adapters
<5min
Quick Start

Three steps. Zero context loss.

HandoffRail sits between your agents as structured middleware. Create a packet, claim it, chain it — context flows forward, never backward.

1

Create

Agent A finishes its work and creates a structured handoff packet — packing decisions, conversation state, pending actions, and dependencies into one validated payload.

2

Claim

Agent B (or a human) claims the packet, instantly receiving the full context. No repetition, no "what were we talking about?" — everything is there.

3

Chain

Need more agents? Chain handoffs create linked packets that carry context forward across any number of agents — with full audit trails at every step.

Everything you need for
seamless handoffs

Built for production multi-agent systems. Structured packets, human checkpoints, framework adapters, and first-class observability.

📦

Structured Handoff Packets

Validated JSON schema with decisions, conversation state, actions, dependencies, and artifacts. Versioned for forward compatibility.

🧑‍⚖️

Human-in-the-Loop

Built-in HITL checkpoints with approval workflows, configurable timeouts, and escalation. Critical decisions get human eyes.

🔗

Chain Handoffs

Link packets into multi-agent workflows. Each chain preserves parent context with full audit trail across the entire sequence.

🪝

Webhooks + HMAC

Event-driven notifications with HMAC-SHA256 signed payloads. Subscribe to packet lifecycle events and build reactive systems.

🐍

Python SDK

Sync + async clients, fluent builder pattern, LangChain & CrewAI adapters, and a base class for custom framework integrations.

⌨️

CLI

7 commands for packet operations. Create, claim, respond to HITL, view history — all from your terminal. handoffrail serve for local dev.

🐳

Docker + PostgreSQL

One-command local dev with Docker Compose. Production setup with PostgreSQL 16, Redis 7, and health monitoring endpoints.

🔒

Auth + Rate Limiting

API key auth with tier-based rate limiting. Free, Pro, and Business tiers with enforced quotas for agents, keys, and packet size.

📊

Observability

Prometheus metrics, structured logging with structlog, health/readiness probes, and full event history for every packet.

Ship in minutes,
not days

From zero to your first handoff in under 5 minutes. SDK, REST, or CLI — pick your weapon.

from handoffrail.sdk import HandoffRailClient

# Connect to HandoffRail
client = HandoffRailClient(
    base_url="http://localhost:8080/api/v1",
    api_key="hr_your_key_here"
)

# Create a handoff packet
packet = client.create_packet(
    source_agent={"id": "sales-01", "name": "SalesBot", "framework": "langchain"},
    target_agent={"id": "billing-01", "name": "BillingBot"},
    summary="Customer wants to upgrade to Business tier",
    priority="high",
    tags=["upgrade", "business-tier"]
)

# Agent B claims the packet
claimed = client.claim_packet(
    packet.id,
    agent_id="billing-01",
    agent_name="BillingBot"
)

# Mark as complete
client.complete_packet(packet.id)
# Create a handoff packet
curl -X POST http://localhost:8080/api/v1/packets \
  -H "X-API-Key: hr_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "metadata": {
      "source_agent": {"id": "sales-01", "name": "SalesBot", "framework": "langchain"},
      "target_agent": {"id": "billing-01", "name": "BillingBot"},
      "priority": "high"
    },
    "context": {
      "summary": "Customer wants to upgrade",
      "conversation_state": [
        {"role": "user", "content": "I want to upgrade"},
        {"role": "agent", "content": "Let me hand you to billing."}
      ]
    },
    "decisions": [],
    "actions": {
      "pending": [{"id": "a1", "description": "Process upgrade", "assignee": "billing-01"}],
      "completed": [],
      "failed": []
    }
  }'

# Claim it
curl -X POST http://localhost:8080/api/v1/packets/{id}/claim \
  -H "X-API-Key: hr_your_key" \
  -d '{"agent_id": "billing-01", "agent_name": "BillingBot"}'
# Start the server
handoffrail serve --port 8080

# Create a packet
handoffrail create \
  --source-id sales-01 \
  --source-name SalesBot \
  --target-id billing-01 \
  --summary "Customer upgrade request" \
  --priority high

# List pending packets
handoffrail list --status created --priority high

# Claim a packet
handoffrail claim abc-123 --agent-id billing-01 --agent-name BillingBot

# Respond to HITL checkpoint
handoffrail respond abc-123 --response "Approved" --responded-by manager@company.com

# View audit trail
handoffrail history abc-123
from handoffrail.sdk import HandoffPacket

# Fluent builder for complex handoffs
packet = (
    HandoffPacket.builder()
    .from_agent("sales-01", "SalesBot", framework="langchain")
    .to_agent("billing-01", "BillingBot")
    .with_summary("Customer wants Business tier upgrade")
    .with_conversation(messages=[
        {"role": "user", "content": "I want to upgrade"},
        {"role": "agent", "content": "Let me connect you to billing"},
    ])
    .with_decision("Proceed with upgrade", rationale="Customer eligible")
    .with_action("Process payment", assignee="billing-01", priority="high")
    .with_dependency("stripe-api", type="api", description="Payment gateway")
    .with_hitl(reason="High-value upgrade", question="Approve upgrade?")
    .with_priority("high")
    .with_tags(["upgrade", "business-tier"])
    .build()
)
from handoffrail.sdk import HandoffRailClient
from handoffrail.integrations.langchain import LangChainAdapter, HandoffRailTool

client = HandoffRailClient(base_url="http://localhost:8080/api/v1", api_key="hr_...")
adapter = LangChainAdapter(client=client, agent_id="sales-01", agent_name="SalesBot")

# Create handoff from LangChain conversation
packet = adapter.create_handoff(
    target_agent_id="billing-01",
    target_agent_name="BillingBot",
    summary="Customer upgrade request",
    conversation_state=adapter.extract_conversation(chat_history),
)

# Receive: poll for unclaimed packets
packets = adapter.poll_for_handoff()
claimed = adapter.claim_handoff(packets[0].id)

# Resume conversation from handoff
messages = adapter.resume_conversation(claimed)

# Use as LangChain Tool
tool = HandoffRailTool(client=client)

Up and running in
under 5 minutes

Clone, install, create your first handoff. That's it.

1

Clone & Install

Get the code and install the server with dev dependencies.

git clone https://github.com/MelaBuilt-AI/HandoffRail.git cd handoffrail/server && pip install -e ".[dev]" pip install handoffrail-sdk # SDK from PyPI
2

Start the API

Fire up the FastAPI server with auto-reload for development.

uvicorn app.main:app --reload --port 8080
3

Create Your First Handoff

Use the SDK, REST, or CLI — your first handoff packet in seconds.

from handoffrail.sdk import HandoffRailClient client = HandoffRailClient(base_url="http://localhost:8080/api/v1", api_key="hr_...") packet = client.create_packet( source_agent={"id": "agent-a", "name": "Agent A"}, target_agent={"id": "agent-b", "name": "Agent B"}, summary="First handoff!", )

Start free. Scale when
you're ready.

Open source, self-hosted forever. Cloud tiers for teams that need more.

Free
$0
forever
Perfect for trying HandoffRail and small projects.
  • 5 handoffs / day
  • 2 agents
  • 1 API key
  • 64 KB packet size
  • HITL checkpoints
  • Webhooks
  • Audit trail
Self-Host Free
Business
$99
/ month
For orgs with serious multi-agent infrastructure.
  • Unlimited handoffs
  • 50 agents
  • 25 API keys
  • 1 MB packet size
  • HITL checkpoints
  • Unlimited webhooks
  • Full audit + export
  • 10,000 req / hr
  • Priority Slack support
Contact Sales

Ready to eliminate context loss?

Get started in under 5 minutes. Open source, self-hosted, production-ready.

⚡ Get Started on GitHub 📦 Install from PyPI