Skip to content
WIP

This guide is a work in progress. Barry is also a work in progress.

Bounds

A bound restricts a session. It removes tools, write access, file paths, shell commands, network destinations, and nodes from what the session’s traits granted, and it never grants anything. A session with no bound has everything its traits grant.

The schema is BoundSchema in sdk/src/bounds/types.ts. It rejects unknown keys at every level, so a misspelled field fails instead of denying nothing. Bound fields lists every key with its type; this page explains how the patterns, enforcement, and merging behave.

Traits and bounds resolve to one policy, enforced by the MCP tool filter, call-time guards, native ceiling, hook gate, and optional egress sandbox.

Field Type Restricts
deniedTools list of strings Tools. Each entry is a namespace or a tool name
deniedAccess list of strings Write access: write for every tool, or a namespace or tool name
files.deny list of patterns Paths that match any pattern
files.allowOnly list of patterns Every path that matches no pattern. Each pattern starts with / or ~. deny wins when a path matches both
bash.deny list of strings Shell commands that contain the string. Prefer denyPrograms
bash.denyPrograms list of strings Shell commands that run the program, or program:subcommand
network.actions list of action tags Network operations. See network actions
network.domains list of host patterns Destinations to deny
network.allowDomains list of host patterns The only destinations the egress sandbox lets through. Needs enforce: sandbox
network.enforce guard or sandbox Enforcement level. Default guard. See enforcement levels
nativeTools map of harness ID to tool names That harness’s own tools, by the names the harness uses. See enforcement coverage
nodes.allow list of node IDs Every installation the list doesn’t name: only the named ones run the work. local or this installation’s ID names this machine
nodes.deny list of node IDs The installations it names

For example, this bound denies writes and pushes, and blocks secret files:

deniedAccess: [write]
files:
deny: ["*.env", "~/.ssh/**"]
network:
actions: [git:push]
Where Pattern Matches
files *.ext Any path that ends in .ext
files dir/** or dir/* Any path that contains dir/. A leading **/ means any depth
files Another pattern with * * matches any characters, anywhere in the path
files No * Any path that contains the text
files Leading ~ Your home directory
domains example.com or *.example.com example.com and every subdomain
allowDomains example.com Only example.com
allowDomains *.example.com Every subdomain, not example.com itself
denyPrograms git Every git command
denyPrograms gh:pr:create Only that subcommand
denyPrograms gh:api:write gh api with -X POST, PUT, PATCH, or DELETE, or with -f or -F fields

Barry checks file patterns against both the path as written and its absolute form.

denyPrograms matches every command in a line, across &&, ||, ;, |, subshells, and command substitutions. It looks through wrappers such as env, sudo, xargs, timeout, sh -c, npx, and uvx. Barry denies a command it cannot parse. It has no exception syntax: to deny most of a program, list each subcommand.

A parent tag denies all of its children.

Tag Parent Denies
all None Every tag in this table
write all git:push, http:write, and ssh:write
read all git:fetch, http:read, ssh:read, and dns
git:push write git push, and the git bag’s push tool
http:write write curl, wget, and httpie with a write method or a body, and mutating gh api calls
ssh:write write scp, rsync, and sftp, in either direction
git:fetch read git fetch, pull, clone, ls-remote, and submodule, and the git bag’s pull, fetch, and remotes tools
http:read read curl, wget, and httpie reads, read-only gh api calls, WebFetch, and WebSearch
ssh:read read ssh
dns read dig, nslookup, and host

Barry denies a command it cannot parse. A program that none of these tags names, such as nc or python, runs.

enforce What enforces the bound Strength
guard (default) Barry filters its tool list and checks each call to its tools before the tool runs Cooperative. A script written to disk, or a program the classifier does not know, gets past it
sandbox The guards, plus the agent runtime’s egress proxy, which filters every outbound connection from the agent’s process tree by hostname The agent cannot lift it. The proxy knows hosts, not HTTP methods, so a hosted session refuses to start when actions splits reads from writes, such as [write] alone

Under sandbox, an absent allowDomains means an empty allowlist: no egress except to localhost. Barry rejects a bound that sets allowDomains without enforce: sandbox.

A session’s bound merges every source:

  1. The bounds its selected traits carry, by name (bounds:) or inline (bound:), including the traits they include.
  2. The required bounds of Barry’s base identity. An identity turns an inherited required bound off with optional: true.
  3. The identity’s required bounds, under bounds: in identity.yaml.
  4. The session’s named bounds, from --bound or -r.
  5. The identity’s inline bound, under bound: in identity.yaml.
  6. An inline bound on the session record.

Merging only moves toward more restriction:

Field Merge rule
Every list except the allowlists Union
files.allowOnly, network.allowDomains, nodes.allow Intersection of identical strings. An absent list has no effect; an empty list permits nothing
network.enforce sandbox wins over guard
Command Effect
<identity> session start -r Starts a session with every packed bag’s tools under the readonly bound, skipping the trait picker
<identity> session start --bound <name> Starts a session with a named bound. An unknown name exits with the list of bounds instead of starting
<identity> identity bounds add <name> Adds a required bound to the identity, applied to every session it starts
<identity> identity bounds remove <name> Removes one of the identity’s required bounds
<identity> identity bounds clear Removes every required bound from the identity
barry bound list Lists every named bound and what it restricts

For example:

Terminal
barry bound list
<identity> session start --bound no-network-write --traits coding
<identity> identity bounds add no-secrets

A bag’s trait carries a bound with bounds: or bound:; see Packing bags. An identity carries its required bounds under bounds: in identity.yaml.

Barry’s base identity defines these in its identity.yaml, each with optional: true. Every identity can select them, and none applies until a session names one with --bound or -r, a selected trait carries it, or the identity requires it. no-bash comes from the bash bag:

Name Rules
readonly deniedTools: [Bash, Write, Edit], deniedAccess: [write], network.actions: [write]
no-bash deniedTools: [Bash, BashOutput, KillShell]
no-secrets files.deny: *.env, .env.*, .ssh/**, *.pem, *.key, *.p12, *.pfx
no-network network.actions: [all]
no-network-write network.actions: [write]
sandboxed-offline network.actions: [all], enforce: sandbox, allowDomains: []

These bounds also take back native tool categories. readonly takes back the native shell, file writes, and network. no-secrets, like any bound with a files rule, takes back the native shell, file reads, and file writes, so a session under it reads and writes files only through Barry’s file tools. The enforcement coverage section explains why.

Barry enforces a bound on the tools it serves. The agent’s own native tools, such as Claude Code’s Bash or Codex’s exec_command, run outside Barry’s guards, so Barry governs them by category instead. A native tool stays off wherever the session’s mode can control it, a trait turns it on, and a bound takes it back. The rules live in native-policy.ts.

Rule Barry’s tools Native tools it takes back
nativeTools Not applied The tools it names for that harness
deniedTools Removed from the tool list. Names match in any case Bash: shell. Read, Glob, or Grep: file reads. Write or Edit: file writes. filesystem: file reads and file writes. WebFetch or WebSearch: network. A harness’s own tool name: that tool
deniedAccess Write tools removed from the tool list write: shell and file writes
files.deny, files.allowOnly Checked on the path fields of Barry’s file tools. Barry’s Bash leaves the tool list Shell, file reads, and file writes
bash.deny, bash.denyPrograms Checked on Barry’s Bash Shell
network.actions Network tools removed from the list, and Bash commands classified Shell and network
network.domains URLs checked in Bash commands and in WebFetch Shell and network
network.allowDomains Not applied Shell and network
enforce: sandbox Not applicable Shell and network, plus the egress proxy where the mode table says so

Each harness’s adapter bag names the tools in each category, as native-<category> traits that grant them and no-<category> bounds that take them back. When a harness bag lacks a category’s bound, taking that category back takes back every native tool the harness has.

Harness native-shell native-file-reads native-file-writes native-network
Antigravity (experimental) run_command, send_command_input, command_status view_file, grep_search, find_by_name, list_dir write_to_file, replace_file_content, multi_replace_file_content, sed_file read_url_content, search_web
Claude Code Bash Read, Glob, Grep Write, Edit, NotebookEdit WebFetch, WebSearch
Codex exec_command, write_stdin view_image apply_patch web_search
Cursor Shell, WriteShellStdin Read, Grep, List, Glob Write, Edit, Delete WebFetch, WebSearch, Fetch
OpenCode shell read, grep, glob edit, write, patch webfetch, websearch
Pi bash, powershell read, grep, find, ls edit, write None

How firmly a native tool stays off depends on the harness and on the session mode. Each mode declares how it gates native calls:

  • Per-call: the harness asks Barry before each call, and Barry answers.
  • Static: a denylist fixed at launch.
  • Hooks: a Barry hook inside the harness can refuse a call.
Harness Mode Native gate Native tools it cannot turn off Operator override Egress sandbox
Antigravity (experimental) Hosted Hooks None None No
Antigravity (experimental) Instrumented Hooks None /hooks turns Barry’s gate off No
Antigravity (experimental) Guest Hooks None /hooks turns Barry’s gate off No
Claude Code Hosted Per-call None None Yes. Ollama and llama.cpp endpoints lose it
Claude Code Instrumented Static None None No
Claude Code Guest Static None None No
Codex Hosted Hooks None None No
Codex Instrumented Hooks None /hooks turns Barry’s gate off until the next turn starts No
Codex Guest Hooks None /hooks turns Barry’s gate off for the rest of the session No
Cursor Hosted Per-call Grep, List, Glob, SemanticSearch, Fetch None No
Cursor Instrumented, macOS only Hooks WebFetch, WebSearch, Glob None No
Cursor Guest Hooks WebFetch, WebSearch, Glob None No
OpenCode Hosted Per-call None None No
OpenCode Instrumented Not available
OpenCode Guest Static None None No
Pi Hosted Per-call None None No
Pi Instrumented and guest Not available

What each harness adds:

  • Antigravity is experimental: its hosted checks run against a scripted Gemini endpoint, not Gemini’s real API. In every mode, its gate refuses a forced native call when the policy script goes missing, throws, or times out.
  • Claude Code hosted rules each call in one shared hook, which refuses a call it cannot rule on before its deadline. Instrumented and guest run no Barry hook, so the native tool list and denial settings that Barry writes at launch keep native tools off.
  • Codex runs Barry’s hook launcher in every mode, and the launcher refuses a forced native call. A missing launcher, a missing Node, or Codex’s outer hook deadline leaves a gap. In instrumented, Barry turns its gate back on at the start of each turn, so a call made before then runs ungated. A web_search grant changes only at thread start or resume.
  • Cursor hosted refuses an ungranted native call through the workspace’s denylist before Cursor asks Barry. Cursor runs Grep, List, Glob, and SemanticSearch over ACP with no permission request and no hook, and runs Fetch with no permission check. In the terminal modes, Cursor approves WebFetch and WebSearch under --force, and Barry has no verified hook for them or for Glob.
  • OpenCode hosted puts each call to Barry and offers the model no native tool that a trait does not grant. Guest denies ungranted native tools in its configuration at launch.
  • Pi hosted puts every tool call, nested calls included, to Barry, and a ruling that fails refuses the call. Pi has no terminal modes, because a Pi terminal signs in with the user’s own login.

At launch:

  • A tool the mode cannot turn off stays in the session’s tool list even without a grant, and Barry warns. A bound that would take one back stops the launch.
  • Some tools turn on only together, such as Cursor’s Write and Edit, plus Delete in hosted, and OpenCode’s edit, write, and patch. A trait that grants part of a group gets none of it.
  • A grant the mode cannot honor stays off, and Barry warns.
  • Where the mode has an operator override, Barry prints it.

Only Claude Code’s hosted mode declares the egress sandbox, and the model endpoint has the final say: z.ai keeps it, while Ollama and llama.cpp do not. A hosted session whose bound asks for the sandbox on a harness or endpoint without it refuses to start.

Other limits:

  • Tools that bags serve make their own network requests in Barry’s process. Traits, deniedTools, and deniedAccess govern them; network rules do not.
  • network.domains reads URLs as written. It misses URLs built at runtime and hosts reached by IP address.
  • A program the classifier does not know runs under guard. Only the sandbox covers it.

Adapters covers the agent capabilities behind these tables. Policy resolution explains how bounds join traits in one policy, and Distributed nodes explains where nodes rules apply.