Modern browsers have been solving this problem for years — Datasette finally noticed.
Token-based CSRF protection requires forms to embed secrets and AJAX calls to fish them out of cookies. It's 2026 and browsers ship Sec-Fetch-Site headers that tell you exactly where a request originated. #2689 rips out the token machinery entirely and trusts the header instead. Every form just got simpler. Every plugin that posts data just lost a failure mode. The approach comes from Filippo Valsorda's writeup on modern CSRF — turns out the web platform solved this while we weren't looking.
A one-day turnaround for a breaking change nobody saw coming.
Datasette 1.0a27 introduced a new on-disk internal database to fix locking issues. It also accidentally broke every execute_write_fn() callback that didn't name its parameter exactly 'conn'. #2691 landed less than 48 hours later in 1.0a28. The same release added datasette.close() (#2693) plus a pytest plugin that calls it automatically — because plugin test suites were bleeding file descriptors after the temp-disk change. Sometimes shipping fast means shipping twice.
Testing permission logic just got dramatically less annoying.
Writing tests for Datasette plugins that check permissions meant constructing fake request objects or mocking authentication. The new actor= parameter on datasette.client methods (#2688) lets you make internal HTTP requests as any actor you want. One keyword argument replaces an entire test fixture. The change also landed a TokenRestrictions.abbreviated() helper (#2696) for building those permission dictionaries without memorizing the schema.
Because pasting the same prompt four times was getting old.
Anthropic shipped claude-opus-4-7 and suddenly @simonw's token counter needed updating. #269 adds the new model, but the real change is multi-model support — paste once, see token counts for every Claude variant simultaneously. #270 groups related models with visual styling so you're not squinting at a wall of identical names. Also this week: EXIF JSON output now wraps long lines (#267) and newsletter generation supports beats (#268).
Database-level permissions were there. Table-level permissions were hiding.
Token management showed you which databases a token could access, but table-level restrictions were invisible. #41 nests table permissions under their database headings where they belong. The plugin also switched to Datasette's new TokenHandler API (#42) from 1.0a25, which means it's ready for the CSRF changes upstream.
The --continue flag, API key validation, and three logging edge cases.
The llm repo saw no merged PRs this week, but five fixes are queued. #1409 repairs --continue so it actually resumes your most recent conversation instead of starting fresh. #1408 rejects non-ASCII characters in API keys before they cause cryptic failures downstream. The other three address logging: redacting inline file data (#1407), correctly attributing toolbox results (#1406), and deduplicating embeddings by content hash (#1405).
RSS readers were getting raw HTML. Now they get preformatted text.
The blog's markdown-copy elements were rendering as meaningless divs in Atom feeds. #662 converts them to pre tags so feed readers display code the way it was meant to be seen. A small fix, but anyone reading via RSS just got a dramatically better experience. #661 also adds a shortcut link to trigger builds from the importers admin page.
A bookmarklet for people who want their marginalia in markdown.
Kindle's web notebook shows your highlights but won't let you export them sanely. This browser extension fixes that, and #1 adds a "Copy markdown to clipboard" button so you can paste directly into Obsidian or wherever your notes live. An open PR (#2) is working on iOS support for the truly dedicated.
| llm | ★★★★★★★★★★ | 11,681 |
| datasette | ★★★★★★★★★☆ | 10,986 |
| tools | ★☆☆☆☆☆☆☆☆☆ | 1,643 |
| simonw/research | ★☆☆☆☆☆☆☆☆☆ | 621 |
| simonw | ★☆☆☆☆☆☆☆☆☆ | 432 |
| simonwillisonblog | ★☆☆☆☆☆☆☆☆☆ | 407 |
| llm-openrouter | ★☆☆☆☆☆☆☆☆☆ | 311 |
| datasette.io | ★☆☆☆☆☆☆☆☆☆ | 134 |
| scrape-hacker-news-by-domain | ★☆☆☆☆☆☆☆☆☆ | 84 |
| docs-for-llms | ★☆☆☆☆☆☆☆☆☆ | 58 |
| sf-tree-history | ★☆☆☆☆☆☆☆☆☆ | 48 |
| simonwillisonblog-backup | ★☆☆☆☆☆☆☆☆☆ | 46 |
| ollama-models-atom-feed | ★☆☆☆☆☆☆☆☆☆ | 34 |
| pge-outages | ★☆☆☆☆☆☆☆☆☆ | 23 |
| scrape-fediverse | ★☆☆☆☆☆☆☆☆☆ | 21 |
| datasette-auth-tokens | ★☆☆☆☆☆☆☆☆☆ | 14 |
| scrape-fema-shelters | ★☆☆☆☆☆☆☆☆☆ | 12 |
| scrape-florida-outages | ★☆☆☆☆☆☆☆☆☆ | 12 |
| usgs-scraper | ★☆☆☆☆☆☆☆☆☆ | 11 |
| package-stats | ★☆☆☆☆☆☆☆☆☆ | 10 |
| recent-california-brown-pelicans | ★☆☆☆☆☆☆☆☆☆ | 10 |
| scrape-faa-releasable-aircraft | ★☆☆☆☆☆☆☆☆☆ | 9 |
| scrape-roads-dot-ca-gov | ★☆☆☆☆☆☆☆☆☆ | 8 |
| scrape-github-actions-package-versions | ★☆☆☆☆☆☆☆☆☆ | 8 |
| datasette/datasette-export-database | ★☆☆☆☆☆☆☆☆☆ | 6 |
| prime-radiant-inc/kindle-highlight-exporter | ★☆☆☆☆☆☆☆☆☆ | 5 |
| free-threaded-wheels-results | ★☆☆☆☆☆☆☆☆☆ | 3 |
| usgs-demo | ★☆☆☆☆☆☆☆☆☆ | 1 |
Database-level permissions were there. Table-level permissions were hiding.
Token management showed you which databases a token could access, but table-level restrictions were invisible. #41 nests table permissions under their database headings where they belong. The plugin also switched to Datasette's new TokenHandler API (#42) from 1.0a25, which means it's ready for the CSRF changes upstream.
The --continue flag, API key validation, and three logging edge cases.
The llm repo saw no merged PRs this week, but five fixes are queued. #1409 repairs --continue so it actually resumes your most recent conversation instead of starting fresh. #1408 rejects non-ASCII characters in API keys before they cause cryptic failures downstream. The other three address logging: redacting inline file data (#1407), correctly attributing toolbox results (#1406), and deduplicating embeddings by content hash (#1405).
RSS readers were getting raw HTML. Now they get preformatted text.
The blog's markdown-copy elements were rendering as meaningless divs in Atom feeds. #662 converts them to pre tags so feed readers display code the way it was meant to be seen. A small fix, but anyone reading via RSS just got a dramatically better experience. #661 also adds a shortcut link to trigger builds from the importers admin page.
A bookmarklet for people who want their marginalia in markdown.
Kindle's web notebook shows your highlights but won't let you export them sanely. This browser extension fixes that, and #1 adds a "Copy markdown to clipboard" button so you can paste directly into Obsidian or wherever your notes live. An open PR (#2) is working on iOS support for the truly dedicated.
| llm | ★★★★★★★★★★ | 11,681 |
| datasette | ★★★★★★★★★☆ | 10,986 |
| tools | ★☆☆☆☆☆☆☆☆☆ | 1,643 |
| simonw/research | ★☆☆☆☆☆☆☆☆☆ | 621 |
| simonw | ★☆☆☆☆☆☆☆☆☆ | 432 |
| simonwillisonblog | ★☆☆☆☆☆☆☆☆☆ | 407 |
| llm-openrouter | ★☆☆☆☆☆☆☆☆☆ | 311 |
| datasette.io | ★☆☆☆☆☆☆☆☆☆ | 134 |
| scrape-hacker-news-by-domain | ★☆☆☆☆☆☆☆☆☆ | 84 |
| docs-for-llms | ★☆☆☆☆☆☆☆☆☆ | 58 |
| sf-tree-history | ★☆☆☆☆☆☆☆☆☆ | 48 |
| simonwillisonblog-backup | ★☆☆☆☆☆☆☆☆☆ | 46 |
| ollama-models-atom-feed | ★☆☆☆☆☆☆☆☆☆ | 34 |
| pge-outages | ★☆☆☆☆☆☆☆☆☆ | 23 |
| scrape-fediverse | ★☆☆☆☆☆☆☆☆☆ | 21 |
| datasette-auth-tokens | ★☆☆☆☆☆☆☆☆☆ | 14 |
| scrape-fema-shelters | ★☆☆☆☆☆☆☆☆☆ | 12 |
| scrape-florida-outages | ★☆☆☆☆☆☆☆☆☆ | 12 |
| usgs-scraper | ★☆☆☆☆☆☆☆☆☆ | 11 |
| package-stats | ★☆☆☆☆☆☆☆☆☆ | 10 |
| recent-california-brown-pelicans | ★☆☆☆☆☆☆☆☆☆ | 10 |
| scrape-faa-releasable-aircraft | ★☆☆☆☆☆☆☆☆☆ | 9 |
| scrape-roads-dot-ca-gov | ★☆☆☆☆☆☆☆☆☆ | 8 |
| scrape-github-actions-package-versions | ★☆☆☆☆☆☆☆☆☆ | 8 |
| datasette/datasette-export-database | ★☆☆☆☆☆☆☆☆☆ | 6 |
| prime-radiant-inc/kindle-highlight-exporter | ★☆☆☆☆☆☆☆☆☆ | 5 |
| free-threaded-wheels-results | ★☆☆☆☆☆☆☆☆☆ | 3 |
| usgs-demo | ★☆☆☆☆☆☆☆☆☆ | 1 |
Your GitHub week, turned into something worth reading.
Generate your dispatch →