{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "_comment": "Permissive defaults: agents can iterate without prompting on routine dev actions. Anything that mutates shared/remote state still requires explicit approval. Secrets are guarded by target, not by program: the env-file-guard hook (.claude/hooks/env-file-guard.sh, a port of Course-Studio/baseplate's hook whose header states its threat model) denies any Bash command that names an env file or a credential store, opens one from inline or heredoc code (node -e, bash -c, python3 - <<EOF), sweeps the repo root without excluding env files and Wrangler's .dev.vars, or sweeps any other directory that holds an env file or a credential store, whatever program runs it, matching names in any case; and it denies the CLIs that print a credential (security find-generic-password and its kin, op, gh auth token, git credential fill and the credential helpers' get, printenv, env) past a launcher too, where the Bash denies below never look. That is why the node, npx, pnpm exec and pnpm dlx allows can stay. It needs bash, jq and python3, and fails closed: a crash, a missing tool or a timeout denies the call. Its cases live in .claude/hooks/env-file-guard.test.sh; run sh .claude/hooks/env-file-guard.test.sh from the app root. The Read denies cover .env* and .dev.vars at any depth and the credential stores; the hook reads the Read(~/...) rules below and keeps its own copy of them, so a new store is one rule in each. It guards against an honest mistake, not a determined reader (Course-Studio/baseplate ADR BP-102): deliberate evasion such as brace expansion or a globbed store path is left to the OS sandbox; a path built at run time, a script that opens the file itself, or pnpm exec of a credential CLI it does not list is invisible to it, and it cannot tell a secret environment variable from NODE_ENV (node -p process.env.X, echo $X).",
  "permissions": {
    "allow": [
      "Bash(pnpm install*)",
      "Bash(pnpm run *)",
      "Bash(pnpm exec *)",
      "Bash(pnpm dev*)",
      "Bash(pnpm build*)",
      "Bash(pnpm test*)",
      "Bash(pnpm lint*)",
      "Bash(pnpm format*)",
      "Bash(pnpm style*)",
      "Bash(pnpm check*)",
      "Bash(pnpm typecheck*)",
      "Bash(pnpm db:*)",
      "Bash(pnpm theme:build*)",
      "Bash(pnpm dlx *)",
      "Bash(pnpm --filter *)",
      "Bash(pnpm -w *)",
      "Bash(node *)",
      "Bash(npx *)",
      "Bash(git status*)",
      "Bash(git diff*)",
      "Bash(git log*)",
      "Bash(git show*)",
      "Bash(git branch*)",
      "Bash(git ls-files*)",
      "Bash(git ls-tree*)",
      "Bash(git stash*)",
      "Bash(git add*)",
      "Bash(git checkout *)",
      "Bash(git switch *)",
      "Bash(git restore *)",
      "Bash(git rev-parse*)",
      "Bash(git remote -v)",
      "Bash(git fetch*)",
      "Bash(git pull --ff-only*)",
      "Bash(mkdir *)",
      "Bash(touch *)",
      "Bash(ls *)",
      "Bash(find *)",
      "Bash(grep *)",
      "Bash(rg *)",
      "Bash(cat *)",
      "Bash(head *)",
      "Bash(tail *)",
      "Bash(wc *)",
      "Bash(sort *)",
      "Bash(uniq *)",
      "Bash(jq *)",
      "Bash(curl http://localhost*)",
      "Bash(curl http://127.0.0.1*)",
      "Bash(pnpm exec skillex*)",
      "Bash(pnpm exec playwright *)",
      "Bash(pnpm exec vitest*)",
      "Bash(pnpm exec drizzle-kit*)",
      "Bash(pnpm exec next *)",
      "Bash(pnpm exec tsc*)",
      "Bash(pnpm exec oxlint*)",
      "Bash(pnpm exec oxfmt*)",
      "Bash(pnpm exec stylelint*)",
      "Read",
      "Edit",
      "Write",
      "Glob",
      "Grep",
      "WebFetch"
    ],
    "ask": [
      "Bash(git commit*)",
      "Bash(git push*)",
      "Bash(git merge*)",
      "Bash(git rebase*)",
      "Bash(git reset*)",
      "Bash(gh issue*)",
      "Bash(gh pr*)",
      "Bash(gh release*)",
      "Bash(gh workflow*)",
      "Bash(pnpm publish*)",
      "Bash(pnpm nx release*)",
      "Bash(npm publish*)"
    ],
    "deny": [
      "Bash(git push --force*)",
      "Bash(git push -f *)",
      "Bash(git push * --force*)",
      "Bash(rm -rf /*)",
      "Bash(rm -rf ~)",
      "Bash(rm -rf $HOME*)",
      "Bash(cat .env*)",
      "Bash(cat *.env)",
      "Bash(cat *.env.local)",
      "Bash(cat *.env.production)",
      "Bash(printenv*)",
      "Bash(env)",
      "Bash(op)",
      "Bash(op *)",
      "Bash(security find-generic-password*)",
      "Bash(security find-internet-password*)",
      "Bash(security dump-keychain*)",
      "Bash(security export*)",
      "Bash(gh auth token*)",
      "Read(./.env*)",
      "Read(./**/.env*)",
      "Read(./.dev.vars)",
      "Read(./**/.dev.vars)",
      "Read(~/**/.env)",
      "Read(~/**/.env.local)",
      "Read(~/**/.env.production)",
      "Read(~/.ssh/**)",
      "Read(~/**/id_rsa)",
      "Read(~/**/id_ed25519)",
      "Read(~/.aws/**)",
      "Read(~/.gnupg/**)",
      "Read(~/Library/Keychains/**)",
      "Read(~/.claude/.credentials.json)",
      "Read(~/.config/gh/**)",
      "Read(~/.npmrc)",
      "Read(~/.config/op/**)",
      "Read(~/Library/Application Support/com.vercel.cli/**)",
      "Read(~/.config/neonctl/**)",
      "Read(~/.sentryclirc)",
      "Read(~/Library/Preferences/.wrangler/**)",
      "Read(~/.docker/config.json)",
      "Read(~/.git-credentials)",
      "Read(~/.config/git/credentials)",
      "Read(~/.netrc)",
      "Read(~/.pgpass)",
      "Read(~/.kube/config)",
      "Read(~/.config/gcloud/**)",
      "Read(~/.pypirc)",
      "Read(~/.cargo/credentials.toml)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/env-file-guard.sh\"",
            "timeout": 15
          }
        ]
      }
    ]
  }
}
