A calibrated context sieve for Claude Code: every tool result is judged by a System One model before it enters context.
# Add to your Claude Code skills
git clone https://github.com/GhalebDweikat/winnowSee how winnow compares with popular alternatives.
winnow is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by GhalebDweikat. A calibrated context sieve for Claude Code: every tool result is judged by a System One model before it enters context. It has 54 GitHub stars.
winnow's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/GhalebDweikat/winnow" and add it to your Claude Code skills directory (see the Installation section above).
winnow is primarily written in Python. It is open-source under GhalebDweikat on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh winnow against similar tools.
No comments yet. Be the first to share your thoughts!
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
A calibrated context sieve for Claude Code.
Every large Read, Bash, or Grep result is judged before it enters Claude's context. Blocks the judge is confident you don't need are replaced with a three-line stub: what was hidden, a one-paragraph summary from a cheap model, and a key that restores the full text on demand. Nothing is lost; it just stops costing tokens until you ask for it.
Terms used below. The judge is the model that answers one yes/no question per block ("is this block needed for the current task?") with a probability. By default that is Jev, TypeSafe AI's System One model: a model that returns calibrated probabilities for typed questions instead of generating text, so a hundred questions come back in one call in a few hundred milliseconds. Jev is in early access. The adapter is TypeSafe's system-one-adapter package, which answers the same questions by prompting Claude Haiku 4.5; it is not calibrated, but it lets the whole pipeline run today.
Read big.py ──► Claude Code ──► tool.call hook ──► winnow
│
split into ~25-line blocks ◄─────────────────────────┘
one call to the judge: "is block N needed for the current task?" ×N, in parallel
keep confident-yes and uncertain blocks verbatim
hide confident-no blocks: cache full text ─► summarize ─► stub
│
Claude sees ◄── { result } ◄───────────────────────────────┘
A stub looks like this:
[winnow] Lines 41-188 (148 lines) hidden: judged unlikely to matter for the current task (relevance <= 0.22).
[winnow] Summary: Argparse setup for the --export and --format flags, plus the license header.
[winnow] Full text cached as key a1b2c3d4e5f6. Call winnow_recall(key="a1b2c3d4e5f6", start=41, end=188) if you need it.
Without a summarizer the middle line is a deterministic digest instead, so Claude still knows what kind of thing it lost: for a search result, which files the hidden matches came from and how many each; for anything else, the line count, whether it was mostly comments, imports or repetition, and the first line.
Two safety rules are built in. If the judge thinks the output shows an error, nothing is hidden. If a block's probability is merely uncertain (between WINNOW_DROP and WINNOW_KEEP), it is kept. Both thresholds are tunable; the rules themselves are not optional. The default WINNOW_DROP of 0.1 is the bin that came back clean on hand-labeled replay (see Measured); raise it only with your own evidence.
The hook is a function-hook module (see How it hooks in) that talks to a small resident server (winnow serve) on loopback, started at session start, so a judged call costs about 16 ms plus the judge call rather than a Python startup. winnow never judges its own files or its own commands, so recalls and labeling sheets always come back whole.
A second hook runs at prompt time. It ranks the memory files Claude Code keeps for the project (~/.claude/projects/<project>/memory/*.md, everything except the MEMORY.md index, which Claude already loads) plus any directories in WINNOW_CONTEXT_DIRS against your prompt, and injects the relevant ones so Claude reads what it needs without a round of Read calls.
What winnow changes is only what Claude sees. Files on disk, the commands that ran, and Claude Code's own transcript are untouched.
Requirements: Python 3.10+, uv, Claude Code 2.1.260 or newer with function hooks enabled (early access; one line in settings, below).
First turn on function hooks in ~/.claude/settings.json (winnow does nothing without this, and winnow doctor checks it):
{ "env": { "CLAUDE_CODE_ENABLE_FUNCTION_HOOKS": "1" } }
Then install:
git clone https://github.com/GhalebDweikat/winnow.git
claude plugin marketplace add ./winnow
claude plugin install winnow@winnow
Then add a key (next section), open a new Claude Code session, and read any file longer than about 1,500 characters. If a [winnow] line appears in the result, it's working. If not, see Troubleshooting.
Before you have any key, you can still see what it does:
uv run --project winnow/sidecar winnow demo --fake
That runs a synthetic 130-line file through the real pipeline with a keyword judge and prints what Claude would have seen. Once a key is set, drop --fake and the same command makes the first real judge call.
The repo is its own plugin marketplace, so it also installs straight from GitHub without cloning:
claude plugin marketplace add GhalebDweikat/winnow
claude plugin install winnow@winnow
GitHub shorthand clones over SSH by default; set CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1 if you don't have an SSH key on this machine.
Installing applies everywhere that shares your ~/.claude config: the CLI, the desktop app, and IDE extensions. New sessions pick the plugin up; running sessions don't. The first session after install syncs the sidecar's environment and starts the resident server, which takes a few seconds once; after that, sessions share the running server and start instantly.
Installed plugins are copied to ~/.claude/plugins/cache/, not linked, so after pulling changes run claude plugin update winnow@winnow. For a hot-reload loop while developing, load the checkout for one session instead:
claude --plugin-dir ./winnow
To scope the plugin to one project rather than your whole account, add --scope project to the marketplace add command.
winnow needs one key for the judge and, optionally, one for summaries. Nothing runs until at least the judge key is in place; until then every hook passes results through untouched and, once per session, tells you so.
1. Get a Jev key. Jev is in early access. Join the waitlist at typesafe.ai, and once you're admitted create a key at console.typesafe.ai/settings/keys. No key yet? Skip to step 3.
2. Put the keys where hooks can see them. A hook runs with the environment of whatever launched Claude Code. A key exported in one terminal is invisible to the desktop app and to IDE sessions. Either of these works everywhere:
A file at ~/.winnow/env (on Windows, %USERPROFILE%\.winnow\env), one KEY=VALUE per line. winnow reads it on every hook call. Keep it private; it is outside the repo.
TYPESAFE_API_KEY=ts-...
ANTHROPIC_API_KEY=sk-ant-...
Or the env block of ~/.claude/settings.json, which Claude Code applies to every session and every subprocess it starts:
{ "env": { "TYPESAFE_API_KEY": "ts-...", "ANTHROPIC_API_KEY": "sk-ant-..." } }
A variable already in the environment wins over the file, so a plain shell export still works for CLI use.
3. No Jev key yet? Use the adapter. Add WINNOW_JUDGE=adapter to the same file. The adapter sends the identical request to Claude Haiku 4.5 through your Anthropic credentials (ANTHROPIC_API_KEY, or a profile from the ant CLI's ant auth login). Its probabilities are not calibrated, but the whole pipeline works, and switching to Jev later is one line. This path bills your Anthropic account; see cost.
4. Verify.
uv run --project winnow/sidecar winnow doctor
It prints which keys were found, where they came from, and whether each backend initializes. Then winnow demo (without --fake) makes one real judge call and shows the result.
Summaries use the Anthropic credentials. Set WINNOW_SUMMARY=0 to turn them off; stubs then say "Summary unavailable" and everything else still works.
winnow commandsFrom the clone, every command is uv run --project winnow/sidecar winnow <command>. To have winnow on your PATH anywhere:
uv tool install ./winnow/sidecar
winnow doctor
Commands: doctor, demo [--fake], stats, recall <key> [--start N --end M], replay {extract,judge,score,run,sample,label,import-labels,agreement}, serve [--ensure|--status|--stop], bench [--http], clean, mcp, hook <event>.
winnow's job is reading everything Claude reads, so be clear about where it goes.
| Data | Sent to | When |
|---|---|---|
| The tool output being judged, in blocks, plus a short task description from the transcript (last user request, last assistant sentence) and the tool's arguments | TypeSafe (judge typesafe) or Anthropic (judge adapter) |
every judged result over WINNOW_MIN_CHARS |
| The hidden blocks only | Anthropic | when summaries are on and something was hidden |
| Your prompt and the first 600 characters of each candidate memory file | the judge | every prompt, when candidate files exist |
Nothing is sent when the judge is off, and nothing is sent for outputs under the size threshold. The full text of every hidden output is kept locally in ~/.winnow/cache/ for recall; there is no eviction yet, so clear it when you like.
Approximate cost per judged result, for a 10,000-token output:
| Judge | Judge call | Summaries (up to 4, Haiku 4.5) | Total |
|---|---|---|---|
| Jev at $0.042 per million input tokens | $0.0004 | about $0.005 | under a cent |
| Adapter on Haiku 4.5 at $1 per million input tokens | about $0.01 | about $0.005 | a few cents |
winnow stats reports the judge's actual token usage and cost after the fact.
All settings are environment variables (or lines in ~/.winnow/env). Defaults are deliberately conservative.
| Variable | Default | Meaning |
|---|---|---|
| `WINNOW_MO |