Enhance Claude Code with custom patches for thinking display, background command notification formatting, Task Output waiting-format cleanup, and subagent model configuration.
- Thinking Display Patch - Make thinking blocks visible by default
- Background Command Format Patch - Remove embedded raw commands from background completion notifications
- Task Output Waiting Format Patch - Remove huge multiline task descriptions from
Task Output ... Waiting for task - Subagent Model Configuration - Configure which models subagents use
- NPM Deprecation Warning Patch - Remove the “switched from npm to native installer” banner
Make Claude Code's thinking blocks visible by default without pressing ctrl+o.
Claude Code collapses (or hides) thinking by default. In v2.0.74+ (including 2.1.1) you may see a collapsed banner like:
∴ Thinking (ctrl+o to expand)
And the spinner/status line may show timing hints like thinking / thought for 1s (this is separate UI from the thinking block).
You have to press ctrl+o every time to see the actual thinking content. This patch makes thinking blocks visible inline automatically.
Note: This patch does not change the spinner/status line (e.g. thought for 1s) text or position — it only affects whether the message thinking content is rendered inline.
Current Version: Claude Code 2.1.204 (Updated 2026-07-08)
Tested Versions: 2.0.62, 2.0.71, 2.0.74, 2.0.75, 2.0.76, 2.1.1, 2.1.2, 2.1.3, 2.1.4, 2.1.6, 2.1.7, 2.1.9, 2.1.11, 2.1.12, 2.1.14, 2.1.15, 2.1.17, 2.1.19, 2.1.20, 2.1.22, 2.1.23, 2.1.27, 2.1.30, 2.1.31, 2.1.32, 2.1.33, 2.1.34, 2.1.36, 2.1.37, 2.1.38, 2.1.39, 2.1.40, 2.1.41, 2.1.42, 2.1.44, 2.1.45, 2.1.47, 2.1.48, 2.1.49, 2.1.50, 2.1.51, 2.1.52, 2.1.53, 2.1.54, 2.1.55, 2.1.56, 2.1.58, 2.1.59, 2.1.61, 2.1.62, 2.1.63, 2.1.64, 2.1.66, 2.1.67, 2.1.68, 2.1.69, 2.1.70, 2.1.71, 2.1.72, 2.1.73, 2.1.74, 2.1.75, 2.1.76, 2.1.77, 2.1.78, 2.1.79, 2.1.80, 2.1.81, 2.1.83, 2.1.84, 2.1.85, 2.1.86, 2.1.87, 2.1.88, 2.1.89, 2.1.90, 2.1.91, 2.1.92, 2.1.94, 2.1.96, 2.1.97, 2.1.98, 2.1.101, 2.1.104, 2.1.105, 2.1.107, 2.1.108, 2.1.109, 2.1.110, 2.1.111, 2.1.112, 2.1.113, 2.1.114, 2.1.116, 2.1.117, 2.1.118, 2.1.119, 2.1.120, 2.1.121, 2.1.122, 2.1.123, 2.1.126, 2.1.128, 2.1.129, 2.1.131, 2.1.132, 2.1.133, 2.1.136, 2.1.137, 2.1.138, 2.1.139, 2.1.140, 2.1.141, 2.1.142, 2.1.143, 2.1.144, 2.1.145, 2.1.146, 2.1.147, 2.1.148, 2.1.149, 2.1.150, 2.1.152, 2.1.153, 2.1.154, 2.1.156, 2.1.157, 2.1.158, 2.1.160, 2.1.161, 2.1.162, 2.1.163, 2.1.165, 2.1.166, 2.1.167, 2.1.168, 2.1.169, 2.1.170, 2.1.172, 2.1.173, 2.1.174, 2.1.175, 2.1.176, 2.1.177, 2.1.178, 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, 2.1.204
Research notes:
2.1.86:.research/v2.1.86/README.md2.1.87:.research/v2.1.87/README.md2.1.88:.research/v2.1.88/README.md2.1.89:.research/v2.1.89/README.md2.1.90:.research/v2.1.90/README.md2.1.91:.research/v2.1.91/README.md2.1.92:.research/v2.1.92/README.md2.1.94:.research/v2.1.94/README.md2.1.96:.research/v2.1.96/README.md2.1.97:.research/v2.1.97/README.md2.1.98:.research/v2.1.98/README.md2.1.101:.research/v2.1.101/README.md2.1.102:.research/v2.1.102/README.md2.1.103:.research/v2.1.103/README.md2.1.104:.research/v2.1.104/README.md2.1.105:.research/v2.1.105/README.md2.1.106:.research/v2.1.106/README.md2.1.107:.research/v2.1.107/README.md2.1.108:.research/v2.1.108/README.md2.1.109:.research/v2.1.109/README.md2.1.110:.research/v2.1.110/README.md2.1.111:.research/v2.1.111/README.md2.1.112:.research/v2.1.112/README.md2.1.113:.research/v2.1.113/README.md2.1.114:.research/v2.1.114/README.md2.1.116:.research/v2.1.116/README.md2.1.117:.research/v2.1.117/README.md2.1.118:.research/v2.1.118/README.md2.1.119:.research/v2.1.119/README.md2.1.120:.research/v2.1.120/README.md2.1.121:.research/v2.1.121/README.md2.1.122:.research/v2.1.122/README.md2.1.123:.research/v2.1.123/README.md2.1.126:.research/v2.1.126/README.md2.1.128:.research/v2.1.128/README.md2.1.129:.research/v2.1.129/README.md2.1.130:.research/v2.1.130/README.md2.1.131:.research/v2.1.131/README.md2.1.132:.research/v2.1.132/README.md2.1.133:.research/v2.1.133/README.md2.1.136:.research/v2.1.136/README.md2.1.137:.research/v2.1.137/README.md2.1.138:.research/v2.1.138/README.md2.1.139:.research/v2.1.139/README.md2.1.140:.research/v2.1.140/README.md2.1.141:.research/v2.1.141/README.md2.1.142:.research/v2.1.142/README.md2.1.143:.research/v2.1.143/README.md2.1.144:.research/v2.1.144/README.md2.1.145:.research/v2.1.145/README.md2.1.146:.research/v2.1.146/README.md2.1.147:.research/v2.1.147/README.md2.1.148:.research/v2.1.148/README.md2.1.149:.research/v2.1.149/README.md2.1.150:.research/v2.1.150/README.md2.1.152:.research/v2.1.152/README.md2.1.153:.research/v2.1.153/README.md2.1.154:.research/v2.1.154/README.md2.1.155:.research/v2.1.155/README.md2.1.156:.research/v2.1.156/README.md2.1.157:.research/v2.1.157/README.md2.1.158:.research/v2.1.158/README.md2.1.160:.research/v2.1.160/README.md2.1.161:.research/v2.1.161/README.md2.1.162:.research/v2.1.162/README.md2.1.163:.research/v2.1.163/README.md2.1.164:.research/v2.1.164/README.md2.1.165:.research/v2.1.165/README.md2.1.166:.research/v2.1.166/README.md2.1.167:.research/v2.1.167/README.md2.1.168:.research/v2.1.168/README.md2.1.169:.research/v2.1.169/README.md2.1.170:.research/v2.1.170/README.md2.1.171:.research/v2.1.171/README.md2.1.172:.research/v2.1.172/README.md2.1.173:.research/v2.1.173/README.md2.1.174:.research/v2.1.174/README.md2.1.175:.research/v2.1.175/README.md2.1.176:.research/v2.1.176/README.md2.1.177:.research/v2.1.177/README.md2.1.178:.research/v2.1.178/README.md2.1.179:.research/v2.1.179/README.md2.1.180:.research/v2.1.180/README.md2.1.181:.research/v2.1.181/README.md2.1.182:.research/v2.1.182/README.md2.1.183:.research/v2.1.183/README.md2.1.184:.research/v2.1.184/README.md2.1.185:.research/v2.1.185/README.md2.1.186:.research/v2.1.186/README.md2.1.187:.research/v2.1.187/README.md2.1.190:.research/v2.1.190/README.md2.1.191:.research/v2.1.191/README.md2.1.193:.research/v2.1.193/README.md2.1.194:.research/v2.1.194/README.md2.1.195:.research/v2.1.195/README.md2.1.196:.research/v2.1.196/README.md2.1.197:.research/v2.1.197/README.md2.1.198:.research/v2.1.198/README.md2.1.199:.research/v2.1.199/README.md2.1.200:.research/v2.1.200/README.md2.1.201:.research/v2.1.201/README.md2.1.202:.research/v2.1.202/README.md2.1.203:.research/v2.1.203/README.md2.1.204:.research/v2.1.204/README.md
npm availability note (updated 2026-07-08): @anthropic-ai/claude-code@2.1.43, 2.1.46, 2.1.57, 2.1.60, 2.1.65, 2.1.102, 2.1.103, 2.1.106, 2.1.130, 2.1.155, 2.1.164, 2.1.171, 2.1.180, 2.1.184, 2.1.188, 2.1.189, 2.1.192, and 2.1.194 are not published on npm (ETARGET/E404). 2.1.154, 2.1.156, 2.1.157, 2.1.158, 2.1.160 through 2.1.163, 2.1.165 through 2.1.170, 2.1.172 through 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, and 2.1.204 are published and were re-verified. @anthropic-ai/claude-code-linux-x64@2.1.156 returned ETARGET during earlier research, while @anthropic-ai/claude-code-darwin-arm64@2.1.156 was published and verified. For 2.1.157, 2.1.158, 2.1.160 through 2.1.163, 2.1.165 through 2.1.170, 2.1.172 through 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, and 2.1.204, both @anthropic-ai/claude-code-darwin-arm64 and @anthropic-ai/claude-code-linux-x64 are published and were dry-run verified.
patch-thinking.js now also registers 2.1.154 through 2.1.158, plus 2.1.160 through 2.1.163, 2.1.165 through 2.1.170, 2.1.172 through 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, and 2.1.204, for native/binary targets. 2.1.165 reuses the same tweakcc-style memoized call-site regex family as 2.1.163; 2.1.166 through 2.1.170, 2.1.172 through 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, and 2.1.204 use the newer memoized call-site shape where hideInTranscript is no longer passed, so the patch removes the gates and forces isTranscriptMode:!0 without trying to patch hideInTranscript. 2.1.203 and 2.1.204 keep the same props but emit the early return as if(...){return null}, so the regex family accepts both braced and unbraced gate forms. 2.1.186 and later published versions use jsx(...)/jsxs(...) at the relevant React call sites, so the regex family accepts createElement, jsx, and jsxs. Starting in 2.1.113, the npm package is a wrapper whose postinstall copies or hardlinks the platform native binary into bin/claude.exe, so the patchers also auto-detect that npm/local binary path. 2.1.154, 2.1.156, 2.1.157, 2.1.158, 2.1.160 through 2.1.163, 2.1.165 through 2.1.170, 2.1.172 through 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, and 2.1.204 were verified on darwin-arm64 native binaries, linux-x64 native binaries, and npm-wrapper postinstall-equivalent targets. 2.1.155 remains inferred support only because Anthropic did not publish npm tarballs for direct validation; 2.1.164, 2.1.171, 2.1.180, 2.1.184, 2.1.188, 2.1.189, 2.1.192, and 2.1.194 are not registered because no npm wrapper/native tarballs are published.
No need to clone the repository — run patches directly:
# Thinking display patch
curl -fsSL https://raw.githubusercontent.com/cnzgray/claude-code-patches/main/patch-thinking.js | node
# NPM deprecation warning patch
curl -fsSL https://raw.githubusercontent.com/cnzgray/claude-code-patches/main/patch-npm-deprecation-warning.js | node
# Background command format patch
curl -fsSL https://raw.githubusercontent.com/cnzgray/claude-code-patches/main/patch-background-command-format.js | node
# Task Output waiting format patch
curl -fsSL https://raw.githubusercontent.com/cnzgray/claude-code-patches/main/patch-task-output-format.js | node
# Subagent model configuration patch (create ~/.claude/subagent-models.json first)
curl -fsSL https://raw.githubusercontent.com/cnzgray/claude-code-patches/main/patch-subagent-models.js | nodeIf you need --dry-run, --restore or other options, download the script first:
curl -fsSL https://raw.githubusercontent.com/cnzgray/claude-code-patches/main/patch-thinking.js -o /tmp/patch-thinking.js
node /tmp/patch-thinking.js --dry-run
node /tmp/patch-thinking.js --restore# Clone this repository
git clone https://github.com/cnzgray/claude-code-patches.git
cd claude-code-patches
# Run the patch script (automatically detects your installation)
node patch-thinking.js
# Restart Claude CodeThat's it! Thinking blocks now display inline without ctrl+o.
Works with:
- ✅ Local installations (
~/.claude/local) - ✅ Global npm installations (
npm install -g @anthropic-ai/claude-code) - ✅ Native/binary installations (
~/.local/bin/claude,~/.local/share/claude/versions/*) - ✅ All Node version managers (NVM, nodenv, asdf, etc.)
macOS note (native/binary installs): The native claude binary is code-signed. After patching, it must be re-signed (ad-hoc) or macOS may kill it on launch. The patch script handles this automatically; if needed you can run codesign --force --deep --sign - /path/to/claude yourself.
If your npm-installed Claude Code shows a banner like:
Claude Code has switched from npm to native installer. Run `claude install` ...
You can remove just that notification (without affecting other UI) by patching the compiled cli.js:
node patch-npm-deprecation-warning.jsAlso supports native/binary installs: patch the claude binary in-place (macOS may require re-signing; this script attempts ad-hoc re-sign automatically).
Re-verified on 2.1.69 / 2.1.70 / 2.1.71 / 2.1.72 / 2.1.73 / 2.1.74 / 2.1.75 / 2.1.76 / 2.1.77 / 2.1.78 / 2.1.79 / 2.1.80 / 2.1.83 / 2.1.84 / 2.1.85 / 2.1.86 / 2.1.87 / 2.1.88 / 2.1.89 / 2.1.90 / 2.1.91 / 2.1.92 / 2.1.94 / 2.1.96 / 2.1.97 / 2.1.98 / 2.1.101 / 2.1.104 / 2.1.105 / 2.1.107 / 2.1.108 / 2.1.109 / 2.1.110 / 2.1.111 / 2.1.112 / 2.1.113 / 2.1.114 / 2.1.116 / 2.1.117 / 2.1.118 / 2.1.119 / 2.1.120 / 2.1.121 / 2.1.122 / 2.1.123 / 2.1.126 / 2.1.128 / 2.1.129 / 2.1.131 / 2.1.132 / 2.1.133 / 2.1.136 / 2.1.137 / 2.1.138 / 2.1.139 / 2.1.140 / 2.1.141 / 2.1.142 / 2.1.143 / 2.1.144 / 2.1.145 / 2.1.146 / 2.1.147 / 2.1.148 / 2.1.149 / 2.1.150 / 2.1.152 / 2.1.153 / 2.1.154 / 2.1.156 / 2.1.157 / 2.1.158 / 2.1.160 / 2.1.161 / 2.1.162 / 2.1.163 / 2.1.165 / 2.1.166 / 2.1.167 / 2.1.168 / 2.1.169 / 2.1.170 / 2.1.172 / 2.1.173 / 2.1.174 / 2.1.175 / 2.1.176 / 2.1.177 / 2.1.178 / 2.1.179 / 2.1.181 / 2.1.182 / 2.1.183 / 2.1.185 / 2.1.186 / 2.1.187 / 2.1.190 / 2.1.191 / 2.1.193 / 2.1.195 / 2.1.196 / 2.1.197 / 2.1.198 / 2.1.199 / 2.1.200 / 2.1.201 / 2.1.202 / 2.1.203 / 2.1.204: through 2.1.161, the npm/native build used key:"npm-deprecation-warning", so the existing patch strategy stayed valid. In 2.1.162, 2.1.163, 2.1.165 through 2.1.170, 2.1.172 through 2.1.179, 2.1.181, 2.1.182, 2.1.183, 2.1.185, 2.1.186, 2.1.187, 2.1.190, 2.1.191, 2.1.193, 2.1.195, 2.1.196, 2.1.197, 2.1.198, 2.1.199, 2.1.200, 2.1.201, 2.1.202, 2.1.203, and 2.1.204, that warning is already absent from the npm-wrapper/native targets; the patcher therefore returns Already patched (npm deprecation warning not found). 2.1.184, 2.1.188, 2.1.189, 2.1.192, and 2.1.194 were not published on npm at verification time.
Options:
--dry-runpreview changes--restorerestore fromcli.js.backup--file /path/to/cli.jspatch a specific file
Before (e.g. v2.0.74+):
∴ Thinking (ctrl+o to expand)
[thinking content collapsed]
After:
∴ Thinking…
[thinking content displayed inline]
The actual thinking process is now visible
without any keyboard shortcuts needed
This patch modifies Claude Code's compiled JavaScript (the exact hook point depends on version):
Before:
function GkQ({streamMode:A}){
// ... displays "Thought for Xs (ctrl+o to show thinking)"
}After:
function GkQ({streamMode:A}){return null}Effect: Removes the collapsed thinking banner entirely.
Version History:
- v2.0.9: Function named
Mr2 - v2.0.10: Renamed to
br2, usedPE.createElement - v2.0.11: Renamed to
er2, uses_E.createElement - v2.0.13: Renamed to
hGB, usesTL.createElement - v2.0.14: Renamed to
pGB, usesTL.createElement,TX1.useState - v2.0.15: Renamed to
KYB, usesxL.createElement,mX1.useState - v2.0.19: Renamed to
aFB, usesZM.createElement,BV1.useState - v2.0.21: Renamed to
wVB, usesXM.createElement,DV1.useState - v2.0.22: Renamed to
YOB, usesNM.createElement,zK1.useState - v2.0.24: Renamed to
GSB, usesoM.createElement,kD1.useState - v2.0.25: Renamed to
YSB, usestM.createElement,xD1.useState - v2.0.26: Renamed to
KjQ, usesQO.createElement,gKA.useState - v2.0.28: Renamed to
RjQ, usesIO.createElement,iKA.useState - v2.0.29: Unchanged from v2.0.28 (
RjQ,IO.createElement,iKA.useState) - v2.0.30: Renamed to
GkQ, usesNO.createElement,dDA.useState - v2.0.31: Renamed to
_kQ, usesMO.createElement,nDA.useState - v2.0.32: Renamed to
wkQ, usesLO.createElement,oDA.useState - v2.0.37: Renamed to
nR2, usesCR.createElement,AwA.useState - v2.0.42: Renamed to
cR2, usesRR.createElement,UwA.useState - v2.0.46: Renamed to
Et2, usesxP.createElement,HTA.useState - v2.0.53: Renamed to
hq2, usesQP.createElement,dMA.useState - v2.0.55: Renamed to
nM2, usesUP.createElement,bOA.useState - v2.0.56: Renamed to
CL2, usesHP.createElement,xOA.useState - v2.0.57: Renamed to
HM2, usesEP.createElement,oOA.useState - v2.0.58: Renamed to
SM2, uses$P.createElement,GRA.useState - v2.0.59: Renamed to
DO2, usesMP.createElement,CRA.useState - v2.0.61: Renamed to
RR2, usesrj.createElement,vTA.useState,Pcontainer - v2.0.62: Renamed to
ZT2, usesGP.createElement,rTA.useState,Pcontainer
Before:
case"thinking":if(!K&&!Z)return null;
return H7.createElement(T32,{addMargin:Q,param:A,isTranscriptMode:K,verbose:Z});After:
case"thinking":
return H7.createElement(T32,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z});Effect: Forces thinking content to render as if in transcript mode (visible).
Version History:
- v2.0.9: Used
S2Bcomponent - v2.0.10: Changed to
DOBcomponent,z→Hvariable - v2.0.11: Changed to
SOBcomponent,H→zvariable - v2.0.13: Changed to
xlBcomponent,K→Dvariable swap - v2.0.14: Changed to
dlBcomponent, maintainsKandDvariable pattern - v2.0.15: Changed to
FpBcomponent,z3→C3variable - v2.0.19: Changed to
NoBcomponent,C3→B7variable - v2.0.21: Changed to
H8Qcomponent,B7→G7variable, checksKandD - v2.0.22: Changed to
nNBcomponent,G7→e3variable, checksKandD - v2.0.24: Changed to
nTBcomponent,e3→Y7variable, checksKandD - v2.0.25: Changed to
aTBcomponent, maintainsY7variable, checksKandD - v2.0.26: Changed to
CTQcomponent,Y7→Y3variable, checks onlyV - v2.0.28: Changed to
LTQcomponent,Y3→C3variable, checks onlyV - v2.0.29: Unchanged from v2.0.28 (
LTQcomponent,C3variable, checksV) - v2.0.30: Changed to
sjQcomponent,C3→D3variable, checksVandI, addedverboseparameter - v2.0.31: Changed to
MSQcomponent,D3→E3variable, checksVandI - v2.0.32: Changed to
ljQcomponent,E3→F3variable, checksVandI - v2.0.37: Changed to
n$Qcomponent,F3→K3variable, checksVandI - v2.0.42: Changed to
xLQcomponent,K3→w3variable, checksVandI - v2.0.46: Changed to
T32component,w3→H7variable, checksKandZ - v2.0.53: Changed to
o09component,H7→L3variable, checksKandG - v2.0.55: Changed to
J29component,L3→y3variable, checksKandG - v2.0.56: Changed to
b29component,y3→v3variable, checksKandG - v2.0.57: Changed to
K49component,v3→b3variable, checksKandG - v2.0.58: Changed to
k49component (lowercase k),b3variable, checksKandG - v2.0.59: Changed to
F89component,u3variable, checksKandG - v2.0.61: Changed to
T69component,A3variable, checksFandG - v2.0.62: Changed to
X59component,J3variable, checksFandG
In v2.0.74 / v2.0.75 / v2.0.76 thinking visibility is controlled in two places:
- The message renderer call site can short-circuit and hide thinking unless transcript mode / verbose is enabled.
- The thinking renderer (
co2in 2.0.74/2.0.75,lo2in 2.0.76) can render a collapsed banner instead of the full thinking content.
This patcher updates both so thinking renders inline by default (no ctrl+o needed).
Before:
case"thinking":if(!D&&!Z)return null;
return J5.createElement(co2,{addMargin:Q,param:A,isTranscriptMode:D,verbose:Z});After:
case"thinking":
return J5.createElement(co2,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z});Before:
function co2({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G}){
if(!A)return null;
if(!(B||G))return ... "∴ Thinking (ctrl+o to expand)";
return ... "∴ Thinking…" + thinking text ...
}After:
function co2({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G}){
if(!A)return null;
return ... "∴ Thinking…" + thinking text ...
}Effect: Removes the collapsed banner branch and always renders the full thinking content inline.
In v2.1.1 thinking visibility is still controlled in two places, but with slightly different logic:
- The message renderer call site still short-circuits and hides thinking unless transcript mode / verbose is enabled.
- The thinking renderer (
NbA) now has two hiding branches:- a transcript hide gate (
hideInTranscript) - the collapsed banner branch (
∴ Thinking (ctrl+o to expand))
- a transcript hide gate (
The patcher updates both so thinking renders inline by default (no ctrl+o needed).
In v2.1.2 the overall structure is the same as v2.1.1 (call-site gate + thinking renderer gate), but the compiled identifiers changed:
- The message renderer call site still short-circuits unless transcript mode / verbose is enabled.
- The thinking renderer is now
ybAand still includes both:- a transcript hide gate (
hideInTranscript) - the collapsed banner branch (
∴ Thinking (ctrl+o to expand))
- a transcript hide gate (
The patcher updates both so thinking renders inline by default (no ctrl+o needed).
- Claude Code installed (tested: 2.0.62 / 2.0.71 / 2.0.74 / 2.0.75 / 2.0.76 / 2.1.1)
- Node.js (comes with Claude Code installation)
-
Download the patcher:
# Clone this repository git clone <repository-url> cd claude-code-thinking
-
Run the patcher:
node patch-thinking.js
-
Restart Claude Code for changes to take effect.
The script supports several options:
# Apply patches (default)
node patch-thinking.js
# Preview changes without applying
node patch-thinking.js --dry-run
# Restore original behavior from backup
node patch-thinking.js --restore
# Patch a specific cli.js file or native claude binary (skip auto-detection)
node patch-thinking.js --file /path/to/cli.js
node patch-thinking.js --file /path/to/claude
# Show help
node patch-thinking.js --helpThe script automatically detects Claude Code installations using a robust 5-tier detection strategy:
You can also skip auto-detection:
--file /path/to/cli.js- or set
CLAUDE_CODE_CLI_PATH=/path/to/cli.js(both also accept a nativeclaudebinary path)
-
Local Installations (Priority 1)
~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js~/.config/claude/local/node_modules/@anthropic-ai/claude-code/cli.js
-
Global npm Installation (Priority 2)
- Dynamically detected via
npm root -g - Works with all Node version managers (NVM, nodenv, asdf, nvm-windows)
- Automatically resolves symlinks
- Dynamically detected via
-
Derived from Node.js Binary (Priority 3)
- Falls back to
process.execPathderivation - Works when npm command is unavailable
- Falls back to
-
Unix Binary Location (Priority 4)
- Uses
which claudeon macOS/Linux - Traces binary back to installation directory
- Uses
-
Native/Binary Installation (Priority 5)
- Detects the official native/binary installer layout
~/.local/bin/claude~/.local/share/claude/versions/*
- ✅ Works with any Node version - No hardcoded paths
- ✅ Supports all version managers - NVM, nodenv, asdf, etc.
- ✅ Cross-platform - macOS, Linux, Windows
- ✅ Automatic symlink resolution - Handles npm global symlinks
- ✅ Comprehensive error messages - Shows all attempted paths
Backup Created:
cli.js.backup(in the same directory as cli.js)
When you run claude update, the patches will be overwritten. You must re-apply them:
cd claude-code-thinking
node patch-thinking.js
# Restart Claude CodeThe patch script automatically:
- Detects your Claude Code installation
- Creates a backup before patching (if it doesn't exist)
- Applies both patches atomically
- Reports success or failure
- Safe to run multiple times
To restore the original behavior:
Option 1: Using the script
node patch-thinking.js --restoreOption 2: Manual restore
# The backup is created in the same directory as cli.js
cp ~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js.backup \
~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.jsThen restart Claude Code.
Check if patches are applied:
# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[20]!==Y)N=F5.createElement(jQ4,{addMargin:Y}),q[20]=Y,q[21]=N;else N=q[21];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=D&&!(!G||W===G)&&!Z,k;if(q[22]!==Y||q[23]!==D||q[24]!==K||q[25]!==T)k=F5.createElement(dW6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[22]=Y,q[23]=D,q[24]=K,q[25]=T,q[26]=k;else k=q[26];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.42# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[20]!==Y)N=F5.createElement(pF4,{addMargin:Y}),q[20]=Y,q[21]=N;else N=q[21];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=D&&!(!G||W===G)&&!Z,k;if(q[22]!==Y||q[23]!==D||q[24]!==K||q[25]!==T)k=F5.createElement(hW6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[22]=Y,q[23]=D,q[24]=K,q[25]=T,q[26]=k;else k=q[26];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.41# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[20]!==Y)N=B5.createElement(ib4,{addMargin:Y}),q[20]=Y,q[21]=N;else N=q[21];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=D&&!(!G||W===G)&&!Z,k;if(q[22]!==Y||q[23]!==D||q[24]!==K||q[25]!==T)k=B5.createElement(GP6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[22]=Y,q[23]=D,q[24]=K,q[25]=T,q[26]=k;else k=q[26];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.40# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[20]!==Y)N=F5.createElement(Kb4,{addMargin:Y}),q[20]=Y,q[21]=N;else N=q[21];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=j&&!(!G||W===G)&&!Z,k;if(q[22]!==Y||q[23]!==j||q[24]!==K||q[25]!==T)k=F5.createElement(pM6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[22]=Y,q[23]=j,q[24]=K,q[25]=T,q[26]=k;else k=q[26];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.39# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[20]!==Y)N=m5.createElement(Bx4,{addMargin:Y}),q[20]=Y,q[21]=N;else N=q[21];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=j&&!(!G||W===G)&&!Z,k;if(q[22]!==Y||q[23]!==j||q[24]!==K||q[25]!==T)k=m5.createElement(CM6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[22]=Y,q[23]=j,q[24]=K,q[25]=T,q[26]=k;else k=q[26];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.38# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[19]!==Y)N=b5.createElement(vh4,{addMargin:Y}),q[19]=Y,q[20]=N;else N=q[20];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=j&&!(!P||G===P)&&!Z,k;if(q[21]!==Y||q[22]!==j||q[23]!==K||q[24]!==T)k=b5.createElement(Mj6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[21]=Y,q[22]=j,q[23]=K,q[24]=T,q[25]=k;else k=q[25];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.37# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[19]!==Y)N=b5.createElement(Th4,{addMargin:Y}),q[19]=Y,q[20]=N;else N=q[20];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=j&&!(!P||G===P)&&!Z,k;if(q[21]!==Y||q[22]!==j||q[23]!==K||q[24]!==T)k=b5.createElement(jj6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[21]=Y,q[22]=j,q[23]=K,q[24]=T,q[25]=k;else k=q[25];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.36# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[19]!==Y)N=I5.createElement(oS4,{addMargin:Y}),q[19]=Y,q[20]=N;else N=q[20];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=M&&!(!P||G===P)&&!Z,k;if(q[21]!==Y||q[22]!==M||q[23]!==K||q[24]!==T)k=I5.createElement(sD6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[21]=Y,q[22]=M,q[23]=K,q[24]=T,q[25]=k;else k=q[25];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.34# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(q[19]!==Y)N=I5.createElement(aS4,{addMargin:Y}),q[19]=Y,q[20]=N;else N=q[20];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=M&&!(!P||G===P)&&!Z,k;if(q[21]!==Y||q[22]!==M||q[23]!==K||q[24]!==T)k=I5.createElement(iD6,{addMargin:Y,param:K,isTranscriptMode:!0,hideInTranscript:!1}),q[21]=Y,q[22]=M,q[23]=K,q[24]=T,q[25]=k;else k=q[25];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\{[\s\S]{0,600}isTranscriptMode:!0[\s\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.33# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let k;if(K[21]!==Y)k=H9.createElement(i6K,{addMargin:Y}),K[21]=Y,K[22]=k;else k=K[22];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let R=D&&!(!V||P===V)&&!T,b;if(K[23]!==Y||K[24]!==D||K[25]!==q||K[26]!==R||K[27]!==H)b=H9.createElement(Ej1,{addMargin:Y,param:q,isTranscriptMode:!0,verbose:H,hideInTranscript:!1}),K[23]=Y,K[24]=D,K[25]=q,K[26]=R,K[27]=H,K[28]=b;else b=K[28];return b}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\\{return[\\s\\S]{0,400}isTranscriptMode:!0[\\s\\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.20# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let E;if(K[21]!==Y)E=Y9.createElement(c8K,{addMargin:Y}),K[21]=Y,K[22]=E;else E=K[22];return E}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let R=D&&!(!V||P===V)&&!T,b;if(K[23]!==Y||K[24]!==D||K[25]!==q||K[26]!==R||K[27]!==H)b=Y9.createElement(iM1,{addMargin:Y,param:q,isTranscriptMode:!0,verbose:H,hideInTranscript:!1}),K[23]=Y,K[24]=D,K[25]=q,K[26]=R,K[27]=H,K[28]=b;else b=K[28];return b}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Identifiers vary across builds; use a regex search instead of exact strings:
rg -a -n -P 'case\"thinking\":\\{return[\\s\\S]{0,400}isTranscriptMode:!0[\\s\\S]{0,400}hideInTranscript:!1' \
~/.local/share/claude/versions/2.1.22# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let k;if(K[21]!==Y)k=H9.createElement(OU7,{addMargin:Y}),K[21]=Y,K[22]=k;else k=K[22];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let R=D&&!(!V||P===V)&&!T,x;if(K[23]!==Y||K[24]!==D||K[25]!==q||K[26]!==R||K[27]!==H)x=H9.createElement(oG1,{addMargin:Y,param:q,isTranscriptMode:!0,verbose:H,hideInTranscript:!1}),K[23]=Y,K[24]=D,K[25]=q,K[26]=R,K[27]=H,K[28]=x;else x=K[28];return x}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Use ripgrep's `-a` flag to search binary data:
rg -a -nF 'case"redacted_thinking":return t9.createElement(w_1,{addMargin:A});' \
~/.local/share/claude/versions/2.1.19
rg -a -nF 'case"thinking":{return t9.createElement(sFA,{addMargin:A,param:H,isTranscriptMode:!0,verbose:E,hideInTranscript:!1})}' \
~/.local/share/claude/versions/2.1.19# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let N;if(K[20]!==Y)N=Y9.createElement(aU7,{addMargin:Y}),K[20]=Y,K[21]=N;else N=K[21];return N}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=D&&!(!P||f===P),k;if(K[22]!==Y||K[23]!==D||K[24]!==q||K[25]!==T||K[26]!==H)k=Y9.createElement(YW1,{addMargin:Y,param:q,isTranscriptMode:!0,verbose:H,hideInTranscript:!1}),K[22]=Y,K[23]=D,K[24]=q,K[25]=T,K[26]=H,K[27]=k;else k=K[27];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Native/binary installs store the JS bundle inside the executable.
# Use ripgrep's `-a` flag to search binary data:
rg -a -nF 'case"redacted_thinking":return t9.createElement(j_1,{addMargin:A});' \
~/.local/share/claude/versions/2.1.17
rg -a -nF 'case"thinking":{return t9.createElement(FKA,{addMargin:A,param:H,isTranscriptMode:!0,verbose:E,hideInTranscript:!1})}' \
~/.local/share/claude/versions/2.1.17# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":{let f;if(K[20]!==Y)f=g3.createElement(wU7,{addMargin:Y}),K[20]=Y,K[21]=f;else f=K[21];return f}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{let T=D&&!(!V||P===V),k;if(K[22]!==Y||K[23]!==D||K[24]!==q||K[25]!==T||K[26]!==H)k=g3.createElement(k_1,{addMargin:Y,param:q,isTranscriptMode:!0,verbose:H,hideInTranscript:!1}),K[22]=Y,K[23]=D,K[24]=q,K[25]=T,K[26]=H,K[27]=k;else k=K[27];return k}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return q3.createElement(ru2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return q3.createElement(zkA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a zkA() that always returns the expanded renderer:
grep -nF 'function zkA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return L9A.default.createElement(j,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return N3.createElement(ju2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return N3.createElement(WkA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a WkA() that always returns the expanded renderer:
grep -nF 'function WkA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return z9A.default.createElement(j,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return N3.createElement(cu2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return N3.createElement(FkA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include an FkA() that always returns the expanded renderer:
grep -nF 'function FkA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return U9A.default.createElement(j,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return J5.createElement(X_2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return J5.createElement(dvA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a dvA() that always returns the expanded renderer:
grep -nF 'function dvA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return s4A.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return J5.createElement(Z_2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return J5.createElement(dvA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a dvA() that always returns the expanded renderer:
grep -nF 'function dvA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return s4A.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should NOT include the collapsed banner text:
grep -n '∴ Thinking (ctrl+o to expand)' ~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return o8.createElement(Vo2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return o8.createElement(ybA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a ybA() that always returns the expanded renderer:
grep -nF 'function ybA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return q6A.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should NOT include the collapsed banner text:
grep -n '∴ Thinking (ctrl+o to expand)' ~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include call sites that never short-circuit:
grep -nF 'case"redacted_thinking":return o8.createElement(ya2,{addMargin:Q});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
grep -nF 'case"thinking":{return o8.createElement(NbA,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z,hideInTranscript:!1})}' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include an NbA() that always returns the expanded renderer:
grep -nF 'function NbA({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G,hideInTranscript:Z=!1}){if(!A)return null;return $6A.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should NOT include the collapsed banner text:
grep -n '∴ Thinking (ctrl+o to expand)' ~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a thinking call site that always renders lo2():
grep -n 'case"thinking":return J5.createElement(lo2,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a lo2() that immediately returns the expanded renderer:
grep -n 'function lo2({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G}){if(!A)return null;return Vs.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should NOT include the collapsed banner text:
grep -n '∴ Thinking (ctrl+o to expand)' ~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a thinking call site that always renders co2():
grep -n 'case"thinking":return J5.createElement(co2,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:Z});' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include a co2() that immediately returns the expanded renderer:
grep -n 'function co2({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G}){if(!A)return null;return Vs.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Should NOT include the collapsed banner text:
grep -n '∴ Thinking (ctrl+o to expand)' ~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js
# Should include an mn2() that immediately returns the expanded renderer:
grep -n 'function mn2({param:{thinking:A},addMargin:Q=!1,isTranscriptMode:B,verbose:G}){if(!A)return null;return nr.default.createElement(T,{flexDirection:"column"' \
~/.nvs/node/*/*/lib/node_modules/@anthropic-ai/claude-code/cli.js# Check ZT2 patch
grep -n "function ZT2" ~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js
# Should show: function ZT2({streamMode:A}){return null}
# Check thinking visibility patch
grep -n 'case"thinking":return J3.createElement(X59' ~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js
# Should show: case"thinking":return J3.createElement(X59,{addMargin:Q,param:A,isTranscriptMode:!0,verbose:G});Cause: The script cannot locate your Claude Code installation.
The script will display all attempted detection methods and paths, for example:
❌ Error: Could not find Claude Code installation
Searched using the following methods:
[local installation]
- ~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js
- ~/.config/claude/local/node_modules/@anthropic-ai/claude-code/cli.js
[npm root -g]
- /opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/cli.js
[derived from process.execPath]
- /opt/homebrew/bin/../lib/node_modules/@anthropic-ai/claude-code/cli.js
[which claude]
- /opt/homebrew/bin/../lib/node_modules/@anthropic-ai/claude-code/cli.js
[native/binary default paths]
- ~/.local/bin/claude
- ~/.local/share/claude/versions/*
💡 Troubleshooting:
1. Verify Claude Code is installed: claude --version
2. For local install: Check ~/.claude/local or ~/.config/claude/local
3. For global install: Ensure "npm install -g @anthropic-ai/claude-code" succeeded
4. Check that npm is in your PATH if using global install
5. For native/binary install: Check ~/.local/bin/claude and ~/.local/share/claude/versions
Solutions:
- Verify installation: Run
claude --versionto confirm Claude Code is installed - For local installations: Check that cli.js exists in
~/.claude/localor~/.config/claude/local - For global installations:
- Ensure
npm install -g @anthropic-ai/claude-codecompleted successfully - Verify npm is in your PATH:
npm --version - If using NVM: Ensure you've activated the correct Node version
- Ensure
- Check file permissions: Ensure the script has read access to the installation directory
- For native/binary installations: Ensure
~/.local/binis on yourPATH, or run with--file ~/.local/bin/claude
Cause: This means:
- Claude Code has been updated to a newer version
- The patches are already applied
- The file structure has changed
Solution:
- Run
node patch-thinking.js --dry-runto check status - If already applied, you're good!
- If version changed, the patterns may need updating for the new version
Solution: You must restart Claude Code for changes to take effect.
The patch script creates a backup automatically on first run. The --restore command will fail if the backup doesn't exist.
The script works on:
- macOS ✅ Full support (all 4 detection methods)
- Linux ✅ Full support (all 4 detection methods)
- Windows ✅ Supported (3 detection methods - excludes
which claude)
macOS & Linux:
- All 4 detection methods available
- Includes
which claudebinary resolution - Automatic symlink resolution for Homebrew, NVM, etc.
Windows:
- Uses first 3 detection methods
- Works with nvm-windows and system Node
- Skips Unix-specific
whichcommand
Path detection is fully automatic using Node.js built-in modules.
The script automatically works with all Node.js version managers:
| Version Manager | Support | Notes |
|---|---|---|
| NVM (Node Version Manager) | ✅ Full | Detects via npm root -g |
| nodenv | ✅ Full | Detects via process.execPath |
| asdf | ✅ Full | Detects via npm root -g |
| nvm-windows | ✅ Full | Works with all 3 Windows methods |
| System Node | ✅ Full | Standard installation detection |
| Homebrew (macOS) | ✅ Full | Symlink resolution included |
How it works:
npm root -gdynamically finds the global node_modules directory regardless of version managerprocess.execPathderives the path from the current Node.js binary location- No hardcoded paths means it works with any Node setup
- cli.js: ~3,600+ lines, ~9+ MB (heavily minified)
- Version: Claude Code 2.0.46
- Patches: Non-invasive, minimal changes
The patcher uses a sophisticated detection system with multiple fallback methods:
// Priority 1: Local installations
~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js
~/.config/claude/local/node_modules/@anthropic-ai/claude-code/cli.js
// Priority 2: Global npm (dynamic)
$(npm root -g)/@anthropic-ai/claude-code/cli.js
// Priority 3: Derived from Node binary
$(dirname process.execPath)/../lib/node_modules/@anthropic-ai/claude-code/cli.js
// Priority 4: Unix binary resolution
$(which claude) → resolve symlinks → find cli.jsKey implementation details:
- Uses
child_process.execSync()with proper error handling - Automatically resolves symlinks via
fs.realpathSync() - Tracks all attempted paths for detailed error reporting
- Cross-platform compatible (Windows, macOS, Linux)
- ZT2 Function: Controls the UI banner shown after thinking completes
- Thinking Renderer: Controls whether the actual thinking text is displayed
Both must be patched because they're separate systems:
- Patching only ZT2 → Blank line appears where thinking should be
- Patching only the renderer → Banner still shows "ctrl+o to show"
The minified code patterns change with each Claude Code update:
| Version | Banner Function | Component | Variables |
|---|---|---|---|
| 2.0.9 | Mr2 |
S2B |
Various |
| 2.0.10 | br2 |
DOB |
H check |
| 2.0.11 | er2 |
SOB |
z check |
| 2.0.13 | hGB |
xlB |
K check |
| 2.0.14 | pGB |
dlB |
K check |
| 2.0.15 | KYB |
FpB |
K check |
| 2.0.19 | aFB |
NoB |
K check |
| 2.0.21 | wVB |
H8Q |
K,D check |
| 2.0.22 | YOB |
nNB |
K,D check |
| 2.0.24 | GSB |
nTB |
K,D check |
| 2.0.25 | YSB |
aTB |
K,D check |
| 2.0.26 | KjQ |
CTQ |
V check |
| 2.0.28 | RjQ |
LTQ |
V check |
| 2.0.29 | RjQ |
LTQ |
V check |
| 2.0.30 | GkQ |
sjQ |
V,I check |
| 2.0.31 | _kQ |
MSQ |
V,I check |
| 2.0.32 | wkQ |
ljQ |
V,I check |
| 2.0.37 | nR2 |
n$Q |
V,I check |
| 2.0.42 | cR2 |
xLQ |
V,I check |
| 2.0.46 | Et2 |
T32 |
K,Z check |
| 2.0.53 | hq2 |
o09 |
K,G check |
| 2.0.55 | nM2 |
J29 |
K,G check |
| 2.0.56 | CL2 |
b29 |
K,G check |
| 2.0.57 | HM2 |
K49 |
K,G check |
| 2.0.58 | SM2 |
k49 |
K,G check |
| 2.0.59 | DO2 |
F89 |
K,G check |
| 2.0.61 | RR2 |
T69 |
F,G check |
| 2.0.62 | ZT2 |
X59 |
F,G check |
When Claude Code updates, function names and component identifiers are regenerated during minification. In some cases (like v2.0.29), the patterns remain unchanged.
- Breaks on updates: Must re-run after
claude update - Minified code: Fragile, patterns may change with version updates
- No official config: This is a workaround until Anthropic adds a native setting
- Version-specific: Patterns are specific to v2.0.62
Consider requesting this as an official feature from Anthropic:
- Configuration option to always show thinking
- User preference in settings (
~/.claude/config.json) - Toggle command like
/thinking showor/thinking hide - Environment variable like
CLAUDE_SHOW_THINKING=true
Submit feedback: https://github.com/anthropics/claude-code/issues
If Claude Code updates and the patches stop working:
-
Locate the new patterns in cli.js:
- Search for the thinking banner function (look for "Thought for" text)
- Search for
∴ Thinking (ctrl+o to expand)to find the collapsed thinking renderer branch - Search for
case"thinking"to find the visibility check
-
Update the script with new patterns
-
Test thoroughly before committing
-
Update this README with the new version information
Pull requests welcome!
If Claude Code shows a completion notification like:
Background command "...very long multi-line command..." completed (exit code 0)
and the embedded command becomes extremely long, you can patch Claude Code so the completion notification no longer embeds the raw command text.
Apply the patch:
node patch-background-command-format.jsRe-verified on 2.1.76 / 2.1.77 / 2.1.78 / 2.1.79 / 2.1.80 / 2.1.83 / 2.1.84 / 2.1.85 / 2.1.86 / 2.1.87 / 2.1.88 / 2.1.89 / 2.1.90 / 2.1.91 / 2.1.92 / 2.1.94 / 2.1.96 / 2.1.97 / 2.1.98 / 2.1.101 / 2.1.104 / 2.1.105 / 2.1.107 / 2.1.108 / 2.1.109 / 2.1.110 / 2.1.111 / 2.1.112 / 2.1.113 / 2.1.114 / 2.1.116 / 2.1.117 / 2.1.118 / 2.1.119 / 2.1.120 / 2.1.121 / 2.1.122 / 2.1.123 / 2.1.126 / 2.1.128 / 2.1.129 / 2.1.131 / 2.1.132 / 2.1.133 / 2.1.136 / 2.1.137 / 2.1.138 / 2.1.139 / 2.1.140 / 2.1.141 / 2.1.142 / 2.1.143 / 2.1.144 / 2.1.145 / 2.1.146 / 2.1.147 / 2.1.148 / 2.1.149 / 2.1.150 / 2.1.152 / 2.1.153 / 2.1.154 / 2.1.156 / 2.1.157 / 2.1.158 / 2.1.160 / 2.1.161 / 2.1.162 / 2.1.163 / 2.1.165 / 2.1.166 / 2.1.167 / 2.1.168 / 2.1.169 / 2.1.170 / 2.1.172 / 2.1.173 / 2.1.174 / 2.1.175 / 2.1.176 / 2.1.177 / 2.1.178 / 2.1.179 / 2.1.181 / 2.1.182 / 2.1.183 / 2.1.185 / 2.1.186 / 2.1.187 / 2.1.190 / 2.1.191 / 2.1.193 / 2.1.195 / 2.1.196 / 2.1.197 / 2.1.198 / 2.1.199 / 2.1.200 / 2.1.201 / 2.1.202 / 2.1.203 / 2.1.204: the notification builder still emits the same three completion states (completed / failed / was stopped), but 2.1.77+ now constructs the shared Background command prefix via a minified variable before interpolating the raw command. The patch script handles both the old direct-string form and the newer prefix-variable form, for both npm and native installs, and patches duplicate embedded native bundles in one run. 2.1.184, 2.1.188, 2.1.189, 2.1.192, and 2.1.194 were not published on npm at verification time.
Options:
--dry-runpreview changes without applying them--restorerestore fromcli.js.backup--file /path/to/cli.jspatch a specific file
Current behavior after patching:
- removes the embedded raw command from the completion notification
- keeps the completion status such as
completed (exit code 0) - avoids huge multi-line notifications entirely
Supports:
- npm/local installs with patchable
cli.js - native/binary installs via length-preserving in-place patching
macOS note for native installs:
- patched native binaries may need ad-hoc
codesign; the script attempts this automatically
If Claude Code shows a waiting block like:
Task Output abc123
codeagent-wrapper --agent ... <<'EOF'
... many lines ...
EOF
Waiting for task (esc to give additional instructions)
the long multiline command is not the final task output. It is the task description rendered by the Task Output tool while it waits.
Apply the patch:
node patch-task-output-format.jsRe-verified on 2.1.80 / 2.1.83 / 2.1.84 / 2.1.85 / 2.1.86 / 2.1.87 / 2.1.88 / 2.1.89 / 2.1.90 / 2.1.91 / 2.1.92 / 2.1.94 / 2.1.96 / 2.1.97 / 2.1.98 / 2.1.101 / 2.1.104 / 2.1.105 / 2.1.107 / 2.1.108 / 2.1.109 / 2.1.110 / 2.1.111 / 2.1.112 / 2.1.113 / 2.1.114 / 2.1.116 / 2.1.117 / 2.1.118 / 2.1.119 / 2.1.120 / 2.1.121 / 2.1.122 / 2.1.123 / 2.1.126 / 2.1.128 / 2.1.129 / 2.1.131 / 2.1.132 / 2.1.133 / 2.1.136 / 2.1.137 / 2.1.138 / 2.1.139 / 2.1.140 / 2.1.141 / 2.1.142 / 2.1.143 / 2.1.144 / 2.1.145 / 2.1.146 / 2.1.147 / 2.1.148 / 2.1.149 / 2.1.150 / 2.1.152 / 2.1.153 / 2.1.154 / 2.1.156 / 2.1.157 / 2.1.158 / 2.1.160 / 2.1.161 / 2.1.162 / 2.1.163 / 2.1.165 / 2.1.166 / 2.1.167 / 2.1.168 / 2.1.169 / 2.1.170 / 2.1.172 / 2.1.173 / 2.1.174 / 2.1.175 / 2.1.176 / 2.1.177 / 2.1.178 / 2.1.179 / 2.1.181 / 2.1.182 / 2.1.183 / 2.1.185 / 2.1.186 / 2.1.187 / 2.1.190 / 2.1.191 / 2.1.193 / 2.1.195 / 2.1.196 / 2.1.197 / 2.1.198 / 2.1.199 / 2.1.200 / 2.1.201 / 2.1.202 / 2.1.203 / 2.1.204: the waiting-state UI still renders taskDescription verbatim inside renderToolUseProgressMessage, so removing just that description element is enough to keep the view compact. In 2.1.186 and later published versions, the method is emitted as renderToolUseProgressMessage(e){...} and the child element uses jsx/jsxs, so the script supports both that shape and the older createElement(...) shape. The actual task output, task state, and completion notifications are unchanged. 2.1.184, 2.1.188, 2.1.189, 2.1.192, and 2.1.194 were not published on npm at verification time.
Options:
--dry-runpreview changes without applying them--restorerestore fromcli.js.backup--file /path/to/cli.jspatch a specific file
Current behavior after patching:
- removes the extra raw task-description line above
Waiting for task - keeps the
Task Output <id>tag and theWaiting for task (esc to give additional instructions)status line - avoids huge multiline waiting blocks caused by wrapped commands or heredocs
Supports:
- npm/local installs with patchable
cli.js - native/binary installs via length-preserving in-place patching
macOS note for native installs:
- patched native binaries may need ad-hoc
codesign; the script attempts this automatically
Configure which AI models Claude Code uses for different subagent types (Plan, Explore, general-purpose).
By default, Claude Code hardcodes the models used by subagents:
- Plan subagent: Uses Sonnet (for planning tasks)
- Explore subagent: Uses Haiku (for code exploration)
- general-purpose subagent: Inherits from main loop model
You cannot change these defaults without modifying the source code.
This patch allows you to configure subagent models via a configuration file (~/.claude/subagent-models.json).
Current Version: Claude Code 2.0.46
# 1. Create configuration file
cat > ~/.claude/subagent-models.json <<EOF
{
"Plan": "sonnet",
"Explore": "sonnet",
"general-purpose": "sonnet"
}
EOF
# 2. Run the patch script
node patch-subagent-models.js
# 3. Restart Claude CodeCreate ~/.claude/subagent-models.json with your preferred models:
{
"Plan": "sonnet",
"Explore": "haiku",
"general-purpose": "sonnet"
}Valid model values:
"haiku"- Fast and efficient (Claude Haiku 4.5)"sonnet"- Balanced performance (Claude Sonnet 4.5)"opus"- Most capable (Claude Opus 4.1)
Subagent Types:
- Plan - Used in planning mode for breaking down tasks
- Explore - Used for codebase exploration and file searching
- general-purpose - Used for general multi-step tasks
# Apply patches
node patch-subagent-models.js
# Preview changes without applying
node patch-subagent-models.js --dry-run
# Restore original behavior
node patch-subagent-models.js --restore
# Patch a specific cli.js file or native claude binary (skip auto-detection)
node patch-subagent-models.js --file /path/to/cli.js
node patch-subagent-models.js --file /path/to/claude
# Show help
node patch-subagent-models.js --helpThe patch modifies Claude Code's cli.js to change the hardcoded model assignments:
Before (v2.0.37):
// Plan subagent
R3A={agentType:"Plan",...,model:"sonnet"}
// Explore subagent
model:"haiku"}});var R3A;After (with config: Plan="haiku", Explore="sonnet"):
// Plan subagent
R3A={agentType:"Plan",...,model:"haiku"}
// Explore subagent
model:"sonnet"}});var R3A;-
After Claude Code Updates: Must re-run after
claude update:node patch-subagent-models.js
-
Backup: Created automatically at:
~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js.subagent-models.backup -
Version-Specific: Patterns are specific to v2.0.37. May need updates for newer versions.
Using the script:
node patch-subagent-models.js --restoreManual restore:
cp ~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.js.subagent-models.backup \
~/.claude/local/node_modules/@anthropic-ai/claude-code/cli.jsUse Sonnet everywhere (avoid Haiku):
{
"Plan": "sonnet",
"Explore": "sonnet",
"general-purpose": "sonnet"
}Use Haiku for speed:
{
"Plan": "haiku",
"Explore": "haiku",
"general-purpose": "haiku"
}Balanced approach:
{
"Plan": "sonnet",
"Explore": "haiku",
"general-purpose": "sonnet"
}"No model configuration found"
- Create
~/.claude/subagent-models.jsonwith your desired configuration - Ensure the JSON syntax is valid
"Pattern not found"
- Claude Code version may have changed
- Run with
--dry-runto see which patterns are detected - Check if patches are already applied
Changes not taking effect
- Restart Claude Code after applying patches
- Verify patches were applied with
--dry-run
| Version | Plan Default | Explore Default | Notes |
|---|---|---|---|
| 2.0.31 | sonnet | haiku | Previous |
| 2.0.32 | sonnet | haiku | Previous |
| 2.0.37 | sonnet | haiku | Current |
This patch is provided as-is for educational purposes. Use at your own risk.
Developed through analysis of Claude Code's compiled JavaScript. Special thanks to the community for identifying the thinking display issue.
Last Updated: 2025-12-09 Claude Code Version: 2.0.62 Status: ✅ Working
# Install
node patch-thinking.js
# Preview
node patch-thinking.js --dry-run
# Restore
node patch-thinking.js --restore
# Help
node patch-thinking.js --help