Send to human
Use robotrock.sendToHuman() from your shared client module to send an approval request. Set ROBOTROCK_API_KEY in your environment (named keys in Settings → API Keys).
Client setup
// lib/robotrock.ts
import { createClient } from "robotrock";
export const robotrock = createClient({
app: "my-service",
version: process.env.AGENT_VERSION,
webhook: {
url: "https://your-app.com/api/robotrock/webhook",
},
});JSON Forms foundation
RobotRock task forms are built on top of JSON Forms concepts:
- JSON Schema defines the structure and validation of response data.
- UI schema controls field rendering (widgets, labels, placeholders, options).
You provide these via action schema and ui fields.
Minimal example
import { robotrock } from "@/lib/robotrock";
const response = await robotrock.sendToHuman({
type: "budget-approval",
name: "Approve Q4 budget update",
actions: [
{ id: "approve", title: "Approve" },
{ id: "reject", title: "Reject" },
],
});Top-level task fields
import { robotrock } from "@/lib/robotrock";
await robotrock.sendToHuman({
type: "string (required)",
name: "string (required)",
description: "string (optional)",
validUntil: new Date(Date.now() + 2 * 60 * 60 * 1000), // Date or ISO string (optional)
context: {
data: {},
ui: {},
}, // optional
actions: [], // required, at least one action
idempotencyKey: "optional-retry-safe-key",
threadId: "optional-thread-id", // group related tasks; omit to start a new thread
priority: "urgent", // optional — thread-scoped: low | normal | high | urgent
update: { message: "Build finished.", status: "waiting" }, // optional — log an initial thread update
assignTo: {
users: ["alice@acme.com"],
groups: ["finance"],
}, // optional — narrows inbox visibility
version: "1.3.1", // optional — per-task agent version override
});app and agent version are configured on createClient (defaults to AGENT_VERSION from env). Override per task with top-level version on sendToHuman.
The server returns a threadId on response.task.threadId. Reuse it on later tasks to group them in the inbox—see Threads.
Priority (priority)
Optional top-level field to set how important a thread is in the inbox. Values: low, normal, high, urgent. When set on a task, it applies to the whole thread and overwrites any previous priority. Omit on later tasks to leave the thread unchanged. Defaults to normal.
See Priority for semantics, sorting, and examples.
Assignment (assignTo)
Optional top-level field (not stored inside task context JSON):
assignTo?: {
users?: string[]; // tenant member emails
groups?: string[]; // group slugs, e.g. "finance"
};Visibility:
assignTo.groups | Visible to |
|---|---|
omitted / ["all"] | All workspace members |
["admins"] | Tenant admins only |
["finance"] (custom slug) | Members of that group |
- Omitted — task is assigned to the tenant All group; every member sees it.
- Set — only listed users and members of listed groups see the task in the inbox.
{ groups: ["all"] }— same as omittingassignTo.{ groups: ["admins"] }— only workspace administrators see the task (virtual group synced from admin role).
Invalid emails or unknown group slugs return 400. You cannot combine "all" with other group slugs. "admins" may be combined with other groups and users.
Agent version
Set the agent release on createClient so Statistics and feedback analysis can compare human feedback over deploys:
export const robotrock = createClient({
app: "my-agent",
version: process.env.AGENT_VERSION,
});Wire format (set automatically by the SDK):
agent?: { version: string }; // semver, git SHA, or deploy tagawait robotrock.sendToHuman({
type: "budget-approval",
name: "Approve Q4 spend",
actions: [
{ id: "approve", title: "Approve" },
{ id: "reject", title: "Reject" },
],
version: "1.3.1", // optional override of client version
});Agent improvement loop
- Set
versiononcreateClient(or pass per task) - Humans handle tasks (action + feedback forms)
- Run feedback analysis from Statistics (or wait for the weekly cron)
- Before changing agent code, call MCP
get_feedback_analysiswith the sameappandtype - Apply
agentInstructionswhenisHealthyisfalse
See MCP integration for get_feedback_analysis.
Trigger.dev and Vercel Workflow (handled → OTel)
On durable platform tasks, enable trace recording so human decisions appear on the run trace (not stored in RobotRock):
export ROBOTROCK_OTEL_RECORD_HANDLED=trueawait sendToHumanTask.triggerAndWait({
type: "deploy-approval",
name: "Approve deploy",
actions: [{ id: "approve", title: "Approve" }, { id: "reject", title: "Reject" }],
recordOtel: true,
});The SDK adds span robotrock.wait_for_human, event robotrock.task_handled, and attributes such as robotrock.action.id and robotrock.human_wait_ms.
Inbox routing
Set app on createClient to group tasks in the dashboard inbox.
When app is omitted on the client, the API uses your API key name as the inbox bucket.
Webhooks
Configure webhook: { url, headers? } on createClient. The webhook applies to every action. See Webhooks.
Without a webhook, sendToHuman() polls until handled. Set polling on createClient (not on each task). Polling respects each task's validUntil deadline—see Polling.
Platform terminal actions
Reviewers can mark as done or reject the request from the inbox without choosing your task actions. When handled, action.id is a reserved platform id — stop your agent and do not retry:
robotrock:mark-done— closed manually (data: {})robotrock:reject-request— bad agent output (data: { feedback: string })
import { shouldStopAgentForHandledAction, parseHandledOutcome } from "robotrock";
if (result.mode === "handled" && shouldStopAgentForHandledAction(result.actionId)) {
const outcome = parseHandledOutcome({
actionId: result.actionId,
data: result.data,
});
return; // terminal — do not continue
}Exported constants: PLATFORM_MARK_DONE_ACTION_ID, PLATFORM_REJECT_REQUEST_ACTION_ID. See Webhooks — Platform action IDs.
Split references
- For all
contextfields and widgets, see Context. - For complete task payload examples, see Examples under Tasks in the sidebar.
- For all
actionsfields and examples, see Actions. - For grouping related tasks together, see Threads.
- For thread priority and inbox ordering, see Priority.
- For sending status updates to a thread, see Updates.
- For
getTask,cancelTask, and task statuses, see Task lifecycle.