Trigger.dev
Use robotrock/trigger when you need a durable wait for human input inside Trigger.dev workflows.
If you run agents with the Vercel AI SDK inside Trigger workers, see Vercel AI for robotrock/ai tools and approval helpers.
Installation
npm install robotrock @trigger.dev/sdkRegister SDK tasks
Trigger.dev discovers tasks exported from your trigger/ directory. Re-export the RobotRock tasks once:
// trigger/robotrock.ts
export { sendToHumanTask, approveByHumanTask } from "robotrock/trigger";Environment variables
The SDK tasks create a RobotRock client from environment variables inside the task run:
ROBOTROCK_API_KEY(required)ROBOTROCK_BASE_URLorROBOTROCK_API_URL(optional)ROBOTROCK_APP(optional default inbox app bucket; override per task withappon the payload)
Why robotrock/trigger instead of client.sendToHuman() polling?
- Base
robotrock.sendToHuman()falls back to polling when no clientwebhookis configured and is best for regular server scripts. sendToHumanTaskcreates a Trigger wait token, sets the token URL as the client webhook, creates the RobotRock task, and suspends until a human handles an action.
sendToHumanTask (full control)
Call the SDK task from your own Trigger tasks with triggerAndWait():
import { task } from "@trigger.dev/sdk";
import { sendToHumanTask } from "./robotrock";
export const deploymentTask = task({
id: "deployment",
run: async (payload: { version: string; environment: string }) => {
const actions = [
{
id: "approve",
title: "Deploy now",
schema: {
type: "object",
required: ["changeTicket"],
properties: {
changeTicket: { type: "string" },
},
},
},
{
id: "reject",
title: "Block deploy",
schema: {
type: "object",
required: ["reason"],
properties: {
reason: { type: "string" },
},
},
},
] as const;
const waitResult = await sendToHumanTask.triggerAndWait({
type: "deployment",
name: `Deploy ${payload.version} to ${payload.environment}`,
description: "Please review risk and rollout plan",
actions,
});
if (!waitResult.ok) {
throw waitResult.error;
}
const result = waitResult.output;
if (result.actionId === "approve") {
// inferred: { changeTicket: string }
return {
allowed: true,
ticket: result.data.changeTicket,
handledBy: result.handledBy,
};
}
// inferred: { reason: string }
return { allowed: false, reason: result.data.reason };
},
});Simple approvals with approveByHumanTask
For yes/no gates, call approveByHumanTask instead of defining actions yourself.
import { task } from "@trigger.dev/sdk";
import { approveByHumanTask } from "./robotrock";
export const releaseGate = task({
id: "release-gate",
run: async (payload: { releaseId: string }) => {
const waitResult = await approveByHumanTask.triggerAndWait({
type: "release-gate",
name: `Approve release ${payload.releaseId}`,
description: "Final go/no-go check",
});
if (!waitResult.ok) {
throw waitResult.error;
}
const decision = waitResult.output;
return {
approved: decision.actionId === "approve",
handledBy: decision.handledBy,
};
},
});approveByHumanTask always uses these actions:
approvedecline
Wait duration
The Trigger wait token timeout is derived from validUntil on the task. When validUntil is omitted, the SDK defaults to one week for both the RobotRock task deadline and the Trigger wait.
Set validUntil on the payload when you need a different deadline.
Payload reference
await sendToHumanTask.triggerAndWait({
app: "budgeting-service",
type: "budget-approval",
name: "Approve Q4 budget update",
actions: [
{ id: "approve", title: "Approve" },
{ id: "reject", title: "Reject" },
],
});When app is omitted, the SDK uses ROBOTROCK_APP from the environment, or your API key name.
Handler behavior and audit trail
For each action, the SDK sets the Trigger wait token URL as the webhook handler. Handler calls appear in RobotRock audit logs, including status and timing metadata.