dot

NixOS dotfiles
git clone https://git.echoz.io/dot.git
Log | Files | Refs

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 }