I have been ‘enjoying’ some awkward moments with default sandboxing of Codex CLI, Claude Code, and (lack of it in) OpenCode. I settled on a single sandboxing solution, and it is nono - Next-Generation Agent Security.
The problem
All coding agents use current shell environment to launch the tools they use. Those with sandboxing have rules which are set up to prevent ‘invalid’ use, but in practice they break often and are painful (or not possible) to configure properly per tool.
I have had issues with them for a while. Some notable pain points:
Problem: Go module and build caching
I use non-default Go cache locations:
GOCACHE='/Users/mstenber/scratch/go-build'
GOMODCACHE='/Users/mstenber/share/1/go/pkg/mod'
(GOMODCACHE is synced between machines - GOCACHE is not)
This leads to it not being used with all coding agents (due to sandboxing restrictions). In OpenCode container on the other hand I didn’t mount these extra paths so it was not used there either.
Problem: golangci-lint caching
Most coding agents seem to allow access to ~/Library/Caches by default, but with OpenCode container I had to specify ‘something else’ to deal with ~/Library/Caches/golangci-lint
Problem: rtk caching
RTK default cache path ~/Library/Application Support/rtk was not allowed by coding agents, nor my container setup. So yet more work.
The solution as of today
So I switched to using single sandboxing solution that is NOT the coding agent, and just disable sandboxing in the coding agents themselves.
I use general ‘nono run’ alias which allows for things I consider safe or necessary to allow in my dev environments in general:
alias nono-run-dev='nono run \
--allow `go env GOMODCACHE` \
--allow `go env GOCACHE` \
--allow "$HOME/Library/Application Support/rtk" \
--allow "$HOME/Library/Caches/golangci-lint" \
--read-file $HOME/.gitconfig \
--read-file $HOME/.gitconfig_global \
--read-file $HOME/.gitignore_global \
--allow-cwd'
And then have shell alias for each coding agent. Codex worked right out of their manual:
alias codex='nono-run-dev --profile codex -- codex --sandbox danger-full-access --ask-for-approval on-request'
And for OpenCode, I added ugly hack to deal with symlinked working directory paths ( opencode (profile) does not work with symlinked directories as cwd · Issue #662 · always-further/nono):
alias opencode='cd `realpath`; nono-run-dev --profile opencode -- opencode'
No Claude Code yet, as I don’t use it right now, but probably soon again..
The big bonus of this exercise is that I get to get rid of oc.sh , which is my own podman wrapper for OpenCode which wraps its execution in a container. Maintaining it was a hassle.
Is nono worth it?
Time will tell. However, I have barely scratched the surface with nono and I like it already.
Notable other features I potentially may find use for later on:
- mini-tmux ( detach and attach session )
- rollback ( ability to snapshot the allowed directories, and revert them back to pristine state ) ( this may be cool with e.g. CI use)