Guides
herdr
The herdr profile runs Claude Code with a herdr server in each sandbox. One herdr client on your host adds each sandbox as a remote machine. You watch and drive many agents from one place, one agent per sandbox.
herdr reaches a remote machine only over SSH, and a sandbox has no open port. The herdr-stock image carries sshd and a wrapper, herdr-sshd. Your ssh runs the wrapper through brig exec as its ProxyCommand, and the wrapper runs sshd on the input and output of that exec. Nothing listens in the guest.
The image is ghcr.io/brig-sh/herdr-stock, built from images/herdr in community-images. The rest of the profile matches claude: the same guest home, credentials and volumes. Built-in profiles prints it in full.
Set it up once #
Add this block to ~/.ssh/config, above any Host * block that sets User:
Host herdr*+*
User root
ForwardAgent no
StrictHostKeyChecking yes
UserKnownHostsFile /dev/null
KnownHostsCommand /bin/sh -c 'r=$(echo "$1" | sed "s/+/@/") && k=$(brig -q exec "$r" -- cat /etc/ssh/ssh_host_ed25519_key.pub 2>/dev/null) && [ -n "$k" ] && echo "$1 $k"' sh %n
LogLevel ERROR
ProxyCommand sh -c 'exec brig -q exec "${1%%+*}@${1#*+}" -- /usr/local/sbin/herdr-sshd 2>/dev/null' sh %nA host name is <profile>+<sandbox>. herdr+api is the sandbox herdr@api, and herdr-review+api is herdr-review@api. Both commands split the name at the first +. A profile name cannot contain +, so the profile is always what is left of it.
The block matches every profile whose name starts with herdr. A profile that you make with brig agent new herdr-<name> --from herdr needs no block of its own.
| Setting | Why |
|---|---|
brig exec, not brig sh |
brig sh always asks for a terminal in the guest. A terminal in the middle of the SSH stream hangs it |
KnownHostsCommand |
The image ships no host keys, and the guest root does not survive brig stop. A sandbox has new keys after every boot. herdr checks a machine with strict host key checking, which a known_hosts file passes only until the next boot. The command reads the key through brig exec, and an empty key fails the check. It splits the host name with sed, because ssh expands ${...} itself in this setting |
| No key | The image accepts root with an empty password. Whoever can run brig exec on your host is already root in the guest, and the guest has no open port. A key guards nothing that brig exec does not |
ForwardAgent no |
A forwarded agent gives the guest a signer for every key you hold |
To keep the Claude Code login on the host, attach a policy with a route on the claude-code preset, as for claude. Credential broker explains routes. Save this policy as ~/.config/brig/policies/claude-routed.yaml:
apiVersion: brig.sh/v1alpha1
kind: Policy
metadata:
name: claude-routed
spec:
egress:
default: deny
routes:
- name: anthropic
preset: claude-code
credential:
secretRef: { name: claude-credentials }Then attach it:
brig policy attach claude-routed herdrAdd a sandbox #
brig run -d herdr@api ~/code/api
herdr machine add herdr+api --label apibrig run -d boots the sandbox and starts no agent. Claude Code runs only in the herdr panes, one for each claude you start there.
herdr machine add prints Remote server is ready. Open a pane on api in herdr and run cd /work/api && claude. A pane starts in /root, not in the project.
The environment of a pane #
sshd starts every session with an empty environment. Each SSH connection is a new brig exec, so it carries a new session token. herdr-sshd writes what the exec received to /run/herdr/env, and /etc/bash.bashrc reads that file in an SSH session.
- A pane keeps the values it started with.
- A pane that does not start
bashgets none of them. It has noCLAUDE_CONFIG_DIR, so aclaudestarted there writes its credential to the guest home, which is on host disk. brig shdoes not read the file. It keeps the token that Brig gave it.
/run/herdr/env holds the values of the latest connection, including the route's session token and an exported GH_TOKEN. The file is on tmpfs, mode 0600 and owned by root. It is outside the guest home, so it does not reach host disk. See Security.
Remove a sandbox #
Remove the herdr machine first, then restart the herdr client, then remove the sandbox:
herdr machine remove <id>
brig rm herdr@apiherdr machine remove takes the id that herdr machine list prints.
Warning A running herdr client keeps a machine that it has connected to until the client restarts, and it reconnects. The reconnect is a
brig exec, which starts the sandbox again afterbrig rm.