Hand Off Work to a Managed Agent
Code is fast, cheap, and predictable. AI is better for work that needs judgment, for example a summary, or a decision about an unusual case. A code automation can do both: code does the fixed steps, then it gives the rest to the managed agent.
Turn on handoffs
Section titled “Turn on handoffs”Set mode and agent in the deployment:
export const deployment = { mode: "code_with_optional_agent", agent: { instructions: "You triage failed deploys for the platform team. Be brief." }, subscriptions: { /* ... */ },} satisfies AutomationDeployment;agent.instructionsapply to every handoff.- With
mode: "code"(the default), handoffs fail the run.
Stage a handoff
Section titled “Stage a handoff”export default class { async onFailure(ctx: AutomationContext, event: IntegrationEvent) { const logs = await readLogs(ctx, event); if (logs.isErr()) return err(logs.error); if (logs.value.knownFlake) return ctx.setOutput({ action: "ignored", reason: "known flake" });
const staged = await ctx.agent.run({ effectKey: `triage:${event.id}`, instructions: "Find the cause of this deploy failure. Post a short summary in the Space.", context: { failedStep: logs.value.step, lastLines: logs.value.tail }, }); if (staged.isErr()) return err(staged.error); return ctx.setOutput({ action: "handed_off" }); }}- Type starts the AI only after the method succeeds. If the method fails, no handoff starts.
- Type gives the AI the full source event. Put other evidence in
context. - The AI works in the Space, with the Space’s connections and skills.
- A staged handoff is not a delivered result. The run output shows that you staged it.
Let a model decide if the AI is needed
Section titled “Let a model decide if the AI is needed”ctx.agent.evaluate stages a handoff with a question. After the method succeeds, a model answers it:
await ctx.agent.evaluate({ effectKey: `review:${event.id}`, instructions: "Review this customer message and draft a reply.", context: { message: text }, evaluation: { question: "Does this message need a reply from the team?", criteria: { skip: "Thanks, automatic replies, or messages that need no action.", invoke_agent: "Questions, complaints, or requests that need a person.", }, },});- If the model is confident (0.8 or more) that the answer is
skip, no AI starts. - In all other cases, the AI starts.
- Your code does not get the answer. For answers in code, use AI questions in a matcher.
Give the AI specific tools
Section titled “Give the AI specific tools”Add tools to limit the handoff to tools that you choose:
await ctx.agent.run({ effectKey: `issue:${event.id}`, instructions: "Create one Linear issue for this failure.", tools: [{ service: "linear", name: "create_issue", organizationIntegrationId: "orgint_abc123" }],});You can list at most 16 tools.
effectKey: 1 to 500 characters. Use the same key for the same logical handoff.instructions: 1 to 10,000 characters.- At most 100 handoffs in a run.
- The same
effectKeywith the same input counts one time. The same key with different input fails the run.
When to use code only
Section titled “When to use code only”Use mode: "code" for reads, filters, comparisons, text formats, checkpoints, and writes that have clear rules. mode: "code" turns off handoffs to the managed agent. It does not turn off AI filters: a matcher with AI questions still calls a model and uses AI. Without handoffs and AI filters, a run uses no model, costs less, and gives the same result each time. Add a handoff only for the part that needs judgment.