ThinWindow
Less in the window. Don't pay for it twice. ThinWindow keeps Claude Code's context window thin from the first prompt to the next morning. It trims oversized reads and logs while you work, shows what every request carries, and when you come back to an expired session, offers a fresh start from a short brief instead of paying for the old context again. Listed in the official Claude Code plugin directory.
01Overview
ThinWindow is a small, local plugin for Claude Code, and an Agent Skill for other agents. It works at the four moments of a session:
Start setup
Shows what every request carries, once a week per project, and offers an opt-in profile with fewer built-in tools.
During guards
Short rules, and hooks that trim oversized reads, logs and searches before they enter the context.
Between sessions resume
Keeps a brief of each session, and before you re-pay an expired one, offers a fresh start from it.
After report
Shows where your own sessions' context went, from the transcripts on your machine.
Who it is for: people who run Claude Code for hours on real repositories, and pay for it in money or in usage limits.
What it is not: a model, a proxy, a service or a memory system. Nothing is hosted, nothing is sent anywhere, and it changes no setting on its own.
02Why context is the bill
A coding agent pays for what it carries more than for what it writes.
- Every request re-sends the whole session. Each file Claude reads, each log it prints and each long answer stays in the conversation, and is paid again, from the prompt cache, on every request after it.
- An expired session gets paid for twice. Claude Code keeps a session's prompt cache for up to an hour. Come back later, and your next prompt writes the whole context again at the cache-write price, many times what reading it from the cache costs.
- Your setup rides on every request. The system prompt, the tool definitions, the skill and agent listings, MCP instructions and CLAUDE.md files go out with each one.
03Start: know what every request carries
The setup-cost notice
Once a week per project, when a session's first request is 40k tokens or more, ThinWindow shows you one line: what every request in that session starts at, and its largest parts. It's shown to you and never sent to Claude. In the desktop app it appears as a collapsed "Claude Code notice". Example:
ThinWindow: each request in this session starts at 54k tokens (skill listing 5.3k, deferred tools 2.5k, MCP instructions 1.6k). Run /context to see what you could turn off.
thinwindow-minimal, an opt-in profile
One file you copy, for focused coding sessions. It keeps Claude Code's own system prompt and your MCP tools, and removes the built-in tools the maintainer's sessions almost never used: subagents and agent teams; /loop, scheduled tasks, remote triggers and push notifications; background-task tools (background Bash commands still run); reading the task list back; worktrees, notebooks and multiple-choice questions; plan mode entered by Claude (Shift+Tab still works); the Skill tool and its listing (skills you type still run); and, in the desktop app, artifacts, design sync, file cards, feedback and review findings.
curl -fsSL --create-dirs -o ~/.claude/agents/thinwindow-minimal.md https://raw.githubusercontent.com/thinwindow/thinwindow/main/profiles/thinwindow-minimal.md
claude --agent thinwindow-minimal
Or, for every session in a project, "agent": "thinwindow-minimal" in that project's .claude/settings.json. ThinWindow never turns it on for you. Skip it when you want subagents, /loop, scheduled tasks or skills Claude starts on its own. While the file is in ~/.claude/agents/, sessions that don't use it list it among your subagents, one line with its tool list; delete the file to remove it.
04During: keep the window thin while you work
The rules tell Claude what to do. The guards make sure the expensive part happens, because a rule the agent can forget under pressure is not a rule. They act on the tool call itself, before its result reaches the context, so enforcing them costs no extra turn.
The rules
This is the complete text added to Claude's context at session start, from rules/thinwindow.md. The Agent Skill, the AGENTS.md snippet and this page carry the same copy, and CI checks that they stay in sync. The rules stay under 2,000 characters.
# thinwindow: spend fewer tokens
Everything you read or write stays in context and is re-sent on every later turn. Read, write and say only what the task needs.
Read less
- Locate before reading: grep or glob for the symbol, then read only the range around it.
- Don't read whole files over ~300 lines. Don't re-read what is already in context unless it changed.
- Batch independent lookups into one call. Stop exploring once you have enough to act.
- To count, search or summarize across many files, run one command that prints only the answer.
- Don't send a subagent to explore what one grep answers.
Print less
- Cap command output: quiet flags, `| tail -n 40`, `--max-count`, `git diff --stat`, `git log -n 10 --oneline`, or `thinwindow-run <cmd>` for installs, builds and tests.
Write less
- Before adding code, check that it needs to exist and that the codebase, standard library or platform doesn't already do it. Then make the smallest change that works.
- Never cut validation, error handling, security or tests to save lines.
- Don't add comments or docstrings that restate the code.
Say less
- Don't narrate between tool calls; just make the next call.
- End with at most three lines: what changed and where. No preamble, no restating the task, no step-by-step recap unless asked.
- Cite `file:line` instead of pasting code back.
The workflow of one tool call
Session start
The SessionStart hook adds the rules to the agent's context. After a compaction or /clear, it also forgets which files were read, because that content is gone from the context.
The agent decides on a tool call
A Read of a file, a Bash command, or a Grep search.
ThinWindow's PreToolUse hook inspects it
Locally, in a Node script, with no network access. It ends in one of three outcomes:
The result enters the context
Smaller than it would have been, and therefore cheaper on every turn that follows.
Guards reference
Every threshold below is configurable; see Configuration.
SessionStart
On startup, resume, clear, compact and fork: adds rules/thinwindow.md to the context. On compact and clear, it also resets read tracking, because that content is gone from the context. On startup, it also removes state files and briefs older than 7 days.
PreToolUse · Read
| Guard | When | What happens |
|---|---|---|
| Large file | No offset/limit, and the file has more than 400 lines | The Read returns the first 120 lines plus a line-numbered outline of the file's classes, functions and headings, so the next read can target a range. With "rewrite": false, it is refused with the line count and a grep-plus-range suggestion. |
| Re-read | Same file and range, read earlier by the same agent, with the same mtime and size | Refused as "already in context". The main conversation and each subagent are tracked separately. |
| Soft block | The exact refused call is repeated within ten minutes | Goes through. |
Images, PDFs, notebooks, binary files and missing paths are left alone. Ranged reads count for Claude Code's read-before-edit check.
PreToolUse · Bash
| Category | Examples | What happens |
|---|---|---|
| Noisy commands | install, build, test and lint for npm, pnpm, yarn, bun, pip, uv, poetry, pytest, cargo, go, gradle, maven, dotnet, make and more | Run through thinwindow-run automatically, unless already capped by a pipe, a redirect, a quiet flag or thinwindow-run. Background commands are left alone. With "rewrite": false, a soft block. |
| Unbounded scope | Recursive grep/rg/ag over the whole tree with no cap or exclude; a bare git diff | Fixed in place: the search is limited to its first 100 lines (grep also skips node_modules, .git, dist, build), and git diff runs as git diff --stat. With "rewrite": false, a soft block. |
| Anti-patterns | cat (or bat, less, more, nl, tac) of a big, lock, minified or binary file; git log without -n, a range or --since; ls -R; tree without -L; find from the repo root without -maxdepth | Refused, with a cheaper replacement. Output piped into head, tail, grep, wc and similar, or redirected to a file, counts as capped and is not blocked. |
PreToolUse · Grep
A content search (output_mode: "content") with no head_limit gets head_limit: 100. File-list and count searches are left alone.
thinwindow-run
Runs a command and keeps its full stdout and stderr in a log under the OS temp directory, never inside your repository. It prints the exit code and duration, then:
- on success, the last 10 lines;
- on failure, the last 40 lines plus earlier error-like lines (error, fail, warn, panic, exception), deduplicated;
- and the path of the full log, so the agent can read exactly the part it needs.
When nothing would be cut (10 lines or fewer on success, 40 on failure), the output comes back as it is, with the exit code if the command failed. The command's exit code is preserved.
Stop
At the end of every turn: updates the session's brief from what the transcript gained since the last turn (at most 4 MB per turn, plus git status after a turn that could have changed files), then shows the setup-cost notice when one is due. Each part fails open on its own.
UserPromptSubmit
Before each prompt you send: the cold-resume notice. It reads the last 256 KB of the transcript for the last request's time, context size and model, and holds the prompt once per idle gap when the session was idle for over an hour with at least coldResumeMinTokens tokens of context. It acts only in sessions a person attends, and never on commands or on prompts Claude Code writes itself.
State, logs and briefs
Read tracking and the hooks' counts live in one small file per session in <os temp dir>/thinwindow/state/, with one tiny file per project for the setup-cost notice. thinwindow-run logs go to <os temp dir>/thinwindow/logs/, and briefs to the plugin's data folder. ThinWindow removes them once they're 7 days old, the next time it runs. Nothing is written inside your repository, and nothing is sent anywhere.
What Claude gets back
What the agent asks for, and what it gets with ThinWindow installed. All of these are default behaviours of the plugin.
thinwindow-run npm test. If the tests pass, the agent sees the exit code, the duration and 10 lines. If they fail, it sees the last 40 lines, the error lines, and where the full log is.node_modules, .git, dist and build.git diff --stat; the agent can then diff the one path it cares about.Design principles
- Fails open. If a hook errors for any reason, the tool call or the prompt proceeds. ThinWindow must never block someone's work because of its own bug.
- Can't get stuck. Repeating a refused
Read, or a refused noisy or unbounded command, within ten minutes lets it through. The commands that are always refused come with a cheaper replacement that works. - Never approves anything. ThinWindow never returns an
allowdecision, so it can't approve a call your permission settings would have asked about. A rewritten command still goes through your permission rules. - Its own footprint is budgeted. The rules stay under 2,000 characters, and CI fails otherwise. The commands you type add nothing to the skill listing Claude sees.
- Never phones home. No telemetry, no analytics, no update or license checks.
05Between sessions: resume without paying twice
The brief
At the end of every turn, ThinWindow keeps a short brief of the session up to date, without calling a model: the goal, your last requests, the files changed, the last commands with their exit codes, and Claude's last reply. A session that never uses the brief gains no tokens from it.
The cold-resume notice
You send a prompt to a session that has been idle for over an hour with at least 100k tokens of context. ThinWindow holds it once and shows what continuing re-writes, in tokens and in US$ at the model's list price, next to a fresh start. You decide every time: send the prompt again to continue. Commands are never held, and neither are prompts in -p, SDK or background sessions. In the desktop app the notice is an "A hook blocked your prompt" card, with "Edit prompt" to send it again. Example:
ThinWindow held this message: this session has been idle 9 h, so its prompt cache has expired.
Continuing re-writes ~427k tokens (~US$3.42 at Opus 5.5 list price): send it again.
A fresh start from a short brief re-writes ~55k tokens (~US$0.44): /clear, then /thinwindow:resume <your request>.
/thinwindow:resume
After /clear, it starts the new session from this project's newest brief, up to 48 hours old, optionally followed by your next request. The brief is at most 600 characters, marked as reference for Claude to check against git status, and comes with its age, the commits made since and the path to the full brief.
/thinwindow:brief
Before you step away, Claude writes a five-line handoff while the cache is still warm: what's done, where it stopped, the decisions, what didn't work, and the next step. ThinWindow keeps it in the brief.
Claude Code shows its own dialog when you --resume a large session after about an hour (Pro and Max plans). ThinWindow also covers sessions you left open, shows what continuing costs before you pay it, and keeps a brief for any later /clear.
06After: see where your context went
/thinwindow:report reads the transcripts of your own Claude Code sessions on this machine and prints, on one screen:
- how much context each request re-sends, on average and in your longest sessions;
- how often a session was re-written after its cache expired, at what size, and what those re-writes cost at list price;
- what a session's first request carries, and its largest parts;
- whose tool output is re-sent most, and in what sizes;
- what ThinWindow did in the last 7 days.
The amounts are what's at stake in your own sessions, not what ThinWindow saved. On a subscription, read US$ as a relative size. /thinwindow:report --json prints a short summary without US$ amounts; you can share it in #43 if you want to. Nothing is collected automatically.
07Install
From the plugin directory
In the Claude desktop app, Customize → Plugins → Discover → ThinWindow. In Claude Code, /plugin → Discover → ThinWindow, or:
claude plugin install thinwindow@anthropic-plugin-directory
From the repository, in Claude Code
/plugin marketplace add thinwindow/thinwindow
/plugin install thinwindow@thinwindow
Any agent with Agent Skills
Codex, Cursor, Copilot, Gemini CLI, OpenCode and other agents that support the Agent Skills standard get the rules, thinwindow-run and the report script.
npx skills add thinwindow/thinwindow
Agents that read AGENTS.md
Paste adapters/AGENTS.md into your project's AGENTS.md, or into whichever instructions file your agent loads.
Turning it off
Set THINWINDOW=off in the environment, or "enabled": false in .thinwindow.json. With it off, thinwindow-run runs commands with their output untouched.
Requirements: Node.js 18 or newer. No other dependencies.
08Where it works
| Where | What ThinWindow does there |
|---|---|
| Claude Code (terminal, IDE, the desktop app's Code tab) | Everything: the rules, the guards, the brief, the cold-resume notice, the setup-cost notice and the /thinwindow: commands. The thinwindow-minimal profile works from the terminal. |
| Cowork | The rules, the Read guard and /thinwindow:brief work. /thinwindow:report covers only the current task, briefs don't carry over between tasks, and neither notice shows. |
| Chat (claude.ai, the desktop and mobile apps) | Only the Agent Skill: Claude loads the rules when it decides a task needs them, and /thinwindow:brief works. The other commands need a shell, which chat doesn't run. |
ThinWindow's validation ran in Claude Code. Cowork and chat were checked for what works there, not measured.
09Configuration
ThinWindow works without configuration. To change it, create .thinwindow.json in the project root or ~/.thinwindow.json in your home directory. Project values override home values; lists from both files are combined.
{
"enabled": true,
"maxReadLines": 400,
"rewrite": true,
"briefs": true,
"coldResumeNotice": true,
"coldResumeMinTokens": 100000,
"setupNotice": true,
"setupNoticeMinTokens": 40000,
"noisyCommands": ["^just (build|test)\\b"],
"allowlist": {
"paths": ["docs/**", "*.lock"],
"commands": ["^make lint$"]
}
}
| Key | Default | Effect |
|---|---|---|
enabled | true | false turns every hook off for that project, or everywhere in ~/.thinwindow.json. |
maxReadLines | 400 | Line count above which a whole-file Read is shortened, and cat of the file is refused. |
rewrite | true | Fix wasteful calls in place. false refuses them instead, as a soft block, at the cost of a turn each. |
briefs | true | false stops keeping session briefs for /thinwindow:resume. |
coldResumeNotice | true | false turns off the cold-resume notice. |
coldResumeMinTokens | 100000 | The smallest context, in tokens, for which the notice holds a prompt. |
setupNotice | true | false turns off the setup-cost notice. |
setupNoticeMinTokens | 40000 | The smallest first request, in tokens, for which the notice shows. |
noisyCommands | built-in list | Extra regular expressions for noisy commands, added to the built-in list. |
allowlist.paths | [] | Globs for files ThinWindow never blocks. |
allowlist.commands | [] | Regular expressions for Bash commands ThinWindow never blocks. |
A missing, unreadable or mistyped file is ignored, and a key with the wrong type keeps its default.
Environment variables
| Variable | Effect |
|---|---|
THINWINDOW=off | Turns ThinWindow off, whatever the config files say. |
THINWINDOW_DEBUG=1 | The hooks write each decision to stderr, which Claude Code keeps in its debug log (claude --debug). |
The complete reference is docs/configuration.md in the repository.
10Upgrading from 0.3.0
Nothing that worked stops working, and every new part has its own off switch.
- New hooks: at the end of each turn (the brief and the setup-cost notice), and before each prompt (the cold-resume notice).
- New commands:
/thinwindow:resume,/thinwindow:briefand/thinwindow:report. You type them; they add nothing to the skill listing Claude sees. - New switches:
briefs,coldResumeNotice,coldResumeMinTokens,setupNoticeandsetupNoticeMinTokens. - New, optional: the
thinwindow-minimalprofile, a file you copy in. - Changed: the rules say the same in fewer words.
11How it's checked
ThinWindow used to publish one benchmark percentage per model. From 0.4.0 it's checked with a different method (#28):
- Every mechanism has unit tests, run in CI on macOS, Linux and Windows.
- Ideas are first replayed on recorded sessions, at no model cost, to see what's at stake.
- A few targeted agent runs answer what only a model can, with the pass criteria written before the first run.
- 0.4.0 was validated before release against Claude Code without the plugin, on real open-source repositories, with its method and pass rules posted before the first run (#38). Every benchmark task and every resume chain completed with ThinWindow, as they did without it. When the second task of a chain started fresh after the prompt cache expired, it cost less per completed chain than continuing.
The method, the raw rows and the agents' scrubbed transcripts are public in bench/.
12What it reads, writes and sends
- Reads: the tool call Claude Code passes to the hooks (a file path, a command or a search pattern), and the line count and outline of files Claude is about to read or print; its settings in
.thinwindow.json; the environment variablesTHINWINDOW,THINWINDOW_DEBUG,CLAUDE_PROJECT_DIR,CLAUDE_PLUGIN_DATAandCLAUDE_CODE_SESSION_ATTENDED; before each prompt, the last 256 KB of the session's transcript, and the first 256 KB when a cold-resume notice is due; at the end of each turn, the part of the transcript written since the last turn, and its first 256 KB while a setup-cost notice may be due; andgit statusin the session's folder after a turn that could have changed files./thinwindow:resumealso runsgit logthere. It reads no credentials. - Writes, to your operating system's temp folder: one small file per session (which files and ranges were read, recent refusals, when a cold-resume notice was last shown, and counts of what the hooks did), one tiny file per project (when the setup-cost notice was last shown), and the full log of each command run through
thinwindow-run. - Writes, to the plugin's data folder (
~/.claude/plugins/data/): one small brief per session, in a folder per project. A brief holds excerpts of your prompts and of Claude's replies: the first prompt (up to 200 characters), the last three requests (up to 80 each), the last reply (up to 1,200), the changed files, and the last four commands (up to 70 characters each) with their exit codes."briefs": falsestops writing them. - Deletes: ThinWindow removes its files once they're 7 days old, the next time it runs. Claude Code deletes the plugin's data folder when you uninstall the plugin. If you remove ThinWindow from your account in the Claude desktop app, briefs can stay; delete the
thinwindow-*folder in~/.claude/plugins/data/to remove them. - Sends: nothing. There is no network code. A brief enters a conversation only when you type
/thinwindow:resume.
/thinwindow:report reads your Claude Code transcripts (~/.claude/projects, or $CLAUDE_CONFIG_DIR/projects) only when you run it, and writes nothing. It prints aggregate numbers with its own labels: never prompts, file contents, commands, paths, project names, session ids, or the names of your tools, models or MCP servers; a test checks this. Through the slash command, the printed numbers become part of your conversation; run the script yourself with ! to keep them out. If Claude Code changes its transcript format, the report says "format not recognized" instead of printing wrong numbers.
This page loads no external fonts or scripts either.
13Limitations
- ThinWindow is built for long sessions, and for coming back to big ones. A short task carries little context to begin with.
- The hooks need Claude Code. Other agents get the rules, and Cowork and chat get the parts listed in Where it works.
- US$ figures are estimates at the API list price. They aren't a bill.
- No warranty. The software is provided "as is" under the MIT License, without warranty of any kind. The hooks are designed to fail open, and the tests cover that, but no amount of testing is a guarantee. Review the code before trusting it with real work.
14Repository
| Path | Contents |
|---|---|
rules/thinwindow.md | The rules: the single source of truth for the behaviour. |
skills/ | The Agent Skill, with thinwindow-run and the report script, and the /thinwindow: commands. |
.claude-plugin/, hooks/ | The plugin manifest, its marketplace entry and the hooks. |
profiles/ | The opt-in thinwindow-minimal profile. |
adapters/AGENTS.md | The rules as a snippet for agents that read AGENTS.md. |
bench/ | Tasks, runner, report, hidden checks, reference solutions, raw results and the method. |
docs/ | Product spec, configuration reference and manual testing guide. |
test/, scripts/ | The test suite (node --test) and the repository checks CI runs. |
assets/, website/ | The ThinWindow logo and icon set, and this documentation site. |
Contributing
- A task from your own stack: another language, a monorepo, a framework with heavy generated code.
- A reproducible regression, with the rows that show it.
- A rule or hook proposal, with the compliance table (
node bench/compliance.mjs), and, when the decision depends on how the model reacts, a few targeted runs whose pass criteria are written before running them.
The workflow is in CONTRIBUTING.md. The project uses Conventional Commits and the MIT License.
15FAQ
Does it make Claude worse at the task?
In 0.4.0's validation, every benchmark task and resume chain completed with ThinWindow as often as without it, and a blind review of final answers found them correct and complete in both conditions. Every guard fails open.
How is it different from Claude Code's "Resume from summary"?
That dialog appears when you --resume a large session after about an hour, on Pro and Max plans. ThinWindow also covers sessions you left open, shows what continuing costs in tokens and US$ before you pay it, and keeps a brief for any later /clear.
Will the cold-resume notice interrupt me?
At most once per idle gap: only after an hour idle, and only over 100k tokens of context. Send the prompt again to continue, or turn it off with "coldResumeNotice": false.
Does it send my code or telemetry anywhere?
No. There is no network code in the project: no analytics, crash reports, usage statistics, or license or update checks. The hooks are local Node scripts.
Does it work outside Claude Code?
The rules do, through Agent Skills or AGENTS.md. The hooks need Claude Code. Cowork and chat get the parts in Where it works.
Can it block something I actually need?
It's designed not to. A refused Read or noisy command goes through when repeated, the always-refused commands come with a working replacement, paths and commands can be allowlisted, and THINWINDOW=off disables everything. If a hook itself fails, the call proceeds.