Skip to main content

Winnow

PyPI Python License: MIT

Remove boilerplate from scraped markdown before it reaches an LLM.

Scraping and extract APIs like Tavily hand you "LLM-ready" markdown that still carries navigation, footers, cookie banners, promos, and link farms — 10–90% of the tokens depending on the page. The same goes for your own scraper or loader pipeline: if it produces markdown (or HTML converted to markdown), Winnow slots in right after it — any markdown in, leaner markdown out, with a receipt for every removed block.

  • Subtractive-only. Winnow deletes blocks; it never rewrites a word. Zero hallucination risk by construction.
  • Recall-first. Dropping real content is data loss; keeping boilerplate just costs tokens. When uncertain, Winnow keeps.
  • Auditable. Every removed block comes back with a reason code and score.
  • Template memory. Feed Winnow multiple pages from one site and it learns the site's template — blocks repeated across pages are boilerplate, near-certainly.
  • Zero runtime dependencies. The core install adds nothing to your tree.

Install

pip install winnow-md

Optional extras:

pip install "winnow-md[model]"    # learned block-sequence scorer (numpy + model2vec)
pip install "winnow-md[tokens]"   # exact token counts via tiktoken
pip install "winnow-md[model,tokens]"

Python 3.9+. The package installs as winnow-md and imports as winnow. The core is pure Python with no dependencies; if the [model] extra isn't installed, the learned scorer is silently skipped and the heuristics run alone.

Quickstart

import winnow

# One page
res = winnow.clean(markdown_text)
print(res.markdown)          # cleaned markdown
print(res.stats)             # tokens before/after, reduction %
for r in res.removed:        # the receipt
    print(r.reasons, r.text[:60])

# A crawl — template memory kicks in across pages of the same domain
w = winnow.Winnow(aggressiveness=0.5)
results = w.clean_many(pages)          # list of markdown strings (or (md, url) tuples)

# Streaming with a persistent per-domain template store
w = winnow.Winnow(store="winnow.db")
res = w.clean(md, url="https://example.com/post/1")
winnow clean page.md                      # cleaned markdown to stdout
winnow clean ./crawl/ --report out.html   # batch + filterable HTML audit report
winnow clean ./crawl/ --url-mode strip    # also strip URL bodies from kept links

Jina Reader output (Title: / URL Source: preamble) is auto-detected and the source URL is used for template memory.

Benchmark

Seven generations of independently-labeled, adversarially-arbitrated exam batches (each fetched fresh, dual-labeled blind, disputes refereed) — ~19,200 hand-adjudicated blocks across 32 domains:

Exam batch Content recall Junk recall Token cut
batch 7 (newest, still converging) 0.969 0.55 −30%
batch 6 0.970 0.55 −27%
batch 5 0.963 0.58 −41%
batch 4 0.979 0.61 −49%
batch 3 0.992 0.57 −35%
batch 2 0.997 0.58 −30%
batch 1 1.000 0.69 −42%

Content recall is the fraction of real content kept — the number that must never slip. Junk recall is the fraction of boilerplate actually removed; what it misses costs tokens, never correctness. Each batch was a fresh exam nothing had been tuned on when first scored, then became training data — the newest batch is always the honest one.

Add --url-mode strip for roughly 15 additional points of token cut with zero text loss. With the [model] extra installed, a learned block-sequence scorer raises junk recall further; it is capped so that it can never delete a block on its own.

The benchmark harness, labeling pipeline, and mutation self-test live in bench/ — see ARCHITECTURE.md.

Contributing

Contributions are welcome — bug fixes, new signals, docs, tests, or ideas. One especially easy and useful report: a page Winnow handles badly, since most improvements so far came from being shown a real page it got wrong. See CONTRIBUTING.md for setup, the three design rules any change must respect, and how to run the benchmark gates before opening a PR.

License

MIT — see LICENSE.

Release files for winnow-md 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for winnow-md 0.1.3
File Size Uploaded
winnow_md-0.1.3.tar.gz 363.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for winnow-md 0.1.3
File Interpreter ABI Platform
winnow_md-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 720.1 kB

Release files / winnow_md-0.1.3.tar.gz

Download URL winnow_md-0.1.3.tar.gz
Size 363.7 kB
Tags Source
SHA-256 checksum
How to use checksums
fcf70fef6e8814809d7e786ea7235d6e1b3569672a7746a297c8d0f7b919f69b
BLAKE2b-256 checksum
How to use checksums
c6e3897e5f1c74f0e5481dbede5f8cbfc5883479891b49066fe594bf575c6391
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / winnow_md-0.1.3-py3-none-any.whl

Download URL winnow_md-0.1.3-py3-none-any.whl
Size 356.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e336db5321cc026e2dc26c5f3a7cba31e3a4719b6150fdf83a462976ab3a564b
BLAKE2b-256 checksum
How to use checksums
5ed21d577790394a094e9435b4da1c3389a894b8e828ca849454a49ff571880b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.18 {"installer":{"name":"uv","version":"0.11.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page