What are Tool Policies?
Tool Policies monitor and control actions taken by AI coding tools in your organization. Create policies to track, warn on, or block terminal commands executed by AI agents or MCP tool calls made through integrated servers like GitHub, Linear, Sentry, and more. Skill policies work the other way. They don’t stop an action. They make the agent load your guidance before it acts. Every policy type has a worked example under Examples. Dashboard: Policies → Agentic Use (gateway.getunbound.ai/policies/agentic-use)Policy Types
Create Policy asks what you want to monitor:Terminal Commands
Monitor shell commands run by the agents Unbound governs — Claude Code, Claude Cowork, Cursor, Codex, GitHub Copilot, Augment Code and Pi (Beta). Agent Coverage has what each one supports. The file families —read_file, write_file and delete_file — also cover the agent’s own file tools, not just the shell. A policy on delete_file catches an agent deleting a path with its built-in delete tool as well as with rm, so you write the rule once rather than per route.
Which of those tools are covered varies by agent:
So a
delete_file rule catches Codex deleting through the shell (rm) but not through its own tooling, and Copilot and Pi have no delete tool to catch. A rule that must hold on every agent should target the shell as well.
This holds for Block, Warn and Require Slack Approval. An Audit policy on its own covers the shell route but not the agent’s own file tools — pair it with one live rule on the same family, or start the rule on Warn, if you need both routes covered.
- Select a Command Family (e.g.,
delete_file,git_action,remote_access) - Set Match Against to the command field you want to inspect (e.g.,
path,branch, orAny) - Define a Pattern to match specific paths, branches, or operations
- Supports exact match, glob patterns (
/etc/*), and regex (.*\.env$)
Unless you say which you wrote, Unbound reads your pattern as regex, glob or exact from its syntax — and the reading can surprise you.
.*bastion.* comes out as a regex; prod.* as a glob in which the . is a literal dot; *prod*|*production* as a regex that isn’t valid, so it matches nothing.Settle it with a prefix — regex:, glob: or exact:. regex:prod.*, regex:prod|production and glob:*prod* all do what they look like. (A glob already matches production from *prod*, so the regex is often unnecessary.)Globs are anchored to the whole value, regexes are an unanchored substring search, and both ignore case. A plain string with no wildcards is an exact match, so prod on its own does not match production.MCP Actions
Monitor tool calls made through MCP (Model Context Protocol) servers.- Select an MCP Service — a canonical service such as GitHub, Linear, or Slack. This is the required first field (“Select a service…”). Picking a service applies the policy across every connected MCP server that maps to it, so you don’t name individual server instances.
- Select one or more MCP Tools to monitor (e.g.,
create_pull_request,create_issue). A service and at least one tool are both required.
read, write, or destructive. Action type, and targeting one specific raw server instance instead of the canonical service, are available only through the policy API — the create-policy modal always targets a canonical MCP Service and its tools.
If you are building an MCP server that calls back into Unbound for policy checks, manage your MCP credentials on the MCP Connections page in the dashboard.
Skills
A skill policy makes the agent load your guidance before it acts. You attach a skill, which is aSKILL.md body, and say when it applies. Unbound then has the agent invoke the skill first. A skill policy never stops work for good. Where an action must stop, use Block or Require Slack Approval on a terminal or MCP policy.
Pick one trigger:
Then fill in the skill:
- MCP tool calls never trigger a skill policy.
- Unbound installs the skill into each covered developer’s agent when a session starts. It removes the skill when you delete or turn off the policy.
- Unbound asks for at most one skill per turn and five skills per conversation.
- If Unbound can’t evaluate the policy, the command goes through.
- Claude Code, Codex, GitHub Copilot and Cursor support skill policies. Augment Code and Pi don’t.
Unsanctioned MCP servers
The policies above target servers you know about. Developers also connect servers you don’t — that’s where a task quietly becomes an exfiltration path. Mark the servers you approve of as sanctioned, and Unbound governs everything else as a group. You choose how, org-wide:
Set the mode from Configure → Sanction MCP Servers. Block and Warn both need at least one sanctioned server, and either mode lets you attach a message of up to 500 characters.
Start on Warn to see what your developers are actually reaching for without breaking their work, then move to Block once you’ve sanctioned the servers you’re happy with.
Under Warn there is one more choice, for runs with nobody to read the notice — headless Claude Code, or the Agent SDK. Pick Allow (the default — the request proceeds like any other allowed request) or Deny (the request is refused and appears under Unsanctioned Usage).
While the mode is Block, Disable Blocking Temporarily — in the same dialog, admin only — suspends blocking org-wide for 24 hours or a week without dismantling the sanctioned list. Useful when an unsanctioned server turns out to be needed mid-incident. It appears only under Block.
Command family reference
A terminal policy targets one command family and matches a pattern against one or more of that family’s fields. The picker groups the families the way they are listed here, and marks the high- and medium-risk families with a coloured dot (red for high, amber for medium); a low-risk family carries no dot. Field names appear title-cased in the dashboard (query_type reads as “Query Type”); the raw names below are what the API and CLI take. Run unbound policy tool families to print the same list, with each family’s fields and risk level.
Custom
System
Filesystem
Process
Network
Container
Cloud
Security
Version control
Database
Analytics shows a few further families that the policy picker does not offer. Those commands appear in your activity view, but you cannot write a rule against them. The picker is the authoritative list of what a terminal rule can target.
Matching rules
These apply to every terminal policy. Several conditions AND together. Add one condition per field and all of them must match. A field may appear only once.Any is on its own. Setting Match Against to Any tests your pattern against every field the family carries, so it cannot be combined with a named field.
The same value can be written several ways, and one pattern catches all of them.
- A field holding a host or URL (
remote_access.host,remote_execution.target_host,data_transfer.destination) matches on the bare host only:https://user@evil.com:8443/google.commatchesevil.com, and nothing in a path or query string can pose as the host. - A path matches however it is written:
~/.aws/credentials,.aws/credentialsand/Users/you/.aws/credentialsall match each other. A glob with no/in it matches against the file name alone, so.env*catches/srv/app/.env.local. - A kubectl short name counts as the full resource, so a
servicepattern ofdeploymentalso matcheskubectl ... deploy.
read_file policy also covers secret reads. Credential reads land in access_password, environment_exposure or database_admin rather than read_file, and a read_file policy fires on those families too — still gated by its own path pattern, so a read_file rule on *.ts does not start matching .pem reads. The broadening runs one way only: a secret-scoped policy stays precise.
The Custom family is what holds when a command cannot be placed. A command Unbound cannot place in a family matches no family-based rule, and is allowed rather than blocked — so a family-based rule is not unconditional. A Custom rule still fires on that command, because it matches the raw command line. Custom is not unconditional either: a Custom pattern that fails to evaluate is allowed through rather than blocked. Custom also covers an agent’s own file tools — a native read, write, edit or delete matches as its shell equivalent (cat <path>, echo "..." > <path>, rm <path>), so write the pattern against that form and one rule covers both routes.
Regex in a Custom pattern has to be portable. A Custom pattern is checked when you save it, and lookahead ((?=, (?!), lookbehind ((?<=, (?<!), atomic groups and backreferences (\1, \k<name>) are refused, along with other constructs that are not portable between regex engines — write a character class or an explicit escape instead. The save fails with the construct named. An ordinary field pattern has no such restriction.
An empty pattern means “any value for this field”. The rule then fires whenever the field is present at all, whatever it holds. The dashboard requires a pattern, and so does the CLI’s --field, so this one is only reachable by handing the config JSON over directly — the CLI’s --config flag, or the policy API. In the dashboard, use * instead.
Actions
Each tool policy has an action that decides what happens on a match. A skill policy has no action to pick. See Skills.
Block and Warn both carry an Enforcement Message — up to 500 characters, shown to the developer and read back by the agent when the policy fires.
Allow 1 hour is a blanket grant, not a one-command exception. For the hour that follows, every command matching the same set of policies goes through without a new Slack request.
When more than one policy matches
Every tool policy that matches is evaluated — there is no single winner and no priority ordering. The strictest action decides what happens to the command: Block → Require Slack Approval → Warn → Audit So a command caught by a Warn rule and a Block rule is blocked. For a terminal command, only the policy that actually enforced gets a match row in its history: when Block wins, the Warn rule that also matched is not credited with the match. For an MCP tool call every matched policy is recorded, so its history can show a match the rule did not enforce. An Audit policy records the command instead of acting on it, so it has no user-facing effect and never combines with the live actions above. A skill policy sits between Block and the rest. When a Block rule also matches, Unbound blocks the command and asks for no skill. Otherwise the skill request comes first. The agent loads the skill, and on the retry any matching Require Slack Approval or Warn rule applies as usual. Policy names are unique within your organization.Applying to Users
By default, a tool policy with no user groups applies to everyone in your organization. To restrict a policy to specific teams, assign it to one or more user groups during creation or editing. When a user group is modified, policy enforcement updates automatically for all affected users.Policy Coverage
The Policy Health view in the Tool Policies dashboard shows which command families and MCP tool categories have no active policies — coverage gaps where agent actions are completely unmonitored. Open the Policy Health tab, then switch between the Terminal and MCP sub-views to see coverage for each.Risk-score policies
A Risk Score policy acts on MCP tool calls whose risk score meets or exceeds a configuredrisk_score_threshold, independent of any specific server or tool. A call’s score follows what the tool does — a read scores lower than a write, and a write lower than something destructive.
Risk Score policies apply to MCP tool calls only. Terminal commands carry a risk score of their own, which you can see and filter on in Analytics, but a Risk Score policy does not act on them — use a command-family policy for terminal rules.
risk_score_thresholdis an integer from 1–10.- A lower threshold fires the action on more tool calls; a higher threshold reserves it for the highest-risk calls.
Risk Score policies are currently API-only — they aren’t yet exposed in the create-policy modal.
Policy Recommendations
The dashboard surfaces policy suggestions from observed agent activity. Each recommendation identifies either a complete gap (no policy covers this command or tool type at all) or a partial gap (a policy exists but doesn’t match all observed variants). Recommendations appear automatically as your agents run. You can create the suggested policy directly from the recommendation card, or dismiss it.Examples
Each example starts from Policies → Agentic Use → Create Policy. Where the CLI can create the same policy, its command follows.Terminal Commands: audit deletions of sensitive files
- Select Terminal Commands
- Fill in the form:
- Name: “Audit Sensitive File Deletions”
- Command Family:
delete_file - Match Against:
path - Pattern:
/etc/*or*.env
- Set Action to
Audit - Optionally select User Groups to limit the policy to specific teams
- Click Preview Impact to see historical matches
- Click Create Policy
Terminal Commands: require approval to push to main
Two conditions on one family, both of which must match.- Select Terminal Commands
- Name: “Approve pushes to main”
- Command Family:
git_action - Add two conditions:
- Branch =
main - Operation =
push
- Branch =
- Action:
Require Slack Approval - Click Create Policy
Terminal Commands: block one exact command
The Custom family matches the whole command line, for a rule no field expresses.- Select Terminal Commands
- Name: “Block the release script”
- Command Family:
custom - Pattern:
make release-prod - Action:
Block, with the Enforcement Message “Use the release pipeline instead.” - Click Create Policy
MCP Actions: confirm before merging a pull request
- Select MCP Actions
- Name: “Confirm PR merges”
- MCP Service: GitHub
- MCP Tools:
merge_pull_request - Action:
Warn, with the Enforcement Message “Merging needs a reviewer’s sign-off. Confirm one has approved.” - Click Create Policy
Unsanctioned MCP servers: warn before blocking
- Open Configure → Sanction MCP Servers
- Mark the servers your teams may use as sanctioned
- Set the mode to Warn, with a message such as “This MCP server is not approved. Request it in #it-help.”
- Watch the Unsanctioned Usage view for a week, and sanction anything legitimate that shows up
- Switch the mode to Block
Skills: load SQL guidance before database commands
- Select Skills
- Policy Name: “Secure SQL guidance”
- When: Before the agent runs a command
-
Command Family:
custom, Pattern:^(psql|mysql)\b -
Slug:
secure-sql -
Skill Body: paste the guidance, or click Copy from Discovered Skill to reuse one your teams already have:
- Leave Message empty to use the default wording
- Click Create Policy
psql in a session, Unbound refuses the command once. The agent invokes unbound-secure-sql, reads the rules, and runs the same command again, which goes through.
Skills: load the release checklist when someone asks to ship
- Select Skills
- Policy Name: “Payments release checklist”
- When: When the user sends a message
- Prompt pattern (regex):
deploy|release|ship it - Project path (regex):
/payments-service$ - Slug:
payments-release, and paste the checklist as the Skill Body - Optionally select User Groups, such as the payments team
- Click Create Policy
payments-service folder types “ship it”, the message goes through, and the agent invokes unbound-payments-release before it starts work.
Risk Score: warn on high-risk MCP calls
You create Risk Score policies through the policy API, with an admin API key. That’s the same keyunbound login --api-key takes:
8 reserves the warning for the riskiest calls, such as destructive ones, and leaves ordinary reads and writes alone. The API rejects the request if it also carries a command family, a config, or an MCP server or tool. On a private deployment, use your own backend host.
Tool Policies vs Security Policies
Tool policies and security policies are managed independently:Slack Integration
Set up Slack for interactive approval workflows
CLI Policy Management
Create and manage tool policies from the terminal

