Skip to content
GitHub Get Started
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

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.

client.ts
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 requests
agent.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");
ReplyBehavior
"once"Approve this single request
"always"Approve this and all future requests of the same type
"reject"Deny the request

Use the onPermissionRequest hook in the actor config to approve permissions server-side without client involvement. This is useful for fully automated pipelines.

server.ts
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();

Inspect the permission request to make approval decisions based on the tool or path.

server.ts
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();
  • Use "always" sparingly. It approves all future requests of that type for the session lifetime.
  • For automated CI/CD pipelines, use the server-side onPermissionRequest hook to auto-approve without client round-trips.
  • For interactive applications, subscribe to permissionRequest on 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.