Timeline
| item_type | item_date | title | body | url |
|---|---|---|---|---|
| news | 2026-09-16 | Datasette [0.65.5](https://docs.datasette.io/en/stable/changelog.html#v0-65-5) and [1.0a40](https://docs.datasette.io/en/latest/changelog.html#a40-2026-09-16) are out, with a security fix for [a table permisisons bypass](https://github.com/simonw/datasette/security/advisories/GHSA-h547-rmjf-5m2m). Datasette 1.0a40 also adds a mechanism for plugins to [run background tasks](https://docs.datasette.io/en/latest/internals.html#datasette-add-background-task). | https://datasette.io/news/2026-09-16 | |
| release | 2026-09-16 | datasette 0.65.5 | - Fixed a security issue where a trailing newline in a requested table name could bypass table permissions and expose private rows. Thanks for the report, [dpfkdlemtp](https://github.com/dpfkdlemtp). [GHSA-h547-rmjf-5m2m](https://github.com/simonw/datasette/security/advisories/GHSA-h547-rmjf-5m2m) | https://github.com/simonw/datasette/releases/tag/0.65.5 |
| release | 2026-09-16 | datasette 1.0a40 | A security fix, a new set of APIs providing background tasks for plugins, an endpoint for counting matching rows, and a collection of bug fixes. ### Security fix - Fixed a security issue where a trailing newline in a requested table name could bypass table permissions and expose private rows. Thanks for the report, [dpfkdlemtp](https://github.com/dpfkdlemtp). [GHSA-h547-rmjf-5m2m](https://github.com/simonw/datasette/security/advisories/GHSA-h547-rmjf-5m2m) ### Background tasks Datasette plugins can now use **background tasks** to run code independent of the Datasette request/response cycle. - New [.add\_background\_task(func, name=None)](https://docs.datasette.io/en/latest/internals.html#datasette-add-background-task) API: plugins register supervised, long-lived background work - typically from a `startup` hook - and these will be launched after every `startup`hook has run. Tasks are cancelled (with a five-second grace period) on shutdown. - New `/-/tasks` JSON debug endpoint lists every supervised background task and its state, in the style of `/-/threads`. See [/-/tasks](https://docs.datasette.io/en/latest/introspection.html#jsondataview-tasks). It requires the `permissions-debug` permission. - New [shutdown(datasette)](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-shutdown) plugin hook, called during graceful shutdown (Ctrl-C, `SIGTERM`) before background tasks are cancelled and before database connections are closed. It is not called on a hard kill (`SIGKILL`). - Plugin `asgi_wrapper` middleware now always runs *after* startup has completed. - If your plugin uses `asgi_wrapper` to start background tasks on the first incoming request, you should migrate to `datasette.add_background_task()` instead. [datasette-cron](https://datasette.io/plugins/datasette-cron) and [datasette-enrichments](https://datasette.io/plugins/datasette-enrichments) are being migrated to this pattern. ### Other features - New [POST count endpoint](https://docs.datasette.io/en/latest/json_api.… | https://github.com/simonw/datasette/releases/tag/1.0a40 |
| release | 2026-09-13 | shot-scraper 1.12 | - WebP support, including different quality settings e.g. `shot-scraper http://www.example.com/ -o shot.webp --quality 80`. WebP filesizes should be significantly smaller than both JPEG and PNG for many web pages. #209 - Fix local file URI handling for WebKit. Thanks, [Xi Qin](https://github.com/QinXi-ai). #208 | https://github.com/simonw/shot-scraper/releases/tag/1.12 |
| release | 2026-09-12 | sqlite-http v0.1.2-alpha.1 | https://github.com/asg017/sqlite-http/releases/tag/v0.1.2-alpha.1 | |
| release | 2026-09-12 | sqlite-http v0.1.2-alpha.2 | https://github.com/asg017/sqlite-http/releases/tag/v0.1.2-alpha.2 | |
| release | 2026-09-12 | sqlite-http v0.1.2-alpha.3 | https://github.com/asg017/sqlite-http/releases/tag/v0.1.2-alpha.3 | |
| release | 2026-09-12 | sqlite-http v0.1.2-alpha.4 | https://github.com/asg017/sqlite-http/releases/tag/v0.1.2-alpha.4 | |
| release | 2026-09-12 | sqlite-http v0.1.2 | - Improved release assets using https://github.com/asg017/sqlite-dist - Fix for https://github.com/asg017/sqlite-http/issues/35 , thank you @ephraimstevens! | https://github.com/asg017/sqlite-http/releases/tag/v0.1.2 |
| blog | 2026-09-11 | Datasette 1.0a39 and 0.65.4 security releases | We have two big security updates for Datasette today - one for the 1.0 alpha series and another for the 0.65.x stable release: | https://datasette.io/blog/2026/september-security-releases/ |
| release | 2026-09-11 | datasette 1.0a39 | See [0.65.4](https://docs.datasette.io/en/stable/changelog.html#v0-65-4) for fixes that have been backported to the stable 0.65.x branch. The Datasette blog [has more details on these releases](https://datasette.io/blog/2026/september-security-releases/). Some of the security fixes include: - Table and view permission checks now take SQLite's case-insensitive names into account. See [How permissions are resolved](https://docs.datasette.io/en/latest/authentication.html#authentication-permissions-explained). - Viewing a full-text search index table now checks you have permission to view the table from which it draws its content. - Viewing SQLite statistics tables (`sqlite_stat1` through `sqlite_stat4`) is now denied by a default. - Table schema display now obeys the `view-table` permission. - Table filters using `?_through=` require permission to view the intermediate table. - Foreign-key target and suggestion APIs, incoming foreign-key relationships and their row counts now respect `view-table` permission. - Row endpoints check permissions before resolving primary keys, to avoid revealing the existence of an otherwise invisible primary key. - Improved permission checks for the create-table API. See [The JSON write API](https://docs.datasette.io/en/latest/json_api.html#json-api-write). - The write SQL interface now checks `view-table` permission for tables referenced by `CREATE VIEW` statements. - Fixed SQL identifier escaping for column names from untrusted database schemas. - Fixed HTML escaping for column names from untrusted database schemas. - URL columns now render links only for validated HTTP or HTTPS URLs. - Private and personalized dynamic responses now use `Cache-Control: private, no-store`. Anonymous dynamic responses vary by `Cookie` and `Authorization`. - Actor cookies now respect `expire_after`. - Restricted actors can no longer create API tokens. - Stored-query create, edit and delete forms now block framing to prevent clickjacking. - Configur… | https://github.com/simonw/datasette/releases/tag/1.0a39 |
| release | 2026-09-11 | datasette 0.65.4 | This release includes security fixes for permissions, SQL construction and caching, backported to the stable 0.65.x branch. See [1.0a39](https://docs.datasette.io/en/latest/changelog.html#v1-0-a39) for the full set of security fixes and other improvements in the 1.0 alpha series. The Datasette blog [has more details on these releases](https://datasette.io/blog/2026/september-security-releases/). Some of the security fixes include: - Table and view permission checks now take SQLite's case-insensitive names into account. See [Controlling access to specific tables and views](https://docs.datasette.io/en/stable/authentication.html#authentication-permissions-table). - Table filters using `?_through=` require permission to view the intermediate table. - Fixed SQL identifier escaping for primary-key column names from untrusted database schemas, including row lookups and pagination. - Full-text search index detection now uses parameterized SQL and treats wildcard characters in table names literally. - Private and personalized dynamic responses now use `Cache-Control: private, no-store`. Anonymous dynamic responses vary by `Cookie` and `Authorization`. - SQLite extension loading is disabled after extensions supplied using `--load-extension` have been loaded. ### Other improvements and fixes - Backported the non-blocking write task ID fixes from [#2861](https://github.com/simonw/datasette/issues/2861) by [Zain Dana Harper (HarperZ9)](https://github.com/HarperZ9). `execute_write_fn(block=False)` now returns a unique UUID for each call, including when `num_sql_threads=0`. | https://github.com/simonw/datasette/releases/tag/0.65.4 |
| release | 2026-09-11 | github-to-sqlite 2.9.1 | - Fix for compatibility with [sqlite-utils 4.x](https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-2). #85 | https://github.com/dogsheep/github-to-sqlite/releases/tag/2.9.1 |
| release | 2026-09-11 | datasette-publish-fly 1.4 | - Sets `force_https=true` in `fly.toml`. #31 - Fix for Volume could not be found bug. #32 - Compatible with app-scoped deploy tokens. #34 | https://github.com/simonw/datasette-publish-fly/releases/tag/1.4 |
| release | 2026-09-07 | llm 0.35 | - New OpenAI model: `gpt-6-astra` for [GPT-6 Astra](https://openai.com/index/gpt-6-astra/). | https://github.com/simonw/llm/releases/tag/0.35 |
| release | 2026-09-02 | llm 0.34 | New features: - `llm logs --usage` Markdown output now includes the response duration in milliseconds and as a human-readable duration. `llm logs --short` includes a new `duration_ms` field. [#1653](https://github.com/simonw/llm/issues/1653) Bug fixes: - Significantly improved the performance of `llm logs` for long conversations by caching repeated message and model lookups. [#1654](https://github.com/simonw/llm/issues/1654) - Dynamically generated OpenAI options classes are now cached, avoiding repeated Pydantic class construction by plugins such as `llm-openrouter`. Thanks, [waveplate](https://github.com/waveplate). [#1651](https://github.com/simonw/llm/pull/1651) - Invalid schema DSL passed to `llm prompt --schema` now produces a clean command-line error instead of a Python traceback. Thanks, [ikatyal2110](https://github.com/ikatyal2110). [#1647](https://github.com/simonw/llm/pull/1647) - `llm --extract` now recognizes fenced code blocks in responses that use CRLF line endings. Thanks, [mameikagou](https://github.com/mameikagou). [#1644](https://github.com/simonw/llm/pull/1644) - `monotonic_ulid()` now remains monotonic if the system clock moves backwards or concurrent calls observe timestamps out of order. Thanks, [Dylan Pulver](https://github.com/dylanpulver). [#1641](https://github.com/simonw/llm/pull/1641) - Declared the `typing-extensions` package as a direct dependency, and added tests to protect against accidental missing dependencies. Thanks, [Vansh Taneja](https://github.com/vanshtaneja23). [#1622](https://github.com/simonw/llm/pull/1622) | https://github.com/simonw/llm/releases/tag/0.34 |
| release | 2026-08-22 | llm 0.33 | New features: - Upgraded to the OpenAI Python library 3.x and switched the HTTP client dependency from `httpx` to `httpx2`. [#1608](https://github.com/simonw/llm/issues/1608), [#1631](https://github.com/simonw/llm/pull/1631) - `llm embed` and `llm embed-multi` now accept `--key`. The Python `EmbeddingModel.embed()`, `EmbeddingModel.embed_multi()`, `Collection.embed()` and `Collection.embed_multi()` methods accept `key=` too, passing the resolved per-call key to embedding plugins without changing shared model state. Existing plugins that read `self.key` continue to work through a compatibility fallback. Thanks, [ChrisJr404](https://github.com/ChrisJr404). [#757](https://github.com/simonw/llm/issues/757), [#1620](https://github.com/simonw/llm/pull/1620) - `llm logs` now includes the output of server-side tool calls, shown in a **Tool results** section within the response. These results are also included in `llm logs --json` and `llm logs --short` output, with a new `server_executed` key distinguishing them from locally executed tool results. [#1629](https://github.com/simonw/llm/issues/1629) - `llm prompt -t/--template` can now be repeated to combine templates in order. This allows model configuration and options from one template to be used with a prompt from another. - Expanded the `llm prompt --help` documentation for `--schema` and `--schema-multi` with details and examples of the supported schema DSL. - `schema_dsl()` now raises descriptive `ValueError` exceptions for unknown field types and duplicate field names, instead of silently treating unknown types as strings or overwriting earlier fields. [#1607](https://github.com/simonw/llm/issues/1607), [#1616](https://github.com/simonw/llm/issues/1616) - Reasoning stream events that contain provider metadata but no text are now preserved as `ReasoningPart` objects. This allows opaque state such as Anthropic signatures and redacted thinking data to round-trip correctly. [simonw/llm-anthropic#81](https://github.com/simonw/llm-anthropic/issues/81) - Reasoni… | https://github.com/simonw/llm/releases/tag/0.33 |
| release | 2026-08-21 | llm 0.32.1 | This version pins LLM to use OpenAI Python versions less than [v3.0.0](https://github.com/openai/openai-python/releases#release-v3.0.0), ensuring fresh LLM installations work without needing to also install an extra `httpx` dependency. [#1630](https://github.com/simonw/llm/pull/1630) | https://github.com/simonw/llm/releases/tag/0.32.1 |
| release | 2026-08-13 | sqlite-utils 4.2 | - New `table.checks`, `table.column_checks` and `table.table_checks` introspection properties expose column-level and table-level `CHECK` constraints. ([#834](https://github.com/simonw/sqlite-utils/issues/834)) - New `sqlite_utils.ANY` marker type for creating and introspecting SQLite `ANY` columns. The Python API and CLI can create, add and transform these columns, and `table.transform()` and `table.extract()` now preserve `ANY` columns and their values in `STRICT` tables. ([#790](https://github.com/simonw/sqlite-utils/issues/790)) - `table.default_values` now unescapes doubled single quotes in string defaults, so a default such as `'O''Brien'` is returned as `"O'Brien"`. Thanks, [ikatyal2110](https://github.com/ikatyal2110). ([#811](https://github.com/simonw/sqlite-utils/pull/811)) - `table.default_values` now decodes unquoted `TRUE`, `FALSE` and `NULL` default literals as `True`, `False` and `None` respectively. ([#836](https://github.com/simonw/sqlite-utils/issues/836)) - `table.enable_fts(..., tokenize=...)` and `sqlite-utils enable-fts --tokenize` now safely quote the tokenizer argument, preventing a crafted value from injecting additional SQL. Thanks, [Bunlong Heng](https://github.com/bunlongheng). ([#828](https://github.com/simonw/sqlite-utils/pull/828)) - `rows_where()`, `pks_and_rows_where()`, `search()` and `search_sql()` now support `offset=` without requiring `limit=`. The `sqlite-utils rows --offset` option now works without `--limit` too. Thanks, [ethanhawkes-gif](https://github.com/ethanhawkes-gif). ([#816](https://github.com/simonw/sqlite-utils/issues/816), [#821](https://github.com/simonw/sqlite-utils/pull/821)) - Empty or whitespace-only input passed to `rows_from_file()` is now handled as an empty CSV file instead of raising `csv.Error`. Thanks, [Rami Abdelrazzaq](https://github.com/RamiNoodle733). ([#808](https://github.com/simonw/sqlite-utils/issues/808), [#837](https://github.com/simonw/sqlite-utils/pull/837)) - `sqlite-utils convert --dry-run` now works for table and column names co… | https://github.com/simonw/sqlite-utils/releases/tag/4.2 |
| release | 2026-08-13 | sqlite-utils 4.2.1 | - Fix for `No module named 'typing_extensions'` crashing bug accidentally shipped in version 4.2. #842 | https://github.com/simonw/sqlite-utils/releases/tag/4.2.1 |
| release | 2026-08-11 | datasette-public 0.4a2 | - Upgraded for compatability with Datasette 1.0a37. | https://github.com/datasette/datasette-public/releases/tag/0.4a2 |
| release | 2026-08-11 | datasette-upload-dbs 0.5a0 | - Documented API for uploading files. #2 - No longer depends on Starlette for file uploads. #13 - Fixed a bug where a corrupt SQLite database could still be swapped in. | https://github.com/simonw/datasette-upload-dbs/releases/tag/0.5a0 |
| release | 2026-08-06 | datasette 0.65.3 | This release fixes a **SQL injection** security issue that affects Datasette instances that serve a **mixture of public and private tables** in the same database, with access configured using the [Datasette permissions system](https://docs.datasette.io/en/stable/authentication.html). Site administrators who serve private tables in this way are advised to disable the [execute-sql permission](https://docs.datasette.io/en/stable/authentication.html#execute-sql) on that database to prevent users from accessing private tables using raw SQL queries. The bug that has been fixed would have allowed users with access to any public table to execute SQL injection attacks despite that restriction, giving them read-only access to data in private tables in the same database. This fix is also available in Datasette 1.0a38. | https://github.com/simonw/datasette/releases/tag/0.65.3 |
| release | 2026-08-06 | datasette 1.0a38 | This release fixes a **SQL injection** security issue that affects Datasette instances that serve a **mixture of public and private tables** in the same database, with access configured using the [Datasette permissions system](https://docs.datasette.io/en/latest/authentication.html). Site administrators who serve private tables in this way are advised to disable the [execute-sql permission](https://docs.datasette.io/en/latest/authentication.html#execute-sql) permission on that database to prevent users from accessing private tables using raw SQL queries. The bug that has been fixed would have allowed users with access to any public table to execute SQL injection attacks despite that restriction, giving them read-only access to data in private tables in the same database. This fix is also available in Datasette 0.65.3. | https://github.com/simonw/datasette/releases/tag/1.0a38 |
| release | 2026-08-06 | datasette-auth-tokens 0.4a13 | - Fix for `sqlite-utils` 4.0. Thanks, [Alex Garcia](https://github.com/asg017). #44 | https://github.com/simonw/datasette-auth-tokens/releases/tag/0.4a13 |
| release | 2026-08-04 | llm 0.32 | LLM 0.32 is a major, backwards-compatible update to the way prompts, responses, tools and logs are represented. It adds structured messages and parts throughout the Python API, adopts the OpenAI Responses API for reasoning-capable models, substantially expands control over pausable and resumable tool loops and introduces a new content-addressed SQLite logging schema. Reasoning traces are now displayed on standard error by the `llm` command, for models that support them. ### Structured messages and richer responses Prompt inputs and model outputs are now represented as lists of `Message` objects, each containing typed `Part` objects for text, reasoning, tool calls, tool results and attachments. - New [messages= keyword argument](https://llm.datasette.io/en/stable/python-api.html#python-api-messages) on the prompt, conversation and chain APIs, including their asynchronous equivalents. For example, `model.prompt(messages=[llm.user("Hello"),llm.assistant("Hi!"), llm.user("What can you do?")])`. Existing `prompt=`, `system=`, `attachments=` and `tool_results=` arguments continue to work and are converted into the same structured representation. - New [structured streaming methods](https://llm.datasette.io/en/stable/python-api.html#python-api-messages) `response.stream_events()` and `response.astream_events()`expose mixed streams of text, reasoning, tool calls and tool results. Iterating over a response directly continues to yield text strings. - `response.messages()` returns the assembled structured output. `response.reply()` continues from any response and can automatically execute pending tool calls before the next turn. - `response.to_dict()` and `Response.from_dict()` provide JSON-safe persistence of complete turns, including reasoning and provider metadata, with matching `TypedDict` definitions in the new `llm.serialization` module. - `response.prompt.messages` is now the canonical record of exactly what was sent to the model, including the full preceding conversation chain. These APIs were … | https://github.com/simonw/llm/releases/tag/0.32 |
| release | 2026-07-30 | llm 0.32rc1 | This release candidate for 0.32 introduces a new database schema for logging prompts and responses that captures full details of the interaction with the underlying LLM, and de-duplicates those records using a **content-addressed message store**. Upgrading to this RC will create those new tables and start logging to them. Existing data in the `responses` table will be left unaffected, and the `logs` command will read from both old and new tables. New interactions will only be written to the new tables. You can create a backup of your logs database prior to upgrading using: llm logs backup logs-backup.db ### Changes to SQLite logging - See [the message store documentation](https://llm.datasette.io/en/latest/logging.html#logging-message-store) for details of the new logging schema. - `llm prompt` logs are now written to a new set of tables, not the legacy tables. - New documented [Response.log_to_db()](https://llm.datasette.io/en/latest/logging.html#logging-message-store-python) Python API for writing to a SQLite logs database. - `llm logs` now reads both generations of log tables: history recorded by older versions of LLM in the legacy `responses` table is merged into the output alongside new turns, with rows from the dual-write era deduplicated by id. The `-m`, `-c`, `-f`, `-T`, `--tools` and `--schema` filters work across both. [#1562](https://github.com/simonw/llm/pull/1562) - Raw provider payloads (the old `prompt_json` and `response_json` columns) are no longer persisted - the stored message chain is the record of what was sent and returned. This means data that only ever lived in those raw payloads is no longer stored, notably the log probabilities returned by OpenAI completion models with `-o logprobs`. - `llm logs -q` full-text search works against the new log tables. Search covers the prompt text you typed and the model's text responses - system prompts, fragment contents, tool activity and reasoning traces are excluded from the index. See [Searching the logs](https://llm.datasette… | https://github.com/simonw/llm/releases/tag/0.32rc1 |
| release | 2026-07-30 | llm 0.32rc2 | - The default model for users who have not set their own default is now [GPT-5.6 Luna](https://developers.openai.com/api/docs/models/gpt-5.6-luna). It was previously [GPT-4o mini](https://developers.openai.com/api/docs/models/gpt-4o-mini). Luna is a much better and more recent model, albeit slightly more expensive - $0.20 per million input tokens and $1.20 per million output tokens, compared to $0.15/$0.60 for 4o mini. You can switch back to 4o mini using `llm models default gpt-4o-mini`, or switch to [GPT-5 nano](https://developers.openai.com/api/docs/models/gpt-5-nano), an even cheaper default model ($0.05/$0.40), using `llm models default gpt-5-nano`. [#1576](https://github.com/simonw/llm/issues/1576) - New [llm openai endpoint](https://llm.datasette.io/en/latest/other-models.html#openai-endpoint) command for running prompts, chats and model listings against arbitrary OpenAI-compatible endpoints without first configuring a model. These calls are not logged. [#1565](https://github.com/simonw/llm/issues/1565) - No longer depends on [sqlite-migrate](https://github.com/simonw/sqlite-migrate), since that functionality is now handled by [sqlite-utils 4.0](https://sqlite-utils.datasette.io/en/stable/changelog.html#v4-0). [#1577](https://github.com/simonw/llm/issues/1577) - Fixed a bug where server-executed tool calls were incorrectly reported as pending by `LogStore.pending_tool_calls()`. Thanks, [ikatyal2110](https://github.com/ikatyal2110). [#1574](https://github.com/simonw/llm/issues/1574) - `schema_dsl()` now raises a descriptive `ValueError` instead of an `IndexError` for malformed fields with no name before the colon. [#1466](https://github.com/simonw/llm/issues/1466) | https://github.com/simonw/llm/releases/tag/0.32rc2 |
| release | 2026-07-26 | sqlite-utils 3.39.1 | - Fixed a bug where `table.delete_where()` left the connection in an open transaction, causing deleted rows to be silently restored when the connection was closed. #815 | https://github.com/simonw/sqlite-utils/releases/tag/3.39.1 |
| release | 2026-07-15 | datasette-backup 0.1.1 | - Compatible with latest Datasette. | https://github.com/simonw/datasette-backup/releases/tag/0.1.1 |
| release | 2026-07-14 | datasette 1.0a37 | Performance improvement for SQL-backed permission checks, plus an improved permission debugging interface. - SQL used to resolve permission checks now aggregates permission rules before joining them to resources, improving performance on instances with large schemas. ([#2832](https://github.com/simonw/datasette/issues/2832)) - The [Permission check view](https://docs.datasette.io/en/latest/authentication.html#permissioncheckview) permission debugger now explains why a decision was allowed or denied, including the matching rules. The interactive form can also test a hypothetical actor supplied as JSON, and the [permissions documentation](https://docs.datasette.io/en/latest/authentication.html#authentication-permissions-explained) now describes resolution rules in more detail. ([#2841](https://github.com/simonw/datasette/issues/2841)) - [db.execute\_write(sql, ..., transaction=True)](https://docs.datasette.io/en/latest/internals.html#database-execute-write) has a new `transaction=` parameter, which can be set to `False` for statements such as `VACUUM` that cannot run inside a transaction. Write tasks now start their transactions using `BEGIN IMMEDIATE`, which also ensures that writes are rolled back if the task fails. ([#2831](https://github.com/simonw/datasette/issues/2831)) - Refreshing a database's schema in Datasette's internal catalog is now performed as a single atomic operation. ([#2831](https://github.com/simonw/datasette/issues/2831)) - Fixed schema introspection, table pages, facets and table counts for tables with names containing a `]` character. Thanks, [TowyTowy](https://github.com/TowyTowy). ([#2431](https://github.com/simonw/datasette/issues/2431), [#2846](https://github.com/simonw/datasette/pull/2846)) - `/-/plugins.json` once again returns a top-level JSON array of plugin objects, reverting the object envelope introduced in 1.0a36. This should fix a large number of trivial test failures in existing plugins. ([#2842](https://github.com/simonw/datasette/issues/2842), [#2843](https://github.c… | https://github.com/simonw/datasette/releases/tag/1.0a37 |
| release | 2026-07-14 | datasette-block-robots 1.1.1 | - Switch to `pyproject.toml`. | https://github.com/simonw/datasette-block-robots/releases/tag/1.1.1 |
| release | 2026-07-12 | sqlite-utils 4.1.1 | - `table.transform()` now raises a `TransactionError` if called while a transaction is open with `PRAGMAforeign_keys` enabled and the table is referenced by foreign keys with destructive `ON DELETE` actions - `CASCADE`, `SET NULL` or `SET DEFAULT`. The pragma cannot be changed inside a transaction, so previously dropping the old table as part of the transform could fire those actions and silently delete or modify referencing rows. See [Foreign keys and transactions](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-transform-foreign-keys-transactions) for details and workarounds. ([#794](https://github.com/simonw/sqlite-utils/issues/794)) - The [CLI](https://sqlite-utils.datasette.io/en/stable/cli.html) and [Python API](https://sqlite-utils.datasette.io/en/stable/python-api.html) documentation now cross-reference each other: CLI sections link to the equivalent Python API functionality and Python API sections link back to the corresponding CLI command. ([#791](https://github.com/simonw/sqlite-utils/issues/791)) | https://github.com/simonw/sqlite-utils/releases/tag/4.1.1 |
| release | 2026-07-12 | shot-scraper 1.11 | - `server:` processes used by `shot-scraper multi` and `shot-scraper video` now wait up to 30 seconds for the target URL to accept connections, polling for port availability and replacing the previous fixed one-second delay. #197 - The `shot-scraper`, `pdf`, `html`, `accessibility` and `har` commands now have a `--js-file` option for loading JavaScript from a local file, standard input or `gh:username/script`, as an alternative to `--javascript`which accepts the string of JavaScript directly as an argument. #192 - `shot-scraper multi` supports the equivalent `js_file:` YAML key. - The `shot-scraper javascript` and `shot-scraper html` commands now have a `--timeout` option for consistency with other commands. #118 | https://github.com/simonw/shot-scraper/releases/tag/1.11 |
| release | 2026-07-11 | sqlite-utils 4.1 | - `sqlite-utils insert` and `sqlite-utils upsert` now accept a `--code` option for [providing a block of Python code](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-insert-code) (or a path to a `.py` file) that defines a `rows()` function or `rows` iterable of rows to insert, as an alternative to importing from a file. ([#684](https://github.com/simonw/sqlite-utils/issues/684)) - `sqlite-utils insert` and `sqlite-utils upsert` now accept `--type column-name type` to [override the type automatically chosen when the table is created](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-insert-csv-tsv-column-types). This is useful for CSV or TSV columns such as ZIP codes that look like integers but should be stored as `TEXT` to preserve leading zeros. ([#131](https://github.com/simonw/sqlite-utils/issues/131)) - New `table.drop_index(name)` method and `sqlite-utils drop-index` command for dropping an index by name. Both accept `ignore=True`/`--ignore` to ignore a missing index. ([#626](https://github.com/simonw/sqlite-utils/issues/626)) - `sqlite-utils query` can now read the SQL query from standard input by passing `-` in place of the query, for example `echo "select * from dogs" | sqlite-utils query dogs.db -`. ([#765](https://github.com/simonw/sqlite-utils/issues/765)) - `sqlite-utils upsert` can now infer the primary key of an existing table, so `--pk` can be omitted when upserting into a table that already has a primary key. - `table.transform()` and `table.transform_sql()` now accept `strict=True` or `strict=False` to change a table’s [SQLite strict mode](https://www.sqlite.org/stricttables.html). Omitting the option preserves the existing mode. ([#787](https://github.com/simonw/sqlite-utils/issues/787)) - The `sqlite-utils transform` command now accepts `--strict` and `--no-strict` to change a table’s strict mode. ([#787](https://github.com/simonw/sqlite-utils/issues/787)) | https://github.com/simonw/sqlite-utils/releases/tag/4.1 |
| release | 2026-07-09 | llm 0.31.1 | - Fix for a bug with OpenAI Chat Completion endpoints where a tool call with empty arguments could result in a JSON error from some providers. [#1521](https://github.com/simonw/llm/issues/1521) | https://github.com/simonw/llm/releases/tag/0.31.1 |
| release | 2026-07-07 | sqlite-utils 4.0rc4 | - **Breaking change**: `table.extract()` - and the `sqlite-utils extract` command - no longer extract rows where every extracted column is `null`. Those rows now keep a `null` value in the new foreign key column instead of pointing at an all-`null` record in the lookup table. When extracting multiple columns, rows are still extracted if at least one of the columns has a value. ([#186](https://github.com/simonw/sqlite-utils/issues/186)) - The `extracts=` option to `table.insert()` and friends no longer creates a lookup table record for `None` values - the column value stays `null`. Previously every batch of inserted rows containing a `None` value would add a duplicate `null` record to the lookup table. - Fixed a bug where `table.lookup()` inserted a duplicate row on every call if any of the lookup values were `None`. Lookup values are now compared using `IS` so that `None` values match existing rows correctly. - JSON output from the command-line tool no longer escapes non-ASCII characters, so `sqlite-utils data.db "select '日本語' as text"` now outputs `[{"text": "日本語"}]`. This matches how values were already stored by `insert` and how CSV/TSV output already behaved. A new `--ascii` option restores the previous behavior of escaping non-ASCII characters, for output destinations that cannot handle UTF-8 - see [Unicode characters in JSON](https://sqlite-utils.datasette.io/en/latest/cli.html#cli-query-json-ascii). The option is available on the `query`, `rows`, `search`, `tables`, `views`, `triggers`, `indexes` and `memory` commands. The `convert --multi --dry-run` preview and `plugins` output also no longer escape non-ASCII characters. ([#625](https://github.com/simonw/sqlite-utils/issues/625)) - `--no-headers` now omits the header row from `--fmt` and `--table` output, not just CSV and TSV output. ([#566](https://github.com/simonw/sqlite-utils/issues/566)) - `table.insert_all(..., pk=...)` now raises `InvalidColumns` if `pk=` names columns that do not exist in an existing table. Previously this behaved inconsisten… | https://github.com/simonw/sqlite-utils/releases/tag/4.0rc4 |
| release | 2026-07-07 | sqlite-utils 4.0 | The 4.0 release includes some minor backwards-incompatible fixes (hence the major version number bump) and introduces three major new features: - [Database migrations](https://sqlite-utils.datasette.io/en/stable/migrations.html#migrations), providing a structured mechanism for evolving a project’s schema over time. ([#752](https://github.com/simonw/sqlite-utils/issues/752)) - [Nested transaction support](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-atomic) via `db.atomic()`, plus numerous improvements to how transactions work across the library. ([#755](https://github.com/simonw/sqlite-utils/issues/755)) - Support for [compound foreign keys](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-compound-foreign-keys), including creation, transformation and introspection through [table.foreign\_keys](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-introspection-foreign-keys). ([#594](https://github.com/simonw/sqlite-utils/issues/594)) Other notable changes include: - Upserts now use SQLite’s `INSERT ... ON CONFLICT ... DO UPDATE SET` syntax, detect existing table primary keys automatically and reject records that are missing required primary key values. ([#652](https://github.com/simonw/sqlite-utils/issues/652)) - `db.query()` now executes immediately and rejects statements that do not return rows; use `db.execute()` for writes and DDL. - CSV and TSV imports now detect column types by default, while inserts into existing tables preserve those tables’ column types. ([#679](https://github.com/simonw/sqlite-utils/issues/679)) - Foreign key handling now preserves `ON DELETE`/`ON UPDATE` actions during transforms and resolves referenced primary keys more accurately. ([#530](https://github.com/simonw/sqlite-utils/issues/530)) - Column names passed to Python API methods are now matched case-insensitively, mirroring SQLite’s own identifier behavior. ([#760](https://github.com/simonw/sqlite-utils/issues/760)) - The command-line tool now e… | https://github.com/simonw/sqlite-utils/releases/tag/4.0 |
| release | 2026-07-07 | datasette 1.0a36 | The signature features of this alpha are new UIs for **inserting multiple rows at once** (from TSV, CSV or JSON) and for **creating a table from rows**, plus a large number of small **JSON API consistency fixes** in preparation for a 1.0 stable release. - Table pages now offer an "Insert multiple rows" mode in the row insertion dialog. This accepts pasted TSV, CSV or JSON, previews the parsed rows before inserting them, validates unknown columns as data is pasted and displays omitted auto integer primary keys as `auto` in the preview. ([#2813](https://github.com/simonw/datasette/pull/2813)) - The bulk insert UI can skip rows with existing primary keys, or update existing rows and insert new rows using the existing `/<database>/<table>/-/upsert` API when the actor has both [insert-row](https://docs.datasette.io/en/latest/authentication.html#actions-insert-row) and [update-row](https://docs.datasette.io/en/latest/authentication.html#actions-update-row) permissions. ([#2813](https://github.com/simonw/datasette/pull/2813)) - The "Create table" dialog now includes a "Create table from data" mode. Paste TSV, CSV or JSON rows to preview inferred columns and types, choose the table name and primary key, then create the table and insert those rows in one step. ([#2813](https://github.com/simonw/datasette/pull/2813)) - Datasette's JSON APIs now consistently encode every `BLOB` value using the documented [binary value JSON format](https://docs.datasette.io/en/latest/binary_data.html#binary-json-format), even when the bytes could be decoded as UTF-8 text. ([#2806](https://github.com/simonw/datasette/issues/2806), [#2822](https://github.com/simonw/datasette/pull/2822)) - The insert and edit row dialogs now provide a dedicated control for `BLOB` values. Existing binary values are shown by byte size, image values under 10MB are previewed as thumbnails, and replacements can be attached, dropped or pasted into the control. ([#2806](https://github.com/simonw/datasette/issues/2806), [#2822](https://github.com/simonw/datasett… | https://github.com/simonw/datasette/releases/tag/1.0a36 |
| release | 2026-07-06 | sqlite-utils 4.0rc3 | Breaking changes: - `table.foreign_keys` now returns `ForeignKey` objects that are dataclasses rather than `namedtuple`instances, so they can no longer be unpacked or indexed as `(table, column, other_table,other_column)` tuples - access their fields by name instead. Compound (multi-column) foreign keys are now represented as a single `ForeignKey` with `is_compound=True` and populated `columns`/`other_columns` tuples, where `column` and `other_column` are `None`. Previously they were returned as one `ForeignKey` per column, misleadingly suggesting several independent foreign keys. See [Upgrading from 3.x to 4.0](https://sqlite-utils.datasette.io/en/latest/upgrading.html#upgrading-3-to-4) for details. ([#594](https://github.com/simonw/sqlite-utils/issues/594)) - Removed support for using `sqlean.py` as a drop-in replacement for the Python standard library `sqlite3` module. `sqlite-utils` will now use `pysqlite3` if it is installed, otherwise it will use `sqlite3` from the standard library. - The `db.ensure_autocommit_off()` context manager has been renamed to `db.ensure_autocommit_on()`, because the old name described the opposite of what it did. The method temporarily puts the connection into driver-level autocommit mode - by setting `isolation_level = None` \- so that statements such as `PRAGMA journal_mode=wal` can run outside of an implicit transaction. ([#705](https://github.com/simonw/sqlite-utils/issues/705)) Compound foreign key support: - Tables can now be created with compound foreign keys, by passing tuples of column names in `foreign_keys=`: `foreign_keys=[(("campus_name", "dept_code"), "departments")]`. The referenced columns default to the compound primary key of the other table. Compound keys are rendered as table-level `FOREIGN KEY` constraints in the generated schema. See [Compound foreign keys](https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-compound-foreign-keys). - `table.transform()` now preserves compound foreign keys, applying any column renames to them. Dr… | https://github.com/simonw/sqlite-utils/releases/tag/4.0rc3 |
| release | 2026-07-05 | sqlite-utils 4.0rc2 | Breaking changes: - Write statements executed with `db.execute()` are now committed automatically, unless a transaction is already open in which case they join it. Previously they opened an implicit transaction that stayed open until something committed it - writes appeared to work when read on the same connection but were silently rolled back when the connection closed. Code that relied on rolling back uncommitted `db.execute()` writes should use the new `db.begin()` method to open an explicit transaction first. The transaction model is documented in full at [Transactions and saving your changes](https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-transactions). - `db.query()` now executes its SQL as soon as it is called, rather than waiting until the returned generator is first iterated. Rows are still fetched lazily during iteration. SQL errors are now raised at the call site, statements such as `INSERT ... RETURNING` are executed and committed immediately without needing to iterate over their results, and passing a statement that returns no rows - previously a silent no-op - now raises a `ValueError` recommending `db.execute()` instead. A statement rejected this way is rolled back before the error is raised, so it has no effect on the database. - Python API validation errors now raise `ValueError` instead of `AssertionError`. Previously invalid arguments - such as `create_table()` with no columns, `transform()` on a table that does not exist, or passing both `ignore=True` and `replace=True` \- were rejected using bare `assert` statements, which are silently skipped when Python runs with the `-O` flag. Code that caught `AssertionError` for these cases should catch `ValueError` instead. - `table.upsert()` and `table.upsert_all()` now raise `PrimaryKeyRequired` if a record is missing a value for any primary key column, or has a value of `None` for one. Previously such records - which can never match an existing row - were quietly inserted as brand new rows, or triggered a confusing `KeyE… | https://github.com/simonw/sqlite-utils/releases/tag/4.0rc2 |
| release | 2026-06-30 | shot-scraper 1.10 | - New `shot-scraper video` command for recording WebM videos from YAML storyboards. Storyboards can define setup steps with `sh:`, `python:` and `server:`, set the viewport, show a cursor and click rings, run startup waits and JavaScript, and then record scenes made from actions including `click`, `type`, `fill`, `press`, `scroll`, `pause`, `wait_for`, `wait_for_url`, `open`, `screenshot`, `sh`, `python` and `javascript`/`js`. Use `-o/--output` to override the WebM filename and `--mp4` to also convert the recording to MP4 using `ffmpeg`. #142, #194 - `shot-scraper multi` and the new `shot-scraper video` both now fail with a non-zero exit code if `sh:` or `python:` commands fail. - `shot-scraper javascript` now has `--width` and `--height` options for setting the browser viewport before executing JavaScript. #195 | https://github.com/simonw/shot-scraper/releases/tag/1.10 |
| release | 2026-06-25 | datasette-export-database 0.3a2 | - No longer pins to exactly `datasette==1.0a27`, so it can be used with more recent Datasette releases. | https://github.com/datasette/datasette-export-database/releases/tag/0.3a2 |
| release | 2026-06-23 | datasette 1.0a35 | This release adds UI for **creating tables** and **altering tables**, to complement the insert and update row interfaces added in [1.0a34](https://docs.datasette.io/en/latest/changelog.html#v1-0-a34). - New "Create table" interface in the database actions menu, backed by the `/<database>/-/create`[JSON API](https://docs.datasette.io/en/latest/json_api.html#tablecreateview). It can define columns, primary keys, custom column types, `NOT NULL` constraints, literal defaults, expression defaults and single-column foreign keys. ([#2787](https://github.com/simonw/datasette/issues/2787)) - New "Alter table" table action and `/<database>/<table>/-/alter` [JSON API](https://docs.datasette.io/en/latest/json_api.html#tablealterview) for changing existing tables: add, rename, reorder and drop columns; change column types, defaults, `NOT NULL`constraints, primary keys and foreign keys; and rename the table. The alter table dialog also includes a "Drop table" button. ([#2788](https://github.com/simonw/datasette/issues/2788)) - New `/<database>/-/foreign-key-targets` and `/<database>/<table>/-/foreign-key-suggestions`JSON APIs for discovering valid single-column foreign key targets and suggested relationships. - New [Template context](https://docs.datasette.io/en/latest/template_context.html#template-context) documentation listing the variables available to custom templates for Datasette's core pages. Variables documented there are treated as a stable API for custom templates until Datasette 2.0. The documentation is generated from dataclass definitions next to the view code, with tests that compare the documented fields against the actual contexts rendered by the database, table, query and row pages. ([#1510](https://github.com/simonw/datasette/issues/1510), [#2127](https://github.com/simonw/datasette/issues/2127), [#1477](https://github.com/simonw/datasette/issues/1477), [#2803](https://github.com/simonw/datasette/pull/2803)) - The "Write to this database" page now includes a Create table starter template, alongside th… | https://github.com/simonw/datasette/releases/tag/1.0a35 |
| release | 2026-06-21 | sqlite-utils 4.0rc1 | - New [database migrations system](https://sqlite-utils.datasette.io/en/latest/migrations.html#migrations), incorporating functionality that was previously provided by the separate [sqlite-migrate](https://github.com/simonw/sqlite-migrate) plugin. Define migration sets using the new `sqlite_utils.Migrations`class and apply them using the `sqlite-utils migrate` command or the [migrations Python API](https://sqlite-utils.datasette.io/en/latest/migrations.html#migrations-python). ([#752](https://github.com/simonw/sqlite-utils/issues/752)) - New `db.atomic()` [context manager providing nested transaction support](https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-atomic) using SQLite transactions and savepoints. Internal multi-step operations such as `table.transform()` now use this mechanism to avoid unexpectedly committing an existing transaction. ([#755](https://github.com/simonw/sqlite-utils/issues/755)) - `Database` objects can now be [used as context managers](https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-close), automatically closing the connection when the `with` block exits. The CLI also now closes database and file handles more reliably, resolving a number of `ResourceWarning` warnings. ([#692](https://github.com/simonw/sqlite-utils/issues/692)) - The `sqlite-utils convert` command can now accept a direct callable reference such as `r.parsedate` or `json.loads --import json` as the conversion code, as an alternative to calling it explicitly with `r.parsedate(value)`. ([#686](https://github.com/simonw/sqlite-utils/issues/686)) - Fixed a bug where CSV or TSV files with only a header row could crash `sqlite-utils insert` and `sqlite-utils memory` when type detection was enabled. Thanks, [Rami Abdelrazzaq](https://github.com/RamiNoodle733). ([#702](https://github.com/simonw/sqlite-utils/issues/702), [#707](https://github.com/simonw/sqlite-utils/pull/707)) - Fixed a bug where installed plugins could be loaded while running the test suite, despite the test-mode sa… | https://github.com/simonw/sqlite-utils/releases/tag/4.0rc1 |
| blog | 2026-06-18 | Host applications inside Datasette with Datasette Apps | Today we're launching Datasette Apps, a way to create and host custom HTML applications inside your Datasette instance. | https://datasette.io/blog/2026/datasette-apps/ |
| release | 2026-06-16 | datasette 1.0a34 | The big feature in this alpha is tools to insert, edit and delete rows within the Datasette interface. These features are available on table pages, and edit and delete are also available as action items on the row page. The edit interface takes [custom column types](https://docs.datasette.io/en/latest/configuration.html#table-configuration-column-types) into account. Plugins that define their own column types can use JavaScript to customize how those column types are presented in the edit interface. - `datasette.allowed_many()` method for [resolving multiple permission checks at once](https://docs.datasette.io/en/latest/internals.html#datasette-allowed-many). ([#2775](https://github.com/simonw/datasette/pull/2775)) - Permission checks are now cached on a per-request basis, speeding up table pages with multiple plugins that check permissions in order to populate the [table actions menu](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-table-actions). - Fixed a warning about `gen.throw(*sys.exc_info())`. ([#2776](https://github.com/simonw/datasette/issues/2776)) - New default custom column type `textarea` for multi-line text content. This is rendered as a `<textarea>` input in the edit UI. - The `json` column type now implements client-side validation in the edit UI. - The [makeColumnField()](https://docs.datasette.io/en/latest/javascript_plugins.html#javascript-plugins-makecolumnfield) JavaScript plugin hook allows plugins to define custom fields in the edit interface for their custom column types. - New UI for inserting, editing, and deleting rows within Datasette. ([#2780](https://github.com/simonw/datasette/issues/2780)) - New `/<database>/<table>/-/autocomplete?q=term` [autocomplete JSON API](https://docs.datasette.io/en/latest/json_api.html#tableautocompleteview) for rapid autocomplete search against the contents of a table. This is used by the edit interface to select related rows for foreign keys. You can try it out on the `/-/debug/autocomplete` debug page. - New `/<database>… | https://github.com/simonw/datasette/releases/tag/1.0a34 |
| blog | 2026-06-11 | Datasette 1.0a33 with JSON extras in the API | The stable release of Datasette 1.0 has been in the pipeline for a long time. Today's release of 1.0a33 incorporates significant progress on one of the key blockers for that release: providing a stable, fully documented JSON API for accessing data hosted in Datasette. | https://datasette.io/blog/2026/api-extras/ |
| release | 2026-06-11 | datasette 1.0a33 | Stored queries can now be edited and deleted through the web interface, and the JSON API `?_extra=` mechanism has been extended to cover row and query pages in addition to tables. This release also fixes two security issues: a SQL injection vulnerability involving table and column names that contain `]`, and an open redirect. ### Editing and deleting stored queries The stored query page gained a "Query actions" menu with Edit this query and Delete this querylinks for actors with the necessary permissions. The owner of a query can always edit or delete it; for queries that are not private, any actor with the [update-query](https://docs.datasette.io/en/latest/authentication.html#actions-update-query) or [delete-query](https://docs.datasette.io/en/latest/authentication.html#actions-delete-query) permission can do so too. Private queries remain editable and deletable only by their owner. See [Stored queries](https://docs.datasette.io/en/latest/sql_queries.html#stored-queries) for details. ([#2735](https://github.com/simonw/datasette/issues/2735)) ### `?_extra=` support for row and query pages Row and query JSON pages now support the same `?_extra=` mechanism as table pages. Row pages can request extras such as `foreign_key_tables`, `query`, `metadata` and `database_color`; arbitrary SQL and stored query pages can request extras such as `columns`, `query`, `metadata` and `private`. The implementation was refactored into a registry of extra classes shared by all three page types. New generated reference documentation describes every `?_extra=` parameter available on table, row and query JSON pages, with example output captured from a live Datasette instance at documentation build time. See [Expanding JSON responses](https://docs.datasette.io/en/latest/json_api.html#json-api-extra) for the full list. Other improvements and fixes to the extras mechanism: - `?_extra=` values can be separated by commas as well as repeated, e.g. `?_extra=count,next_url`. Previously a comma-separated value that included … | https://github.com/simonw/datasette/releases/tag/1.0a33 |
| release | 2026-06-09 | llm 0.32a3 | Driven by the needs of [Datasette Agent](https://github.com/datasette/datasette-agent)'s human-in-the-loop `ask_user()` feature, made the following improvements to how tool calls work: - Tool implementations can declare a parameter named `llm_tool_call` in order to be passed the `llm.ToolCall` object for the current invocation. This allows them to access the current `llm_tool_call.tool_call_id`. See [Accessing the tool call from inside a tool](https://llm.datasette.io/en/latest/python-api.html#python-api-tools-llm-tool-call). [#1480](https://github.com/simonw/llm/pull/1480) - Every tool call is now guaranteed a unique `tool_call_id` - providers that do not supply one get a synthesized `tc_`-prefixed ULID. [#1481](https://github.com/simonw/llm/pull/1481) - Tools can raise a `llm.PauseChain` exception to cleanly pause the tool chain, useful for things like waiting for human approval. The exception propagates to the caller with `.tool_call` and `.tool_results` (completed sibling results) attached, and no model call is made with a placeholder result. See [Pausing a chain from inside a tool](https://llm.datasette.io/en/latest/python-api.html#python-api-tools-pause). [#1482](https://github.com/simonw/llm/pull/1482) - Failure semantics for concurrent tool execution: async sibling tool calls always run to completion before a pause or hook exception propagates. [#1482](https://github.com/simonw/llm/pull/1482) - Chains can now resume from a `messages=` history ending in unresolved tool calls: the calls are executed through the normal `before_call`/`after_call` machinery before the first model call, skipping any that already have results. The `execute_tool_calls()` method also accepts a new optional `tool_calls_list=` argument for executing an explicit list of `ToolCall` objects in place of the calls requested by the response. See [Resuming a chain with pending tool calls](https://llm.datasette.io/en/latest/python-api.html#python-api-tools-resume). [#1482](https://github.com/simonw/llm/pull/1482) - Fixed a bug where… | https://github.com/simonw/llm/releases/tag/0.32a3 |
| release | 2026-05-31 | datasette 1.0a32 | SQLite INSERT ... RETURNING clauses are now supported by `/db/-/execute-write`, plus several fixes relating to the [base_url setting](https://docs.datasette.io/en/latest/settings.html#setting-base-url). - `INSERT`/`UPDATE`/`DELETE` statements that use SQLite's `RETURNING` clause now work correctly in the new `/db/-/execute-write` interface. Datasette fetches returned rows before committing the write transaction, displays them in the HTML UI and includes them in the `"rows"` key for the JSON API response. ([#2762](https://github.com/simonw/datasette/issues/2762), [#2763](https://github.com/simonw/datasette/pull/2763)) - `Database.execute_write()` now returns an `ExecuteWriteResult` object instead of the raw `sqlite3.Cursor` returned by `conn.execute()`. The new object exposes `.rowcount`, `.lastrowid`, `.description`, `.truncated` and `.fetchall()`, and adds `return_all=` and `returning_limit=`options for controlling how rows from `RETURNING` statements are buffered. ([#2763](https://github.com/simonw/datasette/pull/2763)) - Fixed the `/-/jump` navigation search endpoint when Datasette is served with a configured `base_url`. ([#2757](https://github.com/simonw/datasette/issues/2757)) - Fixed JSON and CSV export links, plus `Link:` alternate headers, on table, row and query pages when `base_url` is configured. These could previously be prefixed twice. ([#2759](https://github.com/simonw/datasette/issues/2759)) - Fixed several other `base_url` handling bugs, including the API explorer form actions and share links, the `/-/patterns` development page, permanent redirects such as `/-` to `/-/` and database query redirects from `/<database>?sql=...` to `/<database>/-/query?sql=...`. | https://github.com/simonw/datasette/releases/tag/1.0a32 |
| blog | 2026-05-29 | SQL write queries and stored queries in Datasette 1.0a31 | With Datasette 1.0a31, Datasette now offers users with the necessary permissions the ability to both execute write queries against their database and save stored queries (renamed from "canned queries"), either privately and shared with other members of their Datasette instance. | https://datasette.io/blog/2026/sql-write-queries/ |
| release | 2026-05-29 | datasette 1.0a31 | Datasette now offers users with the necessary permissions the ability to both **execute write queries** against their database and to **save stored queries** (renamed from "canned queries") both privately and for use by other members of their Datasette instance. The ability to write is controlled by the new `execute-write-sql` permission, but the user also needs the relevant `insert-row`/`update-row`/`delete-row`/`create-table`/etc permissions for the query they are trying to execute. ### Write SQL UI - New "Write to this database" interface at `/<database>/-/execute-write` for running arbitrary writable SQL against mutable databases. The form extracts named parameters, analyzes the SQL, shows the table operations that will be attempted, includes starter templates for `INSERT`, `UPDATE` and `DELETE` statements and links to a newly inserted row when a single-row insert succeeds. This is also available as a [JSON API](https://docs.datasette.io/en/latest/json_api.html#executewriteview). ([#2742](https://github.com/simonw/datasette/issues/2742)) - Added the new [execute-write-sql](https://docs.datasette.io/en/latest/authentication.html#actions-execute-write-sql) permission for running arbitrary writable SQL. Execution is also gated by table-level permissions such as [insert-row](https://docs.datasette.io/en/latest/authentication.html#actions-insert-row), [update-row](https://docs.datasette.io/en/latest/authentication.html#actions-update-row) and [delete-row](https://docs.datasette.io/en/latest/authentication.html#actions-delete-row), and writes to attached databases are rejected. ([#2742](https://github.com/simonw/datasette/issues/2742)) - The write SQL analyzer now uses a deny-by-default model for unsupported operations. Reads from source tables require [view-table](https://docs.datasette.io/en/latest/authentication.html#actions-view-table) permission, schema changes require [create-table](https://docs.datasette.io/en/latest/authentication.html#actions-create-table), [alter-table](https://docs.datasette.i… | https://github.com/simonw/datasette/releases/tag/1.0a31 |
| blog | 2026-05-24 | The extensible "Jump to" menu in Datasette 1.0a30 | Datasette 1.0a30, released today, provides a new "Jump menu" for quickly navigating your Datasette instance, plus mechanisms for plugins to extend and customize that menu to incorporate their own custom features. | https://datasette.io/blog/2026/jump-menu/ |
| release | 2026-05-24 | datasette 1.0a30 | The "Jump to" menu, activated by hitting `/` or through the application menu, can now be extended by plugins. - New "Jump to..." menu item, always visible, for triggering the previously undocumented `/` menu. ([#2725](https://github.com/simonw/datasette/issues/2725)) - The `/` jump-to search interface now covers databases, views, canned queries and plugin-provided items in addition to tables. The endpoint backing it has been renamed from `/-/tables` to `/-/jump`. - New [jump_items_sql(datasette, actor, request)](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-jump-items-sql) plugin hook, allowing plugins to contribute additional items to the jump-to menu by returning SQL. `JumpSQL` queries run against Datasette's internal database by default, or can target another database using the optional `database=`argument. ([#2731](https://github.com/simonw/datasette/issues/2731)) - `datasette.jump.JumpSQL.menu_item()` is a shortcut for adding individual jump menu items that are not backed by resources in the internal catalog. - New [makeJumpSections()](https://docs.datasette.io/en/latest/javascript_plugins.html#javascript-plugins-makejumpsections) JavaScript plugin hook, allowing plugins to add custom blank-state sections to the jump-to menu before the user has typed a query. - Debug menu links now appear in the jump-to menu instead of the top-right app menu, with descriptions for each debug item. - Dropped Janus as a dependency, previously used to manage the write queue. This should not have any impact on plugin developers or end-users. ([#1752](https://github.com/simonw/datasette/issues/1752)) - Fixed a bug where stale tables and other related resources were not removed from `catalog_*`tables when a database was removed. ([#2723](https://github.com/simonw/datasette/issues/2723)) - New documented [datasette.fixtures.populate_fixture_database(conn)](https://docs.datasette.io/en/latest/testing_plugins.html#datasette-fixtures-populate-fixture-database) helper for creating the fixture database tab… | https://github.com/simonw/datasette/releases/tag/1.0a30 |
| blog | 2026-05-21 | Datasette Agent, an extensible AI assistant for Datasette | Today we are releasing Datasette Agent, an open source plugin for Datasette that provides an extensible AI assistant for interacting with your SQLite databases. | https://datasette.io/blog/2026/datasette-agent/ |
| blog | 2026-05-13 | Welcome to the Datasette blog | It's about time the Datasette project had its own blog. | https://datasette.io/blog/2026/new-blog/ |
| release | 2026-05-13 | datasette-comments 0.1.2.a6 | https://github.com/datasette/datasette-comments/releases/tag/0.1.2.a6 | |
| release | 2026-05-12 | llm 0.32a2 | ### Support for the OpenAI Responses API Most reasoning-capable OpenAI models now use the [`/v1/responses`](https://developers.openai.com/api/reference/responses/overview) endpoint instead of `/v1/chat/completions`. This enables interleaved reasoning across tool calls for GPT-5 class models. [#1435](https://github.com/simonw/llm/pull/1435) - New `Responses` and `AsyncResponses` model classes driving the OpenAI Responses API. The existing `Chat` and `AsyncChat` classes are unchanged so other plugins that import them keep working. - The following models now use the Responses API by default: `o1`, `o3-mini`, `o3`, `o4-mini`, `gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `gpt-5.1`, `gpt-5.2`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, `gpt-5.5` (and their pinned date variants). - Use `-o chat_completions 1` to fall back to the older `/v1/chat/completions` code path for any of these models. - Encrypted reasoning items are captured as `provider_metadata` on `ReasoningPart` objects and round-tripped back to OpenAI on subsequent turns. - Reasoning summaries are now requested with `"summary": "auto"` so visible reasoning text is streamed back where the model produces it, unless `--hide-reasoning` or `hide_reasoning=` is set. - This means OpenAI prompts run using `llm prompt` that return reasoning tokens will display those on standard error. ### CLI - New `llm -m model --options` flag to list the options supported by a given model. [#1441](https://github.com/simonw/llm/pull/1441) - The `-R/--no-reasoning` option has been renamed to `-R/--hide-reasoning`. ### Python API - New `hide_reasoning=True` keyword argument on `model.prompt()`, `conversation.prompt()`, `model.chain()`, `conversation.chain()`, and their async counterparts, exposed to model plugins as `prompt.hide_reasoning`. Model plugins can [use this to decide](https://llm.datasette.io/en/latest/plugins/advanced-model-plugins.html#advanced-model-plugins-reasoning-tokens) if they should request visible reasoning summaries from their providers. [#1442](… | https://github.com/simonw/llm/releases/tag/0.32a2 |
| release | 2026-05-12 | datasette 1.0a29 | - New `TokenRestrictions.abbreviated(datasette)` [utility method](https://docs.datasette.io/en/latest/internals.html#tokenrestrictions) for creating `"_r"` dictionaries. #2695 - Table headers and column options are now visible even if a table contains zero rows. #2701 - Fixed bug with display of column actions dialog on Mobile Safari. #2708 - Fixed bug where tests could crash with a segfault due to a race condition between `Datasette.close()` and `Datasette.close()`. #2709 | https://github.com/simonw/datasette/releases/tag/1.0a29 |
| release | 2026-04-29 | llm 0.32a0 | This alpha introduces a major backwards-compatible refactor. Models can now be prompted with a list of messages, OpenAI Chat Completions style, and the response can now be iterated over as a sequence of mixed types of content, for example reasoning tokens mixed with text tokens mixed with tool calls. For more background on this release take a look at [the annotated release notes](https://simonwillison.net/2026/Apr/29/llm/) on my blog. Prompt inputs and response outputs are now expressed as a list of `Message` objects, each containing typed `Part` objects (text, reasoning, tool calls, tool results, attachments). The `llm` CLI tool can now display reasoning tokens while executing a prompt. Plugin authors should read the expanded [Advanced model plugins](https://llm.datasette.io/en/stable/plugins/advanced-model-plugins.html#advanced-model-plugins) documentation, which now covers `StreamEvent`, consuming `prompt.messages`, and round-tripping opaque provider metadata such as Anthropic extended-thinking signatures and Gemini `thoughtSignature` values. ### Structured messages and streaming events - New `llm.Message` value type and constructor helpers `llm.user()`, `llm.assistant()`, `llm.system()`, and `llm.tool_message()` for building structured prompt inputs. The helpers accept strings, `Attachment` instances, or nested `Part` lists. - New `messages=` keyword argument on `model.prompt()`, `conversation.prompt()`, `model.chain()`, `conversation.chain()`, and their async counterparts. The `prompt=`, `system=`, `attachments=`, and `tool_results=` keywords still work and synthesize into the same `Message` list internally. - New `response.stream_events()` and `response.astream_events()` methods yielding typed `StreamEvent` objects (`type` is one of `"text"`, `"reasoning"`, `"tool_call_name"`, `"tool_call_args"`, `"tool_result"`, plus a `redacted=True` marker for opaque reasoning). Iterating against `response` directly continues to yield only text strings. - New `response.messages()` method (async: `awa… | https://github.com/simonw/llm/releases/tag/0.32a0 |
| release | 2026-04-29 | llm 0.32a1 | - Fixed a bug in 0.32a0 where tool-calling conversations were not correctly reinflated from SQLite. [#1426](https://github.com/simonw/llm/issues/1426) | https://github.com/simonw/llm/releases/tag/0.32a1 |
| release | 2026-04-24 | llm 0.31 | - New GPT-5.5 OpenAI model: `llm -m gpt-5.5`. [#1418](https://github.com/simonw/llm/issues/1418) - New option to set the [text verbosity level](https://developers.openai.com/cookbook/examples/gpt-5/gpt-5_new_params_and_tools#1-verbosity-parameter) for GPT-5+ OpenAI models: `-o verbosity low`. Values are `low`, `medium`, `high`. - New option for setting the [image detail level](https://developers.openai.com/api/docs/guides/images-vision#choose-an-image-detail-level) used for image attachments to OpenAI models: `-o image_detail low` - values are `low`, `high` and `auto`, and GPT-5.4 and 5.5 also accept `original`. - Models listed in `extra-openai-models.yaml` are now also registered as asynchronous. [#1395](https://github.com/simonw/llm/issues/1395) | https://github.com/simonw/llm/releases/tag/0.31 |
| news | 2026-04-19 | Here's a new TIL on [using SQL functions in Google Sheets to fetch data from Datasette](https://til.simonwillison.net/google-sheets/datasette-sql). | https://datasette.io/news/2026-04-19 | |
| release | 2026-04-17 | datasette-comments 0.1.2.a1 | https://github.com/datasette/datasette-comments/releases/tag/0.1.2.a1 | |
| release | 2026-04-17 | datasette-comments 0.1.2.a2 | https://github.com/datasette/datasette-comments/releases/tag/0.1.2.a2 | |
| release | 2026-04-17 | datasette-comments 0.1.2.a3 | https://github.com/datasette/datasette-comments/releases/tag/0.1.2.a3 | |
| release | 2026-04-17 | datasette-comments 0.1.2.a4 | https://github.com/datasette/datasette-comments/releases/tag/0.1.2.a4 | |
| release | 2026-04-17 | datasette 1.0a28 | - Fixed a compatibility bug introduced in 1.0a27 where `execute_write_fn()` callbacks with a parameter name other than `conn` were seeing errors. ([#2691](https://github.com/simonw/datasette/issues/2691)) - The [database.close()](https://docs.datasette.io/en/latest/internals.html#database-close) method now also shuts down the write connection for that database. - New [datasette.close()](https://docs.datasette.io/en/latest/internals.html#datasette-close) method for closing down all databases and resources associated with a Datasette instance. This is called automatically when the server shuts down. ([#2693](https://github.com/simonw/datasette/pull/2693)) - Datasette now includes a pytest plugin which automatically calls `datasette.close()` on temporary instances created in function-scoped fixtures and during tests. See [Automatic cleanup of Datasette instances](https://docs.datasette.io/en/latest/testing_plugins.html#testing-plugins-autoclose) for details. This helps avoid running out of file descriptors in plugin test suites that were written before the `Database(is_temp_disk=True)` feature introduced in Datasette 1.0a27. ([#2692](https://github.com/simonw/datasette/issues/2692)) | https://github.com/simonw/datasette/releases/tag/1.0a28 |
| release | 2026-04-17 | datasette-public 0.4a1 | - Upgraded for compatibility with [Datasette 1.0a28](https://docs.datasette.io/en/latest/changelog.html#a28-2026-04-16). - Fixed `'duplicate column name: query_name'` warning on startup. | https://github.com/datasette/datasette-public/releases/tag/0.4a1 |
| news | 2026-04-15 | [Datasette 1.0a27](https://docs.datasette.io/en/latest/changelog.html#a27-2026-04-15) changes how CSRF protection works in a way that simplifies form and API integration, and introduces a new `RenameTableEvent` for when a table is renamed by a SQL query. | https://datasette.io/news/2026-04-15 | |
| release | 2026-04-15 | datasette 1.0a27 | ### CSRF protection no longer uses CSRF tokens Datasette's token-based CSRF protection has been replaced with a mechanism based on the `Sec-Fetch-Site` and `Origin` request headers, which are [supported by all modern browsers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-Fetch-Site). See [this article by Filippo Valsorda](https://words.filippo.io/csrf/) for more details of this approach. This removes the need for CSRF tokens in forms and AJAX requests. ([#2689](https://github.com/simonw/datasette/pull/2689)) ### `RenameTableEvent` when a table is renamed Renaming a table within Datasette will now fire a new [`RenameTableEvent`](https://docs.datasette.io/en/latest/events.html#datasette.events.RenameTableEvent "datasette.events.RenameTableEvent"), which plugins can use to react by updating ACL records or re-assigning comments or other associated records to the new table name. ([#2681](https://github.com/simonw/datasette/issues/2681)) This event will not be fired if the table is renamed by SQL running in some other process. The `datasette.track_event()` method can now be called from within a write operation (using [database.execute_write()](https://docs.datasette.io/en/latest/internals.html#database-execute-write) and related methods) and the event will be fired after the write transaction has successfully committed. ([#2682](https://github.com/simonw/datasette/pull/2682)) ### Other changes - New [actor= parameter](https://docs.datasette.io/en/latest/internals.html#internals-datasette-client-actor) for `datasette.client` methods, allowing internal requests to be made as a specific actor. This is particularly useful for writing automated tests. ([#2688](https://github.com/simonw/datasette/pull/2688)) - New `Database(is_temp_disk=True)` option, used internally for the internal database. This helps resolve intermittent database locked errors caused by the internal database being in-memory as opposed to on-disk. ([#2683](https://github.com/simonw/datasette/issues/2683)) (… | https://github.com/simonw/datasette/releases/tag/1.0a27 |
| release | 2026-04-15 | datasette-export-database 0.3a1 | - Upgraded for compatibility with [Datasette 1.0a27](https://docs.datasette.io/en/latest/changelog.html#a27-2026-04-15). | https://github.com/datasette/datasette-export-database/releases/tag/0.3a1 |
| release | 2026-04-09 | datasette-gzip 0.3 | - Depend on [asgi-gzip >= 0.3](https://github.com/simonw/asgi-gzip/releases/0.3) to avoid compressing `text/event-stream`. | https://github.com/simonw/datasette-gzip/releases/tag/0.3 |
| release | 2026-04-08 | datasette-template-sql 1.0.3 | - Upgraded for compatibility with Datasette 1.0a26+ | https://github.com/simonw/datasette-template-sql/releases/tag/1.0.3 |
| release | 2026-04-08 | dogsheep-beta 0.11 | - Upgrade for compatibility with Datasette 1.0 alphas. | https://github.com/dogsheep/dogsheep-beta/releases/tag/0.11 |
| release | 2026-04-08 | datasette-atom 0.10a0 | - Compatible with Datasette 1.0 alphas. | https://github.com/simonw/datasette-atom/releases/tag/0.10a0 |
| release | 2026-04-08 | datasette-graphql 3.0a1 | - Upgrade for compatibility with `datasette>=1.0a20`. #102, #103 | https://github.com/simonw/datasette-graphql/releases/tag/3.0a1 |
| release | 2026-04-01 | datasette-extract 0.3a0 | - Now uses [datasette-llm](https://github.com/datasette/datasette-llm) to manage model configuration, which means you can control which models are available for extraction tasks using the `extract` purpose and [LLM model configuration](https://github.com/datasette/datasette-llm/blob/main/README.md#configuration). #38 | https://github.com/datasette/datasette-extract/releases/tag/0.3a0 |
| release | 2026-03-31 | llm 0.30 | - The [register_models() plugin hook](http://llm.datasette.io/en/stable/plugins/plugin-hooks.html#plugin-hooks-register-models) now takes an optional `model_aliases` parameter listing all of the models, async models and aliases that have been registered so far by other plugins. A plugin with `@hookimpl(trylast=True)` can use this to take previously registered models into account. #1389 - Added docstrings to public classes and methods and included those directly in the documentation. | https://github.com/simonw/llm/releases/tag/0.30 |
| news | 2026-03-18 | [Datasette 1.0a26](https://docs.datasette.io/en/latest/changelog.html#a26-2026-03-18) adds a `column_types` system allowing columns to carry additional type information such as `email` or `url`, or extra types defined by plugins. This alpha also adds a UI for selecting and sorting visible columns on a table page. | https://datasette.io/news/2026-03-18 | |
| release | 2026-03-18 | datasette 1.0a26 | ### New `column_types` system Table columns can now have custom column types assigned to them, using the new `column_types` table configuration option or at runtime using a new UI and `POST /<database>/<table>/-/set-column-type` JSON API. Built-in column types include `url`, `email`, and `json`, and plugins can register additional types using the new [register_column_types()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-register-column-types) plugin hook. ([#2664](https://github.com/simonw/datasette/issues/2664), [#2671](https://github.com/simonw/datasette/issues/2671)) Column types can customize HTML rendering, validate values written through the insert, update, and upsert APIs, and transform values returned by the JSON API. They can optionally restrict themselves to specific SQLite column types using `sqlite_types`. This feature also introduces a new [set-column-type](https://docs.datasette.io/en/latest/authentication.html#actions-set-column-type) permission for assigning column types to a table. ([#2672](https://github.com/simonw/datasette/issues/2672)) The [render_cell()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-render-cell) plugin hook now receives a `column_type` argument containing the assigned type instance, and a column type's own `render_cell()` method takes priority over the plugin hook chain. The [datasette-files](https://github.com/datasette/datasette-files) plugin will be the first to use this new feature. ### UI for selecting columns and their order Table and view pages now include a dialog for selecting and re-ordering visible columns. ([#2661](https://github.com/simonw/datasette/issues/2661)) ### Other changes - Fixed `allowed_resources("view-query", actor)` so actor-specific canned queries are returned correctly. Any plugin that defines a `resources_sql()` method on a `Resource` subclass needs to update to the new signature, see [the resources_sql() method](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-resources-s… | https://github.com/simonw/datasette/releases/tag/1.0a26 |
| release | 2026-03-17 | llm 0.29 | - The `-t/--template` option now works correctly with the `-x/--extract` and `--xl/--extract-last` flags. - `llm logs` now shows any additional model options in the Markdown output. #1322 - New OpenAI models: `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`. #1376 | https://github.com/simonw/llm/releases/tag/0.29 |
| release | 2026-02-26 | datasette 1.0a25 | ### `write_wrapper()` plugin hook for intercepting write operations A new [write_wrapper()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-write-wrapper) plugin hook allows plugins to intercept and wrap database write operations. ([#2636](https://github.com/simonw/datasette/pull/2636)) Plugins implement the hook as a generator-based context manager: ```python @hookimpl def write_wrapper(datasette, database, request): def wrapper(conn): # Setup code runs before the write yield # Cleanup code runs after the write return wrapper ``` ### `register_token_handler()` plugin hook for custom API token backends A new [register_token_handler()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-register-token-handler) plugin hook allows plugins to provide custom token backends for API authentication. ([#2650](https://github.com/simonw/datasette/pull/2650)) This includes a **backwards incompatible change**: the `datasette.create_token()` internal method is now an `async` method. Consult the [upgrade guide](https://docs.datasette.io/en/latest/upgrade_guide.html#upgrade-guide-v1-a25) for details on how to update your code. ### `render_cell()` now receives a `pks` parameter The [render_cell()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-render-cell) plugin hook now receives a `pks` parameter containing the list of primary key column names for the table being rendered. This avoids plugins needing to make redundant async calls to look up primary keys. ([#2641](https://github.com/simonw/datasette/pull/2641)) ### Other changes - Facets defined in metadata now preserve their configured order, instead of being sorted by result count. Request-based facets added via the `_facet` parameter are still sorted by result count and appear after metadata-defined facets. ([#2647](https://github.com/simonw/datasette/issues/2647)) - Fixed `--reload` incorrectly interpreting the `serve` command as a file argument. Than… | https://github.com/simonw/datasette/releases/tag/1.0a25 |
| release | 2026-02-26 | datasette-auth-tokens 0.4a12 | - Compatible with [Datasette 1.0a25](https://docs.datasette.io/en/latest/changelog.html#a25-2026-02-25). #38 - Switched to `pyproject.toml` and `uv`. #39 | https://github.com/simonw/datasette-auth-tokens/releases/tag/0.4a12 |
| news | 2026-02-25 | [Datasette 1.0a25](https://docs.datasette.io/en/latest/changelog.html#a25-2026-02-25) adds [write_wrapper()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-write-wrapper) and [register_token_handler()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-register-token-handler) plugin hooks. | https://datasette.io/news/2026-02-25 | |
| release | 2026-02-08 | datasette-packages 0.3 | - `/-/packages` page now links each package to a new package details page showing metadata and the README. #7 - Now recommends `uv` for the development environment. | https://github.com/simonw/datasette-packages/releases/tag/0.3 |
| release | 2026-02-08 | datasette-pretty-traces 0.7 | - Now intercepts `fetch()` calls and adds those to the visible traces on the page. #10 - `uv run pytest` can now run the tests on a fresh checkout. | https://github.com/simonw/datasette-pretty-traces/releases/tag/0.7 |
| release | 2026-02-04 | datasette-youtube-embed 0.2 | - Update `lite-youtube-embed` to latest version from upstream. Thanks, [Agustin Bacigalup V](https://github.com/redraw). #3 | https://github.com/simonw/datasette-youtube-embed/releases/tag/0.2 |
| release | 2026-02-01 | shot-scraper 1.9.1 | - Fix for a bug where Playwright 1.58 and higher threw an error. #189 - Recommended development environment now uses `uv`. | https://github.com/simonw/shot-scraper/releases/tag/1.9.1 |
| news | 2026-01-29 | [Datasette 1.0a24](https://docs.datasette.io/en/latest/changelog.html#a24-2026-01-29) introduces a new `await request.form(files=True)` method for accepting file uploads, plus various other changes. | https://datasette.io/news/2026-01-29 | |
| release | 2026-01-29 | datasette 1.0a24 | ## `request.form()` method for POST data and file uploads Datasette now includes a `request.form()` method for parsing form submissions, including handling file uploads. ([#2626](https://github.com/simonw/datasette/pull/2626)) This supports both `application/x-www-form-urlencoded` and `multipart/form-data` content types, and uses a new streaming multipart parser that processes uploads without buffering entire request bodies in memory. ```python # Parse form fields (files are discarded by default) form = await request.form() username = form["username"] # Parse form fields AND file uploads form = await request.form(files=True) uploaded = form["avatar"] content = await uploaded.read() ``` The returned [FormData](https://docs.datasette.io/en/latest/internals.html#internals-formdata) object provides dictionary-style access with support for multiple values per key via `form.getlist("key")`. Uploaded files are represented as [UploadedFile](https://docs.datasette.io/en/latest/internals.html#internals-uploadedfile) objects with `filename`, `content_type`, `size` properties and async `read()` and `seek()` methods. Files smaller than 1MB are held in memory; larger files automatically spill to temporary files on disk. Configurable limits control maximum file size, request size, field counts and more. Several internal views (permissions debug, messages debug, create token) now use `request.form()` instead of `request.post_vars()`. `request.post_vars()` remains available for backwards compatibility but is no longer the recommended API for handling POST data. ## `render_cell` and `foreign_key_tables` extras for the JSON API The table JSON API now supports `?_extra=render_cell`, which returns the rendered HTML for each cell as produced by the [render_cell plugin hook](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-render-cell). Only columns whose rendered output differs from the default are included. ([#2619](https://github.com/simonw/datasette/issues/2619)) The row JSON API… | https://github.com/simonw/datasette/releases/tag/1.0a24 |
| release | 2026-01-26 | datasette-visible-internal-db 0.1.1a2 | - Relax pinned version of Datasette. | https://github.com/datasette/datasette-visible-internal-db/releases/tag/0.1.1a2 |
| release | 2026-01-19 | datasette-scale-to-zero 0.3.2 | - Upgraded to `pyproject.toml`. - Dropped support for Python <3.10. - Clarified how to disable the plugin. | https://github.com/simonw/datasette-scale-to-zero/releases/tag/0.3.2 |
| release | 2026-01-06 | datasette-public 0.4a0 | - Now requires [Datasette 1.0a22](https://docs.datasette.io/en/latest/changelog.html#a22-2025-11-13) or higher running in `--default-deny` mode. #19 - Making a database public makes all tables in that database public. - Canned queries still stay private unless toggled even if their database is public. | https://github.com/datasette/datasette-public/releases/tag/0.4a0 |
| release | 2025-12-29 | shot-scraper 1.9 | - The `shot-scraper har` command has a new `-x/--extract` option which extracts all of the resources loaded by the page out to a set of files. This location can be controlled by the `-o dir/` option. #184 - Fixed the `shot-scraper accessibility` command for compatibility with the latest Playwright. #185 | https://github.com/simonw/shot-scraper/releases/tag/1.9 |
| release | 2025-12-21 | git-history 0.7 | - The `--repo` option now supports repository URLs like `https://github.com/user/repo` or `git@github.com:user/repo`. [#67](https://github.com/simonw/git-history/issues/67) - New `--encoding` option for reading CSV files with different character encodings. [#68](https://github.com/simonw/git-history/pull/68) - Fixed bug where the item table did not correctly link to the commits using a foreign key. [#59](https://github.com/simonw/git-history/issues/59) - Fixed bug where some repositories would not process correctly due to data from older versions not being successfully loaded from the commit history. [#64](https://github.com/simonw/git-history/issues/64) | https://github.com/simonw/git-history/releases/tag/0.7 |
| release | 2025-12-16 | s3-credentials 0.17 | - New commands `get-bucket-policy` and `set-bucket-policy`. #91 - New commands `get-public-access-block` and `set-public-access-block`. #92 - New `localserver` command for starting a web server that makes time limited credentials accessible via a JSON API. #93 | https://github.com/simonw/s3-credentials/releases/tag/0.17 |
| release | 2025-12-12 | llm 0.28 | - New OpenAI models: `gpt-5.1`, `gpt-5.1-chat-latest`, `gpt-5.2` and `gpt-5.2-chat-latest`. [#1300](https://github.com/simonw/llm/issues/1300), [#1317](https://github.com/simonw/llm/issues/1317) - LLM now requires Python 3.10 or higher. Python 3.14 is now covered by the tests. - When fetching URLs as fragments using `llm -f URL`, the request now includes a custom user-agent header: `llm/VERSION (https://llm.datasette.io/)`. [#1309](https://github.com/simonw/llm/issues/1309) - Fixed a bug where fragments were not correctly registered with their source when using `llm chat`. Thanks, [Giuseppe Rota](https://github.com/grota). [#1316](https://github.com/simonw/llm/pull/1316) - Fixed some file descriptor leak warnings. Thanks, [Eric Bloch](https://github.com/eedeebee). [#1313](https://github.com/simonw/llm/issues/1313) - Fixed a deprecation warning for `asyncio.iscoroutinefunction`. - Type annotations for the OpenAI Chat, AsyncChat and Completion `execute()` methods. Thanks, [Arjan Mossel](https://github.com/ar-jan). [#1315](https://github.com/simonw/llm/pull/1315) - The project now uses `uv` and dependency groups for development. See the updated [contributing documentation](https://llm.datasette.io/en/stable/contributing.html). [#1318](https://github.com/simonw/llm/issues/1318) | https://github.com/simonw/llm/releases/tag/0.28 |
| release | 2025-12-03 | datasette 1.0a23 | - Fix for bug where a stale database entry in `internal.db` could cause a 500 error on the homepage. #2605 - Cosmetic improvement to `/-/actions` page. #2599 | https://github.com/simonw/datasette/releases/tag/1.0a23 |
| release | 2025-12-03 | datasette-extract 0.2a1 | - Fixed a bug where the `tests/` where included in the released wheel. #37 | https://github.com/datasette/datasette-extract/releases/tag/0.2a1 |
| release | 2025-11-26 | datasette-extract 0.2a0 | - Integration with [datasette-llm-accountant](https://github.com/datasette/datasette-llm-accountant). #36 | https://github.com/datasette/datasette-extract/releases/tag/0.2a0 |
| release | 2025-11-24 | sqlite-utils 4.0a1 | - **Breaking change**: The `db.table(table_name)` method now only works with tables. To access a SQL view use `db.view(view_name)` instead. ([#657](https://github.com/simonw/sqlite-utils/issues/657)) - The `table.insert_all()` and `table.upsert_all()` methods can now accept an iterator of lists or tuples as an alternative to dictionaries. The first item should be a list/tuple of column names. See [Inserting data from a list or tuple iterator](https://sqlite-utils.datasette.io/en/stable/python-api.html#python-api-insert-lists) for details. ([#672](https://github.com/simonw/sqlite-utils/issues/672)) - **Breaking change**: The default floating point column type has been changed from `FLOAT` to `REAL`, which is the correct SQLite type for floating point values. This affects auto-detected columns when inserting data. ([#645](https://github.com/simonw/sqlite-utils/issues/645)) - Now uses `pyproject.toml` in place of `setup.py` for packaging. ([#675](https://github.com/simonw/sqlite-utils/issues/675)) - Tables in the Python API now do a much better job of remembering the primary key and other schema details from when they were first created. ([#655](https://github.com/simonw/sqlite-utils/issues/655)) - **Breaking change**: The `table.convert()` and `sqlite-utils convert` mechanisms no longer skip values that evaluate to `False`. Previously the `--skip-false` option was needed, this has been removed. ([#542](https://github.com/simonw/sqlite-utils/issues/542)) - **Breaking change**: Tables created by this library now wrap table and column names in `"double-quotes"` in the schema. Previously they would use `[square-braces]`. ([#677](https://github.com/simonw/sqlite-utils/issues/677)) - The `--functions` CLI argument now accepts a path to a Python file in addition to accepting a string full of Python code. It can also now be specified multiple times. ([#659](https://github.com/simonw/sqlite-utils/issues/659)) - **Breaking change:** Type detection is now the default behavior for the `insert` and `upsert` CLI commands… | https://github.com/simonw/sqlite-utils/releases/tag/4.0a1 |
| release | 2025-11-24 | sqlite-utils 3.39 | * Fixed a bug with `sqlite-utils install` when the tool had been installed using `uv`. (#687) * The `--functions` argument now optionally accepts a path to a Python file as an alternative to a string full of code, and can be specified multiple times – see [Defining custom SQL functions](https://sqlite-utils.datasette.io/en/stable/cli.html#cli-query-functions). (#659) * `sqlite-utils` now requires Python 3.10 or higher. [sqlite-utils 4.0a1](https://sqlite-utils.datasette.io/en/latest/changelog.html#a1-2025-11-23) is now available as an alpha with some [minor breaking changes](https://simonwillison.net/2025/Nov/24/sqlite-utils-40a1/). | https://github.com/simonw/sqlite-utils/releases/tag/3.39 |
| release | 2025-11-16 | datasette-auth-github 0.14 | - Added support for GitHub Enterprise. Thanks, [Steffen Uhlig](https://github.com/suhlig). #75 - Now correctly handles `base_url` setting. Thanks, [Michal Porebski](https://github.com/michal-porebski). #76 - Actors now include an `"id"` key of `"github:ID"`. Thanks, [Brendan Samek](https://github.com/xrendan). #77 | https://github.com/simonw/datasette-auth-github/releases/tag/0.14 |
| release | 2025-11-13 | datasette 1.0a22 | - `datasette serve --default-deny` option for running Datasette configured to [deny all permissions by default](https://docs.datasette.io/en/latest/authentication.html#authentication-default-deny). ([#2592](https://github.com/simonw/datasette/issues/2592)) - `datasette.is_client()` method for detecting if code is [executing inside a datasette.client request](https://docs.datasette.io/en/latest/internals.html#internals-datasette-is-client). ([#2594](https://github.com/simonw/datasette/issues/2594)) - `datasette.pm` property can now be used to [register and unregister plugins in tests](https://docs.datasette.io/en/latest/testing_plugins.html#testing-plugins-register-in-test). ([#2595](https://github.com/simonw/datasette/issues/2595)) | https://github.com/simonw/datasette/releases/tag/1.0a22 |
| release | 2025-11-12 | datasette-enrichments-opencage 0.1.2a0 | https://github.com/datasette/datasette-enrichments-opencage/releases/tag/0.1.2a0 | |
| release | 2025-11-12 | datasette-enrichments-opencage 0.1.2a1 | https://github.com/datasette/datasette-enrichments-opencage/releases/tag/0.1.2a1 | |
| release | 2025-11-12 | datasette-public 0.3a5 | - Fix for error on non-canned-query page. #17 | https://github.com/datasette/datasette-public/releases/tag/0.3a5 |
| release | 2025-11-11 | datasette-export-database 0.3a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-export-database/releases/tag/0.3a0 |
| release | 2025-11-11 | datasette-write 0.5a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-write/releases/tag/0.5a0 |
| release | 2025-11-11 | datasette-create-view 0.2a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-create-view/releases/tag/0.2a0 |
| release | 2025-11-11 | datasette-secrets 0.3a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-secrets/releases/tag/0.3a0 |
| release | 2025-11-11 | datasette-extract 0.1a12 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-extract/releases/tag/0.1a12 |
| release | 2025-11-11 | datasette-ripgrep 0.9a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-ripgrep/releases/tag/0.9a0 |
| release | 2025-11-11 | datasette-comments 0.1.1.a3 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-comments/releases/tag/0.1.1.a3 |
| release | 2025-11-10 | datasette-upload-csvs 0.10a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-upload-csvs/releases/tag/0.10a0 |
| release | 2025-11-10 | datasette-edit-templates 0.5a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-edit-templates/releases/tag/0.5a0 |
| release | 2025-11-10 | datasette-configure-fts 1.2a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-configure-fts/releases/tag/1.2a0 |
| release | 2025-11-10 | datasette-upload-dbs 0.4a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-upload-dbs/releases/tag/0.4a0 |
| release | 2025-11-10 | datasette-auth-tokens 0.4a11 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-auth-tokens/releases/tag/0.4a11 |
| release | 2025-11-10 | datasette-edit-schema 0.8a5 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/simonw/datasette-edit-schema/releases/tag/0.8a5 |
| release | 2025-11-10 | datasette-events-forward 0.1a4 | - Fix an issue where multiple copies of this plugin could cause warnings in tests. #5 | https://github.com/datasette/datasette-events-forward/releases/tag/0.1a4 |
| release | 2025-11-09 | datasette-ephemeral-tables 0.2.3 | - Fix for flash of pink bar with no text. #6 | https://github.com/simonw/datasette-ephemeral-tables/releases/tag/0.2.3 |
| release | 2025-11-08 | datasette-events-db 0.1a2 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-events-db/releases/tag/0.1a2 |
| release | 2025-11-08 | datasette-write-ui 0.0.1a14 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-write-ui/releases/tag/0.0.1a14 |
| release | 2025-11-08 | datasette-query-assistant 0.1a5 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-query-assistant/releases/tag/0.1a5 |
| release | 2025-11-06 | datasette-enrichments 0.6a0 | * Add `actor_id` parameter to `enrich_batch()` method. #59 * Upgrade for Datasette 1.0a21. #61 | https://github.com/datasette/datasette-enrichments/releases/tag/0.6a0 |
| release | 2025-11-06 | datasette-checkbox 0.1a4 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-checkbox/releases/tag/0.1a4 |
| news | 2025-11-05 | [Datasette 0.65.2](https://docs.datasette.io/en/stable/changelog.html#v0-65-2) and [Datasette 1.0a21](https://docs.datasette.io/en/latest/changelog.html#a21-2025-11-05) have been released with a **security fix** for an open redirect error, see [this advisory](https://github.com/simonw/datasette/security/advisories/GHSA-w832-gg5g-x44m). The latest Datasette alphas also include a breaking change to Datasette's permission system, described in detail in [A new SQL-powered permissions system in Datasette 1.0a20](https://simonwillison.net/2025/Nov/4/datasette-10a20/). | https://datasette.io/news/2025-11-05 | |
| release | 2025-11-05 | datasette 0.65.2 | - Fixes an **open redirect** security issue: Datasette instances would redirect to `example.com/foo/bar` if you accessed the path `//example.com/foo/bar`. Thanks to [James Jefferies](https://github.com/jamesjefferies) for the fix. [#2429](https://github.com/simonw/datasette/issues/2429) - Upgraded for compatibility with Python 3.14. - Fixed `datasette publish cloudrun` to work with changes to the underlying Cloud Run architecture. [#2511](https://github.com/simonw/datasette/issues/2511) - Minor upgrades to fix warnings, including `pkg_resources` deprecation. | https://github.com/simonw/datasette/releases/tag/0.65.2 |
| release | 2025-11-05 | datasette 1.0a21 | - Fixes an **open redirect** security issue: Datasette instances would redirect to `example.com/foo/bar` if you accessed the path `//example.com/foo/bar`. Thanks to [James Jefferies](https://github.com/jamesjefferies) for the fix. ([#2429](https://github.com/simonw/datasette/issues/2429)) - Fixed `datasette publish cloudrun` to work with changes to the underlying Cloud Run architecture. ([#2511](https://github.com/simonw/datasette/issues/2511)) - New `datasette --get /path --headers` option for inspecting the headers returned by a path. ([#2578](https://github.com/simonw/datasette/issues/2578)) - New `datasette.client.get(..., skip_permission_checks=True)` parameter to bypass permission checks when making requests using the internal client. ([#2583](https://github.com/simonw/datasette/issues/2583)) | https://github.com/simonw/datasette/releases/tag/1.0a21 |
| release | 2025-11-04 | datasette-tail 0.1a2 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-tail/releases/tag/0.1a2 |
| release | 2025-11-04 | datasette-events-forward 0.1a3 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). | https://github.com/datasette/datasette-events-forward/releases/tag/0.1a3 |
| release | 2025-11-03 | datasette 1.0a20 | This alpha introduces a major breaking change prior to the 1.0 release of Datasette concerning how Datasette's permission system works. ### Permission system redesign Previously the permission system worked using `datasette.permission_allowed()` checks which consulted all available plugins in turn to determine whether a given actor was allowed to perform a given action on a given resource. This approach could become prohibitively expensive for large lists of items - for example to determine the list of tables that a user could view in a large Datasette instance each plugin implementation of that hook would be fired for every table. The new design uses SQL queries against Datasette's internal [catalog tables](https://docs.datasette.io/en/latest/internals.html#internals-internal) to derive the list of resources for which an actor has permission for a given action. This turns an N x M problem (N resources, M plugins) into a single SQL query. Plugins can use the new [permission_resources_sql(datasette, actor, action)](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-permission-resources-sql) hook to return SQL fragments which will be used as part of that query. Plugins that use any of the following features will need to be updated to work with this and following alphas (and Datasette 1.0 stable itself): - Checking permissions with `datasette.permission_allowed()` - this method has been replaced with [datasette.allowed()](https://docs.datasette.io/en/latest/internals.html#datasette-allowed). - Implementing the `permission_allowed()` plugin hook - this hook has been removed in favor of [permission_resources_sql()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-permission-resources-sql). - Using `register_permissions()` to register permissions - this hook has been removed in favor of [register_actions()](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-register-actions). Consult the [v1.0a20 upgrade guide](https://docs.datasette.io/en/latest… | https://github.com/simonw/datasette/releases/tag/1.0a20 |
| release | 2025-11-03 | datasette-search-all 1.1.5a0 | - Upgraded for compatibility with [Datasette 1.0a20](https://docs.datasette.io/en/latest/changelog.html#a20-2025-11-03). #22 | https://github.com/simonw/datasette-search-all/releases/tag/1.1.5a0 |
| release | 2025-10-24 | datasette-pretty-traces 0.6 | - Add total request time, total SQL time and number of SQL queries to trace display. #9 | https://github.com/simonw/datasette-pretty-traces/releases/tag/0.6 |
| release | 2025-10-21 | datasette-tail 0.1a1 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-tail/releases/tag/0.1a1 |
| release | 2025-10-21 | datasette-column-sum 0.1a1 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-column-sum/releases/tag/0.1a1 |
| release | 2025-10-21 | datasette-checkbox 0.1a3 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-checkbox/releases/tag/0.1a3 |
| release | 2025-10-21 | datasette-extract 0.1a11 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-extract/releases/tag/0.1a11 |
| release | 2025-10-21 | datasette-query-assistant 0.1a4 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-query-assistant/releases/tag/0.1a4 |
| release | 2025-10-21 | datasette-edit-schema 0.8a4 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/simonw/datasette-edit-schema/releases/tag/0.8a4 |
| release | 2025-10-21 | datasette-events-db 0.1a1 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-events-db/releases/tag/0.1a1 |
| release | 2025-10-21 | datasette-public 0.3a4 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-public/releases/tag/0.3a4 |
| release | 2025-10-21 | datasette-import 0.1a6 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-import/releases/tag/0.1a6 |
| release | 2025-10-21 | datasette-plot 0.1.0a1 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-plot/releases/tag/0.1.0a1 |
| release | 2025-10-21 | datasette-write-ui 0.0.1a13 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-write-ui/releases/tag/0.0.1a13 |
| release | 2025-10-21 | datasette-create-view 0.1a1 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-create-view/releases/tag/0.1a1 |
| release | 2025-10-21 | datasette-visible-internal-db 0.1.1a1 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-visible-internal-db/releases/tag/0.1.1a1 |
| release | 2025-10-21 | datasette-events-forward 0.1a2 | - Pin to datasette==1.0a19. [datasette/#2516](https://github.com/simonw/datasette/issues/2516) | https://github.com/datasette/datasette-events-forward/releases/tag/0.1a2 |
| release | 2025-08-12 | llm 0.27.1 | - `llm chat -t template` now correctly loads any tools that are included in that template. [#1239](https://github.com/simonw/llm/issues/1239) - Fixed a bug where `llm -m gpt5 -o reasoning_effort minimal --save gm` saved a template containing invalid YAML. [#1237](https://github.com/simonw/llm/issues/1237) - Fixed a bug where running `llm chat -t template` could cause prompts to be duplicated. [#1240](https://github.com/simonw/llm/issues/1240) - Less confusing error message if a requested toolbox class is unavailable. [#1238](https://github.com/simonw/llm/issues/1238) | https://github.com/simonw/llm/releases/tag/0.27.1 |
| release | 2025-08-11 | llm 0.27 | This release adds support for the new **GPT-5 family** of models from OpenAI. It also enhances tool calling in a number of ways, including allowing [templates](https://llm.datasette.io/en/stable/templates.html#prompt-templates) to bundle pre-configured tools. ### New features - New models: `gpt-5`, `gpt-5-mini` and `gpt-5-nano`. [#1229](https://github.com/simonw/llm/issues/1229) - LLM [templates](https://llm.datasette.io/en/stable/templates.html#prompt-templates) can now include a list of tools. These can be named tools from plugins or arbitrary Python function blocks, see [Tools in templates](https://llm.datasette.io/en/stable/templates.html#prompt-templates-tools). [#1009](https://github.com/simonw/llm/issues/1009) - Tools [can now return attachments](https://llm.datasette.io/en/stable/python-api.html#python-api-tools-attachments), for models that support features such as image input. [#1014](https://github.com/simonw/llm/issues/1014) - New methods on the `Toolbox` class: `.add_tool()`, `.prepare()` and `.prepare_async()`, described in [Dynamic toolboxes](https://llm.datasette.io/en/stable/python-api.html#python-api-tools-dynamic). [#1111](https://github.com/simonw/llm/issues/1111) - New `model.conversation(before_call=x, after_call=y)` attributes for registering callback functions to run before and after tool calls. See [tool debugging hooks](https://llm.datasette.io/en/stable/python-api.html#python-api-tools-debug-hooks) for details. [#1088](https://github.com/simonw/llm/issues/1088) - Some model providers can serve different models from the same configured URL - [llm-llama-server](https://github.com/simonw/llm-llama-server) for example. Plugins for these providers can now record the resolved model ID of the model that was used to the LLM logs using the `response.set_resolved_model(model_id)` method. [#1117](https://github.com/simonw/llm/issues/1117) - Raising `llm.CancelToolCall` now only cancels the current tool call, passing an error back to the model and allowing it to continue. [#1148](https:… | https://github.com/simonw/llm/releases/tag/0.27 |
| release | 2025-07-22 | datasette-public 0.3a3 | - Ability to make canned queries public or private. #14 | https://github.com/datasette/datasette-public/releases/tag/0.3a3 |
| release | 2025-05-27 | llm 0.26 | **Tool support** is finally here! This release adds support exposing [tools](https://llm.datasette.io/en/stable/tools.html#tools) to LLMs, previously described in the release notes for [0.26a0](https://llm.datasette.io/en/stable/changelog.html#v0-26-a0) and [0.26a1](https://llm.datasette.io/en/stable/changelog.html#v0-26-a1). Read **[Large Language Models can run tools in your terminal with LLM 0.26](https://simonwillison.net/2025/May/27/llm-tools/)** for a detailed overview of the new features. Also in this release: - Two new [default tools](https://llm.datasette.io/en/stable/tools.html#tools-default): `llm_version()` and `llm_time()`. [#1096](https://github.com/simonw/llm/issues/1096), [#1103](https://github.com/simonw/llm/issues/1103) - Documentation on [how to add tool supports to a model plugin](https://llm.datasette.io/en/stable/plugins/advanced-model-plugins.html#advanced-model-plugins-tools). [#1000](https://github.com/simonw/llm/issues/1000) - Added a [prominent warning](https://llm.datasette.io/en/stable/tools.html#tools-warning) about the risk of prompt injection when using tools. [#1097](https://github.com/simonw/llm/issues/1097) - Switched to using monotonic ULIDs for the response IDs in the logs, fixing some intermittent test failures. [#1099](https://github.com/simonw/llm/issues/1099) - New `tool_instances` table records details of Toolbox instances created while executing a prompt. [#1089](https://github.com/simonw/llm/issues/1089) - `llm.get_key()` is now a [documented utility function](https://llm.datasette.io/en/stable/plugins/plugin-utilities.html#plugin-utilities-get-key). [#1094](https://github.com/simonw/llm/issues/1094) | https://github.com/simonw/llm/releases/tag/0.26 |
| release | 2025-05-26 | llm 0.26a1 | Hopefully the last alpha before a stable release that includes tool support. ### Features * **Plugin-provided tools can now be grouped into "Toolboxes".** * Toolboxes (`llm.Toolbox` classes) allow plugins to expose multiple related tools that share state or configuration, enhancing modularity and reusability (e.g., a `Memory` tool or `Filesystem` tool). ([#1059](https://github.com/simonw/llm/issues/1059), [#1086](https://github.com/simonw/llm/issues/1086)) * **Tool support for `llm chat`.** * The `llm chat` command now accepts `--tool` and `--functions` arguments, allowing interactive chat sessions to use tools. ([#1004](https://github.com/simonw/llm/issues/1004), [#1062](https://github.com/simonw/llm/issues/1062)) * **Tools can now execute asynchronously.** * Models that implement `AsyncModel` can now run tools, including tool functions defined as `async def`. This enables non-blocking tool calls for potentially long-running operations. ([#1063](https://github.com/simonw/llm/issues/1063)) * **`llm chat` now supports adding fragments during a session.** * Use the new `!fragment <id>` command while chatting to insert content from a fragment. Initial fragments can also be passed to `llm chat` using `-f` or `--sf`. Thanks, [Dan Turkel](https://github.com/daturkel). ([#1044](https://github.com/simonw/llm/issues/1044), [#1048](https://github.com/simonw/llm/issues/1048)) * **Filter `llm logs` by tools.** * New `--tool <name>` option to filter logs to show only responses that involved a specific tool (e.g., `--tool simple_eval`). * The `--tools` flag shows all responses that used any tool. ([#1013](https://github.com/simonw/llm/issues/1013), [#1072](https://github.com/simonw/llm/issues/1072)) * **`llm schemas list` can output JSON.** * Added `--json` and `--nl` (newline-delimited JSON) options to `llm schemas list` for programmatic access to saved schema definitions. ([#1070](https://github.com/simonw/llm/issues/1070)) * **Filter `llm similar` re… | https://github.com/simonw/llm/releases/tag/0.26a1 |
| release | 2025-05-14 | llm 0.26a0 | This is the first alpha to introduce [support for tools](https://llm.datasette.io/en/latest/tools.html#tools)! Models with tool capability (which includes the default OpenAI model family) can now be granted access to execute Python functions as part of responding to a prompt. Tools are supported by [the command-line interface](https://llm.datasette.io/en/latest/usage.html#usage-tools): ```bash llm --functions ' def multiply(x: int, y: int) -> int: """Multiply two numbers.""" return x * y ' 'what is 34234 * 213345' ``` And in [the Python API](https://llm.datasette.io/en/latest/python-api.html#python-api-tools), using a new `model.chain()` method for executing multiple prompts in a sequence: ```python import llm def multiply(x: int, y: int) -> int: """Multiply two numbers.""" return x * y model = llm.get_model("gpt-4.1-mini") response = model.chain( "What is 34234 * 213345?", tools=[multiply] ) print(response.text()) ``` New tools can also be defined using the [register_tools() plugin hook](https://llm.datasette.io/en/latest/plugins/plugin-hooks.html#plugin-hooks-register-tools). They can then be called by name from the command-line like this: ```bash llm -T multiply 'What is 34234 * 213345?' ``` Tool support is currently under **active development**. Consult [this milestone](https://github.com/simonw/llm/milestone/12) for the latest status. | https://github.com/simonw/llm/releases/tag/0.26a0 |
| release | 2025-05-13 | datasette-chronicle 0.3 | - New trigger design, using [sqlite-chronicle 0.4](https://github.com/simonw/sqlite-chronicle/releases/tag/0.4). #4 - Existing chronicle tables are automatically upgraded to the new design, maintaining version and timestamp data. - Now uses the text "Enable row version tracking for this table" in the UI. #5 | https://github.com/datasette/datasette-chronicle/releases/tag/0.3 |
| release | 2025-05-09 | sqlite-utils 4.0a0 | - Upsert operations now use SQLite's `INSERT ... ON CONFLICT SET` syntax on all SQLite versions later than 3.23.1. This is a very slight breaking change for apps that depend on the previous `INSERT OR IGNORE` followed by `UPDATE` behavior. ([#652](https://github.com/simonw/sqlite-utils/issues/652)) - Python library users can opt-in to the previous implementation by passing `use_old_upsert=True` to the `Database()` constructor, see [Alternative upserts using INSERT OR IGNORE](https://sqlite-utils.datasette.io/en/latest/python-api.html#python-api-old-upsert). - Dropped support for Python 3.8, added support for Python 3.13. ([#646](https://github.com/simonw/sqlite-utils/issues/646)) - `sqlite-utils tui` is now provided by the [sqlite-utils-tui](https://github.com/simonw/sqlite-utils-tui) plugin. ([#648](https://github.com/simonw/sqlite-utils/issues/648)) - Test suite now also runs against SQLite 3.23.1, the last version (from 2018-04-10) before the new `INSERT ... ON CONFLICT SET` syntax was added. ([#654](https://github.com/simonw/sqlite-utils/issues/654)) | https://github.com/simonw/sqlite-utils/releases/tag/4.0a0 |
| release | 2025-05-05 | llm 0.25 | - New plugin feature: [register_fragment_loaders(register)](https://llm.datasette.io/en/stable/plugins/plugin-hooks.html#plugin-hooks-register-fragment-loaders) plugins can now return a mixture of fragments and attachments. The [llm-video-frames](https://github.com/simonw/llm-video-frames) plugin is the first to take advantage of this mechanism. [#972](https://github.com/simonw/llm/issues/972) - New OpenAI models: `gpt-4.1`, `gpt-4.1-mini`, `gpt-41-nano`, `o3`, `o4-mini`. [#945](https://github.com/simonw/llm/issues/945), [#965](https://github.com/simonw/llm/issues/965), [#976](https://github.com/simonw/llm/issues/976). - New environment variables: `LLM_MODEL` and `LLM_EMBEDDING_MODEL` for setting the model to use without needing to specify `-m model_id` every time. [#932](https://github.com/simonw/llm/issues/932) - New command: `llm fragments loaders`, to list all currently available fragment loader prefixes provided by plugins. [#941](https://github.com/simonw/llm/issues/941) - `llm fragments` command now shows fragments ordered by the date they were first used. [#973](https://github.com/simonw/llm/issues/973) - `llm chat` now includes a `!edit` command for editing a prompt using your default terminal text editor. Thanks, [Benedikt Willi](https://github.com/Hopiu). [#969](https://github.com/simonw/llm/pull/969) - Allow `-t` and `--system` to be used at the same time. [#916](https://github.com/simonw/llm/issues/916) - Fixed a bug where accessing a model via its alias would fail to respect any default options set for that model. [#968](https://github.com/simonw/llm/issues/968) - Improved documentation for [extra-openai-models.yaml](https://llm.datasette.io/en/stable/other-models.html#openai-compatible-models). Thanks, [Rahim Nathwani](https://github.com/rahimnathwani) and [Dan Guido](https://github.com/dguido). [#950](https://github.com/simonw/llm/pull/950), [#957](https://github.com/simonw/llm/pull/957) - `llm -c/--continue` now works correctly with the `-d/--database` option. `llm chat` now accepts that… | https://github.com/simonw/llm/releases/tag/0.25 |
| release | 2025-05-05 | sqlite-diffable 0.6 | - New feature: `--all --exclude name_of_table` lets you import all tables but exclude one or more by name. Thanks, [giuli007](https://github.com/giuli007). #11 - Migrated from `setup.py` to `pyproject.toml`. | https://github.com/simonw/sqlite-diffable/releases/tag/0.6 |
| release | 2025-05-05 | datasette-enrichments 0.5.1 | - Fixed error about a missing table on server startup for some environments. #58 | https://github.com/datasette/datasette-enrichments/releases/tag/0.5.1 |
| release | 2025-05-01 | datasette-query-assistant 0.1a3 | - Now depends on [LLM](https://llm.datasette.io/) to support multiple models, not just Anthropic. #13 | https://github.com/datasette/datasette-query-assistant/releases/tag/0.1a3 |
| release | 2025-04-22 | datasette 1.0a19 | - Tiny cosmetic bug fix for mobile display of table rows. [#2479](https://github.com/simonw/datasette/issues/2479) | https://github.com/simonw/datasette/releases/tag/1.0a19 |
| release | 2025-04-21 | datasette-comments 0.1.1.a2 | - Update plugin to work with latest Datasette 1.0 alpha - Various UI improvements for comment icon on table view, bug fixes | https://github.com/datasette/datasette-comments/releases/tag/0.1.1.a2 |
| release | 2025-04-17 | datasette 1.0a18 | - Fix for incorrect foreign key references in the internal database schema. [#2466](https://github.com/simonw/datasette/issues/2466) - The ``prepare_connection()`` hook no longer runs for the internal database. [#2468](https://github.com/simonw/datasette/issues/2468) - Fixed bug where ``link:`` HTTP headers used invalid syntax. [#2470](https://github.com/simonw/datasette/issues/2470) - No longer tested against Python 3.8. Now tests against Python 3.13. - FTS tables are now hidden by default if they correspond to a content table. [#2477](https://github.com/simonw/datasette/issues/2477) - Fixed bug with foreign key links to rows in databases with filenames containing a special character. Thanks, [Jack Stratton](https://github.com/phroa). [#2476](https://github.com/simonw/datasette/pull/2476) | https://github.com/simonw/datasette/releases/tag/1.0a18 |
| release | 2025-04-17 | datasette-extract 0.1a10 | - Fixed bugs with floating point columns. #34 - Now strips unicode null characters entirely (GPT-4.1-mini returned these for an image). #35 | https://github.com/datasette/datasette-extract/releases/tag/0.1a10 |
| release | 2025-04-16 | datasette-extract 0.1a9 | - Now depends on [LLM](https://llm.datasette.io/) and supports any model that has both async and schema support. You can also limit it to a subset of models using the new `plugins.datasette-extract.models` configuration list. [#27](https://github.com/datasette/datasette-extract/issues/27) | https://github.com/datasette/datasette-extract/releases/tag/0.1a9 |
| release | 2025-04-11 | llm 0.25a0 | - `llm models --options` now shows keys and environment variables for models that use API keys. Thanks, [Steve Morin](https://github.com/smorin). [#903](https://github.com/simonw/llm/issues/903) - Added `py.typed` marker file so LLM can now be used as a dependency in projects that use `mypy` without a warning. [#887](https://github.com/simonw/llm/issues/887) - `$` characters can now be used in templates by escaping them as `$$`. Thanks, [@guspix](https://github.com/guspix). [#904](https://github.com/simonw/llm/issues/904) - LLM now uses `pyproject.toml` instead of `setup.py`. [#908](https://github.com/simonw/llm/issues/908) | https://github.com/simonw/llm/releases/tag/0.25a0 |
| release | 2025-04-10 | csvs-to-sqlite 1.3.1 | - Upgraded for compatibility with recent Pandas and Click libraries. Thanks, [Luighi Viton-Zorrilla](https://github.com/LuighiV). #99 | https://github.com/simonw/csvs-to-sqlite/releases/tag/1.3.1 |
| release | 2025-04-09 | llm 0.24.2 | - Fixed a bug on Windows with the new `llm -t path/to/file.yaml` feature. [#901](https://github.com/simonw/llm/issues/901) | https://github.com/simonw/llm/releases/tag/0.24.2 |
| release | 2025-04-08 | llm 0.24.1 | - Templates can now be specified as a path to a file on disk, using `llm -t path/to/file.yaml`. This makes them consistent with how `-f` fragments are loaded. [#897](https://github.com/simonw/llm/issues/897) - `llm logs backup /tmp/backup.db` command for [backing up your](https://llm.datasette.io/en/stable/logging.html#backing-up-your-database) `logs.db` database. [#879](https://github.com/simonw/llm/issues/879) | https://github.com/simonw/llm/releases/tag/0.24.1 |
| release | 2025-04-07 | llm 0.24a1 | - New Fragments feature. [#617](https://github.com/simonw/llm/issues/617) - `register_fragment_loaders()` plugin hook. [#809](https://github.com/simonw/llm/issues/886) | https://github.com/simonw/llm/releases/tag/0.24a1 |
| release | 2025-04-07 | llm 0.24 | Support for **fragments** to help assemble prompts for long context models. Improved support for **templates** to support attachments and fragments. New plugin hooks for providing custom loaders for both templates and fragments. See [Long context support in LLM 0.24 using fragments and template plugins](https://simonwillison.net/2025/Apr/7/long-context-llm/) for more on this release. The new [llm-docs](https://github.com/simonw/llm-docs) plugin demonstrates these new features. Install it like this: ```bash llm install llm-docs ``` Now you can ask questions of the LLM documentation like this: ```bash llm -f docs: 'How do I save a new template?' ``` The `docs:` prefix is registered by the plugin. The plugin fetches the LLM documentation for your installed version (from the [docs-for-llms](https://github.com/simonw/docs-for-llms) repository) and uses that as a prompt fragment to help answer your question. Two more new plugins are [llm-templates-github](https://github.com/simonw/llm-templates-github) and [llm-templates-fabric](https://github.com/simonw/llm-templates-fabric). `llm-templates-github` lets you share and use templates on GitHub. You can run my [Pelican riding a bicycle](https://simonwillison.net/tags/pelican-riding-a-bicycle/) benchmark against a model like this: ```bash llm install llm-templates-github llm -t gh:simonw/pelican-svg -m o3-mini ``` This executes [this pelican-svg.yaml](https://github.com/simonw/llm-templates/blob/main/pelican-svg.yaml) template stored in my [simonw/llm-templates](https://github.com/simonw/llm-templates) repository, using a new repository naming convention. To share your own templates, create a repository on GitHub under your user account called `llm-templates` and start saving `.yaml` files to it. [llm-templates-fabric](https://github.com/simonw/llm-templates-fabric) provides a similar mechanism for loading templates from Daniel Miessler's [fabric collection](https://github.com/danielmiessler/fabric): ```bash llm install llm-templates-… | https://github.com/simonw/llm/releases/tag/0.24 |
| release | 2025-03-28 | datasette-auth-existing-cookies 1.0a2 | - Fix some warnings. - Drop support for Python versions prior to 3.9. | https://github.com/simonw/datasette-auth-existing-cookies/releases/tag/1.0a2 |
| release | 2025-03-25 | shot-scraper 1.8 | - `shot-scraper javascript` can now optionally [load scripts hosted on GitHub](https://shot-scraper.datasette.io/en/stable/javascript.html#running-javascript-from-github) via the new `gh:` prefix to the `shot-scraper javascript -i/--input` option. #173 Scripts can be referenced as `gh:username/repo/path/to/script.js` or, if the GitHub user has created a dedicated `shot-scraper-scripts` repository and placed scripts in the root of it, using `gh:username/name-of-script`. For example, to run this [readability.js](https://github.com/simonw/shot-scraper-scripts/blob/main/readability.js) script against any web page you can use the following: ```bash shot-scraper javascript -i gh:simonw/readability \ https://simonwillison.net/2025/Mar/24/qwen25-vl-32b/ ``` | https://github.com/simonw/shot-scraper/releases/tag/1.8 |
| release | 2025-03-20 | datasette-public 0.3a2 | - Fix for compatibility with `datasette-extract`. #13 | https://github.com/datasette/datasette-public/releases/tag/0.3a2 |
| release | 2025-03-01 | llm 0.24a0 | - Alpha release with experimental `register_template_loaders()` plugin hook. [#809](https://github.com/simonw/llm/issues/809) | https://github.com/simonw/llm/releases/tag/0.24a0 |
| release | 2025-02-28 | llm 0.23 | Support for **schemas**, for getting supported models to output JSON that matches a specified JSON schema. See also [Structured data extraction from unstructured content using LLM schemas](https://simonwillison.net/2025/Feb/28/llm-schemas/) for background on this feature. [#776](https://github.com/simonw/llm/issues/776) - New `llm prompt --schema '{JSON schema goes here}` option for specifying a schema that should be used for the output from the model. The [schemas documentation](https://llm.datasette.io/en/stable/schemas.html#schemas) has more details and a tutorial. - Schemas can also be defined using a [concise schema specification](https://llm.datasette.io/en/stable/schemas.html#schemas-dsl), for example `llm prompt --schema 'name, bio, age int'`. [#790](https://github.com/simonw/llm/issues/790) - Schemas can also be specified by passing a filename and through [several other methods](https://llm.datasette.io/en/stable/schemas.html#schemas-specify). [#780](https://github.com/simonw/llm/issues/780) - New [llm schemas family of commands](https://llm.datasette.io/en/stable/help.html#help-schemas): `llm schemas list`, `llm schemas show`, and `llm schemas dsl` for debugging the new concise schema language. [#781](https://github.com/simonw/llm/issues/781) - Schemas can now be saved to templates using `llm --schema X --save template-name` or through modifying the [template YAML](https://llm.datasette.io/en/stable/templates.html#prompt-templates-yaml). [#778](https://github.com/simonw/llm/issues/778) - The [llm logs](https://llm.datasette.io/en/stable/logging.html#logging) command now has new options for extracting data collected using schemas: `--data`, `--data-key`, `--data-array`, `--data-ids`. [#782](https://github.com/simonw/llm/issues/782) - New `llm logs --id-gt X` and `--id-gte X` options. [#801](https://github.com/simonw/llm/issues/801) - New `llm models --schemas` option for listing models that support schemas. [#797](https://github.com/simonw/llm/issues/797) - `model.prompt(..., schema={...})` pa… | https://github.com/simonw/llm/releases/tag/0.23 |
| release | 2025-02-28 | strip-tags 0.6 | - Fixed a bug where `strip-tags -t meta` still removed `<meta>` tags from the `<head>` because the entire `<head>` element was removed first. #32 - Kept `<meta>` tags now default to keeping their `content` and `property` attributes. - The CLI `-m/--minify` option now also removes any remaining blank lines. #33 - A new `strip_tags(remove_blank_lines=True)` option can be used to achieve the same thing with the Python library function. | https://github.com/simonw/strip-tags/releases/tag/0.6 |
| release | 2025-02-27 | llm 0.23a0 | Alpha release adding support for **schemas**, for getting supported models to output JSON that matches a specified JSON schema. [#776](https://github.com/simonw/llm/issues/776) - `llm prompt --schema '{JSON schema goes here}` option for specifying a schema that should be used for the output from the model, see [schemas in the CLI docs](https://llm.datasette.io/en/latest/usage.html#usage-schemas). - `model.prompt(..., schema={...})` parameter for specifying a schema from Python. This accepts either a dictionary JSON schema definition of a Pydantic `BaseModel` subclass, see [schemas in the Python API docs](https://llm.datasette.io/en/latest/python-api.html#python-api-schemas). - The default OpenAI plugin now supports schemas across all models. - Documentation on how to [add schema support to a model plugin](https://llm.datasette.io/en/latest/plugins/advanced-model-plugins.html#advanced-model-plugins-schemas). - LLM now depends on Pydantic v2 or higher. Pydantic v1 is no longer supported. [#520](https://github.com/simonw/llm/issues/520) | https://github.com/simonw/llm/releases/tag/0.23a0 |
| release | 2025-02-20 | shot-scraper 1.7 | - New options for the `shot-scraper har` command: `--wait`, `--wait-for` and `--javascript` - similar to those same options on `shot-scraper shot`. #171 - Documentation now recommends using `shot-scraper multi --har-zip` for larger collections of files to avoid a Playwright crash if the `.har` JSON grows too large. #170 | https://github.com/simonw/shot-scraper/releases/tag/1.7 |
| release | 2025-02-17 | llm 0.22 | See also [LLM 0.22, the annotated release notes](https://simonwillison.net/2025/Feb/17/llm/). - Plugins that provide models that use API keys can now subclass the new `llm.KeyModel` and `llm.AsyncKeyModel` classes. This results in the API key being passed as a new `key` parameter to their `.execute()` methods, and means that Python users can pass a key as the `model.prompt(..., key=)` - see [Passing an API key](https://llm.datasette.io/en/stable/python-api.html#python-api-models-api-keys). Plugin developers should consult the new documentation on writing [Models that accept API keys](https://llm.datasette.io/en/stable/plugins/advanced-model-plugins.html#advanced-model-plugins-api-keys). [#744](https://github.com/simonw/llm/issues/744) - New OpenAI model: `chatgpt-4o-latest`. This model ID accesses the current model being used to power ChatGPT, which can change without warning. [#752](https://github.com/simonw/llm/issues/752) - New `llm logs -s/--short` flag, which returns a greatly shortened version of the matching log entries in YAML format with a truncated prompt and without including the response. [#737](https://github.com/simonw/llm/issues/737) - Both `llm models` and `llm embed-models` now take multiple `-q` search fragments. You can now search for all models matching "gemini" and "exp" using `llm models -q gemini -q exp`. [#748](https://github.com/simonw/llm/issues/748) - New `llm embed-multi --prepend X` option for prepending a string to each value before it is embedded - useful for models such as [nomic-embed-text-v2-moe](https://huggingface.co/nomic-ai/nomic-embed-text-v2-moe) that require passages to start with a string like `"search_document: "`. [#745](https://github.com/simonw/llm/issues/745) - The `response.json()` and `response.usage()` methods are [now documented](https://llm.datasette.io/en/stable/python-api.html#python-api-underlying-json). - Fixed a bug where conversations that were loaded from the database could not be continued using `asyncio` prompts. [#742](https://github.com/simon… | https://github.com/simonw/llm/releases/tag/0.22 |
| release | 2025-02-14 | datasette-public 0.3a1 | - Changes are now recorded to a `public_audit_log` table, which is visible on the table and database permission editing pages. [#11](https://github.com/datasette/datasette-public/issues/11) | https://github.com/datasette/datasette-public/releases/tag/0.3a1 |
| release | 2025-02-13 | shot-scraper 1.6 | - New `shot-scraper har URL` command for [creating an HTML Archive](https://shot-scraper.datasette.io/en/stable/har.html) of a page. #146 - `shot-scraper multi --har` and `--har-zip` and `--har-file` options for [creating an HTML Archive of multiple pages](https://shot-scraper.datasette.io/en/stable/multi.html#multi-har). #166 - `shot-scraper pdf` now has `--wait-for` and `--timeout` options. Thanks, [miccou](https://github.com/miccou). #161 | https://github.com/simonw/shot-scraper/releases/tag/1.6 |
| news | 2025-02-06 | [Datasette 1.0a17](https://docs.datasette.io/en/latest/changelog.html#a17-2025-02-06) is the latest Datasette 1.0 alpha release, with bug fixes and small feature improvements from the last few months. | https://datasette.io/news/2025-02-06 | |
| release | 2025-02-06 | datasette 1.0a17 | - `DATASETTE_SSL_KEYFILE` and `DATASETTE_SSL_CERTFILE` environment variables as alternatives to `--ssl-keyfile` and `--ssl-certfile`. Thanks, Alex Garcia. ([#2422](https://github.com/simonw/datasette/issues/2422)) - `SQLITE_EXTENSIONS` environment variable has been renamed to `DATASETTE_LOAD_EXTENSION`. ([#2424](https://github.com/simonw/datasette/issues/2424)) - `datasette serve` environment variables are now [documented here](https://docs.datasette.io/en/latest/cli-reference.html#cli-datasette-serve-env). - The [register_magic_parameters(datasette)](https://docs.datasette.io/en/latest/plugin_hooks.html#plugin-hook-register-magic-parameters) plugin hook can now register async functions. ([#2441](https://github.com/simonw/datasette/issues/2441)) - Datasette is now tested against Python 3.13. - Breadcrumbs on database and table pages now include a consistent self-link for resetting query string parameters. ([#2454](https://github.com/simonw/datasette/issues/2454)) - Fixed issue where Datasette could crash on `metadata.json` with nested values. ([#2455](https://github.com/simonw/datasette/issues/2455)) - New internal methods `datasette.set_actor_cookie()` and `datasette.delete_actor_cookie()`, [described here](https://docs.datasette.io/en/latest/authentication.html#authentication-ds-actor). ([#1690](https://github.com/simonw/datasette/issues/1690)) - `/-/permissions` page now shows a list of all permissions registered by plugins. ([#1943](https://github.com/simonw/datasette/issues/1943)) - If a table has a single unique text column Datasette now detects that as the foreign key label for that table. ([#2458](https://github.com/simonw/datasette/issues/2458)) - The `/-/permissions` page now includes options for filtering or exclude permission checks recorded against the current user. ([#2460](https://github.com/simonw/datasette/issues/2460)) - Fixed a bug where replacing a database with a new one with the same name did not pick up the new database correctly. ([#2465](https://github.com/simonw/datasette/issu… | https://github.com/simonw/datasette/releases/tag/1.0a17 |
| release | 2025-02-06 | datasette-public 0.3a0 | - Added the ability to make full databases public, including setting if users can execute SQL or not. [#9](https://github.com/datasette/datasette-public/issues/9) - Now depends on Datasette 1.0a and uses the new `internal` database. [#6](https://github.com/datasette/datasette-public/issues/6) | https://github.com/datasette/datasette-public/releases/tag/0.3a0 |
| release | 2025-01-31 | llm 0.21 | - New model: `o3-mini`. [#728](https://github.com/simonw/llm/issues/728) - The `o3-mini` and `o1` models now support a `reasoning_effort` option which can be set to `low`, `medium` or `high`. - `llm prompt` and `llm logs` now have a `--xl/--extract-last` option for extracting the last fenced code block in the response - a complement to the existing `--x/--extract` option. [#717](https://github.com/simonw/llm/issues/717) | https://github.com/simonw/llm/releases/tag/0.21 |
| release | 2025-01-23 | llm 0.20 | - New model, `o1`. This model does not yet support streaming. [#676](https://github.com/simonw/llm/issues/676) - `o1-preview` and `o1-mini` models now support streaming. - New models, `gpt-4o-audio-preview` and `gpt-4o-mini-audio-preview`. [#677](https://github.com/simonw/llm/issues/677) - `llm prompt -x/--extract` option, which returns just the content of the first fenced code block in the response. Try `llm prompt -x 'Python function to reverse a string'`. [#681](https://github.com/simonw/llm/issues/681) - Creating a template using `llm ... --save x` now supports the `-x/--extract` option, which is saved to the template. YAML templates can set this option using `extract: true`. - New `llm logs -x/--extract` option extracts the first fenced code block from matching logged responses. - New `llm models -q 'search'` option returning models that case-insensitively match the search query. [#700](https://github.com/simonw/llm/issues/700) - Installation documentation now also includes `uv`. Thanks, [Ariel Marcus](https://github.com/ajmarcus). [#690](https://github.com/simonw/llm/pull/690) and [#702](https://github.com/simonw/llm/issues/702) - `llm models` command now shows the current default model at the bottom of the listing. Thanks, [Amjith Ramanujam](https://github.com/amjith). [#688](https://github.com/simonw/llm/pull/688) - [Plugin directory](https://llm.datasette.io/en/stable/plugins/directory.html) now includes `llm-venice`, `llm-bedrock`, `llm-deepseek` and `llm-cmd-comp`. - Fixed bug where some dependency version combinations could cause a `Client.__init__() got an unexpected keyword argument 'proxies'` error. [#709](https://github.com/simonw/llm/issues/709) - OpenAI embedding models are now available using their full names of `text-embedding-ada-002`, `text-embedding-3-small` and `text-embedding-3-large` - the previous names are still supported as aliases. Thanks, [web-sst](https://github.com/web-sst). [#654](https://github.com/simonw/llm/pull/654) | https://github.com/simonw/llm/releases/tag/0.20 |
| release | 2025-01-15 | datasette-enrichments 0.5a1 | - Pause, resume, cancel buttons for jobs. [#17](https://github.com/datasette/datasette-enrichments/issues/17) - Enrichments can raise `self.Pause("message")` or `self.Cancel("message")` exceptions inside their `enrich_batch()` methods. [#56](https://github.com/datasette/datasette-enrichments/issues/56) | https://github.com/datasette/datasette-enrichments/releases/tag/0.5a1 |
| release | 2025-01-15 | datasette-enrichments 0.5 | - UI for viewing status of enrichment jobs. [#51](https://github.com/datasette/datasette-enrichments/issues/51) - Pause, resume and cancel buttons. [#17](https://github.com/datasette/datasette-enrichments/issues/17) - Visible progress bar on table with running enrichments. [#52](https://github.com/datasette/datasette-enrichments/issues/52) - Table and database action menu items for viewing enrichment runs. [#53](https://github.com/datasette/datasette-enrichments/issues/53) - Enrichments continue running after a server restart. [#54](https://github.com/datasette/datasette-enrichments/issues/54) - An `enrichment` permission is now correctly registered with Datasette 1.0a+. [#55](https://github.com/datasette/datasette-enrichments/issues/55) - Enrichments can pause or cancel themselves by raising the new `self.Pause(reason)` and `self.Cancel(reason)` exceptions. [#56](https://github.com/datasette/datasette-enrichments/issues/56) | https://github.com/datasette/datasette-enrichments/releases/tag/0.5 |
| release | 2025-01-14 | datasette-write-ui 0.0.1a12 | https://github.com/datasette/datasette-write-ui/releases/tag/0.0.1a12 | |
| release | 2025-01-14 | datasette-enrichments 0.5a0 | - New `/-/enrich/databasename/-/jobs` listing page `/-/enrich/databasename/-/jobs/123` detail page. [#51](https://github.com/datasette/datasette-enrichments/issues/51) - Visible progress bar on tables that have enrichments running. [#52](https://github.com/datasette/datasette-enrichments/issues/52) - Table and database action menu items to view previous runs. [#53](https://github.com/datasette/datasette-enrichments/issues/53) - Continue any enrichment runs after a server restart. [#54](https://github.com/datasette/datasette-enrichments/issues/54) | https://github.com/datasette/datasette-enrichments/releases/tag/0.5a0 |
| release | 2024-12-05 | llm 0.19.1 | - FIxed bug where `llm.get_models()` and `llm.get_async_models()` returned the same model multiple times. [#667](https://github.com/simonw/llm/issues/667) | https://github.com/simonw/llm/releases/tag/0.19.1 |
| release | 2024-12-01 | llm 0.19 | - Tokens used by a response are now logged to new `input_tokens` and `output_tokens` integer columns and a `token_details` JSON string column, for the default OpenAI models and models from other plugins that [implement this feature](https://llm.datasette.io/en/stable/plugins/advanced-model-plugins.html#advanced-model-plugins-usage). [#610](https://github.com/simonw/llm/issues/610) - `llm prompt` now takes a `-u/--usage` flag to display token usage at the end of the response. - `llm logs -u/--usage` shows token usage information for logged responses. - `llm prompt ... --async` responses are now logged to the database. [#641](https://github.com/simonw/llm/issues/641) - `llm.get_models()` and `llm.get_async_models()` functions, [documented here](https://llm.datasette.io/en/stable/python-api.html#python-api-listing-models). [#640](https://github.com/simonw/llm/issues/640) - `response.usage()` and async response `await response.usage()` methods, returning a `Usage(input=2, output=1, details=None)` dataclass. [#644](https://github.com/simonw/llm/issues/644) - `response.on_done(callback)` and `await response.on_done(callback)` methods for specifying a callback to be executed when a response has completed, [documented here](https://llm.datasette.io/en/stable/python-api.html#python-api-response-on-done). [#653](https://github.com/simonw/llm/issues/653) - Fix for bug running `llm chat` on Windows 11. Thanks, [Sukhbinder Singh](https://github.com/sukhbinder). [#495](https://github.com/simonw/llm/issues/495) | https://github.com/simonw/llm/releases/tag/0.19 |
| release | 2024-11-29 | datasette 0.65.1 | - Fixed bug with upgraded HTTPX 0.28.0 dependency. [#2443](https://github.com/simonw/datasette/issues/2443) | https://github.com/simonw/datasette/releases/tag/0.65.1 |
| release | 2024-11-23 | sqlite-utils 3.38 | - Plugins can now reuse the implementation of the `sqlite-utils memory` CLI command with the new `return_db=True` parameter. ([#643](https://github.com/simonw/sqlite-utils/issues/643)) - `table.transform()` now recreates indexes after transforming a table. A new `sqlite_utils.db.TransformError` exception is raised if these indexes cannot be recreated due to conflicting changes to the table such as a column rename. Thanks, [Mat Miller](https://github.com/matdmiller). ([#633](https://github.com/simonw/sqlite-utils/issues/633)) - `table.search()` now accepts a `include_rank=True` parameter, causing the resulting rows to have a `rank` column showing the calculated relevance score. Thanks, [liunux4odoo](https://github.com/liunux4odoo). ([#628](https://github.com/simonw/sqlite-utils/pull/628)) - Fixed an error that occurred when creating a strict table with at least one floating point column. These `FLOAT` columns are now correctly created as `REAL` as well, but only for strict tables. ([#644](https://github.com/simonw/sqlite-utils/issues/644)) | https://github.com/simonw/sqlite-utils/releases/tag/3.38 |
| release | 2024-11-21 | llm 0.19a2 | - `llm.get_models()` and `llm.get_async_models()` functions, [documented here](https://llm.datasette.io/en/latest/python-api.html#python-api-listing-models). [#640](https://github.com/simonw/llm/issues/640) | https://github.com/simonw/llm/releases/tag/0.19a2 |
| release | 2024-11-20 | llm 0.19a0 | - Tokens used by a response are now logged to new `input_tokens` and `output_tokens` integer columns and a `token_details` JSON string column, for the default OpenAI models and models from other plugins that [implement this feature](https://llm.datasette.io/en/latest/plugins/advanced-model-plugins.html#advanced-model-plugins-usage). [#610](https://github.com/simonw/llm/issues/610) - `llm prompt` now takes a `-u/--usage` flag to display token usage at the end of the response. - `llm logs -u/--usage` shows token usage information for logged responses. - `llm prompt ... --async` responses are now logged to the database. [#641](https://github.com/simonw/llm/issues/641) | https://github.com/simonw/llm/releases/tag/0.19a0 |