Approvals
When an agent wants to use a tool (write a file, run a command, etc.), it asks for permission. You approve or deny that request from the client, either interactively or automatically.
- Human-in-the-loop: subscribe to
permissionRequeston the client and respond per-request. - Auto-approve: subscribe to
permissionRequestand immediately reply"always"— no human prompt. - Selective approval: inspect the request, approve some automatically and prompt the human for others.
Permission request flow
Section titled “Permission request flow”When an agent wants to use a tool, it emits a permissionRequest. Subscribe to the event on the client and call respondPermission(sessionId, permissionId, reply). If nothing responds, the request blocks until a reply arrives, then rejects after 120 seconds.
import { createClient } from "@rivet-dev/agentos/client";import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });const agent = client.vm.getOrCreate("my-agent");
// Listen for permission requests over a live connection. The payload is// inferred from the actor's event schema, so no cast is needed.const conn = agent.connect();conn.on("permissionRequest", async (data) => { console.log("Permission requested:", data.request);
// Approve this single request. await agent.respondPermission( data.sessionId, data.request.permissionId, "once", );});
const session = await agent.createSession("claude", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },});await agent.sendPrompt(session.sessionId, "Create a new file at /home/agentos/output.txt");The permissionRequest event payload:
data.sessionId: the session the request belongs to.data.request.permissionId: the id to pass back torespondPermission.data.request.description: human-readable summary of the requested action.data.request.params: raw ACP permission details (requested tool, paths, etc.).
Reply options for respondPermission:
| Reply | Behavior |
|---|---|
"once" | Approve this single request |
"always" | Approve this and all future requests of the same type |
"reject" | Deny the request |
Patterns
Section titled “Patterns”Auto-approve
Section titled “Auto-approve”Subscribe to permissionRequest and reply immediately, with no human in the loop. Useful for fully automated pipelines.
- Inspect:
data.request.permissionId,data.request.description, anddata.request.params. - Reply
"always"so future requests of the same type are approved without another round-trip.
import { createClient } from "@rivet-dev/agentos/client";import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });const agent = client.vm.getOrCreate("my-agent");
// Auto-approve every request as it arrives. Reply "always" so future requests// of the same type are approved without another prompt.const conn = agent.connect();conn.on("permissionRequest", async (data) => { console.log("auto-approving", data.sessionId, data.request.permissionId); await agent.respondPermission(data.sessionId, data.request.permissionId, "always");});
const session = await agent.createSession("claude", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },});await agent.sendPrompt(session.sessionId, "Write files as needed");Selective approval
Section titled “Selective approval”Inspect the permission request in the client handler to make approval decisions based on the tool or path. Approve some automatically and prompt the human for the rest.
import { createClient } from "@rivet-dev/agentos/client";import type { registry } from "./server";
const client = createClient<typeof registry>({ endpoint: "http://localhost:6420" });const agent = client.vm.getOrCreate("my-agent");
// `data.request.description` and `data.request.params` carry the raw ACP// permission details (the requested tool, paths, etc.). Inspect them to decide// which requests to approve automatically and which to send to a human.const conn = agent.connect();conn.on("permissionRequest", async (data) => { const description = data.request.description ?? ""; if (description.toLowerCase().includes("read")) { // Auto-approve read requests. await agent.respondPermission(data.sessionId, data.request.permissionId, "once"); return; } // Everything else goes to a human. const approved = confirm(`Allow: ${JSON.stringify(data.request)}?`); await agent.respondPermission( data.sessionId, data.request.permissionId, approved ? "once" : "reject", );});
const session = await agent.createSession("claude", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },});await agent.sendPrompt(session.sessionId, "Read config.json and update it");- For interactive applications, subscribe to
permissionRequeston the client and build an approval UI. - If the client doesn’t respond, the agent blocks until a response is given or the action times out.