This repository includes the configuration files I use for terminal applications like VIM, tmux and others.
In order to use the VIM plug-in vim-devicons and avoid icon/font display issues while decorating the tmux status bar, one needs to install Nerd Fonts. For macOS users, installation via Homebrew is simple:
brew tap homebrew/cask-fonts
brew install font-hack-nerd-font
Linux users should consult the Nerd Fonts repository for installation details.
I use a fairly simple iTerm2 profile that re-defines some useful key mappings from Mac's own Terminal.app. It also makes Hack Regular Nerd Font (see above) the default terminal font.
I use the lsd utility instead of the default one. For macOS users, installation via Homebrew is as follows:
brew install lsd
I use a virtual environment, pyenv, to manage Python versions and packages and avoid cluttering system Python installations. To set up the virtual environment, use
python3 -m venv ~/pyenv
Do not forget to upgrade the virtual environment after upgrading Python:
python3 -m venv --upgrade ~/pyenv
I use vim-plug for managing VIM plug-ins. The .vimrc file should take care of bootstrapping vim-plug if it isn't there already. However, if you run into issues you can manually set it up via:
curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
If vim-plug is installed manually, you will also need to issue the VIM command :PlugUpdate manually to fetch and install the actual plug-ins.
Be aware that macOS does not ship with a vim-gutentags compatible ctags binary. To use vim-gutentags on macOS, one needs to install Ctags through Homebrew.
Out of the box, ALE tries to auto-detect and enable as many tools as it can, so one does not need to do extra configuration. For Python, I recommend pyls and my .vimrc chooses it as the sole Python tool if the executable pyls is in ${PATH}. As of this writing, I couldn't get clangd to work in ALE, so my .vimrc defaults to clang or gcc for linting. Syntax checking does not yet work in C/C++.
I generally use FZF for searching. I also use ag, which the FZF plug-in also supports. Fellow macOS users can use Homebrew to install ag via:
brew install the_silver_searcher
I use a custom script (scripts/tmux-select-pane) to facilitate seamless movements between TMux and VIM panes.
I use scripts/agent-sandbox to limit Claude and Codex with read/write access to the current directory and read-only access to the necessary system directories (more below). The claude and codex aliases run their respective agent through this sandbox. See this repository for more details. Mind the following:
- This is macOS-specific, and Linux will require a different approach.
- We do not rely on the agent's own sandbox: Claude disables its built-in sandbox, while Codex runs with
--sandbox danger-full-access. The outer macOS sandbox remains the enforcing boundary because macOS does not support nestingsandbox-execprofiles.
This setup consists of three layers:
- The primary security boundary is an OS-level macOS sandbox (
sandbox-exec) that restricts file reads to the current working directory and system paths, limits writes to the project directory,/tmp, select caches, and the agent's state directory (~/.claudeor~/.codex), while permitting full network access. - A pre-execution hook (
path_check.py) provides friendly error messages when commands reference paths outside sandbox boundaries, catching many mistakes before they hit the OS sandbox. This hook also rejects shell access to workspace.env/.env.*,*.pem,*.key,id_rsa*,.ssh,.aws, and.gnupgpaths. The outeragent-sandboxprofile also denies reads for these patterns. - The
agent-sandboxscript gives read-only Keychain access so Claude retrieves its API key, Codex validates the local certificate issuer, and GitHub CLI retrieves its OAuth token. - Run
scripts/test-agent-sandbox.sh --agent claudeorscripts/test-agent-sandbox.sh --agent codexfrom the host (not an existingsandbox-execsession) to verify the effective profile. - Claude's
settings.jsonand Codex's.codex/rules/default.rulescontrol command prompting rather than filesystem security. They auto-approve common development commands, require confirmation for remote-affecting operations, and block dangerous command patterns such assudo, force pushes, and repository deletion. Claude also blocks sensitive-file reads; Codex applies those path protections through its hook and the sandbox.
The aim is to prioritize development productivity by eliminating prompts for safe local operations while maintaining human oversight for irreversible or remote-affecting actions, with the OS sandbox as the ultimate safety net.
- The
scripts/generate-codex-rules.pyscript generates.codex/rules/default.rulesfrom Claude's Bash permissions. When changing.claude/settings.json, regenerate the rules and review the two files together. Generated rules preserveallow,prompt, andforbiddendecisions through Codex's native execution-policy engine. Note that Codex's execution-policy rules cannot represent Claude'sReadandEditpermissions, so Codex relies onpath_check.pyand theagent-sandboxscript to enforce sensitive-file checks. - The generator prints every non-Bash Claude permission it omits, with the count in each category heading, so review its output whenever
.claude/settings.jsonchanges. - Codex does not provide an executable custom status-line hook.
INSTRUCTIONS.md.j2 is the single source of truth for .claude/CLAUDE.md and .codex/AGENTS.md. After editing it, run scripts/render-agent-instructions.py to regenerate them and commit the outputs.