Skip to main content
Agent

Approvals

Handle native ACP permission options with durable AgentOS correlation.

Set a session’s immutable permissionPolicy when calling openSession:

  • reject_all prefers a native reject_once option, then reject_always, and fails with permission_policy_unsatisfied when neither exists.
  • allow_all (the default) prefers allow_once, then allow_always.
  • ask durably records the exact ACP RequestPermissionRequest in the ordinary sequenced session-event stream.

This controls how AgentOS answers an adapter’s native ACP permission request. It does not grant VM filesystem or network permissions, change which tools the adapter exposes, or become ACP adapter configuration.

Subscribing to session events does not enable interactive approval. You must set permissionPolicy: "ask" in openSession; if it is omitted, the default allow_all policy resolves requests automatically and no permission_request event is emitted or persisted.

Human in the loop

With ask, respond using the AgentOS requestId plus one of the exact optionId values supplied by the adapter. Do not translate options into AgentOS-specific once/always strings.

The permission_request session-event variant contains:

  • sessionId: stable public AgentOS session ID from the durable event envelope.
  • requestId: globally unique AgentOS correlation ID; the adapter JSON-RPC ID is private.
  • toolCall, options, and optional _meta: exact native ACP request fields exposed directly, without a nested request object.

respondPermission requires an explicit sessionId and returns accepted or not_pending with a specific terminal reason. The first valid response wins atomically. Invalid options fail with invalid_permission_option and list the offered IDs. accepted means the decision reached the active ACP waiter; it does not mean the tool operation succeeded.

Permission requests have no sidecar expiry. They remain pending until answered or terminated by prompt cancellation, adapter exit, session deletion, or VM shutdown. RivetKit’s actor-wide safety bound defaults to about 24.8 days rather than the old 15-minute action timeout. Both the request and its accepted response are durable history entries, so reconnecting consumers subscribe, read history after their last sequence, and deduplicate by (sessionId, sequence).

Automatic policy

For a fully automated session, omit permissionPolicy or choose allow_all explicitly. No permission event or client round-trip is required.

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");

// allow_all selects an adapter-supplied allow option without a client round-trip.
await agent.openSession({
	agent: "pi",
	permissionPolicy: "allow_all",
	env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
await agent.prompt({
	content: [{ type: "text", text: "Write files as needed" }],
});

For unattended fail-closed work, choose reject_all explicitly. ACP approval is advisory; VM filesystem, network, and process permissions remain the security boundary. Automatically handled requests are neither emitted nor persisted.