Guides
Agent profiles
On this page
A profile is a YAML file that tells Brig which image to boot, where the guest home is, and which credentials the guest receives.
The command and its <ref> argument say "agent": brig agent ls, brig agent edit. The file format, the profile directory and BRIG_PROFILE_DIR say "profile".
A profile is optional. Brig boots an agent from an OCI image, and any Linux CLI that runs in one works. A profile saves you from typing the image, the guest home and the credential variables on every run.
Minimal profile #
name: mine
image: ghcr.io/brig-sh/claude-code-stock:root
guestHome: /root
binary: claude
mem: 4096
cpus: 4The default kind: agent requires these six fields. All other fields are optional.
Create a profile #
Start from the closest existing profile:
brig agent new mine --from claude-code # writes ~/.config/brig/mine.yaml
brig agent edit mine # change the image, and what it forwards
brig run mineThe argument of new is a name. Brig writes the file to your profile directory and refuses a name that contains /.
new also writes the name into the name: field. Brig identifies a profile by that field, not by the file name. The rest of the file is the profile you copied, with a header comment that explains every field.
brig agent edit opens the profile's file in $VISUAL, then $EDITOR, then vi. It works only on a profile that has a file. For a built-in profile, it prints the commands that create a file, and it creates nothing.
To import a file that you wrote by hand, use brig agent import:
brig agent import mytool.yamlFields #
| Field | Required | Purpose |
|---|---|---|
name |
yes | Profile name |
image |
yes | Guest image to boot |
guestHome |
yes | Where the guest home is mounted |
kind |
no | agent, shell or gui |
binary |
yes, for kind: agent |
Agent CLI inside the guest |
mem |
yes | Guest memory |
cpus |
yes | Guest CPU count |
desc |
no | One-line description |
secrets |
no | Secrets the profile wants from the store |
env |
no | Variables the guest sees |
forward |
no | Deprecated spelling of env |
files |
no | Credential files the guest sees |
volumes |
no | Mounts inside guestHome |
deny |
no | Variables never bound |
statePaths |
no | Deprecated, superseded by volumes |
staleCredentialFiles |
no | Old credential paths to warn about |
headless |
no | Agent supports a non-interactive run |
guiTitle |
no | Window title for a kind: gui profile |
network |
no | Network posture |
hypervisor |
no | macOS backend |
runtimeBin |
no | Runtime binary to drive |
rootfsType |
no | How the guest root reaches the microVM |
genericBoot |
no | Boot a plain OCI image |
hostConfigDir |
no | Host agent configuration directory |
projectPaths |
no | Subdirectories to seed with --skills |
onboarding |
no | First-run state file to seed |
reserved |
no | Protects a guest home from session names |
unpublished |
no | No published image |
policy |
no | Policies attached inline |
Brig refuses a misspelled field, such as forwards: in place of forward:.
name #
The profile name. It becomes the guest home directory and the sandbox name.
name: mineLimits:
- Lowercase letters, digits, dot, dash and underscore only.
image #
The guest image to boot.
image: ghcr.io/brig-sh/claude-code-stock:rootLimits:
- Brig cannot check the signature of an image outside
ghcr.io/brig-sh. It warns on every boot and still boots. See Security.
guestHome #
The absolute path where the guest home is mounted. The state of the agent lands here, so the guest home is the unit that persists.
guestHome: /rootkind #
Sets what brig run does when the guest is up. Default: agent.
kind: shell| Value | What brig run does |
Trailing arguments |
|---|---|---|
agent |
Execs binary: |
Passed to binary: |
shell |
Opens a login shell | Run as one command |
gui |
Boots the sandbox with a graphical console | Refused |
brig sh always execs bash -l, or bash -lc for a command. It never execs binary:.
For kind: gui, brig run starts the sandbox and attaches to nothing. guiTitle names the window.
Limits:
- A
kind: shellorkind: guiprofile cannot carrypolicy:, because it has no agent process for an egress rule. Brig refuses the profile at parse time. - Only the
vzhypervisor backend shows a console. Brig refuses to boot akind: guiprofile onhviorqemu. - The older
shell:andgui:booleans still parse. Brig converts them tokind:when it reads the file. See Migration.
binary #
The agent CLI inside the guest, which brig run execs.
binary: claudeLimits:
- For
kind: shell, Brig does not require or read the field. The built-inubuntuprofile setsbinary: bashonly as documentation.
mem #
Guest memory size.
mem: 4096Limits:
- Must be greater than zero.
cpus #
Guest CPU count.
cpus: 4Limits:
- Must be greater than zero.
desc #
One line that brig agent ls shows.
desc: our internal agentsecrets #
The names of the secrets that this profile wants from Brig's secret store. secrets: is the list of requirements, and env and files are the bindings.
secrets:
- gh_token
env:
- name: GH_TOKEN
ref: secrets.gh_tokenA bare string is the short form of a required secret that you create by hand. secrets: [gh_token] means {name: gh_token, required: true}.
Object form #
secrets:
- name: claude-credentials
required: false # warn and boot, instead of refusing
expiryField: expiresAt # found at any depth; drives the stale warning
sources: # where `brig secret import` looks
- from: keychain
service: Claude Code-credentials
- from: file
path: ~/.claude/.credentials.json
hint: run `claude` on the host once to log in| Key | What it does |
|---|---|
name |
The name of the secret in the store |
required |
Decides whether the run stops. Absent means required. required: false warns and boots |
sources |
Where brig secret import looks. Also decides which command the error names |
field |
How to read the value of the secret from what a source yields. If absent, Brig stores the value verbatim |
expiryField |
How to read the expiry of the secret from what a source yields |
The built-in claude-code profile uses required: false, because the agent can log in inside the sandbox.
field: and expiryField: belong to the secret, not to a source. Every source for one secret must yield the same document shape.
Leave field: out for a secret that is a file. The host keychain blob has the format of the agent's credentials file, so Brig stores it whole and loses no field.
Sources #
Brig tries the sources in order, and the first that exists wins. One secret can name the macOS keychain and the Linux file, so one profile works on both platforms.
A secret with no sources: is one that you create by hand.
Each from: value takes one locator:
from: |
Locator | What it reads |
|---|---|---|
keychain |
service: |
A macOS keychain generic-password item. macOS only. The Linux store is a Secret Service keyring, and no source reads from it. See Secrets |
file |
path: |
A host file, verbatim. Brig expands a leading ~ when it reads the file, so a profile holds no home directory of one host |
env |
var: |
A host environment variable, copied once at import |
A source with the wrong locator is a parse error, for example a keychain source with a path:.
Warning
from: envandref: env.<name>behave differently. Brig reads aref:on every run. Afrom: envsource copies the value into the store when you runbrig secret import, and never reads it again. For a value that expires, use arefs:chain. For this reason, the built-inclaude-codeprofile uses nofrom: envsource.
On macOS, the keychain source answers first, so Brig never reaches the path: ~/.claude/.credentials.json source there. That path is the documented Linux location, not an observed one. On a Linux host with a keyring, import reads that file and stores it in the Secret Service backend.
Limits:
- A credential whose two host locations differ in shape needs two secrets.
- A
files:binding names one secret, and onepath:takes one binding. One portable profile cannot express an agent whose credential file differs per platform. Claude's two locations share a shape.
Missing secrets #
A missing required secret fails the run before Brig creates a sandbox. The error names the secret, the sandbox and the command that creates the secret:
$ brig run mine
brig: missing secret "gh_token" needed by the brig-mine sandbox -- create it first with: brig secret create gh_tokenIf more than one secret is missing, one error names all of them:
brig: missing 2 secrets needed by the brig-mine sandbox:
gh_token: create it first with: brig secret create gh_token
npm_token: create it first with: brig secret create npm_tokenA missing optional secret gives a warning, and the run boots. The warning names the secret and the command that supplies it:
$ brig run claude-code
brig: claude-code runs without 1 secret
○ claude-credentials → brig secret import claude-code
↳ run `claude` on the host once to log inFor a secret with no sources:, the message names brig secret create, because import cannot fill it:
brig: claude-code runs without 1 secret
○ gh-token → brig secret create gh-token
↳ export GH_TOKEN before running brig, or store one: gh auth token | brig secret create gh-tokenLinux hosts without a keyring
On Linux, the store is a Secret Service keyring. A host with no session bus, or with nothing that answers on it, has no store.
| Secret | Result on a host with no store |
|---|---|
| Required | Every run fails, in the same way as any missing required secret |
| Optional | No warning. The run boots |
To change the result, install a keyring. This is why the built-in claude-code profile boots on Linux.
env #
The variables that the guest sees, and the source of each value: a literal, a stored secret, or Brig's environment.
env:
- name: GH_TOKEN
ref: secrets.gh_token
- name: CI
ref: env.CI
- name: EDITOR
value: viEach entry has a name: and one source:
| Key | Source |
|---|---|
value: |
A literal, for configuration that is not a credential |
ref: secrets.<name> |
The named secret in Brig's store |
ref: env.<name> |
The named variable in Brig's environment |
refs: |
A list of refs. The first that resolves wins |
ref: is a refs: of length one. A binding carries one of the two spellings.
env:
- name: GH_TOKEN
refs: [env.GH_TOKEN, secrets.gh-token] # shell override first, store secondBrig drops a name that a profile binds from the ambient forward. With a bare ref: secrets.gh-token, the value from GH_TOKEN=$(gh auth token) brig run claude-code does not reach the guest, and BRIG_FORWARD_ENV cannot restore it. The chain above keeps the shell override and adds the store as a fallback. The built-in claude-code profile binds GH_TOKEN this way.
If an earlier env. element resolves, Brig does not need the later secrets. element. A run that the environment satisfies does not open the store or the keychain.
Limits:
- An entry must have one of
value:orref:. Brig refuses an entry with both or with neither. - A ref namespace other than
secrets.orenv.is a parse error. The error names the two that exist. - A
secrets.<name>ref whose name is absent fromsecretsis a parse error.
Runtime variables #
The runtime reads HOME, PATH, TMPDIR and XDG_* for itself. Brig passes their guest values on the runtime's command line as NAME=value. See Security.
A binding for one of these names takes value: or ref: env.<name>. A stored secret never goes on the command line. Brig refuses a binding that resolves from the secret store when the sandbox boots or execs.
BRIG_FORWARD_ENV #
BRIG_FORWARD_ENV overrides which variables Brig carries in from its environment. It replaces only the set that comes from the environment. A ref: secrets.<name> binding does not change.
Sandboxes served by brigd #
For a sandbox that brigd serves, an env.<name> ref resolves against the environment of the daemon, not of the shell that sent the request. See brigd.
forward #
Deprecated. A list of variable names to carry in from Brig's environment. Brig converts it to an equivalent env: binding when it reads the file. See Migration.
forward:
- MYTOOL_TOKEN
- GH_TOKENbrig agent show --json always prints the env: form, because JSON export marshals the parsed profile. Plain YAML export returns the file as written.
files #
Credential files that the guest sees. Each entry names a stored secret and the path under guestHome where Brig writes it.
files:
- ref: secrets.claude-credentials
path: .claude/.credentials.json # relative to guestHome
mode: "0600" # default "0600"; quoted, see below| Key | What it is |
|---|---|
ref |
The stored secret, as secrets.<name> |
path |
Target path, relative to guestHome |
mode |
File mode, as a quoted string. Default "0600" |
Use files: where the agent can read a credential from a file, and env: where it cannot. A file stays out of /proc/<pid>/environ. The processes that the agent spawns do not inherit it. Brig can rewrite it under a running agent, so a rotated secret can reach a live session.
The agents that use GEMINI_API_KEY, XAI_API_KEY, OPENROUTER_API_KEY and CURSOR_API_KEY read them only from the environment. You can bind one secret through both channels. The exposure is then the union of the two, so do it only when something reads both.
Limits that the parser enforces:
ref:only. Brig refusesrefs:andenv.<name>.mode:is a quoted string. YAML reads an unquoted0600as decimal 600, which is0o1130.- The target must be inside a
tmpfsvolume. Ahostmountunder that volume must not bind the target back out. Brig refuses this at parse time. Seevolumes. - One binding per
path:.
Other limits:
field:on a file-bound secret writes a bare token where the agent expects a document. The agent then tries a refresh, fails, and prompts. Usefield:only when the agent reads a one-line file.- An unresolved binding leaves no file, no mount and no empty target.
brig secret push, for rotating a file binding in a running sandbox, is not implemented yet. A re-run rewrites the file under a live agent.
volumes #
The mounts inside guestHome, one primitive per entry.
volumes:
- kind: tmpfs
path: .claude # memory-only: nothing written here reaches the host
size: 512m # optional, default 64m
- kind: hostmount
path: .claude/sessions # ... except these, kept across boots
- kind: hostmount
path: .claude/projects
- kind: hostmount
path: .claude/history.jsonl
file: true # the target is a file, not a directorykind: |
What it does |
|---|---|
tmpfs |
Covers a directory so that nothing written under it can reach your disk |
hostmount |
An exception: one path bound back out to the same path in the guest home |
volume |
Reserved for a named volume that several sandboxes share. Parsed and refused as not yet supported |
| Key | Applies to | What it is |
|---|---|---|
path |
both | Path inside guestHome |
size |
tmpfs |
How big the tmpfs can grow. Default 64m |
file |
hostmount |
true when the target is a file, not a directory |
A tmpfs leaves a files binding no path from the credential to the host. Brig checks this: the covered path must read as tmpfs and /proc/swaps must be empty. If not, the run stops before Brig hands over a credential.
Order in the file does not matter, because Brig mounts parents before children.
size: is a ceiling. At the ceiling, tools in the guest get ENOSPC, and nothing on the host watches for it. A directory of configuration needs less than the home of an agent, where edit history and per-job scratch accumulate.
Limits:
- A
hostmountmust be nested under atmpfs. Otherwise it is a parse error. - Brig refuses
source:on ahostmount. Its source is implicit. - A
hostmounttakes nosize:. It is as large as the guest home it comes from. size:must be a number optionally followed byk,morg. Brig refuses anything else at parse time.
Warning State that an agent writes under a
tmpfs-covered path with no matchinghostmountdoes not survivebrig stop.
The built-in profiles differ here:
| Profile | Hostmounts under .claude |
Result |
|---|---|---|
claude-code |
Includes .claude/skills and .claude/plugins |
A --skills copy there survives a stop |
claude-desktop |
settings.json, CLAUDE.md, sessions, projects, plugins and history.jsonl |
.claude/skills is not kept. Anything the bundled desktop app writes there is lost at shutdown |
claude-code and claude-desktop are the only two built-in profiles that declare volumes:. The other six persist everything under guestHome to host disk, with nothing memory-only. codex, cursor, gemini, grok and opencode declare only the deprecated statePaths:. ubuntu declares neither.
deny #
Variables that Brig never binds, whatever env or forward says.
deny:
- MYTOOL_ADMIN_KEY # lets the agent reconfigure the accountSome provider variables outrank the credential that you want the sandbox to use. For example, Claude Code prefers ANTHROPIC_API_KEY to its subscription credential. If Brig forwards it, the sandbox moves from your subscription to metered API billing and does not tell you. Put each variable of this type in deny.
Brig refuses a denied variable with an explanation. BRIG_ALLOW_DENIED=1 overrides the refusal, for a user who wants metered billing.
Limits:
denyapplies in the same way to a value that arrives byref:.denyguards the environment channel only. Brig does not check afiles:binding against it, so a profile can deliver a metered key inside asettings.jsonand nothing detects it.
statePaths #
Deprecated, superseded by volumes. It still parses. See Migration.
statePaths:
- .config/mytoolLimits:
- Declaring it with
volumes:is an error, not a merge.
staleCredentialFiles #
Paths where an older wrapper wrote a credential. Brig never writes a credential there. If Brig finds one, it warns and does not delete it.
staleCredentialFiles: [.claude/.credentials.json]headless #
States that the agent supports a non-interactive run.
headless: trueguiTitle #
The window title for a kind: gui profile.
kind: gui
guiTitle: Claude Desktopnetwork #
The network posture of the sandbox. A new sandbox defaults to isolated.
network: isolated| Value | Meaning |
|---|---|
shared |
One network for the sandboxes that use it |
isolated |
A network for this sandbox only |
offline |
No route out |
See Policies for the postures.
An existing sandbox keeps its recorded posture. BRIG_NETWORK, --network and --offline override the profile and a recorded posture.
The vz and qemu backends, and older sessions
| Case | Result |
|---|---|
No posture named, on hull's vz or qemu backend |
Falls back to shared, and Brig reports it |
Explicit isolated on vz or qemu |
Refused. Those backends cannot enforce isolation |
| Existing session with no recorded posture | Keeps the posture inspected from the runtime |
If you copy a profile that names isolated and change its backend to vz or qemu, change the network to shared too.
hypervisor #
The macOS backend to boot on. Linux ignores the field, because the shim decides.
hypervisor: hvi| Value | Notes |
|---|---|
vz |
The default when the field is absent. The only backend with a graphical console |
hvi |
Six of the eight built-in profiles say hvi |
qemu |
BRIG_HYPERVISOR overrides the field.
runtimeBin #
The runtime binary to drive, in place of the one on PATH. Brig expands ~.
runtimeBin: ~/bin/hullThis field describes your machine, so do not share it in a profile. Use it to pin a profile to a runtime build that you work on.
BRIG_RUNTIME_BIN overrides the field.
rootfsType #
How the guest root reaches the microVM: block, virtiofs or 9pfs.
rootfsType: block # room to apt installIf the field is unset, the runtime picks its default. That default suits a profile that only runs an agent. If the sandbox installs packages, set block. The sandbox then has a writable disk in place of a share sized to the image.
genericBoot #
States that the image is a plain OCI image such as ubuntu:latest, with no kernel and no urunc metadata. The runtime supplies the kernel and initrd and boots the image unmodified, on macOS and Linux.
name: plain-ubuntu
image: docker.io/library/ubuntu:latest
guestHome: /root/work
kind: shell
binary: bash
genericBoot: true
rootfsType: block # room to apt install
mem: 4096
cpus: 2The image's argv, environment, hostname and mounts are restored before the guest switches root.
Two OCI annotations carry the kernel and the initrd. Both are host files and never come from image metadata, so an image cannot name a file on your machine. The kernel file is Image on arm64 and bzImage on x86_64. The guest agent that brig sh talks to comes from the initrd, not from the image.
If the kernel and initrd are missing, Brig fetches them once, on the first brig run of a genericBoot profile.
hull takes the two annotations on its command line.
The kernel and initrd are in hull's store, and Brig asks hull for their location.
hull fetches them.
urunc reads the two annotations from the OCI spec of the container, which nerdctl passes through. This needs the urunc that the runtime bundle builds, because no urunc release reads the pair. See Runtimes.
Brig looks for the kernel and initrd in ~/.local/share/brig/assets.
Brig fetches with oras. If oras is not installed, Brig says so and tells you what to fetch.
genericBoot needs nerdctl, not docker. Docker does not pass OCI annotations to the runtime, so a sandbox booted through it has no kernel. Brig refuses before the boot.
| Variable | Effect |
|---|---|
BRIG_BOOT_ASSETS |
Overrides where Brig looks for the kernel and initrd, on both platforms. Turns the fetch off |
BRIG_BOOT_ASSETS_REF |
Pins a specific bundle in place of the current one for your platform |
The bundle is published as the OCI artifact ghcr.io/nofireai/hull-assets, one tag per guest platform. It pulls anonymously. The repository that builds it is not public. To do the same fetch by hand:
oras pull ghcr.io/nofireai/hull-assets:<os>-<arch> --output <dir>See Guest image for what genericBoot means for the image.
hostConfigDir #
The directory of your agent configuration on the host. Brig uses it only when the run passes --skills or sets BRIG_SKILLS=1.
hostConfigDir: ~/.claude
projectPaths: [skills, plugins]Limits:
hostConfigDirandprojectPathsare required together.- Only
claude-codedeclares them, so--skillsdoes nothing on the other seven built-in profiles.
projectPaths #
The subdirectories of hostConfigDir that Brig seeds into the guest home, under the same condition.
hostConfigDir: ~/.claude
projectPaths: [skills, plugins]Limits:
- Required together with
hostConfigDir.
onboarding #
A first-run state file to seed.
onboarding:
file: .claude.json
seed:
hasCompletedOnboarding: true
hasTrustDialogAccepted: true
trustKey: [projects, hasTrustDialogAccepted]| Key | What it does |
|---|---|
file |
The agent's state file |
seed |
The flags to write |
trustKey |
The two JSON levels around a directory name, for an agent that records trust per directory |
Some agents ask a first-run question that is not authentication, such as a login method that opens a browser. The microVM has no browser. A few non-secret flags in the agent's state file answer the question.
Brig sets trustKey for the directory that each run starts in, resolved to the git repository root as the guest sees it.
Limits:
- Brig writes
seedonly whenfiledoes not exist. An existing file belongs to the agent. - Brig never seeds anything that contains a credential.
reserved #
Marks a profile whose guest home a session name can otherwise map onto.
reserved: trueThe built-in claude-desktop profile sets it. That profile owns the guest home of the Desktop app, so Brig refuses brig run claude@desktop. Without the field, that command puts a Claude Code session there.
The trailing word of the name is reserved too. claude-desktop reserves both desktop and claude-desktop.
Warning A profile named
my-codexwithreserved: truereservescodexandmy-codex. Brig then refusesbrig agent importof any other profile namedcodexas a collision.
unpublished #
States that the profile ships without an image. brig run reports this and stops before it reaches the registry, where the pull fails with a 404 that looks like an outage.
unpublished: trueTo run the profile anyway, pass --image with an image that you built. brig agent ls marks the profile (no published image). cursor is the only built-in profile with the field.
policy #
Names of policies attached inline to this profile. Every run carries all of them, together with the policies attached separately by name. See Policies.
Limits:
- Not allowed on a
kind: shellorkind: guiprofile.
Worked example #
This profile runs a CLI called mytool from your image:
# The vendored CLI needs a bigger guest than the default.
name: mytool
desc: our internal agent
image: ghcr.io/example/mytool:arm64
guestHome: /home/mytool
binary: mytool
forward:
- MYTOOL_TOKEN
- GH_TOKEN
deny:
- MYTOOL_ADMIN_KEY # lets the agent reconfigure the account
statePaths:
- .config/mytool
headless: true
mem: 8192
cpus: 4brig agent import mytool.yaml
MYTOOL_TOKEN=$(pass show mytool/token) brig run mytoolforward: and statePaths: here are the deprecated spellings.
The image is outside ghcr.io/brig-sh, so Brig warns on every boot. See image.
Building the image #
Brig does not build the image. bring-your-own-image.md documents how to build one. The images of the built-in profiles are open source at brig-sh/community-images.
Guest image is the full contract: every binary that Brig execs inside the guest, and the account it expects. It also names a script that checks an image that you built.
Profile directory #
The eight built-in profiles are embedded in the binary, so brig run claude needs no install step.
Your profiles are one file each in $XDG_CONFIG_HOME/brig. The default is ~/.config/brig. The directory is flat: ~/.config/brig/claude-code.yaml. BRIG_PROFILE_DIR overrides the location.
The directory starts empty. Only three commands write to it:
| Command | Overwrites an existing file |
|---|---|
brig agent import |
|
brig agent export <agent> <name> |
Only with --force |
brig agent new <name> --from <agent> |
Only with --force |
The location follows the XDG Base Directory Specification, version 0.8. An empty XDG_CONFIG_HOME counts as unset. Brig ignores a relative one as invalid, because a relative value can give a different set of profiles in each project directory.
Listing profiles #
brig agent ls lists embedded and file-backed profiles together in one namespace. It marks the origin of each:
| Marker | Meaning |
|---|---|
| none | Embedded |
(file) |
A profile that exists only as a file |
(file, overrides built-in) |
A file that shadows an embedded profile |
A file can take the name of a built-in profile. Use this to pin your image for a profile that Brig knows.
Duplicate names #
The file name and the name: inside the file can differ, so two files can declare one name. Brig reports the collision and says which file won. See Confirmation for how brig agent rm treats them.
Settings from older versions
BRIG_TEMPLATE_DIRis the older name forBRIG_PROFILE_DIR. It works until v0.4.0.- Brig does not read
~/.config/brig/templatesand migrates nothing. These files name credential variables, and Brig cannot know which ones you still want. Brig reports files left there on every invocation. Move them withbrig agent import.
Built-in profiles #
| Profile | Alias | Kind | Image | Network |
|---|---|---|---|---|
claude-code |
claude |
agent | ghcr.io/brig-sh/claude-code-stock:root |
isolated |
claude-desktop |
desktop |
gui | ghcr.io/nofireai/urunc-claude-desktop:aarch64 |
shared |
codex |
agent | ghcr.io/brig-sh/codex-stock:root |
isolated |
|
cursor |
agent, example profile | ghcr.io/brig-sh/cursor:latest |
unset | |
gemini |
agent, example profile | ghcr.io/brig-sh/gemini-stock:root |
isolated |
|
grok |
agent, example profile | ghcr.io/brig-sh/grok-stock:root |
isolated |
|
opencode |
agent, example profile | ghcr.io/brig-sh/opencode-stock:root |
isolated |
|
ubuntu |
shell | docker.io/library/ubuntu:latest |
isolated |
Built-in profiles prints the full YAML of each one.
"example profile" is the desc: of the profile, and brig agent ls prints it. claude-code and codex carry no such marker.
Kinds. brig agent ls lists all eight, although brig agent --help calls the group "the agents you can run". claude-desktop opens a window, and ubuntu opens a shell.
Images. The table states what each profile declares, not whether the image pulls today. Brig expects you to be able to pull seven of the eight images. cursor declares unpublished: true.
Signatures. claude-code, codex, gemini, grok and opencode are Brig's multi-architecture builds under ghcr.io/brig-sh. claude-desktop and ubuntu are outside it, at ghcr.io/nofireai/ and Docker Hub, so Brig warns on every boot. See image. The claude-desktop image is also single-architecture, aarch64 only.
Network. The six isolated profiles use hvi. claude-desktop uses shared because its GUI requires vz. cursor leaves the posture unset: Linux and hvi isolate, and vz and qemu fall back to shared. These are defaults for new sandboxes. See network for existing sessions.
Export and import #
brig agent export claude-code # prints to stdout
brig agent export claude-code mine # ~/.config/brig/mine.yaml
brig agent export claude-code mine --force # ...overwriting what is there
brig agent export claude-code > ./mine.yaml # a copy somewhere of your own
brig agent export x | brig agent import -With a destination, export writes the file as Brig ships it, comments included. Import also stores your bytes as written, so your comments and your ordering stay.
An exported built-in profile carries its explicit network: value. Before you change its backend to vz or qemu, see network.
Export writes YAML. If a program reads profiles, use brig agent show --json. Import reads both YAML and JSON.
Destination names #
The destination is a name, never a path. For a copy in another location, export to stdout and redirect it.
Brig refuses these destinations, and each refusal names the collision:
| Destination | Why it is refused |
|---|---|
| A path, or a typo that looks like one | Brig writes only to the profile directory |
A built-in alias, such as claude |
A profile named claude wins the lookup over the alias. Every brig run claude then means the copy, and the built-in profile is reachable only as claude-code |
A name that a reserved profile owns |
The same reason |
For example, Brig refuses brig agent new claude --from claude-code.
Inspecting a run #
brig info <profile> reports what the guest receives. It reports names only, never a value. It annotates a variable from the secret store with (secret). An ambient or literal variable has no annotation.
No test pins the wording, so treat this as the shape of the output:
$ brig info mine
brig: workspace /Users/you/brig/mine (sandbox brig-mine)
brig: runtime hull (/opt/homebrew/bin/hull)
brig: image ghcr.io/brig-sh/claude-code-stock:root (pull missing)
brig: forwarding to guest:
brig: GH_TOKEN(secret)
brig: CI
brig: EDITOR
brig: guest git over HTTPS: off (BRIG_GIT_CONFIG=1 to enable)No path through this command reads a value, and a test fails the build if a value reaches the output.
brig info resolves secrets as a run does. If a secret is missing from the store, it fails as brig run does.
BRIG_ENV_ARGV #
BRIG_ENV_ARGV=1 puts an ordinary forwarded variable on the command line of the runtime. It is for a runtime build that does not take a bare --env KEY.
It has no effect on a value bound from the secret store, because the host durably logs the argv of every exec. On a runtime build that needs BRIG_ENV_ARGV=1, a stored credential does not arrive.
Removing a profile #
brig agent rm mytoolThe argument is a profile name, not a file name. rm resolves it through the merged set, so it takes aliases and finds the file under any file name.
Built-in profiles are compiled in and cannot be removed. To shadow one, import a profile of the same name.
Confirmation #
File that rm resolves to |
What rm does |
|---|---|
The file you named, such as mytool.yaml for brig agent rm mytool |
Removes it without asking |
| A file reached through an alias | Names the file and waits for a y |
| A second file that declares the same profile | Names the file and waits for a y |
| A file renamed by hand | Names the file and waits for a y |
If more than one file declares the name, rm removes all of them.
-y answers in advance, as in brig secret delete:
brig agent rm claude -y # the alias resolves to claude-code's fileIf there is no terminal to ask on, rm refuses and says so.
Existing sandboxes #
rm refuses while a sandbox of the profile exists, running or stopped. It names the brig rm <ref> command for each one.
Remove those sandboxes first. After the file is gone, brig rm <ref> cannot reach them. You must then use brig rm --all, or create a new profile of the same name.
rm does not refuse an override of a built-in profile, because the name still resolves to the built-in profile.
How rm finds the runtime
To find sandboxes, rm asks the runtime of the profile what it holds.
| Case | Runtime that rm asks |
|---|---|
| Brig has recorded a session of the profile | The profile's runtimeBin |
| No session recorded yet | The runtime on PATH |
So rm never executes the runtimeBin of a profile that you imported and never ran.
If Brig cannot ask, rm keeps the file and names the cause. Correct that setting first. The causes are:
BRIG_RUNTIMEis set to a runtime Brig does not know.runtimeBinpoints at nothing, on a profile Brig has run.
With no runtime installed, there are no sandboxes, and rm continues.