By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
World of SoftwareWorld of SoftwareWorld of Software
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Search
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
Reading: I Automated 80% of My Code Review With 5 Shell Scripts | HackerNoon
Share
Sign In
Notification Show More
Font ResizerAa
World of SoftwareWorld of Software
Font ResizerAa
  • Software
  • Mobile
  • Computing
  • Gadget
  • Gaming
  • Videos
Search
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Have an existing account? Sign In
Follow US
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
World of Software > Computing > I Automated 80% of My Code Review With 5 Shell Scripts | HackerNoon
Computing

I Automated 80% of My Code Review With 5 Shell Scripts | HackerNoon

News Room
Last updated: 2026/03/09 at 10:31 PM
News Room Published 9 March 2026
Share
I Automated 80% of My Code Review With 5 Shell Scripts | HackerNoon
SHARE

Copy-paste hook configurations from production for pre-commit validation, PII scanning, deploy safeguards, and session logging

Six months ago I kept a sticky note on my monitor. It said: “Did you lint? Did you check the branch? Did you look at what it deleted?”

Every Claude Code session, the same manual checks. Every time Claude edited a file, I would switch to another terminal and run the formatter. Every time it ran a Bash command, I would squint at the output wondering if anything touched production. Every time it tried to commit, I would check I was on the right branch first.

The sticky note was not the problem. The problem was that I was doing a computer’s job. Repetitive pattern matching on every action, hundreds of times a day. That is what scripts are for.

Then I found out Claude Code fires events. Every single action. Tool calls, file edits, Bash commands, session starts, session ends. All of them. And you can intercept any of them with a shell script.

The sticky note is gone. Here is what replaced it.

The Event System Nobody Talks About

Claude Code is not just a chat interface that writes code. Under the surface, it runs a lifecycle loop. User sends a prompt. Claude decides which tool to use. The tool executes. Claude reads the result. Repeat until done.

At every transition in that loop, Claude Code fires an event. And you can attach a handler to any of them.

The two events that matter most:

  • PreToolUse fires before a tool call executes. Your handler can inspect the call and return a JSON verdict: allow it, deny it, or stay silent and let the normal permission flow handle it.
  • PostToolUse fires after a tool call succeeds. Your handler gets the full output. Do whatever you want with it. Lint the file. Log the command. Send a webhook. The tool already ran, so this is reactive, not preventive.

Handlers are registered in .claude/settings.json. They can be shell commands, HTTP endpoints, or LLM prompts. I use shell commands because they are fast, debuggable, and do not require infrastructure.

The entire interface is: Claude Code pipes JSON to your script’s stdin. Your script optionally writes JSON to stdout. That is it. If your script exits without output, Claude Code proceeds normally.

Script 1: The Disaster Prevention Script

I wrote this one after Claude tried to rm -rf a build directory that happened to have a symlink into my home folder. Nothing bad happened because I caught it in the permission prompt. But I should not have to catch it. A machine should catch it.

#!/bin/bash
# .claude/hooks/guard.sh
# Blocks destructive commands before they execute

CMD=$(jq -r '.tool_input.command // empty')
[ -z "$CMD" ] && exit 0

# Patterns I never want to run unreviewed
BLOCKED_PATTERNS=(
  'rm -rf'
  'rm -r /'
  'DROP TABLE'
  'DROP DATABASE'
  'truncate '
  '> /dev/sd'
  'mkfs.'
  'dd if="
)

for pattern in "${BLOCKED_PATTERNS[@]}"; do
  if echo "$CMD" | grep -qi "$pattern"; then
    jq -n --arg reason "Blocked: command matches dangerous pattern "$pattern'" '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "deny",
        permissionDecisionReason: $reason
      }
    }'
    exit 0
  fi
done

Eight patterns. Could be eighty. The point is not to enumerate every dangerous command. The point is to catch the ones you have personally almost run by accident. My list reflects my scars. Yours will reflect yours.

The registration in .claude/settings.json:

"PreToolUse": [
  {
    "matcher": "Bash",
    "hooks": [{ "type": "command", "command": ".claude/hooks/guard.sh" }]
  }
]

The matcher is a regex on the tool name. "Bash" means this hook only fires for Bash commands, not file edits or reads. Keeps it fast.

Script 2: The Formatter That Never Forgets

Before this hook, my workflow was: Claude edits file, I notice the formatting is wrong, I ask Claude to fix it, Claude runs the formatter, I review the formatted version. Four steps for something that should be zero steps.

#!/bin/bash
# .claude/hooks/fmt.sh
# Formats files immediately after Claude edits them

TOOL=$(jq -r '.tool_name // empty')
[ "$TOOL" != "Edit" ] && [ "$TOOL" != "Write" ] && exit 0

FP=$(jq -r '.tool_input.file_path // .tool_input.path // empty')
[ -z "$FP" ] || [ ! -f "$FP" ] && exit 0

case "${FP##*.}" in
  js|ts|jsx|tsx|mjs)
    if [ -f node_modules/.bin/prettier ]; then
      node_modules/.bin/prettier --write "$FP" 2>/dev/null
    elif command -v npx &>/dev/null; then
      npx prettier --write "$FP" 2>/dev/null
    fi
    ;;
  rs)
    rustfmt "$FP" 2>/dev/null
    ;;
  py)
    command -v ruff &>/dev/null && ruff format "$FP" 2>/dev/null
    command -v ruff &>/dev/null && ruff check --fix "$FP" 2>/dev/null
    ;;
  go)
    gofmt -w "$FP" 2>/dev/null
    ;;
  css|scss)
    command -v stylelint &>/dev/null && stylelint --fix "$FP" 2>/dev/null
    ;;
esac

exit 0

This version is more thorough than the minimal example you find in documentation. It checks whether the formatter actually exists before calling it. It handles Prettier via local install or npx. It runs both ruff format and ruff check --fix for Python because formatting and linting are different things.

Register it as PostToolUse with an "Edit|Write" matcher. It fires after every file modification. The file is formatted before Claude reads it back or moves to the next edit.

The compound effect is significant. Over a week I measured it. Without the hook, I was spending an average of 4 minutes per session asking Claude to fix formatting issues. With the hook, zero. Across 30 sessions a week, that is two hours reclaimed.

Script 3: The Secret Detector

This one exists because of a near-miss. Claude was debugging an API integration, read a config file containing a test API key, and included the key in its response. The key was for a staging environment and was rotated the next day. But the principle bothered me. Tool outputs flow through the conversation, get cached, potentially get logged. I do not want credentials in that flow.

#!/bin/bash
# .claude/hooks/secrets.sh
# Scans tool output for credential-shaped strings

OUTPUT=$(jq -r '.tool_output // empty')
[ -z "$OUTPUT" ] && exit 0

ALERTS=""

# AWS keys (AKIA...)
echo "$OUTPUT" | grep -qE 'AKIA[0-9A-Z]{16}' && ALERTS="$ALERTS aws_key"

# Generic API key patterns (long hex/base64 after common key names)
echo "$OUTPUT" | grep -qiE '(api_key|apikey|secret_key|access_token|auth_token)["x27: =]+[A-Za-z0-9+/]{20,}' && ALERTS="$ALERTS api_credential"

# Private key headers
echo "$OUTPUT" | grep -q 'BEGIN.*PRIVATE KEY' && ALERTS="$ALERTS private_key"

# JWT tokens
echo "$OUTPUT" | grep -qE 'eyJ[A-Za-z0-9_-]{10,}.eyJ[A-Za-z0-9_-]{10,}.' && ALERTS="$ALERTS jwt_token"

# Connection strings with passwords
echo "$OUTPUT" | grep -qiE '(postgresql|mysql|mongodb|redis)://[^:]+:[^@]+@' && ALERTS="$ALERTS connection_string"

if [ -n "$ALERTS" ]; then
  TS=$(date '+%H:%M:%S')
  TOOL=$(jq -r '.tool_name // unknown')
  echo "[$TS] SECRET_ALERT in $TOOL:$ALERTS" >> .claude/secret-alerts.log
  echo "WARNING: potential credential in $TOOL output ($ALERTS)" >&2
fi

exit 0

This is not a replacement for proper secrets management. It is a tripwire. It catches the obvious patterns: AWS access keys, things that look like API credentials, private key blocks, JWTs, database connection strings with embedded passwords.

When it fires, it logs to .claude/secret-alerts.log and prints a warning to stderr. It does not block anything. Blocking on a false positive would interrupt your flow. Logging on a true positive gives you something to investigate at the end of the session.

I review secret-alerts.log once a day. Most entries are false positives (test fixtures, documentation examples). About once a week, one is real enough to warrant rotating a credential or updating a .gitignore.

Script 4: The Branch Cop

Short, sharp, and born from a genuine mistake. I was on main, asked Claude to push a quick fix, and it ran git push origin main before I registered what was happening. The push went through. CI was green. No damage done. But the commit was not supposed to land on main without a PR.

#!/bin/bash
# .claude/hooks/no-push-main.sh
# Prevents git push to main/master/production branches

CMD=$(jq -r '.tool_input.command // empty')
echo "$CMD" | grep -q 'git push' || exit 0

BRANCH=$(git branch --show-current 2>/dev/null)
PROTECTED="main master production release"

for b in $PROTECTED; do
  if [ "$BRANCH" = "$b" ]; then
    jq -n --arg branch "$BRANCH" '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "deny",
        permissionDecisionReason: ("Push to " + $branch + " blocked. Create a feature branch first.")
      }
    }'
    exit 0
  fi
done

# Also block force push to any branch
if echo "$CMD" | grep -qE 'push.*(-f|--force)'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Force push blocked. Use --force-with-lease if you must."
    }
  }'
fi

Two guards in one script. No pushing to protected branches. No force pushing to any branch. The second rule is optional but I keep it because force pushes are the kind of thing that should require you to type the command yourself, with full awareness of what you are doing.

Claude handles the denial gracefully. It sees the reason, suggests creating a feature branch, and proceeds on the right track. The hook does not interrupt the session. It redirects it.

Script 5: The Black Box Recorder

Every tool call. Every input. Every output. Timestamped and appended to a log file. This is the hook I most frequently recommend to teams because it answers the question you always ask after something goes wrong: “What exactly did Claude do?”

#!/bin/bash
# .claude/hooks/record.sh
# Logs every tool call to a structured audit file

TS=$(date '+%Y-%m-%d %H:%M:%S')
TOOL=$(jq -r '.tool_name // "unknown"')
SESSION=$(jq -r '.session_id // "unknown"')

# Compact input (one line, no whitespace bloat)
INPUT=$(jq -c '.tool_input // {}')

# Truncate output to prevent log bloat (first 500 chars)
OUTPUT=$(jq -r '.tool_output // empty' | head -c 500)

# Tab-separated for easy parsing with awk/cut
printf '%st%st%st%st%sn' 
  "$TS" "$SESSION" "$TOOL" "$INPUT" "$OUTPUT" 
  >> .claude/session-log.tsv

exit 0

Tab-separated, not JSON. Deliberate choice. TSV files are greppable, sortable, and cuttable with standard Unix tools. Need to see every Bash command from today?

grep "$(date +%Y-%m-%d)" .claude/session-log.tsv | grep "Bash" | cut -f4

Need to count how many file edits Claude made this week?

grep -c "Edit|Write" .claude/session-log.tsv

The output field is truncated to 500 characters to prevent multi-megabyte log files when Claude reads large files. If you need full output, switch to per-session log files: replace the filename with .claude/logs/session-${SESSION}.tsv.

For teams that need centralised logging, replace the file append with an HTTP hook pointing at your logging infrastructure. The JSON payload Claude Code sends contains everything this script captures, plus additional context like the working directory and tool configuration.

The Combined Settings File

All five scripts, wired together:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": ".claude/hooks/guard.sh" },
          { "type": "command", "command": ".claude/hooks/no-push-main.sh" }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": ".claude/hooks/fmt.sh" }
        ]
      },
      {
        "matcher": "",
        "hooks": [
          { "type": "command", "command": ".claude/hooks/secrets.sh" },
          { "type": "command", "command": ".claude/hooks/record.sh" }
        ]
      }
    ]
  }
}

Copy the JSON into .claude/settings.json. Create the five scripts in .claude/hooks/. Run chmod +x .claude/hooks/*.sh. Done.

PreToolUse hooks run in order. Both guard.sh and no-push-main.sh evaluate every Bash command. If either returns a deny, the command is blocked. PostToolUse hooks also run in order but they cannot block anything; the tool already executed.

The empty matcher on the second PostToolUse entry means secrets.sh and record.sh fire on every tool call, not just file edits. That is intentional. I want to scan Bash output for credentials and I want to log everything, regardless of tool type.

What I Learned Running These for Six Months

The formatter hook pays for itself on day one. Everything else is insurance. The formatter is an immediate, measurable time saving. Install that one first even if you ignore the rest.

False positives in the secret scanner are fine. I would rather review ten false alarms a week than miss one real credential. The log file review takes 30 seconds. Rotating a leaked credential takes an hour.

The guard script needs to evolve. Every few weeks I add a pattern after a near-miss. It started with rm -rf. Now it has eight patterns. In six months it will have twenty. That is the point. It accumulates your team’s institutional knowledge about what should never run unreviewed.

The audit log is most valuable after incidents. You rarely read it proactively. But when something goes wrong, having a complete record of every action Claude took turns a two-hour investigation into a five-minute grep.

Keep hooks fast. Every PreToolUse hook adds latency to every tool call. My guard and branch-cop scripts run in under 5ms each. The formatter is the slowest at 50-200ms depending on file size, but it runs PostToolUse so it does not block the pipeline. If your hook calls an external API, use PostToolUse or accept the latency.

The Sticky Note Is Gone

The monitoring that used to live in my head now lives in five shell scripts totalling 150 lines. They run on every tool call without my involvement. They catch things I would miss when I am tired at the end of a long session. They never forget to check the branch.

AI coding assistants are powerful. But power without guardrails is just risk you have not measured yet. Five scripts, ten minutes of setup, and the risk drops to nearly zero.

The sticky note has been replaced by something better. Something that does not rely on me remembering to look at it.

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Email Print
Share
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article Today's NYT Connections: Sports Edition Hints, Answers for March 10 #533 Today's NYT Connections: Sports Edition Hints, Answers for March 10 #533
Next Article Google Photos can finally remember how much you don’t want to use Ask Photos Google Photos can finally remember how much you don’t want to use Ask Photos
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

248.1k Like
69.1k Follow
134k Pin
54.3k Follow

Latest News

The Best PDF Editor We’ve Tested for 2026
The Best PDF Editor We’ve Tested for 2026
News
Unitree Robotics founder Wang Xingxing named rotating chair of new embodied intelligence alliance in Hangzhou
Unitree Robotics founder Wang Xingxing named rotating chair of new embodied intelligence alliance in Hangzhou
Computing
A new iPhone Fold design leak reportedly revealed
A new iPhone Fold design leak reportedly revealed
News
China shelves restructuring plan to merge Changan and Dongfeng · TechNode
China shelves restructuring plan to merge Changan and Dongfeng · TechNode
Computing

You Might also Like

Unitree Robotics founder Wang Xingxing named rotating chair of new embodied intelligence alliance in Hangzhou
Computing

Unitree Robotics founder Wang Xingxing named rotating chair of new embodied intelligence alliance in Hangzhou

1 Min Read
China shelves restructuring plan to merge Changan and Dongfeng · TechNode
Computing

China shelves restructuring plan to merge Changan and Dongfeng · TechNode

1 Min Read
Multiple Chinese cities pause trade-in subsidies, sparking confusion amid 618 sales rush · TechNode
Computing

Multiple Chinese cities pause trade-in subsidies, sparking confusion amid 618 sales rush · TechNode

1 Min Read
DJI’s car tech unit raises new funds from Chinese automakers GAC and BAIC · TechNode
Computing

DJI’s car tech unit raises new funds from Chinese automakers GAC and BAIC · TechNode

1 Min Read
//

World of Software is your one-stop website for the latest tech news and updates, follow us now to get the news that matters to you.

Quick Link

  • Privacy Policy
  • Terms of use
  • Advertise
  • Contact

Topics

  • Computing
  • Software
  • Press Release
  • Trending

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

World of SoftwareWorld of Software
Follow US
Copyright © All Rights Reserved. World of Software.
Welcome Back!

Sign in to your account

Lost your password?