How to Configure Structured Handoffs Between Agents in Orchestrate for Task Propagation

Orchestrate enables reliable task propagation through typed, verifiable handoff messages that transfer work between agents via cryptographic verification records, with automatic fallback routing when deliveries fail.

The Cursor plugins repository provides a robust multi-agent workflow engine through its Orchestrate skill. Configuring structured handoffs between agents allows complex tasks to propagate reliably across distributed systems while maintaining data integrity and observability. This guide explains how to implement the handoff mechanism using the actual source code from cursor/plugins.

What Are Structured Handoffs?

A handoff is a schema-driven, typed message that transfers responsibility for a unit of work from one agent to another. In orchestrate/skills/orchestrate/scripts/core/handoff.ts, the handoff() function constructs these payloads according to strict JSON schemas defined in scripts/schemas.ts.

Each handoff includes a verification record generated by handoff-verification-record.ts that contains a SHA-256 hash of the payload body and a timestamp. This cryptographic verification ensures that downstream agents receive exactly the data intended, with tamper-evident audit trails for observability tools like the watchdog and checkpoint-restart systems.

Core Architecture Components

The handoff system isolates payload construction, transport, and error handling into distinct layers:

  • Handoff Core (core/handoff.ts): Constructs and validates payloads against schemas before dispatch.
  • Agent Manager (core/agent-manager.ts): Central dispatcher that selects appropriate adapters (Slack, HTTP, etc.) and manages retry logic.
  • Verification Record (core/handoff-verification-record.ts): Generates cryptographic hashes and audit metadata for every handoff.
  • Failure Handoff (core/failure-handoff.ts): Creates safe fallback payloads when primary delivery fails, routing to designated error-handling agents.
  • Adapters (adapters/slack/client.ts): Translate handoff objects into concrete transport formats without modifying core logic.
  • Privacy Redaction (core/redact-body.ts): Strips PII from payloads before logging or persistence.

Step-by-Step Implementation

Creating the Handoff Payload

Upstream agents assemble payloads that conform to the schema requirements. The payload must include identifying information for the task and the target agent.

import { handoff } from '@/orchestrate/skills/orchestrate/scripts/core/handoff';
import { AgentName } from '@/orchestrate/skills/orchestrate/scripts/types';

// Build the payload that complies with the schema defined in scripts/schemas.ts
const payload = {
  taskId: '12345',
  result: { summary: 'All good', data: { /* ... */ } },
  nextAgent: 'reviewer' as AgentName,
};

// Send the handoff to the downstream "reviewer" agent
await handoff(payload, 'reviewer');

Source: [core/handoff.ts](https://github.com/cursor/plugins/blob/main/orchestrate/skills/orchestrate/scripts/core/handoff.ts)

Verification and Dispatch

When handoff() receives the payload, it immediately calls createVerificationRecord() to generate a cryptographic hash and timestamp. The agent manager then selects the appropriate adapter based on the target agent's configuration and dispatches the verified record.

This dispatch process handles transport abstraction—whether routing through Slack, HTTP endpoints, or custom channels—while maintaining the integrity of the verification record. Each adapter implements the required send contract defined in the adapter interface.

Downstream Reception and Validation

Downstream agents receive handoffs through CLI entry points and must validate the verification record before processing. The cli/task.ts file provides the standard entry point for this workflow.

import { verifyRecord } from '@/orchestrate/skills/orchestrate/scripts/core/handoff';
import { parseIncoming } from '@/orchestrate/skills/orchestrate/scripts/cli/util';

async function run() {
  // Pull the raw message (e.g., from Slack)
  const raw = await parseIncoming();

  // Convert raw JSON into a typed handoff verification record
  const record = JSON.parse(raw);

  // Ensure the payload matches the schema and hash
  const isValid = await verifyRecord(record);
  if (!isValid) {
    throw new Error('Invalid handoff verification');
  }

  // Continue processing with the verified payload
  const { taskId, result } = record.payload;
  console.log(`Continuing task ${taskId}`, result);
}

run().catch(console.error);

Source: [cli/task.ts](https://github.com/cursor/plugins/blob/main/orchestrate/skills/orchestrate/scripts/cli/task.ts)

Handling Failures with Fallback Handoffs

When validation fails or the downstream agent is unavailable, the system activates the failure-handoff path. The failureHandoff() function in core/failure-handoff.ts constructs a fallback payload that preserves error context and routes it to a designated error-handler agent.

import { failureHandoff } from '@/orchestrate/skills/orchestrate/scripts/core/failure-handoff';

async function onDeliveryError(originalRecord, err) {
  // Create a fallback payload that includes the error context
  const fallback = {
    originalTaskId: originalRecord.payload.taskId,
    error: err.message,
    retry: false,
  };

  // Route the fallback to the "error-handler" agent
  await failureHandoff(fallback, 'error-handler');
}

Source: [core/failure-handoff.ts](https://github.com/cursor/plugins/blob/main/orchestrate/skills/orchestrate/scripts/core/failure-handoff.ts)

This ensures that workflow state is never lost—failed handoffs become tasks for error-handling agents rather than silent failures.

Extending the System with Custom Adapters

Because handoffs are pure data objects, the system supports new transport mechanisms without modifying core orchestration logic. To add a new adapter:

  1. Create a new directory under adapters/ (e.g., adapters/teams/ or adapters/pubsub/).
  2. Implement the send and receive contracts to translate handoff objects into your transport format.
  3. Register the adapter with the agent manager in core/agent-manager.ts.

The Slack adapter at adapters/slack/client.ts demonstrates this pattern by converting handoff verification records into Slack API messages while preserving the underlying payload structure.

Summary

  • Structured handoffs in Orchestrate are schema-verified messages that enable reliable task propagation between agents in the cursor/plugins repository.
  • Each handoff generates a cryptographic verification record with SHA-256 hashing to ensure payload integrity.
  • The agent manager abstracts transport concerns, routing handoffs through adapters like Slack or HTTP without changing core logic.
  • Failure handoffs provide automatic fallback routing to error-handling agents when delivery fails.
  • Redaction utilities ensure PII is stripped from logs while preserving operational metadata.

Frequently Asked Questions

What makes a handoff "structured" in the Orchestrate system?

A handoff is structured because it must conform to a strict JSON schema defined in scripts/schemas.ts and carry a verification record with cryptographic hashing. This structure ensures type safety, payload integrity, and observability across the workflow chain.

How does the system handle network failures or unavailable agents?

When delivery fails, the failureHandoff() function in core/failure-handoff.ts automatically generates a fallback payload containing error details and routes it to a designated error-handler agent. This prevents workflow stalls and ensures visibility into delivery problems.

Can I integrate custom communication channels beyond Slack?

Yes. The architecture supports adding new adapters under the adapters/ directory by implementing the standard send/receive interface. The system treats handoffs as pure data objects, so you can add Teams, Pub/Sub, or proprietary channels without modifying the core handoff logic in core/handoff.ts.

How is sensitive data protected during handoff propagation?

The core/redact-body.ts utility automatically strips PII from payloads before logging or persistence. This ensures that while verification records maintain hash integrity for audit trails, actual sensitive content is sanitized according to data-privacy constraints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →