Skip to content
WIP

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

@barry-rocks/sdk/bounds

The bound and trait types and the policy machinery behind them: BoundSchema, tool metadata, native-tool policy, and execution scopes. Policy resolution explains how these combine into a session’s policy.

import { … } from "@barry-rocks/sdk/bounds";

Agent Trait — a named capability granted to a task. Traits enable: they grant namespaces and/or individual tools with an access level.

Property Type Description
access Access Access level granted to all namespaces and tools in this trait
bound? Bound Restrictions carried by this trait. Merged (union of denials) with any barry/session bound at resolution time. Lets a trait bundle a policy with its grants — e.g. the coding trait grants git tools but denies raw git/gh in Bash so all git goes through the structured tools.
boundNames? string[] Named bounds whose restrictions this trait carries — resolved and merged at session bound time.
harnessTraits? Record<string, string> -
includes? string[] Composite: includes other traits
name string -
namespaces string[] Tool namespaces this trait enables — all tools in a namespace are granted
nativeTools? Record<string, string[]> -
tools? string[] Individual tools this trait enables — takes precedence over namespace grants. Entries should be qualified namespace:tool ids; a bare tool name is legacy, matches that name in EVERY namespace, and emits a deprecation warning at resolution. Prefer "sentry:search_issues" over "search_issues".

Result of classifying one command line.

Property Type Description
argvs string[][] Quote-removed effective argument vectors, including nested commands.
programs string[] Program basenames invoked anywhere in the line (deduped, lowercased kept as-is).
subcommands Map<string, string[]> Subcommand chains per program, colon-joined: git push origin → “git” -> [“push”]; gh pr create → “gh” -> [“pr:create”]. Used for program:sub and program:sub:subsub deny rules.
unparseable boolean True if any part of the line could not be safely tokenized → caller must fail closed.

Property Type
handler (params, context) => Promise<unknown>
name string
schema? Readonly<Record<string, unknown>>

Property Type
allowedToolIds string[]
bound Bound | null
harness? string
identity? string
traits string[]

Property Type Description
path? string The file the command appears to write, when the shape reveals it.
reason string Short reason, e.g. “sed -i” or “> a source file”. Safe to show an agent.

MCP tool annotations — advisory hints about a tool’s behavior. Local mirror of the MCP spec’s ToolAnnotations to avoid SDK coupling.

Property Type
destructiveHint? boolean
idempotentHint? boolean
openWorldHint? boolean
readOnlyHint? boolean
title? string

Property Type
bag? object
bag.manifest Pick<BagManifest, "name" | "bounds">
defaultMode? ModeId
id string
label? string
modes? Partial<Record<ModeId, Pick<Mode, "native"> | null>>
nativeTools readonly string[]

Property Type
allowed string[]
conflicts Record<string, string>
denied string[]
operatorOverride? string
refused Record<string, string>
uncontrolled Record<string, string>

Property Type Description
byNamespace ResolvedTraits namespace → access
byTool ResolvedTraits qualified namespace:tool id → access (explicit per-tool grants). Keyed on the qualified id, never a bare name: two bags may both export status, and a grant for a bare status previously admitted every namespace’s status AND took precedence over the namespace grant. A caller resolves a tool’s grant with toolGrant(grants, namespace, tool).
byToolLegacy ResolvedTraits Legacy bare-tool-name grants (tools: ["status"], no namespace). Kept for backward compatibility with manifests that have not qualified their tools: entries. A bare name matches that name in ANY namespace, which is the imprecision SDK-4 is about, so each one emits a one-time deprecation warning. Prefer qualified ns:tool ids.

Metadata for a tool — namespace, name, and whether it reads or writes. This is just metadata, not the tool itself.

Property Type Description
access "read" | "write" -
annotations? McpAnnotations MCP annotations from the tool’s upstream server or definition.
contractHash? string Trusted catalog evidence for the versioned input/output contract.
namespace string -
toolName string -

Access = "read" | "readwrite"

Access level for agent capabilities.

  • “read”: observe without side effects
  • “readwrite”: observe and modify

ExecutionScope = z.infer<typeof executionScopeSchema>


ResolvedTraits = Map<string, Access>

Resolved traits — the output of resolving a task’s traits. Maps namespace or toolName → effective access level.

const ALLOW_DOMAINS_NEEDS_SANDBOX: “network.allowDomains is enforced only by the egress sandbox: add network.enforce: "sandbox", or deny hosts with network.domains instead” = “network.allowDomains is enforced only by the egress sandbox: add network.enforce: "sandbox", or deny hosts with network.domains instead”

Why a bound naming network.allowDomains without enforce: "sandbox" is refused: only the egress sandbox can enforce an allowlist, so under the guards it would read as a restriction and restrict nothing.


const BoundSchema: ZodObject<{ bash: ZodOptional<ZodObject<{ deny: ZodOptional<ZodArray<ZodString>>; denyPrograms: ZodOptional<ZodArray<ZodString>>; }, $strict>>; deniedAccess: ZodOptional<ZodArray<ZodString>>; deniedTools: ZodOptional<ZodArray<ZodString>>; description: ZodOptional<ZodString>; files: ZodOptional<ZodObject<{ allowOnly: ZodOptional<ZodArray<ZodString>>; deny: ZodOptional<ZodArray<ZodString>>; }, $strict>>; name: ZodOptional<ZodString>; nativeTools: ZodOptional<ZodRecord<ZodString, ZodArray<ZodString>>>; network: ZodOptional<ZodObject<{ actions: ZodOptional<ZodArray<ZodEnum<{ all: "all"; dns: "dns"; git:fetch: "git:fetch"; git:push: "git:push"; http:read: "http:read"; http:write: "http:write"; read: "read"; ssh:read: "ssh:read"; ssh:write: "ssh:write"; write: "write"; }>>>; allowDomains: ZodOptional<ZodArray<ZodString>>; domains: ZodOptional<ZodArray<ZodString>>; enforce: ZodOptional<ZodEnum<{ guard: "guard"; sandbox: "sandbox"; }>>; }, $strict>>; nodes: ZodOptional<ZodObject<{ allow: ZodOptional<ZodArray<ZodString>>; deny: ZodOptional<ZodArray<ZodString>>; }, $strict>>; }, $strict>

Strict at every level, for the same reason network.actions is an enum rather than a string: a restriction that fails to parse is loud, while one that parses into an empty object denies nothing and is indistinguishable from a working bound. A misspelled denyProgram or deniedTool must not leave the session quietly unrestricted.


const CORE_NAMESPACES: Set<string>

Barry’s own namespaces, as opposed to a vendor’s.

This no longer decides which namespaces get their own /mcp/ns/<namespace> endpoint — every namespace does, which is what gives the agent mcp__linear__* and mcp__git__* instead of one flat mcp__barry__*.

Its only remaining job is cosmetic: on the aggregate /mcp endpoint, where everything really does share the mcp__barry__ prefix, vendor tools get a [Linear] tag on their description to show where they came from. Tagging Barry’s own tools there would be noise.


const executionScopeSchema: ZodObject<{ bound: ZodNullable<ZodObject<{ bash: ZodOptional<ZodObject<{ deny: ZodOptional<ZodArray<ZodString>>; denyPrograms: ZodOptional<ZodArray<ZodString>>; }, $strict>>; deniedAccess: ZodOptional<ZodArray<ZodString>>; deniedTools: ZodOptional<ZodArray<ZodString>>; description: ZodOptional<ZodString>; files: ZodOptional<ZodObject<{ allowOnly: ZodOptional<ZodArray<ZodString>>; deny: ZodOptional<ZodArray<ZodString>>; }, $strict>>; name: ZodOptional<ZodString>; nativeTools: ZodOptional<ZodRecord<ZodString, ZodArray<ZodString>>>; network: ZodOptional<ZodObject<{ actions: ZodOptional<ZodArray<ZodEnum<…>>>; allowDomains: ZodOptional<ZodArray<ZodString>>; domains: ZodOptional<ZodArray<ZodString>>; enforce: ZodOptional<ZodEnum<{ guard: …; sandbox: …; }>>; }, $strict>>; nodes: ZodOptional<ZodObject<{ allow: ZodOptional<ZodArray<ZodString>>; deny: ZodOptional<ZodArray<ZodString>>; }, $strict>>; }, $strict>>; contracts: ZodOptional<ZodRecord<ZodString, ZodString>>; fingerprint: ZodString; harness: ZodOptional<ZodString>; identity: ZodOptional<ZodString>; tools: ZodRecord<ZodString, ZodEnum<{ read: "read"; write: "write"; }>>; traits: ZodArray<ZodString>; }, $strict>


const NATIVE_CATEGORIES: readonly ["shell", "file-reads", "file-writes", "network"]


const NETWORK_TOOL_ACTIONS: Record<string, string[]>

Static map of MCP/structured tool names to their network action tags.

Keys are bare tool names as a bag defines them — push, not mcp__git__push. Tools no longer repeat their namespace, so these match the git bag’s own names. A key naming a tool that does not exist is silently inert, so entries must be kept in step with the bag (git_clone sat here for a while against a tool that was never defined).


const NETWORK_TOOL_URL_PARAMS: Record<string, string>

Tools whose parameters carry a URL that domain rules should apply to. Maps tool name → the parameter holding the URL.

Without this, domains only ever constrained Bash, so denying *.internal.co still left WebFetch https://api.internal.co working.

applyBoundGuards<T>(tools, scope): T[]

Type Parameter
T extends BoundGuardTool
Parameter Type
tools T[]
scope Bound

T[]


approveExecutionScope(options): Promise<{ bound: { bash?: { deny?: string[]; denyPrograms?: string[]; }; deniedAccess?: string[]; deniedTools?: string[]; description?: string; files?: { allowOnly?: string[]; deny?: string[]; }; name?: string; nativeTools?: Record<string, string[]>; network?: { actions?: ("read" | "write" | "all" | "git:push" | "git:fetch" | "http:write" | "http:read" | "ssh:write" | "ssh:read" | "dns")[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }; nodes?: { allow?: string[]; deny?: string[]; }; } | null; contracts?: Record<string, string>; fingerprint: string; harness?: string; identity?: string; tools: Record<string, "read" | "write">; traits: string[]; }>

Resolve explicit selections. No identity/default trait union occurs here.

Parameter Type
options { boundByName: (name) => Promise<Bound | null | undefined>; bounds?: readonly (Bound | null | undefined)[]; harness?: string; identity?: string; tools: ToolMeta[]; traitNames: readonly string[]; traits: Record<string, AgentTrait>; }
options.boundByName (name) => Promise<Bound | null | undefined>
options.bounds? readonly (Bound | null | undefined)[]
options.harness? string
options.identity? string
options.tools ToolMeta[]
options.traitNames readonly string[]
options.traits Record<string, AgentTrait>

Promise<{ bound: { bash?: { deny?: string[]; denyPrograms?: string[]; }; deniedAccess?: string[]; deniedTools?: string[]; description?: string; files?: { allowOnly?: string[]; deny?: string[]; }; name?: string; nativeTools?: Record<string, string[]>; network?: { actions?: ("read" | "write" | "all" | "git:push" | "git:fetch" | "http:write" | "http:read" | "ssh:write" | "ssh:read" | "dns")[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }; nodes?: { allow?: string[]; deny?: string[]; }; } | null; contracts?: Record<string, string>; fingerprint: string; harness?: string; identity?: string; tools: Record<string, "read" | "write">; traits: string[]; }>


assertNodeAllowed(nodeId, bound?): void

Parameter Type
nodeId string
bound? Bound | null

void


assertScopeDelegation(scope, delegator, catalog): void

Parameter Type
scope { bound: { bash?: { deny?: string[]; denyPrograms?: string[]; }; deniedAccess?: string[]; deniedTools?: string[]; description?: string; files?: { allowOnly?: string[]; deny?: string[]; }; name?: string; nativeTools?: Record<string, string[]>; network?: { actions?: ("read" | "write" | "all" | "git:push" | "git:fetch" | "http:write" | "http:read" | "ssh:write" | "ssh:read" | "dns")[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }; nodes?: { allow?: string[]; deny?: string[]; }; } | null; contracts?: Record<string, string>; fingerprint: string; harness?: string; identity?: string; tools: Record<string, "read" | "write">; traits: string[]; }
scope.bound { bash?: { deny?: string[]; denyPrograms?: string[]; }; deniedAccess?: string[]; deniedTools?: string[]; description?: string; files?: { allowOnly?: string[]; deny?: string[]; }; name?: string; nativeTools?: Record<string, string[]>; network?: { actions?: ("read" | "write" | "all" | "git:push" | "git:fetch" | "http:write" | "http:read" | "ssh:write" | "ssh:read" | "dns")[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }; nodes?: { allow?: string[]; deny?: string[]; }; } | null
scope.contracts? Record<string, string>
scope.fingerprint string
scope.harness? string
scope.identity? string
scope.tools Record<string, "read" | "write">
scope.traits string[]
delegator ExecutionContext
catalog readonly ToolMeta[]

void


assertToolAllowed(context, tool, nodeId): void

Parameter Type
context ExecutionContext
tool Pick<ToolMeta, "namespace" | "toolName">
nodeId string

void


boundHasContent(bound?): boolean

True if a bound carries any actual restriction (not just {}).

network.enforce counts: a bound of {network:{enforce:"sandbox"}} is a real instruction to escalate enforcement, and dropping it here would strip that escalation before it ever reached the merge.

Parameter Type
bound? Bound

boolean


classifyBashCommand(command): BashClassification

Classify a command line: which programs it invokes, plus a fail-closed flag.

Parameter Type
command string

BashClassification


classifyFileWrite(command): FileWriteFinding | null

Does this command look like it writes a file?

Returns null when it doesn’t (the common case — most commands are builds, tests, greps and git). Never throws.

Parameter Type
command string

FileWriteFinding | null


classifyNetworkActions(classification, rawCommand): string[]

Given a BashClassification and the raw command string, return all network action tags the command would perform.

Parameter Type
classification BashClassification
rawCommand string

string[]


expandActions(actions): Set<string>

Expand a set of action tags to include all descendants. e.g. [“write”] → {“write”, “git:push”, “http:write”, “ssh:write”}

Parameter Type
actions string[]

Set<string>


expandTraitNames(names, traits, harness?): string[]

Expand selected traits, including the compound for the actual harness.

Parameter Type
names readonly string[]
traits Readonly<Record<string, AgentTrait>>
harness? string

string[]


extractDomainsFromCommand(command): string[]

Parameter Type
command string

string[]


filterTools(tools, traitNames, allTraits, bound?, harness?): string[]

Filter tools based on traits and optional bound.

Returns BARE names, which cannot distinguish two namespaces exporting the same tool. Use filterToolsQualified for authorization decisions.

Parameter Type
tools ToolMeta[]
traitNames string[]
allTraits Record<string, AgentTrait>
bound? Bound
harness? string

string[]


filterToolsQualified(tools, traitNames, allTraits, bound?, harness?): string[]

Filter tools based on traits and optional bound, returning QUALIFIED ids.

  1. Resolve traits → namespace grants + explicit tool grants
  2. Filter tools: include if namespace or toolName is enabled AND access permits
  3. Exclude denied tools (by namespace or toolName)
  4. Exclude write tools for deniedAccess entries
  5. Exclude tools implied by network action restrictions
  6. Return namespace:toolName for each survivor

Prefer this over filterTools anywhere the result gates invocation. The bare-name version cannot express “this name from that namespace” and is kept only for callers that genuinely want names for display.

Parameter Type
tools ToolMeta[]
traitNames string[]
allTraits Record<string, AgentTrait>
bound? Bound
harness? string

string[]


getImpliedDeniedTools(actions): string[]

Return tool names that should be denied based on network action restrictions. Used by filterTools to expand the denied set.

Parameter Type
actions string[]

string[]


intersectExecutionScope(approved, current, catalog, restrictions?): ExecutionContext

Each bound must allow the operation; grants can only shrink after approval.

Parameter Type Default value
approved { bound: { bash?: { deny?: string[]; denyPrograms?: string[]; }; deniedAccess?: string[]; deniedTools?: string[]; description?: string; files?: { allowOnly?: string[]; deny?: string[]; }; name?: string; nativeTools?: Record<string, string[]>; network?: { actions?: ("read" | "write" | "all" | "git:push" | "git:fetch" | "http:write" | "http:read" | "ssh:write" | "ssh:read" | "dns")[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }; nodes?: { allow?: string[]; deny?: string[]; }; } | null; contracts?: Record<string, string>; fingerprint: string; harness?: string; identity?: string; tools: Record<string, "read" | "write">; traits: string[]; } undefined
approved.bound { bash?: { deny?: string[]; denyPrograms?: string[]; }; deniedAccess?: string[]; deniedTools?: string[]; description?: string; files?: { allowOnly?: string[]; deny?: string[]; }; name?: string; nativeTools?: Record<string, string[]>; network?: { actions?: ("read" | "write" | "all" | "git:push" | "git:fetch" | "http:write" | "http:read" | "ssh:write" | "ssh:read" | "dns")[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }; nodes?: { allow?: string[]; deny?: string[]; }; } | null ...
approved.contracts? Record<string, string> ...
approved.fingerprint string ...
approved.harness? string ...
approved.identity? string ...
approved.tools Record<string, "read" | "write"> ...
approved.traits string[] ...
current ExecutionContext undefined
catalog readonly ToolMeta[] undefined
restrictions readonly (Bound | null)[] []

ExecutionContext


isBashDenied(command, deny): string | null

Check if a bash command matches any deny pattern. Patterns are substrings matched against the command string.

Parameter Type
command string
deny string[]

string | null


isDomainDenied(domain, domains): string | null

Check if a domain matches any deny pattern. Patterns support wildcards: “*.foo.com” matches “api.foo.com” and “x.y.foo.com”. Exact match: “staging.example.com” matches only that domain.

Parameter Type
domain string
domains string[]

string | null


isFileAllowed(filePath, allowOnly): string | null

Check if a file path matches any allowOnly pattern. Returns the matching pattern, or null when NOTHING allows it — under an allowOnly bound that null is a denial, and the caller treats it as one.

Parameter Type
filePath string
allowOnly string[]

string | null


isFileDenied(filePath, deny): string | null

Check if a file path matches any deny pattern. Returns the matching pattern, or null when nothing denies it.

Parameter Type
filePath string
deny string[]

string | null


isNetworkActionDenied(command, actions): string | null

Check if a bash command performs a denied network action. Returns the matched action tag, or null if allowed.

Parameter Type
command string
actions string[]

string | null


isProgramDenied(command, denyPrograms): string | null

Decide whether a command is denied by denyPrograms rules.

Rules:

  • "git" — deny any invocation of git.
  • "git:push" — deny only git push ….
  • "gh:pr:create" — deny only gh pr create … (multi-level subcommand).

Matching is on resolved program basenames + subcommand chains, so git -C /x push, FOO=1 git push, cd a && git push, (git push), git push | tee, xargs git push, /usr/bin/git push, and bash -c "git push" all match, while gh pr view is allowed under a gh:pr:create rule.

Fails closed: if the line couldn’t be safely tokenized AND any deny rule exists, returns a deny (so obfuscation can’t slip a denied program through).

Parameter Type
command string
denyPrograms string[]

string | null

the matched rule string, or null if allowed.


mergeBounds(base, override): Bound | null

Parameter Type
base Bound | null
override Bound | null

Bound | null


mergeNetwork(base?, override?): { actions?: string[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; } | undefined

Parameter Type Description
base? { actions?: string[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; } -
base.actions? string[] Network actions to deny. Entries are hierarchical action tags: “all” — all network access “write” — all outbound writes (git:push, http:write, ssh:write) “read” — all outbound reads (git:fetch, http:read, dns) “git:push” — git push specifically “git:fetch” — git fetch/pull/clone “http:write” — HTTP POST/PUT/PATCH/DELETE “http:read” — HTTP GET/HEAD “ssh:write” — scp upload, rsync push “ssh:read” — ssh connections “dns” — DNS lookups (dig, nslookup, host) Parent tags expand to include their children: “write” implies “git:push” + “http:write” + “ssh:write”.
base.allowDomains? string[] Destination hosts the session may reach, enforced by the agent runtime’s egress proxy. Requires enforce: "sandbox": the app-level guards cannot enforce an allowlist, so a bound that sets this without it is refused. This is the inverse of domains, and the two are NOT interchangeable: a deny-list says nothing about which of the infinite remaining hosts are acceptable. Both may be set; they are independent layers and a host present in domains is denied regardless of this list. Omitting it under enforce: "sandbox" means an EMPTY allowlist — no egress except localhost. Opening a host is always an explicit act.
base.domains? string[] Destination domains to deny. Supports wildcards: “*.internal.co” matches “api.internal.co”. Best-effort — inspects URL arguments in bash commands (curl, wget, git clone). Cannot cover bag proxy tools or dynamically constructed URLs.
base.enforce? "guard" | "sandbox" Enforcement level: “guard” (default) — application-level tool/command interception only. Cooperative safety rail with clear error messages. “sandbox” — adds the agent runtime’s process-tree sandbox: outbound traffic is forced through an egress proxy that filters by HOSTNAME (see allowDomains), and the agent cannot lift it. Covers write-to-disk bypasses and network binaries the command classifier doesn’t know. It filters by host, not by HTTP method, so partial action denials (e.g. actions: [“write”]) still rely on the guards.
override? { actions?: string[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; } -
override.actions? string[] Network actions to deny. Entries are hierarchical action tags: “all” — all network access “write” — all outbound writes (git:push, http:write, ssh:write) “read” — all outbound reads (git:fetch, http:read, dns) “git:push” — git push specifically “git:fetch” — git fetch/pull/clone “http:write” — HTTP POST/PUT/PATCH/DELETE “http:read” — HTTP GET/HEAD “ssh:write” — scp upload, rsync push “ssh:read” — ssh connections “dns” — DNS lookups (dig, nslookup, host) Parent tags expand to include their children: “write” implies “git:push” + “http:write” + “ssh:write”.
override.allowDomains? string[] Destination hosts the session may reach, enforced by the agent runtime’s egress proxy. Requires enforce: "sandbox": the app-level guards cannot enforce an allowlist, so a bound that sets this without it is refused. This is the inverse of domains, and the two are NOT interchangeable: a deny-list says nothing about which of the infinite remaining hosts are acceptable. Both may be set; they are independent layers and a host present in domains is denied regardless of this list. Omitting it under enforce: "sandbox" means an EMPTY allowlist — no egress except localhost. Opening a host is always an explicit act.
override.domains? string[] Destination domains to deny. Supports wildcards: “*.internal.co” matches “api.internal.co”. Best-effort — inspects URL arguments in bash commands (curl, wget, git clone). Cannot cover bag proxy tools or dynamically constructed URLs.
override.enforce? "guard" | "sandbox" Enforcement level: “guard” (default) — application-level tool/command interception only. Cooperative safety rail with clear error messages. “sandbox” — adds the agent runtime’s process-tree sandbox: outbound traffic is forced through an egress proxy that filters by HOSTNAME (see allowDomains), and the agent cannot lift it. Covers write-to-disk bypasses and network binaries the command classifier doesn’t know. It filters by host, not by HTTP method, so partial action denials (e.g. actions: [“write”]) still rely on the guards.

{ actions?: string[]; allowDomains?: string[]; domains?: string[]; enforce?: "guard" | "sandbox"; }

Name Type Description
actions? string[] Network actions to deny. Entries are hierarchical action tags: “all” — all network access “write” — all outbound writes (git:push, http:write, ssh:write) “read” — all outbound reads (git:fetch, http:read, dns) “git:push” — git push specifically “git:fetch” — git fetch/pull/clone “http:write” — HTTP POST/PUT/PATCH/DELETE “http:read” — HTTP GET/HEAD “ssh:write” — scp upload, rsync push “ssh:read” — ssh connections “dns” — DNS lookups (dig, nslookup, host) Parent tags expand to include their children: “write” implies “git:push” + “http:write” + “ssh:write”.
allowDomains? string[] Destination hosts the session may reach, enforced by the agent runtime’s egress proxy. Requires enforce: "sandbox": the app-level guards cannot enforce an allowlist, so a bound that sets this without it is refused. This is the inverse of domains, and the two are NOT interchangeable: a deny-list says nothing about which of the infinite remaining hosts are acceptable. Both may be set; they are independent layers and a host present in domains is denied regardless of this list. Omitting it under enforce: "sandbox" means an EMPTY allowlist — no egress except localhost. Opening a host is always an explicit act.
domains? string[] Destination domains to deny. Supports wildcards: “*.internal.co” matches “api.internal.co”. Best-effort — inspects URL arguments in bash commands (curl, wget, git clone). Cannot cover bag proxy tools or dynamically constructed URLs.
enforce? "guard" | "sandbox" Enforcement level: “guard” (default) — application-level tool/command interception only. Cooperative safety rail with clear error messages. “sandbox” — adds the agent runtime’s process-tree sandbox: outbound traffic is forced through an egress proxy that filters by HOSTNAME (see allowDomains), and the agent cannot lift it. Covers write-to-disk bypasses and network binaries the command classifier doesn’t know. It filters by host, not by HTTP method, so partial action denials (e.g. actions: [“write”]) still rely on the guards.

undefined


nativeToolDenials(bound, harness, inventory): string[]

Parameter Type
bound Bound | null | undefined
harness string
inventory readonly string[]

string[]


nativeToolsTakenBack(bound, harness): string[]

Native calls bypass Barry’s guards, so a guarded restriction takes back the category.

Parameter Type
bound Bound | null | undefined
harness NativeHarness

string[]


nativeToolStatus(traits, bound, harness, mode?): object

Parameter Type
traits readonly AgentTrait[]
bound Bound | null | undefined
harness NativeHarness
mode? ModeId

object

Name Type
allowed string[]
denied string[]
refused Record<string, string>
uncontrolled object

qualifyToolId(namespace, toolName): string

The identity a tool is authorized under: namespace AND name, never one alone.

Two bags may both export status. Authorization is decided per (namespace, name) — filterToolsQualified below gets that right — but returning a bare name collapses the pair, and a consumer testing membership by name then admits every tool sharing an allowed name. Granting system also admitted git’s status.

Parameter Type
namespace string
toolName string

string


resolveEffectiveBound(options): Promise<Bound | null>

One restriction chain for native enforcement and MCP guards.

Parameter Type
options { boundByName: (name) => Promise<Bound | null | undefined>; bounds?: readonly (Bound | null | undefined)[]; harness?: string; traitNames: readonly string[]; traits: Readonly<Record<string, AgentTrait>>; }
options.boundByName (name) => Promise<Bound | null | undefined>
options.bounds? readonly (Bound | null | undefined)[]
options.harness? string
options.traitNames readonly string[]
options.traits Readonly<Record<string, AgentTrait>>

Promise<Bound | null>


resolveExecutionContext(options): Promise<ExecutionContext>

No default grants: the caller supplies all selected traits.

Parameter Type
options { boundByName: (name) => Promise<Bound | null | undefined>; bounds?: readonly (Bound | null | undefined)[]; harness?: string; identity?: string; tools: ToolMeta[]; traitNames: readonly string[]; traits: Record<string, AgentTrait>; }
options.boundByName (name) => Promise<Bound | null | undefined>
options.bounds? readonly (Bound | null | undefined)[]
options.harness? string
options.identity? string
options.tools ToolMeta[]
options.traitNames readonly string[]
options.traits Record<string, AgentTrait>

Promise<ExecutionContext>


resolveNativePolicy(grants, harness, mode?): NativePolicy

Parameter Type
grants { bound: Bound | null; tools: readonly Tool[]; }
grants.bound Bound | null
grants.tools readonly Tool[]
harness? NativeHarness
mode? ModeId

NativePolicy


resolveTraits(traitNames, allTraits, harness?): ResolvedTraitGrants

Resolve a list of trait names into namespace and tool grant maps.

Expands composite traits (via includes), then unions all grants. When multiple traits grant the same namespace or tool with different access levels, the more permissive level wins (readwrite > read).

AgentTrait.tools entries may be qualified (ns:tool) or a bare legacy name. Qualified ids key byTool; a bare name keys byToolLegacy and warns.

Parameter Type
traitNames string[]
allTraits Record<string, AgentTrait>
harness? string

ResolvedTraitGrants


scopeFingerprint(value): string

Canonical policy evidence; never contains credentials or transport tokens.

Parameter Type
value unknown

string


validateNativeTools(manifest, harness): void

An adapter bag cannot grant or deny a native name its harness does not offer.

Parameter Type
manifest Pick<BagManifest, "name" | "bounds" | "traits">
harness Pick<NativeHarness, "id" | "nativeTools">

void

Re-exports Bound