Skip to main content
You run an orchestrator that triages tickets and delegates response drafting to a worker agent. You want the full story — who did what, when the handoff happened, and what each agent produced — in one session replay. When you finish this page, you’ll model orchestrator → worker pipelines with sessions, child runs, workflow steps, and handoff events.

The pattern

Complete example

import { Ratri } from "@ratri-sh/sdk";

const ratri = await Ratri.create({
  agent: { key: "support-ops-orchestrator", name: "Support Ops Orchestrator" },
  mode: "monitor",
});

await ratri.withSession(
  {
    kind: "pipeline",
    inputSummary: "Handle urgent enterprise support escalation",
    metadata: { triggerKind: "support_escalation" },
  },
  async (session) => {
    await ratri.withRun(
      {
        sessionId: session.id,
        stepKey: "orchestrator",
        stepName: "Orchestrator",
        stepIndex: 0,
      },
      async (orchestratorRun) => {
        await ratri.withWorkflowStep(
          {
            runId: orchestratorRun.id,
            sessionId: session.id,
            stepKey: "triage-ticket",
            stepName: "Triage ticket",
            stepIndex: 1,
          },
          async () => { /* triage logic */ },
        );

        await ratri.trackHandoffRequested({
          sessionId: session.id,
          sourceRunId: orchestratorRun.id,
          reason: "Delegate customer response draft",
          payloadSummary: { ticketId: "SUP-123", priority: "urgent" },
        });

        await ratri.withChildRun(
          {
            sessionId: session.id,
            parentRunId: orchestratorRun.id,
            stepKey: "response-worker",
            stepName: "Response worker",
            stepIndex: 2,
            role: "worker",
          },
          async (workerRun) => {
            await ratri.trackHandoffCompleted({
              sessionId: session.id,
              runId: workerRun.id,
            });

            await ratri.withTool(
              {
                runId: workerRun.id,
                tool: { name: "support.compose_reply", riskLevel: "low" },
                action: { type: "write", name: "support.compose_reply" },
                resource: { type: "work_item", externalId: "SUP-123" },
              },
              async () => { /* compose draft */ },
            );
          },
        );
      },
    );
  },
);

await ratri.flush();
await ratri.shutdown();

What you’ll see

A session replay showing:
  1. Orchestrator run with triage workflow step
  2. Handoff requested event with ticket metadata
  3. Child worker run with handoff completed
  4. Tool call for composing the reply

Step metadata

Use stepKey, stepName, and stepIndex on runs and workflow steps to keep the timeline ordered and readable:
FieldPurpose
stepKeyStable identifier (orchestrator, response-worker)
stepNameHuman-readable label
stepIndexSort order in session replay
roleorchestrator, worker, or custom

Recipe walkthrough

See Multi-agent handoff recipe for a line-by-line walkthrough of the full example script.

Next steps

Declare capabilities

Declare what each agent in the pipeline may do.

Production release gate

Pipeline with risky CI/CD actions.