Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
1735 commits
Select commit Hold shift + click to select a range
5909fa7
Merge pull request #3123 from JinyangWang27/move-entries
JinyangWang27 May 12, 2026
5885075
Add ultralytics to Computer Vision section
aasimansari1 May 17, 2026
420619b
add links to the website
vinta May 17, 2026
3e66360
refine wording
vinta May 17, 2026
e7cd326
Merge pull request #3132 from aasimansari1/add-ultralytics
JinyangWang27 May 18, 2026
a9b13e4
update .gitignore
vinta May 18, 2026
a089ae2
Merge pull request #3137 from raahulrahl/add-bindu
raahulrahl May 19, 2026
e403a8f
build(deps): bump idna from 3.11 to 3.15 (#3147)
dependabot[bot] May 22, 2026
a10ec14
Add graphify (#3154)
JinyangWang27 May 23, 2026
9036e5e
Add KittenTTS
imdewan May 23, 2026
fe6379f
clean up
vinta May 24, 2026
9e20e51
Add FunASR to Speech section
May 24, 2026
a6033b5
Merge branch 'master' into add-kittentts
dewana-sl May 25, 2026
e90ae86
Merge pull request #3155 from dewana-sl/add-kittentts
JinyangWang27 May 26, 2026
79e0d8d
docs: add repository agent guidance
vinta May 27, 2026
96da94e
Add chdb to Database
ShawnChen-Sirius May 28, 2026
1f915d6
Merge pull request #3169 from ShawnChen-Sirius/add-chdb
JinyangWang27 May 28, 2026
aa8dad7
Merge pull request #3157 from LauraGPT/master
JinyangWang27 May 29, 2026
d51eff7
docs: add scikit-lego to Machine Learning section (#3168)
Samxss May 30, 2026
f0bfc4c
Add synology-api entry to README (#3174)
N4S4 Jun 2, 2026
d85e849
Update canonical GitHub project links (#3177)
lonelyhty Jun 4, 2026
5fe1dbd
Add uuid-utils (#3178)
aminalaee Jun 4, 2026
b7e6781
add nuwa-skill
JinyangWang27 Jun 4, 2026
6dd7b2a
Add kubesdk (#3166)
bb6111 Jun 4, 2026
2350345
Merge pull request #3183 from JinyangWang27/add-nuwa-skill
JinyangWang27 Jun 5, 2026
eb86241
sync with upstream
fauzan171 Jun 6, 2026
4ae14cb
fix: correct authlib description in Authentication section
fauzan171 Jun 6, 2026
3e8404c
fix: update outdated version references in descriptions
fauzan171 Jun 6, 2026
647d723
fix: update chardet description to remove outdated Python 2 reference
fauzan171 Jun 6, 2026
ada2293
Merge pull request #3190 from fauzan171/fix/chardet-description
vinta Jun 6, 2026
037de83
Merge pull request #3189 from fauzan171/fix/outdated-version-references
vinta Jun 6, 2026
bcfba78
add Indie Dev sponsorship tier
vinta Jun 6, 2026
ee08cd7
update sponsorship webpage
vinta Jun 6, 2026
9f156de
make descriptions shorter
vinta Jun 6, 2026
32ae78f
fix: improve website SEO metadata
vinta Jun 6, 2026
c0b80fd
fix: surface sponsorship link in header
vinta Jun 6, 2026
58977f3
Merge pull request #3193 from Oliver-Liu99/add-outlines
Oliver-Liu99 Jun 9, 2026
32b4e7f
Add Jumpstarter to Hardware (#3179)
raballew Jun 9, 2026
6ed5378
Add langgraph to AI and Agents (Orchestration) (#3194)
Oliver-Liu99 Jun 12, 2026
ac24993
Added parsy to 'Text Processing / Parsers' section (#3212)
spookylukey Jun 24, 2026
9c8a450
Add LiteLLM (#3214)
S4ch9n Jun 26, 2026
89bc8e6
style: fix entry sorting and update redirected URLs in README.md
Jun 29, 2026
bb02f20
Add buridan/ui to Web Based section (#3219)
LineIndent Jun 29, 2026
f91797e
Add zvec to Database section (#3218)
chinaux Jun 29, 2026
a9a0d1b
Apply suggestion from @vinta
vinta Jun 29, 2026
844f343
Merge branch 'master' into fix/authlib-description
vinta Jun 29, 2026
61faed9
Merge pull request #3188 from fauzan171/fix/authlib-description
vinta Jun 29, 2026
a535d7b
Merge pull request #3222 from aoright/fix-sorting-and-redirects
vinta Jun 29, 2026
8c59fb5
Update kreuzberg entry to xberg (renamed, 97+ formats) (#3230)
Goldziher Jul 1, 2026
cf76662
Add entroly to AI > Data Layer (#3233)
juyterman1000 Jul 5, 2026
2e0a7c0
Add html-to-markdown to HTML Manipulation (#3239)
Goldziher Jul 5, 2026
0c992c5
Add crawlberg to Web Scraping (#3238)
Goldziher Jul 5, 2026
70d290c
Add fiftyone (#3244)
Burhan-Q Jul 7, 2026
a543b88
fix: remove duplicate dash in scikit-lego entry (#3245)
Shivam-Shukla0 Jul 7, 2026
4ebfa3b
Add liter-llm to AI and Agents (#3240)
Goldziher Jul 7, 2026
d3c5935
Add SenseVoice (#3246)
LauraGPT Jul 8, 2026
75360ff
Update README.md (#3253)
dmitriy1ikobe Jul 14, 2026
c6e08dc
Add website-downloader (Web Scraping / Frameworks) (#3250)
PKHarsimran Jul 14, 2026
9a9281f
Add hatch to Package Management #HSFDPMUW (#3256)
JulianGStudium Jul 17, 2026
ca8ca17
Add tree-sitter-language-pack to Text Processing (#3241)
Goldziher Jul 20, 2026
a53ca41
Add tkdesigner to GUI libraries list (#3262)
Severian0 Jul 22, 2026
eac8c46
Add lumen to AI and Agents > Data Layer (#3261)
ghostiee-11 Jul 22, 2026
3c3c8fc
Add kaydet (#3263)
miratcan Jul 23, 2026
4e1f6db
Add livetalking in Orchestration subsection (#3268)
lipku Jul 29, 2026
058aab0
Add smolagents to AI and Agents (#3272)
MeiSiristhebest Aug 3, 2026
94159a8
Add msgspec to serialization libraries (#3273)
aryansk Aug 5, 2026
4add70b
Add seleniumbase to awesome-python
mdmintz Aug 13, 2026
043379b
Change seleniumbase to SeleniumBase
mdmintz Aug 13, 2026
63146cc
docs: capture shortlist-reform decisions on shortlist-reform branch
vinta Aug 15, 2026
bd657b3
docs: fix stale cap wording in shortlist ADR
vinta Aug 15, 2026
d4d518f
docs: fix stale claims in shortlist-not-catalog ADR
vinta Aug 15, 2026
9218024
docs: fold serves-Python-developers scope test into ADR-0001
vinta Aug 15, 2026
c413b8f
docs: fix stale and inaccurate definitions in CONTEXT.md
vinta Aug 15, 2026
663fad0
docs: mark Challengers by ordering, not description text
vinta Aug 15, 2026
553bf88
feat: replace acceptance lanes with shortlist admission rule
vinta Aug 15, 2026
3ca241d
clean up
vinta Aug 15, 2026
e10ff58
prune: sweep AI and Agents to the shortlist cap
vinta Aug 15, 2026
e4e70cd
feat: add claude-agent-sdk to Vendor Agent SDKs
vinta Aug 15, 2026
6cd5ffc
prune: sweep File Format Processing to the shortlist cap
vinta Aug 15, 2026
5488d08
prune: sweep Data Visualization to the shortlist cap
vinta Aug 15, 2026
5200ffa
prune: sweep Testing to the shortlist cap
vinta Aug 15, 2026
b0cdf40
feat: add verdict-preview skill for maintainer review pages
vinta Aug 15, 2026
fc88ebb
feat: add BigQuery-based PyPI downloads fetcher
vinta Aug 15, 2026
bb53dfe
docs: require live verification of keep/drop reasons
vinta Aug 15, 2026
3ae3483
docs: reinstate crewai in AI and Agents orchestration
vinta Aug 15, 2026
9290f18
feat: reinstate bokeh as Plotting challenger
vinta Aug 15, 2026
1463ba8
prune: sweep Data Analysis to the shortlist cap
vinta Aug 15, 2026
54c0c0c
prune: sweep Data Ingestion / ETL to the shortlist cap
vinta Aug 15, 2026
9103f59
prune: sweep Data Validation to the shortlist cap
vinta Aug 15, 2026
9631207
prune: sweep Geolocation to the shortlist cap
vinta Aug 15, 2026
0c1409d
prune: sweep Science to the shortlist cap
vinta Aug 15, 2026
c9abd51
style: apply challenger ordering and entry format to Quantum Computing
vinta Aug 15, 2026
846a6bd
docs: order entries by downloads/month within tiers, not alphabetically
vinta Aug 15, 2026
46b7b57
style: reorder swept sections by downloads/month within tiers
vinta Aug 15, 2026
59cc42e
docs: sync AGENTS.md with the shortlist reform rules
vinta Aug 15, 2026
83f6ceb
feat: add audit-the-list skill for recurring section audits
vinta Aug 15, 2026
7f0e923
refactor: rename verdict-preview skill to preview-verdicts
vinta Aug 15, 2026
a1ed550
fix: filter BigQuery PyPI download query on project, not file.project
vinta Aug 15, 2026
fd79813
feat: switch default PyPI download source to ClickPy
vinta Aug 15, 2026
fcac019
feat: add pepy.tech spot-check helper for download audits
vinta Aug 15, 2026
f39d00d
audit: sweep Web Frameworks to the shortlist cap
vinta Aug 15, 2026
b26c30d
audit: sweep Web APIs to the shortlist cap
vinta Aug 15, 2026
fb35807
audit: sweep Web Servers to the shortlist cap
vinta Aug 15, 2026
69e03b7
audit: sweep WebSocket to the shortlist cap
vinta Aug 15, 2026
6b9a1cc
audit: sweep Admin Panels to the shortlist cap
vinta Aug 15, 2026
4c57da8
audit: sweep CMS to the shortlist cap
vinta Aug 15, 2026
e18d521
audit: sweep Static Site Generators to the shortlist cap
vinta Aug 15, 2026
e7e17a8
style: reorder Authentication and Web Asset Management by downloads
vinta Aug 15, 2026
7447549
docs: define Sub-item in CONTEXT.md
vinta Aug 15, 2026
5297061
refactor: rename download-fetch scripts to source-suffixed scheme
vinta Aug 15, 2026
5ece46f
docs: cover awesome-* links in the Sub-item definition
vinta Aug 15, 2026
1abfb1a
refactor: split download fetchers into writer and cross-check scripts
vinta Aug 15, 2026
c2ba7d4
audit: sweep HTTP Clients to the shortlist cap
vinta Aug 15, 2026
fdf66eb
audit: sweep Web Scraping to the shortlist cap
vinta Aug 15, 2026
d2d344f
audit: sweep Email to the shortlist cap
vinta Aug 15, 2026
9fc4f00
style: rename HTTP Clients' General subcategory to Clients
vinta Aug 15, 2026
41f89f7
audit: sweep ORM to the shortlist cap
vinta Aug 15, 2026
b8dd653
style: restructure Database Drivers section
vinta Aug 15, 2026
0cc4e0e
feat: add asyncpg to Database Drivers > PostgreSQL
vinta Aug 15, 2026
774da72
feat: add clickhouse-connect to Database Drivers > ClickHouse
vinta Aug 15, 2026
9b28c56
feat: add pyodbc to Other Relational Databases
vinta Aug 15, 2026
442291d
feat: add oracledb to Database Drivers > Other Relational Databases
vinta Aug 15, 2026
3a3b20c
audit: sweep Database to the shortlist cap
vinta Aug 15, 2026
b7b633d
feat: add lancedb to Database & Storage > Vector
vinta Aug 15, 2026
02735b6
style: reorder Caching by downloads, rename python-diskcache to diskc…
vinta Aug 15, 2026
7ac2950
audit: sweep Search to the shortlist cap
vinta Aug 15, 2026
f953956
feat: add opensearch-py to Search as obvious choice
vinta Aug 15, 2026
509fcaa
feat: add meilisearch to Search as a challenger
vinta Aug 15, 2026
745347d
style: reorder Serialization by downloads
vinta Aug 15, 2026
5da1d16
docs: define Second Tier in CONTEXT.md
vinta Aug 15, 2026
bc3e7a0
docs: condense AGENTS.md and CLAUDE.md for progressive disclosure
vinta Aug 15, 2026
6c93b1e
docs: update audit-the-list SKILL.md wording
vinta Aug 15, 2026
c6957d4
docs: require WebSearch evidence for tier judgments
vinta Aug 15, 2026
36c6179
update wordings
vinta Aug 15, 2026
a2da210
feat: stamp pypi downloads cache with fetched_at and header row
vinta Aug 15, 2026
8814a85
feat: store verdict preview pages in repo-local ./tmp
vinta Aug 15, 2026
3e90482
audit: sweep Code Analysis to the shortlist cap
vinta Aug 16, 2026
5e3d778
feat: add pyright to Type Checkers
vinta Aug 16, 2026
b496053
audit: sweep Debugging Tools to the shortlist cap
vinta Aug 16, 2026
3a65a02
feat: add memray to Profiler
vinta Aug 16, 2026
d316a8e
feat: add pyinstrument to Profiler
vinta Aug 16, 2026
8125688
audit: sweep Build Tools to the shortlist cap
vinta Aug 16, 2026
71eee5d
feat: add ipython to Interactive Interpreter
vinta Aug 16, 2026
2d0f5da
feat: add mkdocs-material as sub-item under mkdocs
vinta Aug 16, 2026
166c9c9
style: reorder Algorithms and Design Patterns and Documentation by do…
vinta Aug 16, 2026
fb7383c
docs: point Build Tools readers to Package Management
vinta Aug 16, 2026
a610fce
audit: sweep DevOps Tools to the shortlist cap
vinta Aug 16, 2026
b06104c
feat: add azure-sdk-for-python to Cloud Providers
vinta Aug 16, 2026
77e7b62
feat: add google-cloud-python to Cloud Providers
vinta Aug 16, 2026
4fc3222
audit: sweep Distributed Computing to the shortlist cap
vinta Aug 16, 2026
83c723d
style: reorder Task Queues by tier and downloads
vinta Aug 16, 2026
e5ce98c
feat: add confluent-kafka to Messaging
vinta Aug 16, 2026
28b6d13
feat: add pika to Messaging
vinta Aug 16, 2026
7fd4957
feat: add paho-mqtt to Messaging
vinta Aug 16, 2026
03d9139
audit: sweep Job Schedulers to the shortlist cap
vinta Aug 16, 2026
635a735
audit: sweep Logging to the shortlist cap
vinta Aug 16, 2026
b8cacb5
audit: sweep Network Virtualization to the shortlist cap
vinta Aug 16, 2026
3290ce5
style: merge Security Linters into Linters and Formatters
vinta Aug 16, 2026
35c6898
audit: sweep CLI Development, mint TUI Frameworks, drop cement
vinta Aug 16, 2026
1a8e14c
audit: sweep CLI Tools, dissolve Productivity Tools, drop thefuck, ka…
vinta Aug 16, 2026
9bbe1cf
audit: sweep GUI Development, split Desktop into Qt and Tkinter, drop…
vinta Aug 16, 2026
41a1b4b
audit: sweep Image Processing, split into use cases, drop pymatting
vinta Aug 16, 2026
9970486
feat: add rembg to Image Processing > General
vinta Aug 16, 2026
8f9c388
audit: sweep Audio & Video Processing, re-home TTS to Speech, drop bi…
vinta Aug 16, 2026
3f391b3
audit: sweep Game Development, split into use cases, drop py-sdl2, py…
vinta Aug 16, 2026
8a3771e
feat: add pygame-ce to Game Development > Game Frameworks
vinta Aug 16, 2026
9fa72c1
audit: sweep Implementations, drop ironpython
vinta Aug 16, 2026
6af6158
audit: sweep Functional Programming, drop coconut
vinta Aug 16, 2026
19875cf
audit: sweep Asynchronous Programming, split into Async I/O and Paral…
vinta Aug 16, 2026
16077fc
style: re-tier Built-in Classes Enhancement and Date and Time
vinta Aug 16, 2026
c00094a
feat: add whenever to Date and Time
vinta Aug 16, 2026
15c4064
docs: amend Entry Ordering so standard-library modules sort first in …
vinta Aug 16, 2026
05a9dd4
style: move standard-library entries to the top of their tiers
vinta Aug 16, 2026
5f6f1f0
docs: clarify that standard-library modules lead the use case outright
vinta Aug 16, 2026
a4eba37
audit: sweep Environment Management, drop KillPy, pyenv-win becomes a…
vinta Aug 16, 2026
1b51907
audit: sweep Package Management, mint Package Managers subcategory, c…
vinta Aug 16, 2026
1a36f77
feat: add setuptools to Package Management > Build Backends
vinta Aug 16, 2026
0ec6f49
feat: add hatchling to Package Management > Build Backends
vinta Aug 16, 2026
947b939
feat: add uv-build to Package Management > Build Backends
vinta Aug 16, 2026
9f9bd8d
style: split Distribution into Executables and Obfuscation
vinta Aug 16, 2026
5a8c062
audit: sweep Configuration Files, drop python-decouple
vinta Aug 16, 2026
ee0caca
feat: add pydantic-settings to Configuration Files
vinta Aug 16, 2026
cf38a34
refactor: re-home pre-commit to Code Analysis > Git Hooks
vinta Aug 16, 2026
283f142
style: fix display-name casing to canonical PyPI names
vinta Aug 16, 2026
438881a
style: audit Cryptography and Penetration Testing — renames and re-tiers
vinta Aug 16, 2026
fe7006e
feat: add pip-audit, minting the Supply Chain Security section
vinta Aug 16, 2026
913b380
feat: add uv audit to Supply Chain Security
vinta Aug 16, 2026
16e17d6
style: drop the preview label from uv audit's description
vinta Aug 16, 2026
0194cbb
audit: sweep Hardware, drop synology-api
vinta Aug 16, 2026
f8e594a
audit: sweep Miscellaneous, drop tryton, re-home itsdangerous to Cryp…
vinta Aug 16, 2026
a265963
feat: add odoo, minting the ERP section
vinta Aug 16, 2026
660d746
style: move the ERP section to the Web Development group
vinta Aug 16, 2026
34c550b
style: split Deep Learning into Frameworks and Reinforcement Learning
vinta Aug 16, 2026
b95ce7e
feat: add gymnasium to Deep Learning > Reinforcement Learning
vinta Aug 16, 2026
7d1c5c8
audit: sweep Machine Learning, three-way split, drop h2o, mindsdb, sc…
vinta Aug 16, 2026
c83b98c
audit: sweep Natural Language Processing, drop funnlp
vinta Aug 16, 2026
67c9f7a
style: split Computer Vision into General and OCR
vinta Aug 16, 2026
da4383a
audit: sweep Text Processing, dissolve General, drop textdistance, na…
vinta Aug 16, 2026
043cb6d
feat: add charset-normalizer to Text Processing > Encoding and Unicode
vinta Aug 16, 2026
db9c262
feat: add rapidfuzz, minting Text Processing > Fuzzy Matching
vinta Aug 16, 2026
ad698c2
audit: sweep HTML Manipulation, drop html-to-markdown, pyquery, tinycss2
vinta Aug 16, 2026
15cd51c
style: re-tier File Manipulation
vinta Aug 16, 2026
5249b75
refactor: re-home fasthtml to Web Frameworks > Asynchronous
vinta Aug 16, 2026
e5f7b5b
style: update graphify link to the moved Graphify-Labs repo
vinta Aug 16, 2026
441f206
feat: add pathway to Data Ingestion / ETL
vinta Aug 16, 2026
f60d5b4
style: move fasthtml back to Web Frameworks > Synchronous
vinta Aug 16, 2026
194b386
docs: codify the Override rule in CONTRIBUTING and CONTEXT
vinta Aug 16, 2026
39eeab7
docs: warn about wrong-package PyPI download counts
vinta Aug 16, 2026
c034c88
docs: add audit log registry for maintainer overrides
vinta Aug 16, 2026
3e43fa1
docs: clarify cross-section re-homes and resources scope in audit rules
vinta Aug 16, 2026
deae0e0
docs: broaden Obvious Choice signal and note Cap has no floor
vinta Aug 16, 2026
2c50d9e
docs: document gitignored output and orphan-key behavior
vinta Aug 16, 2026
2c2ce2f
docs: document empirically verified README parsing behavior
vinta Aug 16, 2026
cfb60a6
docs: codify dual-listing policy in CONTRIBUTING.md
vinta Aug 16, 2026
cccfa18
docs: rewrite PR template to match shortlist rules
vinta Aug 16, 2026
68b15a4
docs: rephrase obvious-choice criterion in PR template
vinta Aug 16, 2026
08fdfa6
update readme
vinta Aug 16, 2026
0e9ae0c
clean up
vinta Aug 16, 2026
f13075b
refactor: re-home aws-sdk-pandas from pandas sub-item to ETL General
vinta Aug 16, 2026
63a1ead
docs: remove typeshed sub-item from under mypy
vinta Aug 16, 2026
b0434ab
refactor: promote mkdocs-material to full Documentation entry
vinta Aug 16, 2026
49b229b
refactor: promote flower from celery sub-item to full DevOps Monitori…
vinta Aug 16, 2026
ecd9dea
refactor: move pyenv-win from pyenv sub-item to full entry
vinta Aug 16, 2026
c39e4d6
docs: restrict sub-items to awesome-* also-see links
vinta Aug 16, 2026
24d6c28
build: upgrade project to Python 3.14
vinta Aug 16, 2026
0d13cd2
build: use >= floors instead of == pins for dependency groups
vinta Aug 16, 2026
e9329d4
fix: correct hydra-core repo URL to facebookresearch/hydra
vinta Aug 16, 2026
b440e64
fix: resolve PyPI download counts through curated package overrides
vinta Aug 16, 2026
cc804b1
feat: add Downloads/Month column to website table
vinta Aug 16, 2026
f3ff733
fix: add three more PyPI name remaps for NOT_FOUND triage
vinta Aug 16, 2026
fcfc65d
data: record all remaining NOT_FOUND names as explicit null overrides
vinta Aug 16, 2026
b841db6
refactor: make pypi_name_overrides.json entries self-documenting
vinta Aug 16, 2026
d3fec1f
feat: default-sort the website table by downloads per month
vinta Aug 16, 2026
da491ff
docs: rename Downloads/Month column header to PyPI Downloads
vinta Aug 16, 2026
f5f7a1c
refactor: swap PyPI Downloads and GitHub Stars column order
vinta Aug 16, 2026
bfdd087
feat: show "Not on PyPI" badge for missing download counts
vinta Aug 16, 2026
b7e12cf
Merge pull request #3288 from vinta/refactor/shortlist-reform
vinta Aug 16, 2026
30c9f18
feat: annotate llms.txt entries with PyPI download counts
vinta Aug 16, 2026
ee8089d
add build date to llms.txt
vinta Aug 16, 2026
e63de26
update readme
vinta Aug 16, 2026
8b14b4f
update styles
vinta Aug 16, 2026
4fc3535
docs: update og-image wordings to match current site copy
vinta Aug 16, 2026
9ce2a21
feat: add review-prs skill as workflow-only PR triage
vinta Aug 16, 2026
b3222c4
chore: remove stale review-pending-prs command file
vinta Aug 16, 2026
f306208
Merge pull request #3284 from mdmintz/master
vinta Aug 16, 2026
de4a7e6
docs: fold review-prs fixes from live runs into SKILL.md
vinta Aug 16, 2026
e9d6ea7
docs: reword review-prs stale-base rationale to be rate-free
vinta Aug 16, 2026
9ffb5ab
docs: drop UV_PYTHON=3.13 pin from audit-the-list commands
vinta Aug 16, 2026
bf11114
update skill
vinta Aug 16, 2026
d4fd148
update wordings
vinta Aug 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"permissions": {
"allow": [
"Bash(gh api:*)",
"Bash(gh pr close:*)",
"Bash(gh pr comment:*)",
"Bash(gh pr diff:*)",
"Bash(gh pr edit:*)",
"Bash(gh pr list:*)",
"Bash(gh pr view:*)",
"Bash(gh run list:*)",
"Bash(gh run rerun:*)",
"Bash(gh run view:*)",
"Bash(gh search:*)"
],
"deny": []
}
}
39 changes: 39 additions & 0 deletions .claude/skills/audit-the-list/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: audit-the-list
description: Audit README.md sections against the shortlist rules — re-verify every entry's verdict with live data, promote or demote challengers, restructure oversized use cases, prune, and evaluate proposed additions. Fire when the maintainer asks to audit, sweep, prune, re-check, or maintain sections, or asks whether an entry (or a proposed one) deserves its slot.
argument-hint: [all or specific sections]
---

# Audit the list

An Audit re-runs the admission test over live sections of README.md: every entry re-verified against current data, tiers reassessed, structure reconsidered, then the maintainer adjudicates and the result is committed. The rules live in CONTRIBUTING.md (Admission, Evidence, Entry Ordering) and CONTEXT.md (vocabulary) — this skill is the process that applies them, not a second copy of them. Entry changes land only on the maintainer's explicit go.

## 1. Scope

Resolve the scope from the arguments. Named sections mean exactly those, whether or not they were audited before (a re-run is how a past verdict gets rechecked). `all` is ambiguous — `AskUserQuestion` whether it means every section or only never-audited ones; prior audits are recorded in git history (`git log --oneline --grep="sweep\|audit"`). With no arguments, AskUserQuestion listing the never-audited Thematic Groups. Batch the work one Thematic Group per sitting. Done when the section list is settled.

## 2. Evidence

Fetch live evidence for every entry in scope before judging anything (CLAUDE.md verification rule):

- **Downloads/month**: `cd website && uv run python fetch_pypi_downloads_via_clickpy.py` — free keyless ClickPy sweep of the full README, sole writer of `data/pypi_downloads.tsv` (rewritten from scratch each run; header row, every row stamped with its `fetched_at` date). A cache whose `fetched_at` is within the last 7 days is current enough for verdicts — skip the sweep; older than that, re-run it (costs ~1s). Cross-checks print to stdout, take explicit names, and never touch the cache: `fetch_pypi_downloads_via_bigquery.py <name> ...` (canonical source, maintainer's own GCP account, `--dry-run` first — the docstring carries the cost constraints; full-README sweeps exceed the free tier, keep name lists small), `fetch_pypi_downloads_via_pepy.py <name> ...` (needs `PEPY_TECH_API_KEY` in repo-root `.env`, throttled to 5 requests/minute), or `https://pypistats.org/api/packages/{name}/recent` paced 8s or slower. pypistats excludes mirror/CI traffic; ClickPy, BigQuery, and pepy include it — never mix sources within one comparison.
- **Repo state**: archived flag, last push, created date, stars, description — `gh api repos/{owner}/{repo}`, GitLab API for GitLab-hosted projects.
- **PyPI metadata** (`https://pypi.org/pypi/{name}/json`) wherever a name might not be the canonical package — ownership collisions and wrong display names surface here. Wrong-package cache rows are common: the sweep looks up README display names, so when the display name differs from the canonical package, the row silently measures an unrelated squatter or a dead predecessor. When a famous entry shows a count that looks off (too small, or absurdly round), verify identity before citing it, and fetch the canonical package's count via pepy.

Done when every entry in scope has downloads (or a stated no-signal reason), repo state, and a confirmed PyPI name.

## 3. Verdicts

Draft a verdict and reason for every entry, restructure before cap: decide Splits, mints, and re-homes first — cutting before restructuring destroys entries — then apply the cap tier by tier, including promotions and demotions between obvious choice and challenger. Ground every reason in the fetched evidence; label anything unverifiable as a judgment call. Where fresh evidence contradicts the standing verdict, say so in the reason instead of silently keeping the seed.

## 4. Review and go

Run the `preview-verdicts` skill: it generates the interactive review page and defines how the maintainer's feedback JSON comes back and gets processed. Their verdicts are final. Before touching README.md, surface what the feedback implies but does not decide — cap overflows, homeless entries after a Split, tier for a tierless flip — as named assumptions or questions, then get an explicit go.

## 5. Execute

One commit per section: body lists each removal with its reason and downloads figure; restructures, tier moves, and reorders ride the same commit. Format-only outcomes (no removals) are a single style commit. `make test` before every commit, `make build` after the last one. Generic commit helpers tend to split a section audit into structural and per-subcategory commits — if that happens, squash back to one commit per section. Done when the tree is clean, tests passed before each commit, and the build count reconciles with the adjudicated changes.

## 6. Record

A conclusion that outlives the sitting goes into the repo before the audit ends: admission or evidence rules into CONTRIBUTING.md, repo process and environment facts into CLAUDE.md and AGENTS.md (kept in sync), vocabulary into CONTEXT.md. Done when nothing the next audit needs is stranded in conversation.
24 changes: 24 additions & 0 deletions .claude/skills/preview-verdicts/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: preview-verdicts
description: Generate the interactive keep/drop verdict preview (HTML page with per-row feedback controls) whenever a prune sweep, batch entry edit, or restructure needs maintainer review before touching README.md — and process the feedback JSON the maintainer pastes back.
---

# Verdict preview

Maintainer review happens through an interactive HTML page: one row per entry with your seeded verdict and reason, a Keep/Drop toggle and a reason field for the maintainer, and a **Copy feedback** button that exports only changed or commented rows as JSON. Generate the page, wait for the pasted JSON, then apply it. Entry changes land in README.md only after the review — and only on an explicit go.

## Generate the preview

1. Build the `DATA` array. A group is `[section, subcategory, rows]`; a row is `[entry, url, downloads, verdict, reason]`.
- `subcategory` may carry a note after ` — ` (rendered muted): use it for proposed splits, re-homes, or anything the maintainer should weigh for the whole group.
- `downloads` is PyPI last-month as a comma-formatted string; use `—` when no signal exists (e.g. agent skill packs), `stdlib` for standard-library modules, `fetch failed` when the lookup failed. State the fetch date in the sub-header.
- `verdict` is `keep` or `drop`, seeded from the current adjudication or dry-run.
- `reason` is plain language the maintainer reads cold — no invented shorthand. When fresh evidence contradicts the seeded verdict (a big download count on a drop, a dead repo on a keep), say so in that row's reason instead of silently changing the seed.
2. Copy `template.html` (sibling of this file) and replace the placeholders: `__TITLE__` (page title), `__SUB__` (sub-header: scope, seed provenance, fetch date, and the standing instruction to flip/comment then Copy feedback), `__KEY__` (localStorage key), `__DATA__` (the array). `__KEY__` must be unique per review — slug plus date, e.g. `awesome-python-science-2026-09-01` — because saved state under a reused key bleeds a previous review's flips into rows with the same section and entry name.
3. Write the page to `tmp/awesome-python-<slug>-preview.html` in the repo root (git-ignored; create the directory if needed), `open` it, and tell the maintainer the path and the return path: flip or comment rows (they highlight yellow), press **Copy feedback**, paste the JSON into the chat. Done when the page is open and the return path is stated.

## Process the pasted feedback

Each JSON row is `{section, subcategory, entry, my_verdict, your_verdict, reason}`. The maintainer's verdict is final — apply it, never re-argue it. An empty reason means the verdict stands unexplained; that is enough.

Before executing, surface anything the flips imply that the maintainer has not decided: a use case pushed past its cap, an entry left homeless by a proposed split, a request that is already satisfied (a no-op). Ask, then execute on their go. Done when every pasted row is either applied or surfaced back — none silently dropped.
160 changes: 160 additions & 0 deletions .claude/skills/preview-verdicts/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>__TITLE__</title>
<style>
:root {
--ink: #1c1917; --paper: #faf9f7; --muted: #78716c; --line: #e7e5e4;
--keep: #1d4ed8; --keep-bg: #eff4ff; --drop: #b42318; --drop-bg: #fdf1ef;
--changed: #fffbeb; --changed-line: #f5c518;
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--paper); color: var(--ink); font: 16px/1.5 -apple-system, "SF Pro Text", "Helvetica Neue", Arial, sans-serif; }
.wrap { padding: 2rem 2.5rem 6rem; }
h1 { font-size: 1.7rem; margin: 0 0 .3rem; }
.sub { color: var(--muted); margin: 0 0 1.6rem; font-size: 1rem; }
.sub b { color: var(--ink); }
.sub code { background: #f0eeec; padding: .1em .35em; border-radius: 4px; font-size: .92em; }
h2 { font-size: 1.35rem; margin: 2.2rem 0 .2rem; border-bottom: 2px solid var(--ink); padding-bottom: .3rem; }
h3 { font-size: 1.05rem; margin: 1.3rem 0 .4rem; color: var(--ink); }
h3 .note { font-weight: 400; color: var(--muted); font-size: .92rem; }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; font-size: .82rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); padding: .35rem .6rem; border-bottom: 1px solid var(--line); }
td { padding: .5rem .6rem; border-bottom: 1px solid var(--line); vertical-align: top; }
tr.changed td { background: var(--changed); border-bottom-color: var(--changed-line); }
td.name { white-space: nowrap; font-weight: 600; }
td.name a { color: var(--ink); text-decoration: none; border-bottom: 1px solid #c8c4c0; }
td.name a:hover { border-bottom-color: var(--ink); }
td.dl { white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--muted); text-align: right; }
td.mine { white-space: nowrap; }
.badge { display: inline-block; font-size: .78rem; font-weight: 700; letter-spacing: .03em; padding: .12em .5em; border-radius: 4px; }
.badge.keep { color: var(--keep); background: var(--keep-bg); }
.badge.drop { color: var(--drop); background: var(--drop-bg); }
td.reason { color: #44403c; font-size: .95rem; max-width: 34rem; }
td.yours { white-space: nowrap; }
.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.seg button { border: 0; background: #fff; padding: .3rem .8rem; font: inherit; font-size: .88rem; cursor: pointer; color: var(--muted); }
.seg button + button { border-left: 1px solid var(--line); }
.seg button.on.k { background: var(--keep); color: #fff; font-weight: 700; }
.seg button.on.d { background: var(--drop); color: #fff; font-weight: 700; }
td.fb input { width: 100%; min-width: 14rem; font: inherit; font-size: .92rem; padding: .3rem .5rem; border: 1px solid var(--line); border-radius: 6px; background: #fff; }
td.fb input:focus { outline: 2px solid var(--keep); outline-offset: 0; }
.bar { position: fixed; bottom: 0; left: 0; right: 0; background: var(--ink); color: #fafaf9; display: flex; align-items: center; gap: 1.4rem; padding: .7rem 2.5rem; font-size: .95rem; }
.bar .counts b { font-variant-numeric: tabular-nums; }
.bar button { font: inherit; font-weight: 700; padding: .45rem 1.1rem; border: 0; border-radius: 6px; background: #fafaf9; color: var(--ink); cursor: pointer; }
.bar button:hover { background: #e7e5e4; }
.bar .hint { color: #a8a29e; }
#out { display: none; width: 100%; height: 9rem; margin-top: 1rem; font: 13px/1.4 ui-monospace, monospace; }
</style>
</head>
<body>
<div class="wrap">
<h1>__TITLE__</h1>
<p class="sub">__SUB__</p>
<div id="app"></div>
<textarea id="out" readonly></textarea>
</div>
<div class="bar">
<span class="counts" id="counts"></span>
<button onclick="copyFeedback()">Copy feedback</button>
<span class="hint" id="hint">Copies only rows you changed or commented, as JSON.</span>
</div>
<script>
const DATA = __DATA__;

const KEY = "__KEY__";
let state = {};
try { state = JSON.parse(localStorage.getItem(KEY) || "{}"); } catch (e) {}

function rowId(section, name) { return section + "::" + name; }

function render() {
const app = document.getElementById("app");
let html = "", lastSection = "";
for (const [section, subcat, rows] of DATA) {
if (section !== lastSection) { html += `<h2>${section}</h2>`; lastSection = section; }
const parts = subcat.split(" — ");
html += `<h3>${parts[0]}${parts[1] ? ` <span class="note">— ${parts[1]}</span>` : ""}</h3>`;
html += `<table><tr><th>Entry</th><th style="text-align:right">Downloads/mo</th><th>My verdict</th><th>My reason</th><th>Yours</th><th>Your reason (optional)</th></tr>`;
for (const [name, url, dl, mine, reason] of rows) {
const id = rowId(section, name);
const s = state[id] || {};
const yours = s.verdict || mine;
const changed = yours !== mine || (s.feedback || "").trim() !== "";
html += `<tr id="${cssId(id)}" class="${changed ? "changed" : ""}">
<td class="name"><a href="${url}" target="_blank" rel="noopener">${name}</a></td>
<td class="dl">${dl}</td>
<td class="mine"><span class="badge ${mine}">${mine.toUpperCase()}</span></td>
<td class="reason">${reason}</td>
<td class="yours"><span class="seg">
<button class="k ${yours === "keep" ? "on" : ""}" onclick="setV('${esc(id)}','keep')">Keep</button>
<button class="d ${yours === "drop" ? "on" : ""}" onclick="setV('${esc(id)}','drop')">Drop</button>
</span></td>
<td class="fb"><input value="${(s.feedback || "").replace(/"/g, "&quot;")}" oninput="setF('${esc(id)}', this.value)" placeholder="why…"></td>
</tr>`;
}
html += `</table>`;
}
app.innerHTML = html;
updateCounts();
}

function cssId(id) { return "r-" + id.replace(/[^a-zA-Z0-9]/g, "_"); }
function esc(id) { return id.replace(/'/g, "\\'"); }

function setV(id, v) { state[id] = state[id] || {}; state[id].verdict = v; save(); render(); }
function setF(id, f) {
state[id] = state[id] || {}; state[id].feedback = f; save();
const [section, name] = id.split("::");
const mine = findMine(section, name);
const yours = state[id].verdict || mine;
document.getElementById(cssId(id)).className = (yours !== mine || f.trim() !== "") ? "changed" : "";
updateCounts();
}
function findMine(section, name) {
for (const [s, , rows] of DATA) if (s === section) for (const r of rows) if (r[0] === name) return r[3];
}
function save() { localStorage.setItem(KEY, JSON.stringify(state)); }

function collect() {
const out = [];
for (const [section, subcat, rows] of DATA) {
for (const [name, , , mine] of rows) {
const id = rowId(section, name);
const s = state[id] || {};
const yours = s.verdict || mine;
const fb = (s.feedback || "").trim();
if (yours !== mine || fb) out.push({ section, subcategory: subcat.split(" — ")[0], entry: name, my_verdict: mine, your_verdict: yours, reason: fb });
}
}
return out;
}

function updateCounts() {
let keeps = 0, total = 0, changed = 0;
for (const [section, , rows] of DATA) for (const [name, , , mine] of rows) {
total++;
const s = state[rowId(section, name)] || {};
const yours = s.verdict || mine;
if (yours === "keep") keeps++;
if (yours !== mine) changed++;
}
document.getElementById("counts").innerHTML = `<b>${keeps}</b> keep · <b>${total - keeps}</b> drop of <b>${total}</b> &nbsp;|&nbsp; <b>${changed}</b> verdicts flipped`;
}

function copyFeedback() {
const fb = collect();
const text = fb.length ? JSON.stringify(fb, null, 1) : "(no changes — all verdicts accepted as-is)";
const hint = document.getElementById("hint");
navigator.clipboard.writeText(text).then(
() => { hint.textContent = `Copied ${fb.length ? fb.length + " row(s)" : "acceptance note"} — paste into the chat.`; },
() => { const o = document.getElementById("out"); o.style.display = "block"; o.value = text; o.select(); hint.textContent = "Clipboard blocked — select & copy the box above."; }
);
}

render();
</script>
</body>
</html>
Loading