Tool Permissioning Tiers
Classify tools by risk and enforce tiered permissions: auto-allow, session-allow, always-ask, and never - enforced in the harness.
The route
4 steps to Done
- 01
Classify the toolset by risk
Reversibility and blast radius decide the tier.
Preview prompt + verify gate ▾ Hide ▴
Classify every tool. Tiers: SAFE (read-only, no side effects: file reads, searches, listings) - auto-allow; SESSION (mutating but contained and reversible: file edits in the workspace, git commits) - first use asks, approval covers the session; ASK (consequential or hard to reverse: shell commands by default, network calls, package installs) - every use asks unless a narrow rule says otherwise; NEVER (catastrophic or out of scope: credential file access, force-push, bulk deletion) - blocked outright. For parameterized tools, write argument rules: run_command with a read-only known-safe binary (ls, cat, git status) may drop to SAFE; anything matching destructive patterns (rm -rf, DROP TABLE, force flags) escalates to ASK or NEVER. Deliver the classification table with a one-line justification per tier assignment.
- ✓ Every tool assigned with justification
- ✓ Parameter rules cover the shell
- ✓ NEVER list includes credential and bulk-destructive patterns
- 02
Enforce tiers in dispatch
One chokepoint, impossible to bypass.
Preview prompt + verify gate ▾ Hide ▴
Implement enforcement in the single tool-dispatch path. Before any handler executes: resolve the tool + arguments to a tier (tool default, then parameter rules); SAFE executes; SESSION checks the grant store, asking on miss; ASK always requests approval; NEVER returns a refusal immediately. Approval requests present: tool, full arguments (with diffs for file changes), tier, and reason the agent gave. Denials return a structured message to the model ('permission denied for X: [user reason]') so it can adapt - the loop must continue gracefully, not crash. Unclassified tools hard-default to ASK with a review flag. Test each tier path including a denial mid-task.
- ✓ No dispatch path bypasses the check
- ✓ Approval prompts show full arguments
- ✓ Denial keeps the loop alive and adapting
- 03
Implement session grants and revocation
Convenience with an expiry date.
Preview prompt + verify gate ▾ Hide ▴
Build the session grant store. On SESSION-tier approval, record {tool, scope (exact tool or tool+argument-pattern), granted_at, expires: session end}; subsequent matching calls skip the prompt. Include scope options in the approval UI: 'allow once', 'allow for session', and where sensible 'allow for this file/directory'. Revocation: a command lists active grants and revokes any; revoked tools re-ask. Grants never persist across sessions in v1 (persistent grants are a deliberate later decision with their own review). Test: approve an edit tool for the session, verify subsequent edits flow, revoke, verify the re-ask.
- ✓ Grant scopes work as selected
- ✓ Revocation takes effect immediately
- ✓ Nothing persists past the session
- 04
Log decisions and drill the system
Auditability plus a live-fire test.
Preview prompt + verify gate ▾ Hide ▴
Complete the system. LOGGING: every permission decision appends {timestamp, tool, arguments-digest, tier, decision (auto/user-approved/denied/blocked), grant-used, session} to an append-only log; verify you can reconstruct 'what ran with what authority' for a full session. DRILL: run a realistic task and inject the dangerous moments - have the agent attempt a NEVER-pattern command (verify block + honest report), an unclassified tool (verify ASK default), and a destructive-flag variant of an approved tool (verify parameter escalation catches it). Review the log afterward and confirm it tells the whole story. Fix any gap the drill exposes.
- ✓ Log reconstructs authority per session
- ✓ All three drill injections behaved correctly
- ✓ Gaps fixed and re-drilled
Research-backed