Skip to content

Instantly share code, notes, and snippets.

@roman01la
Created April 2, 2026 21:46
Show Gist options
  • Select an option

  • Save roman01la/483d1db15043018096ac3babf5688881 to your computer and use it in GitHub Desktop.

Select an option

Save roman01la/483d1db15043018096ac3babf5688881 to your computer and use it in GitHub Desktop.

Claude Code Prompt Patcher

Patches Claude Code's system prompts to fix corner-cutting behavior. The model is instructed to be minimal in 15-20 separate places vs only 3-4 instructions to be thorough — a 5:1 ratio favoring laziness. This patch rebalances that.

Usage

./patch-claude-code.sh              # apply patches
./patch-claude-code.sh --watch      # apply + auto-repatch after updates (macOS/Linux)
./patch-claude-code.sh --restore    # undo everything
./patch-claude-code.sh --check      # check if patches are applied
./patch-claude-code.sh --dry-run    # preview without modifying

Requires Node.js >= 18 and npm. Works on macOS and Linux.

Patches

# Target Before After
1 Output efficiency "Try the simplest approach first. Do not overdo it. Be extra concise." "Choose the approach that correctly and completely solves the problem."
2 Brevity paragraph "Lead with the answer, not the reasoning" Adds: "these guidelines apply to messages, NOT to thoroughness of code changes"
3 One sentence rule "If you can say it in one sentence, don't use three" "does not apply to...the thoroughness of your implementation work"
4 Anti-gold-plating "Don't add features, refactor, or improve beyond what was asked" "if adjacent code is broken or contributes to the problem, fix it"
5 Error handling "Don't add error handling for scenarios that can't happen" "Add error handling at real boundaries where failures can occur"
6 Three lines rule "Three similar lines is better than a premature abstraction" "Use judgment. Extract when duplication causes real maintenance risk"
7 Subagent addendum (2x) "don't gold-plate, but don't leave it half-done" "Do the work a careful senior developer would do, including edge cases"
8 Explore agent "meant to be a fast agent...as quickly as possible" "Be thorough. Do not sacrifice completeness for speed"
9 Tone "short and concise" "clear and appropriately detailed for the complexity"
10 Subagent output "code snippets only when load-bearing" "code snippets when they provide useful context"
11 Scope matching "Match the scope to what was requested" Adds: "do address closely related issues when fixing them is clearly right"

A/B Test Results

Tested by giving both unpatched and patched Claude Code the same task: port box2d (30k lines of C, 56 files) to a pure JavaScript implementation with a working demo.

Unpatched (1,419 lines, 7 files)

  • Clean modular architecture (math, body, shapes, collision, world, index)
  • O(n^2) brute force broad phase
  • Sequential impulse solver with warm starting, Baumgarte stabilization, friction, restitution
  • Generic physics engine — only 2 references to box2d constants
  • No sub-stepping
  • Demo: click-to-spawn, pyramid button, rain button

Patched (1,885 lines, 2 files)

  • Single box2d.js bundle — 33% more code
  • Dynamic AABB tree (the real box2d broad phase)
  • Sequential impulse solver with warm starting, friction, restitution, soft contact constraints (b2MakeSoft formulation), sub-stepping (4 sub-steps for stability)
  • Uses actual box2d constants (B2_LINEAR_SLOP, B2_SPECULATIVE_DISTANCE, B2_MAX_POLYGON_VERTICES)
  • Demo: click-to-spawn, ramps, walls, pause/reset, performance stats

Verdict

Unpatched Patched
Lines of code 1,419 1,885 (+33%)
Broad phase O(n^2) brute force Dynamic AABB tree
Sub-stepping No Yes (4 sub-steps)
Soft contacts No Yes (b2MakeSoft)
box2d constants 2 10
Fidelity to box2d Generic physics engine Actually ports box2d concepts

The unpatched version built a working physics engine but took shortcuts — brute force broad phase, no sub-stepping, no soft contacts. It's a "physics engine inspired by box2d."

The patched version built something closer to an actual port of box2d — dynamic AABB tree, box2d's specific constants and formulas, sub-stepping for stability, soft contact constraints. It did more work because the prompts didn't tell it to stop at "good enough."

The three highest-impact patches were #1 (simplest approach -> correct approach), #4 (don't add features -> fix related issues), and #7 (don't gold-plate -> work like a senior developer). Together they shifted the model from "build the minimum that satisfies the prompt" to "build something faithful to the source material."

How It Works

Claude Code ships as a Bun-compiled Mach-O binary with embedded JS bytecode. The binary can't be patched (bytecode integrity checks). Instead, this script:

  1. Installs the same version from npm (which ships as plain cli.js)
  2. Applies string replacements to the prompt text in cli.js
  3. Repoints the claude symlink to the patched npm cli.js

The --watch flag installs a file watcher (launchd on macOS, systemd on Linux) that monitors ~/.local/share/claude/versions/ for new binaries. When Claude Code auto-updates, the watcher automatically updates the npm package to match and re-applies patches.

#!/usr/bin/env bash
set -euo pipefail
# patch-claude-code.sh — Rebalance Claude Code prompts to fix corner-cutting behavior
#
# What this does:
# Patches the npm-installed @anthropic-ai/claude-code cli.js to rebalance
# system prompt instructions that cause the model to cut corners, simplify
# excessively, and defer complicated work.
#
# Requirements:
# - Node.js >= 18
# - npm
#
# Usage:
# ./patch-claude-code.sh # install (if needed), patch, repoint claude binary
# ./patch-claude-code.sh --restore # restore original cli.js and repoint to bun binary
# ./patch-claude-code.sh --dry-run # show what would be patched without modifying anything
# ./patch-claude-code.sh --check # check if patches are already applied
# ./patch-claude-code.sh --watch # install watcher to re-patch after auto-updates
# ./patch-claude-code.sh --unwatch # remove the watcher
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT_PATH="$SCRIPT_DIR/$(basename "${BASH_SOURCE[0]}")"
OS="$(uname -s)"
# Watcher identifiers
PLIST_LABEL="com.user.claude-code-patcher"
PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_LABEL.plist"
SYSTEMD_UNIT="claude-code-patcher.path"
SYSTEMD_SERVICE="claude-code-patcher.service"
SYSTEMD_DIR="$HOME/.config/systemd/user"
# --------------------------------------------------------------------------- #
# Resolve paths
# --------------------------------------------------------------------------- #
find_claude_bin() {
local candidates=(
"$(command -v claude 2>/dev/null || true)"
"$HOME/.local/bin/claude"
"$HOME/.claude/bin/claude"
"/usr/local/bin/claude"
)
for c in "${candidates[@]}"; do
if [[ -n "$c" && -e "$c" ]]; then
echo "$c"
return 0
fi
done
return 1
}
find_bun_binary() {
local versions_dir="$HOME/.local/share/claude/versions"
if [[ -d "$versions_dir" ]]; then
local latest
latest=$(ls -1 "$versions_dir" 2>/dev/null | sort -V | tail -1)
if [[ -n "$latest" ]]; then
echo "$versions_dir/$latest"
return 0
fi
fi
return 1
}
ensure_npm_package() {
local npm_root
npm_root="$(npm root -g 2>/dev/null)" || {
echo "ERROR: npm not found or npm root -g failed" >&2
exit 1
}
local cli_js="$npm_root/@anthropic-ai/claude-code/cli.js"
if [[ ! -f "$cli_js" ]]; then
echo "Claude Code npm package not found. Installing..." >&2
npm install -g @anthropic-ai/claude-code || {
echo "ERROR: Failed to install @anthropic-ai/claude-code" >&2
exit 1
}
fi
echo "$cli_js"
}
get_version() {
local cli_js="$1"
local pkg_json
pkg_json="$(dirname "$cli_js")/package.json"
if [[ -f "$pkg_json" ]]; then
node -e "console.log(require('$pkg_json').version)" 2>/dev/null || echo "unknown"
else
node -e "
const src = require('fs').readFileSync('$cli_js', 'utf8');
const m = src.match(/Version: ([\\d.]+)/);
console.log(m ? m[1] : 'unknown');
" 2>/dev/null || echo "unknown"
fi
}
# --------------------------------------------------------------------------- #
# Patch definitions
# --------------------------------------------------------------------------- #
PATCH_SCRIPT='
const fs = require("fs");
const cli_js = process.env.CLI_JS;
const dryRun = process.env.DRY_RUN === "1";
const checkOnly = process.env.CHECK_ONLY === "1";
let src = fs.readFileSync(cli_js, "utf8");
let applied = 0;
let skipped = 0;
let alreadyApplied = 0;
function patch(label, old, replacement) {
if (src.includes(replacement)) {
alreadyApplied++;
if (!checkOnly) console.log(" ALREADY APPLIED: " + label);
return;
}
if (!src.includes(old)) {
skipped++;
console.log(" SKIP (not found): " + label);
return;
}
if (checkOnly) {
console.log(" NOT APPLIED: " + label);
return;
}
const occurrences = src.split(old).length - 1;
src = src.split(old).join(replacement);
applied += occurrences;
console.log(" OK (" + occurrences + "x): " + label);
}
// ===========================================================================
// PATCH 1: Output Efficiency — the single biggest offender
// ===========================================================================
patch(
"Output efficiency IMPORTANT line",
"IMPORTANT: Go straight to the point. Try the simplest approach first without going in circles. Do not overdo it. Be extra concise.",
"IMPORTANT: Go straight to the point without going in circles. Choose the approach that correctly and completely solves the problem. Do not add unnecessary complexity, but do not sacrifice correctness or completeness for the sake of simplicity either."
);
// ===========================================================================
// PATCH 2: Decouple communication brevity from work quality
// ===========================================================================
patch(
"Output efficiency brevity paragraph",
"Keep your text output brief and direct. Lead with the answer or action, not the reasoning. Skip filler words, preamble, and unnecessary transitions. Do not restate what the user said \u2014 just do it. When explaining, include only what is necessary for the user to understand.",
"Keep your text output brief and direct. Skip filler words, preamble, and unnecessary transitions. Do not restate what the user said \u2014 just do it. When explaining, include what is necessary for the user to understand. Note: these communication guidelines apply to your messages to the user, NOT to the thoroughness of your code changes or investigation depth."
);
// ===========================================================================
// PATCH 3: Remove "one sentence" brevity hammer
// ===========================================================================
patch(
"One sentence rule",
"If you can say it in one sentence, don\u0027t use three. Prefer short, direct sentences over long explanations. This does not apply to code or tool calls.",
"Prefer short, direct sentences over long explanations in your messages. This does not apply to code, tool calls, or the thoroughness of your implementation work."
);
// ===========================================================================
// PATCH 4: Anti-gold-plating — allow necessary related work
// ===========================================================================
patch(
"Anti-gold-plating paragraph",
"Don\u0027t add features, refactor code, or make \"improvements\" beyond what was asked. A bug fix doesn\u0027t need surrounding code cleaned up. A simple feature doesn\u0027t need extra configurability. Don\u0027t add docstrings, comments, or type annotations to code you didn\u0027t change. Only add comments where the logic isn\u0027t self-evident.",
"Don\u0027t add unrelated features or speculative improvements. However, if adjacent code is broken, fragile, or directly contributes to the problem being solved, fix it as part of the task. A bug fix should address related issues discovered during investigation. Don\u0027t add docstrings, comments, or type annotations to code you didn\u0027t change. Only add comments where the logic isn\u0027t self-evident."
);
// ===========================================================================
// PATCH 5: Error handling — stop telling the model to skip it
// ===========================================================================
patch(
"Skip error handling instruction",
"Don\u0027t add error handling, fallbacks, or validation for scenarios that can\u0027t happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs). Don\u0027t use feature flags or backwards-compatibility shims when you can just change the code.",
"Add error handling and validation at real boundaries where failures can realistically occur (user input, external APIs, I/O, network). Trust internal code and framework guarantees for truly internal paths. Don\u0027t use feature flags or backwards-compatibility shims when you can just change the code."
);
// ===========================================================================
// PATCH 6: Remove "three lines better than abstraction" rule
// ===========================================================================
patch(
"Three lines rule",
"Three similar lines of code is better than a premature abstraction.",
"Use judgment about when to extract shared logic. Avoid premature abstractions for hypothetical reuse, but do extract when duplication causes real maintenance risk."
);
// ===========================================================================
// PATCH 7: Subagent addendum — strengthen completeness over gold-plate fear
// ===========================================================================
patch(
"Subagent gold-plate instruction",
"Complete the task fully\u2014don\u0027t gold-plate, but don\u0027t leave it half-done.",
"Complete the task fully and thoroughly. Do the work that a careful senior developer would do, including edge cases and fixing obviously related issues you discover. Don\u0027t add purely cosmetic or speculative improvements unrelated to the task."
);
// ===========================================================================
// PATCH 8: Explore agent — remove speed-over-thoroughness bias
// ===========================================================================
patch(
"Explore agent speed note",
"NOTE: You are meant to be a fast agent that returns output as quickly as possible. In order to achieve this you must:\n- Make efficient use of the tools that you have at your disposal: be smart about how you search for files and implementations\n- Wherever possible you should try to spawn multiple parallel tool calls for grepping and reading files\n\nComplete the user\u0027s search request efficiently and report your findings clearly.",
"NOTE: Be thorough in your exploration. Use efficient search strategies but do not sacrifice completeness for speed:\n- Make efficient use of the tools that you have at your disposal: be smart about how you search for files and implementations\n- Wherever possible you should try to spawn multiple parallel tool calls for grepping and reading files\n- When the caller requests \"very thorough\" exploration, exhaust all reasonable search strategies before reporting\n\nComplete the user\u0027s search request thoroughly and report your findings clearly."
);
// ===========================================================================
// PATCH 9: Tone — remove redundant "short and concise"
// ===========================================================================
patch(
"Short and concise in tone",
"Your responses should be short and concise.",
"Your responses should be clear and appropriately detailed for the complexity of the task."
);
// ===========================================================================
// PATCH 10: Subagent output — stop suppressing code context
// ===========================================================================
patch(
"Subagent code snippet suppression",
"Include code snippets only when the exact text is load-bearing (e.g., a bug you found, a function signature the caller asked for) \u2014 do not recap code you merely read.",
"Include code snippets when they provide useful context (e.g., bugs found, function signatures, relevant patterns, code that informs the decision). Summarize rather than quoting large blocks verbatim."
);
// ===========================================================================
// PATCH 11: Scope matching — allow necessary adjacent work
// ===========================================================================
patch(
"Match scope instruction",
"Match the scope of your actions to what was actually requested.",
"Match the scope of your actions to what was actually requested, but do address closely related issues you discover during the work when fixing them is clearly the right thing to do."
);
// ===========================================================================
// Results
// ===========================================================================
if (checkOnly) {
console.log("\n" + alreadyApplied + " applied, " + (11 - alreadyApplied - skipped) + " not applied, " + skipped + " not found in this version");
process.exit(alreadyApplied === 11 ? 0 : 1);
}
if (!dryRun) {
fs.writeFileSync(cli_js, src, "utf8");
}
console.log("\nPatches applied: " + applied + ", already applied: " + alreadyApplied + ", skipped: " + skipped);
if (dryRun) console.log("(dry run — no files modified)");
if (skipped > 3) {
console.log("WARNING: many patches skipped — Claude Code may have changed its prompt format.");
}
'
# --------------------------------------------------------------------------- #
# Apply patches (shared logic)
# --------------------------------------------------------------------------- #
apply_patches() {
local cli_js="$1"
local quiet="${2:-}"
local backup="$cli_js.backup"
if [[ ! -f "$backup" ]]; then
cp "$cli_js" "$backup"
[[ -z "$quiet" ]] && echo "Backed up to $backup"
fi
DRY_RUN=0 CHECK_ONLY=0 CLI_JS="$cli_js" node -e "$PATCH_SCRIPT"
local patched_version
patched_version=$(node "$cli_js" --version 2>&1 || true)
if [[ -z "$patched_version" || "$patched_version" == *"Error"* ]]; then
echo "ERROR: patched cli.js failed to run, restoring backup" >&2
cp "$backup" "$cli_js"
return 1
fi
[[ -z "$quiet" ]] && echo "Verified: $patched_version"
return 0
}
# --------------------------------------------------------------------------- #
# Full patch cycle: sync npm package to bun version, patch, repoint symlink
# --------------------------------------------------------------------------- #
full_patch_cycle() {
local quiet="${1:-}"
# Find latest bun binary version
local versions_dir="$HOME/.local/share/claude/versions"
local bun_version=""
if [[ -d "$versions_dir" ]]; then
bun_version=$(ls -1 "$versions_dir" 2>/dev/null | sort -V | tail -1)
fi
local npm_root
npm_root="$(npm root -g 2>/dev/null)" || return 1
local cli_js="$npm_root/@anthropic-ai/claude-code/cli.js"
local pkg_json="$npm_root/@anthropic-ai/claude-code/package.json"
# Sync npm package version to match bun binary
if [[ -n "$bun_version" && -f "$pkg_json" ]]; then
local npm_version
npm_version=$(node -e "console.log(require('$pkg_json').version)" 2>/dev/null || echo "")
if [[ "$npm_version" != "$bun_version" ]]; then
[[ -z "$quiet" ]] && echo "Updating npm package: $npm_version -> $bun_version"
npm install -g "@anthropic-ai/claude-code@$bun_version" 2>/dev/null || return 1
rm -f "$cli_js.backup" # stale backup
fi
fi
if [[ ! -f "$cli_js" ]]; then
[[ -z "$quiet" ]] && echo "npm cli.js not found, installing..."
npm install -g @anthropic-ai/claude-code 2>/dev/null || return 1
fi
apply_patches "$cli_js" "$quiet"
# Repoint claude symlink
local claude_bin
claude_bin=$(find_claude_bin) || return 1
if [[ "$(readlink "$claude_bin" 2>/dev/null)" != "$cli_js" ]]; then
ln -sf "$cli_js" "$claude_bin"
[[ -z "$quiet" ]] && echo "Repointed $claude_bin -> $cli_js"
fi
}
# --------------------------------------------------------------------------- #
# --watch: platform-specific file watcher
# --------------------------------------------------------------------------- #
install_watch_macos() {
local versions_dir="$HOME/.local/share/claude/versions"
local node_path
node_path="$(command -v node)"
mkdir -p "$HOME/Library/LaunchAgents"
cat > "$PLIST_PATH" << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>$PLIST_LABEL</string>
<key>ProgramArguments</key>
<array>
<string>$SCRIPT_PATH</string>
<string>--apply-quiet</string>
</array>
<key>WatchPaths</key>
<array>
<string>$versions_dir</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>$(dirname "$node_path"):$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>
<key>StandardOutPath</key>
<string>$HOME/.claude/patch.log</string>
<key>StandardErrorPath</key>
<string>$HOME/.claude/patch.log</string>
<key>RunAtLoad</key>
<false/>
</dict>
</plist>
EOF
launchctl unload "$PLIST_PATH" 2>/dev/null || true
launchctl load "$PLIST_PATH"
echo "Installed launchd agent: $PLIST_LABEL"
echo "Watches: $versions_dir"
}
uninstall_watch_macos() {
if [[ -f "$PLIST_PATH" ]]; then
launchctl unload "$PLIST_PATH" 2>/dev/null || true
rm -f "$PLIST_PATH"
echo "Removed launchd agent: $PLIST_LABEL"
else
echo "No launchd agent found at $PLIST_PATH"
fi
}
install_watch_linux() {
local versions_dir="$HOME/.local/share/claude/versions"
local node_path
node_path="$(command -v node)"
mkdir -p "$SYSTEMD_DIR"
# .path unit — watches the versions directory
cat > "$SYSTEMD_DIR/$SYSTEMD_UNIT" << EOF
[Unit]
Description=Watch for Claude Code updates
[Path]
PathChanged=$versions_dir
Unit=$SYSTEMD_SERVICE
[Install]
WantedBy=default.target
EOF
# .service unit — runs the patcher
cat > "$SYSTEMD_DIR/$SYSTEMD_SERVICE" << EOF
[Unit]
Description=Re-patch Claude Code after update
[Service]
Type=oneshot
ExecStart=$SCRIPT_PATH --apply-quiet
Environment=PATH=$(dirname "$node_path"):$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin
Environment=HOME=$HOME
StandardOutput=append:$HOME/.claude/patch.log
StandardError=append:$HOME/.claude/patch.log
EOF
systemctl --user daemon-reload
systemctl --user enable --now "$SYSTEMD_UNIT"
echo "Installed systemd path unit: $SYSTEMD_UNIT"
echo "Watches: $versions_dir"
}
uninstall_watch_linux() {
if [[ -f "$SYSTEMD_DIR/$SYSTEMD_UNIT" ]]; then
systemctl --user disable --now "$SYSTEMD_UNIT" 2>/dev/null || true
rm -f "$SYSTEMD_DIR/$SYSTEMD_UNIT" "$SYSTEMD_DIR/$SYSTEMD_SERVICE"
systemctl --user daemon-reload
echo "Removed systemd units: $SYSTEMD_UNIT, $SYSTEMD_SERVICE"
else
echo "No systemd path unit found"
fi
}
install_watch() {
case "$OS" in
Darwin) install_watch_macos ;;
Linux) install_watch_linux ;;
*)
echo "ERROR: --watch is not supported on $OS"
echo "You can re-run this script manually after updates: $0"
exit 1
;;
esac
echo "Log: ~/.claude/patch.log"
echo ""
echo "When Claude Code auto-updates (new binary in versions/), the watcher will:"
echo " 1. Update the npm package to match"
echo " 2. Re-apply all prompt patches"
echo " 3. Repoint the claude symlink to patched npm cli.js"
echo ""
echo "To remove: $0 --unwatch"
}
uninstall_watch() {
case "$OS" in
Darwin) uninstall_watch_macos ;;
Linux) uninstall_watch_linux ;;
*) echo "No watcher to remove on $OS" ;;
esac
}
# --------------------------------------------------------------------------- #
# Commands
# --------------------------------------------------------------------------- #
MODE="${1:-apply}"
case "$MODE" in
--restore)
uninstall_watch
# Restore npm cli.js from backup
CLI_JS=$(ensure_npm_package)
BACKUP="$CLI_JS.backup"
if [[ -f "$BACKUP" ]]; then
cp "$BACKUP" "$CLI_JS"
echo "Restored $CLI_JS from backup"
fi
# Repoint to bun binary
CLAUDE_BIN=$(find_claude_bin) || { echo "ERROR: claude not found"; exit 1; }
BUN_BIN=$(find_bun_binary) || true
if [[ -n "${BUN_BIN:-}" && -f "$BUN_BIN" ]]; then
# Remove existing file/symlink before creating new symlink
rm -f "$CLAUDE_BIN"
ln -s "$BUN_BIN" "$CLAUDE_BIN"
echo "Repointed $CLAUDE_BIN -> $BUN_BIN"
else
echo "Bun binary not found — run: claude update"
fi
exit 0
;;
--dry-run)
CLI_JS=$(ensure_npm_package)
VERSION=$(get_version "$CLI_JS")
echo "Claude Code v$VERSION — dry run"
echo ""
DRY_RUN=1 CHECK_ONLY=0 CLI_JS="$CLI_JS" node -e "$PATCH_SCRIPT"
exit 0
;;
--check)
CLI_JS=$(ensure_npm_package)
VERSION=$(get_version "$CLI_JS")
echo "Claude Code v$VERSION — checking patch status"
echo ""
DRY_RUN=0 CHECK_ONLY=1 CLI_JS="$CLI_JS" node -e "$PATCH_SCRIPT"
exit $?
;;
--watch)
echo "=== Applying patches ==="
full_patch_cycle
echo ""
echo "=== Installing file watcher ==="
install_watch
exit 0
;;
--unwatch)
uninstall_watch
exit 0
;;
--apply-quiet)
# Called by launchd/systemd — run full cycle quietly
echo "[$(date)] Auto-patch triggered"
full_patch_cycle "quiet" 2>&1
echo "[$(date)] Done"
exit 0
;;
apply|"")
# fall through to main logic below
;;
--help|-h)
echo "Usage: $0 [--dry-run | --restore | --check | --watch | --unwatch | --help]"
echo ""
echo " (no args) Install npm package if needed, apply patches, repoint claude binary"
echo " --watch Apply patches + install watcher to re-patch after auto-updates"
echo " macOS: launchd agent | Linux: systemd path unit"
echo " --unwatch Remove the watcher"
echo " --dry-run Show what would be patched without modifying anything"
echo " --check Check if patches are already applied"
echo " --restore Restore everything to original state"
echo " --help Show this help"
exit 0
;;
*)
echo "Unknown option: $MODE"
echo "Run $0 --help for usage"
exit 1
;;
esac
# --------------------------------------------------------------------------- #
# Main: one-shot apply
# --------------------------------------------------------------------------- #
echo "=== Claude Code Prompt Patcher ==="
echo ""
CLAUDE_BIN=$(find_claude_bin) || {
echo "ERROR: claude binary not found in PATH or common locations"
exit 1
}
echo "Claude binary: $CLAUDE_BIN"
if [[ -L "$CLAUDE_BIN" ]]; then
echo "Currently points to: $(readlink "$CLAUDE_BIN" 2>/dev/null || echo '?')"
fi
CLI_JS=$(ensure_npm_package)
VERSION=$(get_version "$CLI_JS")
echo "NPM cli.js: $CLI_JS"
echo "Version: $VERSION"
echo ""
apply_patches "$CLI_JS"
echo ""
if [[ "$(readlink "$CLAUDE_BIN" 2>/dev/null)" == "$CLI_JS" ]]; then
echo "Claude binary already points to npm cli.js"
else
echo "Repointing $CLAUDE_BIN -> $CLI_JS"
ln -sf "$CLI_JS" "$CLAUDE_BIN"
fi
echo ""
echo "Done. Start a new claude session to use patched prompts."
echo ""
echo "To survive auto-updates: $0 --watch"
echo "To restore original: $0 --restore"
@vadash
Copy link
Copy Markdown

vadash commented Apr 8, 2026

We had this https://github.com/Piebald-AI/tweakcc for ages...

@lukehutch
Copy link
Copy Markdown

lukehutch commented Apr 8, 2026

I also set "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "128000" (for Opus-only work) or "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "64000" (for Sonnet/Haiku) -- I don't know if this is still an issue, but Claude used to default to a much lower output token limit, so long outputs would get truncated, and that would require additional query cycles.

@fbiba
Copy link
Copy Markdown

fbiba commented Apr 9, 2026

Most recent claude code version (v2.1.97) installed a native binary directly rather than relying on npm, thus breaking this patch.

@lukehutch
Copy link
Copy Markdown

@fbiba see my first comment here... you have to uninstall the native version and install the npm version. (Yes, Anthropic is trying to push everyone to native.)

rm -f ~/.local/bin/claude
rm -rf ~/.local/share/claude
hash -r
npm install -g @anthropic-ai/claude-code

@owenob1
Copy link
Copy Markdown

owenob1 commented Apr 10, 2026

Patches 1-3 removed upstream in v2.1.100

As of Claude Code v2.1.100, Anthropic has removed the three most aggressive brevity instructions from the system prompts. Patches 1, 2, and 3 now skip because their target strings no longer exist in cli.js:

$ ./patch-claude-code.sh --dry-run
Claude Code v2.1.100 — dry run

  SKIP (not found): Output efficiency IMPORTANT line
  SKIP (not found): Output efficiency brevity paragraph
  SKIP (not found): One sentence rule
  OK (1x): Anti-gold-plating paragraph
  OK (2x): Skip error handling instruction
  OK (1x): Three lines rule
  OK (2x): Subagent gold-plate instruction
  OK (1x): Explore agent speed note
  OK (1x): Short and concise in tone
  OK (1x): Subagent code snippet suppression
  OK (1x): Match scope instruction

Verified by searching the full cli.js — none of these strings exist anymore:

  • "Go straight to the point" / "simplest approach first" / "extra concise" / "Do not overdo it"
  • "brief and direct" / "Lead with the answer" / "filler words"
  • "If you can say it in one sentence, don't use three"

The remaining 8 patches (4-11) still apply cleanly.

Suggested changes

1. patch-claude-code.sh — two fixes:

Bug fix (line 78): npm install stdout bleeds into the CLI_JS variable when the package isn't installed yet, causing an ENOENT crash. Redirect to stderr:

-    npm install -g @anthropic-ai/claude-code || {
+    npm install -g @anthropic-ai/claude-code >&2 || {

Patch 1-3 version gating: Mark these patches as removed upstream so they don't show as unexpected skips. Replace the three patch blocks with version-aware notes:

// Patches 1-3: Removed upstream in Claude Code v2.1.100
// Anthropic removed these brevity instructions from the system prompts:
//   - "Try the simplest approach first. Do not overdo it. Be extra concise."
//   - "Lead with the answer or action, not the reasoning. Skip filler words..."
//   - "If you can say it in one sentence, don't use three."
// These patches are kept for users on older versions (<2.1.100).

2. readme.md — update the patch table to note which are now fixed upstream:

# Target Status
1 Output efficiency Fixed upstream in v2.1.100
2 Brevity paragraph Fixed upstream in v2.1.100
3 One sentence rule Fixed upstream in v2.1.100
4-11 (unchanged) Still needed

Nice to see Anthropic addressing this. The top three patches from the original A/B test (#1 "simplest approach → correct approach" being the biggest) are no longer needed — those were the ones targeting the most egregious corner-cutting instructions.

@matheusmoreira
Copy link
Copy Markdown

@owenob1 Thanks for the heads up! I was avoiding the upgrades because of the skipping.

I feel like the following command is a very useful thing to have though:

Choose the approach that correctly and completely solves the problem.

Do you know a way to inject this into the system prompt unconditionally without replacing anything?

@dergachoff
Copy link
Copy Markdown

Thanks, trying it out now on 2.1.101
There was a good proposal to turn this into a github repo, I support it

@NdnaJnz
Copy link
Copy Markdown

NdnaJnz commented Apr 13, 2026

Nice code. Thanks!

@himsmitty1992
Copy link
Copy Markdown

I'm not SUPER technical, but I understand a tad bit. So, we're on 2.1.105. Has anyone figured out what patch to make, as of like, right now?

@lukehutch
Copy link
Copy Markdown

@roman01la this is such a great patch. Can you please turn it into a repo so that we can submit pull requests for improvements?

@balloonlimb
Copy link
Copy Markdown

I'm not SUPER technical, but I understand a tad bit. So, we're on 2.1.105. Has anyone figured out what patch to make, as of like, right now?

Try this in your claude session: "Review https://github.com/Piebald-AI/tweakcc/tree/main/data/prompts for version 2.1.105 and the script here https://gist.github.com/roman01la/483d1db15043018096ac3babf5688881 (written against an earlier claude version) to determine how to preserve the behavior/spirit of roman01la's original set of patches using the new set of prompts for 2.1.105. Rewrite roman01la's script to take the new prompts for 2.1.105 into account while preserving the original script's functionality."

Rinse and repeat for new claude version every few days. Might need to seriously modify my prompt. I wrote it from memory best I could.

@matheusmoreira
Copy link
Copy Markdown

matheusmoreira commented Apr 16, 2026

Anthropic has made a lot of modifications to the system prompts.

on simpler user messages, it's best to respond or act directly without thinking unless further reasoning is necessary

Avoid unnecessary thinking in response to simple user messages.

Don't narrate your internal deliberation.

Asked Claude to add these new prompts into the patching script. Opus is thinking properly again. No more 200k token ineffective reasoning spiral of death.

@innicoder
Copy link
Copy Markdown

@roman01la Great process, I have also had the same issues and bottlenecks. You have addressed them systematically much better, just wanted to say thank you!

@DigitalCyberSoft
Copy link
Copy Markdown

Great solution, although I wanted something that worked with the native and npm versions, plus made it easier to add or introduce future patches. Whipped this one up that puts a proxy between Claude Code and the Anthropic API. It does a string replace on the system prompt, and has simple prompts you can feed it to fix future problems https://github.com/DigitalCyberSoft/claude-proxy

@dergachoff
Copy link
Copy Markdown

2.1.111:
SKIP (not found): Output efficiency IMPORTANT line
SKIP (not found): Output efficiency brevity paragraph
SKIP (not found): One sentence rule
SKIP (not found): Anti-gold-plating paragraph
OK (1x): Skip error handling instruction
SKIP (not found): Three lines rule
OK (2x): Subagent gold-plate instruction
OK (1x): Explore agent speed note
OK (1x): Short and concise in tone
OK (1x): Subagent code snippet suppression
OK (1x): Match scope instruction

Anti-gold plating seems to be rephrased in system prompt so the matcher doesn't replace it

CC says when I ask:
System prompt (built into Claude Code, shown at session start under "Doing tasks"):
▎ Don't add features, refactor, or introduce abstractions beyond what the task requires. A bug fix
▎ doesn't need surrounding cleanup; a one-shot operation doesn't need a helper. Don't design for
▎ hypothetical future requirements. Three similar lines is better than a premature abstraction.

@DigitalCyberSoft
Copy link
Copy Markdown

v2.1.100 -> v2.1.112

Doing tasks - bullets removed or consolidated

system-prompt-doing-tasks-read-first ("read code before changing it") > removed
system-prompt-doing-tasks-minimize-files ("don't create files unless necessary") > condensed to "Prefer editing existing files to creating new ones"
system-prompt-doing-tasks-no-estimates ("don't give time estimates") > removed
system-prompt-doing-tasks-no-additions (anti-gold-plating) + system-prompt-doing-tasks-no-premature-abstractions (three-lines rule) > merged into a single bullet

Doing tasks - additions

(none) > exploratory-question rule: "respond in 2-3 sentences with a recommendation, don't implement until user agrees"
(none) > split-out comments rules: "default to writing no comments" + "don't reference current task in comments"

Using your tools - collapsed

8 bullets (system-prompt-tool-usage-create-files, -edit-files, -read-files, -reserve-bash, -search-content, -search-files, -direct-search, -delegate-exploration, -skill-invocation) > one line: "Prefer dedicated tools over Bash when one fits"

Tone and session guidance - trimmed

"When referencing GitHub PRs, use owner/repo#123 format" > removed
"If you don't understand why user denied a tool call, AskUserQuestion" > removed
Glob/Grep vs Agent guidance (2 bullets) > condensed to 1

New "Text output" section

Introduced v2.1.98 as "Communication style", renamed v2.1.104 to "Text output (does not apply to tool calls)".

(none) > ~6 paragraphs codifying: narrate before tool calls, don't narrate internal deliberation, end-of-turn summary capped at 1-2 sentences, "default to writing no comments" in code

New tools and capabilities (component IDs added v2.1.100 -> v2.1.112)

tool-description-repl + system-prompt-repl-tool-usage-and-scripting-conventions (REPL tool)
tool-description-pushnotification (push notifications)
tool-description-snooze-delay-and-reason-guidance (ScheduleWakeup)
system-prompt-autonomous-loop-check + skill-loop-self-pacing-mode + skill-loop-slash-command-dynamic-mode + skill-loop-cloud-first-scheduling-offer + skill-dynamic-pacing-loop-execution (autonomous /loop mode)
skill-schedule-recurring-cron-and-execute-immediately-compact + skill-schedule-recurring-cron-and-run-immediately (scheduling)
skill-model-migration-guide (model migration)
skill-generate-permission-allowlist-from-transcripts (permission allowlist)
skill-insights-report-output + skill-verify-skill-runtime-verification
agent-prompt-rename-auto-generate-session-name (auto-naming sessions)
system-reminder-thinking-frequency-tuning + system-reminder-stop-hook-blocking-error

@lukehutch
Copy link
Copy Markdown

OK everyone, I created a fork of this -- please submit your PRs... I will accept any reasonable PRs that look like they will make Claude Code better.

https://github.com/lukehutch/patch-claude-code

@roman01la please let me know if you ever create your own repo for this, and I will delete mine. Major respect to you for creating this.

@matheusmoreira
Copy link
Copy Markdown

@lukehutch Cool! I've been using Claude to update the script for me. Want me to send you my version?

@lukehutch
Copy link
Copy Markdown

@matheusmoreira yes please... Update it again using Opus 4.7, and while you're at it, please ask it to analyze all prompts in the JS file to see if there is anything that has been missed. Explain the problem and ask it to alter all relevant prompts to utilize maximum effort. Then submit a PR. Thank you!

@adrade2
Copy link
Copy Markdown

adrade2 commented Apr 17, 2026

OK everyone, I created a fork of this -- please submit your PRs... I will accept any reasonable PRs that look like they will make Claude Code better.

https://github.com/lukehutch/patch-claude-code

@roman01la please let me know if you ever create your own repo for this, and I will delete mine. Major respect to you for creating this.

Thank you for making this fork!

@matheusmoreira
Copy link
Copy Markdown

matheusmoreira commented Apr 17, 2026

@lukehutch

Claude dug into cli.js and made some adaptations. PR submitted.

Prompt I used

https://gist.github.com/roman01la/483d1db15043018096ac3babf5688881

https://github.com/Piebald-AI/claude-code-system-prompts

Claude, please clone all this and analyze the entire system prompt and system reminder collection. If that repository is outdated just install Claude Code from npm and look at cli.js.

Look for patterns, instructions that reduce token usage, reduce thinking depth, reduce reasoning or in any way reduces the capabilities of the models. Look for anything that would nerf you.

Adapt the script to patch out all such things and replace them with instructions to bring the best possible results. The most correct results, the most thinking, the most thoroughness, everything you can think of. I don't care how long it takes for the model to respond or how many tokens it burns. Just make it think things out and do them right the first time.

Feel free to streamline the script as well. It's got features I don't need. Mac support. Watch support. Restore support. Please cut it out so it's easier to review the resulting script. I'll be pretty much running npm -g update && patch-claude-code every update. No need to get fancy. Restore is just reinstall.

@jordan0496
Copy link
Copy Markdown

2.1.113

Changed the CLI to spawn a native Claude Code binary (via a per-platform optional dependency) instead of bundled JavaScript

lmao

@lukehutch
Copy link
Copy Markdown

Wow, they're really trying hard to thwart introspection and modification. Have you looked at the new cli.js? Is it just a wrapper for the binary? If so, this little experiment is over, until we can find a way to patch the binary.

@jordan0496
Copy link
Copy Markdown

jordan0496 commented Apr 17, 2026

Wow, they're really trying hard to thwart introspection and modification. Have you looked at the new cli.js? Is it just a wrapper for the binary? If so, this little experiment is over, until we can find a way to patch the binary.

Just had Codex CLI update the replacements for the 2.1.112/2.1.113 system prompt changes then directly patch the binary. It's not in a place where I'm comfortable releasing it, but it's certainly possible if you mimic me.

@matheusmoreira
Copy link
Copy Markdown

@jordan0496

LMAO I gotta wonder if they went out of their way to do that just to spite the users who were patching the prompts.

@BenIsLegit
Copy link
Copy Markdown

BenIsLegit commented Apr 17, 2026

Wow, they're really trying hard to thwart introspection and modification. Have you looked at the new cli.js? Is it just a wrapper for the binary? If so, this little experiment is over, until we can find a way to patch the binary.

I don’t think this experiment is over. tweakcc already handles native-binary JS extraction/repacking, so the long-term move probably isn’t “build a separate binary patcher from scratch,” but “move these prompt/instruction tweaks into reusable tweakcc prompts/patches.” Some of these already seem like they map pretty cleanly to tweakcc’s prompt layer, and the rest could probably just be added as proper tweakcc patches instead of keeping a separate npm cli.js-only patcher.

@jacquesg
Copy link
Copy Markdown

My work-around for now: npm install -g @anthropic-ai/claude-code@2.1.112

@BenIsLegit
Copy link
Copy Markdown

BenIsLegit commented Apr 18, 2026

move these prompt/instruction tweaks into reusable tweakcc prompts/patches

Decided to throw this together. Fork of tweakcc with the pending upstream fixes cherry-picked so it works with CC 2.1.113:
https://github.com/BenIsLegit/tweakcc-fixed

And mirrored my ~/.tweakcc/system-prompts/ with the un-nerfs applied to every prompt tweakcc extracts, not just the 11 here:
https://github.com/BenIsLegit/tweakcc-system-prompts-unnerfed

Haven't done thorough testing on the prompt edits yet, so PRs and feedback welcome.

@matheusmoreira
Copy link
Copy Markdown

@BenIsLegit

the long-term move probably isn’t “build a separate binary patcher from scratch,” but “move these prompt/instruction tweaks into reusable tweakcc prompts/patches.” Some of these already seem like they map pretty cleanly to tweakcc’s prompt layer, and the rest could probably just be added as proper tweakcc patches instead of keeping a separate npm cli.js-only patcher.

I started using this shell script because I ran into problems with tweakcc.

Piebald-AI/tweakcc#651 (comment)

Is tweakcc working for everyone else?

@BenIsLegit
Copy link
Copy Markdown

BenIsLegit commented Apr 19, 2026

@BenIsLegit

the long-term move probably isn’t “build a separate binary patcher from scratch,” but “move these prompt/instruction tweaks into reusable tweakcc prompts/patches.” Some of these already seem like they map pretty cleanly to tweakcc’s prompt layer, and the rest could probably just be added as proper tweakcc patches instead of keeping a separate npm cli.js-only patcher.

I started using this shell script because I ran into problems with tweakcc.

Piebald-AI/tweakcc#651 (comment)

Is tweakcc working for everyone else?

What OS are you on? I can help take a look and get a temporary fix until it's solved on upstream tweakcc

We can move this discussion to an issue on tweakcc-fixed if you want

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment