Skip to content

Instantly share code, notes, and snippets.

@selckin
Last active May 18, 2026 13:07
Show Gist options
  • Select an option

  • Save selckin/9d27160e2c5bab4959b7ed642832e399 to your computer and use it in GitHub Desktop.

Select an option

Save selckin/9d27160e2c5bab4959b7ed642832e399 to your computer and use it in GitHub Desktop.
claude/opencode bwrap quick & dirty
#!/usr/bin/env bash
# Require PWD to be a non-hidden subdir of $HOME
# since --bind "$PWD" "$PWD" below grants the sandbox rw access to PWD.
home="${HOME%/}"
pwd_clean="${PWD%/}"
case "$pwd_clean" in
"$home")
err="cannot run in \$HOME itself" ;;
"$home"/*)
rel="${pwd_clean#"$home"/}"
case "$rel" in
.*|*/.*) err="cannot run in a hidden directory" ;;
*) err="" ;;
esac ;;
*)
err="must be inside \$HOME" ;;
esac
if [[ -n "$err" ]]; then
echo "refusing to run: $err ($PWD)" >&2
exit 1
fi
if ! secret-migrate; then
echo "secret-migrate failed, exiting" >&2
exit 1
fi
export DISABLE_AUTOUPDATER=1
export DISABLE_INSTALLATION_CHECKS=1
uid="$(id -u)"
args=(
--unshare-all
--share-net
--die-with-parent
--ro-bind /opt/ /opt
--ro-bind-try /etc/claude-code/ /etc/claude-code/
--ro-bind /usr/ /usr
--symlink usr/lib /lib
--symlink usr/lib64 /lib64
--symlink usr/bin /bin
--symlink usr/sbin /sbin
--ro-bind /etc/ld.so.conf /etc/ld.so.conf
--ro-bind /etc/ld.so.conf.d /etc/ld.so.conf.d
--ro-bind /etc/ld.so.cache /etc/ld.so.cache
--proc /proc
--dev /dev
--perms 1777 --tmpfs /dev/shm
--perms 1777 --tmpfs /tmp
--perms 0755 --tmpfs /run
--perms 0700 --dir "/run/user/$uid"
# /etc/resolv.conf is typically a symlink into /run/systemd/resolve/.
# --ro-bind follows the symlink on the host side at bind time, so the
# content survives the /run tmpfs above — keep tmpfs /run before this.
--ro-bind /etc/resolv.conf /etc/resolv.conf
--ro-bind /etc/hosts /etc/hosts
--ro-bind /etc/nsswitch.conf /etc/nsswitch.conf
--ro-bind /etc/passwd /etc/passwd
--ro-bind /etc/group /etc/group
--ro-bind /etc/localtime /etc/localtime
--ro-bind /etc/ssl /etc/ssl
--ro-bind-try /etc/ca-certificates /etc/ca-certificates
--bind "$HOME/.sandbox-home/" "$HOME"
--setenv HOME "$HOME"
--chdir "$PWD"
--bind "$PWD" "$PWD"
--ro-bind-try "$HOME/.gentoo/" "$HOME/.gentoo/"
--bind-try "$HOME/.claude.json" "$HOME/.claude.json"
--bind-try "$HOME/.claude/" "$HOME/.claude/"
--ro-bind "$HOME/sources/claude-hooks" "$HOME/sources/claude-hooks"
--ro-bind "$HOME/sources/dotfiles/" "$HOME/sources/dotfiles/"
--setenv TMPDIR /tmp
--setenv XDG_RUNTIME_DIR "/run/user/$uid"
--setenv PATH "$HOME/sources/dotfiles/general/local/claude/bin/:$HOME/.local/bin/:/opt/bin:/usr/local/bin:/usr/bin:/bin"
)
# Env vars to forward from the parent environment into the sandbox.
# Patterns are bash globs matched against variable names. Forwarded values
# override any --setenv above (bwrap takes the last --setenv for a given var).
forward_env=(
'TERM'
'TERM_*'
'COLORTERM'
'LANG'
'LC_*'
'GIT_*'
'GHOSTTY_*'
)
while IFS= read -r -d '' entry; do
name="${entry%%=*}"
for pattern in "${forward_env[@]}"; do
if [[ "$name" == $pattern ]]; then
args+=(--setenv "$name" "${entry#*=}")
break
fi
done
done < <(env -0)
# TIOCSTI is disabled by default since kernel 6.2 (dev.tty.legacy_tiocsti=0),
# so --new-session is only needed on older kernels or when TIOCSTI is re-enabled.
# --new-session breaks SIGWINCH delivery (terminal resize).
if [[ "$(sysctl -n dev.tty.legacy_tiocsti 2>/dev/null)" != "0" ]]; then
args+=(--new-session)
fi
# tmux: shift-enter trouble enable extended keys
# set -s extended-keys on
# set -as terminal-features 'xterm-ghostty:RGB:extkeys'
# set -g focus-events on
args+=(claude "$@")
# args+=(tmux new-session -A -s claude claude "$@")
# args+=(env)
exec env -i bwrap "${args[@]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment