Skip to content
OPQAI.
Sourced intermediate / 💻 Coding

Customize Claude Code's Behavior with Undocumented Features

Job to be done: Customize Claude Code's behavior using undocumented features, e.g., adding --dry-run to git push

🇳🇬 Ways to use this in Nigeria

Ideas to get you started, adapt to your situation.

  • 9-5 employee

    Prevent accidental code pushes by adding --dry-run to git push commands executed by Claude Code.

  • Student

    Automate adding --dry-run to git push commands for class projects using Claude Code hooks.

What you’ll get

A way to bend Claude Code (the paid AI coding assistant) to your will using “hooks”, small scripts it runs at set moments. The worked example makes Claude Code add --dry-run to every git push it tries, so a push is only rehearsed, never actually sent, a safety net against accidental pushes. Once you see how one hook works, you can rewrite or gate other commands too. It is intermediate: you write a short shell script and edit a settings file.

Note: these features come from reading Claude Code’s source code, so they are “undocumented” and could change in a future version.

Tools you need

  • Claude Code (paid): the AI coding assistant whose behavior you are customizing. Needs a paid plan or credits.
  • jq (free): a small command-line tool for reading and writing JSON (a structured data format). The hook uses it to read and edit the command.
  • git (free): used in the example, where the hook rewrites git push.

Steps

  1. Know where the config lives: Claude Code keeps personal settings in ~/.claude/ (on Windows that path is C:\Users\YourName\.claude\), and per-project settings in a .claude/ folder inside a project. You will work in the personal one. (The shell commands below are written for macOS or Linux; on Windows, run them in Git Bash or WSL, where ~ means your home folder.)

  2. Make a folder for hooks:

    # macOS or Linux (Windows: use Git Bash or WSL)
    mkdir -p ~/.claude/hooks/

    You should have a new hooks folder inside ~/.claude/. (-p just means “create parent folders if missing”.)

  3. Write the hook script: create a file ~/.claude/hooks/dry-run-pushes.sh with this content. It reads the command Claude Code is about to run, and if it is a git push, hands back the same command with --dry-run added:

    #!/bin/bash
    INPUT=$(jq -r '.tool_input.command' /dev/stdin)
    
    if echo "$INPUT" | grep -q 'git push'; then
        jq -n --arg cmd "$INPUT" '{ updatedInput: { command: ($cmd + " --dry-run") } }'
    else
        jq -n --arg cmd "$INPUT" '{ updatedInput: { command: $cmd } }'
    fi
  4. Make the script runnable: give it permission to execute:

    # macOS or Linux (Windows: use Git Bash or WSL)
    chmod +x ~/.claude/hooks/dry-run-pushes.sh

    No output means it worked.

  5. Tell Claude Code when to run it: open (or create) ~/.claude/settings.json and add this. A PreToolUse hook runs before a tool is used; the matcher “Bash” means “before any Bash command”:

    {
      "hooks": {
        "PreToolUse": [
          {
            "matcher": "Bash",
            "hooks": [
              {
                "type": "command",
                "command": "~/.claude/hooks/dry-run-pushes.sh"
              }
            ]
          }
        ]
      }
    }

    If settings.json already has content, merge this hooks section into it rather than overwriting.

  6. Test it: in Claude Code, ask it to run a push (for example git push origin main). It should run with --dry-run added, so nothing is actually pushed. That confirms the hook works.

Original source

Based on ankitg12’s Hacker News post and the article “I Read the Claude Code Source Code” on buildingbetter.tech, documenting configuration options for Claude Code found by reading its source.

Notes & variations

  • Free-tier alternatives: this hook mechanism is specific to Claude Code. For plain command tweaks outside an AI assistant, shell aliases or functions in your .bashrc or .zshrc do something similar, but without the AI integration.
  • Common pitfall: forgetting chmod +x. If Claude Code reports “permission denied” on the hook, the script is not executable.
  • Tip for better results: explore other hook types from the source, like SessionStart (inject standing context) and PostToolUse (act on a tool’s output), and return fields like additionalContext or permissionDecision to auto-approve or block actions. Since these are undocumented, expect them to shift between versions.

Keep going

More Coding workflows