Surgically excise a topic from a Claude Code session's context —
keep what you need, cut out the middle you don't.
bisturi is Brazilian Portuguese for scalpel — and that's the whole idea. A
Bubble Tea TUI to pick the blocks, safe re-threading so the trimmed session still
resumes, and a local surgery log so any cut can be undone later. Not a blunt
/clear, not a lossy /compact — a clean cut of a specific span.
You start on topic A, then B comes up related to A, and now you want to work on C — but B is dead weight bloating the context. You want B gone while A and C stay intact.
The built-ins don't do this:
| Built-in | What it does | Why it's not this |
|---|---|---|
/clear |
wipes the whole context | loses A and C too |
/compact |
LLM-summarizes everything | lossy; you can't choose what drops |
/rewind (Esc·Esc) |
rolls back to a checkpoint | linear — to drop B it also drops C |
Rewind moves one pointer back in time; it can't remove a span from the middle and keep what came after. That middle-excision is the gap bisturi fills.
Pick the blocks in the TUI — each block is one prompt plus its full reply, shown with a token weight so you know what's heavy:
Press d to preview the exact diff before committing — what's removed, what's
kept, and the token delta:
Press y in the diff to apply. It writes straight to the session file, keeping
a .bak-* backup and a restorable surgery:
A real session bloated by reading a 1,000-line CSV. Cutting the CSV blocks and restarting the session took it from 21% of the window down to 4% — messages dropped from 185.3k to 15.6k tokens:
| Before the cut | After the cut + restart |
|---|---|
![]() |
![]() |
The drop only lands after you restart Claude Code on that session — a running session holds its context in memory and reloads the trimmed transcript on
claude --resume. bisturi reminds you of this when you apply.
A session lives at ~/.claude/projects/<slugged-cwd>/<session-id>.jsonl; each
line is one JSON object, and message objects are threaded by uuid/parentUuid.
Real sessions aren't a clean line — parallel tool calls, retries, sidechains and
compaction make the thread a forest (many roots and leaf tips). So bisturi
doesn't try to reverse-engineer one canonical path. It treats the file as what it
is — a chronological append log — and:
- Groups it into turns: one real user prompt plus its attachments, tool results, assistant replies and metadata, up to the next prompt. Injected prompts (hook feedback, skill preambles) fold into their surrounding turn, so you select whole topics.
- Removes the turns you pick and relinks the survivors into one clean linear
chain — each surviving node points at the previous survivor. The result is
always single-rooted, fully reachable, and free of dangling references,
whatever the original shape, and it resumes whether Claude Code walks
parentUuidfrom the leaf or reads the log in order. - Saves the cut as a surgery you can undo — even after the session has grown with new turns (anchors are matched by uuid, so later additions don't interfere).
Prebuilt binary — grab the archive for your OS/arch from the
latest release, extract,
and put bisturi on your PATH:
# macOS (Apple Silicon) example — adjust the asset name for your platform
curl -sL https://github.com/GuitarWag/bisturi/releases/latest/download/bisturi_<version>_darwin_arm64.tar.gz | tar xz
sudo mv bisturi /usr/local/bin/With Go (1.24+):
go install github.com/GuitarWag/bisturi@latestFrom source:
git clone https://github.com/GuitarWag/bisturi && cd bisturi
go build -o bisturi .
ln -sf "$PWD/bisturi" ~/.local/bin/bisturi # optionalReleases are built for linux / macOS / windows on amd64 and arm64 by GoReleaser
via GitHub Actions on each v* tag. Check your build with bisturi --version.
bisturi # pick a session interactively (searchable picker), then TUI
bisturi -s 353 # match by the /rename name (what `claude --resume` shows)
bisturi -s "connection" # …or by session id / ai-title (substring)
bisturi -a # pick across ALL projects, not just the cwd's
bisturi --project ~/code/app # sessions for another project
bisturi path/to/session.jsonl # operate on a file directly
bisturi --list # list sessions (id, rename name, ai-title)Run bisturi from any folder: with no session named, it opens a searchable
picker. Type to filter by rename name, ai-title, or id; enter opens the block
TUI for that session. If the current folder has no sessions of its own, the
picker spans all projects. -s matches the rename name first — the same
name you use with claude --resume.
Inspect and cut without the TUI:
bisturi -s slack --print # numbered turn breakdown + token estimates
bisturi -s slack --json # same, as JSON (for scripts / the slash command)
bisturi FILE --cut 2,4 --dry-run # show what would change, write nothing
bisturi FILE --cut 2-4 # writes FILE.cut.jsonl (original untouched)
bisturi FILE --cut 2 --in-place # replace original, keep a .bak-* backup
bisturi FILE --cut 2 --compact # replace the block with an LLM summary instead of deleting
bisturi -s NAME --suggest # ask claude which blocks are safe to compact, print the command--compact (optional) pipes the selected blocks to claude -p and splices the
summary back in as a compact-summary message — keeps topic B's gist while
reclaiming most of its tokens. Lossy and needs the claude CLI; hard cut is the
default. The originals are still saved, so --restore brings back the real
content and drops the summary.
Undo:
bisturi --surgeries # list saved cuts (undo history)
bisturi --restore <id> # put a cut's blocks back (backup kept)Restore is idempotent — it refuses to run if the blocks are already present, so it can never duplicate transcript content.
| Key | Action |
|---|---|
↑/↓ or k/j |
move between blocks |
space / x |
mark/unmark a block for cutting |
a / n |
select all / none |
enter |
expand the block (scroll its full interaction) |
s |
ask claude which blocks are safe to compact, and pre-select them |
d / y |
diff preview (what's removed, token delta, before→after) |
y (in the diff) |
apply the cut |
q / esc |
quit without changing anything |
A slash command drives this from within a session. A slash command can't host a
full-screen TUI itself (the agent's shell has no interactive terminal), so
/bisturi gives you two ways to see and confirm the blocks:
- Visual TUI — it hands you
!bisturi -s <name>. The!prefix runs it in your real terminal, so the checkbox TUI opens right there; its result prints back into the chat. - In-chat — Claude lists the numbered blocks and confirms your selection with Claude Code's native selectable UI, then shows a dry-run before writing.
Note: you can't hot-edit the currently running session — Claude Code owns that
file while live. Cut a past session, or cut the current one and pick up the
trimmed context on the next claude --resume.
- The original is never touched unless you pass
--in-place, and even then a.bak-<timestamp>copy is written first. - Every cut is also saved as a restorable surgery under
~/.claude/bisturi/surgeries/. - Writes are atomic (temp file + rename).
- Tests assert the cut chain is single-rooted, fully reachable, and dangling-free, and that a cut survives a restore even after the session grew.
- Relinking collapses abandoned branches (retries, dead tool calls) into the linear order. That's faithful to what happened and keeps the context complete; it isn't a byte-for-byte copy of the original tree.
- Token counts are estimates (~4 chars/token), for relative sizing, not billing.
- Close the session in Claude Code before cutting it in place.
go test ./...




