sqlite-utils 4.1 Ships With a Codex-Assisted Toolkit

Simon Willison has released sqlite-utils 4.1, the first dot-release since version 4.0 landed just days earlier. According to Simon Willison, the update bundles a handful of small but practical features for anyone who works with SQLite from the command line or Python. What stands out here is how he built it: Willison had OpenAI’s Codex review every open issue and flag the easiest ones to close.

For the unfamiliar, sqlite-utils is a widely used open-source tool for creating, querying, and reshaping SQLite databases. This release is free, open source, and available now through the usual Python channels.

What’s new in 4.1

  1. Generate rows with a Python code block. The insert and upsert commands now take a --code option. You can pass a block of Python (or a path to a .py file) that defines a rows() function or iterable, then have sqlite-utils insert whatever it yields. Willison calls this a long-standing feature request that turned out to be a simple implementation, and it extends a pattern the tool already used for the convert command.
  2. Drop an index by name. There’s a new table.drop_index(name) method and a matching drop-index CLI command. Both accept ignore=True or --ignore so a missing index won’t blow up your script.
  3. Read SQL from standard input. The query command now accepts - in place of the query itself. That means you can pipe SQL straight in, like echo "select * from dogs" | sqlite-utils query dogs.db -. Small change, but it plays nicely with shell workflows.
  4. Smarter upserts. upsert can now infer the primary key of an existing table, so you can drop --pk when the target table already has one. Willison notes this was another Codex suggestion, an obvious missing CLI feature that mirrored a Python library improvement shipped back in 4.0.
  5. Switch tables in and out of STRICT mode. Both table.transform() and table.transform_sql() now accept strict=True or strict=False, and the transform command gets --strict and --no-strict flags. Leave the option off and the existing mode stays put.

Why the STRICT feature matters

That last one has a good backstory. Willison says the strict-table support was inspired by Evan Hahn’s post Prefer STRICT tables in SQLite, which made the rounds on Hacker News. Hahn pointed out a real limitation: “I don’t think there’s a way to ALTER a table to make it strict. I think you have to copy the data out of the non-strict table into the strict one.”

Copying data between tables is exactly what the sqlite-utils transform mechanism already does under the hood. So Willison extended it to flip tables from strict to non-strict and back. It’s a clean example of an existing tool solving a problem the ecosystem was still complaining about.

The Codex angle

The interesting subtext of this release is workflow. Willison leaned on AI to triage the backlog and to write the strict-table code, and he published the full Codex transcript he used. One prompt he singled out as especially useful told the model to skip the automated tests for a moment and manually exercise the new .transform(strict=) option with uv run python -c, hunting for edge cases and bugs by hand.

That instruction, effectively asking the model to test its own work outside the tests it had already written, turned up two minor issues that then got fixed. It’s a small but telling detail about how experienced developers are folding coding assistants into real release work: not just generating code, but poking at it the way a skeptical human would.

sqlite-utils 4.1 is available now. You can find the full changelog and the Codex transcript at the original source.

Scroll to Top