Agent
Permissions
- Human-in-the-loop approval for agent tool use (file writes, command execution, etc.)
- Auto-approve patterns for trusted workloads
- Server-side hooks for programmatic permission decisions
- Client-side subscriptions for building approval UIs
Permission request flow
Section titled “Permission request flow”When an agent wants to use a tool (e.g. write a file, run a command), it emits a permissionRequest event. Your code responds with respondPermission to approve or deny.
import { createClient } from "rivetkit/client";import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");const agent = client.vm.getOrCreate(["my-agent"]);
// Listen for permission requestsagent.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("pi", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },});await agent.sendPrompt(session.sessionId, "Create a new file at /home/user/output.txt");import { agentOs } from "rivetkit/agent-os";import { setup } from "rivetkit";import common from "@rivet-dev/agent-os-common";import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({ options: { software: [common, pi] },});
export const registry = setup({ use: { vm } });registry.start();Permission reply options
Section titled “Permission reply options”| Reply | Behavior |
|---|---|
"once" | Approve this single request |
"always" | Approve this and all future requests of the same type |
"reject" | Deny the request |
Server-side auto-approve
Section titled “Server-side auto-approve”Use the onPermissionRequest hook in the actor config to approve permissions server-side without client involvement. This is useful for fully automated pipelines.
import { agentOs } from "rivetkit/agent-os";import { setup } from "rivetkit";import common from "@rivet-dev/agent-os-common";import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({ onPermissionRequest: async (c, sessionId, request) => { // Auto-approve all file operations await c.respondPermission(sessionId, request.permissionId, "always"); }, options: { software: [common, pi] },});
export const registry = setup({ use: { vm } });registry.start();import { createClient } from "rivetkit/client";import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");const agent = client.vm.getOrCreate(["my-agent"]);
// No need to handle permissions on the client. The server auto-approves.const session = await agent.createSession("pi", { 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 to make approval decisions based on the tool or path.
import { agentOs } from "rivetkit/agent-os";import { setup } from "rivetkit";import common from "@rivet-dev/agent-os-common";import pi from "@rivet-dev/agent-os-pi";
const vm = agentOs({ onPermissionRequest: async (c, sessionId, request) => { // `request.description` and `request.params` carry the raw ACP // permission details (the requested tool, paths, etc.). // Auto-approve reads, require manual approval for writes. const description = request.description ?? ""; if (description.toLowerCase().includes("read")) { await c.respondPermission(sessionId, request.permissionId, "always"); } // Anything not handled here is forwarded to the client via the // permissionRequest event. }, options: { software: [common, pi] },});
export const registry = setup({ use: { vm } });registry.start();import { createClient } from "rivetkit/client";import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");const agent = client.vm.getOrCreate(["my-agent"]);
// Only write permissions reach the clientagent.on("permissionRequest", async (data) => { const approved = confirm(`Allow write: ${JSON.stringify(data.request)}?`); await agent.respondPermission( data.sessionId, data.request.permissionId, approved ? "once" : "reject", );});
const session = await agent.createSession("pi", { env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },});await agent.sendPrompt(session.sessionId, "Read config.json and update it");Recommendations
Section titled “Recommendations”- Use
"always"sparingly. It approves all future requests of that type for the session lifetime. - For automated CI/CD pipelines, use the server-side
onPermissionRequesthook to auto-approve without client round-trips. - For interactive applications, subscribe to
permissionRequeston the client and build an approval UI. - If neither the server hook nor the client responds, the agent blocks until a response is given or the action times out.