bag.yaml
bag.yaml is a bag’s manifest. It sits at the root of the bag’s directory, and
Barry reads it whenever it registers, builds, or loads the bag. The schema is
strict: Barry rejects any key it doesn’t know, so a misspelled key fails the
whole manifest instead of loading as a bag that quietly does nothing. The
manifest schema
is the source of truth for every key on this page.
Every bag needs name and description. Most bags add one or two more keys:
stores for data, services for long-running processes, jobs and
schedules for background work, or traits and bounds for policy. A bag’s
tools come from code (tools.ts or src/tools.ts), not from the manifest, and
its instructions, skills, and actions come from the instructions/, skills/,
and actions/ directories beside the manifest. To create a bag with a starter
manifest, run barry new. To validate a bag directory without installing it,
run barry bag check.
Barry substitutes constants before it validates the manifest: anywhere a value
appears, {constant: name} or {constant: bag:name} replaces the whole value
with one the constants key defines. Barry also accepts the retired keys
verbs and nouns and ignores them, so a remote server that still sends them
keeps loading. It rejects tool-metadata and deployments with a message
that names their replacement.
Overview
Section titled “Overview”Every key bag.yaml accepts, with its type. Each key has its own section under Fields.
name: string # requireddescription: string # requiredversion: stringextends: stringinstructions: stringbags: list of strings or map of <name> <name>: object or null repo: string rev: string ref: string path: string subdir: stringrequires: map of <bag> <bag>: object reason: string optional: boolean # default false resource: string allow-remote: booleandependencies: map of <package> or string <package>: object reason: string # required bin: string optional: boolean install: object macos: string linux: stringpermissions: list of objects kind: string # required app: string reason: string # requiredtools: list of single-key mapsprompts: object entry: string # requiredtraits: map of <name> <name>: object description: string # required access: string # default read includes: list of strings harnessTraits: map of strings nativeTools: map of string lists bags: list of strings namespaces: list of strings skills: list of strings instructions: list of strings bounds: list of strings bound: objectbounds: map of <name> <name>: object description: string # required bound: object # requiredconstants: map of any valuecredentials: map of <ENV_VAR> <ENV_VAR>: object source: string # required item: string # required field: string # requiredvendors: list of objects id: string # required label: string # required baseUrl: string or object credential: object or null # required compatible: list of objects models: list of objects # requiredmcp-servers: map of <name> <name>: object type: string url: string command: string args: list of strings env: list of strings session-scoped: booleanauth: object command: string # required args: list of strings check: objectcli: object alias: stringdefault_notifier: object tool: string # required target: stringslash-commands: object entry: string # required commands: list of objects # requiredhooks: object or list agent: list of objects event: string # required run: string # required args: list of strings matcher: string cursor-matcher: string cursor-events: list of strings timeout: number barry: list of objectsstore: object owned_by: string # required engine: string # required migrations: string # requiredstores: map of <name> <name>: object owned_by: string # required engine: string # required migrations: string # requiredsnapshots: map of <store> <store>: object entry: string # requiredrestores: map of <store> <store>: object entry: string # requiredservices: map of <name> <name>: object description: string # required entry: string command: string args: list of strings env: list of strings secrets: list of strings optional-secrets: list of strings working-directory: string autostart: string # default login serves: string health: string socket: string user: string local-only: booleanapps: map of <name> <name>: object name: string # required description: string # required platform: string # required build: string or object # required output: string # required id: string protocol-version: number capabilities: object macos: object ios: objectjobs: map of <name> <name>: object description: string version: string or number runs: object # required using: string # required secrets: list of strings env: list of strings working-directory: string requires: object preflight: object validate: object input_schema: object output_schema: object timeout: number or string bounds: list of stringsschedules: map of <name> <name>: object description: string every: string cron: string timezone: string # default UTC at: string job: string action: string or object entry: string args: list of strings env: list of strings secrets: list of strings timeout: number or string identity: string inputs: object traits: list of strings bounds: list of strings overlap: string # default skip catch_up: string # default once enabled: boolean # default truescripts: map of <name> <name>: object description: string # required entry: string command: string args: list of strings env: list of strings secrets: list of strings working-directory: stringinfra: object provider: string # required root: string # required variables: list of stringsprovides: object local: object tunnel: object reach: list of strings # required gates: list of stringsFields
Section titled “Fields”- Type:
string - Required: yes
The bag’s name. Barry registers the bag under it, qualifies the bag’s
traits and bounds with it (name:trait), and names the bag’s automatic
trait after it. An extension’s name must be a plain bag name of letters,
digits, dots, underscores, and hyphens.
name: weatherdescription
Section titled “description”- Type:
string - Required: yes
One line that says what the bag provides. Barry shows it wherever it lists
bags, such as barry bag list and barry bag show.
description: Current conditions and forecasts from the National Weather Serviceversion
Section titled “version”- Type:
string - Required: no
The bag’s own release, such as v0.1. Barry doesn’t branch on it: the
manifest format has one version, so this field describes the bag, not the
schema. Barry’s first-party bags omit it.
version: v0.1extends
Section titled “extends”- Type:
string - Required: no
Makes this bag an extension of the named parent bag. An extension lives in
<parent>/extensions/<name>/, registers as <parent>/<name>, stamps its
tools with the parent’s namespace, and receives the parent’s grant instead
of an automatic trait of its own. An extension may declare only name,
extends, description, version, instructions, tools,
dependencies, schedules, and scripts; Barry rejects every other key
with a message that says to declare it on the parent.
extends: sessionsinstructions
Section titled “instructions”- Type:
string - Required: no
Legacy guidance text. Barry turns it into an always-on instruction named
after the bag. Prefer a file under the bag’s instructions/ directory: a
file with the bag’s name supersedes this string, which is how a bag
migrates off it.
instructions: Use the weather tools for forecasts instead of searching the web.- Type:
list of strings or map of <name> - Required: no
Sub-bags this bag composes. A composed bag absorbs its children’s tools, skills, instructions, actions, traits, and other capabilities, and the parent’s automatic trait expands to its children’s namespaces.
The list form names bags that the registry already holds. The map form also says where each child comes from, so installing the parent fetches it. A map entry with no value composes the child without naming a source.
bags: tracker: locks: path: ./locks notes: repo: perintyler/notes-bag ref: mainbags.<name>
Section titled “bags.<name>”- Type:
object or null - Required: no
Where one child comes from. Set exactly one of repo or path.
bags.<name>.repo
Section titled “bags.<name>.repo”- Type:
string - Required: no
A Git remote: owner/name shorthand or any URL Git can clone.
bags.<name>.rev
Section titled “bags.<name>.rev”- Type:
string - Required: no
The exact commit to check out. Needs repo; conflicts with ref.
bags.<name>.ref
Section titled “bags.<name>.ref”- Type:
string - Required: no
The branch or tag to track when rev is absent. Needs repo.
bags.<name>.path
Section titled “bags.<name>.path”- Type:
string - Required: no
A directory relative to this bag’s directory. Conflicts with
repo, rev, ref, and subdir.
bags.<name>.subdir
Section titled “bags.<name>.subdir”- Type:
string - Required: no
The directory inside the clone that holds the bag, for a
repository that holds several bags. Needs repo.
requires
Section titled “requires”- Type:
map of <bag> - Required: no
Other bags this bag calls but doesn’t absorb. A requirement gives you a
registered bag, never its tools. The MCP server, the bag command group,
and the Slack server check requirements when they load the bag: an unmet
requirement drops the bag’s tools with one clear message instead of
failing in the middle of a tool call. Use bags to absorb a bag and
dependencies for host programs.
requires: sessions: reason: an event can name the session it came fromrequires.<bag>
Section titled “requires.<bag>”- Type:
object - Required: no
The required bag, by registered name.
requires.<bag>.reason
Section titled “requires.<bag>.reason”- Type:
string - Required: no
Why this bag needs the other one. Barry quotes it in the unmet-requirement message.
requires.<bag>.optional
Section titled “requires.<bag>.optional”- Type:
boolean - Required: no
- Default:
false
When true, an unmet requirement produces a warning and the bag
loads anyway.
requires.<bag>.resource
Section titled “requires.<bag>.resource”- Type:
string - Required: no
Which of the required bag’s services this bag calls. Omit it when this bag needs the other bag only to exist.
requires.<bag>.allow-remote
Section titled “requires.<bag>.allow-remote”- Type:
boolean - Required: no
When true, a remote registry entry for the required bag
satisfies the requirement.
dependencies
Section titled “dependencies”- Type:
map of <package> or string - Required: no
Host programs the bag needs at run time. Barry looks each one up on
PATH, reports a missing one in barry bag show and barry bag doctor,
and prints its install command.
Instead of a map, the value can be a path inside the bag to a YAML file
with the same map, or to a Brewfile of plain brew "name" and
cask "name" lines.
dependencies: ripgrep: bin: rg reason: powers the Glob and Grep tools install: macos: brew install ripgrepdependencies.<package>
Section titled “dependencies.<package>”- Type:
object - Required: no
One package, by its package-manager name.
dependencies.<package>.reason
Section titled “dependencies.<package>.reason”- Type:
string - Required: yes
What the bag uses the program for.
dependencies.<package>.bin
Section titled “dependencies.<package>.bin”- Type:
string - Required: no
The executable to look for, as a bare name or an absolute path,
when it differs from the package name. A package key that contains
/ needs it.
dependencies.<package>.optional
Section titled “dependencies.<package>.optional”- Type:
boolean - Required: no
When true, a missing program produces a warning instead of a
failure.
dependencies.<package>.install
Section titled “dependencies.<package>.install”- Type:
object - Required: no
The command that installs the program, per platform.
dependencies.<package>.install.macos
Section titled “dependencies.<package>.install.macos”- Type:
string - Required: no
The install command on macOS.
dependencies.<package>.install.linux
Section titled “dependencies.<package>.install.linux”- Type:
string - Required: no
The install command on Linux.
permissions
Section titled “permissions”- Type:
list of objects - Required: no
macOS privacy permissions the bag’s code needs, granted by a person in
System Settings under Privacy & Security. barry bag doctor uses this list
to say what to grant, and to which program, before a tool fails on a
silent denial.
permissions: - kind: automation app: Pages reason: exports documents to PDFpermissions.kind
Section titled “permissions.kind”- Type:
string - Required: yes
- Values:
automation,accessibility,screen-recording,full-disk-access
The permission.
permissions.app
Section titled “permissions.app”- Type:
string - Required: no
The app the bag sends Apple events to. Required when kind is
automation.
permissions.reason
Section titled “permissions.reason”- Type:
string - Required: yes
What the bag needs the permission for.
- Type:
list of single-key maps - Required: no
Visibility overrides for tools the bag defines in code. Each entry maps one
tool name to enabled, deferred, or disabled. A deferred tool stays
out of the session’s tool list but remains callable and findable through
tool search; a disabled tool leaves the bag. Overrides need a tools.ts
or src/tools.ts in the bag, and each tool may appear once.
tools: - search_instructions: deferred - publish_instruction: disabledTool metadata itself belongs in the tool’s code. Only a manifest that a remote bag serves over MCP may carry a list of tool metadata objects here.
tools: []prompts
Section titled “prompts”- Type:
object - Required: no
A module that adds computed text to the system prompt of every session that loads the bag. Barry builds the entry, runs it in a separate process at session start, and skips it with a warning when it fails or runs over its time budget.
prompts: entry: prompt.tsprompts.entry
Section titled “prompts.entry”- Type:
string - Required: yes
The module, relative to the bag directory. Its default export is a
definePrompt contributor.
traits
Section titled “traits”- Type:
map of <name> - Required: no
Named grants the bag publishes. Barry qualifies each one with the bag’s
name, so a trait review in bag review-policy becomes
review-policy:review. A trait may also carry restrictions through
bounds or bound. Packing the bag on an identity syncs its traits; after
you edit them, run barry bag sync-traits. See
traits.
traits: services: description: Observe and restart this instance's services bags: [mcp] access: readwritetraits.<name>
Section titled “traits.<name>”- Type:
object - Required: no
One trait.
traits.<name>.description
Section titled “traits.<name>.description”- Type:
string - Required: yes
What the trait grants.
traits.<name>.access
Section titled “traits.<name>.access”- Type:
string - Required: no
- Default:
read - Values:
read,readwrite,write
The tool access the trait grants. Barry reads write as
readwrite.
traits.<name>.includes
Section titled “traits.<name>.includes”- Type:
list of strings - Required: no
Other traits this trait includes. Barry expands them, and rejects a cycle or an unknown name.
traits.<name>.harnessTraits
Section titled “traits.<name>.harnessTraits”- Type:
map of strings - Required: no
A trait to include per harness, keyed by harness id. Barry picks the entry for the running harness, and fails when that harness has no entry.
traits.<name>.nativeTools
Section titled “traits.<name>.nativeTools”- Type:
map of string lists - Required: no
The harness’s built-in tools this trait grants, keyed by harness id. Native tools stay off until a trait grants them.
traits.<name>.bags
Section titled “traits.<name>.bags”- Type:
list of strings - Required: no
The tool namespaces the trait grants. A bag’s tools carry its name as their namespace, so this usually lists bag names.
traits.<name>.namespaces
Section titled “traits.<name>.namespaces”- Type:
list of strings - Required: no
The legacy spelling of bags. Barry reads bags first.
traits.<name>.skills
Section titled “traits.<name>.skills”- Type:
list of strings - Required: no
Skill names, the directory names under the bag’s skills/, that
the trait grants.
traits.<name>.instructions
Section titled “traits.<name>.instructions”- Type:
list of strings - Required: no
Instruction names the trait points at. The text lives in files
under an instructions/ directory, not in the manifest.
traits.<name>.bounds
Section titled “traits.<name>.bounds”- Type:
list of strings - Required: no
Named bounds whose restrictions the trait carries: this bag’s own
by bare name, or another bag’s as bag:name.
traits.<name>.bound
Section titled “traits.<name>.bound”- Type:
object - Required: no
A restriction declared inline on the trait, in the shape that bounds describes. Barry validates it against the real bound schema, so a misspelled key fails instead of restricting nothing.
bounds
Section titled “bounds”- Type:
map of <name> - Required: no
Named restrictions the bag defines. A trait refers to one in its bounds
list; other bags refer to it as bag:name.
bounds: no-bash: description: Disable Barry shell tools bound: deniedTools: [Bash, BashOutput, KillShell]bounds.<name>
Section titled “bounds.<name>”- Type:
object - Required: no
One bound.
bounds.<name>.description
Section titled “bounds.<name>.description”- Type:
string - Required: yes
What the bound restricts.
bounds.<name>.bound
Section titled “bounds.<name>.bound”- Type:
object - Required: yes
The restriction itself: denied tools, file paths, shell programs, network access, and native tools.
constants
Section titled “constants”- Type:
map of any value - Required: no
Named values that other keys reference as {constant: name}. Barry
replaces the whole reference with the value before it validates the
manifest, and leaves strings such as ${API_KEY} alone. To use another
bag’s constant, write {constant: bag:name} and compose or require that
bag.
constants: shell-denials: [git, rm]bounds: safe-shell: description: Keep shell commands read-only bound: bash: denyPrograms: {constant: shell-denials}credentials
Section titled “credentials”- Type:
map of <ENV_VAR> - Required: no
For a harness bag: where each credential its sessions authenticate with comes from when the identity doesn’t define that variable itself. The identity’s own value wins. The value always comes from the identity’s vault, never from the manifest. See secrets.
credentials: ANTHROPIC_API_KEY: { source: vault, item: anthropic-api-key, field: password }credentials.<ENV_VAR>
Section titled “credentials.<ENV_VAR>”- Type:
object - Required: no
One environment variable, in capitals, digits, and underscores.
credentials.<ENV_VAR>.source
Section titled “credentials.<ENV_VAR>.source”- Type:
string - Required: yes
- Values:
vault
Where the value comes from.
credentials.<ENV_VAR>.item
Section titled “credentials.<ENV_VAR>.item”- Type:
string - Required: yes
The vault item.
credentials.<ENV_VAR>.field
Section titled “credentials.<ENV_VAR>.field”- Type:
string - Required: yes
- Values:
username,password,notes,uri
The field of the vault item.
vendors
Section titled “vendors”- Type:
list of objects - Required: no
A catalog of model vendors and the models each serves. Barry reads the catalog as data and attaches call code separately; installing the bag makes its models available. Barry rejects a vendor listed twice, a model listed twice in one vendor, and two models of one kind that claim the same role. See adapters.
vendors: - id: ollama label: Ollama baseUrl: { env: BARRY_OLLAMA_URL, fallback: "http://127.0.0.1:11434" } credential: null models: - { id: qwen3:4b, label: Qwen3 4B, kind: completion, local: true }vendors.id
Section titled “vendors.id”- Type:
string - Required: yes
The vendor’s id.
vendors.label
Section titled “vendors.label”- Type:
string - Required: yes
The vendor’s display name.
vendors.baseUrl
Section titled “vendors.baseUrl”- Type:
string or object - Required: no
Where the vendor listens: a fixed URL, or an object with env (a
variable that overrides the URL), fallback (the URL when the
variable is unset), and path (appended to the URL). Omit it for a
vendor Barry never calls directly.
vendors.credential
Section titled “vendors.credential”- Type:
object or null - Required: yes
The key the vendor needs: {env, item, field} names the variable and
an optional default vault item, {placeholder} sends a fixed
non-secret value, and null means the vendor needs none.
vendors.compatible
Section titled “vendors.compatible”- Type:
list of objects - Required: no
Other vendors’ APIs this vendor also serves. Each entry takes with
(the other vendor’s id), baseUrl, and optional structuredOutput
and egressSandbox.
vendors.models
Section titled “vendors.models”- Type:
list of objects - Required: yes
At least one model. Each takes id, label, and kind
(completion, embedding, or decision), plus optional roles
(default, small), note, local, dimensions, and
structuredOutput (native or prompted).
mcp-servers
Section titled “mcp-servers”- Type:
map of <name> - Required: no
MCP servers this bag owns. One bag owns each server declaration; another bag reuses a server by composing its owner. See external bags.
mcp-servers: github: command: npx args: [-y, "@modelcontextprotocol/server-github"] env: [GITHUB_TOKEN]mcp-servers.<name>
Section titled “mcp-servers.<name>”- Type:
object - Required: no
One server. Declare url, command, or both.
mcp-servers.<name>.type
Section titled “mcp-servers.<name>.type”- Type:
string - Required: no
- Values:
http
The transport for a url server.
mcp-servers.<name>.url
Section titled “mcp-servers.<name>.url”- Type:
string - Required: no
The server’s URL.
mcp-servers.<name>.command
Section titled “mcp-servers.<name>.command”- Type:
string - Required: no
The program that starts a local server.
mcp-servers.<name>.args
Section titled “mcp-servers.<name>.args”- Type:
list of strings - Required: no
Arguments for command.
mcp-servers.<name>.env
Section titled “mcp-servers.<name>.env”- Type:
list of strings - Required: no
Names of the secrets the server needs. Barry resolves each one from the identity and passes it to the server.
mcp-servers.<name>.session-scoped
Section titled “mcp-servers.<name>.session-scoped”- Type:
boolean - Required: no
When true, every session gets its own connection instead of
sharing one. Set it for a server that holds state between calls,
such as a browser tab, since each session costs one server
process.
- Type:
object - Required: no
A login command for a vendor whose own command-line tool runs the browser login.
<identity> bag auth runs check first and stops when it exits 0, then
runs command interactively. The credentials stay in the vendor tool’s
own store.
auth: command: temporal args: [cloud, login] check: command: temporal args: [cloud, namespace, list]auth.command
Section titled “auth.command”- Type:
string - Required: yes
The login program.
auth.args
Section titled “auth.args”- Type:
list of strings - Required: no
Arguments for command.
auth.check
Section titled “auth.check”- Type:
object - Required: no
A command that exits 0 when the login already holds. Takes command
and args.
- Type:
object - Required: no
How the bag’s tools and scripts appear in the command-line tool.
cli: alias: wxcli.alias
Section titled “cli.alias”- Type:
string - Required: no
The command group name to use instead of the bag’s name.
default_notifier
Section titled “default_notifier”- Type:
object - Required: no
A notification tool this bag offers when the identity hasn’t configured one. An explicit notifier and the identity’s own setting both take precedence. The tool must be one this bag provides and must work without a target.
default_notifier: tool: notify_desktopdefault_notifier.tool
Section titled “default_notifier.tool”- Type:
string - Required: yes
The tool to call.
default_notifier.target
Section titled “default_notifier.target”- Type:
string - Required: no
A destination for the notification. Usually omitted, since a default that needs configuring isn’t a default.
slash-commands
Section titled “slash-commands”- Type:
object - Required: no
Slack slash commands the bag provides, such as /oncall. The Slack app bag
imports entry at startup and registers one route per command. These
aren’t coding-agent slash commands, which come from actions.
slash-commands: entry: src/slash-commands.ts commands: - name: oncall description: Show who is on callslash-commands.entry
Section titled “slash-commands.entry”- Type:
string - Required: yes
The module that exports one handler per command name.
slash-commands.commands
Section titled “slash-commands.commands”- Type:
list of objects - Required: yes
At least one command, each with a name and a description.
- Type:
object or list - Required: no
Scripts Barry runs when something happens. agent hooks fire on the
coding agent’s lifecycle, and Barry maps the neutral event names onto each
harness. barry hooks fire when Barry records an event. A bare list is a
permanent second spelling of agent.
hooks: agent: - event: session-start run: hooks/session-tracker/index.ts args: [start] barry: - event: event-created run: hooks/forward-event.tshooks.agent
Section titled “hooks.agent”- Type:
list of objects - Required: no
Hooks on the agent’s lifecycle.
hooks.agent.event
Section titled “hooks.agent.event”- Type:
string - Required: yes
- Values:
session-start,session-end,user-prompt,stop,pre-tool,post-tool
The lifecycle event.
hooks.agent.run
Section titled “hooks.agent.run”- Type:
string - Required: yes
The script, relative to the bag directory.
hooks.agent.args
Section titled “hooks.agent.args”- Type:
list of strings - Required: no
Arguments appended to the command, which often carry the hook’s mode.
hooks.agent.matcher
Section titled “hooks.agent.matcher”- Type:
string - Required: no
A Claude tool-name matcher for pre-tool and post-tool. Omitted,
the hook matches every tool.
hooks.agent.cursor-matcher
Section titled “hooks.agent.cursor-matcher”- Type:
string - Required: no
A Cursor matcher, which matches by substring.
hooks.agent.cursor-events
Section titled “hooks.agent.cursor-events”- Type:
list of strings - Required: no
Cursor event names that replace the default mapping for this hook.
hooks.agent.timeout
Section titled “hooks.agent.timeout”- Type:
number - Required: no
Seconds each run may take.
hooks.barry
Section titled “hooks.barry”- Type:
list of objects - Required: no
Hooks on Barry records. Each takes event (only event-created),
run, args, and timeout.
- Type:
object - Required: no
A single SQLite store, named default. Use stores for more than one;
declaring both fails. See
services and stores.
store: owned_by: identity engine: sqlite migrations: ./migrations/catalogstore.owned_by
Section titled “store.owned_by”- Type:
string - Required: yes
- Values:
identity,node
identity gives each identity its own database; node gives the
machine one database.
store.engine
Section titled “store.engine”- Type:
string - Required: yes
- Values:
sqlite
The database engine.
store.migrations
Section titled “store.migrations”- Type:
string - Required: yes
The directory of SQL migrations that builds the store’s schema.
stores
Section titled “stores”- Type:
map of <name> - Required: no
The bag’s SQLite stores, keyed by lowercase name. Each entry takes the
same owned_by, engine, and migrations keys as store.
stores: events: owned_by: identity engine: sqlite migrations: ./migrations/events unscoped: owned_by: node engine: sqlite migrations: ./migrations/eventsstores.<name>
Section titled “stores.<name>”- Type:
object - Required: no
One store. The name uses lowercase letters, digits, hyphens, and underscores, and starts with a letter or digit.
stores.<name>.owned_by
Section titled “stores.<name>.owned_by”- Type:
string - Required: yes
- Values:
identity,node
identity gives each identity its own database; node gives the
machine one database.
stores.<name>.engine
Section titled “stores.<name>.engine”- Type:
string - Required: yes
- Values:
sqlite
The database engine.
stores.<name>.migrations
Section titled “stores.<name>.migrations”- Type:
string - Required: yes
The directory of SQL migrations that builds the store’s schema.
snapshots
Section titled “snapshots”- Type:
map of <store> - Required: no
Snapshot hooks for stores whose database refers to companion files. Each
key names a declared store (default for store), and entry names a
compiled JavaScript module inside the bag that exports
captureSnapshot.
store: owned_by: identity engine: sqlite migrations: ./migrations/catalogsnapshots: default: entry: ./dist/snapshot.jssnapshots.<store>
Section titled “snapshots.<store>”- Type:
object - Required: no
The hook for one declared store.
snapshots.<store>.entry
Section titled “snapshots.<store>.entry”- Type:
string - Required: yes
A .js or .mjs path inside the bag.
restores
Section titled “restores”- Type:
map of <store> - Required: no
Restore hooks that prepare a store from a snapshot, used by
barry db restore. Each key names a store, and entry names a compiled
JavaScript module inside the bag that exports prepareRestore.
restores: default: entry: ./dist/restore-adapter.jsrestores.<store>
Section titled “restores.<store>”- Type:
object - Required: no
The hook for one declared store.
restores.<store>.entry
Section titled “restores.<store>.entry”- Type:
string - Required: yes
A .js or .mjs path inside the bag.
services
Section titled “services”- Type:
map of <name> - Required: no
Long-running processes the bag ships. A service runs continuously, and
Barry restarts one that exits. The service manager assigns an HTTP
service its port and passes it as PORT; where the service is reachable
from is installation policy, not manifest data. Set exactly one of entry
or command.
services: web: description: Serves the bag's dashboard entry: src/server.ts working-directory: . serves: http health: /health secrets: [BARRY_SECRET]services.<name>
Section titled “services.<name>”- Type:
object - Required: no
One service.
services.<name>.description
Section titled “services.<name>.description”- Type:
string - Required: yes
What the service does.
services.<name>.entry
Section titled “services.<name>.entry”- Type:
string - Required: no
A JavaScript or TypeScript file inside the bag, run with Barry’s Node.
services.<name>.command
Section titled “services.<name>.command”- Type:
string - Required: no
A program to run instead of an entry.
services.<name>.args
Section titled “services.<name>.args”- Type:
list of strings - Required: no
Arguments for the entry or command.
services.<name>.env
Section titled “services.<name>.env”- Type:
list of strings - Required: no
Non-secret KEY=VALUE literals. Put credentials in secrets.
services.<name>.secrets
Section titled “services.<name>.secrets”- Type:
list of strings - Required: no
Names of the secrets the service needs.
services.<name>.optional-secrets
Section titled “services.<name>.optional-secrets”- Type:
list of strings - Required: no
Secrets the service runs without when they’re absent.
services.<name>.working-directory
Section titled “services.<name>.working-directory”- Type:
string - Required: no
The directory the service starts in, relative to the bag.
services.<name>.autostart
Section titled “services.<name>.autostart”- Type:
string - Required: no
- Default:
login - Values:
login,manual
login starts the service when you log in; manual leaves
starting it to something else.
services.<name>.serves
Section titled “services.<name>.serves”- Type:
string - Required: no
- Values:
http
The protocol the service speaks. Omit it for a service that serves nothing.
services.<name>.health
Section titled “services.<name>.health”- Type:
string - Required: no
A readiness path, such as /health. Needs serves or socket.
services.<name>.socket
Section titled “services.<name>.socket”- Type:
string - Required: no
A Unix socket to listen on instead of a port, relative to the
service’s state directory for a user service and to the bag
otherwise.
services.<name>.user
Section titled “services.<name>.user”- Type:
string - Required: no
A macOS service account to run as, starting with an underscore,
such as _barryvault. sudo barry setup --system creates the
account and installs the service as a LaunchDaemon.
services.<name>.local-only
Section titled “services.<name>.local-only”- Type:
boolean - Required: no
- Values:
true
Marks a service whose security assumes callers on this Mac. Barry
refuses any tunnel route to it. Needs serves or socket.
- Type:
map of <name> - Required: no
macOS or iOS apps the bag builds and registers. Unlike a service, a person launches an app and may quit it. See apps.
apps: menubar: name: Weather description: Menu bar forecast platform: macos build: build:app output: dist/Weather.app macos: bundle-id: rocks.barry.weather login-item: trueapps.<name>
Section titled “apps.<name>”- Type:
object - Required: no
One app.
apps.<name>.name
Section titled “apps.<name>.name”- Type:
string - Required: yes
The app’s display name.
apps.<name>.description
Section titled “apps.<name>.description”- Type:
string - Required: yes
What the app does.
apps.<name>.platform
Section titled “apps.<name>.platform”- Type:
string - Required: yes
- Values:
macos,ios
The platform. It decides whether macos or ios applies.
apps.<name>.build
Section titled “apps.<name>.build”- Type:
string or object - Required: yes
A package script name, or an Xcode build as project (a
.xcodeproj path), scheme, and configuration (default
Release).
apps.<name>.output
Section titled “apps.<name>.output”- Type:
string - Required: yes
The .app bundle the build produces, inside the bag.
apps.<name>.id
Section titled “apps.<name>.id”- Type:
string - Required: no
The app’s id.
apps.<name>.protocol-version
Section titled “apps.<name>.protocol-version”- Type:
number - Required: no
- Values:
1,2
The app protocol the app speaks: 1 for the legacy protocol, 2
for AG-UI.
apps.<name>.capabilities
Section titled “apps.<name>.capabilities”- Type:
object - Required: no
Protocol capabilities, each a boolean: streaming, gating,
listener, attachments, approvalReview, and replay. Needs
protocol-version.
apps.<name>.macos
Section titled “apps.<name>.macos”- Type:
object - Required: no
macOS registration: bundle-id, url-schemes, login-item, and
keep-alive.
apps.<name>.ios
Section titled “apps.<name>.ios”- Type:
object - Required: no
iOS registration: bundle-id, url-schemes, and device, which
says whether the app can install onto a device.
- Type:
map of <name> - Required: no
Work the bag ships for Barry to run: on a schedule, from the SDK, or for a
subagent. A job pairs a contract (what it needs, takes, and produces)
with runs, which says what does the work. Job names are kebab-case. See
background work.
jobs: reaper: description: Close sessions whose process is gone runs: using: node main: src/reaper.ts secrets: [BARRY_SECRET] env: - BARRY_REAPER_DRY_RUN=0 timeout: 10mjobs.<name>
Section titled “jobs.<name>”- Type:
object - Required: no
One job.
jobs.<name>.description
Section titled “jobs.<name>.description”- Type:
string - Required: no
What the job does.
jobs.<name>.version
Section titled “jobs.<name>.version”- Type:
string or number - Required: no
The job’s version. A versioned job runs on other machines as
bag:name@version.
jobs.<name>.runs
Section titled “jobs.<name>.runs”- Type:
object - Required: yes
What does the work. using decides which other keys apply.
jobs.<name>.runs.using
Section titled “jobs.<name>.runs.using”- Type:
string - Required: yes
- Values:
node,process,action
node runs the JavaScript or TypeScript file in main with
Barry’s Node. process runs command, a list of program and
arguments, without a shell. action hands the work to an
agent through action, this bag’s action or bag:name.
jobs.<name>.runs.secrets
Section titled “jobs.<name>.runs.secrets”- Type:
list of strings - Required: no
For node and process: names of the secrets the process
needs.
jobs.<name>.runs.env
Section titled “jobs.<name>.runs.env”- Type:
list of strings - Required: no
For node and process: non-secret KEY=VALUE literals.
jobs.<name>.runs.working-directory
Section titled “jobs.<name>.runs.working-directory”- Type:
string - Required: no
For node and process: the directory to run in, relative
to the bag.
jobs.<name>.requires
Section titled “jobs.<name>.requires”- Type:
object - Required: no
What must exist for the job to run: tools, secrets, bins,
and labels, the worker labels a machine needs to take the job.
jobs.<name>.preflight
Section titled “jobs.<name>.preflight”- Type:
object - Required: no
A probe Barry runs before the job: command must exit 0 within
timeout seconds (60 at most), and hint tells a person how to
fix a failure. A job whose probe fails doesn’t start.
jobs.<name>.validate
Section titled “jobs.<name>.validate”- Type:
object - Required: no
Checks Barry makes when the job finishes: files_exist,
command, and timeout in seconds (600 at most).
jobs.<name>.input_schema
Section titled “jobs.<name>.input_schema”- Type:
object - Required: no
JSON Schema for the job’s inputs. Not for an action job, which
takes it from the action.
jobs.<name>.output_schema
Section titled “jobs.<name>.output_schema”- Type:
object - Required: no
JSON Schema for the job’s result. Not for an action job.
jobs.<name>.timeout
Section titled “jobs.<name>.timeout”- Type:
number or string - Required: no
How long a run may take: seconds, or a number with s, m, h,
or d.
jobs.<name>.bounds
Section titled “jobs.<name>.bounds”- Type:
list of strings - Required: no
Named bounds the job’s process runs under. A bounded job must use
node with a single .js or .mjs file, and can’t declare
preflight or validate.
schedules
Section titled “schedules”- Type:
map of <name> - Required: no
Work the scheduler runs on a trigger. Each schedule sets exactly one
trigger (every, cron, or at) and exactly one payload (job,
action, or entry). Schedule names are kebab-case. See
schedules and workers.
schedules: maintenance: every: 1d traits: [bash, artifacts] job: maintenance digest: cron: "0 9 * * 1" timezone: America/New_York action: slack:weekly-digest inputs: { channel: eng }schedules.<name>
Section titled “schedules.<name>”- Type:
object - Required: no
One schedule.
schedules.<name>.description
Section titled “schedules.<name>.description”- Type:
string - Required: no
What the schedule does.
schedules.<name>.every
Section titled “schedules.<name>.every”- Type:
string - Required: no
- Values:
1m,5m,15m,30m,1h,1d
A recurring trigger on the calendar: 5m fires at minutes 0, 5,
10, and so on.
schedules.<name>.cron
Section titled “schedules.<name>.cron”- Type:
string - Required: no
A five-field cron expression.
schedules.<name>.timezone
Section titled “schedules.<name>.timezone”- Type:
string - Required: no
- Default:
UTC
The IANA time zone for every or cron.
schedules.<name>.at
Section titled “schedules.<name>.at”- Type:
string - Required: no
login to run once per login session, or an ISO 8601 time with an
offset to run once.
schedules.<name>.job
Section titled “schedules.<name>.job”- Type:
string - Required: no
A job to run: this bag’s by name, or bag:name, optionally with
@version.
schedules.<name>.action
Section titled “schedules.<name>.action”- Type:
string or object - Required: no
An action to run, by name or bag:name, or an inline action: the
body of an action.yaml without name.
schedules.<name>.entry
Section titled “schedules.<name>.entry”- Type:
string - Required: no
A script inside the bag to run directly. Only an entry schedule
takes args, env, secrets, and timeout.
schedules.<name>.args
Section titled “schedules.<name>.args”- Type:
list of strings - Required: no
Arguments for entry.
schedules.<name>.env
Section titled “schedules.<name>.env”- Type:
list of strings - Required: no
Non-secret KEY=VALUE literals for entry.
schedules.<name>.secrets
Section titled “schedules.<name>.secrets”- Type:
list of strings - Required: no
Secret names for entry.
schedules.<name>.timeout
Section titled “schedules.<name>.timeout”- Type:
number or string - Required: no
How long an entry run may take: seconds, or a number with s,
m, h, or d.
schedules.<name>.identity
Section titled “schedules.<name>.identity”- Type:
string - Required: no
The identity an agent action runs as.
schedules.<name>.inputs
Section titled “schedules.<name>.inputs”- Type:
object - Required: no
Inputs for the action, checked against its input schema when it runs.
schedules.<name>.traits
Section titled “schedules.<name>.traits”- Type:
list of strings - Required: no
Traits the run gets.
schedules.<name>.bounds
Section titled “schedules.<name>.bounds”- Type:
list of strings - Required: no
Bounds the run runs under.
schedules.<name>.overlap
Section titled “schedules.<name>.overlap”- Type:
string - Required: no
- Default:
skip - Values:
skip,queue
What to do when a fire arrives while the last run is still going.
schedules.<name>.catch_up
Section titled “schedules.<name>.catch_up”- Type:
string - Required: no
- Default:
once - Values:
none,once
Whether to run a fire that the machine missed while it slept or was off.
schedules.<name>.enabled
Section titled “schedules.<name>.enabled”- Type:
boolean - Required: no
- Default:
true
Set it to false to keep the schedule from firing.
scripts
Section titled “scripts”- Type:
map of <name> - Required: no
Commands the bag ships for a person to run on demand from the bag’s
command group. Barry reads scripts from the manifest alone, so a script
runs even when the bag’s tool code fails to load. Set exactly one of
entry or command.
scripts: audit: description: Check an identity's secret references and bag credentials command: barry args: [identity, check]scripts.<name>
Section titled “scripts.<name>”- Type:
object - Required: no
One script.
scripts.<name>.description
Section titled “scripts.<name>.description”- Type:
string - Required: yes
What the script does.
scripts.<name>.entry
Section titled “scripts.<name>.entry”- Type:
string - Required: no
A JavaScript or TypeScript file inside the bag.
scripts.<name>.command
Section titled “scripts.<name>.command”- Type:
string - Required: no
A program to run instead of an entry.
scripts.<name>.args
Section titled “scripts.<name>.args”- Type:
list of strings - Required: no
Arguments for the entry or command.
scripts.<name>.env
Section titled “scripts.<name>.env”- Type:
list of strings - Required: no
Non-secret KEY=VALUE literals.
scripts.<name>.secrets
Section titled “scripts.<name>.secrets”- Type:
list of strings - Required: no
Names of the secrets the script needs.
scripts.<name>.working-directory
Section titled “scripts.<name>.working-directory”- Type:
string - Required: no
The directory to run in, relative to the bag. Defaults to the bag directory.
- Type:
object - Required: no
A Terraform root the bag owns. barry bag infra runs Terraform there with
the declared variables set, and barry bag check fails when the root
doesn’t exist.
infra: provider: terraform root: infra variables: [CLOUDFLARE_API_TOKEN]infra.provider
Section titled “infra.provider”- Type:
string - Required: yes
- Values:
terraform
The infrastructure tool.
infra.root
Section titled “infra.root”- Type:
string - Required: yes
The Terraform root directory, relative to the bag.
infra.variables
Section titled “infra.variables”- Type:
list of strings - Required: no
Environment variables Terraform needs.
provides
Section titled “provides”- Type:
object - Required: no
For a hosting provider bag: what hosting it can do. Barry checks routes in
the installation’s hosting policy against it and refuses a route the
provider can’t honor, such as a public route with no gate. Name local,
tunnel, or both.
provides: local: {} tunnel: reach: [private, public] gates: [access]provides.local
Section titled “provides.local”- Type:
object - Required: no
An empty object: the provider can give services readable names on this Mac.
provides.tunnel
Section titled “provides.tunnel”- Type:
object - Required: no
The provider can carry routes in from elsewhere.
provides.tunnel.reach
Section titled “provides.tunnel.reach”- Type:
list of strings - Required: yes
- Values:
private,public
Where routes can come from.
provides.tunnel.gates
Section titled “provides.tunnel.gates”- Type:
list of strings - Required: no
- Values:
access
The gates the provider can put in front of a route.
Examples
Section titled “Examples”A tools-only bag
Section titled “A tools-only bag”Tools in src/tools.ts, a host program they call, and a trait that grants them.
name: weatherdescription: Current conditions and forecasts from the National Weather Service
dependencies: jq: reason: shapes forecast JSON for the summary tool install: macos: brew install jq
traits: forecasts: description: Read forecasts and current conditions bags: [weather] access: readA bag with a service, a store, and background work
Section titled “A bag with a service, a store, and background work”A dashboard service, an identity-owned store, and a nightly job.
name: reading-listdescription: Saved articles with a reading dashboard and a nightly cleanup
requires: sessions: reason: links each saved article to the session that saved it
stores: articles: owned_by: identity engine: sqlite migrations: ./migrations/articles
services: web: description: Serves the reading dashboard entry: src/server.ts working-directory: . serves: http health: /health secrets: [BARRY_SECRET]
jobs: prune: description: Archive articles read more than 30 days ago runs: using: node main: src/prune.ts secrets: [BARRY_SECRET] timeout: 5m
schedules: prune: cron: "30 4 * * *" timezone: UTC traits: [bash, reading-list] job: prune
scripts: export: description: Write every saved article to a Markdown file command: npx args: [tsx, scripts/export.ts]A policy bag
Section titled “A policy bag”Constants, named bounds, and traits that compose them, with no code at all.
name: review-policydescription: Reusable review restrictions
constants: shell-denials: [git, rm]
bounds: safe-shell: description: Keep shell commands read-only bound: bash: denyPrograms: {constant: shell-denials}
traits: review: description: Review restrictions bounds: [safe-shell] restricted: description: Composed review policy includes: [review]