soft-shell crabvietnam crab exporter

Simon Willison’s Weblog

Newsletter
Atom feed

Elsewhere

Filters: Sorted by date

When I switched LLM over to httpx2 in LLM 0.33 I forget that this would break any plugins which used httpx without directly depending on it. llm-tools-datasette was one of those plugins, now fixed.

I'm working towards a new LLM release, and testing PRs caused me to revisit the llm-echo debug plugin. This plugin provides a "model" which doesn't involve an LLM at all - it just repeats back the prompts that have been fed to it. The new release now updates the simulated token usage counts to take tool calls, system prompts, and reasoning tokens into account.

Example usage:

uvx --with llm-echo llm -m echo 'hi there' -o thinking 1 --usage

Outputs:

First I consider the prompt, then I decide what to say.
{
  "prompt": "hi there",
  "system": "",
  "attachments": [],
  "stream": true,
  "previous": []
}
Token usage: 2 input, 24 output
Sighting 2:07 PM – 2:12 PM — House Sparrow, Eastern Gray Squirrel, in Philadelphia Center City, PA, US
House Sparrow
House Sparrow
Eastern Gray Squirrel
Eastern Gray Squirrel

web-edit (previously) is my tiny web app for browsing and editing files in a folder. I mainly built it for editing files on different machines via Tailscale.

I added a "copy to clipboard" option for both text and image data. I needed this because I was running pelican prompts on a laptop from my phone (here's DeepSeek 4.1 Flash 1017) and I wanted an easy way to copy the resulting logs into a Gist.

Another game experiment - I wanted to see if it was feasible to have a two player game on two separate phones running in static HTML where the networking code uses chirps sent via the microphone. It seems to work!

Build a two player competitive pong like game where two players use their phones close to each other and the game state is sent via audio noises which the web microphone API can interpret - but add graphical and gameplay twists to make it a lot more fun and intertwine than pong

Claude Opus 5.5 Extra in Claude Code.

Inspired by Paul Ford and Aboard Foundary's new web app Tiny Little Office, which provides a suite of web app content editors (a Word Processor, Outliner, Presentation Builder, Spreadsheet, Calculator, Drawing Tool, Diagram Maker, Animator, Calendar, and Trip Planner).

Tiny Little Office's signature trick is to store all of the document data in the #fragment section of the URL, so every document created using it becomes a bookmarkable and shareable link.

It also has an llms.txt file telling agents how to construct URLs that will render as documents. Claude used that file to generate this link to a deck that explains how the URL format works:

Screenshot of a slide deck editor in a web app with a dark-themed presentation open. The document title field reads "How a Tiny Little Office link works", with a progress ring, share icon and menu icon at top right. Below is a formatting toolbar with an "Insert" dropdown followed by icon buttons for play, bold, italic, underline, strikethrough, highlight, code, link, superscript, emoji, outdent, indent, layout and color palette. The main canvas shows slide 1 with a blue chain-link icon and the text: "The whole document is the link" "No server, no database, no account" "Everything after the # stays in your browser" and a slide counter "1 / 9". Below the canvas is a "SPEAKER NOTES" heading. A sidebar on the right shows slide thumbnails. Slide 1 (selected): "The whole document is the link" "No server, no database, no account" "Everything after the # stays in your browser". Slide 2: "Anatomy of a link" with bullets "tinylittleoffice.com/#/v1/deck/y7Vj..." "v1: the format version" "deck: which app opens it" "y: the mode letter" "7Vj...: the document, compressed and encoded". Slide 3: "Step 1: write it as text" with bullets "Every document is TLO, a Markdown variant" "Slides split on --- lines" "Charts, drawings and animations are fenced blocks" "This deck is about 1 KB of plain text". Slide 4: "Step 2: squeeze it" with bullets "Raw DEFLATE, the same algorithm as zip and gzip" "z: plain DEFLATE" "y: DEFLATE with a preset dictionary" "r: no compression at all".

Tiny Little Office inspired me to have Claude Code (Opus 5.5 Extra) build a similar tool that works with LaTeX. Here's the sequence of prompts I used:

I want a tool where you can link to it with a fragment hash #code-here and it treats that code as LaTeX and renders it really effectively. It should also support a prefix which means the latex is compressed with a custom compression dictionary optimized for latex. Use the best available latex render library from a CDN (consider WebAssembly too). If loaded without a fragment hash show an editor you can paste latex into and then toggle to a "rendered" view. That rendered view should be bookmarkable. The #fragment view should let you switch to edit source too.

Since it was working in my tools repo I told it to take inspiration from the <iframe sandbox="..."> mechanism used by my existing SVG in Markdown tool as protection against XSS risks:

Safe from XSS? We could run in an iframe sandbox like we do on the SVG markdown render project

I had it copy the Gist/URL loading feature from that tool as well:

We should have an option to load latex from a URL (or gist) similar to the markdown SVG tool

Here's an example link. The tool uses Pako 2.1.0, MathJax 4.1.3, faster-latex 0.3.1, and DOMPurify 3.4.16.

Screenshot of a web app titled "LaTeX renderer" with a split-pane layout. The top bar has an Edit/Rendered toggle, a blue Copy link button, and a Share button. The left pane, labeled LaTeX source with a "Document · faster-latex (WASM)" badge, has a URL/GitHub Gist input with a Load button, a code editor containing a LaTeX document, and rows of example buttons (Quadratic formula, Gaussian integral, Maxwell, Attention, Matrix, Chemistry, Prose, TikZ, Document). The right pane shows the typeset output: a paper titled "Sums of Odd Numbers" by A. Student, with a section stating a theorem that the first n odd numbers sum to n squared, a Proof section with numbered equations, and a bulleted list of small cases.

Another game experiment with Claude. This one used the default Claude iPhone app (chat mode, not Claude Code mode), where I prompted Claude Opus 5.5 Max with:

Build a three js game called "Tree appreciator" - it shows you two algorithmically generated trees and the game mechanics is about appreciating the differences between them. Think hard about how to make sure it is both fun and beautiful.

Somewhat embarrassingly given my recent talk, I've found that telling Opus 5.5 "make sure it is fun" works uncomfortably well. In this case Claude crunched for 3 hours and 7 minutes before retuning a cosy little spot-the-difference game with music and animation and achievements that's quite compelling to play.

Screenshot of a mobile spot-the-difference puzzle game with a dark interface. Header reads "No. 003 Acer autumnalis ‘Hid…" with subtitle "Autumn maple · A country lane in late a…" and icons for sound, a book, and help. Two nearly identical 3D-rendered scenes are stacked vertically, labeled "Fig. i" and "Fig. ii", each showing a dark-trunked maple tree with red, orange and pale peach leaves, leaves falling through the air, a golden grassy field with a few small rocks, and hazy hills with pine silhouettes under a pale sky. Two differences are circled in blue in both images: circle "a" at the base of the trunk, where Fig. i has a small red mushroom that is missing in Fig. ii, and circle "b" in the right side of the canopy, where Fig. i has a patch of green leaves that are red in Fig. ii. The bottom bar shows "2 of 4", a reset button, a "Hint" button with three filled and two empty dots, and a score of "1,803".

I added support to llm-gemini for the new Gemini 4 Argon model, made available today via the Gemini API and for customers of their $100/month subscription plan.

Here are the low, medium and high pelicans. As expected, they are all excellent: Gemini has a track record of producing great SVGs, and are the only lab where I know their staff have invested in SVG specifically (and who have boasted about their pelicans before.)

Here's the "high" illustration, which cost me 17.166 cents:

Stylish, accurate bicycle frame. Fish in the basket. Snazzy scarf. Feet on either side of the frame touching the pedals. Spokes, a little hat, a good beak and pouch, a somewhat fierce expression.

The pricing is interesting. At launch, Argon is $2/million input and $10/million output - the same price as GPT-6 Sol, half the price of Claude Opus 5.5 and 1/5th the price of Claude Fable 5.1 and GPT-6 Astra.

But on December 1st Argon is set to double in price - so it will be the same price as Opus 5.5.

Prices like this aren't really comparable these days since what really matters is how many tokens a model takes to achieve a goal within an agentic harness.

One useful clue for that comes from Artificial Analysis, who publish the total cost to run their benchmark using each model. Argon is looking very good there - costing $2,407 to run the benchmark, putting it close to GLM-5.3 and significantly cheaper than OpenAI, Anthropic, and Meta's latest models.

When the price doubles it will still be a little cheaper than GPT-6 Astra.

Screenshot of a stacked bar chart from Artificial Analysis comparing dollar costs for 14 AI models, sorted from lowest to highest, with bars colored by provider, the provider's logo beneath each bar and angled model names along the bottom. Logo at top right: Artificial Analysis. A hover tooltip pointing at the Gemini 4 Argon bar reads: Gemini 4 Argon (High), $2,407, Output $313, Reasoning $815, Cache Write $897, Cache Read $264, Non-Cache Input $118, Click for more info. Bars from left to right, with the total above each bar and some segment values printed inside: Qwen3.8 27B (xhigh), $1,336, Alibaba logo; Mistral Large 4 Preview, $1,607, Mistral logo; Gemini 3.8 Flash (high), $1,623, Google logo; Muse Spark 1.3 (max), $2,000, segment $769, Meta logo; Gemini 4 Argon (high), $2,407, segments $815 and $897, Google logo; GLM-5.3 (max), $2,503, segment $790, Z.ai logo; Kimi K3 (max), $3,658, Kimi logo; Qwen3.8 Max (0902), $4,935, segments $893 and $1,441, Alibaba logo; Grok 4.7 (xhigh), $4,967, segments $1,861 and $1,618, xAI logo; GPT-6 Astra (max), $5,324, segments $778 and $978, OpenAI logo; Muse Wonder (max), $5,733, segment $1,748, Meta logo; Claude Sonnet 5.5 (max with fallback), $7,260, segments $1,216 and $1,815, Anthropic logo; Claude Opus 5.5 (max with fallback), $8,708, segment $921, Anthropic logo; Claude Fable 5.1 (max with fallback), $13,129, segment $7,219, Anthropic logo.

(I used ChatGPT to edit that chart! The data is all correct, I checked - I needed to get that Gemini 4 Argon info box to display without overlapping the other numbers.)

Some bonus examples using Gemini 4 Argon: here's Generate an SVG of an armadillo in fishnet tights jaywalking on Mars, here's a Fabergé egg it created for me using Blender, and DeepMind staffer @fofrAI shared a video of a pelican riding a bike, using fourier epicycles. That's a fun new twist!

Meta AI release Muse Wonder (and Muse Wonder Full), their new "most capable models". These look like they may be Meta's first Fable class models - Artificial Analysis scores Muse Wonder (Max) as equivalent to GPT-6.1 Sol.

I updated my llm-meta-ai plugin for the new model. Here are pelicans for Muse Wonder for the six reasoning levels: minimal, low, medium, high, xhigh, max. This is the max one:

Blue cycling helmet, bicycle is missing one bar but otherwise an OK shape, has mudguards, nice background, OK beak.

For comparison, here are pelicans for Muse 1.3 (released September 2nd) and Muse 1.2 (released August 5th). Meta AI are putting out a new model a month, and the improvements between each model (at least in terms of drawing pelicans) are material.

Sighting 2:41 PM – 2:46 PM — Brewer's Blackbird, California Brown Pelican, Heermann's Gull, in Pescadero State Beach, CA, US
Brewer's Blackbird
Brewer's Blackbird
California Brown Pelican
California Brown Pelican
Heermann's Gull
Heermann's Gull

I put the new Python 3.15 profiler through its paces by having GPT-6 Astra Extra High in Codex run it against my new web-edit app:

I need a Python 3.15 flame graph and heatmap demo of the "web-edit" app from PyPI - research first then make me those demos

Here's the resulting example flame graph and heatmap.

I was working on a project from my phone using Codex Remote when I found myself wanting to edit a credentials file without round-tripping those credentials through the LLM itself.

So... I had Codex and GPT-6 Astra Extra High build this Python web app which provides a web UI for viewing and editing files in a folder. It's intended to be run over Tailscale, so I can have an agent start this running and then edit files via my Tailscale network directly from my phone.

Here's the interface for browsing files in a folder:

Screenshot of a web file manager interface. Header reads "WORKSPACE" above the title "Files", with buttons "Refresh", "Upload files" and "New file" (dark green). A breadcrumb shows "web-edit / web_edit / static". A table with columns "Name", "Size", "Modified" lists four files, each with "Download ↓" and "Delete" links: "app.css" 8.4 KB Oct 12, 2026; "app.js" 671.5 KB Oct 12, 2026; "index.html" 4.3 KB Oct 12, 2026 (underlined, as if hovered); "THIRD_PARTY_LICENSES.txt" 32.3 KB Oct 12, 2026. Below the table: "Images under 2 MB appear inline. Select a text file to edit it." A panel below is labelled "UPLOAD QUEUE" with heading "Add files" and a "Close" button. It has a "Destination folder" text field containing "web_edit", then a dashed drop zone reading "Choose files or drop them here" and "Set a path and filename for each file before uploading." with a "Choose Files" button and the text "no files selected". A greyed-out "Upload files" button sits at the bottom right.

Editing uses CodeMirror 6 - I was going to use Monaco but that still doesn't have a great mobile experience yet.

My plugin for detecting and listing all Datasette instances on the current machine now works with the latest version, and displays the detected PID as well. Knowing the PID makes it easier to attach the new Python 3.15 profiler.

Sighting 4:15 PM – 4:48 PM — White-crowned Sparrow, Great Egret, Lesser Goldfinch, in City of Sunnyvale, California, CA, US
White-crowned Sparrow
White-crowned Sparrow
Great Egret
Great Egret
Great Egret
Great Egret
Lesser Goldfinch
Lesser Goldfinch

I released ttok 0.4, ran uv tool upgrade ttok, piped a file into the new version... and realized that it was defaulting to the GPT-4 tokenizer when it should very clearly default to GPT-5/GPT-6 instead!

I figured switching the default was a reasonable excuse to finally ship a 1.0.

OpenAI haven't actually confirmed that GPT-6 uses the same tokenizer as the GPT-5 family yet - there's an angry issue about it - but I found this commit by William Liu which reports on an experiment he ran confirming that the tokenizers are likely the same:

All seven GPT models (5.5, 5.6 Sol/Terra/Luna, 6 Astra/Sol/Luna) report 44,794 tokens and match each other on every one of the 31 fixtures. GPT-6 introduces no input-count change on this corpus.

ttok is my CLI tool for counting tokens, using OpenAI's open source tiktoken library.

It hasn't been in updated in a couple of years, but I finally fixed a Click warning, updated CI, and added a --list-models command to list available models.

It works with uvx, so you can count tokens in anything like this:

cat file.txt | uvx ttok
Sighting 11:34 AM – 1:08 PM — California Towhee, Red-tailed Hawk, California Brown Pelican, Osprey, in San Mateo County, CA, US
California Towhee
California Towhee
Red-tailed Hawk
Red-tailed Hawk
Red-tailed Hawk
Red-tailed Hawk
California Brown Pelican
California Brown Pelican
Osprey
Osprey
Osprey
Osprey

OpenAI released their new Jev-style Decisions API, as previously announced at last week's DevDay.

Since I already have an llm-typesafe plugin for talking to Jev, I had GPT-6 Astra read the new OpenAI API documentation and build an llm-openai-decisions plugin inspired by llm-typesafe.

Unlike Jev, the new gpt-6-luna decision model supports image input in addition to text. Both models charge for input it and not for output: OpenAI's is 10 cents per million input tokens, Jev's is 4.2 cents per million.

Otherwise the API shape is very similar to Jev, at least conceptually. Jev supports three question types for yes/no, choices, or scores. OpenAI Decisions supports the same three types.

Install the plugin like this:

llm install llm-openai-decisions

Here's an example query against an image attachment:

llm -m openai-decisions/gpt-6-luna \
  -a https://static.simonwillison.net/static/2025/two-pelicans.jpg \
  -s 'Does this image contain any mammals?'

And example output:

{"type": "predicate", "name": "evaluation", "probability": 0.0}

Consult the README for full details of how to run the other types of questions.

Adds support for reasoning models, such as the newly released Mistral Large 4.

Comment My comment on EmbeddingGemma 2 — Hacker News

I really appreciate that EmbeddingGemma 2 is under the Apache 2.0 license.

For embedding models in particular, I don't think it makes sense to use a closed, proprietary, hosted-only model.

Most applications of embedding models involve calculating thousands or even millions of embedding vectors and storing them for later comparison.

If your model is proprietary, the vendor is likely someday going to decide to stop offering that model. They'll have a better model to replace it, but you still need to pay to re-calculate those millions of stored existing vectors.

(In April 2024 OpenAI offered to "cover the financial cost of users re-embedding content with these new models" - https://openai.com/index/gpt-4-api-general-availability/ - but I don't think that's something we can rely on from every provider.)

Notably, I don't want to host the model myself. I'd much rather pay a provider for a hosted model while knowing that if they ever stop hosting it I can run the open weights version myself - or find another vendor who can do that for me.

# 6th October 2026, 8:37 pm / google, ai, generative-ai, embeddings, gemma

None

I saw Parseable in a Show HN today - it's a new observability platform with both an open source (AGPL) Rust implementation (a single ~180MB binary), an "Enterprise" version with extra features and a cloud hosted option.

Since Datasette 1.0a41 added OpenTelemetry support (thanks, Alex Garcia), I decided to fire up Codex and have it figure out how to run Parseable and feed it traces from Datasette.

Here's my (human-written) TIL showing the patterns that worked, and here's a screenshot of a Datasette trace displayed within the Parseable localhost web application:

Screenshot of a trace detail view in an observability web app, with a span waterfall overlaid on a dimmed navigation sidebar and filter column. Dimmed sidebar: breadcrumb "Community > Traces > datas" (cut off), search box "Search... ⌘K", nav items "Home", "Ingest telemetry", section "ANALYZE": "Keystone", "Dashboards", "SQL Editor", section "OBSERVE": "Logs", "Metrics", "Traces" (selected), "APM", "Agents", section "MONITOR": "Alerts", "Errors", section "DATA": "Datasets", and at the bottom "Settings", "Book a call", "Support". Dimmed filter column, cut off at the right edge: "Search fi", "Core", "Log format", "User agent", "Source IPs", "Error", "Service", "service.ins", "service.na", "datasett" (checked), "Span", "Database", "HTTP", "http.reque", "NULL" (unchecked), "GET" (checked), "http.respo", "http.route", "Server", "server.add", "Telemetry", "URL", "All fields". Trace panel header: "Trace detail > 6f819a2170bcd1e91c6ea3ae236ec60b" with a copy icon, a "Related logs" button and a close X. Summary: "Start time 6:56 PM, Oct 6, 2026 UTC", "Duration 40.9 ms", "Spans 247". A minimap with axis "0ns 10.2ms 20.5ms 30.7ms 40.9ms" shows many short span bars cascading diagonally from top left toward the lower middle, with a few longer bars. Below is a span table with a "Span name" header, a "Search spans..." box, collapse and expand buttons, and a timeline axis "0ns 10.2ms 20.5ms 30.7ms 40.9ms". Rows (name, service, duration): root span with collapse toggle "123", "GET /..." "datasette..." 40.9ms spanning the full timeline; then alternating rows where each "db.query" has a collapse toggle "1": db.query datasette-local 679µs, db.query.execute datasette-local 278µs, db.query datasette-local 341µs, db.query.execute datasette-local 55µs, db.query datasette-local 357µs, db.query.execute datasette-local 197µs, db.query datasette-local 330µs, db.query.execute datasette-local 73µs, db.query datasette-local 2.26ms, db.query.execute datasette-local 2.02ms, db.query datasette-local 232µs, db.query.execute datasette-local 64µs, db.query datasette-local 207µs, db.query.execute datasette-local 71µs, db.query datasette-local 6.11ms. The child span bars start progressively later across the early part of the timeline.

Comment My comment on Mistral Large 4 — Hacker News

wren6991: The benchmark is saturated. Frontier models are tested with an armadillo in fishnet tights jaywalking on Mars.

OK well I couldn't resist this one:

llm -m claude-opus-5.5 'Generate an SVG of an armadillo in fishnet tights jaywalking on Mars'
llm -m gpt-6.1-sol 'Generate an SVG of an armadillo in fishnet tights jaywalking on Mars'
llm -m gemini-3.8-flash 'Generate an SVG of an armadillo in fishnet tights jaywalking on Mars'
llm -m mistral/mistral-large-4 'Generate an SVG of an armadillo in fishnet tights jaywalking on Mars'

Default reasoning levels for each: https://tools.simonwillison.net/markdown-svg-renderer?url=ht...

# 6th October 2026, 6:20 pm

A minor fix for compatibility with the latest Datasette alphas. This meant we could upgrade the datasette.io site to Datasette 1.0a41.

I wanted to see if Claude Opus 5.5 could compose music, so I tried this:

I want you to write some computer game music for me. First design simple text based format for the music and build an artifact that can play it out loud - include some example tracks in that artifact

I am looking for music of the quality of the original secret of Monkey Island

It leaned a lot harder into the Monkey Island theme than I had intended, but the results are surprisingly good.

Screenshot of a retro pixel-art web music player. Header in blackletter type reads "Scrimshaw Jukebox", with the text "Six original adventure-game tracks, written as plain text and played by a synthesizer running in your browser. Pick a tune, press Play, then open the score and change it." A large pixel-art scene shows a harbor at night under a purple starry sky: a full moon at top right reflecting on the water, an island silhouette on the left with palm trees and a hut with two lit windows, and a sailing ship moored at a wooden pier. Overlaid on the scene: "Moonlit Harbor" and "Press Play". Below it a bar reads "Play Moonlit Harbor". A control panel has buttons "Play", "Stop", "Restart", "Loop: on", "Edit score", "Read guide" and a "Volume" slider set to about three quarters. A track list of six cards, the first highlighted: "Moonlit Harbor 100 bpm · 4/4 · 16 voices · 1:26", "The Rusty Anchor 112 bpm · 6/8 · 8 voices · 0:56", "The Ghost Galleon 66 bpm · 4/4 · 9 voices · 2:11", "The Jungle Path 92 bpm · 4/4 · 12 voices · 1:29", "Duel on the Docks 152 bpm · 4/4 · 12 voices · 1:13", "Lantern Waltz 96 bpm · 3/4 · 8 voices · 1:38". A section titled "Score view" with the caption "1:26 · 4/4 at 100 bpm · Main theme. A calypso for a harbour town after dark." shows a piano-roll visualization of colored horizontal note bars and percussion ticks on a dark background, with a section marker "A" and a yellow vertical playhead line. A color-coded legend of voices reads: "pan steeldrum", "flute flute", "marimba marimba", "skank organ", "strings strings", "harp harp", "bass fretless", "timp timpani", "kick kick", "rim rim", "shaker shaker", "conga conga", "tumba tumba", "bongo bongo", "crash crash", "surf surf". Footer text: "Click a voice to mute it. Space bar plays and stops."

I wonder if the ability to compose competent music is similar to the 3D graphics thing - a new capability for text models that emerged in the past few months?

Would need some careful experiments with other recent and not-so-recent models to confirm if this is new or if they've been able to do this for a while.

Sighting 6:15 PM – 6:31 PM — Brewer's Blackbird, California Brown Pelican, Common Raven, in Monterey Bay National Marine Sanctuary, CA, US, CA
Brewer's Blackbird
Brewer's Blackbird
California Brown Pelican
California Brown Pelican
Common Raven
Common Raven

Colin Frasier posted on Bluesky about an experiment he ran over two years ago using GPT-4o to see how well it could "compute the sum but return the answer in words" across increasingly large numbers. Here's the chart he shared of those results:

Heatmap chart of accuracy on an addition prompt, colored from dark green (high) through yellow to dark red (low). Title: "What is {a} + {b}? Please write your answer in words. Do not include any other text or information, just the answer in words." Subtitle: 30 randomly selected pairs for each digit combination (n = 30 * 13 * 13 = 5070). X axis: Number of digits in a, 1 to 13. Y axis: Number of digits in b, 1 to 13. Legend: Accuracy, 1.00, 0.75, 0.50, 0.25, 0.00. Values by row, listed for a = 1 to 13. b = 13: 100%, 77%, 27%, 20%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%. b = 12: 97%, 80%, 80%, 40%, 23%, 20%, 7%, 13%, 20%, 27%, 67%, 63%, 3%. b = 11: 97%, 97%, 53%, 17%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 37%, 0%. b = 10: 100%, 90%, 47%, 20%, 7%, 0%, 0%, 0%, 3%, 0%, 0%, 7%, 0%. b = 9: 97%, 93%, 80%, 77%, 53%, 67%, 47%, 87%, 97%, 3%, 0%, 13%, 0%. b = 8: 93%, 87%, 53%, 43%, 7%, 0%, 0%, 13%, 87%, 0%, 0%, 0%, 0%. b = 7: 93%, 93%, 47%, 10%, 13%, 20%, 23%, 0%, 70%, 0%, 0%, 0%, 0%. b = 6: 100%, 100%, 100%, 83%, 97%, 97%, 23%, 0%, 53%, 3%, 0%, 10%, 0%. b = 5: 100%, 100%, 80%, 70%, 73%, 100%, 13%, 13%, 70%, 0%, 20%, 30%, 0%. b = 4: 100%, 100%, 93%, 100%, 60%, 97%, 20%, 50%, 67%, 53%, 40%, 40%, 40%. b = 3: 100%, 100%, 97%, 90%, 83%, 100%, 63%, 50%, 63%, 53%, 60%, 60%, 30%. b = 2: 100%, 100%, 90%, 97%, 93%, 100%, 93%, 83%, 90%, 83%, 87%, 87%, 83%. b = 1: 100%, 100%, 100%, 97%, 100%, 97%, 97%, 97%, 100%, 100%, 100%, 97%, 100%.

I'm confident GPT-4o didn't cheat and use a calculator, especially since it got so many of the calculations wrong, but I was inspired to run the experiment again on local hardware (a DGX Spark) to explore the effect in a fully controlled environment.

I pasted his image into a Codex Remote session (GPT-6 Astra) and had it run the same experiment using Qwen3.8-27B-Q4_K_M.gguf. Here's the result for a run of 30 attempts per combination with reasoning disabled:

Heatmap in the same layout as the previous chart, using an orange (low) to white to blue (high) color scale, showing much lower accuracy overall. Title: Addition in words — Qwen3.8 27B Q4_K_M. Subtitle: Reasoning disabled · 30 fixed pairs per ordered digit-length cell (n = 5,070). Overall numeric accuracy: 1,195 / 5,070 (23.57%). X axis: Number of digits in a, 1 to 13. Y axis: Number of digits in b, 1 to 13. Legend: Accuracy, 100%, 75%, 50%, 25%, 0%. Values by row, listed for a = 1 to 13. b = 13: 17%, 13%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%. b = 12: 53%, 20%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%. b = 11: 47%, 10%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%, 0%. b = 10: 70%, 27%, 3%, 0%, 0%, 0%, 0%, 0%, 0%, 13%, 0%, 0%, 0%. b = 9: 77%, 47%, 3%, 0%, 0%, 0%, 0%, 3%, 7%, 0%, 0%, 0%, 0%. b = 8: 53%, 20%, 0%, 0%, 0%, 0%, 7%, 13%, 0%, 0%, 0%, 0%, 0%. b = 7: 53%, 23%, 17%, 10%, 3%, 3%, 13%, 3%, 0%, 0%, 0%, 0%, 0%. b = 6: 60%, 60%, 33%, 10%, 53%, 47%, 7%, 3%, 0%, 0%, 0%, 0%, 0%. b = 5: 73%, 67%, 87%, 80%, 53%, 40%, 0%, 0%, 3%, 0%, 0%, 0%, 0%. b = 4: 83%, 93%, 90%, 93%, 53%, 13%, 0%, 0%, 0%, 0%, 0%, 0%, 0%. b = 3: 100%, 93%, 90%, 80%, 67%, 37%, 17%, 0%, 0%, 3%, 0%, 0%, 0%. b = 2: 100%, 100%, 93%, 90%, 77%, 77%, 43%, 50%, 63%, 43%, 40%, 13%, 23%. b = 1: 97%, 100%, 100%, 100%, 80%, 67%, 77%, 80%, 80%, 60%, 43%, 30%, 37%. Footnote: Colorblind-safe orange–blue scale; percentages provide a redundant non-color encoding.

Then I ran it again with reasoning enabled. This took a lot longer per pair, so instead of running 30 samples per square I ran just one - which results in a much less visually appealing heatmap since each square is either 100% or 0%:

Heatmap in the same layout as the previous charts, almost entirely blue. Title: Addition in words — Qwen3.8 27B — medium reasoning pilot. Subtitle: 1 fixed pair per ordered digit-length cell · easiest first (n = 169). X axis: Number of digits in a, 1 to 13. Y axis: Number of digits in b, 1 to 13. Legend: Accuracy, 1.00, 0.75, 0.50, 0.25, 0.00. Every cell shows 100% except two orange cells showing 0%: a = 2 with b = 8, and a = 12 with b = 9.

It got the right answer in 167 out of 169 attempts, and since these were one-shot I'm confident a second run would produce different results here.

Here's a version of the report that includes the reasoning traces from some of those larger calculations, which include text like this:

Wait, let me redo this more carefully.

4,299,366,105,622
6,088,794,067,970

Let me align them:
4 2 9 9 3 6 6 1 0 5 6 2 2
6 0 8 8 7 9 4 0 6 7 9 7 0

Adding from right to left:
Position 1 (units): 2 + 0 = 2
Position 2 (tens): 2 + 7 = 9
Position 3 (hundreds): 6 + 9 = 15, write 5, carry 1
Sighting 9:35 AM – 9:58 AM — Alpaca, Red-shouldered Hawk, in San Mateo County, CA, US
Alpaca
Alpaca
Alpaca
Alpaca
Red-shouldered Hawk
Red-shouldered Hawk
Green Rex's Dino Store sign with yellow lettering advertising NEWS • ROCKS • EGGS • LEAVES • STICKS • NEST GOODS • LOTTO, beneath a window displaying dinosaur-themed newspapers and candy bars, framed by white subway tiles.

Located just before the turnstiles in the Grand Army Plaza subway station at the north end of Brooklyn's Prospect Park is this former newsstand which is now operated by a dinosaur.

The density of dinosaur puns is exceptional.