Permission Scope
The access a task needs, scope by scope with its risk, granted or withheld by the user for a chosen duration.
≈ 1,061 tokens per use (tool 625 · guidance 271 · typical payload 165)How token costs are estimated
Example: Permission Scope
Book the team offsite for next month and send everyone the invite.
Book the team offsite
To find a date, hold a venue and invite six people.
Allow for
When to use
- The agent needs several kinds of access before starting a task (read a calendar, send email, spend money) and the user hasn't granted them yet.
- The user should decide scope by scope what the agent may touch, and for how long.
When not to use
- The agent is about to take one specific action with known parameters. Use an Approval Request.
- The user is choosing how independently the agent works in general. Use Autonomy Control.
- Access is already granted. Don't ask again; act.
How the agent should use it
- Ask only for what the task needs, lowest risk first, each
labelverb first ("Read your calendar"). - Set
riskhonestly:lowfor reads,mediumfor acting in the user's name,highfor spending, deleting or sharing outside. - Put caps in
limit("Up to $400"), from what the user said. Never invent an amount. - Mark a scope
requiredonly if the task can't run without it. - Offer
durationsthat fit the work:onceandsessionby default,alwaysonly for low-risk, recurring work. - After a grant, use only the scopes returned, for the duration returned. After a deny, don't retry; ask what the user wants instead.
Interaction
- Each scope is a checkbox row. Low- and medium-risk scopes start ticked, high-risk ones start unticked (override with
granted). Required scopes stay ticked. - Each row ends with its risk as a badge: Low blue, Medium orange, High red.
- Ticking a high-risk scope opens a red warning note under the list (an icon, the scope's name, and one plain sentence on what it means for the chosen duration).
- The duration is a radio group of pills; a one-line summary under the list recomposes as the selection changes.
- Allow selected sends the ticked scope ids; it's off while nothing is ticked. Deny all sends a deny. Either one locks the card, and focus moves to the decision record.
- While streaming, scopes arrive one by one and the controls are disabled. Changes are announced to screen readers.
Installation
npx shadcn@latest add https://your-site.com/r/permission-scope.json
Usage
import { tool } from "ai"
import { permissionScopeTool } from "@/components/genui/permission-scope.schema"
const tools = {
[permissionScopeTool.name]: tool({
description: permissionScopeTool.description,
inputSchema: permissionScopeTool.inputSchema,
}),
}import { PermissionScope } from "@/components/genui/permission-scope"
function ToolPart({ part, addToolResult }) {
if (part.type !== "tool-request_permissions") return null
return (
<PermissionScope
{...part.input}
status={part.state === "input-streaming" ? "streaming" : undefined}
result={part.state === "output-available" ? part.output : undefined}
onResult={(result) =>
addToolResult({
tool: "request_permissions",
toolCallId: part.toolCallId,
output: result,
})
}
/>
)
}The result tells the agent what it may use, and for how long:
{ action: "grant", scopes: ["calendar-read", "contacts", "email-send"], duration: "once" }
// or
{ action: "deny" }Schema
| Prop | Type | Notes |
|---|---|---|
question | string? | Shown above the card |
title | string | The task, up to 60 characters |
purpose | string? | One line on why, up to 140 characters |
scopes | { id, label, detail?, risk, limit?, required?, granted? }[] | 1–8, lowest risk first. risk is low, medium or high. limit is data-bound |
durations | ("once" | "session" | "always")[] | Choices offered. Default ["once", "session"] |
duration | string? | Starting duration. Default the first offered |
Host props: status (streaming, ready, granted, denied), onResult, result and className.