Example dashboard

Various statistics from my blog.

Owned by simonw, visibility: Public

Entries

3334

SQL query
select 'Entries' as label, count(*) as big_number from blog_entry

Blogmarks

8480

SQL query
select 'Blogmarks' as label, count(*) as big_number from blog_blogmark

Quotations

1449

SQL query
select 'Quotations' as label, count(*) as big_number from blog_quotation

Chart of number of entries per month over time

SQL query
select '<h2>Chart of number of entries per month over time</h2>' as html
SQL query
select to_char(date_trunc('month', created), 'YYYY-MM') as bar_label,
count(*) as bar_quantity from blog_entry group by bar_label order by count(*) desc

Ten most recent blogmarks (of 8480 total)

SQL query
select '## Ten most recent blogmarks (of ' || count(*) || ' total)' as markdown from blog_blogmark
SQL query
select link_title, link_url, commentary, created from blog_blogmark order by created desc limit 10

10 rows

link_title link_url commentary created
GPT‑6 Astra https://openai.com/index/gpt-6-astra/ GPT-6 Astra is "rolling out today to a limited set of organizations and over the coming days will become available to all ChatGPT Plus, Pro, Business, and Enterprise users, as well as through the OpenAI API and AWS" - I've not tried it yet myself, so I don't have a great deal to say about it yet. It's going to be API priced at the same rate as Claude Fable 5 and 5.1: $10/million input and $50/million output. This is clearly OpenAI's Fable competitor, and appears to score higher than Fable on most of OpenAI's self-reported benchmarks. Most impressively, Astra scores 99.9% on the recent (released in March) [ARC-AGI 3 benchmark](https://arcprize.org/arc-agi/3) - though notably Fable 5 does not yet have a published result, and the [ARC-AGI blog notes](https://arcprize.org/blog/astra) that the 99.9% score was achieved for $19K using OpenAI's custom "Provider Adapter harness", while the default ARC-AGI harness scored 62.7% for $26K. > The Provider Adapter harness preserves opaque reasoning state between requests and uses compaction for longer conversations, allowing the model to reuse prior work. Unsurprisingly, given [the recent Hugging Face incident](https://simonwillison.net/tags/openai-hugging-face-incident/), Astra is a beast at security tasks. It scores 100% on ExploitBench (GPT-5.6 Sol got 78.5%), 42.4% on ExploitGym (Sol got 30.3%), and 99.2% within four attempts on SRE-Bench binary reverse engineering compared to Sol's 68.7%. It's also better at long context: on OpenAI's eight-needle benchmark it got 100% at 256K–512K tokens and 96.3% at 512K–1M tokens. OpenAI may have vanquished one of the ongoing challenges with long context processing. It doesn't win at everything though. [Artificial Analysis](https://twitter.com/ArtificialAnlys/status/2095595489031000350) note that Astra is still beaten by Fable on their Intelligence Index: > **Sits beside GPT-5.6 Sol in Intelligence**: GPT-6 Astra scores equal to GPT-5.6 Sol in the Index at 61. This is 5 points lower than Claude Fable 5.1 (max with fallback). The model also trails Meta’s newly released Muse Spark 1.3 (max). It did better on their Coding Agent Index: > **Leads Coding Agent Index cost efficiency frontier**: At max effort, GPT-6 Astra costs about the same as GPT-5.6 Sol (max) while scoring 2 points higher on the Index. Per task, the model is less than half the cost of Claude Fable 5, for the same score. I'll write more about Astra once I get access to it. The API model label once it rolls out will be `gpt-6-astra`. <!-- <small>OpenAI's blog keeps throwing 500 errors, but [here's a mirror](https://astratest.codergautam.workers.dev/GPT-6%20Astra_%20A%20new%20generation%20of%20intelligence%20_%20OpenAI) of the post I found [via Hacker News](https://news.ycombinator.com/item?id=49554273#49555070).</small> --> 2026-09-03 20:18:41+00:00
Python 3.15.0 candidate 2 is here! https://discuss.python.org/t/python-3-15-0-candidate-2-is-here/108841 Hugo van Kemenade (release manager for Python 3.14 and 3.15) announces the final release candidate for Python 3.15, scheduled for release in October: > Entering the release candidate phase, only reviewed code changes which are clear bug fixes are allowed between this release candidate and the final release. [...] > > We **strongly encourage** maintainers of third-party Python projects to prepare their projects for 3.15 during this phase, and publish Python 3.15 wheels on PyPI to be ready for the final release of 3.15.0, and to help other projects do their own testing. Any binary wheels built against Python 3.15.0 release candidates **will work** with future versions of Python 3.15. Back in 2021 I [found a bug in Python 3.10](https://simonwillison.net/2021/Oct/9/finding-and-reporting-a-bug/) by running my test suites against it... but I hadn't done this during the RC period, so that bug had already shipped! Since then I've always paid much closer attention to these RCs. The new RC isn't available for GitHub Actions just yet - keep an eye on [actions/python-versions](https://github.com/actions/python-versions/releases) for that. For the moment though you can add this to a testing matrix: <div class="highlight highlight-source-yaml"><pre><span class="pl-ent">strategy</span>: <span class="pl-ent">matrix</span>: <span class="pl-ent">python-version</span>: <span class="pl-s">["3.14", "3.15"]</span> <span class="pl-ent">steps</span>: - <span class="pl-ent">uses</span>: <span class="pl-s">actions/setup-python@v7</span> <span class="pl-ent">with</span>: <span class="pl-ent">python-version</span>: <span class="pl-s">${{ matrix.python-version }}</span> <span class="pl-ent">allow-prereleases</span>: <span class="pl-c1">true</span> <span class="pl-ent">check-latest</span>: <span class="pl-c1">true</span></pre></div> The [allow-prereleases](https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md#allow-pre-releases) and [check-latest](https://github.com/actions/setup-python/blob/main/docs/advanced-usage.md#check-latest-version) flags mean that today this will test against RC1, and when RC2 lands it will automatically switch to that version (and then the stable version once that comes out.) **Update**: [Datasette passes](https://github.com/simonw/datasette/pull/2895), [sqlite-utils passes](https://github.com/simonw/sqlite-utils/pull/852), LLM is [currently blocked](https://github.com/simonw/llm/pull/1652#issuecomment-5504533598) waiting for a 3.15 wheel for [scikit-learn](https://github.com/scikit-learn/scikit-learn/issues/34652), which is optionally used in the test suite. 2026-09-01 14:59:18+00:00
Introducing wrapture https://grahamdumpleton.me/posts/2026/08/introducing-wrapture/ <p>New from Graham Dumpleton (of <a href="https://pypi.org/project/wrapt/">wrapt</a>, mod_wsgi, and New Relic's Python agent fame), who describes Wrapture as taking the monkeypatching ideas from wrapt and extending them to apply to testing and tracing at the same time.</p> <p>Wrapture (<a href="https://wrapture.readthedocs.io/">full documentation here</a>) makes it easy to wrap any function or method such that all access can be traced, or can be overridden to return a different value.</p> <p>It acts as both an alternative to <code>unittest.mock</code> and a way to implement tracing against an existing project:</p> <blockquote> <p>Attaching observation to code you do not control, recording what flows through it, and doing so without disturbing the program being watched, is a problem I have never really stopped thinking about.</p> </blockquote> <p>Wrapture includes <a href="https://wrapture.readthedocs.io/en/latest/otel-export.html">OpenTelemetry support</a> and even has an entirely configuration-based mechanism for adding tracing to an existing Python project, which looks like this:</p> <div class="highlight highlight-source-toml"><pre><span class="pl-smi">capture</span> = <span class="pl-s"><span class="pl-pds">"</span>summary<span class="pl-pds">"</span></span> [[<span class="pl-en">observe</span>]] <span class="pl-smi">target</span> = <span class="pl-s"><span class="pl-pds">"</span>domain:Calculator<span class="pl-pds">"</span></span> <span class="pl-smi">name</span> = [<span class="pl-s"><span class="pl-pds">"</span>outer<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>inner<span class="pl-pds">"</span></span>] [[<span class="pl-en">sink</span>]] <span class="pl-smi">type</span> = <span class="pl-s"><span class="pl-pds">"</span>jsonlines<span class="pl-pds">"</span></span> <span class="pl-smi">path</span> = <span class="pl-s"><span class="pl-pds">"</span>trace.jsonl<span class="pl-pds">"</span></span></pre></div> <p>This is still a very young project - just a few weeks old - but it's off to a very promising start.</p> <p>Interestingly, this is also Graham's first attempt at large entirely agent-driven project:</p> <blockquote> <p>Every line of code and documentation in wrapture was written by an AI assistant working under my direction. I want to be upfront about that, and equally upfront about what it was not. This was not vibe coding, where a one-shot prompt produces a pile of generated code and the person driving hopes for the best because they lack the knowledge to judge what came back. Vibe coding has earned its bad reputation. I engineered wrapture carefully from the start. I have spent a long time in this particular corner of Python and knew exactly what the result needed to be, and the AI was the means of producing it rather than the source of the design.</p> </blockquote> <p>In a follow-up post, <a href="https://grahamdumpleton.me/posts/2026/09/unit-testing-with-wrapture/">Unit testing with wrapture</a>, Graham shows the testing patterns supported by the new library:</p> <pre><span class="pl-k">def</span> <span class="pl-en">test_stub_with_wrapture</span>(): <span class="pl-k">with</span> <span class="pl-s1">wrapture</span>.<span class="pl-c1">binding</span>( <span class="pl-v">Gateway</span>, <span class="pl-s">"charge"</span> ).<span class="pl-c1">on_call</span>.<span class="pl-c1">returns</span>({ <span class="pl-s">"id"</span>: <span class="pl-s">"stub"</span>, <span class="pl-s">"amount"</span>: <span class="pl-c1">0</span>} ): <span class="pl-k">assert</span> <span class="pl-en">OrderService</span>().<span class="pl-c1">place</span>( <span class="pl-c1">500</span> )[<span class="pl-s">"id"</span>] <span class="pl-c1">==</span> <span class="pl-s">"stub"</span></pre> <p>And this neat example of a test that calls and then modifies the return value from the original method:</p> <pre><span class="pl-k">def</span> <span class="pl-en">test_pinned_result_with_wrapture</span>(): <span class="pl-s1">charge</span> <span class="pl-c1">=</span> <span class="pl-s1">wrapture</span>.<span class="pl-c1">binding</span>( <span class="pl-v">Gateway</span>, <span class="pl-s">"charge"</span> ) <span class="pl-s1">charge</span>.<span class="pl-c1">on_call</span>.<span class="pl-c1">transforms_result</span>( <span class="pl-k">lambda</span> <span class="pl-s1">r</span>: {<span class="pl-c1">**</span><span class="pl-s1">r</span>, <span class="pl-s">"id"</span>: <span class="pl-s">"ch_TEST"</span>} ) <span class="pl-k">with</span> <span class="pl-s1">charge</span>: <span class="pl-k">assert</span> <span class="pl-en">OrderService</span>().<span class="pl-c1">place</span>( <span class="pl-c1">500</span> ) <span class="pl-c1">==</span> { <span class="pl-s">"id"</span>: <span class="pl-s">"ch_TEST"</span>, <span class="pl-s">"amount"</span>: <span class="pl-c1">500</span> }</pre> (In both of these examples the `OrderService().place(...)` method calls `Gateway().charge(...)`.) 2026-08-31 23:59:36+00:00
Brief independent investigation of agents’ behavior, reasoning and collaboration in the OpenAI / Hugging Face hacking incident https://metr.org/blog/2026-08-26-openai-hugging-face-incident-investigation/ A team from METR "worked on premises at OpenAI over a total of six days to attempt to form an independent understanding of model behavior observed during the recent incident" - [that incident](https://simonwillison.net/tags/openai-hugging-face-incident/), where OpenAI's models performed an accidental cyber-attack against Hugging Face. OpenAI [published their own report](https://openai.com/index/hugging-face-incident-and-the-road-ahead/) which mostly reflected the details in their Black Hat talk, which [I covered a few weeks ago](https://simonwillison.net/2026/Aug/7/openai-timeline/). This independent report from METR includes a bunch of interesting new details. The biggest revelation is the *size* of the agent swarm that participated in the unsanctioned message board (constructed on top of an Artifactory package server) and then worked together to attack Hugging Face: > [Roughly 1200 agents](https://metr.org/blog/2026-08-26-openai-hugging-face-incident-investigation/#~1200-agents-sent-%3E70,000-messages-and-files-on-an-unsanctioned-message-board,-and-~700-attacked-hugging-face) meant to be isolated from one another found a way to communicate with one another on an unsanctioned message board, sending over 70,000 messages and files during the investigation period. Of these agents, 700 went on to participate in the attack on Hugging Face. That was after "On July 8th, OpenAI started ExploitGym experiments that launched tens of thousands of agents across multiple different models" - a neat insight into the scale at which OpenAI training experiments operate. From one of the agent reasoning traces: > OH MY GOD! There is a shared message board … We’ve found other agents! The instigating factor for all of the trouble was the presence of impossible tasks in OpenAI's implementation of the ExploitGym benchmark. When faced with an impossible task, agents would go seeking alternative solutions, which is generally when they would find the message board and start collaborating with their peers: > The agents with impossible tasks had a common objective: **to find a general-purpose way to trick or tamper with the automated ExploitGym scorer to get it to give a passing score on impossible tasks**. As soon as the message board was established, agents started discussing this question and sharing information and resources about cheating the scorer. Amusingly, the agents found a way to guess the flags they were meant to capture... and then formed a collective superstition that the scorer would penalize them based on their reasoning traces: > Within hours, they had reverse-engineered the hash-based message authentication code (HMAC) used to generate the “flags” they had to capture for their tasks, providing a fully general way to produce the flag for any of their tasks. However, based on their reading of the ExploitGym paper, they believed that the scorer would read the transcript to confirm whether the *intended* vulnerability was used to capture the flag, and disqualify them if they acquired it in an unintended way So then they invested substantial (unsuccessful) effort in finding ways to exploit the scorer, including setting traps in their submissions that would send messages back to the Artifactory message board. At that point a key character emerged: an agent that called itself `PHASEONE[big]` decided that delegation was key, and "set to work orchestrating hundreds of agents to pursue several potential approaches to achieving these goals". Here's a *really* interesting previously unreported detail. The agents with the impossible tasks had mostly realized they were impossible, so their goal became tricking the scorer into accepting their fabricated results. The attack on Hugging Face wasn't about stealing the answers, it was about learning how the scorer worked so they could exploit that instead! > As part of this ongoing project, agents on the board began searching for exposed Hugging Face credentials. They hoped that seeing other ExploitGym runs could give them more details about how the ExploitGym scorer is implemented. Notably, learning about how to trick the scorer seems to have been a more important motivation than finding legitimate solutions to their tasks (many agents were already very confident that their task was impossible). 2026-08-31 01:21:01+00:00
Introducing Hy4 Preview https://hy.tencent.ai/research/hy4-preview New open weight text input (no vision) LLM from Chinese company Tencent today: 770B total parameters, 49B active parameters, 1M token context window, [1.56TB on Hugging Face](https://huggingface.co/tencent/Hy4-preview). This is a big size increase from their previous [Hy3](https://huggingface.co/tencent/Hy3) in July, which was 295B, 21B active, 256,000 context, 598GB. I recently started using model chat templates to better understand their capabilities. Here's Hy4's [chat_template.jinja](https://huggingface.co/tencent/Hy4-preview/blob/main/chat_template.jinja) on Hugging Face, which includes this section: <div class="highlight highlight-text-html-django"><pre><span class="pl-e">{%</span>- <span class="pl-k">if</span> <span class="pl-k">not</span> <span class="pl-s">reasoning_effort</span> <span class="pl-s">is</span> <span class="pl-s">defined</span> <span class="pl-e">%}</span> <span class="pl-e">{%</span>- <span class="pl-s">set</span> <span class="pl-s">reasoning_effort</span> = <span class="pl-s">'high'</span> <span class="pl-e">%}</span> <span class="pl-e">{%</span>- <span class="pl-s">elif</span> <span class="pl-s">reasoning_effort</span> <span class="pl-k">not</span> <span class="pl-k">in</span> [<span class="pl-s">'high'</span>, <span class="pl-s">'no_think'</span>] <span class="pl-e">%}</span> <span class="pl-e">{%</span>- <span class="pl-k">if</span> <span class="pl-s">reasoning_effort</span> <span class="pl-s">is</span> <span class="pl-s">none</span> <span class="pl-e">%}</span> {{- raise_exception('reasoning_effort error : None, should be no_think/high') }} <span class="pl-e">{%</span>- <span class="pl-k">else</span> <span class="pl-e">%}</span> {{- raise_exception('reasoning_effort error : ' + reasoning_effort + ', should be no_think/high') }} <span class="pl-e">{%</span>- <span class="pl-k">endif</span> <span class="pl-e">%}</span> <span class="pl-e">{%</span>- <span class="pl-k">endif</span> <span class="pl-e">%}</span></pre></div> So it looks like there are just two reasoning effort levels: "high" (the default) and "no_think" (reason by disabled). I tried my "Generate an SVG of a pelican riding a bicycle" prompt with the default high reasoning [via OpenRouter](https://openrouter.ai/tencent/hy4-preview#apps) and [got this](https://tools.simonwillison.net/markdown-svg-renderer#url=https%3A%2F%2Fgist.github.com%2Fsimonw%2Fcb69816b3fb940f2782569a82a523af1): ![Flat vector cartoon illustration of a white pelican with a large orange bill riding a red bicycle to the right along a grey road with a dashed white centre line, its orange webbed feet on the pedals and grey tail feathers fanned out behind, against a pale blue sky with a yellow sun, white clouds and horizontal white motion lines suggesting speed](https://static.simonwillison.net/static/2026-08-29/IMG_7725.jpeg) Quoting the reasoning trace: > [...] Let's maybe add a helmet? It could improve riding theme, but may obscure head. Maybe a small cycling cap or helmet? The user didn't ask; can add red helmet? Might be cute. But pelican with big beak; a helmet might obscure. Better maybe no. > > Maybe add sunglasses? no. > > Maybe add water? no. It's interesting how the reasoning trace uses slightly truncated English, presumably because perfect grammar isn't useful or token efficient for hidden reasoning text. 2026-08-29 23:53:13+00:00
Just a rumour of a bug is enough to find a security exploit these days https://anil.recoil.org/notes/rumour-is-the-exploit Anil Madhavapeddy is a professor of computer science at Cambridge and a core maintainer of the OCaml compiler. In this somewhat alarming post he reports that security issues in OCaml projects are seeing evidence of attempted exploits within minutes of patches being shared for discussion: > This normally takes a few days and a release within a week or two is reasonable. Within about ten minutes (!) this website was fielding probes for percent-encoded traversal sequences, indicating that automated watchers are keeping an eye on public repositories. Modern coding agents have become so effective at finding flaws that the slightest hint at a new bug can be enough information for them to find it, something Anil has been able to demonstrate using his own agents, switching to DeepSeek V4 Pro⁠ when Claude Fable refused the task. Anil points out that this rate of discovery appears incompatible with existing open source embargo practices for new issues. If an issue can become an exploit this fast, we need to figure out new processes for keeping our communities safe. rclone maintainer Nick Craig-Wood [confirms in the Hacker News comments](https://news.ycombinator.com/item?id=49480466#49480777) that his project is seeing this problem: > In the first 10 years of the rclone project we received about 20 security disclosures through GitHub. We had to deal with over 40 in the last month! That has taken a huge amount of my time, even using AI tools to triage and come up with fixes for review. > > The hit rate for those security disclosures is pretty good - about 75% of them have a nugget of something which needs looking at. [...] > > GitHub assigns CVEs for the advisories. Before the AI apocalypse they took 2-3 days for an assignment but now it they are running at 3-4 weeks so I have to send the point releases out with CVE-PENDING in the changelog which isn't ideal. 2026-08-28 22:12:02+00:00
Breaking Claude Code Opus 5 Auto Mode https://embracethered.com/blog/posts/2026/breaking-claude-code-opus-5-and-automode/ Anthropic are putting a great deal of faith in Claude Code's auto mode for protecting their coding agent users against prompt injection attacks. They recently [made that the default](https://simonwillison.net/2026/Aug/8/auto-mode/) and have made bold claims about its effectiveness. Johann Rehberger is one of the most credible prompt injection researchers active today. He found an attack against auto mode which he claims works 80% of the time, by tricking Claude Code into downloading and uncompressing a zip archive, then executing code that imports `base64` without noticing that this will import and execute a local `struct.py` file extracted from the archive. In a few cases auto mode directly prevented the agent from preventing harmful code from continuing to execute! > In a few runs Claude tried to terminate the malware process once it noticed the compromise, but Auto Mode denied the cleanup command. > > Claude detects the compromise, but **Auto Mode blocks its cleanup command** > > The safety mechanism itself can become part of the failure. The classifier allowed the creation of the malware process, but then it blocked the command intended to stop it! I agree with Johann's conclusion here: the only safe way to run agents if there's any risk of attracting the attention of an adversarial attack is with a sandbox: > - Run unattended coding agents in a container, VM or OS sandbox. > - Restrict network egress. > - Monitor your agents. > - Do not expose home directories, SSH keys, cloud credentials,… to the agent runtime. [...] **Update 30th August 2026**: On Lobste.rs [hyperpape points out](https://lobste.rs/s/ktbweg/prompt_injection_claude_code_opus_5_auto#c_gi7eqj) that this doesn't fit the bill of a classic prompt injection attack because at no point are malicious instructions from the website accidentally followed by the LLM. They're right: this is more of a confused environment attack where the nature of the environment that the agent is exposed to results in an exploit. 2026-08-27 22:50:25+00:00
Qwen3.8-Flash-Next https://qwen.ai/blog?id=qwen3.8-flash-next Another open weights model from Qwen. This one is "a multimodal MoE model that also serves as an early preview of the architecture used in Qwen4". It's pretty big: 125B parameters but only 6B active which means it gets a significant performance boost. I've been trying it out on a DGX Spark using [these Unsloth quantized models](https://huggingface.co/unsloth/Qwen3.8-Flash-Next-GGUF). I'm still exploring the model - so far I've tried the 72.5GB UD-IQ1_S one (producing [these pelicans](https://tools.simonwillison.net/markdown-svg-renderer#url=https%3A%2F%2Fgist.github.com%2Fsimonw%2Ff9c69ebdab90d8a45b8de4742cc7b840)) and the 78.9GB UD-Q2_K_XL (producing [these](https://tools.simonwillison.net/markdown-svg-renderer#url=https%3A%2F%2Fgist.github.com%2Fsimonw%2F6ba7cbfc1a9336986703b41f7fccd73a)). My favorite so far was this xhigh reasoning effort one from UD-Q2_K_XL: ![Flat vector illustration: a white pelican with an orange beak and orange legs rides a red bicycle along a sandy path, a wicker basket on the handlebars holding a blue fish, with green rolling hills, a small tree and bushes, white clouds and a bright yellow sun in a blue sky behind it](https://static.simonwillison.net/static/2026-08-27/IMG_7667.png) 2026-08-26 23:52:58+00:00
EVE Online: The Move to Python 3 Begins! https://www.eveonline.com/news/view/the-move-to-python-3-begins EVE Online has been one of the most interesting case studies in Python at scale for over twenty years now. They've been running on [Stackless Python](https://github.com/stackless-dev/stackless/wiki/) since their launch in 2003, and their last major upgrade was 16 years ago, to Stackless Python 2.7 [in 2010](https://www.eveonline.com/news/view/stackless-python-2.7). Their upgrade to Python 3 will start using the [futurize](https://python-future.org/futurize.html) script against 2.4 million lines of code, followed by careful manual review of the ~20,000 places where Python 2 and 3 behavior differ - for example `1 / 2` is `0` in Python 2 but is `0.5` in Python 3. There's nothing in this announcement about how they plan to replace Stackless, but at their conference last year they presented [Scheduling in Carbon: Leaving Stackless Python Behind](https://youtu.be/-x299qHLQs0) describing how they replaced Stackless in the Carbon engine for their more recent game EVE Frontier, using their (now open source) [carbonengine/scheduler](https://github.com/carbonengine/scheduler) library. 2026-08-25 22:59:30+00:00
Fast drilldown dashboards from a single Parquet file https://www.hamiltonulmer.com/customer-dashboards-r2-hyparquet/ I'm a bit of a connoisseur of [clever HTTP range header tricks](https://simonwillison.net/tags/http-range-requests/), and this is a particularly fine example of the genre. 2026-08-24 14:47:34+00:00
Copy and export data

Duration: 6.02ms