Pinning Claude Code Developer Olaf Alders pinned his Claude Code to Opus 4.8, citing that Opus 5 feels worse in some ways, and shared a script that forces environment variables via Claude's config to disable auto-updates while re-enabling plugin updates. Alders' config sets the model to claude-opus-4-8 and excludes Fable due to high credit consumption and concerns about foreign government influence. Pinning Claude Code Earlier today I saw this post from Curtis Poe https://github.com/ovid . Just yesterday I pinned my Claude Code to Opus 4.8 for similar reasons. Opus 5 doesn’t seem to be a clear improvement over 4.8 and, in some ways, it just feels worse. I can’t provide you with benchmarks to prove it, so this is mostly hand waving, but I feel like the results I’m getting are worse, more verbose, wider in scope and sometimes just mystifying. It’s taking longer to do basic things. I’m happy to switch back to 4.8 for as long as it’s available. Newer does not automatically mean better. If you’ve ever released your own software, you likely know this to be true. Curtis’ post contains a quick workaround for this, but I do something different, so I figured I’d show that off. And when I say that I do something different, it’s just a script that Claude wrote for me. Claude, however, did not write this post. A few weeks ago, I wrote about being bitten by a Claude upgrade Easter Egg: Claude Code: Anatomy of a Misfeature /2026/07/17/claude-code-anatomy-of-a-misfeature/ . I was pleased to later read an article by Mauricio Patiño Cervantes https://mauroepce.dev/blog/trust-boundaries-claude-code which referenced my piece. I was also happy to see that this article was advocating for a way of managing Claude’s defaults that is similar to mine. on-the-joys-of-pinning On the Joys of Pinning Photo: Safety Pin https://commons.wikimedia.org/wiki/File:Safety Pin.jpg by Haragayato https://commons.wikimedia.org/wiki/User:Haragayato , licensed under CC BY-SA 3.0 https://creativecommons.org/licenses/by-sa/3.0/ . I’ve come to the conclusion that I prefer boring upgrades when it comes to Claude Code, so I’ve been pumping the brakes on the YOLO mode that it defaults to. There is more than one way to do this, but I wanted something that would instantly stick across all of my new sessions without requiring me to do much, since I’m against busy work. It turns out you can force environment variables via Claude’s config. That allows me to have env vars propagate instantly to new Claude sessions without personally having to update the env in all of my far too many tmux sessions. So, I end up with a config that looks something like this truncated version: { "env": { "DISABLE AUTOUPDATER": "1", "FORCE AUTOUPDATE PLUGINS": "1" }, "model": "claude-opus-4-8", "availableModels": "claude-opus-4-8", "opus", "sonnet", "haiku" } The highlights here are: DISABLE AUTOUPDATER stops Claude from happily updating itself in the background, but it also stops plugins from doing the same. I have a higher risk tolerance for plugins, so I re-enable that behaviour via FORCE AUTOUPDATE PLUGINS . I then choose a default model via model and create a list of models I’d generally like to choose from. You’ll note that Fable is missing from that list because the last time I ran /model fable the only thing I saw was a lot of credits go up in smoke. I think what I do is just not complex enough to need Fable and I’m not super jazzed about things that can get turned on and off on the whims of a foreign government. So that gives me the pin that goes back to Opus 4.8, but I’m not doing this by hand. I have too many places where my dot-files https://github.com/oalders/dot-files live, so I want this to be scriptable and idempotent. I give you my config and caveat emptor the LLM-generated portion of tonight’s entertainment. It currently lives in my dot-files: configure/claude-settings.sh https://github.com/oalders/dot-files/blob/main/configure/claude-settings.sh . Contains LLM-generated content not written by Olaf bash /usr/bin/env bash Force host-level Claude Code settings that must not live in this repo. ~/.claude/settings.json is deliberately untracked it holds the plugin list and marketplace config , so we merge individual keys into whatever is already there rather than symlinking or overwriting the file. bin/nn sets the same env vars for nono-sandboxed sessions. Setting them here covers plain claude runs, which never go through bin/nn. set -eu -o pipefail SETTINGS="$HOME/.claude/settings.json" mkdir -p "$ dirname "$SETTINGS" " if -f $SETTINGS ; then echo '{}' "$SETTINGS" fi set env key { local key=$1 value=$2 if jq -e --arg k "$key" --arg v "$value" '.env $k == $v' "$SETTINGS" /dev/null; then return fi jq --arg k "$key" --arg v "$value" '.env $k = $v' "$SETTINGS" "$SETTINGS.tmp" mv "$SETTINGS.tmp" "$SETTINGS" echo "set env.$key=$value in $SETTINGS" } Like set env key, but for a top-level key whose value is raw JSON bool, number, string, object rather than a string env var. set key { local key=$1 value=$2 if jq -e --arg k "$key" --argjson v "$value" '. $k == $v' "$SETTINGS" /dev/null; then return fi jq --arg k "$key" --argjson v "$value" '. $k = $v' "$SETTINGS" "$SETTINGS.tmp" mv "$SETTINGS.tmp" "$SETTINGS" echo "set $key=$value in $SETTINGS" } Pin the claude binary; installer/claude.sh owns which version we land on. set env key DISABLE AUTOUPDATER 1 ...but keep plugins updating, which DISABLE AUTOUPDATER would otherwise freeze alongside the CLI. set env key FORCE AUTOUPDATE PLUGINS 1 Compact automatically instead of needing a manual /compact. Compaction fires at window-33k 20k reserved for output, 13k buffer , and the window itself is clamped to the model max -- so on a 200k model anything above 200000 is a no-op, and anything below just compacts sooner for no saving. 200000 is the max useful value; it also keeps the clamp meaningful if 1M context is ever re-enabled above. set key autoCompactEnabled true set key autoCompactWindow 200000 Stay on 200k-class context instead of the native 1M window some models e.g. Sonnet 5 offer. Long context is rarely worth the spend here, and a hard ceiling keeps sessions focused. This is the setting that actually caps token spend -- autoCompactWindow above only moves when compaction fires. set env key CLAUDE CODE DISABLE 1M CONTEXT 1 Cap concurrently-running subagents so one message can't fan out unbounded background agents. Added in claude 2.1.217, where it defaults to 20; inert on older versions. DISABLE AUTOUPDATER above means installer/claude.sh decides when we actually land on a version that reads this. set env key CLAUDE CODE MAX CONCURRENT SUBAGENTS 5 Allowlist the models offered by /model, --model, ANTHROPIC MODEL and resume, which keeps Fable out of the picker. Experimental: unverified whether this key is honored; harmless if ignored since it only narrows an allowlist. The pinned opus id below is listed explicitly so it matches the allowlist exactly rather than relying on the "opus" family alias, which resolves to the newest Opus. set key availableModels ' "claude-opus-4-8","opus","sonnet","haiku" ' Default new sessions to Opus 4.8 rather than whatever the "opus" alias points at today Opus 5 . /model overwrites this in ~/.claude/settings.json for the session; --model and ANTHROPIC MODEL override for a single run. set key model '"claude-opus-4-8"' Default new sessions to medium reasoning effort to trim thinking-token spend. /effort overwrites this in ~/.claude/settings.json; --effort and CLAUDE CODE EFFORT LEVEL override for a single session. Accepts low/medium/high/xhigh no "max" . set key effortLevel '"medium"' So far this has worked quite well for me. I can now upgrade Claude Code on my own schedule and tweak config settings in various environments without having to do anything other than run my dot-files installer.