claudswap
Switch Claude Code to any model — including the old ones /model doesn't show you.
Claude Code's built-in /model picker only lists the models Anthropic currently promotes. But the API supports every model your account has access to, and /model <exact-id> still works if you know the ID. claudswap bridges the gap: a /switch command that lists everything, resolves fuzzy aliases, and actually switches the running session.
Why reach for an older model? They aren't just cheaper or faster — they behave differently. If you tuned a prompt against a specific version, you're comparing behavior across versions, or you need to reproduce something a particular model did, "whatever is newest" is the wrong tool. The API keeps serving them; only the picker moved on.
The problem
Claude Code's live model is in-process state. No file, socket, or API can change it from outside — only the CLI's own /model command, dispatched through stdin. Most terminals have no way to programmatically type into their own input. The kernel mechanism that used to allow this (TIOCSTI) is dead since Linux 6.2.
The solution
claudswap is a transparent pty wrapper. It runs claude under a pseudo-terminal and exposes a FIFO. Anything inside the session can inject input by writing to the FIFO. The terminal is out of the equation — it works in VS Code, GNOME Terminal, Windows Terminal, Terminal.app, Alacritty, bare SSH, everywhere ptys exist.
For tmux, screen, and zellij users, /switch works without the wrapper — their APIs can target their own pane. claudswap is the universal path for everything else.
Install
pip install claudswap
claudswap install
pip install gives you the claudswap wrapper. claudswap install writes the /switch slash command and its backend into ~/.claude/ — run it once. (pip can't do that step itself; post-install hooks are unreliable and effectively deprecated.)
From source, without pip
git clone https://github.com/brandonrthomas/claudswap.git
cd claudswap
bash install.sh
Either route puts:
claudswapin~/.local/bin/switch-model.shin~/.claude/scripts//switchslash command in~/.claude/commands/
Usage
Start a session with claudswap
claudswap # same as: claude
claudswap -c # same as: claude -c (resume)
claudswap --model opus # same as: claude --model opus
claudswap --run bash # wrap any command, not just claude
Or make it the default:
# add to .bashrc / .zshrc
alias claude=claudswap
/switch — list models
Type /switch with no argument inside a Claude Code session. Example output — the real list is fetched live from the API, so yours will differ:
# alias name released
── Fable ─────────────────────────────────────
1 fable Claude Fable 5 2025-12-12
── Opus ──────────────────────────────────────
2 opus Claude Opus 5 2026-05-22
3 opus-4.8 Claude Opus 4.8 2026-03-24
4 opus-4.7 Claude Opus 4.7 2026-02-24
5 opus-4.6 Claude Opus 4.6 2025-10-14 ← current
...
── Sonnet ────────────────────────────────────
...
── Haiku ─────────────────────────────────────
...
Numbers and aliases auto-update when Anthropic adds new models.
/switch — switch models
/switch 2 → switches to model #2
/switch opus → switches to newest Opus
/switch haiku → switches to newest Haiku
/switch opus 4.7 → switches to Opus 4.7
The switch fires the moment Claude's current turn ends.
How it works
-
claudswap allocates a pty, runs
claudeon it, and mirrors I/O in raw mode (window resizes, signals, exit status — all transparent). It also opens a per-session FIFO at$CLAUDSWAP_FIFO. -
/switch fetches the full model list from
GET /v1/modelsusing the Claude Code OAuth token, resolves the user's input (number, alias, substring), and writes/model <resolved-id>\rto the FIFO. -
Claude Code sees
/model ...as typed input, queued during the current turn. When the turn ends, it executes — switching the live model.
Injection backends
| Backend | When it's used | Needs claudswap? |
|---|---|---|
| claudswap | $CLAUDSWAP_PID in process ancestry |
Yes |
| tmux | tmux in process ancestry |
No |
| screen | screen in process ancestry |
No |
| zellij | zellij in process ancestry |
No |
| (manual) | Everything else | Prints /model command for you |
Backend detection walks the process tree (not env vars — those get inherited across terminal boundaries and cause mis-targeting). The nearest multiplexer or wrapper wins.
Credentials
/switch reads your Claude Code OAuth token from ~/.claude/.credentials.json in order to call GET /v1/models. It is sent only to api.anthropic.com over HTTPS — the same endpoint Claude Code itself uses, and the only host this project contacts.
The token is never printed, logged, or written to disk, and it is never placed in a command line. Passing a credential as a process argument would expose it through /proc/<pid>/cmdline, which any process running as you — and root — can read for the duration of the call. Instead it is piped to curl on stdin via --config -. The claudswap wrapper never touches the token at all; it only moves bytes between your terminal and the pty.
Requirements
- Python 3.9+ (the pty wrapper is standard library only — no runtime dependencies)
jqandcurl(for the API call)- Claude Code with an active OAuth session (
~/.claude/.credentials.json)
Authors
- Brandon Thomas — author
- Claude — co-author (written with Claude Code)
License
Apache-2.0 © 2026 Brandon Thomas
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claudswap-0.1.1.tar.gz.
File metadata
- Download URL: claudswap-0.1.1.tar.gz
- Upload date:
- Size: 16.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b39be3d0c782bbe234b6ee1373495738226aa2b3fccb9d9b9e5d884d99d662d2
|
|
| MD5 |
5e7f8de593413767939ff1d754353696
|
|
| BLAKE2b-256 |
384119a37873b707bb7f69726f8213c1ff114104c516db4d846b583244c9f947
|
Provenance
The following attestation bundles were made for claudswap-0.1.1.tar.gz:
Publisher:
publish.yaml on brandonrthomas/claudswap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claudswap-0.1.1.tar.gz -
Subject digest:
b39be3d0c782bbe234b6ee1373495738226aa2b3fccb9d9b9e5d884d99d662d2 - Sigstore transparency entry: 2377471984
- Sigstore integration time:
-
Permalink:
brandonrthomas/claudswap@c87739494f556c4a34c2dfb674d34e0e101299ee -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/brandonrthomas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@c87739494f556c4a34c2dfb674d34e0e101299ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file claudswap-0.1.1-py3-none-any.whl.
File metadata
- Download URL: claudswap-0.1.1-py3-none-any.whl
- Upload date:
- Size: 17.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dfa15cb72f373b05770b21d11545c34750fadc8fd353bc1e6311059e8f3d2e8b
|
|
| MD5 |
fd3fa30280483f33e27fe92d52b1a4f0
|
|
| BLAKE2b-256 |
2e42d99e1226fdd14a8b97a600214621f322efe7d9951f33578226a8ee8c399d
|
Provenance
The following attestation bundles were made for claudswap-0.1.1-py3-none-any.whl:
Publisher:
publish.yaml on brandonrthomas/claudswap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claudswap-0.1.1-py3-none-any.whl -
Subject digest:
dfa15cb72f373b05770b21d11545c34750fadc8fd353bc1e6311059e8f3d2e8b - Sigstore transparency entry: 2377472079
- Sigstore integration time:
-
Permalink:
brandonrthomas/claudswap@c87739494f556c4a34c2dfb674d34e0e101299ee -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/brandonrthomas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@c87739494f556c4a34c2dfb674d34e0e101299ee -
Trigger Event:
push
-
Statement type: