default.nix (6536B)
1 { user, ... }: 2 { 3 environment.persistence."/fix".users.${user} = { 4 directories = [ ".claude" ]; 5 files = [ ".claude.json" ]; 6 }; 7 8 home-manager.users.${user} = 9 { config, pkgs, ... }: 10 let 11 sandboxTools = pkgs.buildEnv { 12 name = "claude-sandbox-tools"; 13 paths = with pkgs; [ 14 bashInteractive 15 coreutils 16 curl 17 diffutils 18 fd 19 file 20 findutils 21 gawk 22 git 23 gnugrep 24 gnupatch 25 gnused 26 gnutar 27 gzip 28 jq 29 less 30 nix 31 procps 32 python3 33 ripgrep 34 unzip 35 which 36 yq-go 37 xz 38 ]; 39 }; 40 caBundle = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; 41 sandboxContext = pkgs.writeText "claude-sandbox-context.md" '' 42 ## Sandboxed environment 43 44 You are running inside a bubblewrap container. Only the current project 45 directory, `~/.claude`, `/tmp`, and the nix store exist; the rest of the 46 filesystem is absent. Network access works and nix builds work through 47 the nix daemon. 48 49 Claude Code's internal command sandbox is disabled here — the container 50 itself provides the isolation. Network access and nix work directly in 51 regular commands. 52 53 There are no SSH keys or GitHub credentials in this environment, and 54 `gh` is not installed. `git push`, `git fetch` and `gh` cannot 55 authenticate — do not attempt them and do not spend time diagnosing 56 this. Instead, commit your work to a new branch and finish by giving 57 the user a copy-pasteable command to run outside the sandbox to push 58 and open a PR. Keep every line under typical terminal width (~80 59 columns), using backslash continuations — wrapped lines don't copy 60 correctly: 61 62 git push -u origin <branch> && \ 63 gh pr create --head <branch> --title "..." --fill 64 ''; 65 sandboxSettings = pkgs.writeText "claude-sandbox-settings.json" ( 66 builtins.toJSON { sandbox.enabled = false; } 67 ); 68 claude-sandboxed = pkgs.writeShellScriptBin "claude-sandboxed" '' 69 tmp=$(mktemp -d -t claude-sandbox.XXXXXXXX) 70 trap 'rm -rf "$tmp"' EXIT 71 ${pkgs.bubblewrap}/bin/bwrap \ 72 --unshare-all \ 73 --share-net \ 74 --die-with-parent \ 75 --proc /proc \ 76 --dev /dev \ 77 --bind "$tmp" /tmp \ 78 --tmpfs "$HOME" \ 79 --ro-bind /nix/store /nix/store \ 80 --ro-bind /nix/var/nix/db /nix/var/nix/db \ 81 --ro-bind /nix/var/nix/profiles /nix/var/nix/profiles \ 82 --bind /nix/var/nix/daemon-socket /nix/var/nix/daemon-socket \ 83 --ro-bind-try /etc/nix /etc/nix \ 84 --ro-bind-try /etc/static /etc/static \ 85 --ro-bind-try /etc/resolv.conf /etc/resolv.conf \ 86 --ro-bind-try /etc/hosts /etc/hosts \ 87 --ro-bind-try /etc/nsswitch.conf /etc/nsswitch.conf \ 88 --ro-bind-try /etc/passwd /etc/passwd \ 89 --ro-bind-try /etc/group /etc/group \ 90 --ro-bind-try /etc/machine-id /etc/machine-id \ 91 --ro-bind ${sandboxContext} /etc/claude-code/CLAUDE.md \ 92 --ro-bind ${pkgs.bashInteractive}/bin/bash /bin/sh \ 93 --ro-bind ${pkgs.coreutils}/bin/env /usr/bin/env \ 94 --bind "$HOME/.claude" "$HOME/.claude" \ 95 --ro-bind-try "$HOME/.claude/settings.json" "$HOME/.claude/settings.json" \ 96 --file 11 "$HOME/.claude.json" \ 97 --ro-bind-try "$HOME/.config/git" "$HOME/.config/git" \ 98 --bind "$PWD" "$PWD" \ 99 --chdir "$PWD" \ 100 --clearenv \ 101 --setenv HOME "$HOME" \ 102 --setenv USER "$USER" \ 103 --setenv LOGNAME "$USER" \ 104 --setenv SHELL ${pkgs.bashInteractive}/bin/bash \ 105 --setenv TERM "''${TERM:-xterm-256color}" \ 106 --setenv COLORTERM "''${COLORTERM:-truecolor}" \ 107 --setenv LANG "''${LANG:-C.UTF-8}" \ 108 --setenv PATH ${sandboxTools}/bin \ 109 --setenv TMPDIR /tmp \ 110 --setenv NIX_REMOTE daemon \ 111 --setenv SSL_CERT_FILE ${caBundle} \ 112 --setenv NIX_SSL_CERT_FILE ${caBundle} \ 113 --setenv CURL_CA_BUNDLE ${caBundle} \ 114 ${config.programs.claude-code.finalPackage}/bin/claude \ 115 --permission-mode auto \ 116 --settings ${sandboxSettings} \ 117 "$@" \ 118 11< "$HOME/.claude.json" 119 ''; 120 in 121 { 122 nixpkgs.config.allowUnfree = true; 123 124 home.packages = [ claude-sandboxed ]; 125 126 programs.claude-code = { 127 enable = true; 128 context = '' 129 ## Git workflow 130 131 Always create a feature branch for any code change — never commit directly to the default branch. 132 133 When merging a PR: squash merge, then delete both the remote and local branch. 134 135 Don't add a PR body unless the change genuinely warrants explanation beyond the title. 136 137 ## Interacting with the system 138 139 Network access and nix usage requires running commands unsandboxed. 140 141 Avoid making assumptions about the unsandboxed environment. 142 143 Use `nix run` or `nix shell` to run programs not typically available on every system. 144 145 ## Shell redirection 146 147 Be mindful of where you redirect stderr to stdout with 2>&1. If you're parsing standard 148 output of a command with tools like jq or yq this will likely break parsing. 149 ''; 150 settings = { 151 permissions = { 152 allow = [ 153 "Read(//nix/store/*)" 154 ]; 155 }; 156 sandbox = { 157 enabled = true; 158 excludedCommands = [ 159 "nix *" 160 "gh *" 161 "git push" 162 "git push *" 163 "git pull" 164 "git pull *" 165 "git commit *" 166 "git fetch" 167 "git fetch *" 168 ]; 169 filesystem = { 170 denyRead = [ "/" ]; 171 allowRead = [ 172 "/nix" 173 "/run/current-system" 174 ]; 175 }; 176 }; 177 effortLevel = "medium"; 178 model = "fable"; 179 }; 180 mcpServers.agentgateway = { 181 type = "http"; 182 url = "https://mcp.stafftastic.com/mcp/http"; 183 }; 184 }; 185 186 home.file."${config.programs.claude-code.configDir}/settings.json" = { 187 mutable = true; 188 force = true; 189 }; 190 }; 191 }