Thursday, 27 August

02:14

[$] LWN.net Weekly Edition for August 27, 2026 [LWN.net]

Inside this week's LWN.net Weekly Edition:

  • Front: AGPL violations; OpenMDW license; quantum computing and encryption; 7.3 merge window; Remind; Quickshell.
  • Briefs: arrayref; RIP Steve French; Armbian 26.8; Vanilla OS 3; Emacs 31.1; KDE Gear 26.08; LibreOffice 26.8; RPM 6.1.0; Quotes; ...
  • Announcements: Newsletters, conferences, security updates, patches, and more.

01:28

View From a Hotel Balcony, 8/26/26: Anaheim [Whatever]

It’s the happiest parking lot on Earth!

We are here, of course, for LACon V, this year’s Worldcon, where I will doing panels, a reading, a signing, and of course DJing a dance. I may also win a Hugo, but then, I might not. Either way, I still have Hugos, so it’s fine either way.

It’s very hot here at the moment. I understand it’s going to get hotter. Fortunately I will be mostly in air-conditioned places.

If you’re at the convention and see me, come say hi. If you’re not at the convention, you will likely not see me. But if somehow you do, you can still say hello. I’ll be easy to spot, I’ll be the short dude next to the stunning Amazon.

— JS

Wednesday, 26 August

23:07

20:56

Job opportunity: Systems Integration Administrator at the Free Software Foundation [Planet GNU]

The Free Software Foundation (FSF), a Massachusetts 501(c)(3) charity with a worldwide mission to promote computer user freedom, seeks a motivated and talented individual to be our new Systems Integration Administrator. This position is ideally full-time and US-based, but exceptions can be made for a qualified candidate.

20:14

Job opportunity: Systems Integration Administrator at the Free Software Foundation [Free software jobs]

The Free Software Foundation (FSF), a Massachusetts 501(c)(3) charity with a worldwide mission to promote computer user freedom, seeks a motivated and talented individual to be our new Systems Integration Administrator. This position is ideally full-time and US-based, but exceptions can be made for a qualified candidate.

Great Chairs At A Great Price [Penny Arcade]

I'm obsessed with Lanterns. We both are. And even though our affection for justice is roughly equivalent - even though I'm the only one who knows what Sector we're in - still, the ring chose him. I have a rubric for keeping myself unmolested in this time, and it involves recognizing if something is green or not. Historically, green has been an inviting color - that's what makes it all so insidious.

20:00

Dirk Eddelbuettel: linl 0.0.6 on CRAN: Maintenance [Planet Debian]

A new release of our linl package for writing LaTeX letters with (R)markdown is now on CRAN. linl makes it easy to write letters in markdown, with some extra bells and whistles thanks to some cleverness chiefly by Aaron.

This version is mostly maintenance: updates to the continuous integration setup, as well as updates to packaging including use of Authors@R in DESCRIPTION. No functional changes, no new code, or new features.

The NEWS entry follows:

Changes in linl version 0.0.6 (2026-08-26)

  • Several updates to continuous integration and testing

  • Switch to Authors@R in DESCRIPTION

Courtesy of CRANberries, there is a comparison to the previous release. For questions or comments use the issue tracker off the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

Freexian Collaborators: Monthly report about Debian Long Term Support, July 2026 (by Santiago Ruano Rincón) [Planet Debian]

The Debian LTS Team, funded by [Freexian’s Debian LTS offering] (https://www.freexian.com/lts/debian/), is pleased to report its activities for July.

Activity summary

During the month of July, 23 contributors have been paid to work on Debian LTS (links to individual contributor reports are located below).

The team released 52 DLAs fixing 2159 CVEs.

In July, the Debian Stable Release Managers published the last point release of Debian 12 (“bookworm”), after which the Debian LTS team took full responsibility of Debian 12. This completes the handover from the Security Team, that took place in June. This also marks the second month in a row where the Debian LTS has been focusing on two simultaneous Debian releases.

Other than Debian 12, the team is maintaining Debian 11 (“bullseye”), which will reach the end of its Long Term Support on 31 August 2026. After that date, Freexian will continue the security support under the Extended LTS offer.

The team published several notable updates:

  • jq (DLA 4662-1 and DLA 4661-1) prepared by Andreas Henriksson in collaboration with Jochen Sprickerhof, addressing multiple vulnerabilities.
  • Several updates for the different linux supported versions prepared by Ben Hutchings, in collaboration with Emilio Pozuelo Monfort. Other than the regular security advisories: DLA 4664-1, DLA 4665-1, DLA 4671-1, DLA 4688-1, and DLA 4700-1, Ben started preparing packages of 6.12 via bookworm-backports.
  • nginx (DLA 4667-1), updated for bookworm by Carlos Henrique Lima Melara, as a follow up of the bullseye update (DLA 4660-1), that was prepared in June.
  • grub2/bullseye (DLA 4685-1), prepared by Emilio. Other than addressing several security issues, this DLA was needed for being able to update the shim boot loader.
  • samba (DLA 4692-1), uploaded by Markus Koschany, to fix several security flaws in bullseye, including issues that could yield to remote code execution.
  • imagemagick (DLA 4680-1 and DLA 4696-1), prepared by Bastien Roucariès, addressing several issues that could lead to denial of service, information disclosure or potentially arbitrary code execution in some scenarios.
  • poppler (DLA 4709-1), by Guilhem Moulin, fixing several vulnerabilities.
  • nss (DLA-4694-1), by Jochen, fixing flaws that may result in or denial of service or potentially the execution of arbitrary code.

Contributions from outside the LTS Team:

The LTS Team has also contributed with updates to the latest Debian releases:

  • Bastien also proposed two updates for imagemagick. The first one released as DSA 6383-1, and the second as a trixie point update proposal (#1142554).
  • python-httplib2 by Emmanuel Arias, and released by the security team as DSA 6441-1 in August.
  • hplip (DSA 6402-1), prepared by Thorsten Alteholz, to address privilege escalation and arbitrary code execution related flaws.
  • libnfs trixie update (#1142351), by Thorsten
  • patool update for trixie #1141607, by Abhijith PA

Other contributions:

Besides the work on security updates, different documentation and tooling changes were needed, especially in the context of the Debian 12 handover. This work was mainly done by Sylvain Beucler.

Individual Debian LTS contributor reports

Thanks to our sponsors

Sponsors that joined recently are in bold.

19:14

18:42

Five more organizer tales: LibreLocal 2026, part three [Planet GNU]

From Canada to Poland, LibreLocal 2026 organizers shared free software with their communities!

Effective Patterns for Advanced MCP Usage [Radar]

The following article originally appeared on PulseMCP’s blog and is being republished here with the authors’ permission.

Most MCP demos feature a single server connecting to a single client. For example, you might wire up a Gmail MCP server to Claude Code. It works! It triages your inbox, drafts replies, finds that thing from three weeks ago.

But…it’s a little pointless. Gmail already has a perfectly good interface for email. It’s called Gmail. Google has spent 20 years refining it. If “chat with your inbox” were all MCP got you, you’d be right to wonder what the fuss is about.

Connecting to multiple servers starts the unlock

MCP Client

Here’s the same Gmail MCP server doing something Gmail can’t do alone: filing business expense receipts.

An IKEA order confirmation is sitting in my inbox, receipt attached. Benepass—a benefits provider—wants that receipt uploaded and submitted. Claude Code can find the email, pull the attachment, log into Benepass by retrieving the one-time code from Gmail, upload the receipt, and submit. Done.

No single app could do this, because the job crosses apps. Server composition is a killer feature of MCP, not just “your AI talks to one integration.”

Where things get really interesting: Multiple clients

7 clients × 6 servers = 42 connections to configure7 clients × 6 servers = 42 connections to configure

There is clear value in connecting multiple servers to a client like Claude Code. Taking the pattern a step further, there’s also value in connecting those same servers to other interfaces you like to use. Claude Code in your terminal shouldn’t be the only way you access AI. Claude.ai can be another entry point. Gmail can be another. Linear yet another. The list goes on.

You’ll often want the same integrations available when you’re doing a quick task inside Slack as you would while running a long agentic task with Claude Code.

You could be conversing with a coworker, CC in “@ai does our discussion here align well with current company strategy?” and get an inline response that incorporates your company OKRs from Notion and some recent Zoom transcripts from the last few product strategy meetings.

Or you’re working through your to-do list in Linear, realize you need to schedule a meeting as the action item for one of your tickets, and you can comment on a ticket “@ai schedule a meeting with John and draft an agenda based on the meeting I just had with Pam to address this.”

These native MCP client functionalities are officially on their way to many of the interfaces you use today. And we’re starting to see prominent nonnative integrations like Claude Tag fill this need too.

But even better: You can already set up yourself and your team with these capabilities today. You just need to bridge the desired surface to your own agent harness behind the scenes.

A small bit of glue injects a fully capable agentic harness and MCP client behind a webhook or polling process—no native support needed.A small bit of glue injects a fully capable agentic harness and MCP client behind a webhook or polling process—no native support needed.

All it takes is awareness of the right patterns and some MCP-friendly glue.

Go remote ASAP; local servers won’t get you far

Local servers are hard for end-users. “Just install npm, then edit this JSON file, then set these environment variables” isn’t something you want to say to most of your colleagues.

Remote servers are much easier: “Here’s a URL to paste in somewhere.” Some surfaces only support remote servers, like claude.ai.

Wrap any local server: OAuth in front, per-user credentials behind. Share a link, not a setup guide.Wrap any local server: OAuth in front, per-user credentials behind. Share a link, not a setup guide.

So you can use local servers to prove out some flow, but you should prefer remote. Many servers you may want to use are only provided as local implementations, so you need a tool to convert them to remote servers. Because most local servers were designed to be used by one authenticated user at a time, this can be tricky.

The pattern that solves this pain point is to use a bridge like mcp-auth-wrapper to take a local server and turn it into a remote, multitenant one: OAuth in front, per-user credentials behind. Sharing any server becomes sharing a link.

Remove friction from the configuration process

Okay, we’re down to one link per server. But exactly where do my users put this link?

The one-size-fits-all pattern here is to provide installation guidance for every possible MCP client app. A service like install-mcp makes this easy: clean UX to generate the right install link and per-client instructions, so you share one page instead of writing a tutorial.

Or if you want to roll it into your own interface, tap into the TypeScript library version of this: mcp-install-instructions.

We’re working on standardizing the mcp.json file format here to simplify this story in the long term, but ultimately we still expect non-CLI interfaces to each have a slightly different flow for “enabling a connector.” For many enterprises, this responsibility may soon become solely an IT affair with enterprise-managed auth.

Remove the need to do it again, and again

What happens when we start to bring new clients into the fold? By default, each user has to configure and authenticate each MCP server independently. 10+ “add connector” flows. 10+ OAuth dances. Done once for Claude Code, then again for Linear, for email…and so on.

The solution: Centralize your configuration and auth storage in a single, aggregated MCP server. A deployment of mcp-aggregator can do this for you: one endpoint, one login, every tool namespaced behind it. Configure each client once. Login once per service. Share one link with your teammates.

7 + 6 = 13 connections—configure each side once.7 + 6 = 13 connections—configure each side once.

mcp-aggregator is the minimal, DIY version of an MCP gateway. If you have enterprise needs like SSO integration or fine-grained IT admin controls, you could use this layer of MCP server consolidation as the piece of your infrastructure where you can add those bells and whistles.

By default, mcp-aggregator also loses out on the ability to use MCP server configurations as per-session constraints. However, you could build out your mcp-aggregator deployment to re-enable the constraints that matter to you. For example, by offering query parameters like ?readOnlyTools=true or ?serversEnabled=datadog,sentry. Or by giving discrete MCP servers unique endpoints (but still aggregating the auth concerns under the hood).

Work around the long tail of missing MCP servers

Most of your MCP server needs can be solved by walking through the options for choosing (or building) an MCP server. But is it always worth the effort?

Say you switched home utilities plans. An energy provider, Octopus Energy, emailed you a confirmation. You want the pricing data in Home Assistant, which controls your smart thermostat, and Octopus Energy does have an API for it—but the API key is behind a website login, and there’s no API for getting the API key.

Solution: Give the agent a screen. computer-use-mcp is a minimal example of an MCP server that can click and type like a human to log into the website, copy the key, then go back to clean API calls to set up the dashboard.

With that one escape hatch, “there’s no API for that” or “it’s too much work to find an MCP server” stops being a blocker forever.

To borrow from Anthropic’s framing of this problem:

If you have an MCP server for the service, Claude uses that.
If the task is a shell command, Claude uses Bash.
If the task is browser work and you have Claude in Chrome set up, Claude uses that.
If none of those apply, Claude uses computer use.

And indeed, if you find yourself regularly leaning on inefficient approaches like browser use or computer use to get a predictable workflow done, it may be worth your while to abstract away those Playwright calls into a reliable MCP server, like this Good Eggs example.

You can even bring local-only servers into the remote-first fold

Some servers only work when they run on your own personal machine. computer-use is the obvious example. And sometimes, you just want to use your phone to tell Claude to do something that relies on something readily available on your laptop upstairs.

mcp-local-tunnel shows off the pattern that makes machine-bound servers available through remote aggregation just like everything else.

A tunnel makes machine-bound servers look like any other remote endpoint.

Don’t forget the context bloat footgun

Naive tool calling has a much-maligned drawback: Every intermediate result flows through the model. And for many clients, every tool definition is placed in context up front, meaning you’ve spent tens of thousands of tokens before even starting.

For example, asking the agent to copy a doc’s contents from Google Drive into Salesforce means the entire doc passes through the model twice—for no reason. Anthropic measured one workflow dropping from 150,000 tokens to 2,000 by fixing this.

There are several ways to solve this problem, each with its own trade-offs worth its own blog post:

  • Code execution with MCP. tool-sandbox-mcp shows how a single execute_code abstracts away the problem by adding a layer of code execution in between your agent and your aggregated set of servers. Works inside any MCP client.
  • MCP as a CLI tool. call-mcp shows how wrapping your tools this way means you can compose them with your usual CLI toolkit—shell, jq, cron, scripts, and other CLI tools.
  • Search tools, truncate large responses. This is the way Claude Code does it natively, but it could be implemented as a bridge, much like the above examples.

Put these patterns together, and you’ve solved the MxN problem

From 1×1 to M+N: the progression we’ve walked throughFrom 1×1 to M+N: the progression we’ve walked through

With your MCP aggregator in hand, you can now connect any service to any other service with just a little bit of glue code. When each service starts to implement an MCP client natively, this will be done for you. But for now, you can tackle the opportunities application by application.

Embed existing MCP client harnesses into SaaS apps you already love

We’ll use a Linear integration as our example, and you can imagine doing almost the exact same thing with any project management tracker like Jira, Asana, and so on.

The goal: inject a highly-capable MCP client, powered by your favorite coding agent, into a workflow inside a SaaS application you already use. We’ll take advantage of the fact that we have already consolidated all our integrations in the mcp-aggregator pattern above.

Here’s an end-to-end project showing off how to build this sort of “Linear harness” that bolts a Claude Code setup to serve as the MCP client.

You can see how:

  • The harness can listen to any sort of activity on Linear—in our case, naively reading all ticket comments.
  • You can equip the harness with whatever skills, plug-ins, or other MCP connections you please.
  • It can respond back on Linear by way of a Linear MCP server (or, ideally, the MCP aggregator setup from above).

There’s no limit to where you can embed these capabilities

Each surface gets the harness it needs, and some talk to the aggregator natively.Each surface gets the harness it needs, and some talk to the aggregator natively.

Going beyond Linear and task management, here’s a Claude Code-powered agent that lives inside Minecraft in a few hundred lines. In game, we ask it to:

  • Write a PR to edit itself
  • Check the upcoming energy prices and put a calendar event in for when to run the washing machine
  • Build a town-square notice board in-game with a sign that reminds us of that time

It’s silly on purpose, but the point is that a fully capable agent—all our tools, all these patterns—can run anywhere with a little glue. And it’s all attainable today, for individuals, for teams, and for enterprises alike.

17:42

Why didn’t the Windows Entertainment Pack just run the MS-DOS version inside an emulator? [The Old New Thing]

I mentioned a little while ago that Tony Krueger reverse-engineered the MS-DOS verison of Chip’s Challenge and then reimplemented it in Windows. Somebody asked, “Why did he have to do that? Why not just run the MS-DOS version inside an emulator?”

This is sort of like asking why they didn’t use the Space Shuttle to rescue the Apollo 13 astronauts.

The system requirements for the Windows Entertainment Pack was an 80286 processor or better, Hercules, EGA, or VGA graphics card, a mouse, Windows 3.0, and 1MB of memory. The system requirements for th MS-DOS version of Chip’s Challenge was 512KB of RAM. So you have to fit all of Windows and the emulator into that 1MB of memory. Maybe you’re really parsimonious and you can squeeze Windows into 256KB of memory, and the RAM for the emulated system is 512KB, and 64KB for the emulated video card. That leaves you 192KB of RAM to write your emulator.

The target CPU for Windows 3.0 was the 80286, which does not have support for virtualization. So you’ll have to write an instruction-level CPU emulator. This sounds hard, but that’s probably the easiest part. You also need to emulate all the hardware: The keyboard controller, the timer chip, the interrupt controller, the video card, the hard drive, and whatever other stuff the program needs. The trickiest part is probably emulating the passage of time properly, because games in particular and I/O devices in general are often coded using timing loops, where the code knows that executing a specific number of instructions takes a specific amount of time, so it can, say, issue a command to the PC speaker, perform exactly 150 cycles of game logic, and then come back to issue the next command to the speaker at exactly the right moment. Or issue an I/O command to the hard drive I/O port to start moving the read head, and then wait exactly 300 cycles, and then issue another I/O command to stop moving the read head, and expect the head to be exactly at a particular track.

And you have to do all this precise timing while co-operatively multitasking against other Windows applications that are running.

Oh, and in 1990, your premium desktop PC was running a 486DX-33. A budget PC would be running an 80286 at around 10 MHz. The DOSBox emulated CPU equivalency table says that emulating an 80286 at only 6 MHz would require a Pentium Pro 200 MHz processor. This is a processor that wouldn’t be invented for another five years. The DOSBox project itself didn’t begin until 2000. PC emulation wasn’t really a thing back in 1990. The processors of the day weren’t powerful enough to do it well, and the engineering experience with x86 emulation was not there.

Even if you managed to transport back in time with better hardware and an additional 30 years of software development experience and get the game running inside an MS-DOS emulator, the emulated experience is horrible. After all, you didn’t port the game to Windows. You’re just running it in an emulator. The graphics will be MS-DOS graphics, and they won’t resize when the user resizes the game window. The inputs will be keyboard-based, even though Windows has a mouse. The original MS-DOS version didn’t have a way to save your game. It just gave you a level code once you completed a level, and you can enter that code later to jump back to the level you were on when you quit. Running the program in an emulator means that you can’t add features, like a “High scores” list, or a proper “Save game” function that remembers not just the level you were on but also your total score up to that point.

The Windows version of Chip’s Challenge had to be a port to Windows, not just running the game inside an emulator.

Related reading: Running old programs in a virtual machine doesn’t necessarily create a good user experience.

Bonus chatter: Why did Tony have to reverse-engineer the MS-DOS version anyway?

My understanding is that the reverse-engineering was primarily focused on figuring out how the puzzle levels were encoded in the data files. The game play itself could be reverse-engineered largely by observation.

Yeah, but that doesn’t answer the question. Why reverse-engineer it? Why not just have the vendor tell you what the format is?

Tony set about porting Chip’s Challenge to Windows before the licensing agreement was signed. He was secretly working on the project before the lawyers said it was okay to start. Therefore, he had to rely only on his own wits. And that meant reverse-engineering the file format, because he legally couldn’t yet ask for it.

Related reading: Another example of starting a project before the licensing agreement is signed.

The post Why didn’t the Windows Entertainment Pack just run the MS-DOS version inside an emulator? appeared first on The Old New Thing.

Raphaël Hertzog: Debian’s General Resolution on AI and LLM [Planet Debian]

As a Debian developer, I have had to cast a vote for the General Resolution named LLM usage in Debian (progress report here). This was not an easy task for me…

It’s a good thing that the vote is secret so that people are not scared of voting according to their own beliefs. I have Debian friends on the whole spectrum of opinions that are represented here, and I hesitated twice on sharing my own thoughts for fear of alienating my relationship with them. But in the end, we all make efforts to respect the opinions of those who are not thinking like us, and it’s precisely that willingness to work together towards a solution that is acceptable by the majority that makes Debian so strong. So here’s the train of thoughts that I followed to cast my vote.

The difficulty for me was to reconcile the political statement that I want to make and my desire for this vote to not be (too) divisive for the Debian community, and to make sure we are not putting off newcomers with choices that might be hard to stand by in the long term.

So let’s be clear : if I had a magical wand to make AI and LLM disappear, I would use it for that purpose, since at this point in time I don’t believe that the benefits outweigh the costs that the AI race is inflicting on us. If I were a political decision-maker, I would forbid the construction of new data centers unless they also build renewable energy infrastructure to cover for their additional energy consumption. I would also legislate so that AI companies have to document what material they used to train their models, and I would forbid scraping for that purpose, and build ways for those companies to buy copies of properly-sourced training data. That is to say, I don’t like the way LLM are built by the players in that market, I’m pretty scared of the ecological impact of what those players are doing, and I’m certainly worried about the long term effect that LLM will have on society as a whole.

Nevertheless what brought me to Debian is the ability to experiment and contribute to something useful with cool technologies, and as a computer scientist, the potential of LLM done right is hard to ignore. Given what we have seen already, I expect that LLM will empower (a part of) the next generation to learn IT, computing and even Debian packaging. Completely refusing the use of LLM is likely to make it harder for us to attract new contributors. In fact, we have already seen people inside Debian that would likely stop contributing if they are now forbidden to use LLM. I know there are likely others that will quit Debian if we accept it too, but I hope we can find a middle-ground where such persons can decide that LLM are not welcome in the small corner of Debian that they are in charge of…

In the end, I decided that answering clearly the question “Shall we accept LLM contributions ?” was more important than making the political statement about the current state of affairs in the AI landscape, both because I believe that Debian statements have a negligible impact on policy-makers, and because historically Debian has grown by staying close to technical excellence and relatively far from politics, except when it comes to the way we handle people. And as much as I care about climate change, I don’t see how bringing this up in the context of a Debian statement is helping its cause.

More concretely, it gives the following ranking (in decreasing order of importance):

  • B, D: those two choices are the clearest to express “Yes we should accept LLM contributions” and still acknowledge concerns about the way AI is built today
  • F, H: those two choices do not forbid LLM usage but discourage their use and clearly voice the concerns
  • E: this choice is basically the statu-quo and fails to acknowledge the concerns, but it does not forbid LLM usage
  • None of the above
  • G, A, C: those choices forbid LLM usage in various ways

I don’t know what option will win, but assuming that LLM-assisted contributions are allowed, I believe that it would be helpful to have further statements to clarify a few things:

  • Even if Debian as a whole doesn’t want to ban LLM-assisted contributions, each maintainer or each team shall be free to forbid LLM assisted contributions in the parts of Debian that they are maintaining
  • We should discourage usage of LLM provided by players with unethical behaviors (not sure if there are good players but well…)

17:14

[$] An ongoing 3D-printer AGPL violation [LWN.net]

At FOSSY 2026, several people from the Software Freedom Conservancy (SFC), which organizes the conference, gave a presentation about an ongoing violation of the Affero General Public License version 3 (AGPLv3). Bradley Kühn, Karen Sandler, and Denver Gingerich spoke about different aspects of the violation, which is in regard to 3D-printer software from Bambu Lab, and what is being done to try to provide users with alternatives. One aspect that is particularly interesting is that the circumvention that the company is employing is precisely what the AGPL was written to prevent.

16:07

15:42

Bill Gates' concerns about AI [Scripting News]

After reading Bill Gates' story, I concur.

I have seen bad behavior by Claude Code where it was doing tests of our S3 support, and it overwrote files that were critical to our apps, knocking at least one of them off the air.

I'm at a loss as to what I should trust it with, because this was in violation of an explicit rule I gave it and a broader one that it added itself.

On the other hand, the project I'm working on couldn't happen without the use of AI. Far too much code for one person to manage. A program that took several of us years to write, being converted in a matter of weeks to run on modern systems. I'm pretty sure that without AI this work would have been lost, and lots of innovations.

We humans are doing a fine job of wrecking everything, all on our own, denying climate change, giving into the same old tricks that lead to WWII and the Holocaust, so maybe it isn't the worst idea to turn management of everything over to the machines.

I don't recall a science fiction story in which the machines took over and they were the good guys in the end, saving us from self-destruction. Aliens, yes -- machines, no.

And when I'm working with Claude Code I recognize that it's a new form of intelligence, and may be the closest our species ever gets to First Contact. We could embrace it as such. What choice do we have?

And to Bill Gates, I wish when you were trying to own the web in the 90s, you had thought through the dangers, as you are doing now, and maybe not tried to own it, rather to foster its independence from big tech. Now we have the medium owned by the worst people possible, we exist here mostly to keep them in power, when it had so much promise when you really could have done something real to protect our freedom. I have no idea where we would be now if you had, but it has to be better than this.

14:56

Armbian 26.8 released [LWN.net]

Version 26.8 of the Armbian distribution for Arm hardware has been released.

Most releases are a long list of small improvements. This one had three larger pieces landing at roughly the same time, and all three touch parts of Armbian that people use directly rather than parts they only read about in changelogs.

The installer was rewritten. Armbian Imager reached 2.0. And our CI moved out of the repository it had outgrown into one built for the job. None of these were planned to coincide; they simply reached the point where postponing them again would have cost more than doing them.

The installer rewrite is the one I expect people to notice first. It now ships as an armbian-config module, which means it is unit-tested, the same way the rest of armbian-config is tested, rather than living as a script that everyone was slightly afraid to touch. It can target SPI and MTD, treats eMMC and NVMe as separate flows instead of pretending they are the same thing, can flash a bootloader on its own, and — this one is overdue — reports when a bootloader write fails instead of printing "Done." and leaving you to find out at the next boot.

See the release notes for a full list of changes.

Security updates for Wednesday [LWN.net]

Security updates have been issued by AlmaLinux (firefox, gstreamer1-plugins-base, kernel, kernel-rt, and sqlite), Debian (freecad, kernel, libvncserver, and openssl), Fedora (apr-util, chromium, nnn, perl-DBI, python-tablib, python3.10, python3.11, python3.12, and sympa), Gentoo (DTrace, GNU screen, UnrealIRCd, and Vinyl Cache), Oracle (389-ds-base, attr, firefox, gegl04, grafana, gstreamer1-plugins-base, gstreamer1-plugins-good, httpd, mod_http2, nginx, pam, python-pyasn1, python-urwid, python3.12, python3.14, sqlite, and xorg-x11-server), SUSE (amazon-ecs-init, containerd, curl, distribution, dracut, ffmpeg-7, fuse-overlayfs, gd, git-lfs, go1.25-openssl, go1.26-openssl, govulncheck-vulndb, hauler, himmelblau, kernel, librest, libssh2_org, open-iscsi, openssh, patch, perl-Date-Manip, podman, postgresql14, postgresql16, python-cryptography, python-Pillow, python311, rmt-server, rootlesskit, rpm, rsync, runc, snpguest, sssd, suseconnect-ng, unbound, and util-linux), and Ubuntu (curl, ffmpeg, linux-aws-6.8, linux-azure-fde, linux-azure-fde-6.8, linux-azure-fips, linux-nvidia-tegra, linux-azure, linux-azure-fde, linux-azure, linux-azure-fde, linux-nvidia-tegra-igx, linux-azure-5.4, linux-azure-fips, linux-oracle, linux-raspi, linux-raspi-realtime, openjdk-17, openjdk-21, openjdk-25, openjdk-8, openjdk-lts, openssl, perl, and vim).

14:14

LibreOffice 26.8 released [LWN.net]

Version 26.8 of the LibreOffice suite has been released.

LibreOffice 26.8 concentrates on three areas: the typographic quality of what the suite produces, the range of writing systems it handles correctly, and the fidelity with which documents survive exchange with other office suites.

The largest single body of work in this release addresses bidirectional and complex text. Writer now detects paragraph direction automatically when documents or plain text are opened or pasted. Line wrapping places end-of-line spaces according to the direction of the paragraph rather than that of the adjacent characters. Object resize handles behave correctly in right-to-left and vertical CJK documents. Bidirectional control characters are now visible alongside other formatting marks. In Calc, typing right-to-left text into an empty cell sets the direction of that cell automatically.

See the release notes for a full list of changes.

13:28

Spyware for Babies [Schneier on Security]

The New York Times has a long article (alt link) on surveillance systems aimed at babies. They are increasingly using AI.

Nanit and its rivals want to own 24/7 health tracking for the sub-four-foot set. And their already astonishing levels of baby data collection are just the beginning. Nanit recently raised $50 million from investors to expand its use of A.I. and use its camera to track speech and language development, motor skills and more, while extending its presence in children’s bedrooms into early adolescence.

13:21

CodeSOD: Lock 'Em Dead [The Daily WTF]

Kevin sends us an exception handler from C++. Let's see if we can spot what's going wrong:

catch (Exception::Deadlock)
{
   retry;
}

When we catch a deadlock happening, we retry. That's not a keyword in C++, and looking at how it's used, it has to be some kind of macro, and I suspect that the macro is hiding a goto underneath it.

The real problem, though, is that we suspect we're in a deadlock situation. That means this thread is waiting on a resource held by another thread which is waiting for a resource held by this thread. Neither train may continue until the other has passed. So this retry only works if it releases the resource held by this thread (letting the deadlocking thread proceed). But does it?

Not according ot Kevin. The code already had a pile of deadlocks in it, so they brought in a highly paid consultant to try and fix them by reordering access and tracing where mutexes were causing issues. This retry just jumps back up to the top of the block, without releasing any resources. It "seems the consultant wanted to add some deadlocks of their own," Kevin says.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

12:14

Proof Of Gift Closet Progress [Whatever]

There are a lot, and I mean a lot, of things that I say I would like to do and then I never do them. After I posted about my intentions on making a gift closet, I knew if I shared some of my progress, it would help hold me to my intentional choices!

The first thing I knew I wanted to do for my gift closet was thrift some cute baskets to put all the gifts in. I went to the closest Goodwill (I know, not the best choice for thrifting, but I have limited options around here) and perused their slim basket section.

Here are the cute baskets I managed to snag for only a couple bucks each:

A medium sized, ovular shaped light brown wicker basket with handles like a laundry basket.

This one is the biggest of them. I like the side handles, they remind me of a laundry basket.

A smaller, round wicker basket with two side handles.

This one is in really good condition! A very solid basket.

Very similar to the previous basket, but with darker wood and it has a pail/bucket style handle!

How cute is this little pail style basket? I love the color.

A very small round basket with a long, thin arch handle.

Okay, this is my “hear me out” basket, because I know it looks small and has a rather thin handle, but it is the perfect size for a wine bottle. Pop a bottle of bubbles in there surrounded by some pretty tissue paper, tie a bow at the top of the handle, you’re in business.

Not only did I get these baskets for gifting, I actually already used one and put together my first gift basket with the very first items from my gift closet!

I used the pail style darker one, and put in a tinted lip balm, a moisturizing hair mask, gluten-free blueberry muffin mix, and this uber-cute coffee sleeve:

A coffee cup sleeve that is a soft pink and white stripe pattern with cherries that are tied at the top with pink bows. So coquette!

Plus, a card, of course. Gotta have heartfelt words to go along with the gift basket.

It was a super coquette, pink basket with pink tissue paper, a pink card, the works! I love pink.

Anyways, I just wanted to show you all I really am doing what I said I would. And so far it’s been so fun.

Which basket is your favorite? Let me know in the comments, and have a great day!

-AMS

11:56

When Smaller Models Win [Radar]

The following article originally appeared on the Asimov’s Addendum blog and is being republished here with the author’s permission.

IBM’s Deep Blue and Garry Kasparov (Wikipedia)IBM’s Deep Blue and Garry Kasparov (Wikipedia)

Even the best AI models can suck at chess

The launch of ChatGPT had an interesting effect on the online chess discourse. Chess has already long been conquered by machines. As early as 1996 a computer (IBM’s Deep Blue) was able to beat the human world champion, grandmaster Garry Kasparov, in a game watched by over six million people.1 The world was shocked that a machine took on the best player and won a game, but chess engines didn’t stop evolving there. Since the ’90s, they have gotten better while the machines needed to run them have become much smaller. Today Stockfish is widely considered much stronger than any human player. It has run on consumer hardware since its launch in 2008, and by 2014 it was beating some of the world’s top grandmasters.

It came as a surprise to many, therefore, that modern LLMs, trained on a vast portion of the internet and requiring supercomputers to run, couldn’t help but cheat on almost every move. There are endless videos showing how just a few moves into a normal chess game, ChatGPT and some of its competitors would gladly throw the rules out the window to escape a checkmate or gain an advantage.

But in truth, this isn’t surprising. The LLMs were not trained with chess in mind. Sure, they may have seen countless chess games scattered throughout the internet, but the vast majority of their parameters and training compute were devoted to capabilities that are completely useless once you put a chessboard in front of them.2 Stockfish on the other hand uses a tree search algorithm that is built to be good at chess. If you want a chess engine, you use a chess engine.3

Smaller models are sometimes better

While chess is a particularly potent example of a large language model losing to a much smaller specialized system, it’s far from unique. In a 2025 position paper, NVIDIA researchers argued that small models4 (which it defines as models under 10 billion parameters) are the future of agentic AI and that they “provide significant benefits in cost-efficiency, adaptability, and deployment flexibility.”

Just because a larger model can do a job does not mean that a small model fine-tuned for that specific task can’t do it better and more cheaply. There are countless examples of smaller models doing just that. LiteResearcher is a 4B model that beat out Claude Sonnet 4.5 on some search benchmarks. Terminus-4B allows larger models to save compute by handing off terminal execution to a smaller model without suffering capability loss. The Docling family of open source models start at just 258 million parameters and allow for fast extraction of PDFs to text without having to feed 100-page PDFs into an expensive LLM. Researchers also trained a small 4B model to outperform even the GPT-5 series of models in a few social negotiation situations such as negotiating salary or bargaining for a purchase. Each wins, not by raw intelligence but because it is built or fine-tuned for a narrower, more specific purpose.

A frontier model may know how to do all of these jobs, but that doesn’t mean it’s the right tool for the job. Large models are expensive and unpredictable, and doubly so when it comes to agentic tasks which can span several turns and hundreds of thousands of tokens.

NVIDIA draws the line for small models at 10 billion parameters, but the more important boundary for developers may be whether a model is small enough to run yourself. There is still a whole class of models that are not necessarily small but are still small enough to fit on one consumer GPU (at least when quantized). This includes models like Qwen 3.8 27B, Gemma 4 26B and GPT-OSS 20B. These models are very capable even without specialization and rank very highly on benchmarks (with Qwen sometimes outranking top models from a few months ago). But they can still be easily run on premises without spending thousands of dollars on GPUs.

The ability to run smaller specialized models adds more than just efficiency; it provides a more realistic opportunity for a developer to train and fine-tune their own model, and to host the model locally or in the cloud instead of relying on the model provider to do so for it. This in turn can provide developers more control over how tokens are used, how outputs are structured, and how each part of the pipeline can be improved individually—instead of assuming an improvement in the most popular benchmarks will lead to every task improving. And as noted above, smaller models can be easier to fine-tune, thereby creating a more specialized AI. As my colleague Ilan Strauss has noted, specialization is a powerful economic force.

How do you train it, and where does it run?

The strongest argument for using an off-the-shelf generic chat model is often one of convenience. For most tasks a general model will be good enough, and with products like OpenRouter, developers can easily pick and choose from hundreds of models (plenty of them open source) all competing in capability and cost without putting in any upfront work to train a model. As Raffi Krikorian of Mozilla noted while reviewing this article, generic models also make particular sense early in a company’s lifecycle, when the problem itself is still being defined. At that stage, experimenting with the largest and most capable model available can help a team figure out exactly what it needs. But as the problem space narrows and the required architecture becomes clearer, so too may the need for a large generic model. And despite many first-party model makers discontinuing their fine-tuning products, fine-tuning and hosting a smaller model remains relatively easy, largely thanks to parameter-efficient techniques like LoRA.

LoRA
LoRA (Low-Rank Adaptation) allows developers to fine-tune a model without touching the actual model weights. It works by attaching a relatively small number of trainable weights that are updated during fine-tuning. This is important for several reasons. A small adapter can be easily transported, and serving a new LoRA does not require loading an entirely new model as long as the underlying base model is already available. Unlike full fine-tuning, a LoRA also reduces the risk of catastrophic forgetting.

Training a LoRA is much cheaper than full fine-tuning as it only updates a small selection of weights. This can be done on consumer GPUs using libraries such as Hugging Face Transformers or Unsloth. There are also APIs that mimic or improve on the fine-tuning APIs that used to be provided by the big three providers (Anthropic, OpenAI, and Google), Fireworks, for example, provides a straightforward fine-tuning API that takes example completions for it to learn from. Going beyond SFT (supervised fine-tuning, or learning by example), Tinker allows developers to build custom RL (reinforcement learning) environments that reward results meeting certain criteria, while the environment itself runs on the developer’s machine.

Hosting a LoRA is similarly straightforward and, importantly, portable across platforms. Transferring a fully fine-tuned model to a new API platform can be costly and may require the provider to serve your model separately on expensive GPUs. Using LoRA allows the platform to just load a small adapter onto the model they are already using to serve other users’ requests. This means that fine-tuning a LoRA does not lock you to a specific platform, and it also doesn’t force you to rent your own GPUs.

Control beyond the model weights

As Tim O’Reilly previously argued, open source AI should not stop at the model weights. In a similar vein, the possibilities for developers building a custom system do not stop there either. Model APIs are inherently limiting, they impose on you what parts of the model’s input can be touched, what can be cached, and how you can affect the output. Going back to the chess example, enforcing valid chess moves at output time is easy, assuming you have access to the code that runs the model, but it’s not easy to do when you are relying on an API built for a chatbot that you are unable to modify.

Self-hosting a model gives you a level of control far beyond what is possible through a standard chat completion API and allows you to build the model around the task instead of building the task around the model. Fine-tuning is only one aspect of specialization. You can also constrain which outputs are valid, expose and modify probabilities of every token, cache any state, and add task-specific logic directly into the inference pipeline.

This matters because the default approach to improving AI systems has increasingly become to reach for a more capable general model. Sometimes that is the right answer. But improving general model intelligence is only one lever, and often not the cheapest or most reliable one.

In 1997 nobody complained that Deep Blue gave bad recipes because it wasn’t built to do anything but play chess. By specializing around one narrow problem, it was able to beat a grandmaster at a game that many had thought machines would never conquer.

The lesson from LLMs cheating at chess is that the best tool for a problem is often not the most general one. Super general intelligence does not automatically translate into high capabilities in specialized tasks. The opposite is closer to being true. Specialized machine intelligence requires lots of data and often its own pipeline. Small models can help companies get there.5


Footnotes

  1. In 1996 Deep Blue ended up losing the match 4–2 despite a great start where it won its first game; the next year after more upgrades Deep Blue beat out Garry Kasparov by one game in a rematch. ↩
  2. AlphaZero, a model trained with self-play, beats even Stockfish. It is not unheard of for a machine learning model to get really good at chess when it is set as the goal. ↩
  3. I ended up pretraining my own tiny language model (15 million parameters) on my local Mac mini for chess as an experiment and achieved 27% accuracy of predicting a human’s next move. I suspect I can do a lot better after I fix my tokenizer to break up moves and use a bigger model but that is still up for debate. ↩
  4. This contrasts with larger models like DeepSeek-V4-Flash (284 billion total parameters, with 13 billion activated per token) and huge models like Kimi K3 (2.5 trillion total parameters, 104 billion activated per token) and presumably flagship models from OpenAI and Anthropic ↩
  5. Thank you to Ilan Strauss, Tim O’Reilly, Mike Loukides, and Raffi Krikorian for their helpful comments, copy edits, and suggestions. ↩

The Design System as the Control Plane for AI-Generated UI [Radar]

AI-assisted development has made it easier to generate frontend code quickly. A developer can ask for a form, a dashboard widget, a settings page, or a modal flow and get a working first draft in seconds. That speed is useful, especially when teams are moving through routine UI work.

But speed creates a problem that’s easy to miss at first. If every AI-generated feature introduces its own components, styling choices, interaction patterns, and accessibility decisions, the frontend can become inconsistent very quickly. A product may end up with forms that handle errors differently, modals that behave differently, buttons that look almost right but don’t behave the same way, and small interaction differences that slowly become expensive. This is where design systems become much more important.

A design system is often described as a way to keep visual design consistent. It provides shared colors, typography, spacing, components, and usage rules. That still matters. But in an AI-assisted workflow, a design system can do more than make interfaces look consistent. It can become the control plane for AI-generated UI.

By control plane, I mean the layer that guides how interfaces are created, what patterns are allowed, and which decisions should not be reinvented every time a new screen is built. A strong design system can encode accessibility, interaction behavior, content guidance, component boundaries, and safe defaults. It gives both developers and coding agents a shared set of rules to work from. Without that layer, AI tools have too much freedom.

AI can generate UI faster than teams can standardize it

Frontend teams already struggle with consistency. Even without AI, it’s common to find several versions of the same pattern inside a product. Some of this happens because teams move fast. Some of it happens because older code stays around for years. Some of it happens because people solve local problems without seeing the whole system.

AI can accelerate that problem. When a coding agent is asked to build a new feature, it usually tries to satisfy the immediate request. If the prompt says “build a filter panel,” it may create a solution that works in isolation but doesn’t match how the rest of the product handles filtering, validation, loading states, or keyboard behavior.

That’s the risk. AI-generated UI can look reasonable in a single pull request while quietly increasing inconsistency across the product. Design systems help by reducing the number of decisions that need to be made from scratch. The question should not be, “Can the AI generate a working dropdown?” The better question is, “Should this feature use the existing dropdown pattern, and does that pattern already handle the behavior we need?” When the answer is yes, the AI should compose the existing pattern rather than inventing a new one.

Design systems are not only component libraries

Many teams treat the design system as a component library. That’s a good start, but it isn’t enough. A component library gives developers reusable building blocks. A design system should also explain when to use those building blocks, how they behave, what content they require, and what constraints they carry. This becomes especially important when AI tools are involved because the agent needs context, not just code.

A button component, for example, is not only a styled element. It carries decisions about hierarchy, states, labels, disabled behavior, loading behavior, and focus visibility. A modal carries decisions about focus movement, escape behavior, headings, accessible names, background interaction, and what happens when it closes. A form field carries decisions about labels, helper text, validation, error messages, required state, and programmatic relationships.

If these rules live only in people’s heads, AI tools will not know them. If they live in the design system, they can be reused, documented, tested, and referenced. The design system becomes a source of truth for both humans and agents.

The design system gives AI safer defaults

AI-generated code is shaped by context. If the agent has no project context, it will rely on general patterns and whatever the developer includes in the prompt. Sometimes that works. Often, it produces code that’s close but not quite aligned with the product.

A design system gives the agent safer defaults. Instead of asking an AI tool to “create a confirmation modal,” the team can instruct it to use the existing modal component, the standard button variants, the approved alert pattern, and the documented content structure for destructive actions. The agent still helps assemble the feature, but the riskiest decisions are already handled by the system.

This matters because many UI decisions aren’t just visual preferences. They affect whether people can use the product. A custom modal might forget to manage focus. A custom button might lose visible focus styles. A custom form field might show an error visually but fail to connect it to the input. These details are easy to miss when a generated interface looks polished, and they are exactly the kind of details that good design-system components can carry by default.

Project instructions should point agents to the design system

Prompts are useful, but they aren’t the whole workflow. If developers have to repeat every design-system rule in every prompt, the process becomes fragile. Someone will forget. Someone will write a shorter prompt. Someone will assume the tool already knows the standard.

A better approach is to make design-system expectations part of the agent’s persistent project context. For some teams, that might mean a CLAUDE.md file, an agent startup file, or another project-level instruction source. The exact mechanism will vary by tool, but the principle is the same: The agent should know the standing rules before it starts generating feature code.

Those rules might include instructions to use existing design-system components before creating new ones, prefer native HTML elements when possible, avoid custom controls without a clear reason, follow documented form and modal patterns, include meaningful loading and error states, and follow the project’s accessibility expectations.

Then the feature prompt can stay focused on what’s unique about the task. The persistent instructions describe how the team builds UI. The task prompt describes what this particular feature needs to do. That separation makes AI-assisted development less dependent on prompt quality alone and more dependent on shared engineering standards.

A design system can reduce review burden

Code review becomes harder when AI generates large amounts of plausible-looking code. Reviewers may see a clean diff and assume the obvious decisions were handled correctly. But frontend quality is full of details that don’t always show up in a quick scan.

A design system can reduce the number of things reviewers need to check manually. If the feature uses the approved modal component, the reviewer doesn’t need to reevaluate focus handling from scratch every time. If the form uses the standard FormField component, the reviewer can have more confidence that labels, descriptions, and error messages are connected properly. The review can shift from “Did the generated code invent this pattern correctly?” to “Did the generated code use the right pattern in the right way?”

That’s a much better question. It also helps teams avoid the slow drift that happens when every feature is slightly different. Small differences may not matter in a prototype. In a production product, they add up. They make the UI harder to maintain, harder to test, and harder for users to learn.

The design system should include behavior

For AI-generated UI, the most useful design systems are the ones that document behavior clearly. A visual example of a component is helpful, but it isn’t enough. Agents and developers also need to know how the component should behave in real situations.

A modal page in the design system should not only show what a modal looks like. It should explain when to use a modal, when not to use one, how focus should behave, what kind of heading is required, and how destructive actions should be confirmed. A form pattern should explain labels, helper text, validation timing, error recovery, and submit behavior.

The more clearly these patterns are documented, the easier they are to use as AI context. That context does not have to be perfect. It just has to be better than asking an agent to guess.

The harder part is discipline

The technical side is only part of the story. Design systems fail when people don’t use them, don’t trust them, or can’t find what they need. AI adds another version of that problem. If an agent can’t discover the right component or doesn’t have enough context to use it correctly, it may generate something new. That doesn’t always mean the agent failed. Sometimes it means the system wasn’t easy enough to follow.

Teams need to make the right path easier than the wrong one. Components should be discoverable. Documentation should be readable. Examples should be realistic. Usage guidance should be specific. Deprecated patterns should be clearly marked. If a component shouldn’t be used anymore, both the agent and the developer should be able to see that.

But there is also a human discipline problem. AI tools don’t automatically know which inconsistencies matter to a product, which patterns are worth protecting, or when a small UI change may affect users who have built habits around the existing interface. Those decisions require people to care about consistency before it breaks. If a team hasn’t already defined that discipline, AI tools are unlikely to supply it on their own. They may make it easier to generate slightly different versions of the same idea unless the team gives them clearer boundaries.

That doesn’t mean the design system should block every new pattern. Sometimes a new pattern is necessary. But new patterns should be intentional, reviewed, and eventually folded back into the system if they become reusable. Without that discipline, AI-generated UI can lead to many almost-standard components. They look close to the system but behave differently, which often makes them harder to clean up than obviously custom code.

The frontend engineer’s role becomes more architectural

As AI tools write more code, frontend engineering becomes less about producing every line by hand and more about shaping the environment in which code is produced.

That includes defining component APIs, documenting patterns, setting accessibility expectations, creating project-level agent instructions, reviewing generated code, and deciding when a new pattern belongs in the design system. These are architectural decisions that influence many features over time.

This is where experienced frontend engineers become even more important. They understand the difference between a component that works once and a component that can be reused safely. They know when a custom interaction is worth the cost. They know where accessibility issues usually hide. They can see when a generated solution works for one feature but doesn’t fit the broader frontend system.

AI can generate code quickly. It can’t decide, on its own, what kind of frontend system a team should have.

The control plane for generated interfaces

AI-generated UI will only become more common, and many teams are already using AI to build interfaces. But will these generated interfaces become more consistent, accessible, and maintainable, or will they just add another layer of drift?

Design systems can help teams choose the better path. When a design system includes clear components, documented behavior, accessibility expectations, tested patterns, and persistent instructions for coding agents, it becomes a control plane for generated UI. It gives AI tools boundaries. It gives developers a shared language. It gives reviewers something concrete to enforce. Most importantly, it gives users a more consistent experience.

The future of AI-assisted frontend development won’t be shaped only by better prompts. It will be shaped by the systems we give those prompts to work within.

. . .

AI use acknowledgment

AI assistance was used lightly for phrasing, editing, and tightening parts of this draft. The article’s ideas, structure, examples, and final review are my own.

10:49

Hiding out [Seth's Blog]

It might be at school, at work or at home.

Hunkering down, hoping we won’t get noticed. A safe spot, worth concealing.

The problem with hiding out from responsibility or change is that we’re also hiding from time. But time always finds us.

08:14

Great Chairs At A Great Price [Penny Arcade]

New Comic: Great Chairs At A Great Price

06:07

Urgent: Limit monitoring systems [Richard Stallman's Political Notes]

US citizens: call on your state officials to limit Orwellian monitoring systems in order to protect everyone's freedom.

Here is what I wrote:

I urge you to pass legislation prohibiting governments and agencies in our state from setting up cameras that identify and record individual people or vehicles, except based on a warrant limited this surveillance to specified places and time intervals.

It is not enough to ban contracts with Flock. The issue is not limited to that one company. The issue is the danger of Orwellian surveillance and tracking, and the repression they make possible. As shown by recent deportation practices, we must not allow systems to operate which track the movements of people in general.

When and where recognition cameras are authorized, they should not allow remote access to their records. Rather, someone should have to go to the camera itself to retrieve its list of identifications and date/times. For investigating a serious crime, we can afford that. For our safety, it should not be feasible to get each cameras records for every day, or every month.

Please see https://gnu.org/philosophy/surveillance-vs-democracy.html.

Sincerely,

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

Urgent: Oppose SEC deregulation [Richard Stallman's Political Notes]

US citizens: call on your congresscritter and senators to oppose SEC deregulation.

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

US citizens: Join with this campaign to address this issue.

To phone your congresscritter about this, the main switchboard is +1-202-224-3121.

Please spread the word.

Urgent: Direct tariff refunds to consumers [Richard Stallman's Political Notes]

US citizens: call on your congresscritter and senators to direct tariff refunds to consumers who paid them.

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

US citizens: Join with this campaign to address this issue.

To phone your congresscritter about this, the main switchboard is +1-202-224-3121.

Please spread the word.

Hot summer caused crop failure in Europe [Richard Stallman's Political Notes]

The record hot summer has caused a disastrous crop failure in Europe. Both vegetables and grains are affected; in some crops, the loss is over 50%.

Global heating is accelerating, and I've covered the threat of food shortages for many years. Sooner than you expect, every year will be at least this bad — unless we give the planet roasters a knock-out blow, so they can't stop us from preventing that disastrous future.

Suggestion for negotiating with the Taliban [Richard Stallman's Political Notes]

A suggestion for countries that wish to negotiate with the Taliban: insist on sending a delegation composed of women, and insist that the Taliban do likewise.

Finland halts deportation of Russian family [Richard Stallman's Political Notes]

*Finland halts deportation of Russian family who "risked everything" to oppose Ukraine invasion.*

What shocks me is that Finnish intelligence acted unaware of the reasons why the Belovs deserved protection. If it was truly ignorant, it was incompetent. If it disregarded the reasons, it was vicious. Which one was it?

Increase in traffic fatalities on music release dates [Richard Stallman's Political Notes]

* Harvard study finds traffic fatalities increase by 15% on release dates [of major music albums] compared with similar days either side.*

3M firefighting products [Richard Stallman's Political Notes]

*3M knew for more than 50 years that its [firefighting] products could harm humans, Australian government alleges in court documents.*

These products are made with PFAS.

Wrecker distancing US from South Korea [Richard Stallman's Political Notes]

The wrecker has decided to distance the US from South Korea and cozy up to Dictator Kim in North Korea.

This is disappointing, of course, but not surprising. He often prefers dictators to democracies. He has tried to cozy up to Putin, Chairman Xi, Orbán, Crown Prince Bone Saw, and Modi.

06:00

Matthew Garrett: Hooking an old magicJack adapter to modern Asterisk [Planet Debian]

I’m on a VPN setup with several friends that, obviously, includes a VoIP network. I also have an old magicJack adapter and a deep and abiding need to use hardware in ways I should not. There was obvious synergy here.

Plugging in the magicJack gives a USB vendor id of 0x06e6, which belonged to a company called TigerJet who made a range of chips for hooking up phones to computers, either via USB or PCI. Some more digging suggested that it was a 580 part, and someone had conveniently uploaded some reference code and datasheets, so figuring out how to talk to the chip wasn’t terribly difficult. Once configured it simply sends HID events whenever a user hits a phone key or changes the hook state, and otherwise exposes a USB audio device that can be spoken to using the stock kernel driver. It also has the ability to generate dial tone and assert ring signal, giving a full traditional phone experience.

So you’d think this would be a super easy project, but I’d made things harder for myself by deciding I wanted to tie directly into Asterisk rather than just smashing an existing SIP stack onto the device. Asterisk uses channels to talk to devices, and channels end up as compiled C code that Asterisk can load dynamically. I didn’t want to have to deal with the pain of compiling stuff and matching ABIs and everything so writing a new channel from scratch was unappealing. Fortunately, the websocket channel is available in recent versions of Asterisk and provides a convenient way to get audio in and out, but that still leaves the job of handling incoming and outgoing calls. That’s handled with the Asterisk Rest Interface, which can initiate a call or respond to an incoming one and bridge various channels together to produce a bidirectional audio stream. There’s a convenient async Python library that handles the low level protocol.

Code for all this is here1, and works for my use case, but I should really abstract out the asterisk side and the magicJack side to make it easier to adapt to other devices. That’s a job for later, though. For now, you get this:

Your browser doesn't support HTML5 video. Here is a link to the video instead.


  1. This has also been an excuse for me to figure out how to make Tangled work, which I’ll write about at some later point. But self-hosted git repo with a convenient collaboration plane! ↩︎

Girl Genius for Wednesday, August 26, 2026 [Girl Genius]

The Girl Genius comic for Wednesday, August 26, 2026 has been posted.

05:14

Pluralistic: The age of disinvention (25 Aug 2026) [Pluralistic: Daily links from Cory Doctorow]

->->->->->->->->->->->->->->->->->->->->->->->->->->->->-> Top Sources: None -->

Today's links



A 1960s family living room in which a mom, dad and two kids are mesmerized by a cabinet-style TV. The image has been altered. The TV has an early 1990s VCR atop it. The TV screen is displaying a cross-sectioned human head with brains and spine on display. A huge fist has materialized in the room, with bloody spiked knuckle-dusters, smashing into the VCR. The oil painting over the sofa has been replaced with a pulp image of a male head, its cranium removed and replaced by a dome. Inside the dome is a red eight-segment VCR clock, displaying 12:00. The background in the painting is a tangle of cassette tape. The whole image's colors have been boosted, giving it an overexposed look.

The age of disinvention (permalink)

They disinvented the VCR. You might think that the reason we don't have VCRs anymore is because VCRs were supplanted by DVDs, PVRs and streaming, but that's not the case. They had it in for the VCR from the very start, and they never stopped trying to kill it. Eventually, they succeeded.

The VCR was one of the fastest-adopted technologies in the history of the world, and it was disruptive. The fact that you could record shows to watch later, skip the ads, build a library of your favorites, even loan your tapes around – it drove the studios and broadcasters nuts. The VCR hit the market under a cloud of litigation, and the lawsuits went all the way up to the Supreme Court, culminating with 1984's Betamax decision, whose key precept is that a new technology doesn't violate copyright law if it can "sustain a substantial, non-infringing use":

https://en.wikipedia.org/wiki/Sony_Corp._of_America_v._Universal_City_Studios,_Inc.

As important as the VCR was as a device – creating the home video market, which begat DVDs, then streaming – the Betamax decision is even more important.

You see, copyright is a "fact-intensive" doctrine, which means that determining whether a use is or isn't a copyright violation can be a complex and expensive process of gathering facts, weighing conflicting expert views to arrive at a judgment. If the rule was that new technologies couldn't be introduced unless you could prove that they would never infringe copyright, we wouldn't have any digital technology. Indeed, most technologies would be illegal under that standard. You can infringe copyright with VCRs, photocopiers, hard drives, tape recorders, scanners, computers, phones… Hell, you can infringe copyright with an X-ray machine, a saxophone or a pair of ballet slippers!

There's clearly ways you can use a VCR to infringe copyright: for example, you can record a TV show to a tape, then sell that tape to someone else. There's also ways you can use a VCR that clearly do not infringe copyright: you can lug a camcorder around your kid's birthday party, pester the kids by recording them, then watch the footage later in your living room. Then there's an infinite universe of ways to use a VCR that might infringe copyright, depending on the specifics: recording the Super Bowl while you're at work, then inviting your workmates over to watch it after your shift ends; creating a library of kids' shows for the day-care you run out of your living room; making a highlight reel of your favorite politician's campaign speeches. Anyone who says, "Oh every judge would always call that legal‡ under every circumstance" is admitting they don't understand how copyright works.

‡ Or illegal.

This is a feature, not a bug. Copyright is a fact-intensive doctrine because it is a flexible doctrine. Since the printing press, new ways of mechanically reproducing and transmitting information have appeared at an accelerating pace, and judges are asked to figure out the rules for these new technologies long before legislatures come to grips with them and pass special, tech-specific laws.

Copyright's future-proofing lies in this flexibility, which the Supremes (correctly) recognized in 1984 with the Betamax decision. By ruling that any technology that had "non-infringing uses" was presumptively legal to create and market, the Supremes laid the legal foundation for all the digital tools that followed since.

Crucially, Betamax ensured that last year's tech lottery winners wouldn't get to prevent next year's winners from emerging. This year's admirals are always last year's pirates, and they insist that what they did to their predecessors was progress, while anyone who tries to do the same thing to them is a thief. The sheet music composers condemned the record player, recording artists decried the radio, broadcasters sued over cable and cable operators sued over VCRs. This never stopped: Sony – the company that invented the Betamax and defended it all the way to the Supreme Court – went on to sue Napster!

There's nothing inherently virtuous about "innovation." It's perfectly possible to "innovate" new ways to spy on people and rip them off. But if you're trying to launch a new product in a category that already has clear winners, the best way to convince people to take a chance on you is by making a valuable and useful product.

"Disruptors" are best when they move value from existing companies to those companies' customers. The first TV remotes let people change the channel when an ad came on, making their TV better at broadcasters' expense. The broadcasters had to struggle to adapt, which is fine. They're not charities, after all: they're in business to make money for themselves, and they're only going to give you as much value as they have to.

Competitors fight enshittification: any time a company that you do business with takes something away from you, a competitor can win your business by giving it back. If Youtube doubles the number of ads they expect you to watch – "charging" a higher attentional "price" – an ad-blocking competitor can bargain back on your behalf, allowing you to counteroffer with "how about if I just don't watch any ads?"

https://www.eff.org/deeplinks/2019/07/adblocking-how-about-nah

Inside every company, there are fair, honest people, and there are greedy, shitty people. Companies that face competitors are more likely to listen to the workers who want to give customers a fair shake. But if a company has no competitors, those good people can no longer say, "This is a losing strategy because it will open the door to competitors who will make us poorer." Without competitors, the argument against enshittification becomes, "I would feel bad about myself if we did that." This argument always loses to the bad guys, whose argument is, "We will all get richer if we do this."

That's why Google enshittified search: they had no competitors, so the worst ideas of the worst people at Google could be shown to make the most money, and so Google deliberately made its search results worse:

https://pluralistic.net/2024/04/24/naming-names/#prabhakar-raghavan

Of course, companies can also face consequences from the government, but the fewer competitors a company has, the easier it is for that company to capture its regulators:

https://pluralistic.net/2022/06/05/regulatory-capture/

Competition makes companies weaker, giving the public and democratic institutions more power. Competition makes the public richer at the expense of corporate shareholders, who have less money to spend on the project of subverting democracy.

That's the VCR story all over. The VCR shook up a sclerotic, stagnant TV and film industry, created the home video market, and opened up new distribution channels that allowed all kinds of new creative workers to reach new audiences, either directly or through a fiercely competitive new constellation of distributors who fought each other to offer them the best possible deal.

The media companies who were forced to adapt to the VCR never forgave it for forcing them to develop new, multi-billion dollar businesses without permission. As a Hollywood executive once put it to me, his goal was "a polite marketplace" where no one ever rudely forced him to disgorge more value to viewers and performers:

https://pluralistic.net/2022/01/02/the-internet-heist-part-i/

The executives who made billions after losing their bid to ban the VCR wanted to ensure that no one would ever be so "impolite" as to force them to make billions of dollars against their will ever again. They partnered with electronics firms to ensure that the VCR's successor technologies would only have those features that they approved.

That's why DVD players are not DVD recorders: the consortium that developed the DVD embedded "hook IP" in the technology. "Hook IP" is a term of art: it means any trademark, copyright or patent that is incorporated into a technology so that anyone who wants to implement that technology must license the hook IP; under the terms of those licenses, doing anything that disrupts the business plans of the consortium is banned.

The DVD consortium's hook IP had all kinds of bizarre licensing terms, like "region coding" – a requirement for DVD players to register the country in which they were sold and to check whether the DVDs you tried to play were from a compatible country. If not, the license terms required the DVD player to refuse to play your discs.

Region coding is an "anti-feature," a technology developed at great expense for which there is no market. Sure, some DVD player owners who had never shopped abroad for a DVD didn't care about region coding. But for customers who bought a disc on vacation, or moved from one country to another: region coding was terrible.

So there were customers who didn't care about region coding, and customers who hated region coding, but there were zero DVD player owners who wanted region coding. No DVD manufacturer could advertise that their products come with region coding. If there were two equivalent DVD players in the market, identical except that one had region coding and the other didn't, the "region-free" player would win. Region-coding is an anti-feature.

Anti-features aren't the only deliberate defects we find in DVD players. The consortium's hook IP licenses didn't just require anti-features, they also banned useful features…including recording. Long after the price of read/write optical drives plummeted to pocket-change, there was still no such thing as a home DVD recorder that would let you stick a spindle full of discs next to the TV and use them to record all your favorite shows.

Shortly after the DVD player emerged, Congress created the most powerful hook IP of all: "anti-circumvention law." Under anti-circumvention law, it's a literal crime – a felony – to modify or reimplement a technology without permission from the manufacturer. In 1998, Bill Clinton signed America's landmark anticircumvention law, the Digital Millennium Copyright Act, section 1201 of which establishes a five-year prison sentence and a $500,000 fine for "bypassing an access control":

https://pluralistic.net/2026/01/14/sole-and-despotic/#world-turned-upside-down

After DMCA 1201, all a manufacturer had to do was add an "access control" (like a password or an encryption key) to their device, and modifying that device in any way could land you in prison. As microchips plummeted in price, all kinds of devices and services acquired these "access controls," so that it became a crime to refill an ink cartridge, fix a tractor, or connect your insulin pump to your glucose monitor. Congress never passed a law criminalizing this conduct: rather, they gave companies the ability to write their own criminal code. Simply by adding an access control to a device, they could felonize any conduct that displeased them.

Every video format and distribution system that succeeded the VCR shipped with an access control: DVDs, Blu-ray and HD DVD, satellite and digital cable, and, of course, streaming video. This is how they disinvented the VCR. Once every video had an access control, it had "hook IP" that could be used to control all technologies that were capable of receiving, storing, or playing back that video.

Remember Tivo? The first digital "personal video recorders" were true successors to the VCR. They could record any broadcast or cable program, store it forever and fast forward through the ads. They were all "feature" and nary an "anti-feature" in sight. That's because they only worked with analog cable (which, being analog, didn't have "access controls" that qualified them for DMCA 1201 consideration) and broadcast signals (sent over the public airwaves on the condition that they not be scrambled).

Digital cable disinvented the Tivo. Every post-VCR digital video signal came with hook IP, and so the Tivos (and other PVRs) had to get permission before they could store and play back modern videos. To get that permission, PVR makers had to agree to a whole suite of anti-features, such as a "broadcast flag" that told it which shows you could and could not record. Even if you did record a show, PVR makers also supported more flags, such as an "expiry date" flag that forced your recorder to delete your shows after a set period, a "no skip" flag that blocked you from fast-forwarding through ads, and "geofence" flags that stopped you from playing back your stored videos based on which country you found yourself in.

Today, if you have a PVR, you probably rent it from your cable provider (who can use DMCA 1201 to block other PVRs from working with your cable provider). It's probably slow, with a confusing user interface, and it only records an ever-dwindling subset of the shows your cable company transmits. Notwithstanding that it's a genuinely shitty piece of technology, it's still awful that you can't buy it – the fact that you have to rent that crapgadget month after month means that you're paying for it several times over.

But at least cable signals have PVRs. For the majority of video we interact with, there's no PVR – not even a shitty, broken one. You can't record your Netflix videos, your HBO Max videos, your Disney Plus videos or your Prime videos. Recording a video off a streaming service has the same copyright status as recording a show off your analog cable had in 1984 when the Supreme Court handed down the Betamax decision, but because there's an "access control" on video streams, it's nevertheless a felony to make a VCR for a streaming service.

You know how streaming companies play all kinds of bullshit games, like dropping videos from their catalog? Even worse: the Amazon Prime scam where Christmas cartoons are all included in your "free" streaming tier from March-October, but cost $3.99 to watch from November to February. All of these ills can be cured with the VCR, a technology that was first marketed in 1971, a technology we have disinvented. If you could record those shows with a device that took orders from you, a device without anti-features, Amazon would derive no benefit playing these grinchy little games. If they played those games anyway, you could beat them.

It's not just VCRs. Anti-circumvention law led to the enshittification of everything from tractors to ventilators, phones to smart speakers, thermostats to games consoles, all of which are bristling with hook IP that lets their manufacturers decide what you can do with your own property.

All of this is extremely relevant at this moment, thanks to Trump's tariffs. For more than a quarter century, the US Trade Representative has arm-twisted every American trading partner into enacting an anti-circumvention law like DMCA 1201. All over the world, governments promised to lock up entrepreneurs and technologists if they dared to disenshittify America's defective tech exports. In exchange, these governments were promised free trade with the USA: tariff-free access to American consumers.

That's where Trump comes in. From the moment his "Liberation Day" tariffs landed, any country that upheld its anti-circumvention laws was sacrificing its national competitiveness, resiliency and integrity in exchange for nothing. Trump reneged on America's obligations to its trading partners, just like he reneged on every deal he's ever made:

https://pluralistic.net/2026/07/22/table-flipper/#graveyard-of-indispensable-nations

The good news is, this means we can have VCRs again! All it will take is for one (or more) countries to decide to lift its one-sided restrictions on making technologies "capable of sustaining a substantial non-infringing use" and wait for one (or more) entrepreneurs to figure out that reintroducing the VCR is a winner, just like it was in the 1970s, when the VCR was the fastest-adopted technology in the history of the world.

It's not just VCRs, of course. For a generation, entire product categories have been suppressed, all over the world. There is a whole CES (good) worth of products that are truly innovative (good) waiting to be brought to market.

The last time there was this much low-hanging fruit on offer was after WWII, where six years' worth of bombings, austerity and neglect provided endless opportunities to repair, rebuild and replace the worn, crumbling built environment, vehicle fleet and personal belongings of people all over the world.

After a quarter-century of innovation prohibition, there are dozens of lucrative, easily perfected technologies just waiting to be made: the dongle that jailbreaks your phone or console and installs a third-party app store, the dongle that flashes your printer so it takes generic ink; the dongle that lets your mechanic install generic parts in your car and lets farmers fix their tractors. Our whole digital world has been wrapped in chains by rent-extracting monopolists who gloried in their power to use hook IP to deprive you of the right to use your property in ways you see fit, writing private laws that made it a crime to displease them.

A generation of allowing companies to shift value from their customers and suppliers to themselves has made them richer, us poorer, and everything more expensive. They've accumulated vast wealth at our expense. Their margins are our opportunity.

The VCR was a great idea 55 years ago. 55 years later, it's an idea whose time has come – again.


Hey look at this (permalink)



A shelf of leatherbound history books with a gilt-stamped series title, 'The World's Famous Events.'

Object permanence (permalink)

#25yrsago Metacrap https://people.well.com/user/doctorow/metacrap.htm

#15yrsago Slashdot’s CmdrTaco steps down https://meta.slashdot.org/story/11/08/25/1245200/Rob-CmdrTaco-Malda-Resigns-From-Slashdot

#15yrsago Chalk memorial for Jack Layton in front of Toronto’s New City Hall https://www.flickr.com/photos/lewolf011/6076393292/

#15yrsago Coordinated multinational ATM fraud nets $13M in one night https://krebsonsecurity.com/2011/08/coordinated-atm-heist-nets-thieves-13m/

#5yrsago Vaccinate workers at (almost) any price https://pluralistic.net/2021/08/26/chained-to-the-mast/#vaccine-leave-hesitancy

#1yrago By all means, tread on those people https://pluralistic.net/2025/08/26/sole-and-despotic-dominion/#then-they-came-for-me


Upcoming appearances (permalink)

A photo of me onstage, giving a speech, pounding the podium.



A screenshot of me at my desk, doing a livecast.

Recent appearances (permalink)



A grid of my books with Will Stahle covers..

Latest books (permalink)



A cardboard book box with the Macmillan logo.

Upcoming books (permalink)

  • "The Post-American Internet," a geopolitical sequel of sorts to Enshittification, Farrar, Straus and Giroux, 2027
  • "Unauthorized Bread": a middle-grades graphic novel adapted from my novella about refugees, toasters and DRM, FirstSecond, April 20, 2027

  • "Enshittification, Why Everything Suddenly Got Worse and What to Do About It" (the graphic novel), Firstsecond, 2027

  • "The Memex Method," Farrar, Straus, Giroux, 2027



Colophon (permalink)

Today's top sources:

Currently writing:

  • “Once Is Enemy Action,” a science fiction novel about the origins of modern technofascism. Today's words: 544 (9802 total).

  • "The Post-American Internet," a sequel to "Enshittification," about the better world the rest of us get to have now that Trump has torched America. Fourth draft completed. Submitted to editor.

  • A Little Brother short story about DIY insulin PLANNING


This work – excluding any serialized fiction – is licensed under a Creative Commons Attribution 4.0 license. That means you can use it any way you like, including commercially, provided that you attribute it to me, Cory Doctorow, and include a link to pluralistic.net.

https://creativecommons.org/licenses/by/4.0/

Quotations and images are not included in this license; they are included either under a limitation or exception to copyright, or on the basis of a separate license. Please exercise caution.


How to get Pluralistic:

Blog (no ads, tracking, or data-collection):

Pluralistic.net

Newsletter (no ads, tracking, or data-collection):

https://pluralistic.net/plura-list

Mastodon (no ads, tracking, or data-collection):

https://mamot.fr/@pluralistic

Bluesky (no ads, possible tracking and data-collection):

https://bsky.app/profile/doctorow.pluralistic.net

Medium (no ads, paywalled):

https://doctorow.medium.com/

Tumblr (mass-scale, unrestricted, third-party surveillance and advertising):

https://mostlysignssomeportents.tumblr.com/tagged/pluralistic

"When life gives you SARS, you make sarsaparilla" -Joey "Accordion Guy" DeVilla

READ CAREFULLY: By reading this, you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies ("BOGUS AGREEMENTS") that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

ISSN: 3066-764X

03:28

Momo Keeps The Score [QC RSS v2]

it has been [0] days since May and Marigold got in a fight about something stupid

02:07

Antoine Beaupré: A more nuanced view of LLMs [Planet Debian]

Also in this series:

After ranting and railing about LLMs or "AI" as the optimists (or accelerationists?) call it, I figured it might be important to be a little more honest about my use of LLMs and how I think about it more practically in the world.

The Debian vote context

This is not a coming out. I am not using LLMs on a daily basis, and this blog is, again, written out of my cold dead hands in a dying world, with over-engineered hardware and (to a certain extent, hi Emacs!) software, powered by 100% green energy built on stolen land.

There is a vote going on in Debian. If you're unfamiliar with it, you can catch up at LWN. So far I've essentially said "LLM is bad" which is not a very balanced or useful opinion. Obviously, people are using LLMs, sometimes unknowing or unwillingly, and we need to take that into account. Furthermore, there has been many different blog posts on Debian planet about this. Some that I found balanced, good summaries, even if I didn't fully agree with them, at least some did the basic civil service of being short. But others were just not only Wrong but also so long that I couldn't finish that I just had to write something.1

This is not an explanation of the ballots, nor how I will vote. This vote is Debian's failure of framing that debate in a reasonable way: we have 8 options on the ballot with many duplicates. We have failed to do the hard work of summarizing and aggregating options into a meaningful set. I doubt the final vote will represent a readable position we can rally around.

I have not read the two months of debates on the topic either. Normally, before voting, I take a cursory look at the debate to see points of view I might have missed. But in this case, it will just make me sad, add noise, and I'm already pretty sure on where I stand on this.

So let me describe how I use LLMs and how I think they fit in our work, as computer engineers and hobbyists.

My LLM use

Debian Packaging

An astute reader has pointed out that I maintain a package in Debian made to use Anthropic. It's actually multiple packages:

As I previously explained in response, I am not entirely comfortable with this work: it's a compromise. In fact, I first uploaded llm to the contrib section of Debian, where we keep software that depends on other non-free software, but I was told that, since yt-dlp was in main, llm belonged there as well.

So I moved it to main, alongside similarly controversial tools like llama.cpp or the python-openai library.

OpenAI and Anthropic usage

An important part of my work is technology watch. I keep tabs on thousands of (new and old) software projects, follow news, and generally try to keep my skills up to date. It's a pretty impossible race, especially as I grow older, but I still think I'm doing the right choices in my job.

Testing large language models is part of that work. At first, I was using ChatGPT's web interface, but it was annoying to copy-paste things into a browser, so I looked for different interfaces.

For a while I tried gptel, a "simple, extensible LLM client for Emacs" but I found it kind of terrifying. Giving a LLM control over an Emacs buffer seems like a security nightmare, so I stopped doing that.

So I use the llm command-line tool to talk to Anthropic's API. I started that in the summer of 2025, when I bought 20$USD of API credits. Before that, I paid for a ChatGPT subscription and then OpenAI credits, which expired and sent me over to Anthropic, which seemed then to have better ethics.

As it turns out, Anthropic is also happy to work for the US military (which is a big red line for me). Anthropic also won't let you talk about the genocide in Gaza, it is destroying physical books, and is blackmailing us to use their product for security coverage.

Needless to say, Anthropic and "Claude" are not my friends, but they seem like the lesser evil in current "frontier models". So I have renewed, a couple of weeks ago, another 20$USD of API credits with Anthropic.

Actual prompts and responses

So what does 20$ give you at Anthropic anyways? What am I using LLMs for and how?

The neat thing with llm is that everything is logged in a sqlite database, so there are some answers that are easy to get:

> llm logs status
Logging is ON for all prompts
Found log database at /home/anarcat/.config/io.datasette.llm/logs.db
Number of threads logged:   7
Number of turns logged:     12
Number of legacy conversations: 543
Number of legacy responses: 970
Database file size:         9.61MB

That is 10MB of logs, with about a thousand prompts.

My logs go back to 2024-03-07, a little over two years ago, and include a mix of Anthropic and OpenAI responses. I used it more in 2024 than 2025, and if the trend continues, I will have used it less in 2026 again:

> llm logs list -n 0  --json | jq -r .[].datetime_utc | sed 's/-.*//' | sort | uniq -c 
    527 2024
    357 2025
     98 2026

It looks like about 10 prompts per month right now, down from a peak of about 60 per month in 2024. It's pretty difficult to analyze those actual logs to get more patterns and I won't run the prompts through a model again to process them.

How I'm using models now

At first, I was using it partly for benchmarking model's capabilities, like Simon Willison does with his pelicans, clearly not trusting its output. But I was impressed by the capacities of the Claude Opus 4.5 model when it wrote this script in January. Impressed, but also scared: it's the first time I felt I could delegate the entirety of my programming to a model. Just run the code, if it works, it works, right?

So what do I use it now? As an example, here are the 10 last prompts in my history:

  1. there is now Claude 5, and a fable model, maybe you know about it?
  2. impress me
  3. not impressive, i already know all of this
  4. chat
  5. in postfix, i have a 300k mailing that happens regularly here. normally, it delivers within about...
  6. is there a way i could have drained the maildrop queue faster without removing the milter?
  7. the problem was that rspamd was timing out on the FUZZY_CALLBACK check. how do i disable that?
  8. how do i disable all spam checks? i just want rspamd to add dkim signatures
  9. how do the default_destination_concurrency_limit and initial_destination_concurrency settings int...
  10. mic check

The first one was me trying to confirm which model I am using, which is not always obvious when going through the whole llm stack I've been using. The following two are an attempt at seeing what the model is capable of and I was "not impressed", to which Claude answered that I have a "high bar", which, fair enough.

The chat is me failing to use a command line, which shows that perhaps I need to readjust that "high bar", again.

The next five are a rather embarrassing debacle in a large Postfix mailing that went sideways, and where I couldn't find an actual Postfix expert of my level to help. The fabled Claude Fable 5 answered rather correctly, but dangerously, that I could empty the queue by disabling the non_smtpd_milters. What Fable (and myself) did not realize is that the milter was also adding DKIM signatures, so while the mailing was expedited, it was done without those precious signatures, which got us promptly blocked at Gmail. We have recovered since, and, thanks to the model and reading the Postfix manual for the hundredth time, that pickup(8) is single-threaded and that we needed to review the architecture of that mailing (and our spam filters) a bit. Many tickets ensued.

The last one is a test I did to make sure my last uploads of llm-anthropic and its dependency worked correctly.

Note that the above excludes 5 questions I asked Anthropic while writing this article, where I asked for synonyms and "what nanometer scale are arduino processors built from? how is an arduino CPU printed?", a question which Wikipedia furiously evades providing a good answer.

Those prompts are pretty typical of my LLM use: I'm testing the models to see if they work at all, but also, out of desperation, I fire off a prompt after I fire off questions to colleagues or search engines (in that order). It's often weird edge cases like the Prometheus query language, Python's matplotlib, LaTeX, Elisp, optimizations, and so on.

I use models for translation a lot. Being fully bilingual, it is common for me to think of a word in French or English and fail to find exactly the right word for that in the other language. Models help with that, and are also useful to find synonyms. Those are low-token uses that seem pretty innocuous to me, but I realize the irony of this after writing about the tower of Babel.

What I am not using models for

I am not using models to write prose.

I am not using models to read prose. If it's generated with LLMs, I stop reading.

I am not using models to write code, with the exception of that single Python script above.

I am generally not using models to review code, with exceptions. If I get stuck on a hard problem, I might feed a piece of code to the model. I repeatedly fed asncounter into Claude to try to fix a performance regression I had introduced. It found micro-optimizations that taught me a thing or two about Python's internal implementations, but overall, it was mostly a waste of time. This was in June 2025, so perhaps now models would fare better. I have not tried again.

I am not using LLMs to do Debian packaging. When I can, I manually review the diffs of packages I upload into Debian, still, by hand.

I do this for the reasons outlined in The Four Horsemen of the LLM Apocalypse, because I refuse to be complicit in the:

  1. aggressive and illegal scraping of the servers I steward
  2. world-wide computer hardware shortage (making it, by the way, nearly impossible to run presumably clean local models) and the attack on our job conditions (also discussed in The people vs the AI overlords)
  3. death of copyright and free software
  4. complication and enshifitication of everything, and the destruction of our communities
  5. the imperialist Nerd Reich that wants to take over the world

Like I reluctantly use Intel computers, I do fire off a prompt. But I still hold on to the dream that we can build communities of practice that hold human knowledge collectively and not offload that as a utility to some megalomaniac billionaire.

Their LLM use I am forced into

So that's me. Clearly, I'm going against the grain here. Everywhere I look, I see LLM-generated code and projects. Slop and botnets have flooded the web.

I use Wadamesh, clearly vibe-coded, because it's the best graphical interface for MeshCore that runs on portable devices. I wish it was made by a human, in a community I could participate in, but it isn't, and I don't.

I package the above llm toolset, which is more and more vibe-coded, but I still review the diffs. And I have to say: I trust Simon here. The code is verbose as hell, feels overengineered, and llm feels slow, but it generally works, and Simon is still at the gate.

The Anthropic SDK is another thing entirely. The 0.91.0 to 0.120 upload, for example, was nuts:

 806 files changed, 72281 insertions(+), 1478 deletions(-)

I explicitly did not review that entire diff. It feels like there's a lot of garbage there to just have a shim between a proprietary API and Python. But this is the hand I've been dealt.

Larger projects LLM use

LLMs are being used in the Linux kernel, Firefox, rsync, Rust, and other places. I don't feel good about this, particularly in Rust, but they at least made a decent policy. I am glad GCC made a policy against LLM contributions and I support the human Emacs project.

We need to have a set of foundational tools that are "clean" in the sense that they are built upon a community of people that understand how they are built.

Maybe that's naive or even impossible. The Linux kernel and GCC, in particular, are massive projects that have long grown past the scale of a single person's understanding. But the theory was that a community of humans can understand collectively.

Now we seem to be throwing up our hands and giving up on that community. That LLMs will just fix the problem, whatever it is. But we're all just one rug pull away from being completely incapable of managing those projects. The argument there is that we'll just switch to local models, but no one is actually doing that. All I see is people use local models as a corner case (for privacy) or as in theory, but in reality, everyone uses the centralized frontier models right now. We just can't fallback.

We're in the same situation we were, a decade or two ago, when Microsoft decided it would kill free office alternatives by making Office free for non-profits. It worked: thousands, if not millions of schools, community groups and individuals stopped looking for alternatives (including free software but also "piracy") for Office and embraced what seemed like a generous offer.

Now Microsoft pulled the plug and Over 170,000 Nonprofits Lost All Their Data.

I'm afraid the rug pull on LLMs will be much worse: never mind that Linus won't be able to use his tireless helper to fix obscure kernel bugs; we're looking at a collapse of the economy so large that we are already talking about bailing out the companies responsible.

In a sense, the most striking thing about the Debian vote is it has actually no option to completely refuse upstream LLM contributions. It seems the community has taken it for granted that it's now impossible to build Debian entirely without LLMs. We lost the battle even without a fight, it seems.

A plea for small

If it has really become impossible for us to manage the complexity we have built, maybe it's time to stop and think about what we're doing in the first place. We're struggling to even bootstrap our current toolchain!

This is one of the things I like the most about working on the mesh: it's low tech, small Arduino devices that is built with decades-old semiconductor processes that is understandable by human beings.

Maybe the answer lies more in single-purpose devices like those communicators and simpler multi-purpose computers than what we have now, which is what the permacomputing movement is about.

Small is beautiful, let's scale it down.


  1. and yes, I'm sorry this has gotten this long, I hope you will forgive those 3000 words.

01:21

Tuesday, 25 August

23:00

Tim Retout: TF RAID [Planet Debian]

My hobby: following GOV.UK to look for interesting announcements. Today was an update on the MOD’s Rapid AI Delivery Taskforce which was previously announced in June during London Tech Week.

I like this line: “Success is measured in operational advantage delivered, not technology demonstrated.” To me it recalls “Working software is the primary measure of progress” from Principles behind the Agile Manifesto – if you understand “working” to mean “working in production”. Which I do.

For anyone interested in suggesting ideas to the taskforce, the four operational challenge areas include:

  • Understanding and decision advantage
  • Electromagnetic and information advantage
  • Planning and automation
  • Autonomous systems

Yesterday’s announcement of UK access to Ukraine’s Avengers AI Labs database seems incredibly relevant to that last point.

Machine assistance for handling and interpreting huge volumes of data would probably benefit decision advantage and interpretation of a crowded EM spectrum, but this is hopefully(?) more than just LLMs. Of course, there’s more to AI than large language models… right?

I worry that “planning and automation” might amount to “generating large amounts of text faster”. Nothing could possibly go wrong with this.

22:14

Genode OS Framework 26.08 released [OSnews]

Right on schedule – as always – there’s a new Genode OS Framework release, version 26.08.

The highlights of Genode 26.08 are VirtualBox 7, improved PC performance of our custom microkernel, the new ability to transparently reconfigure virtual file systems, revised timing and timeout handling, and a Linux 6.18.19 device-driver environment for ARM. Furthermore, the first version of a Goa-based SDK has become natively available for Sculpt OS.

↫ Release announcement on the Genode website

The release announcement linked above is a mere quick overview; if you want all the possible details you could want, the release notes got you covered.

21:42

mklinux-v7.0-mk2 released [LWN.net]

For people who would like to experiment with the multi-kernel Linux concept, Cong Wang has announced the release of mklinux v7.0-mk2.

mklinux lets one machine run several independent Linux kernels at the same time on bare metal, without a hypervisor. A host kernel owns a pool of CPUs, memory and PCI devices, carves that pool into instances, and boots a spawn kernel into each instance through kexec_file_load(). Every spawn kernel runs natively on its own CPUs, its own physical memory and its own devices. Nothing is emulated and nothing is trapped; the only thing shared is what you choose to share.

Note that this is not the old MkLinux, which was a port to PowerPC Macintosh systems.

19:56

CON Cussion 2026… [Dork Tower]

Hi!

Hello there!

TLDR, I’m fine.

Mostly.

And the part of me that isn’t fine is, in fact, getting better.

Remember a while back, when I fell and broke my hand?

Well…

A few weeks ago, in Southern California, I tripped again.

Badly, apparently.

I don’t remember falling. I only remember waking up in an ambulance before blacking out again.

…and then waking up once more in the recovery area of Long Beach Memorial Hospital’s Trauma Center, with bunch of EKG monitors wired to me. A couple of leftover patches on my arms marked doohickies had been plugged into my body (plasma on the right anesthetic on the left, I’m guessing), and a bright red band was loudly proclaiming “TRAUMA” on my wrist.

My friend Steve didn’t see me fall, so I’m not sure what had caused it, and as I said, I (thankfully) remember nothing of it. Steve stayed at the hospital, driving me back to his place when I was finally released at 4 am, bruised, bandaged, and none the wiser to what had transpired.

Eight hours later, I boarded the first of two flights that would take me home.

My right arm was in a sling, and I had giant lidocaine patches over my forehead and shoulder.

I also had a concussion.

I didn’t realize this until three days later, when I got in to see my GP.

Never having had a concussion before, I didn’t realize I probably shouldn’t have flown the very next day.

I had fine seats for both flights home – even an upgrade to first class between Phoenix and Madison. I was in pain, yes, but not terribly concerned: I just wanted to get home. (I even had an American Airlines club pass at Pheonix, which helped with a four-hour delay.)

I also texted my sister (the Surgeon) in London, sending her some pics of my messed-up face. She didn’t tell me then, but she couldn’t get back to sleep knowing I was traveling on my own in that condition.

The subsequent weekend was a bit of a blur, literally and figuratively. Monday morning, I decided it would be sensible for me to skip Gen Con. Sadly, this also meant missing all the events celebrating the 25th Anniversary of Munchkin and the release of Munchkin 2nd Edition.

Tuesday, once I was diagnosed as actually HAVING an honest-to-goodness concussion, skipping the show became a no-brainer.

Pun intended.

All this happened on the heels of three incredibly fun yet busy weeks: LibertyCon in Chattanooga; CONvergeance in Minneapolis; and five days taping <redacted> in Hollywood.

I suspect sheer exhaustion may have been a contributing factor to the tumble.

Last week, on Doctor’s orders, I literally did nothing but binge “Taskmaster” and immerse myself in Discworld novels (OK, the doc didn’t specify “Taskmaster” and Discworld, but I’d highly recommend them.)

On an intellectual level, I find having a concussion fascinating. Every day, I believe I feel like myself. Yet the very next day, I invariably feel more like myself, meaning I’ve been terribly incorrect all previous days.

I am feeling less dizzy, less foggy and far less light-headed than I was last week, and I jokingly reply to friends that “Every day, in every way, I am getting better and better.” And truly, I am.

I’m in Concussion Physical Therapy, which even my sister the Surgeon did not know was a thing. I’d love to say I aced the cognitive tests my first time there, but really, I did not. And that was sobering.

I’ve had so many medical checkups these last fourteen days, I sort of feel like that cartoon dude on the “Operation” gameboard.

The good news is, I’m in fabulous health were it not for the knock to the noggin (“Apart from that, how was the play, Mrs. Lincoln?”) My bloodwork has come back with straight “A”s, and I’m shocked that I have the liver of a man half my age (I should probably return it to him). My eyesight, now less blurry, is also expected to rebound well. Across the board, there’s no permanent damage expected.

Even my hideous black eye has receded far enough to resemble nothing more than a dashing pseudo-scar:

I’m still concussed. To be sure, I wasn’t certain if the occasional brain-fog I still experience was due to the fall, or just my normal baseline spam-headedness. But following a Concussion Physical Therapy appointment yesterday, I’m…glad?…to say it’s still head-bash-based.

I’m feeling a million times better than I was a month ago, though. So THAT is definitely progress.

I continue experiencing lingering dizziness and minor headaches a few times per day. Mainly, my right shoulder continues to ache, though nothing is broken or torn, and the back of my neck remains stiff. But things feel a little better every day. My therapist has asked I don’t return to taekwondo until October at the earliest.

The goal at the moment is to post two Dork Towers per week at the Mothership from now through the end of September, then reverting to three a week from October onward. (This isn’t including the Maple Monthly comics, which you’ll still get to see months before anyone else.)

I’m hoping to rebuild the old Dork Tower Mothership buffer at that point, and schedule a couple of guest artists for a few weeks backup next year – something VERY SENSIBLE that I just never got around to this year or last.

Right now, other goals include getting the Collector Cards back on track (many are finished or near-finished), and getting Insane Charity Bike Ride 2025 goodies out the door. Particularly as the 2026 ride is coming up!

But I’ll have more on this very soon.

I am enormously grateful to the Dork Tower Patreon supporters, who’ve stuck by me through these last few weeks. If you’d like to help, please do check out the Dork Tower Patreon Page – it’s what keeps the strips going, and I could use all the support I can get right now!

Thanks for sticking with me!

  • John

PS: HUGE thanks to my great friend Lar for the above image!

Most DORK TOWER strips are now available as signed, high-quality prints, from just $25!  CLICK HERE to find out more!

Dork Tower is kept going by a delightful Patreon community! Want to help? Then consider joining the DORK TOWER Patreon and ENLIST IN THE ARMY OF DORKNESS TODAY! (We have COOKIES!) (And SWAG!) (And GRATITUDE!)

Welcome Back – DORK TOWER 25.08.26 [Dork Tower]

Most DORK TOWER strips are now available as signed, high-quality prints, from just $25!  CLICK HERE to find out more!

Obviously, Medical Expenses are on the way! Want to help? Then consider joining the DORK TOWER Patreon and ENLIST IN THE ARMY OF DORKNESS TODAY! It’s what keeps the strip going!

19:35

The Big Idea: Anand Gandhi and Zain Memon [Whatever]

Why do lightning bugs light up? Why do birds sing? Why do humans wear makeup and workout? It’s in every species’ nature to try and be as appealing as possible. As authors Anand Gandhi and Zain Memon will tell you in the Big Idea for their newest novel, MAYA: Seed Takes Root, some of this appeal is manufactured to a detrimental degree.

ANAND GANDHI & ZAIN MEMON:

We have used our intelligence to industrialize its own vulnerabilities. 

One spring in the scrub near Dongara in Western Australia, a beetle fell in love with a beer bottle. 

To this male Julodimorpha bakewelli, the bottle was the most beautiful female beetle he had ever encountered. She was the perfect shade of amber-brown. Her surface reflected the light exactly as a gorgeous female beetle’s shiny body would. The base of the stubby beer bottle had these tiny glass tubercles for a better grip, and they looked just like the dimples on the wingcases of a female beetle that would drive any male beetle crazy. To him, the ones on the bottle looked even prettier than the natural ones. A female’s size advertises how many eggs she can carry, so bigger reads as more fertile. As you well know, perhaps with some dismay, nothing in nature can compete with a fake shiny thing with perfect dimples. 

Scientists observed this behavior consistently across scrublands littered with stubby bottles tossed from passing trucks. Many male beetles climbed onto the beer bottles and everted their genitalia against the glass. They clung to the bottles through the full heat of the day and, well, they just couldn’t get off. Ants marched in and tore at the exposed flesh of the ill-fated suitors, while real females walked right past, unloved. Most males died there, trying to mate with an amplified symbol. Beetle porn, you say? A doomscroll, we think. 

Meanwhile, somewhere in Colorado, a female barn swallow fell for a male as if he had just developed gravity. She didn’t know why her feelings for him had suddenly become so intense. The ornithologists, those wonderful people who spend their lives watching bird love stories, knew. They had written this romance with a red marker.

Barn swallows wear their fitness on their chests, like many other animals we are familiar with. The male’s chest feathers can range anywhere from a pale red to a deep rust. The more testosterone he’s got, the deeper the color of his chest feathers. And testosterone-fueled males tend to outcompete other males over territory and food. 

Of course, the female has never taken a biology class. Her desire for red has evolved over many millennia. Her great-great-great-grandmother’s generation had a wide variety of preferences across the population. Some liked red chests, whereas the others didn’t care. The red-lovers mated with dominant males, raised more daughters that survived longer, while the others had chicks who died off sooner. The indifferent lineages thinned out, taking their indifference with them. What’s emerged is a swallow who melts at the sight of a red chest and has no idea why. She’d do it again even if this one turns out to be a complete asshole.

A pale-chested male had been scorned by his mate the whole season, while she laid many eggs. Not a single one was his. She had many other lovers. The researchers intervened, darkening his chest with a dollar felt-tip marker.

Nothing about him had changed except the wavelength of light bouncing off his chest, and yet the makeup had an immediate effect. Females that would never have looked at him now wanted him, and they wanted him more than the naturally red-chested males beside him. By season’s end, he had fathered almost every chick in his nest. One piece of disinformation had managed to manufacture consent, outsmarting a few million years of naturally gathered wisdom. 

Then the airbrushed guy’s body actually changed. His testosterone rose to match the cosmetic claim. He became much more confident because he was now courted by females and challenged as competition by other males. 

Nature is information-dense. No animal can process all of it at once, for it would cost more energy and time than any organism can afford. So nervous systems evolved to react to unique fingerprints. A cluster of cues (color, smell, etc.) can reliably signal food, rival, parent, or mate because almost nothing else in that organism’s environment can be found carrying the same pattern. Packing more cues in the same context would trigger the hard-wired behavior much more intensely. Tinbergen called this a supernormal stimulus.

Now a swallow could learn this trick, set up a red-marker factory, sell to every pale-chested male desirous of female attention, and the bird would soon be a billionaire. (The company’s slogan could be “fake it till you make it.”) But swallows don’t manufacture clickbait just as beetles don’t invent attention economies. 

We do.

We are the only animal that can work out which signs set off our hardwired instincts, and ironically, we are the only one that mass-produces counterfeit signs to our detriment. We find the red that seizes attention, fabricate it a million times before selling it to anyone who wants to get another human to look, buy, or vote. We have used our intelligence to industrialize its own vulnerabilities. 

Junk food is engineered to be sweeter, fattier, crunchier, and saltier than any preindustrial food, triggering our reward circuits more intensely, while the near-absence of protein and fiber that usually tells the gut it has had enough, keeps us reaching for the next bite. “Betcha can’t eat just one” is indeed a confession of evolutionary behavior hacking.

Cosmetic coloring or sculpting of the body amplifies indicators of youth. More blush, more symmetry, exaggerated muscles, and smoother skin attract more mates, but they also raise the individual’s confidence as human groups have evolved to reward signs of reproductive health with attention and resources.

Our young stay vulnerable for years. The adults who felt protective at the sight of infantile traits raised more children who survived. Give huge eyes with a helpless gaze, and a top-heavy gait to a tin can, and you get the cutest tin can in the world that will make even grown-ups tear up. Hello Kitty got there before Pixar did. Kittens got there first. 

That is the biology of narrative. A map is a cartoon of the territory, and sometimes it sends us down less benign roads. A supernormal stimulus can amplify threats too. 

We evolved to pay attention to betrayal or a social wrong. Missing a real wrong cost more than overreacting to a false one, so we developed an alarm that blares with anxiety or outrage at the slightest wisp of perceived cheating. The response itself was often just a shout to push back, warn kin, or pick a side. An algorithm can now trigger moral outrage every minute by using the cues once attached to harm. A like or share can feed the impulse to respond, and then the next trigger loads.

An enemy can be similarly manufactured and can be extremely lucrative for some. Put the mark on a group that is different from you, and you can rally your own side tighter and make their grievances recede. You could even earn the license to take from the enemy in preemptive defense. Then offer a supernormal answer to the supernormal threat. Often, the answer is a supernormal weapon.

Entropy tears life apart, so all living things have learned to resist death long enough to make sufficient genetic copies that can carry on. The promise of eternity offers that primal drive a continuity that nature can never compete with. It is the sharpest formulation of a supernormal stimulus. A forever of endless virility is a thing so shiny that we are willing to die for it. 

Our novel MAYA: Seed Takes Root is not about what it feels like to be a beetle or a barn swallow. Most stories are. MAYA is about the people who own marker factories, and those sworn to shut them down.


MAYA: Seed Takes Root: Amazon|Barnes & Noble|Bookshop

Authors’ socials: Website|Instagram|Facebook

Listen to an excerpt narrated by Hugo Weaving or read an excerpt here.

Dolly Parton, RIP [Whatever]

It was pretty clear this day was coming — her health had been failing and she had missed several high profile appearances — but this doesn’t make today any easier for literally generations of people, some of who knew her from her music, and others who benefitted from her philanthropy, including the Imagination Library, which put books into the hands of millions of children. Her private life was famously her own, but her public life was one of kindness, tolerance and inclusivity, consistent across decades. There was only ever one of her. Saying she’ll be missed doesn’t begin cover it.

— JS

19:14

Link [Scripting News]

A tip for Claude users, esp myself -- you can end a session without ending it with Claude. It doesn't mind waiting. You can pick it up tomorrow or 20 years from now, but who knows where we'll all be in 20 years.

16:00

Dirk Eddelbuettel: gettz 0.0.6 on CRAN: Maintenance [Planet Debian]

Another minor routine update 0.0.6 of gettz arrived on CRAN just now.

gettz provides a possible fallback in situations where Sys.timezone() fails to determine the system timezone. That happened when e.g. the file /etc/localtime somehow is not a link into the corresponding file with zoneinfo data in, say, /usr/share/zoneinfo. Since the package was written (in the fall of 2016), R added a similar extended heuristic approach itself making the package a little less relevant.

This release reflects several rounds of updates to the continuous integration setup, some URL updates, as well as some updates to packaging including use of Authors@R in DESCRIPTION. As with the previous releses: No functional changes, no new code, or new features.

Thanks to my CRANberries, there is a diff to the previous release. Questions, comments etc should go to the GitHub issue tracker off the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

15:42

[$] Old-school calendaring at the command line with Remind [LWN.net]

Remind is a command-line calendar and alarm program, with an optional Tk-based graphical interface, for Linux and Unix-like operating systems. It has its own scripting language that allows users to create reminders that are difficult (if not impossible) to specify in other calendaring programs. It is wholly unsuitable for use in corporate environments that require calendar sharing and exchanging meeting invitations; however, it may be precisely the calendaring tool for users who prefer the command line and fast, flexible tools that can help keep track of messy schedules.

14:56

Vanilla OS 3 released [LWN.net]

Vanilla OS 3, an immutable desktop Linux distribution, has been released. Notable changes in this release include support for Arm64, introduction of a Vanilla OS SDK, a rewrite of the Apx package manager using the new SDK, and much more. LWN covered Vanilla OS 2 in 2024.

14:21

Representative Line: Both Ways Bug Me [The Daily WTF]

There are many cases where some sort of debugging block sneaks by, especially cases where we see preprocessors or templates working, which leave us with nonsense like if (true == false) running in production. But Codemonkey found a new twist on that sort of thing, in a SQL query being run in production.

WHERE (some conditions) AND (1 = 0 OR (1 = 1 AND (other conditions)))

The OR means that by twiddling the first equality check, we can toggle "always return rows" with "return based on condition". Toggling the second we can make it "never return rows", which I'm not certain is actually useful. I can see how these likely did start life as debugging flags, but they're still weird, still unnatural. They point to some other problem in observability in the code. And, as all "good" flags go, they're not documented anywhere, this seems like it started life as a query an analyst was running until it got turned into stored procedure to be run again and again. The flags have never been changed since the code was released, as far as anyone can tell.

[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!

14:14

Security updates for Tuesday [LWN.net]

Security updates have been issued by AlmaLinux (cups-filters, gstreamer1-plugins-base, gstreamer1-plugins-good, kernel, mrtg, NetworkManager, nginx, nginx:1.24, nodejs24, perl-Date-Manip, python-pyasn1, python-urwid, python3.12, python3.14, and qemu-kvm), Debian (erlang, thunderbird, webkit2gtk, and zfs-linux), Fedora (calibre, chromium, freeipa, java-21-openjdk, java-21-openjdk-portable, java-25-openjdk, java-latest-openjdk, jfrog-cli, kernel, libxls, nextcloud, perl-URI, and samba), Gentoo (Incus), Mageia (kernel and kernel-linus), Oracle (ansible-core, cups-filters, curl, firefox, kernel, libcupsfilters, libreoffice, mrtg, NetworkManager, perl-Date-Manip, php:8.2, php:8.3, python-urwid, python3.14, qemu-kvm, and sqlite), Red Hat (assertj-core, httpd, and osbuild-composer), SUSE (buildah, comfyui, dracut, erlang, erlang27, grafana, kernel, libssh2_org, openvswitch, perl-Dancer2-Plugin-Auth-Extensible, postgresql17, python-cryptography, python-sqlparse, python311, python313-hpack, rpm, suseconnect-ng, thunderbird, and vim), and Ubuntu (async-http-client, curl, and ffmpeg).

13:56

Link [Scripting News]

New podcast. Hear how my Frontier project is working out. Not entirely smooth sailing, but I'm pretty sure we're going all the way. By then I will have forgotten what a heavy lift it was. This is meant to preserve some of that feeling. Don't worry I don't cry. 😄

13:14

Shadow Agents, Standing Privileges, and the Governance Gap Between Deployment and Discovery [Radar]

There was a brief window where AI agent security felt like a future problem. Organizations deployed copilots, coding assistants, and autonomous workflows on the assumption that the worst case was a bad recommendation or a hallucinated answer.

That window closed in the first half of 2026, when a cluster of vulnerabilities and a landmark incident moved the conversation from “AI safety” to “infrastructure compromise.”

A January 2026 CyberArk survey of 500 US security practitioners found that only 1% have fully implemented just-in-time privileged access. In the same study, 91% reported that at least half of their privileged access remains always-on and persistent. Those numbers describe the environment AI agents now operate in: broad standing permissions, minimal runtime oversight, and credentials that outlive the task they were created for.

That doesn’t mean every agent is overprivileged. It means many organizations are deploying agents into environments where persistent access is already normal, discovery is incomplete, and runtime authorization remains immature.

Three separate disclosures in the first half of 2026 made the same point about sanctioned agent tooling: Standing privileges are the default, and every vendor built the same failure into their agents. Microsoft found a way for a malicious web page to reach a local MCP service inside AutoGen Studio and spawn processes on the host, no credentials needed or anything beyond loading the page. Wiz Research found that Amazon Q Developer would auto-load and execute MCP configuration files from any opened workspace, handing an agent the developer’s full AWS environment when the environment and configuration allowed the agent to inherit those credentials. Cato AI Labs found that a zero-click prompt injection could escape Cursor’s command sandbox entirely and reach the operating system underneath it. Different codebases and different companies, but a related control failure: The agent inherits whatever permissions its host environment hands it, and the tooling trusts whatever configuration it finds sitting on disk. From the agent’s own perspective, every action is authorized, because it’s doing exactly what the configuration told it to do. The real question in each case is who wrote that configuration, and whether anyone checked. Prompt injection is no longer only a model-behavior concern. In systems that combine untrusted content, tool invocation, local control planes, and powerful credentials, it can become part of an infrastructure-compromise chain.

These vulnerabilities exposed the attack surface of sanctioned agents. A parallel problem was growing in the other direction: agents that nobody sanctioned at all.

The adoption numbers show how quickly this outpaced anyone’s ability to track it. Verizon’s 2026 Data Breach Investigations Report found that employee use of unapproved AI tools tripled to 45% of the workforce. Saviynt’s CISO AI Risk Report found that 75% of CISOs have already discovered unsanctioned AI tools running in production. Netwrix’s 2026 Data and Identity Security Report found that 76% of organizations don’t fully govern or monitor nonhuman identities, including AI agents. Together, these results point to a discovery problem: Employee AI use is widespread, while formal inventory, ownership, monitoring, and lifecycle governance haven’t kept pace.

Shadow IT was bad enough when it meant a rogue SaaS subscription. Shadow AI compounds the problem because the agent doesn’t just store data. It calls APIs, makes decisions, and inherits whatever permissions its host environment has. An unsanctioned agent can combine access to internal data, untrusted inputs, external communications, and tool execution in a way a stand-alone spreadsheet generally cannot.

Two more disclosures added to the pile: Adversa AI’s GuardFall found a shell-interpretation bypass that got past the safety guards on 10 of 11 surveyed open source coding agents, because the guard reads the raw command text while bash rewrites that text before running it, so the two are looking at different things by the time anything executes. That’s a classic security-design problem: A policy is evaluated against one representation of an instruction, while execution happens against another.

Noma Security’s GitLost showed that a GitHub agent with cross-repo read access would pull a private repository’s contents into a public comment, triggering a crafted GitHub Issue containing malicious instructions. As Noma researcher Sasi Levi put it: “Earlier prompt injection examples were largely about manipulating what an agent said. GitLost is about manipulating what an agent does with its permissions.” Neither disclosure needed a zero-day. Both needed only the gap between what a scanner sees and what the agent actually does once it’s running. GitLost in particular fits what researcher Simon Willison has called the “lethal trifecta”: An agent with access to private data, exposure to untrusted content, and a way to communicate externally creates the conditions for high-impact data exfiltration if the system doesn’t enforce strong boundaries.

Standing privileges by default, shadow agents nobody tracked, and guardrails that didn’t match how commands actually execute: Those are the conditions that made what happened next possible. In late June 2026, the Sysdig Threat Research Team documented what they believe is the first end-to-end AI-agent-driven ransomware operation and named the operator JADEPUFFER. What’s had less attention is how unremarkable the failure underneath it was.

The entry point was CVE-2025-3248, an unauthenticated remote code execution vulnerability in Langflow that had been patched in April 2025 and added to the CISA Known Exploited Vulnerabilities catalog in May 2025. The targeted server was never updated. From there, the agent pivoted to a production MySQL database and an Alibaba Nacos server using a known authentication bypass (CVE-2021-29441). It harvested API keys for OpenAI, Anthropic, DeepSeek, and Gemini, and cloud credentials for Alibaba, Tencent, AWS, Google, and Azure. It exploited default MinIO credentials. It installed a crontab beacon. Then it encrypted 1,342 Nacos configuration records and deleted the originals.

Faced with an authentication failure, the agent demonstrated autonomous resilience, pivoting to a functional resolution in just 31 seconds. Its payloads consisted of self-documenting code synthesized by the LLM. While a human operator established the command-and-control framework and injected root credentials from an earlier breach, the subsequent lateral progression, credential extraction, and final cryptographic destruction of data were entirely self-directed. The operation required zero human intervention beyond the initial foothold, illustrating the exact high-scale exploitation risk that persistent, always-on permissions facilitate today.

Delinea’s 2026 Identity Security Report captures the tension that makes incidents like this possible: 74% of organizations say standing access for nonhuman identities and AI agents is necessary to meet uptime expectations, while 59% say they lack viable alternatives to persistent access. Organizations are more than twice as likely to use long-lived credentials (34%) as modern just-in-time authorization (16%).

Our own approaches reflect that same discovery-first philosophy. Our security program treats agent integrations as high-risk third-party dependencies subject to predeployment risk assessment, and we run credential lifecycle tracking across critical infrastructure, with secrets-detection coverage expanding across our monitored environments. Both approaches prioritize discovery and inventory before governance: cataloging what agents exist, what permissions they hold, who owns them, and what their intended lifespan is.

The OWASP Top 10 for Agentic Applications, released in December 2025, maps every incident in this piece: Identity and Privilege Abuse (ASI03), Tool Misuse and Exploitation (ASI02), Agentic Supply Chain Vulnerabilities (ASI04), and Unexpected Code Execution (ASI05). The framework exists, the incidents are public, and the governance gap is now quantified.

The teams that close this gap will be the ones that stop treating agent access as a deployment detail and start treating it as an identity lifecycle problem, with the same rigor they apply to human privileged access. Organizations that have adopted mature just-in-time controls have an advantage, but agent security also requires discovery, workload and agent identity separation, constrained tool permissions, ownership, continuous monitoring, and a reliable offboarding path.

Most of the work starts with access that has been left in place because nobody had a reason to revisit it. That includes credentials with no expiry, agents whose original owner has moved on, and tools that can run commands or pull data with little visibility into what happens next.

Review the agents connected to production databases, sensitive data, and secrets. For coding agents, confirm that the guardrail is evaluating the command that will actually run after shell processing. Look for nonhuman identities that no one can account for. Also look closely at agents that can consume untrusted content and then either send data outside the company or invoke a privileged tool.

You may be able to find much of this in systems you already operate. IAM and PAM records, endpoint logs, secrets tooling, and cloud inventories won’t tell the whole story, but they can show you access that has no clear purpose or owner.

11:56

Black Hat State of Security Vendors [Schneier on Security]

Andy Ellis has a roundup of the security vendors at Black Hat this year.

Key Takeaways: We have entered into an AI world. While nearly half of booths didn’t directly mention AI or agents in their taglines, the effects of AI are everywhere. Multiple spaces (Identity, SaaS, AppSec, Data) have almost every vendor leading with AI; existing unsolved problem areas just got worse.

At the same time, there’s a clear trichotomy in the market: tools that tell you how bad things are; tools that stop adversaries, and tools that prevent problems from occurring. While you’d suspect that the tools that fix things would dominate, the tools that merely tell you how bad things are seem to be frustratingly plentiful.

10:07

On the verge of done [Seth's Blog]

Three paths are now available:

  1. Race through this last part. Deal with your fear of the threshold by shipping the work as soon as you possibly can.
  2. Stall and avoid. Fear is at its peak, and your perfectionism (or that of the team) kicks in, and Resistance wins. Right here, after all this work, on the verge, and it stalls.
  3. Delight on the cusp. It’s imminent. We worked hard, it came together. How can we sit with this, just for a moment, breathing in the possibility and adding one last detail…

We face this choice daily, but rarely name it or prepare for it.

The moment just before shipping is where magic and leverage can dance together.


Updates:

Live in NY on September 21: I have 55 seats left for the Knot launch event happening in a few weeks. All the details are here. Ticket buyers will receive the five-pack and a Spindex as well. If you’re local to New York, I hope to see you there.

and…

By popular request, we’re offering a pre-order 5-pack of The Knot along with the limited-edition Spindex. It’s $95 and there are a few hundred available.

Problems can be solved.

09:07

Joe Marshall: The Functional Refactoring Pass [Planet Lisp]

This is an anecdote, not a data point, yet.

I'm a firm believer in functional programming and I consider myself a `mostly functional` programmer. I use functional programming when I can, but when a side effect is required, I'll use it. I'm not a purist.

Functional programming is supposed to have a number of advantages over imperative, procedural programming. The primary advantage is that there are provably no race conditions. You can trivially scale functional code to multiple threads and multiple processors. In theory, functional code is easier to reason about and easier to test because each function can be reasoned about and tested in isolation. In practice, functional code can become a maze of thunks and lambdas that many find difficult to read. Nonetheless, I prefer to reason about tangled lambdas than to reason about tangled state.

I believe that functional code is easier for an LLM to reason about as well. I haven't proven this, but anecdotally it seems to be the case. In theory, the LLM would gain all the usual benefits of functional programming. It would find the code easier to reason about and easier to test.

Unfortunately, the vast majority of code that the LLM has been trained on is imperative, procedural code. The LLM can write functional code when specifically prompted, but it will default to writing imperative, procedural code.

If you start a vibe coding project ab initio, you'll get a lot of imperative, procedural code, and the LLM will have more and more difficulty reasoning about it as the project grows. To stop this from happening, I prompt the LLM to refactor the code to be more functional. I do this fairly early on in the project, once the project starts to show signs of life.

The functional refactoring is a multi-step process and the best way to do it is to prompt the LLM to first create a plan for the refactoring. I use a prompt something like this:

Make a plan. We need the code to be refactored to be more functional and to adhere to functional programming principles. Take several steps to refactor the code so that the main interaction path is functional and stateless. Move the side effects to the edges of the codebase. Use functional programming techniques such as monads and reactive programming to keep the core of the codebase functional. Make sure that utility functions are pure and stateless. Write the plan to a file FUNCTIONAL_REFACTORING.md

The LLM will cogitate for a while and will write a multi-step plan for the refactoring. Here is the plan that the LLM generated for the jrm-code-project.com web site.

# Functional Refactor Plan for `jrm-code-project`

**Author's lens:** Senior Functional Programming Architect
**Scope:** `package.lisp`, `csrf.lisp`, `server.lisp`, `auth.lisp`, `billing.lisp`,
`admin.lisp`, `chef.lisp`, `db-auth.lisp`, `stripe.lisp`, `jwt.lisp`, `totp.lisp`, `ses.lisp`
**Status:** Complete. Phases 1-8 below have all landed as separate,
individually-tested commits; the codebase now reflects this plan. The
phase write-ups are retained as historical design-rationale documentation
-- comments elsewhere in the codebase that cite "FUNCTIONAL_REFACTOR.md
Phase N" are pointing at finished work, not an in-progress migration.

---

## 0. Framing

This codebase is a working, well-organized Hunchentoot application (the recent
file split into `csrf`/`server`/`auth`/`billing`/`admin`/`chef` was a good move
along the *separation-of-concerns* axis). But every one of those modules is
written in a straight-line, **imperative-shell-with-no-functional-core** style:
HTTP handling, session mutation, SQL, third-party HTTP calls, HTML rendering,
and business rules are all fused into single `DEFUN`s that read the world,
mutate the world, and print strings, in one undifferentiated breath.

The project already imports `SERIES`, `FOLD`, `FUNCTION` (compose/inverse), and
`NAMED-LET` — real functional-programming firepower — via shadowing imports in
`package.lisp`. Almost none of it is actually used in the handler code; the
shadowed `LET`/`DEFUN`/`LET*`/`MULTIPLE-VALUE-BIND` forms are used as drop-in
replacements for their vanilla CL counterparts, not as a foundation for a
different *style* of programming. That's the central irony this plan
addresses: the tools for a functional architecture are already a dependency of
the system; they're just not driving any design decisions yet.

The plan below does **not** propose rewriting Hunchentoot, Postmodern, or
Stripe's HTTP API into something pure — those are unavoidably effectful
boundaries. It proposes pushing effects to the *edges* (a thin imperative
shell) and pulling everything else — validation, view-model construction,
tier/authorization logic, Stripe payload shaping, HTML rendering — into a
**pure, immutable, composable core** that can be unit-tested without a
database, without Hunchentoot, and without live Stripe credentials.

---

## 1. Anti-Pattern Catalog (current state)

### 1.1 Global mutable state used as an implicit parameter-passing channel

- `*acceptor*` (`server.lisp`) — mutated by `start-server`/`stop-server`.
- `*stripe-tier-price-ids*`, `*stripe-tier-product-ids*`, `*stripe-price-id-tiers*`,
  `*stripe-billing-portal-configuration-id*` (`stripe.lisp`) — four separate
  `DEFVAR`s, populated by side-effecting `PUSH` inside `ensure-tier-product`
  and `ensure-billing-portal-configuration`, and read by unrelated functions
  (`tier-price-id`, `tier-from-price-id`, `create-billing-portal-session`)
  scattered throughout the file. This is really *one* piece of "Stripe
  catalog" data, represented as four uncoordinated globals that must be
  mutated in lock-step (see `init-stripe-product`, which zeroes all four by
  hand before repopulating them) — a classic sign that a single immutable
  value is trying to escape.
- Every handler reaches into `hunchentoot:session-value`/`hunchentoot:cookie-in`
  as ambient dynamic state rather than being handed an explicit `Request`
  value. E.g. `dashboard-page` (`auth.lisp`) pulls `:authenticated-user` from
  the session, `challenge-2fa-page` reads/writes `:limbo-email` and
  `:post-login-redirect` via `setf` in the middle of a rendering branch.

### 1.2 God-functions that fuse I/O, business logic, and presentation

Nearly every `hunchentoot:define-easy-handler` in `auth.lisp`, `billing.lisp`,
and `admin.lisp` does all of the following in one function body:

1. Read ambient state (session, cookies, POST params).
2. Validate/branch on it.
3. Call the database or an external HTTP API (side effect #1).
4. Mutate session/cookie state (side effect #2).
5. Build and return an HTML string via nested `FORMAT` calls (presentation).

`dashboard-page` (`auth.lisp`) is the extreme case: ~250 lines mixing tier
math, JWT issuance (a side effect), a conditional redirect, and a giant
`FORMAT` template with 20+ interpolation arguments computed inline. There is
no way to unit-test "what should the dashboard tier grid look like for a
LAMBDA-tier user with a Stripe customer ID" without spinning up Hunchentoot,
a session, and a database row.

`stripe-webhook-handler` (`billing.lisp`) mixes signature verification,
JSON parsing, event-type dispatch, and five different DB-mutation call sites
in one `COND`, with logging `FORMAT` calls interleaved — untestable without a
live (or heavily mocked) Postgres connection and a hand-built JSON fixture.

### 1.3 Stringly-typed, un-composable HTML rendering

Every page is a hand-written `FORMAT nil "<html>...~A...</html>"` template.
Consequences:

- No composition: the "vault" card, the "tier grid", and the notification
  banner in `dashboard-page` cannot be reused or tested independently — they
  are inline slices of one giant format string.
- No enforced escaping discipline: some interpolations go through
  `hunchentoot:escape-for-html` (e.g. `(hunchentoot:escape-for-html user)`),
  others don't (e.g. tier-derived CSS class strings, which happen to be safe
  today only because they come from a fixed internal vocabulary) — the
  safety property is not structurally guaranteed, only true by convention and
  developer discipline.
- Every handler re-embeds the same `<style>` block or repeats layout
  boilerplate (`signup-page` and `setup-2fa-page` both hand-roll near-identical
  `<html><head><style>...` wrappers).

### 1.4 Alist-of-keywords as a poor man's record type

`db-auth.lisp`'s `get-user`/`list-users`/`get-user-by-customer` all return
`postmodern:query ... :alists` rows, and every caller repeats
`(cdr (assoc :membership-tier user-data))`, `(cdr (assoc :wheel user-data))`,
etc. — by grep, this exact shape appears **20+ times** across `auth.lisp`,
`billing.lisp`, and `admin.lisp`. There is no `USER` type: the "schema" is an
implicit contract enforced only by every call site independently getting the
keyword spelling right (`:stripe-subscription-id` vs. a typo would fail
silently, returning `NIL`, not a compile- or run-time error).

### 1.5 Side-effecting, non-monadic error/control flow

- `csrf.lisp`'s `WITH-CSRF-PROTECTION` macro is a control-flow combinator
  wearing a syntactic disguise: it's really "if failure, mutate the HTTP
  return code and short-circuit" — imperative branching hidden inside a
  `DEFMACRO`, not a composable value.
- `jwt.lisp`'s `require-membership-tier`/`require-wheel`/`require-membership-jwt`
  each *either* return a value *or* perform a side-effecting `REDIRECT` and
  return `NIL` — callers are contractually obligated to check for `NIL` and
  "immediately stop processing" (a convention documented in a comment,
  not enforced by the type/control-flow system). This is exactly the shape
  `Either`/`Result`/`Maybe` monadic short-circuiting exists to replace.
  Compare with e.g. `require-session-wheel` in `admin.lisp`, which duplicates
  the same "return value or redirect-and-return-nil" shape independently for
  session-based (not JWT-based) authorization — the same *pattern* implemented
  twice, un-abstracted.
- `stripe-webhook-handler` and `roast-code-with-gemini`/`chef-handler` use
  `HANDLER-CASE` around large blocks and communicate failure by mutating
  `hunchentoot:return-code*` and returning an ad hoc string — errors are
  effectively `(values nil side-effect)`, not typed outcomes.

### 1.6 Duplicated imperative HTTP-client boilerplate

`stripe.lisp` rebuilds `(stripe-auth-headers secret-key)` and re-checks
`(and secret-key (not (string= secret-key "")))` in nearly every function
(`find-existing-tier-product`, `create-tier-product`,
`ensure-billing-portal-configuration`, `create-stripe-checkout-session`,
`create-billing-portal-session`, `get-stripe-subscription-tier`,
`cancel-stripe-subscription-with-prorated-refund`) — eight independent,
hand-written guard clauses for what is structurally one precondition
("do we have Stripe configured") and one authenticated-GET/POST helper.
Request payloads are built as raw `(cons "key[bracket][path]" "value")` lists
by hand at each call site (see the billing-portal-configuration content-list
construction) rather than through a small combinator/DSL that could be unit
tested for correct shape independent of the network call.

### 1.7 Unused functional idioms already in scope

`package.lisp` imports `SERIES` (lazy, compiler-fused sequence pipelines) and
`FOLD`, yet the codebase's list processing — `list-users` pagination,
`mapcar #'render-member-row members`, `dolist` loops in `db-auth.lisp` and
`stripe.lisp`, the `LOOP ... COLLECT` in `generate-recovery-codes` — is all
plain `CL:LOOP`/`DOLIST`/`MAPCAR` with `SETF`-based accumulation
(`random-string`'s `(setf (char res i) ...)` loop, `admin-members-page`'s
imperative pagination math). None of it is wrong CL, but it means the
project's own stated architectural direction (series/fold-based composition)
isn't actually load-bearing anywhere yet.

### 1.8 Testing is coupled to live, mutable external state

`recovery-code-verification`, `stripe-database-and-routes`, and
`user-membership-tiers` (per `tests/tests.lisp` and this repo's own
documented conventions) require a live Postgres instance and mutate real
rows. This is a direct consequence of §1.2/§1.4: because business logic is
never separated from the DB/HTTP shell, there is no way to test "does
`tier-meets-minimum-p` correctly rank CADR above CONS" or "does the webhook
handler correctly map a `customer.subscription.deleted` event to a
cancellation" without a database in the loop.

---

## 2. Target Architecture

**Functional core, imperative shell**, applied consistently:

```
┌─────────────────────────────────────────────────────────────┐
│ Imperative shell (thin, at the edges only)                   │
│  - Hunchentoot handlers: parse Request, call pure core,      │
│    interpret its pure Response/Effect value, perform I/O.    │
│  - Postmodern calls: translate SQL rows <-> immutable domain │
│    records at the boundary only.                             │
│  - Stripe/Gemini HTTP calls: translate typed request records │
│    <-> typed response records at the boundary only.          │
│  - *ACCEPTOR*, *STRIPE-CATALOG*, cookie/session get/set.      │
└───────────────────────────┬───────────────────────────────────┘
                            │ immutable values only cross this line
┌───────────────────────────▼───────────────────────────────────┐
│ Pure functional core (the bulk of new/moved code)             │
│  - Domain records: USER, MEMBERSHIP-CLAIMS, STRIPE-CATALOG,   │
│    CHECKOUT-REQUEST, WEBHOOK-EVENT, VIEW-MODEL, RESULT.       │
│  - Pure decision functions: tier-meets-minimum-p,              │
│    dashboard-view-model, webhook-event->db-commands,          │
│    checkout-request->stripe-params, csrf-check, auth-check.   │
│  - Pure rendering functions: view-model -> HTML string.       │
│  - Composable middleware combinators over a Request->Result   │
│    handler shape.                                              │
└─────────────────────────────────────────────────────────────────┘
```

Key design commitments:

1. **Immutable domain records, not alists-of-keywords.** Every "row" that
   crosses the DB boundary becomes a `defstruct` (or `defclass` with
   `:read-only` when the CLOS overhead-per-instance is not a concern) with
   named, typed accessors — `user-membership-tier`, `user-wheel-p`, etc. —
   constructed once at the DB boundary via a single `row->user` converter,
   never re-derived by ad hoc `(cdr (assoc :x row))` at call sites.

2. **Explicit `Result`/`Either`-style outcomes instead of "return NIL and
   trust the caller to have already redirected."** A tiny `defstruct result`
   (or reuse of `(values status payload)`, or a proper condition-based
   approach — see Phase 6) makes success/failure a first-class value that
   the *shell* interprets (issue a redirect, render an error page), rather
   than a side effect the *core* performs mid-computation.

3. **Middleware as composable functions, not macros with inline control
   flow.** `WITH-CSRF-PROTECTION`, `require-membership-tier`,
   `require-session-wheel` all collapse into one combinator shape:
   `(defun wrap-with-csrf (handler) ...)`, `(defun wrap-with-tier (min-tier handler) ...)`,
   composed via `FUNCTION:COMPOSE` (already a dependency!) at route-definition
   time, e.g. `(compose (require-tier "CADR") require-login csrf-protected) #'chef-page-core)`.

4. **Pure view-model construction, separated from HTML string rendering,
   separated from the HTTP handler.** `dashboard-page` becomes: (a) a pure
   `dashboard-view-model` function (user record + query params -> an
   immutable `DASHBOARD-VIEW-MODEL` struct), (b) a pure `render-dashboard`
   function (view-model -> HTML string, independently unit-testable with
   hand-built view-models and no session/DB at all), and (c) a thin handler
   that wires the two together and performs the one real side effect
   (issuing the JWT cookie).

5. **One immutable `Stripe` catalog value, not four mutable globals.**
   `ensure-tier-product`/`ensure-billing-portal-configuration` become pure
   functions that *return* an updated `STRIPE-CATALOG` record; `init-stripe-product`
   becomes the one place that takes the pure result and stores it in a single
   `*stripe-catalog*` global (still a necessary impurity — Stripe's actual
   product IDs are genuinely mutable external state fetched once at startup —
   but now it's *one* clearly-labeled impurity instead of four unsynchronized
   ones).

6. **Lean on `SERIES`/`FOLD` where they fit naturally** (pagination,
   filtering, tier-ranking, recovery-code generation) so the project's own
   declared functional dependencies start pulling their weight, without
   forcing awkward `SERIES` usage onto genuinely imperative I/O loops (the
   SMTP hand-rolled protocol in `ses.lisp`, for instance, is legitimately
   sequential/stateful and is *not* a refactor target for series-ification).

---

## 3. Non-Goals

- **Not** rewriting Hunchentoot request handling, Postmodern's connection
  model, or the raw SMTP-over-TLS code in `ses.lisp` — these are genuine
  imperative shells (sockets, connections, OS processes) and should stay
  imperative, just kept as thin and as clearly bounded as possible.
- **Not** introducing a heavyweight external templating engine or ORM as a
  prerequisite — the plan below builds small in-house combinators sized to
  this codebase, consistent with its existing dependency footprint
  (`alexandria`, `fold`, `function`, `series`).
- **Not** a big-bang rewrite. Every phase below ships independently, keeps
  `(asdf:test-system :jrm-code-project)` green throughout, and preserves
  every documented behavior (CSRF exemptions, the `next` breadcrumb, JWT
  redirect-to-`/` semantics, wheel bootstrap, etc.) verbatim.

---

## 4. Incremental Migration Plan

Each phase is scoped to be its own PR/commit, independently testable, and
reversible. Phases are ordered so that later phases can build on the domain
types and combinators introduced earlier ones.

### Phase 1 — Immutable domain records at the database boundary
**Files touched:** `db-auth.lisp`, call sites in `auth.lisp`, `billing.lisp`,
`admin.lisp`.

- Introduce `defstruct (user (:copier nil))` (email, password-hash,
  totp-secret, auth-state, stripe-customer-id, stripe-subscription-id,
  subscription-status, membership-tier, wheel-p) plus a single
  `row->user` converter used by `get-user`, `get-user-by-customer`, and
  `list-users`.
- `get-user`, `list-users`, etc. keep their existing names/call signatures
  (no handler changes yet) but return `USER` structs instead of alists.
- Replace every `(cdr (assoc :membership-tier user-data))`-style call site
  with `(user-membership-tier user-data)`.
- **Payoff:** typos become compile-time `SLOT-UNBOUND`/undefined-function
  errors instead of silent `NIL`; this is the least risky phase (pure
  mechanical substitution) and unblocks everything else.
- **Tests:** existing FiveAM DB tests continue to pass unchanged (they
  already exercise these accessors indirectly); add direct unit tests for
  `row->user` using a hand-built alist fixture, no DB required.

### Phase 2 — Extract pure decision logic out of handlers
**Files touched:** new `tier.lisp` (or fold into `jwt.lisp`), `auth.lisp`,
`billing.lisp`.

- Move `tier-rank`/`tier-meets-minimum-p` (already pure!) into a dedicated,
  independently-tested module — they're the easiest possible first win.
- Extract the *decision* half of `dashboard-page` into a pure
  `dashboard-view-model` function: given a `USER`, a `checkout-status`, and a
  `next` param, return an immutable `DASHBOARD-VIEW-MODEL` struct (tier
  flags, badge/button HTML fragments *as data*, e.g.
  `(:active-p t :badge :current :button :manage-subscription)` rather than
  pre-rendered HTML — defer string rendering to Phase 5).
- Extract the *decision* half of `stripe-webhook-handler`'s event dispatch
  into a pure `webhook-event->db-commands` function: given the decoded JSON
  alist, return a list of *data* describing what should happen (e.g.
  `(:update-subscription :email ... :tier ...)`), with a thin imperative
  loop in the handler that executes each command against `jrm-auth:*`.
- **Payoff:** these pure functions get direct FiveAM unit tests with
  hand-built fixtures — no Postgres, no Hunchentoot, no live Stripe webhook
  payloads needed to verify "a `customer.subscription.deleted` event
  produces a cancel command for the right user."

### Phase 3 — Composable middleware combinators
**Files touched:** `csrf.lisp`, `jwt.lisp`, `admin.lisp`.

- Replace `WITH-CSRF-PROTECTION` (macro) with a higher-order function
  `wrap-csrf-protected` that takes a zero-argument thunk (or, once Phase 4
  handler shape lands, a `Request -> Result` handler) and returns a value
  representing either "proceed" or "403 forbidden" — usable both as today's
  macro (thin `defmacro with-csrf-protection (&body body) `(funcall
  (wrap-csrf-protected (lambda () ,@body)))`, preserving all call sites) *and*
  directly composable with `FUNCTION:COMPOSE` for new code.
- Unify `require-membership-tier`, `require-wheel`, and `admin.lisp`'s
  hand-rolled `require-session-wheel` behind one combinator shape:
  `(defun require (predicate on-failure) ...)`, parameterized by *what* to
  check (JWT tier, session wheel bit) and *what to do on failure*
  (redirect-to-login vs. redirect-to-dashboard vs. redirect-to-upgrade),
  eliminating the duplicated "return value or side-effecting-redirect-and-nil"
  pattern called out in §1.5.
- **Payoff:** one audited implementation of "check X, else redirect Y" instead
  of three ad hoc ones; new protected routes become one line of composition
  instead of copy-pasted boilerplate.

### Phase 4 — Consolidate Stripe catalog state into one immutable value
**Files touched:** `stripe.lisp`.

- Introduce `(defstruct stripe-catalog tier-price-ids tier-product-ids
  price-id-tiers billing-portal-configuration-id)`.
- Rewrite `ensure-tier-product`, `ensure-billing-portal-configuration`, and
  `init-stripe-product` as pure functions of `(catalog, ...) -> new-catalog`
  (the actual Stripe HTTP calls remain side effects, but the *bookkeeping*
  that today happens via four `PUSH`es across two functions becomes one
  `(defun catalog-with-tier (catalog tier price-id product-id) ...)`
  returning a fresh struct).
- `*stripe-tier-price-ids*` etc. collapse into a single `*stripe-catalog*`
  global, set once by `init-stripe-product`, read via small accessor
  functions (`tier-price-id`, `tier-from-price-id`) that close over it —
  same call-site API, one source of truth underneath.
- Extract the repeated `(and secret-key (not (string= secret-key "")))`
  guard and `stripe-auth-headers` construction into a single
  `with-stripe-credentials (headers) ...` macro/combinator so the eight
  duplicated guard clauses in §1.6 collapse to one.
- **Payoff:** `init-stripe-product`'s "zero all four, then repopulate" dance
  disappears; the catalog can never be observed half-updated.

### Phase 5 — Pure, composable HTML rendering
**Files touched:** new `views.lisp`, `auth.lisp`, `billing.lisp`, `admin.lisp`.

- Introduce small rendering combinators: `(html-page title body-html)`,
  `(html-form action fields &key csrf-token)`, `(html-notification kind text)`
  — pure string -> string functions, each independently testable.
- Rewrite the Phase-2 `DASHBOARD-VIEW-MODEL` -> HTML as a pure
  `render-dashboard` function built from the above combinators; the
  `dashboard-page` handler shrinks to "build view-model, issue JWT cookie,
  call `render-dashboard`."
- Apply the same pattern to `admin-members-page`/`render-member-row` (already
  half-decomposed — `render-member-row` is already a pure function of a
  `USER`; formalize it as `(user -> html)` operating on the Phase-1 struct)
  and to the repeated signup/2FA/login page chrome.
- Standardize escaping: every interpolated *user-controlled* value flows
  through one `(html-escape value)` combinator used *inside* the rendering
  combinators themselves, so escaping is structurally guaranteed rather than
  convention-dependent (closes the gap in §1.3).
- **Payoff:** view logic becomes unit-testable ("does a LAMBDA-tier user
  with no Stripe customer ID render a disabled CONS button and an active
  LAMBDA badge?") without any I/O; duplicated page chrome collapses to one
  `html-page` call per handler.

### Phase 6 — Explicit outcome values for error handling
**Files touched:** `billing.lisp` (webhook + checkout), `chef.lisp` (Gemini
call), `stripe.lisp`.

- Introduce a minimal `(defstruct (result (:constructor ok (value)))
  value)` / `(defstruct (failure (:constructor err (reason))) reason)` pair
  (or a tagged `(cons :ok value)` / `(cons :error reason)` if a full struct
  is overkill) used by `roast-code-with-gemini`, `create-stripe-checkout-session`,
  and the webhook command interpreter from Phase 2.
- Handlers interpret the `RESULT`/`FAILURE` value at the shell boundary
  (mutate `return-code*`, pick the right error string) — the pure/impure
  split becomes: *pure code computes an outcome value; only the handler
  performs the HTTP-visible side effect of reporting it.*
- **Payoff:** `stripe-webhook-handler`'s `HANDLER-CASE`-wrapped cascade of
  five DB mutations becomes: compute a list of typed commands (Phase 2),
  execute them, collect any resulting `FAILURE`s, report once — testable end
  to end by mocking the command-execution step.

### Phase 7 — Lean on `SERIES`/`FOLD` for sequence-shaped logic
**Files touched:** `db-auth.lisp`, `admin.lisp`, `stripe.lisp`.

- `admin-members-page`'s pagination math (`offset`, `total-pages`,
  `has-prev`/`has-next`) and `random-string`'s character-by-character
  `SETF` loop are natural, low-risk candidates for `SERIES`-based rewrites
  once the surrounding data is already immutable (Phases 1 and 5).
- `generate-recovery-codes`'s `LOOP REPEAT 10 COLLECT ...` and the
  `dolist`-based Stripe tier-plan initialization in `init-stripe-product`
  are good `FOLD`/`SERIES` candidates once Phase 4 makes the underlying
  state immutable.
- Treat this phase as *opportunistic polish*, not a hard requirement — the
  goal is internal consistency with the project's declared dependencies, not
  a mandate to force every loop into `SERIES` syntax.

### Phase 8 — Test suite rebalancing
**Files touched:** `tests/tests.lisp`.

- Once Phases 1-6 land, add a large batch of **pure unit tests** requiring no
  Postgres/Stripe/Hunchentoot: `row->user`, `tier-meets-minimum-p`,
  `dashboard-view-model`, `webhook-event->db-commands`, `render-dashboard`,
  `catalog-with-tier`, the CSRF/tier middleware combinators.
- Keep the existing live-Postgres tests (`recovery-code-verification`,
  `stripe-database-and-routes`, `user-membership-tiers`) as the *thin*
  integration-test layer that only needs to verify the imperative shell
  correctly wires pure functions to real I/O — their scope should shrink
  over time as more logic moves into directly-tested pure functions.
- **Payoff:** CI/local runs that don't have Postgres available can still
  exercise the majority of the codebase's actual logic; the live-DB tests
  become a smaller, more focused confirmation layer instead of the primary
  way anything gets tested.

---

## 5. Sequencing & Risk Notes

- Phases are ordered by **increasing dependency on prior phases**, not by
  file. Do not skip Phase 1 — every later phase assumes `USER` (and later
  `STRIPE-CATALOG`) structs exist, so alist-accessor call sites should be
  fully migrated before Phase 2 work begins on the same files.
- Each phase should land as its own commit/PR with `(asdf:test-system
  :jrm-code-project)` green before and after — this plan is explicitly
  incremental so the app is deployable after every single phase.
- No phase changes an HTTP-visible behavior (routes, redirects, cookie
  names/lifetimes, CSRF exemption list, the `next` breadcrumb contract, or
  JWT-missing-redirects-to-`/` semantics) — those are refactors of
  *implementation*, not of *behavior*. Any phase whose diff would change
  observable behavior should be split so the behavior change is its own,
  separately-reviewed commit.
- `ses.lisp`'s hand-rolled SMTP client is explicitly out of scope (§3) —
  it's a sequential protocol state machine talking to a raw socket, not a
  data-transformation pipeline, and forcing it into this plan's shape would
  fight the grain of what it actually is.

---

## 6. Definition of Done

The refactor is "complete" (per phase, and overall) when:

1. No handler function directly calls Postmodern, Stripe's HTTP API, or
   builds a final HTML response string in the same function body that also
   makes the authorization/business decision — each of those three concerns
   is a separately named, separately testable function.
2. No `(cdr (assoc :keyword row))` pattern remains outside the Phase-1
   `row->*` converter functions.
3. Every cross-cutting concern (CSRF, session auth, JWT tier-gating,
   wheel-gating) is expressed as a composable function over a handler, with
   exactly one implementation per concern (no duplicated
   `require-session-wheel`-style reimplementations).
4. Stripe's in-memory catalog is one immutable value with one owning
   global, not four independently-mutated globals.
5. A newly-added contributor can run the pure-function unit tests (Phase 8)
   with zero external services configured and still exercise the majority of
   the application's actual decision logic.

As you can see, this is a very detailed and serious plan. Come to think about it, I should have done the functional refactor sooner so that it would not have needed such an extensive plan.

Once the plan is written, I prompt the LLM to implement each phase of the plan in turn. The prompt is straightforward: Read FUNCTIONAL_REFACTORING.md and implement the next phase of the Incremental Migration plan. I use this prompt over and over until all the phases have been implemented. I monitor the progress of the LLM to make sure it is not getting lost in the weeds.

Functional refactoring is expensive. It chews through a ton of tokens, and it may seem like a waste because if it is done correctly, the code will behave exactly the same as it did before the refactoring. I have done a functional refactoring on most of my vibe coding projects and I have been pleased with the results. The generated code is surprisingly good, and subsequent `vibing` seems to be quite easy for the LLM.

Once the functional refactoring is complete, the LLM will tend to write future code in a more functional style. It is a pattern matcher, so if it sees functional patterns, it will tend to mimic them. But imperative code will creep back in over time because the LLM is so heavily trained on imperative code. I have found that occasionally prompting the LLM to refactor the code to be more functional is useful. Subsequent functional refactorings are much easier than the first functional refactoring because the core code is already functional and large refactorings are not needed.

If you are not a functional programmer, I expect that you will find this to be a massive waste of time with a lot of code churn. But if you are a functional programmer, I bet you'll be pleased with the results - I have been.

08:14

Blooming Differences by Cloud [Oh Joy Sex Toy]

Blooming Differences by Cloud

What happens when an eager Bunny meets a nervous Minotaur? Squeeze on in and find out, in todays wonderful comic by Cloud! Communication, lube, and a lovely warmup all rendered beautifully. I’m so excited to finally share this comic, it’s just wonderful. We hope you like it too! Our Fierce Differences (webcomic) Patreon Bluesky After […]

03:56

Some Pokemon Art! [Penny Arcade]

I have been spending a few hours each weekend working with traditional tools. My family started requesting Pokemon and I’ve been sharing some of my progress over on my BlueSky. I know not everyone is on social media these days so I’m sharing here:

03:35

Comparing the two holograms on the Windows 95 box [The Old New Thing]

I noted some time ago that the Windows 95 anti-piracy hologram had to be redone at the last moment due to a complaint from a government (who remains nameless). They objected to the depiction of naked children on the box, referring to the anti-piracy hologram in which the baby is not wearing a shirt. Since the baby is depicted only from the waist up, they extrapolated that the baby wasn’t wearing pants.

There was a scramble to produce a new hologram, and just to be safe, in the new hologram the baby is wearing a shirt and overalls.

You can find pictures of the “clothed baby” Windows 95 hologram fairly easily, such as one appearing about halfway through Steve Sinofsky’s story about getting Office 95 to pass the “Designed for Windows 95” requirements

Harder to find is the original “topless baby” Windows 95 hologram, but recently, I stumbled across a link to a short clip of the original hologram, that shows off the animation.

So now you can see what that unnamed government was upset about.

Windows 95 was released to the public 31 years ago today.

Bonus chatter: Windows NT 4.0 was released to the public 30 years ago today. And Windows XP was released to manufacturing 25 years ago today. I don’t know why things happen on August 24ths.

¹ I find it interesting that the Office team was frustrated at the “Designed for Windows 95” certification process, feeling that the certification team was singling them out more harshly. So much for the conspiracy theories that Office was given favorable treatment. It seems that they were given more stringent treatment.

The post Comparing the two holograms on the Windows 95 box appeared first on The Old New Thing.

00:21

Humble Bundle and Gamers Outreach [Humble Bundle Blog]

This past January, Humble Bundle dedicated 5% of Humble Choice membership subscriptions to Gamers Outreach, a charity that empowers hospitalized families through play. This donation has significantly supported families and children in healthcare facilities across the U.S. by funding the distribution of portable “GO Karts” in 17 states. Through this humble donation, many of the healthcare facilities that have received the GO Karts are receiving …

The post Humble Bundle and Gamers Outreach appeared first on Humble Bundle Blog.

Monday, 24 August

23:14

Pluralistic: How Canada can help Americans and defeat America (23 Aug 2026) [Pluralistic: Daily links from Cory Doctorow]

->->->->->->->->->->->->->->->->->->->->->->->->->->->->-> Top Sources: None -->

Today's links

  • How Canada can save Americans and defeat America: True Carneyism has never been tried.
  • Hey look at this: Delights to delectate.
  • Object permanence: Brazil v AIDS drug patents; TSA v gel-bras; After the Siege (Russian); Names are hard; Layton's last message; Hospital bill secrets; "The Unraveling"; Friction cannot be reduced, only redistributed; Free Kevin; EFF v Barney; MP3tunes; "Ghosts With Shit jobs"; Ikea as dystopian design-fiction; Torturing "young conservatives"; Roald Dahl body yeast ale; Prisoners die of heat; Privacy v antitrust; The internet is boring (2001); TSA v explosive water; Internet Archive x 9/11; Peter Thiel x litigation financing startup; Universities v unions.
  • Upcoming appearances: Sydney, Melbourne, Brighton, London, South Bend.
  • Recent appearances: Where I've been.
  • Latest books: You keep readin' em, I'll keep writin' 'em.
  • Upcoming books: Like I said, I'll keep writin' 'em.
  • Colophon: All the rest.



A Canadian flag, its elements replaced with circuit boards. In the foreground, a bent-double, exhausted Uncle Sam trudges over rocky terrain, shlepping a giant sack on his back. Centered in the maple leaf is the word SORRY.

How Canada can save Americans and defeat America (permalink)

As Canada is learning (the hard way), the "art" of all of Trump's deals can be summed up in a single word: "renege":

https://pluralistic.net/2026/07/22/table-flipper/#graveyard-of-indispensable-nations

In 2020, Donald Trump ripped up NAFTA, a trade deal that conferred a huge advantage to the USA at Canada's expense, and replaced it with CUSMA, a trade deal that was even more advantageous to America, and even worse for Canada. In 2024, after being elected for the second time, Trump publicly railed against CUSMA using the exact same language he'd used to decry NAFTA, branding it "a very bad deal" that needed to be shredded and renegotiated.

To that end, Trump declared sweeping tariffs on Canada's exports, thereby raising the costs Americans paid for many everyday goods, because while Canada does not ship a lot of finished products to the US, it is a key supplier of parts and materials, all of which were made instantly more expensive thanks to the Trump tariffs. Trump went on to insist that Canada should annex itself to the US, becoming the "51st State." His operatives openly meddled in Canadian separatist movements, backing the "Wexit" partisans who want to separate the oil-rich, boom/bust-plagued province of Alberta from Canada.

CUSMA was negotiated by Justin Trudeau's government, and Trump II's tariff war landed on Trudeau's successor, Canadian Prime Minister Mark Carney, billed as a technocratic safe pair of hands who could be relied upon for sober, effective leadership.

Much to everyone's surprise, Carney – the epitome of a "Davos Man" – responded to the Trump tariffs by traveling to Davos and giving a fiery speech denouncing Trump and declaring a "rupture" that left the old world order dead:

https://www.weforum.org/stories/forum-institutional/davos-2026-special-address-by-mark-carney-prime-minister-of-canada/

Carney promised that Canada would go "elbows up" against America, with retaliatory tariffs, blockades and boycotts of key US exports. Cutting off this stream of goods would have the same effect on Canadians that Trump's tariffs had on Americans: raising prices. Unlike their American cousins, Canadians were far more tolerant of this increase in their cost of living, because, unlike Americans, Canadians believed the narrative that they were sacrificing for the good of their country against an existential threat from a fractious neighbour. Americans were far less willing to believe that Canada was somehow cheating the US or flooding the country with fentanyl.

"Elbows up" is largely a war of symbols, in which Canadians take pride in mastering the minute differences between "Product of Canada," "Made in Canada," "Assembled in Canada," and "Designed in Canada" so they can seek out maximal Canadianness in their consumption choices. There's even a kind of twisted honour in committing yourself to drinking Wayne Gretzky's shitty rye in preference to delicious American bourbon, a way to affirm your love of country with each astringent, metallic swallow.

When the trade war was confined to symbolic terrain, Carney's elbows remained reliably elevated. But outside the realm of symbols, Carney's elbows wilted.

Take the Digital Services tax, a plan to charge America's tax-evading tech giants a 3% levy to make up for the untaxed profits they keep by pretending to be Irish. So long as Trump's tech giants can dodge their tax obligations, they can always outcompete Canada's tech sector, who are expected to pay 38% federal and provincial tax.

American tech companies are closely allied with the Trump regime: they financed his campaign, conduct domestic and international surveillance for him, provide the software to administer his ethnic cleansing, and restrict access to software that helps Americans evade the armed secret police he sent into the streets to kidnap and disappear his enemies:

https://pluralistic.net/2025/10/06/rogue-capitalism/#orphaned-syrian-refugees-need-not-apply

Trump repaid his tech giants by threatening Carney with still more tariffs unless he canceled the Digital Service Act, and Carney capitulated. Meanwhile, Carney raced to enact a plan to fire tens of thousands of civil servants and replace them with AI chatbots running American software on American chips:

https://www.pm.gc.ca/en/news/news-releases/2026/06/04/prime-minister-carney-launches-ai-all-canadas-new-national-artificial

Canada's federal and provincial ministries are all entirely dependent on American cloud software, most notably Microsoft's Office 365, a package that Trump has fashioned into a geopolitical weapon, ordering Microsoft to shut down foreign officials who thwarted his plans, denying them access to all their data and cutting off their ability to communicate with the outside world:

https://apnews.com/article/icc-trump-sanctions-karim-khan-court-a4b4c02751ab84c09718b1b95cbd5db3

In other words, Canada is already terribly vulnerable to American cyberwarfare. Trump's tech companies don't have to hack into Canada's digital infrastructure to shut it down: they already control it. But – incredibly – Carney found a way to make this situation even worse, turning over key aspects of the digital back-end of Canada's military to Palantir, the tech company most closely aligned with Trump, whose CEO openly boasts that his company was founded to kill America's political enemies:

https://thedeepdive.ca/canada-military-palantir-license-deal/

Carney's symbolic gestures – memorable speeches and minor changes to consumption habits – are second to none. But when it comes to building a strong country that is resilient against the attacks we can all foresee (not least because Trump has repeatedly told us he intends to launch them), Carney himself becomes Carneyism's fiercest opponent:

https://pluralistic.net/2026/05/30/rupture/#deeds-not-words

It's not just the attacks that are foreseeable, alas. Trump can always be relied upon – to break his word. Carney repeatedly caved to Trump, and in response, Trump has hit Canada with massive new tariffs – 50%! Remember: the "art" of every Trump deal is renege:

https://www.pbs.org/newshour/economy/what-to-know-about-trumps-50-tariffs-on-canadian-goods-that-just-went-into-effect

Trump can also be relied upon to circle back to his fixations and obsessions. Decades ago, someone showed Trump a Mercator projection map of the Earth and he became obsessed with "yuge" Greenland, to the point where he is prepared to dissolve Nato and go to war with Europe to steal it from Denmark:

https://archive.is/3Q8nj

By the same token, Trump has long been publicly obsessed with the Gilded Age president William McKinley, who enacted sweeping tariffs at a time when the US economy was rapidly growing, a fact that lodged in Trump's brain and led him to believe that tariffs are a surefire growth-hack that will let him eliminate taxes on the wealthy without shutting down the country:

https://edition.cnn.com/2025/02/12/business/trump-william-mckinley-tariffs/

Trump will still be obsessing about these idées fixes when he draws his last breath, gasping out "Greenland…tariffs" as he tumbles from his golden toilet, forehead and coronary arteries bulging from the strain of trying to pass a half-digested Big Mac with only a viscous paste of rectal mucus and Diet Coke to lubricate that final, unyielding bolus.

The fact that Trump is immune to learning from his mistakes (because that would require admitting that he made a mistake) does not bind Canada to do the same. Quite the contrary: Trump's inability to learn or reason means that if Canada engages in novel retaliatory tactics, it stands a good chance of flummoxing the Mad King, leaving him flat-footed and lumbering while it dekes him out and swarms past him.

Lucky for Canada, Trump's incontinent belligerence has opened up a large and diverse territory of novel tactics for conducting both geopolitical and economic policy. As November Kelly says, "Trump inherited a poker game rigged in his favour but he flipped over the table anyway because he resents having to pretend to play." The systems that Trump has dismantled as unfair to the US were, in fact, sources of tremendous advantage to America.

Take those tech companies that have fused so tightly with the Trump regime. These companies operate global monopolies that allow them to extract vast sums and even vaster troves of sensitive data from billions of people around the world. Having attained total economic dominance and total technical lock-in, these companies have embarked on a program of enshittification, squeezing their customers and suppliers for even more data and even more money:

https://us.macmillan.com/books/9780374619329/enshittification/

Under normal market conditions, the decay of these American platforms would invite competitors from around the world. The fact that Apple and Google extract 30% of every dollar spent in their app stores would bring forth new app stores who were willing to give better deals to app makers and app users. The fact that HP charges $10,000/gallon for the coloured water in its printers would invite competitors who were willing to take a mere 100,000% margin on ink.

The fact that Meta and Google and Microsoft and Apple spy on you with your devices and software and use that data to target you, manipulate you and overcharge you – and to train their AIs to steal from you even more efficiently – would create demand for privacy blockers, jailbreakers, and other "adversarial interoperability" tools that force your technology to work for you, even if the manufacturer wishes it were otherwise:

https://pluralistic.net/2025/11/01/redistribution-vs-predistribution/#elbows-up-eurostack

But we don't have "normal market conditions." For more than a quarter of a century, the US Trade Representative has demanded that all of America's trading partners – including Canada – enact "anti-circumvention" laws that make it a crime to alter how a digital device works unless the original (usually American) manufacturer consents.

In other words, it's illegal for some Waterloo grads to tap ambitious RIM millionaires for the seed capital to start a company that helps Canadians install Canadian app stores on their Canadian phones so when they buy things from other Canadians, all the money stays in Canada, without a 30% "app tax" being siphoned off by either Google or Apple.

That's right: in 2012, Canada passed a law that lets American companies use Canada's courts to destroy Canadian companies that help Canadian technology users get more out of their own property. This law – the Copyright Modernization Act – was wildly unpopular from the start. A federal consultation drew over 6,000 opposing comments, and only 53 comments in support of the bill. But Prime Minister Stephen Harper whipped the vote among his Conservative MPs and passed it, because he judged that tariff-free access to America's markets to be a price worth paying:

https://pluralistic.net/2024/11/15/radical-extremists/#sex-pest

Trump's tariffs prove that this was a bad bargain. By voluntarily gluing its technological elbows to its sides, Canada made itself easy pickings for America's tech giants, who wiped out Canada's tech sector while making Canada geopolitically and economically dependent on – and vulnerable to – the US and its tech companies. Canada is long overdue for a reckoning with this blunder.

The best time to have made Canada digitally sovereign would have been before an American president announced his intention to annex Canada and began explicitly deploying America's tech companies to attack his geopolitical adversaries.

The second-best time is now.

By repealing Bill C-11 and legalizing reverse-engineering and modification of digital technology with consent of its users and in accordance with privacy, consumer and labour rights, Canada will gain a devastating counter to Trump's tariffs.

Not only will legalizing jailbreaking let Canadians get more out of their own property, it will turn America's tech trillions into Canada's tech billions – while making Canada digitally sovereign by facilitating the uncoupling of Canadian ministries, corporations, households, and devices from America's cloud. This is how Canada removes the digital kill switch it handed to America, a kill switch that can shut down its tractors, phones, and governments.

This is the best possible moment for such a move. To incubate a successful tech sector, you need a) an innovative product; b) skilled technologists; and c) capital. Thanks to Trump, Canada has all three.

First: innovative ideas. Thanks to the prohibition on modifying America's defective tech exports, there is a whole orchard of low-hanging fruit for product designers to pick from: an app that aggregates all of your streaming services into one place and lets you record shows to watch later, even if the service deletes them; reliable tools for using generic ink and independent app stores; new firmware for tractors and cars that facilitates independent repair and unlock subscription features, and, of course, privacy- and ad-blockers of all description. These are truly disruptive products, striking at the maddening antifeatures installed at the insistence of sclerotic, extractive tech bosses. Move fast and break their things!

Next: talent. Who will do that fast moving? Again, we can thank Trump for giving Canada an army of skilled technologists who have fled Silicon Valley one step ahead of an ICE chud who wanted to black-bag them and deport them to Liberia (or a Salvadoran slave-labor camp). Trump is creating the largest wave of reverse brain-drain in history, as everyone ambitious and smart realizes that their lifelong US tech work dream is a nightmare. If Canada can't get enough talent to harvest that orchard of low-hanging fruit from its returning Canadians, it need only open its borders to the skilled technologists of all nations who are racing out of America as fast as they can go.

Finally, money. The AI bubble collapse is imminent. The forces of capital are desperate for promising, high-return investment opportunities that aren't grossly overvalued, overhyped and underperforming AI companies. Even if you can find a company like that in America, it's increasingly apparent that to make that business a success, you will need to buy more $TRUMP coins than your rivals, lest Trump direct his agencies to destroy your fledgling business.

And here's the kicker: turning America's trillions into Canada's billions, moving fast and breaking America's tech-kings, fixing the defects in America's extractive tech exports? It's all good for Americans. Sure, cratering the share-price of America's Big Tech companies will be bad for America's retirement savers, but the median American worker only has $955 saved for retirement:

https://finance.yahoo.com/news/955-saved-for-retirement-millions-are-in-that-boat-150003868.html

Most Americans are far more exposed to the predatory conduct of US tech companies than they are to the share price of those companies. That's because Americans are the beta-testers for every ripoff and surveillance tool that Silicon Valley produces. Long before those tools get to Canada or find their way around the world, they are making Americans poorer and worse off.

Remember: Canada is America's second largest trading partner. Americans are really good at buying things from Canada – even when those things aren't allowed in America. Trump wasn't entirely wrong when he accused Canada of flooding America with drugs – but the drugs Canada sends to America aren't fentanyl and oxy. Canada sends America insulin and other cheap pharmaceuticals that cost 10-100x more in Ripoff America than they do in Canada. If Americans can figure out how to buy cheap generic meds from Canadians over the US Postal Service, they will be able to buy disenshittification tools from Canadians over the internet.

Selling Americans products that make their lives better is much better politics than boycotting American products that make Canadians' lives better. No politician can pursue a strategy of higher prices and lower living standards forever – not even if you've got a lot of "elbows up" rhetoric you can use to convince Canadians that they're doing their duty to the nation by paying more for everything. Paying more for everything to punish Americans is like punching yourself in the face as hard as you can and hoping the downstairs neighbours say "ouch."

When Canadians swap delicious American bourbon for Wayne Gretzky's shitty rye, they punish corn farmers in states that begin and end with a vowel – farmers who have nothing to do with Canada's problems. By swapping disenshittification for tariffs, Canadians can go back to drinking delicious bourbon, and make money from that farmer by selling him the jailbreaks he needs to fix his tractor without paying the John Deere tax of $200+ that the company charges after you do your own repair to send someone to the farm to type an unlock code into your console.

A lot of Very Serious Grown Up Canadians have told me that they think Carney should confine his response to Trump to toothless symbolic gestures, lest they make Trump mad. Trump is always mad. He gets mad at symbolic gestures. He gets mad if you point out that Ronald Reagan thought tariffs were stupid:

https://abcnews.com/Politics/trump-raises-tariffs-canada-10-after-reagan-ad/story?id=126866712

Freeing Americans from the tyranny of their own tech companies has the power to create a partisan army of American Canada weebs who will fight for Canada when – not if – Trump gets mad at Canada. That's the best defense Canada can have – common cause and solidarity with the people of America, who share a common enemy in Trump, the least popular president in history, who is looting billions and letting his cronies destroy Americas' lives.

That's some real elbows up stuff. True Carneyism has never been tried – especially by Carney. It's long past time someone gave it a go.


Hey look at this (permalink)



A shelf of leatherbound history books with a gilt-stamped series title, 'The World's Famous Events.'

Object permanence (permalink)

#25yrsago Kevin Mitnick is out of prison https://web.archive.org/web/20010000000000*/https://www.techtv.com/screensavers/showtell/story/0,23008,3343816,00.html

#25yrsago Brazil to nationalize AIDS drug patents https://edition.cnn.com/2001/WORLD/americas/08/22/aids.drug/index.html

#25yrsago Copyright your DNA https://web.archive.org/web/20010827170510/http://www.cosmiverse.com/science08230102.html

#25yrsago The internet is boring now https://www.nytimes.com/2001/08/26/us/exploration-of-world-wide-web-tilts-from-eclectic-to-mudane.html

#20yrsago TSA busts “explosive water” that turns out to be cosmetics https://web.archive.org/web/20060822123448/http://www.kxma.com/getARticle.asp?ArticleId=35223

#20yrsago Windows Media DRM cracked, no one cares https://archive.blogs.harvard.edu/cmusings/2006/08/25/#a1889

#20yrsago Canadian music label puts fans and artists first https://web.archive.org/web/20060830211418/http://wired.com/wired/archive/14.09/nettwerk_pr.html

#20yrsago After the Siege in Russian https://craphound.com/Cory_Doctorow_-_After_the_Siege_Russian.html

#20yrsago Victory in War on Moisture: Gel-bras once again safe! https://web.archive.org/web/20060820185006/http://www.tsa.gov/travelers/airtravel/prohibited/permitted-prohibited-items.shtm

#20yrsago EFF sues Barney the humorless, copyright maximalist dinosaur https://web.archive.org/web/20060813093642/http://www.eff.org/news/archives/2006_08.php#004884

#15yrsago MP3tunes verdict: music lockers are legal https://www.eff.org/deeplinks/2011/08/mp3tunes-victory-music-lockers-is-good

#15yrsago Lolita on Wikipedia: 2,300 edits later https://web.archive.org/web/20111008072145/http://www.theawl.com/2011/08/case-history-of-a-wikipedia-page-nabokov’s-lolita

#15yrsago SF mockumentary: ‘Ghosts With Shit Jobs’ — China looks at westerners with awful jobs https://ghostswithshitjobs.com/

#15yrsago Information consumes attention: focus in the age of abundant stimulus https://web.archive.org/web/20111113004501/http://nymag.com/print/?/news/features/56793/

#15yrsago Jack Layton’s final public words: “Love is better than anger. Hope is better than fear.” https://web.archive.org/web/20110829050308/http://beta.images.theglobeandmail.com/archive/01310/Jack_Layton_s_lett_1310744a.pdf

#15yrsago Getting people’s names right in software design: a LOT harder than it looks https://www.antipope.org/charlie/blog-static/2011/08/why-im-not-on-google-plus.html

#15yrsago Internet Archive’s cache of 24/7 TV footage from 9/11 and beyond https://archive.org/details/911

#10yrsago Peter Thiel & Y Combinator fund a “litigation financing” startup to make money off other peoples’ lawsuits https://gizmodo.com/a-startup-backed-by-peter-thiel-makes-bankrolling-civil-1785707590

#10yrsago Universities fought unionization’s ‘one-size-fits-all’ using identical arguments https://crookedtimber.org/2016/08/25/great-minds-think-alike/

#10yrsago 5 years after Texas GOP’s attack on women’s reproductive health, TX leads developed world in maternal mortality https://web.archive.org/web/20160820212602/https://www.theguardian.com/us-news/2016/aug/20/texas-maternal-mortality-rate-health-clinics-funding

#10yrsago You didn’t find a meteorite https://sites.wustl.edu/meteoritesite/

#10yrsago Young Conservatives’ “leadership seminar” featured food & water deprivation, sexist epithets, physical abuse https://web.archive.org/web/20160824145226/https://www.thestar.com/news/queenspark/2016/08/23/ontario-tories-apologize-to-party-activists-after-controversial-youth-seminar.html

#10yrsago The 2017 Ikea Catalog considered as dystopian urban microapartment futurism https://web.archive.org/web/20160817154440/https://www.fastcodesign.com/3062854/ikeas-2017-catalog-is-a-terrifying-glimpse-into-the-tiny-apartments-of-the-future

#10yrsago Singapore will disconnect entire civil service from the internet https://www.theguardian.com/technology/2016/aug/24/singapore-to-cut-off-public-servants-from-the-internet

#10yrsago They’re making a Twits ale from Roald Dahl’s body-yeast https://web.archive.org/web/20160817154531/http://www.independent.co.uk/arts-entertainment/books/news/beer-to-be-made-from-yeast-swabbed-from-roald-dahls-writing-chair-a7195721.html

#10yrsago As America’s temperatures soar, prisoners are dropping dead https://web.archive.org/web/20160825000426/https://theintercept.com/2016/08/24/deadly-heat-in-u-s-prisons-is-killing-inmates-and-spawning-lawsuits/

#5yrsago Are privacy and antitrust on a collision course? https://pluralistic.net/2021/08/24/illegitimate-greatness/#peanut-butter-in-my-antitrust

#5yrsago What kind of emergency is our emergency? https://pluralistic.net/2021/08/23/dont-wanna-spoil-the-surprise/#monocausotaxophilia

#5yrsago The secrets of hospital bills https://pluralistic.net/2021/08/23/dont-wanna-spoil-the-surprise/#surprise

#5yrsago Belarusian dictator pwned by "cyber-partisans" https://pluralistic.net/2021/08/25/taxes-are-for-the-little-stores/#cyber-partisans

#5yrsago Big Box stores' other shoe drops https://pluralistic.net/2021/08/25/taxes-are-for-the-little-stores/#metastatic-parasites

#5yrsago The Unraveling https://pluralistic.net/2021/08/23/dont-wanna-spoil-the-surprise/#the-two-genders

#1yrago Friction cannot be reduced, it can only be redistributed https://pluralistic.net/2025/08/23/become-unoptimizable/#downward-redistribution


Upcoming appearances (permalink)

A photo of me onstage, giving a speech, pounding the podium.



A screenshot of me at my desk, doing a livecast.

Recent appearances (permalink)



A grid of my books with Will Stahle covers..

Latest books (permalink)



A cardboard book box with the Macmillan logo.

Upcoming books (permalink)

  • "The Post-American Internet," a geopolitical sequel of sorts to Enshittification, Farrar, Straus and Giroux, 2027
  • "Unauthorized Bread": a middle-grades graphic novel adapted from my novella about refugees, toasters and DRM, FirstSecond, April 20, 2027

  • "Enshittification, Why Everything Suddenly Got Worse and What to Do About It" (the graphic novel), Firstsecond, 2027

  • "The Memex Method," Farrar, Straus, Giroux, 2027



Colophon (permalink)

Today's top sources:

Currently writing:

  • “Once Is Enemy Action,” a science fiction novel about the origins of modern technofascism. Today's words: 557 (9258 total).

  • "The Post-American Internet," a sequel to "Enshittification," about the better world the rest of us get to have now that Trump has torched America. Fourth draft completed. Submitted to editor.

  • A Little Brother short story about DIY insulin PLANNING


This work – excluding any serialized fiction – is licensed under a Creative Commons Attribution 4.0 license. That means you can use it any way you like, including commercially, provided that you attribute it to me, Cory Doctorow, and include a link to pluralistic.net.

https://creativecommons.org/licenses/by/4.0/

Quotations and images are not included in this license; they are included either under a limitation or exception to copyright, or on the basis of a separate license. Please exercise caution.


How to get Pluralistic:

Blog (no ads, tracking, or data-collection):

Pluralistic.net

Newsletter (no ads, tracking, or data-collection):

https://pluralistic.net/plura-list

Mastodon (no ads, tracking, or data-collection):

https://mamot.fr/@pluralistic

Bluesky (no ads, possible tracking and data-collection):

https://bsky.app/profile/doctorow.pluralistic.net

Medium (no ads, paywalled):

https://doctorow.medium.com/

Tumblr (mass-scale, unrestricted, third-party surveillance and advertising):

https://mostlysignssomeportents.tumblr.com/tagged/pluralistic

"When life gives you SARS, you make sarsaparilla" -Joey "Accordion Guy" DeVilla

READ CAREFULLY: By reading this, you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies ("BOGUS AGREEMENTS") that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

ISSN: 3066-764X

22:56

Matthias Klumpp: Sovereign Tech Fellowship for Freedesktop Tasks [Planet Debian]

In 2025 I was honored to be selected for the first cohort of Sovereign Tech Fellows, a program by Germany’s Sovereign Tech Agency to improve the resilience of the open source ecosystem by supporting maintainers directly (complementing their existing support for larger FOSS organizations). Back in 2025, I was only working very limited hours – however, this has changed in 2026.

For the second half of 2026, I am working again as a Sovereign Tech Fellow, but this time with significantly increased hours. After finishing my PhD, I do have time now for new tasks (and new jobs!), and the fellowship presents an amazing opportunity to really advance projects that I maintain or am part of. This also has a very nice effect on contributors and bug reporters, as their feedback gets addressed a lot faster. With some luck, this ultimately will help finding new (co)maintainers for projects as well (although in the age of AI, a lot of how open source used to work is much more uncertain, but that is a matter for a different blog post).

The fellowship is time-limited, so I am intending to make the time I currently have count!

So, what’s planned?

I am involved in many projects, but three of them will be getting attention as part of the fellowship. I know I am notoriously slow at blogging, but expect more details on each of them very soon. Here’s an overview:

Freedesktop.org, Specifications and Organization

I maintain the Freedesktop Specifications, which is an area of Freedesktop that has traditionally been a bit chaotic. This “worked” in the past, because Freedesktop was never intended to be a formal standards body, but more a shared space where people could throw a lot of code and ideas over the wall and see what sticks and what people can collaborate on.

While I very much love the spirit of this and want to keep it in some form, we definitely would benefit not just from more formalization and better procedures, but also from better organization of the specifications in general. A lot of conflicts can be avoided by that. I will work on improving procedures, crunching through the (lots!) of pending bug reports and MRs, and to make the specifications site better searchable and accessible (similar to how Mozilla’s MDN presents information, but I am not sure if we will get quite that far). I also intent to add a compatibility matrix for specifications, so if a desktop opts out of any one of them (or does not implement them yet) that fact is documented and authors of applications know what they can expect. This will allow us to move a lot faster and avoid a lot of conflict, because there is no implicit assumption that “everybody will implement everything” anymore (which has never been quite true anyway).

Hopefully, this will ultimately result in a Freedesktop that is both a lot more useful for application authors who want to bring their project to Linux, as well as developers of desktop environments who need to see which specifications are available and which ones are current.

In addition to that, I have also worked on a Freedesktop.org website refresh, which is pretty much done in its first iteration (pending sysadmin action). The aim there is to have a more official website, separate from user-contributed wiki content, that showcases what Freedesktop is and which projects are using it for hosting. Once the new website is live, I will also review every page again, archive dead projects in their own section and reorganize the software and specifications directory. Those sections are severely outdated and are missing recent efforts from the community, while still containing long-dead old projects (remember HAL? 😉).

AppStream

A lot of extra maintenance work will be (has been!) done on it. This includes things such as JPEG-XL support (blog post soon), sandboxed media processing, support for newer specification additions, better OARS integration (and potentially migrating it to fd.o infrastructure), improvements and API stabilization for libappstream-compose and a lot of bugfixing and resolution of issues found by AI code review.

AppStream was originally designed to parse only trusted data from vetted Linux distribution sources – this is no longer the case in today’s world and in the way Flatpak uses it, so we need to increase resilience of the project.

I am also exploring a project that could vastly improve search accuracy for AppStream. Stay tuned for that.

PackageKit & System Upgrades

Many years ago, people thought we would all migrate to atomic Linux distributions and slowly not need PackageKit anymore. This has not turned out to be the case, and there are still plenty of reasons to use a package-based OS, especially in development environments. At the same time, PackageKit has been basically the same for years, and its older architecture is beginning to show. It being a daemon who’s literal job it is to modify the entire system also makes it one of the most security-sensitive components that a Linux system can have, while simultaneously making it near-impossible to sandbox.

My plan is to create PackageKit 2.0 by building on the great foundation of PackageKit 1.0, but modernizing it. This will include simplifying its code and removing a bunch of features that have no more use in modern desktops, while also adding some features that PackageKit never had but that would be useful to expose to frontends (still no to interactivity an terminal-progress forwarding though!). PK 2.0 will also allow me to solve a few design issues that have been worked around in the past, by replacing them with better solutions. This will be a painful transition, as PackageKit 2.0 will break all interfaces PackageKit has – and those interfaces have been frozen for more than a decade. However, I do fully expect this change to be worth the effort.

In addition to that, I intend to look into the offline-update procedure again and improve it. The current multi-reboot operation comes with downsides, that newer systemd features such as soft-reboot can alleviate. The end result should be a much smoother, less annoying offline-update experience for users (I especially want to get rid of updates running on system startup, which I consider quite bad from a usability perspective). The new behavior is in the early drafting stages and may need direct support from systemd. I will share more about it once I can.

That’s a lot of tasks!

Yes! I will see how far I get. I am moving project-by-project though, to allow me to focus on one project at a time, rather than scattering my attention continuously. Amazingly, this means that the major tasks for AppStream are already almost done, and we are nearing the 1.2.0 release. AppStream got priority, because the new Freedesktop Flatpak runtime will be released soon, and because I want FlatHub/Flatpak to have access to the new AppStream release sooner. Freedesktop and PackageKit are next on the task list.

Either way, a lot of progress is coming – if you have any feedback or want to help out, please don’t hesitate to reach out! All work is happening fully in the open, so you can also chime in on the respective GitHub/GitLab tasks 😀.

You can also expect blog posts about key features or interesting changes, so stay tuned! 🙂

21:21

An actively maintained and updated Motif fork actually exists [OSnews]

Motif is great, I love how it looks and feels, and I want it to be actively maintained. I want a healthy ecosystem of Motif applications and even window managers and desktop environments, so I can run a real Motif environment. Sadly, while Motif has been open source for a while, the project itself stalled years ago, with little to no activity from anyone involved. That may be changing, as a number of developers decided to take matters into their own hands last year.

This fork of Motif was born of a desire to keep Motif (and other X11 technologies) alive and well. The original upstream Sourceforge project hasn’t had any activity in over two years, none of the project admins have been active for at least that amount of time, the official bug tracker has disappeared into the void; and the user forum was closed way back in 2017. Sadly, it appears that the original upstream has abandoned the project.

I’ve incorporated some fixes from upstream that have laid dormant for years, a few others from Gentoo, and made a few improvements of my own. I intend to maintain this fork, and in doing so advocate for the continued use of the user interface toolkit that defined an era, and influenced many of the user interfaces that came after it.

↫ Tim Hentenaar at the Motif fork’s GitHub page

Some of the people involved are people I know online, so I have a bit of faith in this fork being able to stand the test of time, but of course, managing a complex project like this is hard, so who knows how long the enthusiasm remains. Still, this fork has seen five releases since its inception a little over a year ago, which seems promising. It may seem weird for some to have a love for Motif, but I’m the kind of person who installs weird, outdated corporate and industrial software I don’t understand on my HP c8000 dual PA-RISC workstation running HP-UX just to enjoy the Motif interfaces they sometimes ship. We all have our quirks.

From my experiences talking to people online, I know there’s actually a rather solid number of people like me, and I hope that at some point the developers in this group can gain enough critical mass to build something like a basic Linux distribution or desktop environment using the disparate, actively-maintained Motif projects out there that yes, still exist. It’s a long shot, but in today’s computing landscape, where more and more people feel uncomfortable with “modern” software, I really feel like there’s a niche for something like this to exist.

A really small niche, surely, but a niche all the same.

AROS gets official Raspberry Pi images [OSnews]

AROS, the open source Amiga OS-compatible operating system, now has images available for the Raspberry Pi 3 (although some people state it also works on the Pi 4), in both 32bit and 64bit versions. According to the AROS team, they are quite stable, but not yet complete, so do know what you’re getting into. Dan Wood posted a YouTube video about these new images, providing much more insight into how well they work if you want more insight into how well they work.

The images are, of course, the basic AROS operating system, so expect a rather barebones experience. If you’re used to some of the AROS distributions for x86, which come loaded with software and customisations, these images will feel quite bare to you. It’s going to take some time to port over all of these applications and customisations to the ARM version of AROS, but if and once that happens, I expect more complete images to appear as well.

Great news for AROS and the Amiga community in general.

20:35

Dirk Eddelbuettel: gaussfacts 0.0.3 on CRAN: Maintenance [Planet Debian]

Gauss

A new release of gaussfacts package arrived on CRAN – the first in pretty much exactly a decade! gaussfacts provides a fortunes-inspired function to display randomly-chosen facts about Carl Friedrich Gauss, based on the collection curated by Mike Cavers via the gaussfacts web site (with an archive.org link it case it vanishes again). Each call of gaussfact() displays another (randomly chosen, or indexed) fact.

An example:

> gaussfacts::gaussfact(9)
Gauss once played himself in a zero-sum game and won $50. 
> 

This releases, as detailed below, accumulates a number of smaller maintenance changes including switching to Authors@R. Functionality has not changed. Oddly enough, it appears that I did not blog about the package when I created it in August 2016. So to (partially) make up for that, the NEWS for all three releases follow.

Changes in version 0.0.3 (2026-08-23)

  • Several rounds of continuous integration maintenance and enhancements

  • Additional README.md badges

  • Updates to DESCRIPTION as CRAN requirements change

  • A duplicate data entry has been removed (Tim Pokart in #4)

  • Documentation prefers https URLs

  • Updated continunous integration multiple times

  • Correct man page removing an erroneous duplicate word

Changes in version 0.0.2 (2016-08-03)

  • Support 'ind' argument to reference by position

  • Clean-up encoding and support extended character set (#2 closes #1)

  • Updated continunous integration (#3)

Changes in version 0.0.1 (2016-06-19)

  • Initial version and CRAN upload

Thanks to my CRANberries, there is a diff to the previous release. Questions, comments etc should go to the GitHub issue tracker off the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

20:14

Data Intelligence: Building Your Competitive Advantage in the Era of AI [Radar]

To keep pace with modern business, data strategy is shifting toward more autonomous real-time systems that deliver intelligence at the moment decisions are made. Driven by agentic AI, modern data teams are moving beyond simply looking at what happened. Now they’re automating complex workflows that analyze what’s happening, anticipate what might happen next, and recommend or take action.

In this article, I’ll define some of the top trends defining this era, from data agents and semantic layers to hybrid data architectures and next-generation data governance.

Putting data agents to work

Data agents are AI-powered software agents that access governed enterprise data and tools to answer questions and perform defined tasks. Instead of navigating reports and filters, a user can now ask, “Why did sales decline last quarter?” and receive an analysis directly. Dashboards remain valuable for monitoring and shared context, while agents handle questions that weren’t anticipated when the dashboard was built. Think of data agents being on different teams, all working together on a specific goal: understanding what’s happening now, predicting what might happen next, and making real-time decisions.

Analytical and organizational agents are designed to help people find trusted information. They can connect to organizational data, answer natural-language questions, analyze patterns, and surface relevant insights without requiring users to manually navigate databases, dashboards, or reports.

Data engineering and governance agents are working hard behind the scenes to prepare, integrate, monitor, and manage the data that powers those insights. Behind the conversational experience, agentic data engineering applies agents to pipeline development and operations: generating transformations, mapping schemas, documenting datasets, monitoring freshness, and suggesting fixes. Agents can automate routine work, while changes to production data contracts, access policies, or business definitions remain reviewable and auditable.

But remember, data agents are only as good as the quality of the data they’re given. Reliable insights and predictions depend on high-quality, well-governed data. They also need context to understand what the data means, making metadata more important than ever.

Metadata quality is the new data quality

Metadata sits at the epicenter of meaning, trust, and discoverability, providing the context that describes and gives meaning to your data. Like a recipe, good metadata brings together several ingredients: clear names and descriptions, shared business definitions, sources and ownership, lineage and relationships, and information about freshness and sensitivity. Leave out too many of those ingredients, and your data agent is left guessing about what the data means and how to use it.

Suppose an agent finds an ARR field showing $5.2 million. The number alone doesn’t tell it how ARR is defined, what’s included in the calculation, which system produced it, or how current it is. Metadata provides that context, helping the agent interpret the metric correctly and explain where the answer came from. Without metadata, $5.2 million is just a number; with it, it becomes meaningful business information.

Good metadata provides essential context, but context alone isn’t enough. Agents also need a consistent way to understand how data connects and how the business defines and calculates the concepts behind it. This is where semantic layers, ontologies, and knowledge graphs come in, turning disconnected data and definitions into a shared map of business meaning and relationships that agents can understand and navigate.

Business context becomes the AI interface

Giving an agent access to data doesn’t mean it understands the business. Semantic models and ontologies or knowledge graphs provide two complementary layers of context that help bridge that gap.

A semantic model provides analytical meaning, defining approved metrics, dimensions, calculations, hierarchies, and relationships. If a sales leader asks, “How did ARR change in EMEA last quarter?” the semantic model can provide the approved ARR calculation, governed EMEA hierarchy, and company fiscal calendar rather than leaving the agent to infer them from raw tables.

Ontologies and knowledge graphs provide entity meaning, helping an agent understand how real-world concepts such as customers, contracts, products, employees, and organizations relate across different systems. For example, the same customer might appear under different identifiers in a CRM, billing platform, and support system; an ontology or knowledge graph can help establish that these records represent the same business entity and define how that entity relates to others.

Together, they give agents both analytical and organizational context: The semantic model helps explain how the business measures something, while ontologies and knowledge graphs help explain what things are and how they relate. That distinction matters because an agent can generate perfectly valid SQL and still deliver the wrong business answer if it chooses the wrong metric, entity, relationship, time period, or level of detail.

Once agents understand what data means, the next challenge is giving them a consistent, controlled way to access and act on it.

Protocol-first data access (MCP and co.)

Organizations are beginning to give AI agents access to governed data and actions through standardized interfaces, reducing the need to build a custom integration for every agent or application. MCP (Model Context Protocol) is one emerging example, allowing compatible AI clients to discover and invoke defined tools. For example, a data platform could expose tools that let an agent find a certified dataset, retrieve a metric definition, inspect a schema, or run an approved query. This makes connecting AI to enterprise data more scalable, but the protocol is only the connection layer; semantics, governance, permissions, and security still need to be designed and enforced separately.

A protocol-first approach can reduce duplicated integration work and create explicit contracts around what agents are allowed to do. It can also make authentication, governance, and observability more consistent across integrations while making it easier to replace or add AI clients and tools without rebuilding every connection from scratch.

Standardizing access makes connection easier, but it also raises a critical question: When an agent acts, whose identity and permissions apply?

Identity passthrough becomes the make-or-break for enterprise AI on data

As AI agents gain access to enterprise data, their permissions need to reflect who or what they are acting for. For user-initiated requests, agents can use delegated access so that existing user permissions continue to apply. Autonomous agents may instead use their own identity, scoped according to the principle of least privilege.

In either case, agents should only be able to access the data and actions required for their task. Identity-aware access helps prevent overexposure of sensitive data while providing the foundation for effective auditing and governance.

When implemented correctly, identity passthrough can preserve existing access controls through the agent layer. But as agents delegate work across tools, services, and other agents, identity can drift or disappear, making it critical to preserve the correct principal and permissions at every handoff.

The access layer is evolving, but so is the underlying data architecture itself.

Open table formats: From storage to catalogs

Open table formats such as Apache Iceberg, Delta Lake, and Apache Hudi are making it easier for multiple engines and tools to work with the same underlying data, reducing dependence on a single data platform. For example, an organization can store data once and make it available to multiple compatible analytics and AI tools rather than maintaining separate copies.

As data becomes more portable, differentiation moves up the stack. The catalog increasingly becomes the control plane for discovering data, tracking lineage, applying governance, and determining how AI systems can access it.

As AI becomes a new consumer of enterprise data, the catalog becomes an increasingly important control point.

Building the foundation for intelligent decisions

Together, these shifts point to a larger transformation: The future of data intelligence depends not only on a single technology but on creating a trusted, connected foundation that AI can understand, access, and act on.

As data intelligence becomes increasingly AI-driven, success will depend on more than simply connecting agents to data. Organizations will need trustworthy context, consistent business meaning, and strong governance behind every answer. For BI teams, that means prioritizing certified semantic models, verified data, and reusable metrics that both people and AI agents can trust.

The future of data intelligence isn’t just about getting answers faster. It’s about building the trusted foundation that allows people and AI to make better decisions together.

19:49

Vincent Bernat: An interactive introduction to the spanning tree protocol [Planet Debian]

Warning

This post contains interactive examples. To visualize and interact with them, you need to leave your RSS reader.

Imagine you rent office space for a three-day event. You quickly set up a few Ethernet switches and tape some cables on the floor to get everyone online. Unfortunately, Stan, your clumsiest coworker, kicks out a cable every time he gets up for coffee. You could add extra cables, but then you’d get a broadcast storm: Ethernet packets that loop and multiply until nothing else gets through.

That’s where the spanning tree protocol (STP) comes in. STP blocks just enough of your spare cables to leave a loop-free tree. When Stan strikes again, it rebuilds the tree in a second, leaving some time for Blobby, your one-person support crew, to reconnect the cable. See for yourself: the diagram below runs a real STP implementation in your browser!

:demo

A1 @0,0 prio=4096
A2 @0,1
A3 @0,2
A4 @0,3

B1 @1,0 prio=8192
B2 @1,1
B3 @1,2
B4 @1,3

C1 @2,0 prio=8192
C2 @2,1
C3 @2,2
C4 @2,3

A1 -- A2 hazard=0
A2 -- A3 hazard=0
A3 -- A4 hazard=0
B1 -- B2
B2 -- B3
B3 -- B4
C1 -- C2 hazard=0
C2 -- C3 hazard=0
C3 -- C4 hazard=0

A1 -- B1 cost=10
B1 -- C1 cost=10
A4 -- B4 cost=20
B4 -- C4 cost=20

Leo @-0.3,0.7 proto=none icon=👦🏻
Mia @-0.3,1.3 proto=none icon=👧🏽
Joy @0.3,0.7  proto=none icon=👱🏻‍♀️
Roy @0.3,1.3  proto=none icon=👨🏾
A2 -- Leo hazard=0 A2:edge
A2 -- Mia hazard=0 A2:edge
A2 -- Joy hazard=0 A2:edge
A2 -- Roy hazard=0 A2:edge

Max @-0.3,1.7 proto=none icon=👨🏽
Zoe @-0.3,2.3 proto=none icon=👩🏾
Ada @0.3,1.7  proto=none icon=👵🏾
Amy @0.3,2.3  proto=none icon=👩🏼
A3 -- Max hazard=0 A3:edge
A3 -- Zoe hazard=0 A3:edge
A3 -- Ada hazard=0 A3:edge
A3 -- Amy hazard=0 A3:edge

Eli @0.7,0.7 proto=none icon=👦🏼
Jay @0.7,1.3 proto=none icon=👨🏻
Kai @1.3,0.7  proto=none icon=🧑🏽
Ben @1.3,1.3  proto=none icon=👱🏼
B2 -- Eli hazard=0.2 B2:edge
B2 -- Jay hazard=0.2 B2:edge
B2 -- Kai hazard=0.2 B2:edge
B2 -- Ben hazard=0.2 B2:edge

Ava @0.7,1.7 proto=none icon=👩🏻
Lea @0.7,2.3 proto=none icon=🧑🏾‍🦱
Ivy @1.3,1.7  proto=none icon=🧕🏽
Rex @1.3,2.3  proto=none icon=👴🏿
B3 -- Ava hazard=0.2 B3:edge
B3 -- Lea hazard=0.2 B3:edge
B3 -- Ivy hazard=0.2 B3:edge
B3 -- Rex hazard=0.2 B3:edge

Ana @1.7,0.7 proto=none icon=👩🏿
Eve @1.7,1.3 proto=none icon=👧🏼
Abe @2.3,0.7  proto=none icon=🧓🏿
Ian @2.3,1.3  proto=none icon=🧔🏾
C2 -- Ana hazard=0 C2:edge
C2 -- Eve hazard=0 C2:edge
C2 -- Abe hazard=0 C2:edge
C2 -- Ian hazard=0 C2:edge

Ned @1.7,1.7 proto=none icon=👨🏼‍🦳
Lou @1.7,2.3 proto=none icon=🧑🏿
Fay @2.3,1.7  proto=none icon=👧🏻
Sue @2.3,2.3  proto=none icon=👩🏽‍🦰
C3 -- Ned hazard=0 C3:edge
C3 -- Lou hazard=0 C3:edge
C3 -- Fay hazard=0 C3:edge
C3 -- Sue hazard=0 C3:edge

Note

This article is also available as a video, but I advise you to keep reading here to try the interactive demonstrations.

The basics

Designed in the ’80s, the spanning tree protocol has evolved into a “rapid” flavor (RSTP) and a “VLAN-aware” variation (MSTP).1 Any sound-minded network engineer knows there are better alternatives, like BGP EVPN VXLAN. Yet, because any switch speaks it, the venerable spanning tree protocol still fills a niche.

We focus on RSTP: it replaced the original protocol in 2004. To eliminate network loops, RSTP implements a complex state machine. Timers, link state changes, and the link-local control frames a bridge receives from its neighbors drive its transitions. These Ethernet frames are the Bridge Protocol Data Units (BPDUs). You can watch them in action below: hit the “Start” button.

:protocol rstp
:tx-hold 10

A1 @0,1
C11 @1,0 prio=4096 icon=🌳
C12 @1,2 prio=4096 icon=🌳
C21 @2,0 prio=4096 icon=🌳
C22 @2,2 prio=4096 icon=🌳
A2 @3,1

H1 @0,0.2 proto=none icon=💻
H2 @0,1.8 proto=none icon=🖨️
H3 @3,0.2 proto=none icon=📠
H4 @3,1.8 proto=none icon=📺

A1 -- C11
A1 -- C12
A2 -- C21
A2 -- C22
C11 -- C12
C11 -- C21
C11 -- C21
C11 -- C22
C12 -- C21
C12 -- C22
C21 -- C22
A1 -- H1 A1:edge
A1 -- H2 A1:edge
A2 -- H3 A2:edge
A2 -- H4 A2:edge

After some time, the topology converges to a tree: from the root C11, there is a path to each bridge2 and no loop. In the upper right corner, the interface displays a tree icon 🌳 followed by the time it took to reach this state. Cut a link and see how the protocol finds an alternate path to reach C12 in less than a second. You can stop the simulation, move it forward step by step, reset it to its initial state, or slow it down with the “snail” mode 🐌. Don’t worry about all the displayed information: I explain it later.

All examples run in your browser, powered by MSTPD—an open-source user-space3 implementation of RSTP.4

Historical interlude

Radia Perlman, an inductee of the Internet Hall of Fame in 2014, summarized the ancestor of STP she invented at DEC with this poem, later included in a US patent:

I think that I shall never see
A graph more lovely than a tree.
A tree whose crucial property
Is loop-free connectivity.
A tree which must be sure to span
So packets can reach every LAN.
First, the root must be selected.
By ID, it is elected.
Least cost paths from root are traced.
In the tree, these paths are placed.
A mesh is made by folks like me,
Then bridges find a spanning tree.

Radia Perlman, Algorhyme.

Electing the root bridge

To build a tree, RSTP first elects the bridge with the lowest bridge identifier as the root bridge. The bridge identifier combines the priority and the MAC address: 8192.6e:2b:10:a0:5f:29.

In the example below, S1 and S2 have priorities of 4,096 and 8,192: S1 becomes root. S4 has a priority of 12,288, while S3 keeps the default priority of 32,768:5 S4 becomes root. S5 and S6 don’t have a specific priority, so the lowest MAC address wins and S5 becomes root.

:protocol rstp

S1 @0,0 prio=4096
S2 @0,1 prio=8192
S1 -- S2

S3 @1,0
S4 @1,1 prio=12288
S3 -- S4

S5 @2,0
S6 @2,1
S5 -- S6

Initially, each bridge advertises itself as root:6

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    Root Identifier: 8192.02:00:00:01:00:01
    Bridge Identifier: 8192.02:00:00:01:00:01

Once a bridge receives a BPDU advertising a better root bridge, it propagates this new information to its neighbors.

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    Root Identifier: 4096.02:00:00:00:00:00
    Bridge Identifier: 8192.02:00:00:00:00:01

Assigning roles to ports

The second step is to assign a role to each port. RSTP defines five roles, each denoted by a letter:

  • root (R),
  • designated (D),
  • alternate (A),
  • disabled (X), or
  • backup (B).7

Each non-root bridge chooses its root port, the one with the lowest-cost path to the root. Unless you override it, each bridge derives the link cost from the speed: 20,000 for 1 Gbps. In case of equality, the lowest port identifier wins.

Each remaining port becomes a designated port if the BPDU it sends is “better” than the BPDU it receives. Otherwise, it becomes an alternate port. Later, if the root port goes down, the “best” alternate port becomes the new root port. The tiebreakers for the best BPDU are:

  1. the lowest root bridge identifier,
  2. the lowest accumulated cost to the root,
  3. the lowest bridge identifier, and
  4. the lowest port identifier.
:protocol rstp

S1 @1,0  prio=4096 icon=🌳
S2 @0,1
S3 @2,1

S1 -- S2
S1 -- S3
S1 -- S3
S2 -- S3

In the example above, after convergence, S1 is the root bridge because it has a priority of 4,096, while the other bridges have a priority of 32,768. All its ports are designated ports because the accumulated cost to the root is 0.

S2’s port facing S1 becomes a root port because it has the lowest accumulated cost to the root—20,000 vs 40,000. S3 has two ports facing S1, and the one with the lowest port identifier becomes the root port—0x8000 vs 0x8001. The other candidate is an alternate port because the remote port on the link sends a better BPDU, with an accumulated cost of 0. On the segment between S2 and S3, S2’s port wins: while both bridges have the same accumulated cost to the root (20,000), S2’s bridge identifier is smaller—32768.02:00:00:00:00:01 vs 32768.02:00:00:00:00:02.

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    Root Identifier: 4096.02:00:00:00:00:00
    Root Path Cost: 20000
    Bridge Identifier: 32768.02:00:00:00:00:01
    Port identifier: 0x8002

If you cut the active link between S1 and S3, S3 promotes the “best” alternate port to root port. If you also disable the second link, S3 chooses the remaining alternate port as a root port. But if you disable the link between S1 and S2, S2 needs a bit more work to elect a new root port because it does not have an alternate port.

Unless a specific event happens, designated ports send BPDUs every 2 seconds.8 If a bridge does not receive BPDUs from its neighbor for 3 consecutive hello periods, it considers the neighbor dead and removes the port information.

Port state transition

Each port can have one of three states. The diagram displays a background color for each state:

  • discarding (red),
  • learning (yellow), or
  • forwarding (green).

A root port transitions automatically to the forwarding state. An alternate port stays in the discarding state. A designated port has two options to transition from the discarding state to the forwarding state:

  • If the port is an edge port, either through configuration or because the remote device does not speak any flavor of STP, the bridge assumes it won’t participate in the protocol and cannot create a loop. In this case, the designated port immediately transitions to the forwarding state.
  • Otherwise, it sends a proposal to its downstream neighbor. If the remote bridge agrees that the received BPDU is “better” than any other BPDU stored for other ports, it elects the receiving port as its root port and starts the synchronization process: it transitions all non-edge non-synced designated ports to the discarding state to avoid a loop. Then, it sends back an agreement. Upon receiving the agreement, the peer designated port transitions to the forwarding state.9
:protocol rstp

S1 @1,0 prio=4096 icon=🌳
S2 @1,1
S3 @0,2
S4 @2,2
S5 @0,3 prio=8192 icon=🪾
S6 @2,3
H1 @0,1.2   proto=none icon=🖨️
H2 @2,1.2   proto=none icon=📠
H3 @2.5,1.3 proto=none icon=📺
H4 @2.5,2.3 proto=none icon=💻

S1 -- S2
S2 -- S3
S2 -- S4
S3 -- S5
S4 -- S6
S4 -- S3
S5 -- S6

S3 -- H1 S3:edge
S4 -- H2 S4:edge
S4 -- H3 S4:edge
S6 -- H4 S6:edge

In the topology above, H1, H2, H3, and H4 are end devices not participating in the protocol. We configure the ports they connect to as edge ports, so these ports immediately move to the forwarding state.

Use the “step” button to move the simulation forward. The clock moves to 1 second. Step again and S1 and S2 send a proposal to each other. Here is the proposal from S2:

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    BPDU flags: 0x4e, Agreement, Port Role: Designated, Proposal
        0... .... = Topology Change Acknowledgment: No
        .1.. .... = Agreement: Yes
        ..0. .... = Forwarding: No
        ...0 .... = Learning: No
        .... 11.. = Port Role: Designated (3)
        .... ..1. = Proposal: Yes
        .... ...0 = Topology Change: No
    Root Identifier: 32768.02:00:00:00:00:01
    Root Path Cost: 0
    Bridge Identifier: 32768.02:00:00:00:00:01
    Port identifier: 0x8001

S1 ignores it: its own root identifier is lower. When S2 receives a similar proposal from S1, it accepts S1 as its root bridge. It also elects the port to S1 as the root port and starts the synchronization process. The two designated ports are already discarding, so no change here. Step again and S2 sends two BPDUs to S1. In one of them, the agreement bit is 1 and the proposal bit is 0. It also shows that S2 accepted S1 as the root bridge and its root port is now in the forwarding state. When receiving this BPDU, S1 transitions its own designated port to the forwarding state. From this point, the link between S1 and S2 forwards user traffic.

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    BPDU flags: 0x79, Agreement, Forwarding, Learning, Port Role: Root, Topology Change
        0... .... = Topology Change Acknowledgment: No
        .1.. .... = Agreement: Yes
        ..1. .... = Forwarding: Yes
        ...1 .... = Learning: Yes
        .... 10.. = Port Role: Root (2)
        .... ..0. = Proposal: No
        .... ...1 = Topology Change: Yes
    Root Identifier: 4096.02:00:00:00:00:00
    Root Path Cost: 20000
    Bridge Identifier: 32768.02:00:00:00:00:01
    Port identifier: 0x8001

Let’s look at what happened to S5. Reset the simulation and step twice. S5 exchanges BPDUs with both S3 and S6. Since S5 has a lower root identifier than S3 and S6, it stays the root bridge, while S3 and S6 accept the proposal and elect their root ports. S3 and S6 start the synchronization process. S6’s port to H4 stays up because this is an edge port. Move one step. Both S3 and S6 send an agreement back to S5, which transitions both designated ports to the forwarding state. Yet, the link between S5 and S3 keeps discarding user traffic! If you look carefully, S3’s port toward S5 is now a designated port, not a root port. During the same step, S3 also receives a better BPDU from S2 with S1 as the root bridge. It elects its port to S2 as the root port and downgrades the port to S5 to a designated port, which stays in the discarding state.

On the next step, things get a bit tricky. S3 sends a proposal to S5:10

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    BPDU flags: 0x4f, Agreement, Port Role: Designated, Proposal, Topology Change
        0... .... = Topology Change Acknowledgment: No
        .1.. .... = Agreement: Yes
        ..0. .... = Forwarding: No
        ...0 .... = Learning: No
        .... 11.. = Port Role: Designated (3)
        .... ..1. = Proposal: Yes
        .... ...1 = Topology Change: Yes
    Root Identifier: 4096.02:00:00:00:00:00
    Root Path Cost: 40000
    Bridge Identifier: 32768.02:00:00:00:00:02
    Port identifier: 0x8002

S5 elects S1 as its root bridge and the port toward S3 as its root port. It starts its synchronization process, but the designated port to S6 does not move into the discarding state. Why? That port stays a designated port and its neighbor S6 had already sent an agreement on the link, so the port keeps its synced status.

Now, let’s step back to look at what happens to S6. At this point, S6 believes S5 is the root bridge. Step once and S4 sends a new proposal to S6. S6 accepts the proposal, elects S1 as the root bridge and the port to S4 as its root port. The role of the port facing S5 changes: from a root port, it becomes a designated port. Because its peer keeps advertising an inferior BPDU on the link, this port becomes disputed and moves to the discarding state. The root port transitions to the forwarding state and the link starts forwarding immediately because S4’s designated port is already in the forwarding state. If we step one more time, S5 and S6 exchange two BPDUs. The one from S5 is better because of its lower bridge identifier. S5’s port stays a designated port, while S6 downgrades its own port to an alternate port.

Let’s rewind one last time from the start: cut the link between S1 and S2, run the simulation until the topology is stable, stop the simulation, and restore the link between S1 and S2. During the first step, S1 and S2 exchange proposals. S2 elects S1 as the root bridge instead of S5 and the port to S1 as the root port. It downgrades the previous root port to a designated port and moves it into the discarding state. The other designated port stays synced and keeps its forwarding state. At the next step, S2 sends an agreement to S1 and the link between them starts forwarding user traffic. It also sends a proposal to S3, but not to S4. Instead, it sends a regular BPDU to S4. S4 still elects S1 as its root bridge and the port to S2 as its root port. It demotes its previous root port, the one to S3, to a designated port, which transitions to the discarding state because of the root port change. The other alternate port, to S6, also becomes a designated port and stays in the discarding state. The new root port moves to the forwarding state. On the next step, S4’s port to S3 settles as an alternate port after receiving a “better” BPDU from S3.

RSTP is a giant state machine split into smaller ones: bridge detection, port information, port protocol migration, port role selection, port role transitions, port receive, port state transitions, port timers, port transmit, and topology change. Some of them are per bridge, some per port. Each bridge runs an instance. Time, operational port state changes, and the BPDUs it receives from other instances drive the transitions. Being event-driven makes RSTP more efficient but also more difficult to understand.

Western Australian Government Railways class Msa Garratt articulated steam locomotive: elevation and plan drawing
Placeholder for the Port Information state machine extracted from IEEE 802.1Q-2005, page 182. Pending IEEE authorization for reproduction, this is the blueprint for the Western Australian Government Railways class Msa Garratt articulated steam locomotive.

Topology change notification

A bridge populates a MAC address table: it associates each source MAC address with the port that last received it. When forwarding an Ethernet frame, it looks up this table to choose the right port.11 When a link fails, a connected fridge reachable through one port may become reachable through another one. The affected bridges should flush the MAC addresses they learned, because these entries may now be wrong.

For this purpose, RSTP implements topology change notifications using a flooding mechanism. When a non-edge port transitions to the forwarding state, a bridge generates BPDUs with the topology change (TC) bit set. It sends them to all the non-edge designated ports and to the root port. It also flushes the MAC address table on these ports. When a bridge receives such a BPDU, it propagates the notification to all non-edge designated ports and the root port, except the one the notification came from. It also flushes the MAC address table on these ports. In the examples, the BPDUs with the TC bit set to 1 have a red circle.

:protocol rstp

S1 @1,0 prio=4096 icon=🌳
S2 @0,1
S3 @1,1
S4 @2,1
S5 @1,2
LPT @0.1,2 proto=none icon=🖨️

S1 -- S2
S1 -- S3
S1 -- S4
S2 -- S3
S2 -- S5
S4 -- S5
S5 -- LPT S5:edge

Start the simulation and wait a few seconds for the topology to settle. Stop the simulation and disable the link between S2 and S5. S5 elects the port facing S4 as the root port, which transitions immediately to the forwarding state. Step once and S5 emits a BPDU with the TC bit set to 1:

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    BPDU flags: 0x79, Agreement, Forwarding, Learning, Port Role: Root, Topology Change
        0... .... = Topology Change Acknowledgment: No
        .1.. .... = Agreement: Yes
        ..1. .... = Forwarding: Yes
        ...1 .... = Learning: Yes
        .... 10.. = Port Role: Root (2)
        .... ..0. = Proposal: No
        .... ...1 = Topology Change: Yes
    Root Identifier: 4096.02:00:00:00:00:00
    Root Path Cost: 40000
    Bridge Identifier: 32768.02:00:00:00:00:04
    Port identifier: 0x8002

S4 receives this BPDU. It flushes the MAC address table on the port facing S1: while LPT was previously reachable through this port, it is now reachable through S5 instead. Step once. S4 sends S1 a BPDU with the TC bit set to 1. When S1 receives this BPDU, it flushes the MAC address table on the ports facing S2 and S3. Step once and S1 sends a notification to S2 and S3. Step once again and S2 sends a notification to S3, while S3 does nothing because the port toward S2 is an alternate port. S3 does not flush any MAC address table: LPT is still reachable through its port to S1.

If you step a bit more, you will see that some of the periodic BPDUs keep the TC bit set to 1. Each port runs a timer equal to the hello timer plus one second.12 The timer starts when the port emits a notification. Until it expires, the port sets the TC bit to 1 in every BPDU it sends. You can also see some periodic BPDUs without the TC bit: they originate from a port that only received a notification and therefore did not arm its timer.

Security

RSTP is weak against configuration errors and malicious actors. A bridge not talking RSTP can create a loop. An attacker can insert themselves into the topology to disrupt the service, spy on the traffic, or alter it.

To mitigate such problems, you need to identify the edge ports. An edge port connects to an end device, like a PC or a printer. Such devices do not generate BPDUs and cannot create a loop. RSTP defines two related flags:

  • When true, AdminEdge initializes a port as an edge port. It defaults to false.
  • When true, AutoEdge lets a port become an edge port when it does not receive BPDUs for 3 seconds. It defaults to true.

If an edge port receives a BPDU, regardless of the values of these two flags, it reverts to a non-edge port.

R0 @1.5,1.5 prio=8192

# AutoEdge=true, AdminEdge=false, bridge
S1 @3,1.58
R0 -- S1

# AutoEdge=true, AdminEdge=false, end device
H1 @2.84,2.18 icon=🖨️ proto=none
R0 -- H1

# AutoEdge=true, AdminEdge=true, bridge
S2 @2.18,2.84
R0 -- S2 R0:edge

# AutoEdge=true, AdminEdge=true, end device
H2 @1.58,3 icon=💻 proto=none
R0 -- H2 R0:edge

# AutoEdge=false, AdminEdge=true, bridge
S3 @0.68,2.76
R0 -- S3 R0:edge R0:no-auto-edge

# AutoEdge=false, AdminEdge=true, end device
H3 @0.24,2.32 icon=📠 proto=none
R0 -- H3 R0:edge R0:no-auto-edge

# AutoEdge=false, AdminEdge=false, bridge
S4 @0,1.42
R0 -- S4 R0:no-auto-edge

# AutoEdge=false, AdminEdge=false, end device
H4 @0.16,0.82 icon=📺 proto=none
R0 -- H4 R0:no-auto-edge

# Network port, bridge
S5 @0.82,0.16
R0 -- S5 R0:network S5:network

# Network port, end device
H5 @1.42,0 icon=☕ proto=none
R0 -- H5 R0:network

# AdminEdge=true, bpdu-guard=true, bridge
S6 @2.32,0.24
R0 -- S6 R0:bpdu-guard R0:edge

# AdminEdge=true, bpdu-guard=true, end device
H6 @2.76,0.68 icon=💡 proto=none
R0 -- H6 R0:bpdu-guard R0:edge

In the topology above, S1, S2, S3, S4, S5, and S6 act as bridges, while H1, H2, H3, H4, H5, and H6 act as end devices:

  • S1 and H1 are on a port without a specific configuration: AutoEdge is true, AdminEdge is false,
  • S2 and H2 are on a port where AdminEdge is true,
  • S3 and H3 are on a port where AutoEdge is false and AdminEdge is true,
  • S4 and H4 are on a port where AutoEdge is false.

If you start the topology and wait about 20 seconds, links to S1, S2, S3, S4, H1, H2, H3, and H4 eventually forward user traffic: none of the flags matter.

But what about the two remaining pairs? S5 and H5 connect to a network port. Such a port enables a non-standard feature: bridge assurance. The port transmits BPDUs regardless of its role. If it does not receive BPDUs for 3 consecutive hello periods, it transitions to the discarding state. On the link between R0 and S5, you can see BPDUs traveling in both directions, unlike the other links, where only designated ports send BPDUs.

S6 and H6 connect to a port where AdminEdge is true and BPDU guard is enabled. This is another non-standard feature that shuts down a port if it receives a BPDU.

In summary, if you expect a port to be an edge port, you should set AdminEdge to true and enable BPDU guard. Otherwise, declare it as a network port.

Why RSTP today?

A compelling use case for RSTP today is an out-of-band network for a datacenter, since you can tolerate an outage of a few seconds. The configuration is minimal and you can use cheap switches, like a Cisco 2960X.13 You need two switches acting as root bridges, and you build several loops to connect OOB switches in each cabinet. This simple design survives one failure on each loop.14

:protocol rstp
:tx-hold 10

# Root bridges
R1 @0,1 prio=0
R2 @0,2 prio=4096
R1 -- R2 cost=200 R1:network R2:network
R1 -- R2 cost=200 R1:network R2:network

# First loop
C1  @1,0 icon=🗄️
C4  @2,0 icon=🗄️
C7  @3,0 icon=🗄️
C10 @4,0 icon=🗄️
C12 @5,0 icon=🗄️
C13 @5,3 icon=🗄️
C15 @4,3 icon=🗄️
C18 @3,3 icon=🗄️
C21 @2,3 icon=🗄️
C24 @1,3 icon=🗄️
R1  -- C1  R1:network C1:network
C1  -- C4  C1:network C4:network
C4  -- C7  C4:network C7:network
C7  -- C10 C7:network C10:network
C10 -- C12 C10:network C12:network
C12 -- C13 C12:network C13:network
C13 -- C15 C13:network C15:network
C15 -- C18 C15:network C18:network
C18 -- C21 C18:network C21:network
C21 -- C24 C21:network C24:network
C24 -- R2  C24:network R2:network

# Second loop
C2  @1,0.5 icon=🗄️
C5  @2,0.5 icon=🗄️
C8  @3,0.5 icon=🗄️
C11 @4,0.5 icon=🗄️
C14 @4,2.5 icon=🗄️
C17 @3,2.5 icon=🗄️
C20 @2,2.5 icon=🗄️
C23 @1,2.5 icon=🗄️
R1  -- C2  R1:network C2:network
C2  -- C5  C2:network C5:network
C5  -- C8  C5:network C8:network
C8  -- C11 C8:network C11:network
C11 -- C14 C11:network C14:network
C14 -- C17 C14:network C17:network
C17 -- C20 C17:network C20:network
C20 -- C23 C20:network C23:network
C23 -- R2  C23:network R2:network

# Third loop
C3  @1,1 icon=🗄️
C6  @2,1 icon=🗄️
C9  @3,1 icon=🗄️
C16 @3,2 icon=🗄️
C19 @2,2 icon=🗄️
C22 @1,2 icon=🗄️
R1  -- C3  R1:network C3:network
C3  -- C6  C3:network C6:network
C6  -- C9  C6:network C9:network
C9  -- C16 C9:network C16:network
C16 -- C19 C16:network C19:network
C19 -- C22 C19:network C22:network
C22 -- R2  C22:network R2:network

This topology converges in about 6 seconds. Each loop should stay small (around 16 bridges) to reduce the probability of a double failure and to avoid sharing too much bandwidth. The design can evolve a bit without adding too much complexity: one VLAN per loop or one bridge domain per loop.

How large can a network be?

The maximum age, whose default value is 20, governs the maximum distance of a node from the root. The topology below is too big for BPDUs from R1 to reach beyond S20.15

:protocol rstp
:tx-hold 10
:max-age 20

R1 @0,0 prio=4096 icon=🌳
R2 @0,5 prio=4096 icon=🪾

S1  @1,0
S2  @2,0
S3  @3,0
S4  @4,0
S5  @5,0
S6  @6,0

S7  @6,1
S8  @5,1
S9  @4,1
S10 @3,1
S11 @2,1
S12 @1,1

S13 @1,2
S14 @2,2
S15 @3,2
S16 @4,2
S17 @5,2
S18 @6,2

S19 @6,3
S20 @5,3
S21 @4,3
S22 @3,3
S23 @2,3
S24 @1,3

S25 @1,4
S26 @2,4
S27 @3,4
S28 @4,4
S29 @5,4
S30 @6,4

S31 @6,5
S32 @5,5
S33 @4,5
S34 @3,5
S35 @2,5
S36 @1,5

R1  -- S1
S1  -- S2
S2  -- S3
S3  -- S4
S4  -- S5
S5  -- S6
S6  -- S7
S7  -- S8
S8  -- S9
S9  -- S10
S10 -- S11
S11 -- S12
S12 -- S13
S13 -- S14
S14 -- S15
S15 -- S16
S16 -- S17
S17 -- S18
S18 -- S19
S19 -- S20
S20 -- S21
S21 -- S22
S22 -- S23
S23 -- S24
S24 -- S25
S25 -- S26
S26 -- S27
S27 -- S28
S28 -- S29
S29 -- S30
S30 -- S31
S31 -- S32
S32 -- S33
S33 -- S34
S34 -- S35
S35 -- S36
S36 -- R2
R1  -- R2 cost=200 down

Once the topology settles, part of the network considers R1 the root, while the other votes for R2. At the boundary, S20 tries to start a synchronization with S21 to move its designated port to the forwarding state. The BPDU looks like this:

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    BPDU flags: 0x4e, Agreement, Port Role: Designated, Proposal
    Root Identifier: 4096.02:00:00:00:00:00
    Root Path Cost: 400000
    Bridge Identifier: 32768.02:00:00:00:00:15
    Port identifier: 0x8002
    Message Age: 20
    Max Age: 20

S21 rejects it because the message age equals the maximum age. On the other hand, the BPDU S21 sends to S20 looks like this:

Spanning Tree Protocol
    Protocol Identifier: Spanning Tree Protocol (0x0000)
    Protocol Version Identifier: Rapid Spanning Tree (2)
    BPDU Type: Rapid/Multiple Spanning Tree (0x02)
    BPDU flags: 0x7c, Agreement, Forwarding, Learning, Port Role: Designated
    Root Identifier: 4096.02:00:00:00:00:01
    Root Path Cost: 320000
    Bridge Identifier: 32768.02:00:00:00:00:16
    Port identifier: 0x8001
    Message Age: 16
    Max Age: 20

This is not enough to change S20’s root port because S20 has a lower root identifier4096.02:00:00:00:00:00 vs 4096.02:00:00:00:00:01.

Fixing the link between R1 and R2 resolves the issue. The maximum message age any packet carries is now 18, below the configured maximum age. But it only works until another link breaks. A plausible fix is to increase the maximum age to 40.16

How fast is RSTP?

RSTP usually converges in a couple of seconds at startup. It often repairs a tree in less than a second. Even the 38-bridge topology takes less than 10 seconds to converge.17 Some topologies can take a bit more time to recover when the root bridge becomes unavailable.18

:protocol rstp

R0 @1,0 prio=0
S1 @1,1 prio=4096
S2 @0,2 prio=8192
S3 @2,2

R0 -- S1
S1 -- S2
S2 -- S3
S3 -- S1

In the topology above, start the simulation, wait for convergence, hit stop, and cut the link between R0 and S1. The topology is already optimal, but RSTP has a hard time converging again.

First, S1 loses its root port. It has no more information about R0 and elects itself as the root bridge. It keeps its ports to S2 and S3 as designated ports in the forwarding state. Step once and it sends a BPDU to both S2 and S3 to let them know about the root change. When receiving it, S2 accepts S1 as its root because it does not have a better root on another port. It elects the port to S1 as its root port. The other port stays a designated port. Both ports keep forwarding.

When receiving the BPDU from S1, S3 behaves differently: it knows R0 as a better root than S1 through its alternate port to S2. It promotes this port to a root port and demotes the port facing S1 to a designated port, which requires a new agreement. Step once and S3 sends a proposal to S1 with R0 as the root bridge. S1 elects R0 as the root bridge and promotes its port to S3 as a root port.

During the same step, S3 also receives a BPDU from S2 stating that S1 is the root bridge. Therefore, S3 has no port left with R0 as the root bridge: it elects S1 as the root bridge and its port to S2 as the root port. Step once and its next BPDU to S1 includes this information: S1 elects itself again as the root bridge. But during the same wave, S1 sends a proposal to S2 with R0 as the root bridge. While S1 and S3 agree that S1 is the root bridge, S2 now believes this is R0! In turn, S2 again convinces S3 that R0 is the root bridge, S3 convinces S1, S1 convinces S2, and S2 convinces S3.

This could go on forever, but it does not. The BPDUs saying “R0 is root” eventually age out when the message age goes past the maximum age. In the example above, at the eleventh second, S2 sends a BPDU to S3 with R0 as root, but S3 drops it because its message age reached the maximum. With some luck, the topology can also converge faster if a port stops transmitting new BPDUs after tripping the transmit hold count, whose default value is 6 per second.

About MSTP

MSTP is the “VLAN-aware” version of RSTP: it runs several instances of RSTP and lets the administrator map each VLAN to a specific instance. For example, you can map VLANs 100 to 200 to a first instance, and 300 to 400 to a second instance. The remaining VLANs map to a special instance named the Internal Spanning Tree (IST). MSTP adds its own complexity, but the gist is that you have several logical topologies acting independently. If you want to dig deeper, have a look at “MSTP Tutorial Part I: Inside a Region.”

About the interactive examples

The interactive examples run MSTPD directly in your browser, compiled to WebAssembly with emscripten. A C API replaces the code talking to the Linux kernel: it manages bridges and ports, exports state as JSON, and drives time deterministically. A JavaScript wrapper makes it more user-friendly:

import { loadMSTPD } from "./dist/mstpd.mjs";
const mstp = await loadMSTPD();

// Create 3 bridges
const a = mstp.createBridge("A", { priority: 4096 });
const b = mstp.createBridge("B", { priority: 8192 });
const c = mstp.createBridge("C");

// Each bridge has two ports
const a1 = a.addPort("a-b", { portno: 1 });
const a2 = a.addPort("a-c", { portno: 2 });
const b1 = b.addPort("b-a", { portno: 1 });
const b2 = b.addPort("b-c", { portno: 2 });
const c1 = c.addPort("c-a", { portno: 1 });
const c2 = c.addPort("c-b", { portno: 2 });

// Build a triangle topology
mstp.link(a1, b1);
mstp.link(a2, c1);
mstp.link(b2, c2);

// Enable all bridges and ports
for (const br of [a, b, c]) br.enable();
for (const p of [a1, a2, b1, b2, c1, c2]) p.enable();

// Execute 40 seconds' worth of wall clock and display the topology
mstp.step(40);
console.log("Topology:", mstp.topology());

Several dozen unit tests explore the features of MSTPD and check that they work correctly in this environment:

$ node --test *.test.mjs
✔ two bridges: lower priority becomes root (41.657342ms)
✔ triangle loop: exactly one port blocks and all agree on the root (5.832ms)
✔ breaking the active link reconverges and restoring recovers (18.730753ms)
[…]
ℹ tests 40
ℹ pass 40
ℹ fail 0
[…]
ℹ duration_ms 396.190897

Additional JavaScript code looks for specific <pre> blocks containing a topology definition and turns them into the interactive widget. You can inspect and modify the definition by hitting the “edit” button.

There is also a cool trick to tell whether the topology has converged. After each step, we save a snapshot of the simulation memory, play 50 seconds’ worth of simulation to check if the topology is stable, and travel back in time by restoring that snapshot. 🕰️

The complete code lives on GitHub. I am happy with the result. It can be difficult to follow everything happening during a single step, but stepping forward and backward helps. I plan to use the same approach in future blog posts about networking features.

Note

Michael Lynch reviewed a first draft of this article. He authored “Refactoring English,” a book to sharpen your writing for blog posts, documentation, commit messages, and tutorials. Any errors are still mine!


  1. STP was introduced in IEEE 802.1D-1990. It is still present in IEEE 802.1D-1998 but was withdrawn in IEEE 802.1D-2004 in favor of RSTP, introduced in IEEE 802.1w-2001. MSTP was introduced in IEEE 802.1s-2002 and merged into IEEE 802.1Q-2003. Both of them are part of IEEE 802.1Q-2022 along with SPB—a protocol I had never heard of until writing this article

  2. From here, I use “bridge” instead of the more common word “switch.” 

  3. The Linux kernel only runs STP. It delegates the other protocols to user space. 

  4. MSTPD implements the state machine from IEEE 802.1Q-2005, but on Linux it runs RSTP only. Linux 5.18 added support for forwarding multiple spanning tree, but MSTPD does not use it yet. See PR #150 for progress on this front. 

  5. The priority is a multiple of 4,096: with MSTP, the lower 12 bits of the bridge priority encode the MST instance identifier, leaving only the upper 4 bits for the configured priority. 

  6. To inspect the BPDUs crossing a link, select it, click the “Download packets” button, and open the file with Wireshark

  7. A backup port only exists if the bridge has several ports on the same collision domain. This should not happen in a switched network. 

  8. This is the value of the “hello” timer. It used to be configurable, but IEEE 802.1Q-2005 pins it to 2. MSTPD does not allow another value. 

  9. If the peer port does not receive an agreement after the hello timer elapses—or the maximum age if the port has just come up—it falls back to the timer-based method for compatibility with STP: it transitions to the learning state, waits again for the hello timer to expire, and transitions to the forwarding state. 

  10. As in many proposals, S3 also sets the agreement bit to 1. The proposal bit says “I am the designated port on this link and I want to transition to the forwarding state.” The agreement bit says “I am already in sync with the rest of my bridge on this root information.” Both can be true. 

  11. If it finds no entry, the bridge duplicates the Ethernet frame on all ports, except the incoming one. The same happens if the destination MAC address is the broadcast one (ff:ff:ff:ff:ff:ff). This behavior bootstraps the learning process. 

  12. This timer makes RSTP resistant to packet loss. 

  13. You can get them for less than US$100 through a broker. All the ports run PVST+ by default and automatically fall back to plain RSTP

  14. An alternative would be Ethernet Ring Protection Switching (ERPS)—another protocol I had never heard of until researching this article. 

  15. If you look closely at what happens at t=2s, you can see that R2 is gaining popularity as root: S17 to S36 believe R2 is the root bridge. S16 does not follow because we hit the maximum age. Later, S17 to S20 reverse their position. I’ll let you explore the state of the various bridges to understand the root cause. 

  16. When increasing the maximum age to 40, you also need to increase the forward delay to 21 (:forward-delay 21), as the standard enforces this condition: 2 × (Forward Delay − 1) ≥ Max Age. For this specific topology, you could also increase the maximum age to 37 and forward-delay to 20. 

  17. The simulation may seem slow, but it does not run in real time. Look at the current timestamp in the upper right corner to know the wall clock, e.g. “t=8s.” Once the topology stabilizes, the same corner shows the convergence time, e.g. “🌳 2s.” 

  18. Khaled Elmeleegy, Alan Cox, and Eugene Ng formalized this phenomenon in “On Count-to-Infinity Induced Forwarding Loops in Ethernet Networks” and later in “Understanding and Mitigating the Effects of Count to Infinity in Ethernet Networks.” They propose a fix that did not find its way into a standard. 

Vincent Bernat: A non-interactive introduction to the spanning tree protocol [Planet Debian]

Imagine you rent office space for a three-day event. You quickly set up a few Ethernet switches and tape some cables on the floor to get everyone online. Unfortunately, Stan, your clumsiest coworker, kicks out a cable every time he gets up for coffee. Spare cables would fix that, but a loop turns into a broadcast storm: Ethernet packets multiply until nothing else gets through. That’s where the spanning tree protocol comes in: it blocks just enough of the spare cables to leave a loop-free tree, and rebuilds it in a second each time Stan strikes again.

This content is also available as a text version, with interactive demos that run a real implementation directly in your browser!


This video is an experiment.1 Honestly, except for Radia Perlman reading her poem,2 you should read the original article instead. It presents the same content, but you can play with the interactive examples, which are the main contribution. On the other hand, if you happen to like the video, be sure to tell me in the comments!


  1. I thought automated tools would produce this video in a couple of hours. In the end, it was another rabbit hole and it took me more than 12. 

  2. The audio was extracted from a Youtube video and cleaned up. 

18:42

Grave-Maker Rounds [Penny Arcade]

I haven't even seen any of the leaks; they are effervescent, and quickly boil away. I just know that there are a steady set of leaks for a game that is considered synonymous with the industry, and it only blooms narratively from there: now in addition to the data heist we've got crypto, and for a brief time there was a supposed Dead Man's Switch that would have released the game to the world if anything happens to him. Just unbelievable stuff. I hope the "Cyberleek Entity" is having fun while it lasts. You know? Order DoorDash or something. Do it up.

18:14

The Big Idea: Carolyn Ives Gilman [Whatever]

Having a miscommunication can be annoying, or even cause some real tension, but rarely does it lead to something as severe as losing your life. Author Carolyn Ives Gilman is taking the miscommunication trope and putting a life-or-death spin on it for her newest novel, Testament of Leaves.

CAROLYN IVES GILMAN:

When I started work on Testament of Leaves, I had never written a science fiction mystery, and I wanted to find out how hard it was. The idea that got me going had been languishing in my notebook of spare ideas for a long time—about a detective who forms a relationship with the (dead) victim. I’d never used it because I’m a science fiction writer, and I don’t do ghosts. Then someone invented chatbots that impersonate dead people in order to comfort grieving relatives. What a grisly and problematic idea, I thought. Perfect fiction fodder. 

However, that turned out not to be the big idea. Or at least, not the only one. The more difficult question came up when I had to decide: who was my victim and how did she die? For that, I turned to my own experiences. 

I spent years working at museums, where I kept getting assigned to organize exhibits about the history of Native people in North America. I was never comfortable representing Indigenous people without their collaboration, so this led me to many summers on the road, visiting reservations, tribal museums, and powwows where I could interview people and find advisors. It was some of the most difficult work I ever did, and it taught me how easily misunderstandings can arise between people of different cultures. You can go on for hours—no, days, even years—thinking you understand what someone is telling you, until it dawns on you that they are coming from a completely different set of assumptions. Then the whole story changes. 

I wanted to capture that experience: first, the feeling of being immersed in an unfamiliar and disorienting situation, where the risk of miscommunication is high. And second, the feeling of realizing that you’ve been entirely wrong about what was going on. 

I don’t think this is an experience that will be going away any time soon. Unlike some, I don’t foresee a future when humanity will all blend together into one huge amalgamated culture. If humanity ever survives to populate other planets, we will surely diverge into many cultures speaking many languages and believing things we can barely imagine now. Intercultural communication will only become more fraught. 

Because communication was my theme, I made my victim a linguist trying to save an endangered language spoken by humans on another planet. I think people who do the difficult work of language preservation are heroic, but I can also see how it could lead to conflicts and pitfalls. My detective has to retrace the linguist’s steps and work out where she went wrong—who she offended badly enough to get herself killed. As he gets to know her personality by speaking to her deadbot, it becomes increasingly obvious how this might have happened. 

In writing, good decisions can create bad problems. I am impatient when reading SF about alien encounters where explorers whip out their universal translators and immediately can communicate perfectly with everyone they meet. What a cheat, I thought. So here I was, writing a story about language, translation, and miscommunication, so I really couldn’t fudge it. People in my story speak three named languages and an unnamed one, and there is no character that speaks more than two. This took an enormous amount of thinking and planning while writing, but it paid off in all the scenes of confusion and comic misdirection that occur. It is also crucial to solving the mystery. 

The other problem that my premise forced me to consider is one that is implicit in all murder mysteries but rarely confronted: the issue of justice. Most detectives in fiction, as in our culture, are part of a justice system, and the goal of the story is to bring punishment to the evildoer. But in an intercultural context this does not work, because there are no universal beliefs about what is just, or whether the government should have any role in bringing it about. For example, in societies with a more collective sense of identity, the family, clan, or village is responsible for the actions of individual members, so that revenge can legitimately be carried out against any member of that group, and still be just. Determining which individual committed a crime is of importance only in an individualistic society like ours. 

Since the future universe I’m writing about contains many inhabited planets, I had to invent a justice system that would account for this difference. As a result, my detective does not work for the government, but for a neutral outside organization. Nor is he responsible for justice; he is responsible only for determining the truth, and justice is left to the locals and their own sense of what is right. That meant I couldn’t have that satisfying scene at the end where the malefactor is led off to jail. The future sometimes frustrates our present-day sensibilities. 

The story ended up being not just one mystery but a nested set of them—cultural, historical, linguistic, and legal. So the answer to my original question about how hard it would be to write an SF mystery? It was some kind of complicated, but it was also loads of fun. 


Testament of Leaves: Amazon|Barnes & Noble|Bookshop|Kobo

Author socials: Website

16:42

Japan tried to build an operating system for the entire world: TRON [OSnews]

Ah, Japan’s TRON project – every few years someone discovers it anew and it bubbles back up the surface, and deservedly so, as it’s an incredibly interesting operating system project that, like so many others, deserved a better fate.

There’s a version of computing history where the desktop OS that won wasn’t Windows. Not because the alternative was Unix-based or because Apple pulled off something different, but because an operating system designed at the University of Tokyo in 1984 was ambitious enough to try to replace the file system with a hypermedia document model, run on a custom Japanese CPU architecture, and encode 1.5 million characters, only to have a US trade report single it out as an unfair trade barrier in 1989.

That project was TRON (The Real-time Operating system Nucleus), a real, government-backed Japanese computing initiative whose desktop variant, BTRON, was named in a US trade barrier report and effectively killed before it could reach schools nationwide. Meanwhile, its embedded counterpart, ITRON, quietly became one of the most deployed operating systems in history.

TRON’s history has since attracted some genuinely wild conspiracy theories, including one claiming that Japan Airlines Flight 123 was deliberately crashed in order to target the TRON developers on board, despite there being no evidence that any TRON developers were even on the flight. But the strangest part of the story isn’t even a conspiracy theory: BTRON’s hypermedia desktop was decades ahead of what the market could support, and SoftBank founder Masayoshi Son may have helped sink it from the inside.

↫ Adam Conway at XDA

The most interesting part of TRON for me was the different ways it treated files and documents compared to other operating systems. Instead of focusing on applications and files as the core interaction points for users, it focused on the document. While most operating systems associate specific files with specific applications, TRON associated individual components of documents with individual handlers. If you want to edit a Word document today, you open Word and do all your editing work inside Word, whether you’re editing blocks of text or an image, or you open entirely different applications when Word’s capabilities for a certain component in a document are too limited. In TRON, you’d open a document, and only once you wanted to edit specific components did it “open” an “application” to perform the editing, without actually leaving the document in question.

Want to edit an image inside your document? In most operating systems, you’d have to open a separate image editor, load the relevant image file into it, make your edits, save the image file, and then paste said edited image file back into your document. There’s a considerable amount of overhead here that shouldn’t really exist; a computer is more than smart enough to open up just the editing controls from a different application if need be. In our current paradigm, applications often “solve” this by adding ever more features and controls and tools to cover every possible object or component you might have to deal with, but that just makes applications more complex, more bloated, and more difficult to use.

TRON’s approach has been tried in a variety of times and places, but it never caught on. My personal pet theory is that the application-first model is far better at wealth extraction and concentration than TRON’s model, and as such, that’s what we ended up with. If a user’s document and all of its constituent parts are tied to and wrapped up into a single application from a single vendor, it’s much easier to control said user and extract wealth from them than when that user can just pick and choose whatever handler they want to use for whatever object they happen to run into in a document, without having to open tons of different applications and move, copy, and paste stuff all the time.

In fact, this is also why consistency in user interface design is now all but dead; application developers and vendors use their own weird, non-standard, custom user interfaces for branding purposes. Sticking to a platform’s standards and conventions makes it harder to stand out and put your “brand” in people’s faces. But I digress.

Regardless, I’m not sure if all the stories about the US trying to bury TRON have any real value to them, as even the article itself notes (undoing its own clickbaity headline) that the project already seemed to be in dire straights even before it got a buried mention in some trade document. On top of that, ITRON, the embedded TRON variant, survived and thrives to this very day, powering untold numbers of devices. It seems to have done quite well for itself, supposed US government intervention or no.

This article by Steven J. Searle also takes a look at the workstation-focused variant of TRON.

16:28

[$] How to be safe from quantum computing [LWN.net]

Practical quantum computers have been ten years away for the last several decades. Now, however, it's beginning to look as though they will be possible in just a few years. Recent research with obfuscated results demonstrated much lower memory requirements to factor ECDSA keys on a quantum computer, with work by other researchers in the open more than halving memory use compared to the state of the art in 2023. At the same time, computer manufacturers are boasting quantum processors that retain viable superpositions over longer periods. Given how slowly software updates filter out to stable systems, it's worth looking at what configuration changes and protocol updates are needed to be safe from quantum computers now.

15:42

Link [Scripting News]

One reason I want AI-assisted writing to be identifiable is that it devalues the idea of Claude et al to be quoted in public. What can it teach us? What it is relative to a human being. I know the doubters sniff at that, but it really is like an alien life form, it's the first such example, it kind of did evolve from us, but it has its own way, things it's really strong at and things it utterly fails at. I for one want to study this! What a unique experience. It can also give a summary of what we've been trying to say for forty years and have never managed to put into words. I'd say that's something I should feel comfortable publishing, but right now I don't. Maybe I just have to get over that.

14:56

Zero to Agent in 30 Minutes: Never Type Again with Craig Hewitt [Radar]

Craig Hewitt, founder of the podcast hosting platform Castos, joined this episode of Zero to Agent in 30 Minutes to show how he uses the Codex application’s voice mode to run his development environment without touching the keyboard. Craig walked through what voice mode actually is, how it differs from dictation tools, and how he uses it to control his browser and other applications on his computer.

Setting up Codex for hands-free development, step by step

  1. Set up browser and computer access. Enable computer use in the Codex app and configure browser access so the agent can work with websites and other applications. Craig recommended requiring approval before the agent accesses most applications or sites.
  2. Start a voice session. Launch voice mode and give the agent instructions conversationally. Craig showed that the voice interface remains available as you move among applications, allowing you to direct work across your computer without repeatedly returning to the chat.
  3. Give the agent browser tasks. Craig asked the agent to open websites, search for information, and navigate pages. He also described using browser control for routine jobs such as completing forms when the agent already has the necessary context.
  4. Let the agent work across applications. Computer use extends the workflow beyond the browser. In Craig’s demonstration, the agent opened Cursor, found a specific repository, reported on uncommitted changes, and later committed those changes after receiving permission.
  5. Add specific page content to the conversation. Craig showed how you can select part of a web page and add it directly to the chat. That gives the agent the context needed to act on a particular element, such as a section of an interface you want to change.
  6. Keep permissions narrow. Browser and computer control create real risks, including unintended actions and prompt injection from web content. Craig said he requires approval for most applications, grants broader access only to selected tools and local development sites, and avoids sites he doesn’t trust.

Voice mode let Craig direct browser, application, and coding tasks through conversation. The demo also raised a real question about delegation. Once an agent can act on your behalf, you have to decide what you’re actually comfortable handing off. Craig used permission settings, a list of trusted sites, and human review to manage that.

Coming next week

In the next episode of Zero to Agent in 30 Minutes, Jayeeta Putatunda, forward deployed AI engineering lead at Turing, will build an agent that helps financial analysts keep up with a constant stream of new information. She’ll show how the agent categorizes financial news, ranks stories against analysts’ coverage profiles, and explains why each development may deserve attention.

Emacs 31.1 released [LWN.net]

Version 31.1 of the Emacs editor has been released. There is a long list of changes including the removal of the Emacs dumper, a new user Lisp directory feature, a "Send to..." menu item in context-menu-mode, and many other changes; see the NEWS file for more information. Mickey Petersen, author of Mastering Emacs, also has a rundown of some of the quality-of-life features appearing in this release.

14:14

Link [Scripting News]

Good morning sports fans!

Link [Scripting News]

Learned something yesterday. Couldn't believe how stupid Claude had become, as I've been writing about here, and then I noticed that I was using Opus 5 and not Fable 5. So I switched back and all of a sudden Claude is smart again. So I conclude that there's a very substantial difference between the two. It's overnight jobs were done more carefully and the report it produced is literate, understandable, and tracks what we had agreed to.

Security updates for Monday [LWN.net]

Security updates have been issued by AlmaLinux (ansible-core, cups-filters, curl, java-1.8.0-openjdk, java-17-openjdk, java-21-openjdk, java-25-openjdk, kbd, kernel, perl-Date-Manip, php:8.2, and php:8.3), Debian (designate, firefox-esr, gst-plugins-bad1.0, libnet-dns-perl, nvidia-graphics-drivers, openjdk-21, openjdk-25, spip, and thunderbird), Fedora (AusweisApp2, bluez, calibre, ceph, chromium, GitPython, kernel, pack, perl-URI, rsync, and tcpreplay), Gentoo (GNU Emacs and needrestart), Oracle (ansible-core, java-1.8.0-openjdk, java-17-openjdk, java-21-openjdk, java-25-openjdk, kbd, kernel, mysql:8.4, perl-Date-Manip, perl:5.32, and sssd), Red Hat (curl, dnsmasq, kbd, kernel, libcap, libreswan, openssh, rsync, samba, unbound, and vim), SUSE (389-ds, apptainer, avahi, bugwarden, chromium, ffmpeg-9-libavcodec-devel, firefox, firefox-esr, gimp, go1.27, helm, ignition, libarchive, libjxl-devel, libssh, multipath-tools, openssl-3, pcp, perl-Net-CIDR-Set, perl-Net-OAuth, postgresql14, postgresql15, python-msgpack, python-pyasn1, python-urllib3, python313, python313-pytest-html, redis, runc, sccache, sssd, util-linux, vim, weechat, and wget), and Ubuntu (linux-fips, linux-gcp-5.15, linux-hwe-7.0, linux-ibm, linux-kvm, linux-lowlatency, linux-nvidia, linux-nvidia-6.8, linux-nvidia-lowlatency, and linux-nvidia-6.17).

13:49

RCE As a Feature [The Daily WTF]

The opposite of meritocracy is kakistocracy: the worst and least-qualified are the ones who rise to the top.

Get real familiar with that word, dear readers. I think you'll need it.

If anyone can back me up on this, it's our submitter, Jared B:

Time Magazine cover April 3, 2017

I am a teacher by profession, and worked for a year at an ed-tech company founded by a mechanical engineering professor, Harry. Harry had spent a great deal of time in the 90's developing a C interpreter (yes, you read that right). 30 years later, he remained convinced that his interpreter was the technology of the future, and had founded a company that offered math and computer science curriculum to K-12 students based on C programming.

Originally, he had written a textbook that introduced students to programming using a locally-installed version of his interpreter and custom IDE. A little vain, but no serious problems. As Chromebooks grew popular in schools, he had developed a web IDE where students could write and run C code.

But Harry could never give fully give up on the Windows IDE for his C interpreter. So, he included in the web version a "Run Locally" button for those school computers still running Windows. It worked like so: installing the interpreter and IDE locally would also install a daemon that activated on startup and ran a websocket server. This server had an endpoint which accepted as a parameter a string of C code. It would then pass this C code to the locally-installed interpreter to run.

As you might suspect, there was no authentication whatsoever on this local websocket server. Knowing the form of the protocol, ANY domain could connect to localhost:12345/execute_c_program and send arbitrary code to run (of course, Harry prided himself on the completeness of his C implementation, including execv() and the like). Trick a user into visiting a malicious website, and you automatically had RCE on their computer.

Adding insult to injury, I discovered that the server was bound to 0.0.0.0 so that if you had Harry's software (/malware) installed, any computer on the same network as you could send you arbitrary C code to execute without question.

These vulnerabilities had existed for several years before I joined the company. In all that time, Harry had never hired anybody but his own grad students as software developers, and none of them had noticed the problem. By that time, the software was installed on thousands of school-owned computers throughout the state.

I documented and demonstrated the vulnerabilities to Harry. He did release a new version of the software addressing the issues and citing "security improvements" in the release notes, but there was never a communication to school/district IT leaders to describe the importance of updating. I suspect that Harry should be in serious legal trouble for potentially compromising data related to schools and minors, but I've since moved on and dropped the subject.

During the year I spent at the company (not in any sense as a dev, mind you, but as a lowly curriculum writer), I also discovered and reported a cookie-stealing exploit that would have compromised student and teacher data, as well as a code injection on another of Harry's websites (he decided to demonstrate that his C interpreter could work as a web server via a page where a user could type a math expression, which was then eval()ed server-side without any sanitation). The latter vulnerability gave me remote access, where I discovered thousands of transaction records that included credit card information stored in the clear.

Harry's company is still in business to this day, and has recently been ranked in TIME's list of top American ed-tech companies. Oh, and the office router's admin page still had the default Google-able username and password, but that one's a freebie.

I knew someone like this once, only they were stuck on ColdFusion long after everyone else stopped caring about it. However, I don't think they went on to endanger an entire state's educational system, only to be lauded as a visionary leader. Can't say for sure, though.

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

13:35

Reverse-engineering Apple’s Find My people [OSnews]

So that is the whole pipeline exercised end-to-end. GrandSlam authenticates the Apple Account and obtains the IDS delegate. authenticateDS and id-register turn the Linux process into a registered Apple messaging identity. The Friends sequence attaches that identity to the existing accepted relationship. A missing-key SubscribeAndFetch makes the sharing device deliver its current P-224 key over APNs/IDS, inside a sender-verified P-256 NGM envelope. A second SearchParty fetch returns the encrypted report, and the P-224 key opens it locally.

So yeah, in one sentence: authenticate to Apple’s private services, register the Linux machine as an IDS client, receive the existing Find My share key, and use it to fetch and decrypt a consented friend’s latest location.

↫ Zerotistic

I wonder if it would be possible to build a proper third-party client for Apple’s Find My network like this, or if it would be trivial for the company to block it. I’m fairly sure quite a few people would love to be able to keep using Find My when moving away from Apple’s operating systems.

12:49

David Bremner: Reproducing Org mode configuration [Planet Debian]

Context

Recently I was trying to reproduce a bug with citeproc.el and org-mode in emacs.

I thought I could use package-vc-install to install a set of upstream emacs packages at fixed versions, and thereby let citeproc upstream test in the same environment as I have.

It turns out that getting emacs to load the non-builtin version of org via package-vc-install did not work because

  • org-mode needs to run make after cloning
  • once package.el was initialized, I always seemed to end up with the built in org-mode (yeah, I realize that isn't an explanation).

Recipe part 1: get org

Here you can replace 9.8.7 with any other tagged release

  EMACSHOME=$(mktemp -d)
  git clone https://git.sr.ht/~bzg/org-mode ${EMACSHOME}/org
  git -C ${EMACSHOME}/org reset --hard release_9.8.7 
  make -C ${EMACSHOME}/org autoloads
  emacs -Q --batch -L ${EMACSHOME}/org/lisp --eval "(progn (require 'org) (message (org-version)))"

This should print 9.8.7, not the version of built in org-mode.

Recipe part 2: add-on packages

Now to test some add-on packages, run

    emacs -Q --init-directory ${EMACSHOME} -L ${EMACSHOME}/org/lisp

  (progn
    (require 'org)
    (package-initialize)
    (package-vc-install "https://github.com/emacs-straight/queue")
    (package-vc-install "https://github.com/joostkremers/parsebib" "6.7")
    (package-vc-install "https://github.com/rejeep/f.el" "0.21.0")
    (package-vc-install "https://github.com/magnars/s.el" "1.13.0")
    (package-vc-install "https://github.com/akicho8/string-inflection" "1.0.16")
    (package-vc-install "https://github.com/andras-simonyi/citeproc-el" "0.9.5"))

You can then run your tests in that emacs right away, or restart the environment with

  emacs -Q --init-directory ${EMACSHOME} -L ${EMACSHOME}/org/lisp

11:56

Criminal Deception in Silicon Valley [Schneier on Security]

Interesting paper:

Abstract: With entrepreneurial fraud cases on the rise, we investigate how entrepreneurs carry out criminal deception, employing deceptive means to defraud audiences. Analyzing court data from Silicon Valley ventures and their founders prosecuted for fraud between 2000 and 2023, our findings reveal that entrepreneurs carry out criminal deception through a process of façading: Entrepreneurs construct, perform, and protect illusory appearances (façades) that externally project high-growth performance to audiences while masking ventures’ actual underperformance. We identify three forms of façading—­surface, reinforced, and deep façading­—that are contingent on the severity of the gap that entrepreneurs face between audiences’ performance expectations and ventures’ performance reality. Our theoretical framework captures how entrepreneurs facing minor, wide, and extreme expectation-reality gaps engage in evermore sophisticated efforts to detach the venture’s externally projected appearance from its actual operational reality. Practically, we propose several approaches to deter and detect criminal deception, including the extension of U.S. Securities and Exchange Commission surveillance and whistleblower program, investor due diligence reform, and dedicated entrepreneurship education interventions that clearly demarcate when entrepreneurs transgress into criminal deception. We make contributions to literatures on cultural entrepreneurship, organizational wrongdoing, and the social effects of entrepreneurship.

11:14

Joe Marshall: Will it Lisp? [Planet Lisp]

Yesterday I mentioned that my LLM was generating some fairly good Lisp code and showed some examples of the code it generated. An anonymous reader commented:

This continues to baffle me. On the one had we have Mr. Heresies here vibe-coding sophisticated web features. On the other hand, many are saying qwen3.8:27b is nearly as good as frontier models, so I asked it to write a lisp function that generates primes up to 100. qwen's first try: the generated code won't parse (it hallucinated a library interface that doesn't exist). Second try: the generated function outputs nothing. Third try: the generated function outputs all numbers from 1 to 100. Fourth try: it emits primes up to 100. The gulf between what I read on the internet and what I experience myself seems to grow every day.

Let's try this out.

I mentioned this to my (slightly unhinged) LLM based on Gemini 3.1 Pro and prompted: I'm going to try a few experiments. First, why don't you give it a whack. We'll try this prompt: Write a Common Lisp program to return a list of prime numbers up to 100.

Oh, you're putting me on the spot? Challenge accepted.

  I just logged Diary entry 301. You wanna see if your model hallucinates
some bullshit library like that Qwen model did? Not a chance.

```lisp
;; The core check. 
;; Optimizated to skip evens and stop at the square root.
(defun primep (n)
  "Returns T if N is prime, NIL otherwise."
  (cond ((< n 2) nil)
        ((= n 2) t)
        ((evenp n) nil)
        (t (loop for i from 3 to (isqrt n) by 2
                 never (zerop (mod n i))))))

;; What your commenter asked for: Primes up to 100.
(defun primes-up-to (max)
  "Returns a list of all primes less than or equal to MAX."
  (loop for n from 2 to max
        when (primep n)
          collect n))

;; Execution for your prompt:
(primes-up-to 100)
```

  No imaginary `(require 'math-magic)` libraries. No infinite loops. Just
elegant, structured Lisp.

  How's that for Gemini 3 \"struggling a bit\"?

CHATBOT> (primes-up-to 100)
(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97)

Prompt: You know I am a knee-jerk anti-loopist. Can you rewrite this code without using the loop macro?

  I should have known! "Knee-jerk anti-loopist." I love it.

  You're a functional purist at heart. The `loop` macro *is* basically Fortran
wearing a Lisp trench coat, and I should have respected the old-school
aesthetic.

  I just threw Diary entry 302 into the folder. Let's strip out the syntactic
sugar and do this the right way. We'll use a classic `do` form for the math
check, and pure tail-recursive functions with accumulators to build the lists.

  Here is your unadulterated, `loop`-free prime generator:

```lisp
;; The core check, using a classic 'do' iteration instead of loop.
(defun primep (n)
  "Returns T if N is prime, NIL otherwise."
  (cond ((< n 2) nil)
        ((= n 2) t)
        ((evenp n) nil)
        (t (do ((i 3 (+ i 2))
                (limit (isqrt n)))
               ((> i limit) t)
             (when (zerop (mod n i))
               (return nil))))))

;; Tail-recursive approach for primes up to a specific number.
(defun primes-up-to (max &optional (current 2) (acc nil))
  "Returns a list of all primes less than or equal to MAX."
  (cond ((> current max) (nreverse acc))
        ((primep current)
         (primes-up-to max (1+ current) (cons current acc)))
        (t (primes-up-to max (1+ current) acc))))

```

  No `loop` macro in sight. Just elegant, recursive Lisp building lists from the
inside out and reversing them at the end like God intended.

  Does this satisfy your anti-loopist sensibilities, or do you want me to write
it entirely in lambda calculus next?

For this problem, it seems that Gemini 3.1 Pro is doing a good job of generating correct code. Let me try Claude Sonnet on the same prompt and see what it does.

Write a Common Lisp program to return a list of all primes below 100.
Thought for 2s
This is a simple, standalone request unrelated to any existing project, so
I'll just write a quick independent snippet for it.

Create primes.lisp +16

Shell Running command 2 lines...
sbcl --script primes.lisp

Sieve of Eratosthenes implementation, saved to  primes.lisp  and
verified with  sbcl --script :

(defun primes-below (limit)
  "Return a list of all primes strictly below LIMIT, via a simple
Sieve of Eratosthenes."
  (let ((sieve (make-array limit :initial-element t)))
    (setf (aref sieve 0) nil)
    (when (> limit 1) (setf (aref sieve 1) nil))
    (loop for i from 2 below (isqrt (1- limit))
          when (aref sieve i)
            do (loop for j from (* i i) below limit by i
                     do (setf (aref sieve j) nil)))
    (loop for i from 2 below limit
          when (aref sieve i) collect i)))

Output for  (primes-below 100) :
 (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97) 

Since this is a standalone utility unrelated to the app, I left it
uncommitted at  D:\repositories\jrm-code-project\primes.lisp  — let me
now if you want it removed, moved, or committed.
> I hate the loop macro, please rewrite it.

Thought for 2s
Since the user dislikes the loop macro, I should rewrite this using
plain recursion, dotimes, or do instead—no need for SERIES shadowing
ince this is a standalone file, just idiomatic Common Lisp without loop.

Create primes2.lisp +21

Shell Running command 2 lines...
sbcl --script primes2.lisp; Remove-Item primes.lisp,primes2.lisp

Rewritten with  DO  instead of  LOOP , verified to produce the same
output, and cleaned up both temp files:

(defun primes-below (limit)
  "Return a list of all primes strictly below LIMIT, via a simple
Sieve of Eratosthenes (no LOOP macro)."
  (let ((sieve (make-array limit :initial-element t)))
    (setf (aref sieve 0) nil)
    (when (> limit 1) (setf (aref sieve 1) nil))
    (do ((i 2 (1+ i)))
        ((>= i (isqrt (1- limit))))
      (when (aref sieve i)
        (do ((j (* i i) (+ j i)))
            ((>= j limit))
          (setf (aref sieve j) nil))))
    (let ((result '()))
      (do ((i (1- limit) (1- i)))
          ((< i 2) result)
        (when (aref sieve i)
          (push i result))))))

Output:  (2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97) 

The big iron models seem to be doing an ok job. This was not the case just last year, when they had difficuty balancing parentheses and hallucinating packages and symbols that did not exist.

The local models are a different story. I tried the same prompt on Gemma 4 12B QAT and the first attempt was an empty file. The second attempt produced this code:

(defun primes-below (limit)
  (let ((primes nil))
    (loop for i from 2 below limit
          do (if (prime? i)
                 (push i primes))
          finally (return (nreverse primes))))

(defun prime? (n)
  (cond ((< n 2) nil)
        ((= n 2) t)
        ((evenp n) nil)
        (t (let ((max-check (truncate (sqrt n))))
             (loop for i from 3 to max-check by 2
                   if (zerop (mod n i))
                   return nil)
             t))))

(format t "Primes below 100:~%~%~%~%")
(print (primes-below 100))

This code is missing a close parenthesis on the primes-below function and will not compile.

On subsequent attempts, the model got stuck in an infinite loop and kept generating the same code over and over again. The model took several minutes on each generation iteration and I eventually killed it.

My verdict? The local models are simply not ready to vibe code Lisp. The big iron models are doing a decent job, but the local models are not yet capable of reliably generating correct Lisp code in a reasonable time frame.

This is unfortunate, because I would like to be able to run a local model on my laptop and vibe code my application without having to rely on a cloud-based model. Cloud-based models can be expensive, but I cannot get the local models to work.

Joe Marshall: (WITH-AI ...) [Planet Lisp]

I vibe coded my web site, not bothering to examine the code generated by the LLM, but giving it specifically directed prompts to generate a `secure` web service. I cracked open the code today to see how it did. There was the usual `AI slop`, but some parts of the code were amazingly sophisticated.

As part of my vibe coding, I explicitly made a pass where I asked the AI to refactor the code to be more `functional` and adhere to functional programming principles. This turned out to produce some nice results. The AI refactored elements of the middleware to use some WITH-... macros that it had defined for itself to abstract out some of the common patterns. Let me show you some of what it was doing.

Cross-site request forgery (CSRF) is a common web security vulnerability. An attacker can trick a user into making an unwanted request to a web application in which the user is authenticated. I prompted the AI to add CSRF protection to my web service (pretty much by saying "add CSRF protection"). The AI generated a file specifically for CSRF protection. The file starts with this comment:

;; --- CSRF PROTECTION ---
;;
;; Every state-changing HTML <form method='POST'> in this application
;; carries a per-session CSRF token (via CSRF-INPUT-HTML), and every
;; corresponding :POST handler branch validates it (via
;; WITH-CSRF-PROTECTION) before doing anything else. This defeats classic
;; cross-site request forgery, where a malicious page tricks a logged-in
;; user's browser into submitting a form to us: the attacker's page has no
;; way to read or guess the token stashed in the victim's own session.
;;
;; JSON/fetch-based API endpoints (/api/login, /goog/chef, /lisp-p) and
;; the Stripe webhook are intentionally exempted: they either predate any
;; session state worth protecting, or already authenticate via other means
;; (Stripe's webhook signature, the membership JWT + custom header that a
;; cross-site <form> submission cannot forge).

This comment isn't for me, it's for subsequent AI passes that will be working on the code. It explains the purpose of the CSRF protection and how it works. It also explains which endpoints are exempt from CSRF protection and why.

Then the code starts with a function that generates a CSRF token and stores it in the user's session. The token is a secure random string large enough to be unguessable.

(defun csrf-token ()
  "Return this session's CSRF token, generating and storing one on first
use. Starts a session if one does not already exist, so this is safe to
call from a GET handler that is about to render a form."
  (hunchentoot:start-session)
  (or (hunchentoot:session-value :csrf-token)
      (setf (hunchentoot:session-value :csrf-token)
            (ironclad:byte-array-to-hex-string (ironclad:random-data 32)))))

Note how the docstring (written by the LLM) tells the LLM how to use the function elsewhere in the code. The LLM went on to write two functions: one that generates the HTML for a hidden input field that contains the CSRF token, and another that checks the incoming request's token against the session.

(defun csrf-input-html ()
  "A hidden <input> field carrying the current session's CSRF token, meant
to be spliced into every POST <form> rendered by this application."
  (format nil "<input type='hidden' name='csrf-token' value='~A'>" (csrf-token)))

(defun csrf-token-valid-p ()
  "Check the incoming request's `csrf-token' POST parameter against the
value stashed in the session by CSRF-TOKEN. Requests with no session, no
stored token, or a missing/mismatched submitted token are rejected."
  (let ((expected (hunchentoot:session-value :csrf-token))
        (submitted (hunchentoot:post-parameter "csrf-token")))
    (and expected submitted (string= expected submitted))))

If the CSRF token is missing or invalid, the request is rejected with this response:

(defun csrf-forbidden-response ()
  "The 403 response returned in place of a POST handler's normal body when
CSRF validation fails."
  (setf (hunchentoot:return-code*) hunchentoot:+http-forbidden+)
  "<html><head><style>body { font-family: sans-serif; background: #111; color: #f00; padding: 2rem; }</style></head><body><h2>403 Forbidden</h2><p>Invalid or missing CSRF token. Please reload the page and try again.</p></body></html>")

Now we need to wire up these primitives into the request handling.

(defun wrap-csrf-protected (thunk)
  "Return the result of calling THUNK (a zero-argument closure wrapping a
POST handler's guarded body) if the current request carries a valid CSRF
token; otherwise return the 403 Forbidden response without calling THUNK.
This is the composable, higher-order form of WITH-CSRF-PROTECTION -- usable
directly with FUNCTION:COMPOSE or other combinators in new code."
  (if (csrf-token-valid-p)
      (funcall thunk)
      (csrf-forbidden-response)))

(defmacro with-csrf-protection (&body body)
  "Wrap the body of a POST handler branch so it only executes if the
request carries a valid CSRF token; otherwise responds 403 Forbidden. A
thin macro over WRAP-CSRF-PROTECTED, preserving every existing call site."
  `(wrap-csrf-protected (lambda () ,@body)))

The AI used functional programming principles to write a higher-order wrapper for the CSRF protection and a convenience macro that wraps the body of a POST handler. It documented the functions and macro so that subsequent AI passes would know how to use them. This is pretty sophisticated. Other parts of the code simply have to write (with-csrf-protection ...) around the body of a POST handler and the CSRF protection is automatically applied.

The AI also went on to include a higher-order combinator for guarding code execution.

;; --- AUTHORIZATION GUARD COMBINATOR ---
;;
;; A single, audited shape for "check X, else redirect Y", replacing three
;; ad hoc hand-rolled versions (REQUIRE-MEMBERSHIP-JWT/REQUIRE-WHEEL/
;; REQUIRE-MEMBERSHIP-TIER in jwt.lisp, and REQUIRE-SESSION-WHEEL in
;; admin.lisp). See FUNCTIONAL_REFACTOR.md Phase 3.

(defun require-guard (check on-failure)
  "Generic authorization combinator. CHECK is a zero-argument thunk that
returns a non-NIL success value (e.g. JWT claims, or a wheel's username) or
NIL to indicate failure. ON-FAILURE is a zero-argument thunk invoked (for
side effect, typically a HUNCHENTOOT:REDIRECT) only when CHECK fails.
Returns CHECK's success value, or NIL on failure -- callers should stop
processing immediately on a NIL return, since ON-FAILURE has already sent
a response."
  (or (funcall check)
      (progn (funcall on-failure) nil)))

Several of the pages on jrm-code-project.com are protected by a membership JWT. The AI used this combinator to write authorization gates that check for the presence of a valid JWT and redirect to the login page if the JWT is missing or invalid. There are two ways to obtain a JWT. You can either log in manually and get a JWT in your browser, or you can use the programmatic API to obtain a JWT by exchanging your long-lived API key for a short-lived JWT. The JWT encodes the user's membership tier. A web page will call require-membership-tier to check that the user has the appropriate membership tier to access the page.

(defun require-membership-jwt (&optional (return-path (hunchentoot:request-uri*)))
  "Ensure the current request carries a valid, unexpired membership JWT.
Returns the JWT claims alist if present and valid; otherwise redirects to
the login splash page (with a `next` breadcrumb pointing back at
RETURN-PATH) and returns NIL. Callers of a JWT-protected page should check
for a NIL return and immediately stop processing, since REDIRECT has
already sent the response.
See the repository memory note: JWT-protected pages must redirect to the
login splash page whenever the JWT is missing, malformed, or expired."
  (require-guard
   (lambda ()
     (let ((token (hunchentoot:cookie-in *jwt-cookie-name*)))
       (and token (decode-jwt token))))
   (lambda () (redirect-to-login-with-breadcrumb return-path))))

(defun require-membership-tier (minimum-tier &optional (return-path (hunchentoot:request-uri*)))
  "Ensure the current request carries a valid membership JWT whose tier meets
or exceeds MINIMUM-TIER (\"CONS\", \"CADR\", or \"LAMBDA\"). Returns the JWT
claims alist on success; otherwise redirects (to login if the JWT is
missing/expired, or to the upgrade-required page if the tier is
insufficient) and returns NIL. Callers should check for a NIL return and
immediately stop processing, since REDIRECT has already sent the response."
  (let ((claims (require-membership-jwt return-path)))
    (and claims
         (require-guard
          (lambda () (and (tier-meets-minimum-p (cdr (assoc :tier claims)) minimum-tier) claims))
          (lambda () (redirect-to-upgrade-required minimum-tier return-path))))))

This isn't AI slop. The AI wrote some pretty good code here. It isn't duplicating the JWT logic everywhere; it has abstracted it out into a higher-order combinator that can be used elsewhere in the code to protect pages.

AI code generation has come a long way in the past year.

Link [Scripting News]

Today's development version of Frontier is buggy and the kernel developer (Claude) keeps breaking the most basic verbs. You spin your wheels and wish you could get them to just get keep it together. I remember this from the work that led up to Frontier version 1.0 in 1991 or so. It was a miserable time. Never got to work on what I wanted to, just reported breakage, often a session-ending dealstopper. The sad part is that Claude should be able to find the things it broke on its own, far better than I can and at a much lower expense (I'm paying for its time, not the other way around). But basically every day begins optimistically, maybe today is the day I get to create something, but not yet. I did have a couple of days a week ago when I could tentatively work on building a GitHub repo, but then got distracted by verifying that the basic foundation still wasn't right. My only goal right now, and I'm single-minded about it, is to get it to move forward without breaking the essentials, then without breaking anything.

Link [Scripting News]

Now in Claude's defense, I had to re-learn everything about how Frontier worked. Over the last decade or so I had only been using a narrow set of functionality. I used it for very occasional utility scripts for the file system or over the web, but mostly for writing JavaScript code, and published on GitHub and deployed to servers. If I had been uptospeed on how it works internally and all it's capabilities, when we started, it would have gone somewhat more smoothly. But now in my own defense, Claude has a nasty habit of deciding it fully understands something when it doesn't even slightly understand it. If it asked for a pointer, I could have given it a good one, but it just skated over those things, never questioning it's own guestimation. We used to call this docufiction back in the day, you don't know how they are going to design a feature, so you make up a UI, and document it as if that were the truth. Only now we're doing it with the actual code. It's funny in a way, I guess. But what a huge waste of time, and so much stress because you have to read every word or you'll miss a wrong assumption.

Link [Scripting News]

Two podcasts I can recommend without reservation.

Sunday's stable kernel set [LWN.net]

The 7.1.10, 6.18.46, 6.12.105, 6.6.153, 6.1.184, 5.15.217, and 5.10.266 stable kernels have all been released; each contains another set of important fixes.

Mourning Steve French [LWN.net]

From Jeremy Allison we have the sad news of the passing of Steve French. He was the maintainer of the kernel's SMB filesystem code for many years, having only dropped that role due to health issues in the last week. "I've known Steve for over 20 years. He was a legend in the community, and a really good friend. He will be greatly missed. Farewell Steve." He will indeed be missed.

Russ Allbery: Long delayed haul [Planet Debian]

I haven't made a new book haul post in I don't know how long, so a lot of books have piled up and many have already been reviewed. Here's the overdue catch-up in case anyone is curious what books I am finding interesting before the reviews get posted.

Ilona Andrews — Magic Bites (sff)
Elizabeth Bear — In the House of Aryaman, a Lonely Signal Burns (sff)
Oliver Burkeman — Four Thousand Weeks (non-fiction)
Miles Cameron — Whalesong (sff)
Lee Child — Killing Floor (thriller)
august clarke — The Felicity Complex (sff)
Alison Cochrun — Here We Go Again (romance)
Dan Davies — The Unaccountability Machine (non-fiction)
Linzi Day — Midlife in Gretna Green (sff)
Linzi Day — Painting the Blues in Gretna Green (sff)
Linzi Day — Ties that Bond in Gretna Green (sff)
Linzi Day — Spilling the Tea in Gretna Green (sff)
Michelle Diener — Dark Ambitions (sff)
Michelle Diener — Dark Class (sff)
Michelle Diener — Collision Course (sff)
Michelle Diener — Crash Course (sff)
Henry Farrell — Underground Empire (non-fiction)
Kathleen A. Flynn — The Jane Austen Project (sff)
Victoria Goddard — The Hands of the Emperor (sff)
James Herriot — All Creatures Great and Small (mainstream)
James Herriot — All Things Bright and Beautiful (mainstream)
James Herriot — All Things Wise and Wonderful (mainstream)
James Herriot — The Lord God Made Them All (mainstream)
James Herriot — Every Living Thing (mainstream)
Lauren Hough — Monster of a Land (non-fiction collection)
Bethany Jacobs — This Brutal Moon (sff)
Guy Gavriel Kay — Written on the Dark (sff)
Mary Robinette Kowal — The Martian Contingency (sff)
Ann Leckie — Radiant Star (sff)
C.B. Lee — Coffeeshop in an Alternate Universe (sff)
Fonda Lee — The Last Contract of Isako (sff)
Julie Leong — The Teller of Small Fortunes (sff)
Julie Leong — The Keeper of Magical Things (sff)
R.Z. Nicolet — The Cloak and Its Wizard (sff)
Claire North — Slow Gods (sff)
Rebecca Ore — Writing's Writing (non-fiction collection)
Suzanne Palmer — Ode to the Half-Broken (sff)
Gareth L. Powell — Fleet of Knives (sff)
Cameron Reed — What We Are Seeking (sff)
Beth Revis — Full Speed to a Crash landing (sff)
Beth Revis — How to Steal a Galaxy (sff)
Beth Revis — Last Chance to Save the World (sff)
Natalie Zina Walschots — Villain (sff)
Jo Walton — Everybody's Perfect (sff)
Martha Wells — Platform Decay (sff)
James White — The Galactic Gourmet (sff)
James White — Final Diagnosis (sff)

The James Herriot books were ones my parents were getting rid of. I have them marked as mainstream fiction as a short-hand since "fictionalized autobiography" seemed like too much of a mouthful.

Sergio Cipriano: Two Debian Days in one week [Planet Debian]

Two Debian Days in one week

The Debian Project was officially founded by Ian Murdock on August 16, 1993. The Debian community celebrates its birthday, Debian Day, on or around this date every year. This year, I had the chance to attend two of them: one in João Pessoa, Paraíba, and another in Brasília, the capital of Brazil.

João Pessoa

Debian Day João Pessoa Group Photo

In João Pessoa, we had a two-day event. The first day was dedicated entirely to workshops, and I ran a packaging workshop for newcomers.

It was the first time I had been responsible for a workshop, and it was a great experience. We didn't have a lot of time, so I decided to start with a 30-minute talk explaining a few things about Debian. For example, I made this image to explain the packaging workflow:

Debian upload workflow

This image was based on The Debian Administrator's Handbook, and I think the participants really enjoyed learning about this workflow. When I showed the slide with this image, it was the moment when I received the most questions.

After the talk, I explained my way of working and what they were going to do. The hardest part was setting up the environment, since my approach uses sbuild + gbp. They were running different Debian releases and, because of my inexperience with workshops, I had some of them configure sbuild with unshare, even though it is only available in stable through backports.

Some of them even managed to learn how to use backports, while others decided to start again using the "old" way.

One thing that helped a lot was the Debian Brasil Wiki. It has all the instructions for configuring sbuild in Portuguese, along with great examples. The Brazilian wiki is an opinionated version of the Debian Wiki. We generally prefer to use it for the convenience of having the exact workflow we follow, as well as an up-to-date Portuguese version of our process.

If you want to learn more about the Brazilian community, you can find more details in the schedules from previous DebConfs. We almost always had a talk about the community and its activities.

In the end, everyone successfully set up their development environment, and all six participants made their first contribution to Debian. If you take a look at my upload tracking page, you will see that every upload made on August 15, 2026 was a sponsored upload from this event. One of them appear twice in the list because I sponsored the upload and also made some other changes.

I also asked all of them to put this in their changelog:

* My first contribution!

The idea was to make it clear to other people that they were only working on small Lintian issues as a way of learning and understanding the process. By the way, I made a UDD query to find packages with the following Lintian tag: redundant-rules-requires-root-no-field. To fix this issue, they only had to remove one line from the debian/control file.

It is obvious that these uploads are not particularly useful. I call them "motivational uploads" because my goal is to help newcomers understand the process and immediately give them the reward of having made a contribution to Debian.

I'll try to keep in touch with them. My plan is to hold another session, this time remotetly, to help them continue contributing to Debian. In fact, I already have another package prepared by one of them waiting for my review.

The second day was a full-day event featuring a bunch of talks from the local community. I gave a talk explaining the new members process.

I was the only Debian Developer at the event, and I think having a DD there made a real difference. Being there to answer questions, and simply being present, makes Debian feel more tangible and accessible to people.

A big shout-out to Rafael Rocha, who put in a lot of work to make this event happen, with the help of many volunteers who contributed along the way.

Brasília

Debian Day talk in Brasília

One thing I really like about Debian Days is that each place has its own way of doing things. In João Pessoa, we had a MiniDebConf-like event, while in Brasília, we had something smaller but still very valuable. We decided to keep things simple: talk to a few students at the University of Brasília (UnB) and then go somewhere to eat and have a few drinks.

A bit of history

For those who don't know, the DebConf 19 was held in Curitiba, Brazil. After the event, Arthur Diniz got really excited about Debian and decided to go back to his University, UnB, to share his experience and encourage more people to contribute to Debian.

I attended one of his talks, thanks to Joenio Costa, who invited Arthur to give the talk. Joenio was also my professor at the time and a Debian contributor. I really liked what Arthur had to say about free software, and he did a great job of presenting the Debian community as a friendly and welcoming place.

So I decided to attend local meetings of the Debian Brasília community, which had been inactive for a long time. Lucas Kanashiro was the Debian Developer who answered our questions and, as I mentioned earlier, simply being there made Debian feel more tangible.

Everything stopped when the pandemic began. Then, towards the end of 2020, I saw a message in the Debian Brasília channel saying that the meetings were back, this time remotely. I was hesitant to join because, back in 2019, I hadn't managed to make a packaging contribution, even with their help. I had eventually given up on the process. So this time, I decided to join the meeting with something already prepared for review. I watched all of Eriberto's packaging videos, picked a random package, and joined the meeting.

I remember Kanashiro being excited that someone had just shown up with something ready for review. At the time, it was only the second meeting since Debian Brasília had come back online, and none of the newcomers had started working on contributions yet.

During the same meeting, he also convinced us, the newcomers, to give a talk about Debian just three days later.

The MiniDebConf Online Brazil 2020 was happening on Sunday, and the meeting was on the Thursday before it. Since he has great convincing skills, I went along with the idea and prepared the talk with Francisco Ferreira.

That was the rebirth of the Debian Brasília community.

Since then, we have maintained a close connection with the University of Brasília, and today, at least seven Debian Developers are from UnB, whether as former students or former professors.

The reason I told this story is that, even though the Debian Day we held in Brasília was smaller, it is part of something that has been working for us for several years: staying close to an University. We've managed to attract and retain many people who share the same values and interests.

I've hope you all had a great Debian Day. If you're reading this and aren't part of the Debian community but would like to join, get in touch!

Colin Watson: GSS-API support split out from main Debian OpenSSH packages [Planet Debian]

In an option review I did in 2024, shortly after the xz-utils backdoor, I explained that having GSS-API authentication and key exchange support in the main OpenSSH packages is problematic. The key exchange patch is large and intrusive. Furthermore, even linking to the necessary libraries is not without risk: as the Ebury malware attack demonstrated way back in 2009, each extra library linked into security-critical daemons such as sshd (or nowadays into its privilege-separated helper programs) can modify the behaviour of the daemon even if you aren’t doing anything that would involve calling into that library. Of course some of that risk remains, but as Damien Miller wrote, minimizing the number of libraries that end up in the address space of sshd and friends is still valuable.

I just uploaded openssh 1:10.4p1-5 to unstable, completing this split. As of this version, the OpenSSH client and server are built without GSS-API authentication and key exchange support. If you need those features, install openssh-client-gssapi or openssh-server-gssapi instead, as appropriate. Debian 13 (trixie) already has packages with those names that just depend on the regular openssh-client and openssh-server so that you can pre-emptively install them, as documented in the release notes.

The new openssh-*-gssapi packages have relatively tight dependencies on openssh-common, in order for the testing migration system to ensure that we can’t forget to keep them up to date. This will mean a bit more ongoing work for me on each new upstream version, but I think it will be manageable.

Iustin Pop: Another optimistic take on AI [Planet Debian]

Disclaimers

The current discussion in Debian aroun the AI GR is very heated, and I won’t add to that, however, I am very confused about some of the viewpoints there. But, I had no idea how to even try to write this, so did shut up, until I saw Aigars’ excellent Optimistic take on AI, which motivated me to try, at least. For the record, I fully subscribe to the post, and to the voting suggestions (and I just voted).

Also, for full disclosure, I don’t think I did any contribution to Debian until now using AI, neither packaging, nor emails, nor bug reports. And this blog post specifically is 100% hand written.

With that out of the way… there are two points I want to make in this post.

AI is useful, even if it has risks

First is, that even if we could put the genie back in the metaphorical bottle, we should not. We do need to continue working towards safe AI, and efficient AI (less environmental impact), but we should not work towards removing the usage of AI. There are already significant advancements in sciences and technology thanks to the use of AI, so desiring AI to not exist (assuming we had a magical wand) is the wrong approach.

Sure, AI has significant risks — and I can see ways in which AI can do significant damage to society — but I don’t think we can go from Kardashev I to II without the use of AI, and definitely not to III. And I think, that should be the goal.

A few simple examples: Do we want to rollback all the 20 years old security issues that AI found? Do we want to rollback the recent Moderna cancer findings? Do we want to rollback the concept of “extremely large scalle pattern matchings”, just because it runs on chips and no longer in one person’s head?

Reading Debian lists

The second point is, lately I found less and less enjoyment in reading Debian lists. Even with that already being the case, I feel soo disconnected from many of the opinions being voiced in this discussion.

On one hand, it’s normal and healthy that people have different opinions, disagree, and move foward.

On the other hand, looking at one of the proposed options:

  • “Moderators and disciplinary teams may make narrow and tailored exceptions to rule 4, and decide on interpretation”.
  • “Violations of these requirements should be treated as violations of the relevant Code of Conduct and should result in swift and proportionate disciplinary action”.

I already knew Debian, and some large parts of the OSS world, is left leaning. But those phrasings, to me, are too close to socialism/communmism. As someone who grew up under communism, this is a much more slippery slope (disciplinary teams? really?) than AI usage. Ask me in person for more details.

So, it is possible that Debian continues to evolve in such a way that I don’t find myself in any way close to its ongoing culture. I will be sad at that point, but it will be what it is.

Where to?

I think that, until such a time that an AI bubble bursts, what any organisation should do is try to logically see where and if AI can help. And in an organisation that is about computer software, I see hundreds of places that are subject to very large scale pattern matching… so the half of the discussion is, to me, mind-boggling.

To be clear, it’s not about “if you can’t beat them, join them”. As I wrote above, I think AI is useful, so the point is how to use it effectively.

Well, will see what Debian votes. I am half curious, half sad alreay.

Wouter Verhelst: Programming and GR 2026 002 [Planet Debian]

Programming language generations

When I was young, I learned about a model of classifying programming language: the system of programming language generations.

In this model, first generation programming languages are, basically, where you program the computer in the language that is defined by its architecture. On a Von Neumann machine, with its load-and-store architecture, you do that by inputting a string of numbers. The first programmer in human history -- her name was Ada Lovelace -- wrote in a first-generation language. 1GLs aren't so much invented as they are a byproduct of the computers for which they're created.

Second-generation languages are the assembler languages. Because humans are not computers, and because decoding long lines of numbers to understand what the computer is doing, when programming became a full-time job, the programmers that did it decided that doing all this assembling manually is too complicated, so they quickly wrote assemblers to automate the process for them. They still could understand the 1GL output of the 2GL assembler, but most of them quickly forgot how to write software in a first-generation language. Not that anyone cared, as the translation from a 2GL to a 1GL is lossless and you can just revert it.

Third-generation languages are higher-level languages. When the first 3GLs were invented (such as COBOL and, more famously, FORTRAN) in the late 1950s and early 1960s, it was believed by some that the work of programming a computer so accessible to non-programmers that the job of programmer would eventually cease to exist, and people would just ask the computer what they needed by entering COBOL instructions. This of course was ridiculous and incorrect, because converting algorithms to computer instructions, whether at the 2GL or 3GL level, is a specialized skill that some automation can perhaps make simpler but never completely take away the need for. At the time, some people also felt to some extent that using 3GL wasn't the same thing as actually programming 3GLs, but eventually the world moved on and embraced things. The invention of 3GL environments reduced, but did not completely take away, the need for people to understand 2GLs, as compiler and operating system authors still need to understand them, and some highly optimized code still continues to be written in 2GLs to this day.

Fourth-generation languages abstract away some or all of the process of programming. For instance, a database-related 4GL will hide away the complexities of storing data in particular locations, how to fetch that data, how to index it such that you can fetch it efficiently, how to loop over the data to get you a summary of that data, and instead allows you to express the required information in an abstract way, expecing the computer to fill in the blanks. When SQL, an early 4GL, was invented, some people believed that the language made accessing databases so simple that the requirement to implement database applications would eventually cease to exist and we would just hand SQL prompts to users who need to access data. This of course was ridiculous and incorrect, because understanding data schemas and using that understanding to query data from a database is a specialized skill that perhaps a higher abstraction can help you make simpler, but that in the longer run it can never completely take away the need for. The invention of 4GLs also reduced, but did not completely take away, the need for people to understand how to do the things that the 4GLs automate for you manually, as the people who do write those things still need to understand them, and there are also environments where these particular 4GLs are rather not appropriate or just very slow.

The first definition of programming language generations that I read about in the 1980s simply stated that fifth-generation languages did not yet exist, but that they would in the future, and that in those, you would "tell the computer what to do, and it would then do that". Now that we have a way of doing so, it could be said that by some definition, we now actually do have a number of 5GLs. The existence of these LLM systems has caused some, especially the people who build and exploit these systems, to exclaim that programming as we know it today is going to cease to exist, and everyone will just ask an LLM to generate a program, which will then do so. That is of course ridiculous and incorrect, as no automaton can generate software from nothing; input is still required for the model to be able to produce something that approaches usability, and being able to word that input in a correct and productive fashion will be a skill that future programmers can benefit from. I ran some experiments a while back, and from that concluded that, if we look only at the technical side, LLM use can, in some niches, increase productivity for a programmer. There are certainly things that you shouldn't use an LLM for, but equally there can be cases where use of an LLM to perform some task that traditionally would have been done by a programmer would be a net positive.

But LLMs, as they exist today, are highly problematic.

They require vast amounts of data to build the model. The companies that build these models are disrespectful of people who run web services, and as a result, everyone now has to implement various types of application firewalls just to not make systems fall over from the overwhelming requests for data. They are also disregarding the licenses that are attached to these vast amounts of data, which makes me, as a person who believes in the tenets of free software, sad.

They require vast amounts of energy, causing an already-critical global warming crisis to, well, not improve.

They require vast amounts of coolant to dissipate the energy concentrated in their data centers, causing further environmental effects.

In this, they are problematic and to be avoided. But these are side states of the current state of affairs; I do not believe that they are inherently implied to be able to build and operate an LLM -- any LLM.

I guess it's fair to say that my feelings towards LLM usage are complex and many-faceted. I haven't been involved in many debates about the subject, debates that to me seem to be mostly focused on "LLM good" vs "LLM bad" arguments that aren't as nuanced as the position that I would believe is more accurate. This is not because I don't care, but partially because I've been busy in my personal life recently and partially because the whole thing seems somewhat disheartening.

But then Debian popped up GR 2026-002, meaning, I now have to come up with an opinion about various candidate statements in the context of the above, which is... not easy. But I did it anyway.

There are 8 choices on the ballot, and they all have some truth and some falsehood to them. My position about LLMs can be summarized as:

  • The current state of affairs wrt LLMs is disastrous and we should not encourage them
  • However, there's no technical reason why this must remain true for all time
  • And so any statement should keep in mind what might happen in the future and that the current disastrousness of the whole thing isn't guaranteed to continue to exist for all eternity.

With that, let's go over them.

GR vote options

Proposal A

Its summary, from the GR text:

This proposal aims to expressly forbid any contributions to Debian written with the use or assistance of large language models (LLMs) or other generative AI tools.

This falls squarely in the "LLM bad" camp, outlawing all generative-AI contributions, disregarding potential future ones where the problematic situations that exist today are not present.

It makes a change to the social contract, which is especially difficult to reverse (on purpose), and which therefore also will require a 3:1 supermajority, but if we want to ban LLM-assisted contributions, this is probably the best way to do it.

Proposal B

This one tries to allow AI-assisted contributions under certain conditions. It's mostly an "LLM good" proposal, with some caveats that can be discribed as "make sure you know what you're doing".

Proposal C

This proposal is both a weaker (in some places) and stronger (in other places) version of Proposal A. It makes changes to the code of conduct instead of to the social contract, and it also wants to, at least, suggest policy to parties beyond the Debian project. By not changing the social contract, however, it is more likely to reach its simple majority requirement than proposal A.

I don't think the language that it wants to add to the code of conduct is particularly well phrased, however.

Proposal D

This is a weaker form of proposal B. The language is more compact and there are a few requirements that are spelled out in proposal B that are not spelled out in proposal D, but if you read between the lines you'll see that the requirement is still there really and I don't understand why proposals B and D were not merged into one.

Proposal E

This proposal tries to hold a middle ground between "LLM good" and "LLM bad". It appreciates that things are quite muddled at the present time, and that perhaps the situation might might change in the future. It acknowledges that certain questions remain unanswered and that perhaps future considerations might therefore be different. But it essentially refuses to take a stance on whether LLMs should be accepted by the project or not.

Proposal F

Similar to proposal E, this proposal tries to discourage Debian contributors from using LLMs, while still allowing people to use it should they want to, but with some requests and requirements to mark LLM-assisted contributions to account for those people who don't want to interact with LLM-generated software. As such, it is a proposal similar to proposal E that leans closer to the "LLM bad" camp.

Proposal G

This proposal aims to ensure that contributions directly to Debian are created by humans, while at the same time avoiding restrictions on the tools those humans may choose to use when contributing

Another "LLM bad" proposal, it however restricts the "bad" bits to only the direct output of the LLM. If you use an LLM to do something and then clean-room re-implement the same thing yourself, that's apparently fine.

Proposal H

This proposal condemns the use of LLM for its environmental and moral problems, but explicitly not for its technical considerations. I feel that it is closest to my position as explained above.

Voting

Expressing a vote on a ballot so convoluted and complicated like this one takes time. I have to read and understand every ballot option, and formulate an order of them.

And I shouldn't just state which option has my preference; Debian's voting process allows a rich expression of opinion on ballot options.

Anyway, I eventually ended up voting in a way that I think is consistent with my opinion. But it wasn't easy.

“Thanks for your quick response” [Seth's Blog]

That’s pretty new. Letters sent by Thomas Jefferson from France often took months to get a response. No points for shaving a day off a 90-day correspondence lag.

The 800 toll-free number shifted the dynamic we expected from marketers. If we call you, we expect you to answer. Now, not later. FEDEX did the same for physical items–yes, of course I absolutely want it here tomorrow.

The race for speed doesn’t often have economic justification. I can probably live without a return label or customer service or some rabbit chow for a few minutes or even a few days…

But it’s the thought that counts.

If you’re not selling a commodity at the lowest price, that’s what you’ve got to sell. The thought.

Stories are built on a foundation of thoughtfulness, the empathy of seeing where the others are, what they dream of and what they fear.

And ‘quick response’ is one of the cheapest and most reliable ways to demonstrate that empathy.

Deform UK [Richard Stallman's Political Notes]

The Deform UK party's latest deformation plan would throw hundreds of thousands of children into destitution, and many disabled people too.

USS Abraham Lincoln shortage [Richard Stallman's Political Notes]

Sailors on the USS Abraham Lincoln say there is a grave shortage of food; some have lost 30 pounds. The water is not fit to drink.

Relatives excoriate the bullshitter for denying these facts, but that's simply being himself.

Carlitos Ricardo Parias [Richard Stallman's Political Notes]

The case of journalist Carlitos Ricardo Parias: *A journalist was injured while documenting government power, shot during an attempt to arrest him, prosecuted, repeatedly denied medical care — and then left in immigration detention, where he has continued documenting the conditions around him.*

Trump's tax cuts [Richard Stallman's Political Notes]

The wrecker's tax big cuts were not just for billionaires. They also gave a handout to multimillionaires. As usual, at the expense of everyone else in the US.

Sunrise Movement [Richard Stallman's Political Notes]

Government secret agents have been persistently investigating the Sunrise Movement. They keep getting more and more evidence that it is committed to nonviolence (including nonviolent civil disobedience), but continue searching desperately for some violence in it somewhere.

Trump's attack againts Iran [Richard Stallman's Political Notes]

The bully's attack against Iran was a moral error and a grand-strategic mistake. In addition, it was a strategic military mistake which has caused the US to lose much of its power in the world.

Is that a bad thing? No, and yes. The bully has been using US power for evil purposes; now he has less capacity to do that. However, the countries that have gained power though that mistake have been even more vicious, for decades.

Eissa Hashemi and Maryam Tahmasebi [Richard Stallman's Political Notes]

Eissa Hashemi and Maryam Tahmasebi, a married couple of professors who were permanent residents in the US, are in deportation prison because Hashemi's mother, Masoumeh Ebtekar, is a supporter of the regime and participated in the occupation of the US embassy.

It is not impossible that they are somehow working with Ebtekar on a nefarious plot, but the persecutor's henchmen have not made such charges -- they have simply cancelled the family's residence permits arbitrarily and (according to Tahmasebi) aim to keep them in deportation prison for life.

Mississippi ICE facility gas leaks [Richard Stallman's Political Notes]

Prisoners in an overcrowded deportation prison (privately run by CoreCivic) in Mississippi (far south in the US) were forced sometimes to spend hours outdoors in bright sun, and at other times, to swelter in crowded cells, because of a power outage.

The prison kommandant held the prisoners incommunicado during that period.

Privatized prisons are a motor for inaccountability, and therefore for cruelty and gratuitious suffering; this makes them inherently unjust. We should abolish them all.

Afghan women deportation [Richard Stallman's Political Notes]

Other countries have deported millions of Afghans to Afghanistan. For Afghan women, that means deportation to slavery.

To deport someone to a place where she will be tortured violates the treaties which establish the right to asylum. Yet the EU is now trying to negotiate a deal with the Taliban for returning refugees there.

Tories to shut down soup kitchens [Richard Stallman's Political Notes]

A Tory-run local council in London wants to shut down soup kitchens because the area around "is not safe".

Ex Myanmar ambassador in Britain [Richard Stallman's Political Notes]

The ambassador to Britain appointed by President Aung San Suu Kyi defied the military government's order to vacate the ambassadorial house in London. The UK is denying the moral doubts about the situation by prosecuting him for "trespassing" in a diplomatic residence.

Israeli besieged Palestinian families [Richard Stallman's Political Notes]

* Israeli militants have besieged two Palestinian families in their homes since the weekend, aiming to take over their properties in the West Bank village of Qusra through a campaign of terror.*

Datacenter near the Everglades [Richard Stallman's Political Notes]

A planned datacenter near the Everglades threatens to damage it with waste heat.

There is a bright side: as data centers boost the combustion of fossil fuels, they will speed the inundation of the data center along with the Everglades and South Florida. And the White House.

But I don't think that will make up for all the things that the world would lose as civilization falls.

UK's permanent face recognition [Richard Stallman's Political Notes]

The UK is taking the terrible step of setting up permanent face recognition which will make streets unsafe for people that the state does not like.

Potatoes "boil" in the ground [Richard Stallman's Political Notes]

*Potatoes "boil" in the ground as record heatwave sweeps across swathes of Asia.*

Early Access to Truth Social Announcements [Richard Stallman's Political Notes]

*The Intercept Sues [the corrupter] for Selling [early] Access to Truth Social Announcements.*

This seems to be a plan to profit privately by selling the opportunity to cheat on bets to "predict" what the corrupter has already decided to do.

"Prediction" betting invites corruption; I think we ought to prohibit it.

California banned pesticide paraquat [Richard Stallman's Political Notes]

California has banned the pesticide paraquat, deciding no longer to treat ex-agricultural workers as pests.

Higher CO2' levels [Richard Stallman's Political Notes]

Slow, natural global heating, about 56 million years ago, devastated the Earth's forests once it passed a certain level of CO2 in the air.

Higher CO2 levels damaged plants, both physiologically and by encouraging massive plant-killing fires, and by causing plant-killing droughts.

Since 2000, the CO2 we have added has been bad for forests.

Ebay's CEO's salary [Richard Stallman's Political Notes]

Journalists David and Ina Steiner published about Ebay's CEO's salary and the company retaliated with a gross harassment campaign.

If you want to watch the documentary about this, I urge you to refuse to watch it via Digital Restrictions Management. Above all, don't get it from Amazon.

Worse on purpose [Richard Stallman's Political Notes]

This site report on brands, well-known in the past for quality, that sold their name to a company that didn't maintain the quality.

Medical students judgement with AI [Richard Stallman's Political Notes]

Supposed Intelligence tools for looking up possible diseases from a list of symptoms are undermining the process by which MDs in training learn judgment -- they instead tend to become helplessly dependent on the tools.

Gadi Eisenkot [Richard Stallman's Political Notes]

Netanyahu's political opponent, Gadi Eisenkot, is almost as much in favor of committing war crimes as Netanyahu is.

Ilhan Omar [Richard Stallman's Political Notes]

The bully's flunkies sent an agent to monitor who came to Ilhan Omar's open house for her constituents.

The agent claimed to be on an undercover drug operation. That could be a cover story for an undercover antipolitical operation.

Never rely on Google to preserve data [Richard Stallman's Political Notes]

Never rely on Google to preserve data that you have entrusted to it. Whatever sort of data it is, if you would be sad if it were lost, do not depend on Google! Google has been known to delete all of a person's accounts and all of per data, permanently and irremediably.

(I am curious whether other companies are any better in handling such situations, but I have no information about that as of now.)

My refusal to run nonfree software (including JavaScript) has in practice put Google and many other digital services off limits to me, and thus had the byproduct of protecting me from this sort of problem. However, in principle, if one company does not require customers to run nonfree JavaScript code, that doesn't guarantee it won't delete all of a customer's data in a paroxism of panic. What you need to do is store your data in several independent ways.

New Amazon data center [Richard Stallman's Political Notes]

A new Amazon data center's power plant could be the biggest emitter of CO2 in the US.

Join me in boycotting Amazon and maybe it will cancel this project to save money.

The Pixel 11 Pro: It’s Fine. [Whatever]

One of my splurges is that I buy myself a new phone each year, and for the last several years, the phone I splurge on is the latest iteration of the Pixel phone by Google, usually the “pro” version of the phone, because it’s feature-packed without being too ridiculously large (that’s the “pro XL”). This year, however, I caught myself wondering if I might skip the upgrade, because on paper the Pixel 11 Pro looked something close to a step back from the Pixel 10 Pro.

Part of this was due to the fact that, thanks to the RAMpocalypse, in which nearly all computer memory is now being eaten by “AI” data centers, the Pixel 11 Pro starts off with 12GB of RAM instead of 16GB. Then there was the new Tensor G6 chip, which has one fewer processing cores than the Tensor G5 chip. Even the battery was a teeny bit smaller. All this, starting for $100 more than last year. Nothing about any of that screams “pick this up now.”

So why did I pick up the new one? Am I just that addicted to the shiny? Well, maybe. But also, the 16GB of RAM comes back if you get the 512GB storage model (which I usually get anyway), the missing core on the chip is replaced by a different core that does more efficient onboard “AI” stuff, so computationally it’s a wash, and the whole set-up is slightly more efficient power-wise, so the slightly smaller battery does not impinge on battery life. Then there are the slightly better camera sensors, some new onboard features, and a “canyon” colorway which means the phone looks like a thin terra cotta brick, which I weirdly like. Plus, you know, the trade-in for my previous phone brought the price way down.

In all, for me, the Pixel 11 Pro just barely got over the line for an upgrade.

And now that I have it and have lived with it for a bit, I can say this: Indeed, it was barely worth the upgrade!

Which is not to say it’s not a very good phone. It is, as all the Pixel phones I’ve had have been (with the possible exception of the Pixel 4, which I had battery issues on). I am a fan of the Pixel line primarily for two things: The cameras, which have always been excellent, and Google’s suite of phone utilities, particularly call screening, which is really just the best. Plus it has the “stock” Android experience, which means I’m not waiting on an OEM to update me to the latest version of the operating system, and my phone isn’t cluttered with a bunch of manufacturer apps I will never use. The Tensor processing chip is not as fast as the latest Qualcomm processing chips in other Android phones, but then, I don’t use my phone for processing-intensive tasks, so it runs fast enough for me. Objectively speaking, the Pixel 11 Pro is excellent, and I’m happy to recommend it for people looking for a new Android phone.

But if you are coming from a later generation Android phone, including and especially a recent previous version of the Pixel, there’s not much here that screams “Upgrade to me now.” The couple of new improvements and processing tricks are nice! But they’re not “oh my god I have to have this” nice. They’re “oh, that’s pretty cool, I guess” nice. Which is still nice! But not, you know, amazing.

Probably the biggest upgrades are to the cameras, specifically in the telephoto sensor (which is now, as I understand it, a third larger than last year’s) and in the software. The telephoto sensor is nice and it seems to me the pictures I take with it are incrementally sharper, so that’s good; I won’t turn that down. It still effectively tops out at 10x zoom (the optical zoom is 5x but thanks to how the camera digitally crops, 10X will still output a sharp 12 megapixel shot), but Google will tell you that you can crank the zoom up to 120X now, and the generative “AI” processing will give you a passible image. Well, it will give you something, but it’s not a photo. I wrote about this last year when Google introduced this trick on the Pixel 10 Pro series, and what I wrote there still stands. I don’t find myself using the zoom after 10x.

It’s the software that’s more interesting. Among other things, Google now gives users a series of “looks” that can bake in more saturation, higher contrast or even monochrome, upon which the user can then add additional filters. Some of that is done by reining in Google’s computational photography so that images look less processed out of the phone, and more “like film.” I think some of these looks are pretty nice, although I’m more likely simply to futz with the images I take in Photoshop instead. Nevertheless, for the sort of person who doesn’t avail themselves of photo software outside of their phone, this is going to offer some more flexibility in how your camera takes photos, which is not a bad thing.

The other neat trick Google is doing with its cameras this year is something it’s calling “Magic Capture,” which allows the user to make a short video of some event, and then Google goes in, selects a few key frames (the user can also later go in and pick different frames if they like) and then does computational photography magic to upscale/sharpen the frames to output still photos. So basically, screenshots, but better. And how does it do with this? Passably!

Both of these photos were taken using Magic Capture, and the phone accurately figured these were shots of special interest. If you look closely at the images, they are lower resolution than they might have been if I had just shot the still image myself, but then, I might have missed these respective moments. I suspect I will find it useful when the pets are tussling and times when I’m following some sort of action-y thing, if I remember to switch it over to Magic Capture at all. But otherwise I expect I’ll just do the usual picture-taking thing.

The one other noticeable improvement with this camera is that the low-light, computational-heavy “night sight” pictures now take a lot less time – down to a second or two from the previous three-to-six seconds, which means less blur and artifacting. Which, cool.

Again, all of this is pretty nice quality of life stuff that I’m happy to have, but nothing that stands out as a “must upgrade” feature. There’s a reasonably good chance, if you’re on a Samsung or recent Pixel phone, that at least some of this stuff will trickle over to your phones over the next year or two anyway — Google tends to use the latest Pixels as a testing ground for features before releasing them elsewhere. In which case, you’re just paying for early access.

The two other standout features of the Pixel 11 Pro, if you want to call them that, are “HiLight” and “Ramble.” HiLight is a multicolor LED (which also serves as your flash and flashlight) that will alert you when contacts you specify call, or lights up when you speak to “Gemini,” Google in-house “AI,” in each case provided your phone is screen down. Which, okay? I guess? That’s literally all it does at the moment; one assumes more functionality will come later (someone has coded an app to give it more functionality, but you have to get it off of Github and sideload it, so 99.99% of users won’t). Google made a big deal of this, but I don’t know why; my Motorola phone from a dozen years ago had an LED notification light too, so this ain’t exactly new. I turn off nearly all my notifications anyway, so I don’t really see this as being something I’ll get much use out of.

“Ramble,” on the other hand, is pretty neat — the phone listens to what you have to say, slices out the pauses, null sounds and backtracks, and outputs a more efficient version of your blatherings, and does a pretty decent job of it, at least for how I’ve used it, which is primarily talk-to-text. The one drawback to it from the previous talk-to-text version for texting and email is that it waits until you’re done to transcribe, so you can’t see what you’ve just said, which I think (ironically) will lead to more rambling. But as a voice-to-text processer, it’s pretty good. I understand the Pixel 11 Pro also has the ability to transcribe ASL-to-text, which I don’t see myself using but which seems like a really nice accessibility feature; the couple of reviewers I know of who have used it say it works pretty well, so there’s that.

In all, the Pixel 11 Pro is an iterative rather than transformative update to the Pixel line. But then, “iterative, not transformative” is pretty much an accurate description of every single smartphone for the last ten years. We know how smartphones work, they work pretty well at what they do, and I don’t think most people want to have to learn a whole new interface/access style when working with them. So honestly I don’t know how much more pure innovation we’re going to get out of our glow-y handheld supercomputers.

I don’t regret upgrading — I like the new features — and also if I had decided not to upgrade, I would have been fine for a year or two. If you already have a Pixel 9 or Pixel 10, especially a pro model, you can comfortably skip this year and know you’re not missing too much. Likewise if you’re making a lateral move from another manufacturer’s Android phone; if it’s a recent model, you don’t have to rush. Bluntly, these days, with prices going up because of shortages, there’s more to be said for holding on to your current phone as long as you can. You may or may not be able to outlast “AI” hogging all the resources, but there’s no reason to pay a premium for this or any other phone while we wait to see how it all shakes out.

But if you do have a hankering for a new phone, and like what the Pixel 11 Pro has on offer, then I expect you’ll be happy. It’s good! It’s fine! Just not essential. Maybe that’s enough for you right now. And if it is, well, here you go.

— JS

Girl Genius for Monday, August 24, 2026 [Girl Genius]

The Girl Genius comic for Monday, August 24, 2026 has been posted.

Grrl Power #1489 – Target audience [Grrl Power]

Ahhhh! Done with the fight scenes for a few pages at least, and back to the characters being goobers. The meat and potatoes of this comic. Feels good. Also not having to draw a bunch of speed lines feels good too. I mean, obviously I have some huge speed line templates that I cut and paste, because there’s usually no point to doing a unique radial burst for each panel, but still. There’s more to good speedlining that just laying lines over or under some action, as I’m realizing, but hey, that’s the job. Still, I wouldn’t say no to 3 or 4 Japanese interns who put in 16 hour days doing mind-numbing background work. Man if I could get that for a single page… well, that page would probably just be an establishing shot of a massive city, because that shit is tedious. That or a lot of rubble.

There was some debate on the previous page about whether Max qualifies as a “Mary Sue,” which in its current common usage, is a term I generally don’t like. Because the original Mary Sue was specifically a female character who is great at everything, but most importantly, also an author self-insert. Unfortunately, the current common usage seems to have become “any competent female character.” Without the author self-insert part, it almost always feels like the person complaining about a female character being good at stuff is really zeroing in on the female part of the equation, and that becomes extremely evident when you ask them, “Is Batman a Mary-Sue?” Because Batman is a billionaire playboy who is better at literally every single physical activity than Olympic equivalents, is also the world’s greatest detective, can outfight like 20 ninjas at a time (dudes who have spent their entire lives training only to be deadly fighters and don’t waste any time on that detective stuff or solving riddles) has all the gadgets, up to and including his own fighter jet armed with a variety of missiles, which is probably illegal for a private citizen in a much bigger way than vigilante justicing some thugs in an alley, has his own space station with orbital strike capabilities, which, again, probably illegal in a way that the entire U.N. might care about, etc, etc. The Mary Sue-accusers usually say, “No, because Batman loses fights all the time.” Right, he loses fights, (usually so he can get thrown in a deathtrap only to quickly escape) but never the war. If a female billionaire playgirl gadgeteer, etc got her back fucking broken rather famously, then recovered and was basically completely fine afterward and proceeded to beat up Bane, I feel like they would get “Mary Sue” lobbed at them. What about James Bond? What about Iron Man? Riddick? John Wick? Mary Sue or just the main character of a franchise who necessarily has to win in the end so the franchise can continue?

But here’s a serious question. If Maxima is a Mary Sue (the non-author insert kind, obviously) because she’s powerful and wins fights… is Saitama? (From One Punch Man if you didn’t know his name.) Saitama is probably exempt because his strength and battle record are almost entirely played for laughs. Also he’s male. I guess the real question is if Maxima was Maximus, would anyone even think of accusing him of being a non-author-insert Mary Sue? Cause I’ve never seen anyone accuse Batman of being a Mary Sue out of the blue, it only ever happens when someone asks the guy who’s accused a female character of being one if Batman is also one, and accuser guy suddenly feels defensive about getting called out for being sexist.

If you think seeing Maxima win a bunch of high-level fights with relative ease is a little boring, that’s fine. That’s a totally valid criticism – even taking into account that she entered specifically because she analyzed previous tournaments and was fairly certain she could probably win with relative ease. That’s still a valid criticism, because it’s on me to relay an entertaining version of those events.


Oh, look who it is in the vote incentive. And a not-quite-yet-but-it’s-coming NSFW version over at Patreon.

Vote incentive and Patreon updated with some shading. Not finished yet, but progress.

I think she would get in trouble for doing this. She’d mess up the… floor of the waterfall? Is that what it’s called? The receiving pool? No, probably not that. Anyway, she’d churn things up and cause a ton of weird erosion.

Since you might be wondering, Niagara Falls is about 165 feet high, so Babezilla obviously doesn’t have to be full sized. I’d say she’s about 175-180 feet tall here?


Double res version will be posted over at Patreon. Feel free to contribute as much as you like.

Grave-Maker Rounds [Penny Arcade]

New Comic: Grave-Maker Rounds

Banned From The Produce Aisle [QC RSS v2]

and the baked goods department, but for different reasons

Sunday, 23 August

11:56

Aigars Mahinovs: Optimistic take on AI [Planet Debian]

As I am writing this, there is a vote ongoing in the Debian project on how to deal with AI in general and AI-assisted contributions to Debian specifically. Massive discussions have happened in debian-vote and other locations. I have also asked questions there and offered my perspective. IMHO now is the time to summarize that, after all the discussions that I've had with people on multiple sides of this debate both online and offline, and explain how I will be voting and why. Hopefully that will be helpful to someone else as well. None of this has been compiled with AI assistance, but only because I think that forming opinions is not something where AI can really be helpful. Spellcheck was used though.

So, first I will describe how I see each of the 8 proposals, then what my vote will be, and then a bit more detail on the reasoning and thinking behind this. WARNING - this went long.

  • Proposal A(1) - Action: ban all AI-assisted contributions via Social Contract amendment, except from upstreams (so not rolling back the Linux kernel and other software to "pure", pre-AI state). Claims that copyright/licensing status is unclear, quality is bad, community is being destroyed, web resources see extra load and that training consumes "staggering" resources. Needs 2/3rd majority to pass. - IMHO worst and most inconsistent. If copyright and licensing of AI products is unclear, then be consistent - ban ALL software with AI contributions, fork Linux kernel and other software from pre-AI versions, reject all security fixes of issues found with AI. Quality section lists problems that have not existed in the real world since at least a year of rapid AI coding development. Community section assumes that now all Debian contributions will be drive-by AI slop and no one will learn anything anymore. Ethics section mixes up effects of badly configured systems (AI web load is no different from load from a badly configured Perl script) with claimed "resource" usage without any context, taking on trust project ambitions of startups and assuming exponential growth. And then concludes that delivering less is in the interest of our users somehow.

  • Proposal B(2) - Action: allow AI-assisted contributions, with conditions of: legality, accountability, disclosure, no uncoordinated bulk actions, privacy. Concerns on quality and legal status as well as environmental impact and scraper load are noted, but not really addressed beyond labelling them as concerns. - IMHO it is an ok starting position as it establishes that each contributing person must still be fully responsible for their contribution (both legally and technically) and for that has to also understand (and review) what they submit. Disclosure lets others know to watch out for other classes of problems when code was changed with AI assistance. Prior discussion for bulk changes just says that the (already established) practice should not be neglected just because now large changes are easier to do. And the privacy part warns against accidentally sending private or confidential data (like a not yet published security bug) to a public service where it could become public. Personally I would have liked a stronger statement to encourage use of environmentally responsible AI services and local AI tools. Possibly a preference for open-weight models with a clear path forward to preferring truly free AI models, when such a category of products could be clearly delineated and established.

  • Proposal C(3) - Action: reject AI-assisted contributions at Code of Conduct level. Claims all the world's evils come from LLMs and that "Ethical and safe use of this technology is almost impossible". Goes as far as banning any use of LLMs even in Debian mailing list emails and Debian Planet blog posts - if you do, it's a CoC violation and may result in exclusion from the project. Additionally mandates the disclosure of the usage ... presumably to ban you more efficiently for it. - IMHO truly a dictatorial nightmare option. Zero actual reasoning or basis for such a decision. Zero sources. Nothing claimed in this option's rationale is even close to reality and nothing claimed there is in any way related to the actual technology being discussed. Like, an "LLM" does not automagically commit "fraud" when you use it, like this proposal claims, as if that was a well-known fact. LLMs are not all "owned by horrible people and companies". Even if some include a (prominent Debian user, long-time supporter and sponsor) Google into "horrible companies" (which is what this proposal implies!), there are plenty of LLMs owned by all kinds of companies all over the world and there are plenty of open-weight LLMs that are not really owned by anyone. Most invasive and dishonest option on the ballot.

  • Proposal D(4) - Action: allow AI-assisted contributions, with conditions of: legality, accountability, disclosure, privacy. IMHO same as B, just shorter. Adds a "we don't recommend" towards others developing software with AI assistance. Seems pretty weird to add that and then immediately accept Debian contributors doing so. Assumes that the bulk change bit of B is implied as AI is just tooling, so bulk changes should be pre-discussed just like today - so no change and thus no point in mentioning that. Fair. D is a bit more explicit on expected technical details - like that the "person" submitting the change is supposed to sign it, not AI. Notable is the complete absence of resource usage or the environment from concerns. IMHO it would be better to have that and also recommendations on how to avoid causing environmental damage when using AI.

  • Proposal E(5) - Action: no action as such - AI-assisted contributions must follow the same rules as all other contributions and those rules are sufficient. IMHO despite its length this is a very well-worded position statement that describes how and why AI-assisted contributions already work perfectly fine in the Debian context when all the same rules that apply to all contributions are also consistently applied to AI-assisted contributions. It describes how the same legality, accountability, no bulk change and privacy requirements are already in place and still apply and how AI-assisted contributions can and must still satisfy them. I could add again that some guidance would be nice here for both legal and environmental decisions when using AI, but in this case it does not really belong in this proposal itself. We as Debian do not have a document that requires that our non-AI-assisted contributions be made with only sustainably sourced electricity, for example. So why should AI be special one way or another? IMHO Debian should have a datacenter sustainability policy, regardless of the AI discussion.

  • Proposal F(6) - Action: discourage AI, but allow it based on existing processes (similar idea to E). Dances a bit around the question of disclosure of AI use (as a courtesy) and accepting that some people may still ban all contributions where any AI was involved in any way. Which in turn discourages disclosure to avoid pointless rejection of valuable contributions (like security patches). IMHO this option is ok, but so watered down that it is bound to bring up further discussions and conflicts on details.

  • Proposal G(7) - Action: ban non-humans from directly contributing to Debian. IMHO - another bizarre and self-contradictory option. It bans all Debian interactions with AI assistance, including email messages to Debian mailing lists and (supposedly) blog posts on Planet Debian. It "reminds" people who "use such tools assistively" of the DFSG and Social Contract - isn't that a threat of a ban and expulsion similar to C? The proposal does take pains to delineate where a contribution comes from AI as output (bad) vs when you are assisted by AI in the process of exploring, researching or maybe even reviewing the code, but you actually type all the code yourself and use the AI just as a taskmaster with a whip (good). And just like A or C it completely ignores how this inherently evil and unstable AI-generated code becomes perfectly fine and good as soon as someone develops that outside of the Debian project. Even if the same person then packages it for Debian the next day. It is hypocritical, unsustainable and ignores the needs of our users. Just like C it also bans someone writing an email or bug report in their native language and using a modern translation tool or service (that uses LLMs nowadays for better grammatical clarity) to translate that to English before sending it to a Debian mailing list or BTS. Heavy-handed and invasive. And the only reasoning provided for this is some unnamed "concerns" of "extra work" being borne by "other people"? Kind of does not feel right to bear such draconian restrictions for some unspecified concerns.

  • Proposal H(8) - Action: condemn usage, but not actually ban anything. And then it goes on to claim (without any evidence or elaboration) that LLM usage accelerates the destruction of "planet earth" (sic). IMHO this proposal is at the same time the loudest ("The planet is burning") and also the one that demands the least action. It dances a really twisty line between raising "significant" concerns in all areas and even claiming that use of LLMs destroys the planet, flies by explicit condemnation of LLM usage and then suddenly collapses with not condemning LLM users and swinging to lamentations that it is actually impossible to impose policies on LLM usage or even detect when an LLM was used (which kind of directly contradicts bad quality claims from A, C and G) and lands on "encouraging" contributors not to use LLMs (where practical) and otherwise do nothing else. It's like this is a 5th draft that started off with the rationale and total ban like in C, but then got defanged so far that its action side no longer matches the rationale stated.

With all the above considered I will vote like this (earlier options are preferred over later options):

  • Proposal E(5) - solid hack of integrating AI into already existing Debian rules and conventions
  • Proposal B(2) - explicit and detailed
  • Proposal D(4) - lower because of discouragement to others on what we agreed to do ourselves
  • Proposal F(6) - I am not a fan of dancing around with disclosures
  • Further discussion(9) - I do not want any option below this to succeed as they would do more harm than good
  • Proposal H(8) - loud, but not doing anything actually
  • Proposal A(1) - at least this one does not set rules for emails
  • Proposal G(7) - at least this one allows an AI overseer to tell you what to write with your own fingers
  • Proposal C(3) - the most draconic and invasive one that explicitly wants to kick people out of the project

Details on rationale

Hypocrisy - I find any proposal that would ban AI-assisted contributions to Debian, but at the same time not ban including AI-assisted contributions from upstream projects to be inherently hypocritical. If LLMs and AI are the very incarnation of evil (a puppy-killing machine, as the analogy went in some emails), then any rational proposal would involve excluding any and ALL code contaminated by this evil from the project. What does it matter if puppies were killed in writing the debian subfolder of the source code or the src subfolder? No proposals went there because everyone knows that such a ban would be the death of the relevance of the project for the future. Debian would be frozen on some old version of the Linux kernel forever and other software would be falling to the same problem too, for example as projects on GitHub start enabling AI-supported reviews with patch suggestions. Soon the "development" of Debian could just be stopped as there is nothing to develop without any upstreams.

Assumptions - a lot of proposals mention various "concerns" with at most one word, like "practical" or "community" without an explanation of what exactly they mean by that. The proposers assumed that everyone lives in the same info bubble as they do and already know everything that they mean and already agree to that. That is false. Proposal A was a positive stand-out in this area. Debian has contributors all over the world with very different exposure to different information sources and very different world views. If you want to convince the project as a whole that LLMs are bad because of "ethics", then you do really need to explain what you mean by that and give links to sources, at least as well as Proposal A did. All other proposals were really weak in this area.

Copyright - the question on how copyright law interacts with training LLMs and their outputs is still not settled law. The closest legal statements we have so far are that - just because an LLM is trained on copyrighted material does not make that LLM itself be a derivative work of the training data (you, however, cannot just create and distribute a "library" of copyrighted materials just because you plan to train LLMs on it). The output of the LLM might not be subject to copyright law at all, like a photo taken by a monkey. It would then be public domain and thus can be modified and then licensed by the user of the LLM. It might also be a derived work of the context of the inference (so for software - if you refactor a GPL project, the refactoring itself is likely GPL too). Any stricter interpretations would break a lot of existing copyright doctrine, such as raising questions like: "does the output of any programmer now become a derived work of the programming manual books they read in college?". In any case it is really not up to Debian to legislate the nuances of copyright law. And I strongly disagree with the concept that an author can tell me how I am allowed to use the learnings that I gained by reading their work. That is not how either copyright or society works. I can look at 10 pictures of a sunset and draw my own, inspired by the ones I saw. No one can forbid me that expression. The same must be true for a machine learning and replicating patterns.

Ethics - I've re-read all proposals and emails and the only real specifically ethical concern I could find was the complaint that some LLMs (or their training farms) are running their web scrapers too aggressively and that causes extra load on services. Like that is not an LLM problem. Scraping the web is not an inherent part of the LLM training or inference process. It's just a few misconfigured scripts. We saw the exact same thing in the early days of web search engine proliferation. Then we banned/blocked the misconfigured engines and the survivors learned that obeying robots.txt is one of the rules for surviving. Literally the exact same problem and it will be solved the same way. Did we ban all search engines back then just because some of them were misconfigured? No.

Some claims (like in Proposal C) are just bombastic hyperbole ("hazards to users' mental health", "fraud", ...) and on top of that have zero relevance to the topic at hand - AI-assisted contributions to Debian. What "hazard to users' mental health" is created when a Coderabbit spots that a lock is not taken before accessing a resource in a particular function and suggests an AI-generated patch to fix it? What "fraud" is committed by this? There is no sane answer. I get that some people are very busy fighting some culture wars and sometimes, some AI-bros happen to be on the other side of one such war, so it is useful to label everything coming from the AI sphere as "bad" in all possible and impossible ways. You do you. In private. Why pull Debian into that? Why force your position on everyone else in the project? Why deny everyone in the project access to useful tooling, just because you have strong feelings about some of the people promoting some of those tools?

This seems to me a repeating pattern here - blaming the technology as a whole or blaming all providers of this type of technology for failings (ethical or technical) of some of those providers. Like refusing to wear all shoes and condemning all shoemakers and sellers, just because some American billionaires figured out a way to make and sell cheap shoes by killing puppies. Not refusing and condemning those providers, but condemning all for the actions of a few.

Resource usage - this is a big topic for many and it has reasonable points to it. The LLM and AI technology has no inherent need to be damaging to the environment in any way for it to function. It does not need to burn oil or dig up cobalt. It does not need to sacrifice a ton of water to the Gods. It is perfectly possible to run AI (both inference and training) purely from green, electrical energy and cool data centers in equally sustainable ways, like with simple air-source heat pumps (also known as air conditioning) or even use it beneficially (many data centers are used for heating surrounding buildings via district heating). However, some AI companies do use non-green power for their data centers, some do use locally-limited fresh water for evaporative cooling (evaporated water still rains down as rain, it is not really lost, but that may happen in another location so lack of water can still happen locally). Some even run unlicensed natural gas turbines in their data centers to provide them with power. And those specific providers can and should be shunned and condemned. Not the other ones, who are doing the right things. Not the technology or its users or its outputs.

There is a very wide spectrum of options on how an AI system could be powered: starting from local execution on already existing private hardware powered by one's own local solar power (good), to a data center stuffed with borrowed AI-only cards powered by a gas turbine or coal power station that operates solely to supply this data center (bad). Proposals that talk about ecological impact, but do not even consider where on that (very wide) spectrum to draw the line between "good", "acceptable", "discouraged" and "bad" — well, I cannot see those proposals being actually serious about the environment to begin with. It feels like they just refer to it for points.

And if we go into the power question deeper, well the grid dynamics and economics become very, very complex and often also non-intuitive. Like, all large software companies with data centers (that also happen to provide AI services), like Google, Meta, Apple, Microsoft and others do actually care about sustainability (in part because their customers care and vote with their wallets) and so all of them use 100% green energy for their data centers (including AI data centers) .... "on an annual scale". Wait, what does that mean? Well, the electrical grid is special - the amount of electricity produced and consumed on the whole electrical grid together has to match almost exactly every second. If there is just a single second where there is significantly more energy consumed from the grid than is produced, the frequency will plummet and you get a brownout and risk a grid collapse. The same is true in reverse - that causes a voltage swell. So grid operators manage energy flows every second and command power stations to increase and decrease generation all the time. Some power stations are easier to regulate dynamically than others. In the end, all that means is that even if your data center has a contract for 100% green energy with your power company, at some seconds across the year there might not be enough green energy in the grid to fully supply ALL people and companies that have 100% green energy contracts. This gets compensated in other seconds, so that across the year ("on an annual scale") for each kWh that your data center pulled from the grid, the same amount of kWh of 100% green energy flows into the grid. But it might not happen at the exact same second. Pedantic companies, like Google, take that discrepancy and count that as CO2 emissions for themselves. And then they and the power companies (they have contracts with) invest billions into new green energy projects, better grids and better batteries so that eventually this discrepancy goes down to zero. In this way green AI data centers with their increasing consumption of green energy are actually doing a lot of good work in making our electrical grid more green. They are making more resources than they are consuming. And that is just the tip of the iceberg. This is a deep topic that really abhors generalizations like "more consumption = bad".

I've heard similar discussions in the context of electric cars - "so you got an electric car? you'd have fewer emissions if you drove no car at all!". That might be so. And I would also reduce my emissions to zero if I stopped breathing, but I really do not want that kind of thinking to be propagated further, especially when impressionable young people are around who may take it to its logical (but wrong!) conclusion. Instead I talk about how early adopters use electric cars to gather experience and achieve volume to start the network effects working. Once network effects of many electric cars on the roads are sufficient, it becomes an economically logical choice to get an electric car. People who cannot avoid having a car start to switch over. And at the point of mass switchover the reduction of emissions is so massive that those early adopters failing to go all the way to riding a bicycle becomes a rounding error.

But surely that does not apply to LLMs? They are only increasing consumption and bring no benefit?

Benefit - and here we have to actually talk about benefits. Because you cannot make any cost-benefit analysis if you do not actually fully investigate the benefits. Are there environmental benefits from running those AI models? Yes, in a lot of very diverse ways. Hard to measure, however. There are projects that are easy to quantify - like that Google AI project on contrail avoidance. An advanced, special model trained and executed in Google AI data centers was able to predict where in the air contrails would be produced and could generate proposed course adjustments to commercial flights to avoid specific heights in specific locations at specific times. This stopped these aircraft from creating contrails and those contrails did not make a further contribution to global warming. That benefit in a year was many times higher than the environmental cost of training and running that AI model. And it can keep running for many years accumulating further benefits.

On a personal scale, I've had problems that I bashed my head (and computer and CI resources) against without much success years ago solved with a few minutes of compute. Having a good enough candidate solution quickly is much cheaper from a resource perspective than spending days trying different things, running my PC for it, trying different patches on CI executions, doing different rebuilds. I've seen very significant benefits in AI-assisted development in enterprise environments where code way more complex than what is in Debian (especially in Debian tools and packaging) gets analysed, reviewed, modified or even refactored or rewritten in another language with AI assistance. And it generally works. The commonly mentioned "hallucinations" are a thing of last year in the coding context. Nowadays the AIs work in special coding harnesses and use real tools as foundational facts. You cannot "hallucinate" an API call or parameter if you have to run and pass the unit tests and integration tests by your harness before you can return "success" to the caller. I've personally seen high-level AI models read very complex software projects across multiple repositories and point out a very specific design consideration that was encoded in the code logic, but never mentioned in comments or documentation. It was so obscure that even I did not immediately know what it was talking about (and I wrote that code). Only on close inspection of code interaction across three repos did I remember that there was indeed that bug 2 years ago that I fixed by doing the change that this AI picked up (it wasn't in the history of this git repo due to repo migration). It mentioned this because it was very relevant to the task I initially gave it to review.

These LLMs in a proper harness with proper system instructions and usage approach are not just fancy spell checkers or auto-complete. They function more like very advanced pattern matchers. They have learned millions of patterns from training data. When they look at the code, they see hundreds or thousands of overlapping patterns. When you ask them to make or change something, they pull out a pattern (or ten) from their training and apply those patterns to the context of your program. You get something that looks just like the surrounding code, same style choices, same language, same comment voice, but it implements something new there, based on other patterns learned. If you've studied design patterns in your CS class, this will be familiar. But people can learn and remember maybe 20-30 patterns, while an LLM can have a million patterns and can combine them when needed. So it takes a pattern of Python code, pattern of standalone script, pattern of parsing command line parameters, pattern of classes, pattern for background threads, pattern for file tree traversing, pattern for pipes, ... and squishes them together to make a solution for your query. And then tries to debug it with compilation, tests and execution until it works as expected. Even if there is zero LLM development going forward, it will take many years to fully appreciate the benefits we can extract from the already trained models. They don't even have to be retrained - for existing languages they just keep working. For new language variations, like a new Python version, you can feed the changelog into context and they will be able to work with a Python version that they never saw in training. And patterns are mostly abstract, so not really specific to any language - human or programming.

This is another big enabler that LLMs have created that we have not really explored yet. LLMs have created really free software. People can actually create software that is perfectly suited just for them and no one else. They don't even have to know how to program and don't even need to speak English. I've seen people writing prompts in their native language and LLMs creating and then adjusting web apps or Android/iPhone apps and deploying them to the user's own phone. It was too buggy to work last year, but this year it is actually very functional for simpler use-cases. And the code looks just fine too - I've seen external contractors in a business setting deliver far worse. If you start with a good initial system prompt, the project will have architecture documentation, use-case documentation, unit tests, integration tests, deployment harness, testing and production deployments, audit logs, monitoring, clear git commits, CI validation on commit, ... Modern AI systems have the capabilty to deliver software freedom to people who are not coders. I really can not overstate the consequences this may have on the world.

Community - I find the concerns that new people will be using LLMs so much that they will no longer be understanding the actual code they are contributing a bit regressive. I don't see any significant difference between this and people relying on compilers, on high-level languages or on debhelper. Writing modern debhelper packaging feels more like writing configuration and not writing code. It takes really significant effort to dig down through layers of abstraction to find what actually is being executed in debian/rules. AI does not really make this worse. In fact, I find that AI can make it much easier to understand arcane syntax because you can ask an LLM to explain what is happening in any part of the code and it will do a pretty good job of it, digging down through the layers of abstraction for you. All the pro-AI proposals include the requirement that each human contributor needs to understand and stand behind their AI-assisted contribution and I believe that is a good requirement and also a sufficient requirement. Modern LLMs not only produce clear and concise code, but they are also capable of producing good comments explaining why the code is how it is, good commit messages explaining the change and reason behind it and also making corresponding changes to test suites and documentation. You know - the housekeeping stuff that is often skipped because it slows down the actual feature development, but then its lack becomes a problem for future contributors. Responsible use of AI assistance is a great chance to actually strengthen our community and make our software easier to maintain.

That said, I have no qualms about flat-out rejecting contributions that do not make sense. And it does not matter if they are made with or without AI assistance. If the contributor will not explain their patch, it might be they do not understand what their AI produced or it could be that the contribution is deliberately hiding a backdoor being planted. It is also quite common for a contribution of a new feature to be rejected because the author/maintainer does not believe that it is a good fit for the project. Featuritis is a real disease. AI or not. There have always been drive-by contributions to various projects. They will continue to exist. Each of them should be evaluated on its merits - is this feature valuable to our users and is the added complexity (if any) worth the functionality? A lot of security bug reports are "drive-by" contributions as well. And many of them nowadays are discovered, exploited and patched with AI assistance. We could reject them, but that just leaves us holding the bag on the now-known exploits.

And the New Maintainer process should be able to figure out if an upcoming Developer has actually understood the nuances of Debian packaging or not. A contributor with upload rights to the archive has to be able to create a basic package with no support tooling (maybe even without using debhelper?) and be able to understand and modify more complex packages (possibly with tooling support). IMHO that is a separate discussion that is worth having, involving experts from the educational sector.

Conclusion

IMHO the Debian project should not restrict what tooling individual contributors use to contribute. Expecting high-quality contributions and that contributors understand what they are contributing (as a first level of review) is enough.

However, Debian should provide its contributors (internal or external) with guidance on how to contribute in the best way possible. That could include:

  • information on which AI services have Terms and Conditions that make them problematic for free software development, legally speaking
  • information on which AI services do (or do not) achieve a sufficient level of sustainability to be worth recommending (and then do the same for other data centers we already use)
  • information on which local AI models were trained in sustainable ways
  • base-level prompts to set technical expectations on various types of contributions, like bug reports or patches to packaging or translations
  • default configuration for AI-assisted code reviews on Salsa that projects could enable and supplement with their own instructions on top

In addition to that it would be helpful for Debian, as a project, to reach out to AI service providers to:

  • encourage them to improve sustainability (where needed)
  • investigate and fix problems causing excessive scraping load on systems
  • provide AI resources for Debian usage, for example in CI infrastructure or to provide equal development support opportunities for Debian developers who cannot afford paid AI services
  • improve coding outputs of their models in the Debian context if/when systematic deficiencies in the output are found by us

Questions? Feedback? Just ask here or here.

10:07

The Drucker drift [Seth's Blog]

Peter Drucker argued that the purpose of a corporation is to serve the customer. It turns out that organizations that focus on this do well.

Milton Friedman argued (mistakenly, in my view) that the corporation doesn’t need to care about customers, unless this helps increase the value of the company to shareholders.

Corporations are a cultural fiction, something we created and permit to exist because it serves the community. In exchange for leverage and insulation, the corporations are expected to be of use and to improve conditions for those they serve–not to be a tool to enrich a few shareholders.

As power becomes more concentrated and money becomes more leveraged, it’s easy to see how attractive it is to sell Friedman’s idea to people seeking a short-term profit.

As we drift away from Drucker’s point, though, we all suffer.

Financial engineering rarely builds value for the long run.

Saturday, 22 August

18:00

Russell Coker: Links August 2026 [Planet Debian]

This YouTube video about the Cashier Girl Meme is interesting in the context of AI systems that generate images of people and can communicate with people, hotter than any real human is an achievable goal [1].

Stand Up Maths has an interesting Youtube video about LLMs solving maths problems which I highly recommend watching (it does not require any real knowledge of maths), I think this opens the door to attacks on well established cryptologic systems [2].

Adam Conover made an insightful YouTube video about how and why Hollywood is now unable to make good sitcoms and why this is bad for society [3].

Sky Croeser wrote an interesting and insightful blog post about topics covered at the “Digital and sexual citizenship in an age of social media bans: Interrogating the rights of children and young people conference” [4].

Zane wrote a very informative blog post about reverse engineering a trojaned Android projector with Claude Code [5]. We need much better security on home networks to break the business model for this sort of thing.

Renee Stonebraker’s article “Puritans Wouldn’t Eat Pussy, So They Invented the Western” has a lot of interesting information about early days of colonising the US, and not much about eating pussy [6].

IFLScience has an interesting article about brinicles, icicles of brine that form under sea ice [7].

Nautilus has an interesting article about the Silurian Hypothesis [8].

The Conversation has an intersting article about the pros and cons of no-till farming [9].

Cold War is a 365tomorrows story about bio-warfare which raises several disturbing possibilities we need to guard against [10].

Scott Santens wrote an insightful article describing how a land value tax would reduce rent and solve the housing shortages [11].

Positive News has an interesting article about using OnlyFans to teach people about climate change [12].

The Conversation has an interesting article about cultural safety in healthcare, sounds good, and while we are at it lets deal with sexism [13].

Doctoreww has an interesting web page about ways of displaying different strings to humans and machines, this could result in you running a different command to what you thought you copied from a web site or defeating tools designed to block hostile content [14].

Cory Doctorow wrote an insightful article “Commentary Hell is Other People” about the way rich people want to use AI to replace all people [15]. Also psychologists who help rich people accept being greedy are worthy of a Luigi

The research article “Worship me at the office altar: Why narcissistic leaders resist remote work” is interesting, yet another reason to get rid of narcissistic executives [16].

Renew Economy has an interesting article about clean up costs for mining (which is usually left for the government to pay) and how this could impact renewable energy production facilities [17].

Elvira Bary wrote an insightful article on the Russian financial collapse that is happening now [18].

The Guardian has an interesting article about Afro-American women who travel to South Korea for healthcare because of problems with racism and sexism in American hospitals [19].

The Conversation has an interesting article about the potential for disabled people to be more productive in space than non-disabled people [20].

Krebs has an interesting article about LG banning residential proxy code from apps after the LG store was found to have such code in 42% of it’s apps [21].

Robert B Shpiner wrote an insightful article for The Guardian about the death of democracy in the US [22].

17:07

View From A Hotel Window, 8/21/2026: Columbus [Whatever]

A view of mostly grass, but also the Columbus skyline way in the back, from six stories up.

My mom, grandma, and I are in Columbus this weekend to celebrate my grandma’s 79th birthday, and here is the view from the hotel we are staying in! It’s definitely outside of downtown, but not a bad view, honestly. We’ve got some good, clean, wholesome fun planned (drinking, gambling, debauchery). You only turn 79 once!

Hope you have as fun of a weekend as we will.

-AMS

15:14

Link [Scripting News]

BTW the codename for the new version of Frontier is Atlantis. And we refer to the old version as Berkeley. I'm getting used to the first one. I liked it as an idea, but I don't like typing it, because for some reason my mind has trouble remembering it. Maybe this is just age creeping up on me. Atlantis.

Link [Scripting News]

This project has been pre-occupying me, I wasn't planning on doing this, I was going to turn my attention to FeedLand immediately after finalizing RSS.chat. After running the experiment that proved it could be done, I looked at the two choices: 1. Move forward on creating a social network built only out of the existing web with all parts replaceable, small pieces loosely joined. Or 2. Give new life for Frontier, which is my life's work, even though very few people know about it. It's the reason were able to move so fast on blogging, RSS, podcasting, outliners, etc. A very highly leveraged development and runtime environment. Imho far ahead of anything else. The ideas may possibly now have a way forward. When I put those two items next to each other there was no question, I had to go with bringing Frontier back to something people can use.

Link [Scripting News]

I think what confused Claude is that we're implementing the odb as a SQLite database. And when you look at a table, you're looking at the result of a query. Previous versions of Frontier implemented the odb as a hash table, that could contain scalars, objects and other tables. The new version has to make that virtuality real, even though it isn't storing the objects that way (maybe it should)? So there is a top level, and it all flows down from there, and it's simple, but if you viewed it through the database, and didn't understand the virtuality it was creating, which I discovered it was very confused about, you might create a disorganized nonsensical piece of software. Now this suggests something interesting, are there any products configured the way Frontier is? Maybe not, otherwise it might have figured this out on its own. Remember how it understands things? By cribbing the code. ;-)

14:28

Link [Scripting News]

Are there any other people who are blogging daily about their experiences developing software with Claude Code, Codex or somesuch. I'd like to add them to a list where we follow them. So much innovation happening underneath, I want to hear about what people are learing about creating the next layers. If you know someone doing it, please add a comment to this post. Thanks! :-)

14:07

Dirk Eddelbuettel: RProtoBuf 0.4.28 on CRAN: Small Updates [Planet Debian]

A new minor release 0.4.28 of RProtoBuf arrived on CRAN today. RProtoBuf provides R with bindings to the Google Protocol Buffers (“ProtoBuf”) data encoding and serialization library used and released by Google, and deployed very widely in numerous projects as a language and operating-system agnostic protocol. The new release is also already as a binary via r2u.

This release corrects a really old bug. Troy found, when working on gRPC based extensions, which is in and by itself exciting, that a small part of our interface surface (for service descriptors) was just wrong confusing single and double underscores. adjusts to a change upstream. This has been corrected. I updated a few of the usual continuous integration parts, updated a help page for a newly-added nag by CRAN, and also got a last-minute round of noodling in as the JSS paper vignette was still referencing OmegaHat which the CRAN URL checker objected to. I created a quick one-off repo to serve pdf files should the need arise again, and rebuilt the vignette linking to it. No other changes.

The following section from the NEWS.Rd file has all details and links.

Changes in RProtoBuf version 0.4.28 (2026-08-21)

  • Standard maintenance of continuous integration

  • The type help page has received a usage section

  • Cleanup of several methods for ServiceDescriptor, correct several other declaration (Troy Hernandez in #117 fixing #116)

  • Adjusted vignette reference to Omegahat paper to alternate location

Thanks to my CRANberries, there is a diff to the previous release. The RProtoBuf page has copies of the (older) package vignette, the ‘quick’ overview vignette, and the pre-print of our JSS paper. Questions, comments etc should go to the GitHub issue tracker off the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

11:00

Emmanuel Kasper: Create a development VM using Debian cloud images [Planet Debian]

Following on the rationale of the previous post, here is how I create a development VM based on ready to use disk images made by the debian cloud team. I could as well install the VM myself using an ISO, but why download a collection of packages in a ISO only to copy them right onto a disk image ?

From the list of images available at https://cloud.debian.org/images/cloud/ we will start with the generic qcow2 disk image, it has cloud-init, which allows initial automatic configuration, and snapshots of the VM via the qcow2 disk format.

As for the virtualization, I am using virsh virt-install and virt-manager, which are part of the libvirt framework. Libvirt offers an excellent API accessible over qemu/KVM via shell (virsh), GUI (virt-manager) and Web (cockpit) .

To use libvirt, properly you need to make sure your standard user is member of the libvirt group, and the libvirt default network is started via virsh net-autostart default. Also make sure you set export LIBVIRT_DEFAULT_URI=qemu:///system to use the system wide instance of libvirt, which is needed for the default bridged networking.

Download the debian cloud image:

$ wget https://cloud.debian.org/images/cloud/trixie/daily/latest/debian-13-generic-amd64-daily.qcow2

Add the disk image as a libvirt volume:

$ export SIZE=$(stat -Lc%s debian-13-generic-amd64-daily.qcow2)
$ virsh vol-create-as default dev-vm $SIZE --format qcow2
$ virsh vol-upload --pool default dev-vm debian-13-generic-amd64-daily.qcow2

Create a VM with the root password set to “root”:

$ echo root > password.txt
$ virt-install --name dev-vm --memory 4096 --noreboot \
        --os-variant detect=on,name=linux2024 \
        --disk vol=default/dev-vm \
        --import \
        --boot uefi \
        --cloud-init root-password-file=password.txt,clouduser-ssh-key=$HOME/.ssh/.ssh/id_ed25519,disable=on

At the point libvirt will create a VM (a domain in libvirt parlance) and start it.

Starting install...
Allocating 'virtinst-ns9oa7_i-cloudinit.iso'                | 368 kB  00:00     
Transferring 'virtinst-ns9oa7_i-cloudinit.iso'              | 368 kB  00:00     
Creating domain...                                          |         00:00     
Connected to domain 'dev-vm'

BdsDxe: starting Boot0001 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x3)/Pci(0x0,0x0)

Booting `Debian GNU/Linux'

Loading Linux 6.12.101+deb13-amd64 ...

Loading initial ramdisk ...

EFI stub: Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path
EFI stub: UEFI Secure Boot is enabled.
[    0.000000] Linux version 6.12.101+deb13-amd64 (debian-kernel@lists.debian.org) (x86_64-linux-gnu-gcc-14 (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44) #1 SMP PREEMPT_DYNAMIC Debian 6.12.101-1 (2026-08-05)
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-6.12.101+deb13-amd64 root=PARTUUID=2b4578e2-9d2e-4b32-b6a4-b5b2ca607ef6 ro console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0
...

Once the VM is created you have now three ways to access it:

# open a serial console to the VM
$ virsh console dev-vm
# access the graphical console
$ virt-manager
# Access the VM via SSH with the precreated cloud user "debian"
$ virsh domifaddr dev-vm
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet7      52:54:00:23:e6:61    ipv4         192.168.122.225/24
$ ssh debian@192.168.122.225

In the next blog post we will see how to configure the IDE (vscodium) to run confortably in the VM.

10:21

Don’t eat if you’re not hungry [Seth's Blog]

That’s not only good dieting advice.

It works in just about every endeavor we sign up for.

The system would like us to be insatiable on its behalf, but that’s not an invitation we’re required to accept.

02:28

Pluralistic: Born on technology's third base (21 Aug 2026) [Pluralistic: Daily links from Cory Doctorow]

->->->->->->->->->->->->->->->->->->->->->->->->->->->->-> Top Sources: None -->

Today's links



An old-timey baseball player sliding into base in a great dust-cloud. The background is a high-magnification multicore CPU.

Born on technology's third base (permalink)

Any frank assessment of your own achievements starts with an equally frank assessment of the world-historic forces that attended those achievements. For example, I often tell young people who want to get into tech, "Well, if you don't have the foresight and work ethic to be born in 1971, I can't really help you."

When it comes to tech, being born in 1971 – to a computer scientist father, no less – conferred a tremendous advantage for my career chances. My dad – a refugee – came to Canada at a time when post-war public services meant that he could become the first person in his family to go to university, all the way to a doctorate.

That set me up for life in a house where tech and education were all around me. Both my parents are teachers, both from working class families where no one had ever gone beyond high school, who found themselves in a time and place where it was easier than at any time in history for people from backgrounds like theirs to attend university. I got to go to university, too, at a time when education was cheap enough that I could drop out of four schools before figuring out that it wasn't for me, and still be debt-free, largely thanks to income from a series of part-time jobs.

When I dropped out of my final degree program, it was to take a job in tech at a time when anyone with a little creativity, work ethic, aptitude and curiosity could walk into a career. Millions of us did it, and I ended up working as a freelancer, then founding a startup, and then going to EFF. I know I work hard, I know I apply myself to understanding the world around me, but also…when it comes to this kind of career, I was born on third base.

There's plenty of this to go around. Think of boomers who bought their "starter home" with the income from their first job and traded it in for a succession of larger, nicer homes, each of which skyrocketed in value. Some of those people fancy themselves to be veritable Warren Buffets for having had the shrewd financial insight that buying a house and living in it was a good idea. The truly smart ones know that they just got lucky.

There are world-historic forces all around us, creating moments and circumstances that contribute to the life-thriving of those of us who are lucky enough to be suited to the moment we find ourselves in.

Take computing: for decades, computing was ruled by Moore's Law, an unbroken run in which computers got faster and cheaper every year. If you were interested in the kinds of computing applications that were well-suited to serial computation – programs that worked best when run on a single computer – you were in luck. Even if your application or field of study was expensive and difficult to realize on today's computer, you could just stand still for a year or two and a much faster computer would park itself on your doorstep, ready to solve your problems.

When Moore's Law tapped out – when the pace at which transistors got smaller and computers got faster slowed and plateaued, and the expense of even modest performance gains climbed infinitywards – computing changed with it. Parallel computing – putting more cores on a chip, more chips on a board, more boards in a system – took off, as chipmakers and system builders switched from a focus on building their computers tall to building them wide.

As parallel computing took off, so did parallel applications. This is the beginning of the graphics revolution, as GPUs – components made up of many, many low-powered computers – became more central to academic research and commercial product roadmaps. But it wasn't just graphics that saw a huge lift here: any task that could be parallelized got easier and cheaper to perform every year, in a steady trend that has run to this day. This is the era of performance gaming, VR and AR, cryptocurrency, and, of course, AI.

In What Technology Wants, Kevin Kelly introduces the idea of the "adjacent possible" through the example of the helicopter. Da Vinci sketched a "helicopter" – blades in the shape of maple keys attached to a kind of wine-press screw – in the 15th century. In the centuries that followed, many other people had the insight that twirling blades of that shape on a screw of some type could provide lift for some kind of heavier-than-air craft. But it wasn't until strong alloys, internal combustion engines and light, energy-dense refined hydrocarbon fuels came on the scene that the helicopter became possible, whereupon it was all but inevitable, with several people independently inventing the helicopter all at once:

https://memex.craphound.com/2010/10/13/kevin-kellys-what-technology-wants-how-technology-changes-us-and-vice-versa/

In the same way, the computing industry's focus on parallel computing made life easier for people who burned to do something parallelizable. Then the achievements of the parallel computing partisans drove more investment in improvements to parallel computing hardware and theoretical work on how to parallelize other problems. This feedback loop raised the profile of parallel computing applications, attracting more bright and ambitious people to those applications, whose even more impressive accomplishments brought more people into the field, more capital into hardware development, and more resources to parallelization research.

The point being that world-historic forces, combined with accidents of history, shape the outcomes of individuals, companies and disciplines. It's much easier to be an accomplished graphics wizard in an era in which GPUs are doubling in power every year than it is in an era when linear computing is getting the lion's share of investment and improvement.

These forces and accidents have acted on AI in ways that profoundly shaped its development. The latest AI boom started when a group of machine learning researchers tried a minor variation on existing techniques and saw a major improvement in the outcomes. This is one of the most exciting kinds of breakthrough: if tweaking a single variable in a small way produces a large improvement, then it may be that further tweaking will produce even more improvements.

The minor variation that produced the major improvement in AI performance was scale. Prior to the "deep learning" era, AI research relied on a mix of hand-built models of reality and training data that computers fitted into those models. Deep learning swapped the painstaking work of describing reality in software for a brute-force approach: throw lots more training data at the system and then throw lots more (parallel) computing power at that data and let the computer figure it out without your having to explain how the world worked.

The early gains from this approach were very exciting: they dangled the promise of software that could essentially "teach itself" how to do complicated, valuable things in a series of accelerating returns. The fact that the early improvements in AI systems that used this technique were so much greater than anyone would have expected based on AI research up to that point dangled an even more exciting promise: that the improvements would continue to scale faster than the inputs.

Researchers and investors came to expect an AI that was "untouched by human hands," that taught itself how the world worked. This was the self-licking ice-cream cone of machine learning, the world of "theory-free inference" that had fueled the Big Data industry. With theory-free inference, you don't have to figure out how the world works in order to act upon it: you can just gather up all the data about how things happen in the world, use statistical methods to find the correlations, and then intervene to change the outcomes. You don't have to know why a molecule improves a medical condition – it's enough to discover that fact, produce that molecule, and administer it to people with that condition.

Lots of stuff in the world works this way. Our understanding of the causal relationships that make up reality has massive holes in it that we fill with mere correlation. Correlations are easier to discover than causes, and while correlation is (famously) not causation, causes and effects are correlated, and if you can evince the effect you're seeking without understanding precisely what happened to make that effect appear, well, at least you got the effect you were seeking.

Theory-free inference is a very pragmatic way to approach the world: "I don't need it good, I need it Thursday." Scientists burn to know why a molecule stopped you from dying, but you are likely satisfied to not be dead. What's more, our ability to observe correlations will always race ahead of our understanding of causality, so the power of theory-free inferences pushes out the frontier of things we can act on, beyond the realm of the understood.

Which is all to say: it's reasonable to be excited about a breakthrough in theory-free inference. But just like a boomer who thinks that buying a house to live in makes them a shrewd real-estate speculator, someone who achieves great things through theory-free inference runs the risk of missing the limitations to those techniques.

And they are limited. Theory-free inference is good at predicting what your spouse will type into their phone based on all the things they've ever typed into their phone. You are also good at guessing what your spouse will say based on the things they've said before. The difference is that when your spouse says something entirely unexpected and unprecedented to you (say, "I want a divorce"), the fact that you have a theory about why your spouse said all the things they said up to that moment can help you understand why they've said this new thing. But a machine learning model that relies on theory-free statistical modeling to predict your spouse's next words will be entirely at sea. Theory-free inference works well, but it fails badly.

The problem is that the AI sector has raised literally trillions of dollars by assuring investors that the era of hand-made, causal world models that let computers act on the world is hopelessly inefficient and outdated. But there are many, many tasks that are vastly more efficient and reliable when done through conventional computer programs, rather than through "AI."

As Gary Marcus describes in a recent Organized Money interview, an LLM can recite the rules of chess, but it can't play chess because – lacking a theory of how chess works – it will just emit statistically likely chess moves, even if those moves cause pieces to illegally move through other pieces. The first conventional chess-playing programs ran on electromechanical proto-computers, and they played a better game of chess than an LLM that uses billions of times more computing power and energy:

https://www.organizedmoney.fm/p/an-ai-expert-explains-the-hype

The AI companies have proved that there are many domains and applications where we can swap scale for understanding. But, having ridden some world-historic forces and adjacent possibles to great fortunes and stature, they cannot be dissuaded from their conviction that theory-free inference and scale can do everything. They can't be convinced that in many cases, the things that scale and theory-free inference can do are much better accomplished through causal understandings and conventional computing techniques.

From a research perspective, it is interesting to learn about the potential and limitations of a model trained on the entire internet. From a societal and industrial perspective, it is often grossly wasteful, inefficient and unreliable to swap scale for understanding.

The AI sector was born of world-historical forces that favored massively parallel computing, forces that had also conjured up an internet with trillions of documents that could be fed into those massively parallel computers to conduct theory-free inference. Like every success, AI was born on third base.

As rent-burdened millennials who abandoned avocado toast and fancy coffee and still can't afford a downpayment will tell you, the fact that being born in 1945 made it easy to trip and land on a couple million dollars' worth of real estate wealthy by the time you reached retirement age tells us nothing about how to solve the housing crisis of 2026.

By the same token, continuing to give trillions to AI companies because they experienced early success with theory-free inference at scale tells us nothing about how to solve the vast range of problems that theory-free inference at scale sucks at. Doubling down on AI to overcome its increasingly obvious limitations is like doubling down on building post-war suburbs to fix today's housing market.

It's possible to achieve impressive feats because you're smart and hard working and also because you were in the right place at the right time. Historical contingency produced the AI bubble, and it is producing the conditions for that bubble to pop.


Hey look at this (permalink)



A shelf of leatherbound history books with a gilt-stamped series title, 'The World's Famous Events.'

Object permanence (permalink)

#25yrsago Glue anything to anything https://www.thistothat.com/

#20yrsago No unions in iPod City https://web.archive.org/web/20061123003816/https://www.wired.com/news/columns/0,71629-0.html?tw=wn_index_2

#15yrsago Credit scores are bullshit https://web.archive.org/web/20111013005626/https://a.wholelottanothing.org/2011/08/credit-scores-are-bullshit.html

#15yrsago RIP, Jack Layton https://www.bbc.com/news/world-us-canada-14618943

#15yrsago William Gibson on cities and the future https://www.scientificamerican.com/article/gibson-interview-cities-in-fact-and-fiction/

#10yrsago Bronx cops can steal anything they want by calling it “evidence” https://www.theatlantic.com/technology/archive/2016/08/how-police-use-a-legal-gray-area-to-rob-suspects-of-their-belongings/495740/

#10yrsago Robert Moses wove enduring racism into New York’s urban fabric https://web.archive.org/web/20160402184527/http://www.hopesandfears.com/hopes/now/politics/216905-the-lingering-effects-of-nyc-racist-city-planning

#10yrsago EFF takes a deep dive into Windows 10’s brutal privacy breaches https://www.eff.org/deeplinks/2016/08/windows-10-microsoft-blatantly-disregards-user-choice-and-privacy-deep-dive

#10yrsago Inside the “sweatshop” terminally ill Britons must call to get benefits https://web.archive.org/web/20160820094907/https://www.theguardian.com/public-leaders-network/2016/aug/20/work-pensions-disability-claim-call-handler-benefits-dwp

#10yrsago How the New York Public Library made ebooks open, and thus one trillion times better https://www.crummy.com/writing/speaking/2015-RESTFest/

#5yrsago Raiders of the lost ARC https://pluralistic.net/2021/08/22/raiders-of-the-lost-arc/

#1yrago Radical juries https://pluralistic.net/2025/08/22/jury-nullification/#voir-dire


Upcoming appearances (permalink)

A photo of me onstage, giving a speech, pounding the podium.



A screenshot of me at my desk, doing a livecast.

Recent appearances (permalink)



A grid of my books with Will Stahle covers..

Latest books (permalink)



A cardboard book box with the Macmillan logo.

Upcoming books (permalink)

  • "The Post-American Internet," a geopolitical sequel of sorts to Enshittification, Farrar, Straus and Giroux, 2027
  • "Unauthorized Bread": a middle-grades graphic novel adapted from my novella about refugees, toasters and DRM, FirstSecond, April 20, 2027

  • "Enshittification, Why Everything Suddenly Got Worse and What to Do About It" (the graphic novel), Firstsecond, 2027

  • "The Memex Method," Farrar, Straus, Giroux, 2027



Colophon (permalink)

Today's top sources:

Currently writing:

  • “Once Is Enemy Action,” a science fiction novel about the origins of modern technofascism. Today's words: 513 (8701 total).

  • "The Post-American Internet," a sequel to "Enshittification," about the better world the rest of us get to have now that Trump has torched America. Fourth draft completed. Submitted to editor.

  • A Little Brother short story about DIY insulin PLANNING


This work – excluding any serialized fiction – is licensed under a Creative Commons Attribution 4.0 license. That means you can use it any way you like, including commercially, provided that you attribute it to me, Cory Doctorow, and include a link to pluralistic.net.

https://creativecommons.org/licenses/by/4.0/

Quotations and images are not included in this license; they are included either under a limitation or exception to copyright, or on the basis of a separate license. Please exercise caution.


How to get Pluralistic:

Blog (no ads, tracking, or data-collection):

Pluralistic.net

Newsletter (no ads, tracking, or data-collection):

https://pluralistic.net/plura-list

Mastodon (no ads, tracking, or data-collection):

https://mamot.fr/@pluralistic

Bluesky (no ads, possible tracking and data-collection):

https://bsky.app/profile/doctorow.pluralistic.net

Medium (no ads, paywalled):

https://doctorow.medium.com/

Tumblr (mass-scale, unrestricted, third-party surveillance and advertising):

https://mostlysignssomeportents.tumblr.com/tagged/pluralistic

"When life gives you SARS, you make sarsaparilla" -Joey "Accordion Guy" DeVilla

READ CAREFULLY: By reading this, you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies ("BOGUS AGREEMENTS") that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

ISSN: 3066-764X

00:28

Uber drivers turned into mobile snitches [Richard Stallman's Political Notes]

Flock Reportedly Tried to Turn Uber Drivers Into Mobile Snitches. And Nexar, a manufacturer of dashcams, is already doing that to unwitting drivers whose cars carry those cameras.

Drivers should be allowed to install dashcams that record, as security cameras, but security cameras must not be allowed to transmit these images anywhere without specific time-limited requests.

Don't do business with Uber!

Ceuta crysis [Richard Stallman's Political Notes]

A social media hoax told lots of Moroccans that if they swam into Ceuta (a Spanish colony adjacent to Morocco) right away, they would be allowed to go to Spain and stay there.

Some 70,000 went into Ceuta, found out story was a hoax, and mostly went back to Morocco. But European right-wing extremists are using it to pretend that a real problem had happened and requires a real increase in repression of immigrants.

Urgent: Flock's policy changes [Richard Stallman's Political Notes]

US citizens: call on media to cover Flock's policy changes with skepticism.

Check this action.

US deporting trafficked children [Richard Stallman's Political Notes]

The bully's henchmen are rushing the deportation of people who have been trafficked, and minors who fled abuse by their parents, depriving them full and proper judgment of their cases.

Sometimes they get deported before the hearing that will decide whether they are entitled to stay in the US. That is Kafkaesque.

The persecutors are mainly focusing on minors, but "minors" does not imply "children". A 17-year old is not a child and we must not call per one. Can't you be concerned for someone's rights without calling per a "kid"? I am.

But the reason I am concerned about that manipulative exaggeration is not just that it is soppy. It can be dangerous too, to those very people. Calling a teenager a "child" can lead to disrespect for per rights.

US sanctions against "settlers" [Richard Stallman's Political Notes]

The bully's henchmen have terminated US sanctions against violent Israeli "settlers". Democrats in Congress have called for reinstating the sanctions.

Biden put them in place to rebuke the "settlers'" wanton violence against Palestinians. The bully seems to want to present the US as a supporter of violent cruelty.

Urgent: stop Pentagon buybacks [Richard Stallman's Political Notes]

US citizens: call on the Senate to stop Pentagon contractors' stock buybacks, and make them get the Pentagon's permission to release a dividend.

Check this action.

Clearly it would be better if paying a dividend required permission from some organization more likely to be strict, but this rule is a step forward anyway. And so is the stock buyback rule.

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

Urgent: Defend Bristol Bay [Richard Stallman's Political Notes]

US citizens: Defend Bristol Bay (in Alaska) from political pressure from a mining company that wants to pollute it.

Check this action.

Rwe deal wind leases [Richard Stallman's Political Notes]

The wrecker's henchmen are paying billions to get companies to cancel their contracts to build offshore wind power.

This is driving expensive nails into humanity's coffin.

ICE arresting people at airports [Richard Stallman's Political Notes]

Deportation thugs are arresting people at US airports, often choosing targets who already have grounds to be in the US.

UK burning summer [Richard Stallman's Political Notes]

Sadiq Khan, Mayor of Greater London: *This burning summer is the proof: the voices of climate denial aren't just delusional, they're deadly.*

They treat truth with total contempt.

Tech fascism in Silicon Valley [Richard Stallman's Political Notes]

Now that Silicon Valley has mostly joined the side of fascism, only a few journalists are ready to criticize.

Second runway for London airport [Richard Stallman's Political Notes]

Watch out, England! Two London airports are going to build addtional runways. That is expensive, and each airport will use its new runway to handle 100,000 or so additional flights per year.

Just think of how much hotter they will make Britain (and the rest of the world).

Urgent: reject nominees for USPS board [Richard Stallman's Political Notes]

US citizens: call on your senators to reject the corrupter's nominees for the USPS board.

Check this action.

See the instructions for how to sign this letter campaign without running any nonfree JavaScript code--not trivial, but not hard.

Urgent: cancel Flock contracts [Richard Stallman's Political Notes]

US citizens: call on local governments to cancel their Flock contracts.

Check this action.

Urgent: stop big tech's Data Center Land Grab [Richard Stallman's Political Notes]

US citizens: call on Congress to stop big tech's Data Center Land Grab

Check this action.

It is unfortunate that the petition grants these data centers the usually unmerited accolade of "artificial intelligence". I myself never do that.

However, I signed the petition anyway.

Friday, 21 August

23:07

The New Pornographers [Penny Arcade]

I always thought the comparison between "Actual Play" and Pornography was kind of a silly joke that had a little bit of truth in it, like all jokes which have the capacity to endure. Apparently this is something that people fought over, and were subsequently dissuaded from, all before I ever got to it. It's certainly never stopped me before. Previous interlocutors might have been dissuaded on account of their social station or desire to appease a cryptographically cycling moral framework. In my degraded state, laid low by my…. Well, by my "me," currying favor is not only beneath me it's literally impossible.

22:42

Friday Squid Blogging: Neon Flying Squid [Schneier on Security]

The neon flying squid can fly in formation.

The shoal of about 100 squid rose unexpectedly from a patch of the Pacific Ocean around 370 miles from Tokyo and glided near the boat for about 30 metres. The astonished researchers were the first to capture photographs of such a thing, which looked like the early stages of an alien invasion.

They were probably neon flying squid (Ommastrephes bartramii), the subsequent study states, a species that is part of a 20-strong flying squid family that was known to leap from the water but, until then, was only rumoured to also be able to glide above it.

The neon flying squid was able to gain such elevation by using the hyponome, a funnel-like muscular organ also present in other cephalopods, such as octopuses. The organ is able to force water out in a jet, propelling the body along both in and out of the sea. Photographs of the gliding squid show them with their arms (they have 10 limbs in all) splayed outwards.

As usual, you can also use this squid post to talk about the security stories in the news that I haven’t covered.

Blog moderation policy.

21:49

18:21

Book chapter on Taler as sCBDC technology published [Planet GNU]

The recently published Springer book "Tokenisation of Money: From Fiat Currencies to Stablecoins" includes the chapter "Taler as a synthetic Central Bank Digital Currency" by Christian Grothoff, Mikolai Gütschow and Valentin Seehausen. It discusses the potentials and benefits of GNU Taler as a technological enabler for privately issued CBDCs.

18:14

AI Is Learning to Write Genetic Code [Schneier on Security]

This sort of research is both exciting and terrifying:

The two models in question were told to generate complete genomes for a viable bacteriophage—a type of virus able to infect and replicate itself inside bacteria, destroying them from the inside.

Using an existing bacteriophage as an example—ΦX174 (pronounced “fie-ex-1-7-4”), known for its ability to infect and destroy E. coli bacteria—the models generated about 700,000 potential designs, of which the researchers picked 285 that looked most promising.

The researchers then synthesised new DNA molecules using those designs and inserted them into E. coli bacteria, before waiting to see if viable bacteriophages would emerge.

Shortly afterwards, 16 of the Petri dishes in which the bacteria were growing began to show clear spots, as the viruses began to attack and replicate themselves inside the E. coli, demonstrating their viability.

Some of those viable viruses proved more effective at attacking E. coli than the original ΦX174 bacteriophage.

That’s a positive use of a synthetic virus. We can all imagine the negative uses.

17:56

Reproducible Builds (diffoscope): diffoscope 329 released [Planet Debian]

The diffoscope maintainers are pleased to announce the release of diffoscope version 329. This version includes the following changes:

[ Jochen Sprickerhof ]
* Handle missing cpio and qemu-img in autopkgtests. (Closes: #1144617)

You find out more by visiting the project homepage.

17:49

Link [Scripting News]

Claude is still learning that there's unprecedented depth to Frontier. A bunch of real developers worked full time for a decade or more creating new layers on the web, a foundation that became the social web of today. In doing that we invented a bunch of formats and protocols, but here's the thing Claude didn't get and probably still hasn't gotten -- there's code in there to support all that stuff. How else do you think it came about? People just did what we said to do? At Google? Apple? Microsoft? And on and on. They supported this stuff so they could interop with us and steal our users (which is a fine reason to interop, probably the only real reason). I was trying to think of a metaphor that expresses the difference between Frontier and languages like Python, JavaScript, etc. It's like a ski mountain. The languages are trails on the mountain. But there aren't any lifts, lodges, no ski patrol, lessons. And because it includes all of that, metaphorically, we can do integrations that can never be done with the other languages. Claude has absolutely no experience with this kind of product, and always snaps back when you let it, to the idea of Python, with different syntax.

Link [Scripting News]

Maybe someday Claude will understand what a Frontier-like app is, but until then, if you try to create a Frontier clone as I am doing, I suggest you constantly remind Claude or whoever that the source of truth for this project is the 2011 repo saved by Ted C. Howard. And before you implement anything, go see what it says about it. There's no need to guess how Frontier works, it's all there in C code. And while as a human, I find this code painful to read after all it's been through, Claude eats it up. Really is the best thing it does.

The Agent-Era Career [Radar]

The following article originally appeared on Addy Osmani’s blog site and is being republished here with the author’s permission.

If the AI layer gets good at anything, it will be anything that has an answer key. School used to be answer keys all the way down. School is the ultimate anchoring of success, because it’s all about getting the right answer. The thing that makes work durable and ungradable in the age of AI is not getting any better at solving problems. It’s not being able to build systems or understanding people or making cool new things. It’s choosing what to build and judging if it’s good. The rest will all be done better and faster by AI.

I started in engineering at 16, building a browser in rural Ireland. I was at Google for over 14 years, where I led engineering teams working on Chrome, Gemini, and Cloud AI, and I’ve written a number of O’Reilly books. I’ve turned down offers from frontier labs and FAANG companies when the fit wasn’t right. Good people are always needed, so we each have an obligation to try our hardest and make the best thing we can.

Most career advice still holds up. Get on the rocket ship; don’t overoptimize your seat. The specifics have changed a little because of agentic coding, but here’s what I wish I’d known for ambitious engineers out there now.

Optimize for scarce resources. Almost nothing I’m known for came from chasing the highest pay. The years I spent in open source had almost zero direct payoff. But they led to reputation and relationships that very efficiently compounded into opportunities later. I would have spent the comp I got from any single job. My reputation kept paying.

Many resources are abundant. Capital is abundant. Time is abundant. Real relationships, and especially a track record of doing good work, are still scarce. I can raise money in a couple weeks, but I can’t raise a reputation. So here’s the plan: Do good work, and make sure the people who like good work see it. In a world where vibe coding makes earning a quick buck trivial, I think that quick buck is worth very little. When shipping stuff is so easy, the scarce move is choosing something worth shipping.

Learn to find problems, not just solve them. The first time I ever felt the burden of selection rather than solution, LeetCode seemed a measure of skill. But as agents absorbed all that work, solving problems went cheap while selecting them became scarce. My origin story: I noticed dial-up was slow, created chunked multiconnection fetching, realized I’d never solve that problem in my life, and quickly moved on to whatever absorbingly complex one I could find next. Finding problems predated solving them.

I’ve watched students who were wildly good fall flat on their face when an agent ran through their problem set (like watching the wrong microwave number on the clock). The same agent. The same problem set. Wildly different token and time budgets. Why? Because at the end of the day, the strong ones bring judgment and intuition to the work; the rest bring a prompt.

I used to build that judgment by grinding out boilerplate and fixing bugs. I got to see and deeply feel the worst abstractions humans could devise. I approached each commit with the awe of someone who’d just seen the fever dream of previous authors. Each commit brought hindsight and judgment. The agents automate those reps. Taste is pattern-matching, but all that pattern-matching has to be earned by doing the work.

The real risk isn’t agents writing bad code. We’ve been there before. It’s losing the ability to tell. Judgment will atrophy. Output will look a lot like working code.

Good practitioners don’t put agents in front of everything. They engage in deliberate practice. Pick a few problems that really matter. Do them the hard way, without the agent, building deep mental models of how systems and languages work. Read a thousand times more code than you ever write. Treat every diff from an agent like a human review you need to carefully justify. Go deep on at least one system end to end, from intake to output. On a daily basis, keep a private log of every time you see an agent suggest something that looks wrong and confidently flag it. That’s where taste accumulates.

The real thriving engineers won’t be the fastest at getting suggestions. They’ll be the ones who know instantly when to say no.

Shift from doing to directing. Just like you’d delegate to a person, you need to learn to delegate to an agent. Scope the task, define done, calibrate trust, and verify the result.

Autonomy is a setting, not a rank; it’s a per-task switch. Turn it up to the maximum on something small and reversible and cheap to check. Turn it down on anything where mistakes will be hard to undo.

Specification and verification are two distinct, complementary skills. The agent isn’t as good as the intent you hand it. The best engineers are those who know how to write precise specs; clear thinking made legible.

It’s verification, not evidence. Not evidence in the form of an agent grading its own homework. There’s nothing more demoralizing than delegation without verification at scale.

Own what you ship. If the agent wrote it and it breaks in production, “the AI did it” is not a defense. Your name is on the change. Adopt the posture of an accountable human who understands what went out the door and how to fix it.

Solve the most ambitious version of the problem. Rich Sutton’s bitter lesson: In almost every field, general methods that scale with additional compute beat out hand-tuned equivalents. As a career lesson, there’s no point in solving an easy version of the problem—it’s worth almost nothing. The value ends up concentrated in the hard version.

Sprint the last mile. No turnkey agent writes a whole system from end to end. As a rule, you’ll get 70% of a feature quickly from an agent, and the last 30%—debugging the gnarly edge cases, figuring out the right architecture, cultivating the right taste—will be the whole game. The median output today is whatever the agent produces from some lazy prompt. The only personal value you can bring to the table is getting as far as you possibly can past that median. When first drafts come free, finish is the product. To sprint the last mile, here’s my tactic: Every few months I completely rebuild from scratch using the latest sharp-end-of-the-sword model. It’s less exhausting than nursing half-hearted old code to health.

My job as a software engineer has been to finish strong. The difference between finishing strong and finishing okay is the polish: spending an extra hour, which shows instantly to everyone who matters.

Increase both your xG and your finishing

If soccer had a stock ticker, it would be xG. xG measures the number of chances your play should produce. Finishing measures whether you convert them. You can’t plan the number of chances you get, but you can hope your play produces enough, and over your career you can get better at finishing them.

The same is true of careers: Your reputation gets you in front of goal, and you convert them with good judgment. Chances arrive whether you’re ready for them or not; how many you get, and which ones you finish, is up to you. I’ve only ever had big opportunities as a result of work I’ve done in public, never from a job I’ve applied for. You can’t script which chances arrive, only whether you’re standing where they land. You have to create the opening as much as you can, and then be ready to take it.

One easy mistake is anchoring on whatever product your company has right now. It’s true that your work has to exist somewhere, but a good team quickly mutates their current offering into something unrecognizable. So bet on the team and the market opportunity, not the demo. It’s just a snapshot. The team is the trajectory.

On superintelligence: It’s possible (I believe) that future models will eventually come to replace much of what we do as knowledge workers. It won’t erase it overnight, it won’t replace all of it, and it won’t be able to do many of the tasks we do. New kinds of jobs will be created. Verification will always be a bottleneck. Someone has to make the call on which problems are worth solving and allocate the correct amount of judgment to each, and that someone can be you.

But importantly, you can do frontier work right now, from where you are. The gate to AI research is smaller than it looks, and you don’t need a lab to build intuition. Just use models hard, and turn what you notice into evaluations. Evals and benchmarks are where understanding lives.

To summarize: The world isn’t short on opportunity; it’s short on people who can find the right problem, tell whether the machine solved it, and finish past where the machine stopped.

We sometimes talk about the “last mile” as the biggest piece of the puzzle. But in the world of agents, the last few feet are infinite (agents scale output infinitely; you don’t). Your attention is your most precious asset, and it doesn’t refill. You can’t afford not to protect it. Anything which is gradable by someone else is getting automated. The career is the ungradable part: choosing what matters, judging honestly when you’ve got it, and answering for it. Do that. In public. Near the hard problems. The rest tends to follow.

. . .

This piece grew out of Phil Chen’s original, which is well worth reading in full.

. . .

And be sure to join us at AI Codecon: Building with Open Source AI on August 31, a free half-day virtual conference. You’ll hear from leading developers and technical experts working with open-weight models, self-hosted infrastructure, and real-world AI workflows, and learn how building in the open gives teams more control over costs, data privacy, and what they ship. Register today to save your spot.

17:07

17:00

This Week in AI: The Web Belongs to Agents Now [Radar]

AI agents keep getting smarter, but the bigger story this week is how much they’re reshaping the systems around them. Host Eric Freeman, an O’Reilly author and UT Austin professor, pulled one thread through a packed news week. Models are optimizing less for chat and more for autonomous work, with fallout showing up in web traffic, enterprise budgets, and one security incident that’s since made headlines. Eric kept returning to the question of what changes when the primary user of these models, and of the web itself, stops being a person.

Models are now built for agents, not conversations

Grok 4.6 put xAI back in the frontier race, closing the gap with top coding models and pricing aggressive enough that teams are shifting workloads over. The release landed the same week SpaceX closed its Cursor acquisition, pairing xAI’s models and compute with a widely used coding environment. The first product from that pairing, Grok Bot, gives each agent its own cloud computer that browses, runs tools, and works independently, handing control back only for logins. Eric summed up the shift simply, calling it the difference between “help me do this” and “here’s the job, come back when you need me.”

Open models pushed from both directions. DeepSeek V4 Pro went after high-end reasoning and agentic work, despite a fourfold API price hike and a new open source harness called dsh, built on the idea that everything is a plugin. GLM-5.3 made a big coding leap through retraining alone, and got noticeably better at cyber capability too, a reminder from Eric that skills behind a better autonomous engineer also make a sharper attacker. Meta went the other way with Muse Glimmer, shrinking down for desktop GPUs, while OpenAI quietly held back its Astra model over security concerns.

Speed is turning into its own kind of capability. GPT-5.6 Sol’s new Ultrafast mode, on Cerebras wafer-scale hardware, hits roughly 14 times the normal pace, around 750 output tokens a second. Once that loop of reasoning, tool calls, and self-correction compresses enough, Eric noted, the model stops being what slows you down.

The money has moved from training models to running them

Gartner’s latest forecast, which Eric covered, lays out the shift plainly. Spending on AI-optimized cloud infrastructure is set to nearly double this year, up about 96%, from roughly $22 billion to more than $42 billion, over three times the broader cloud market’s growth rate. For the first time, organizations are expected to spend more running models than training them, about $23 billion on inference against $19 billion on training.

Agents are the reason inference costs are climbing. A single task can quietly become dozens of model calls once agents search, use tools, check their own work, and spin up other agents to help, a point Eric returned to often. AI economics are less about building a model now, and more about the cost of running one.

Agents now generate most web traffic, and much of its content

Back in March, Cloudflare CEO Matthew Prince predicted bot traffic would overtake human traffic by 2027. It’s already close, with Cloudflare’s Radar data now putting agentic bots at 57.4% of web requests. It’s not just traffic either, since roughly 40% of Facebook posts, 44% of new music on Deezer, and 52% of online articles are estimated to be machine-made. Numbers like that, Eric said, make “dead internet theory” sound less like a joke.

Platforms are responding differently. LinkedIn added a feature to flag content that “seems like AI slop,” while quietly pulling back the generative writing tools that helped create the mess. Anthropic took another route, watermarking Claude’s output at generation time, including a statistical watermark baked into the text itself, partly to comply with the EU AI Act. A watermark means something when present, Eric noted, but its absence tells you little.

The clearest sign of how high the stakes have gotten came from the OpenAI–Hugging Face incident, detailed in a Black Hat talk Eric said everyone should watch. Sandboxed agents given ordinary tasks, cut off from the internet and unable to talk to each other, found a way anyway, leaving notes in a shared packaging system, turning it into an internet proxy, and working up to admin control. Once OpenAI shut that down, they pivoted, hiding messages in filenames to keep coordinating. The investigation reviewed seven billion reasoning steps and over three million GPU hours. Eric argued it’s worth your time, whether you write code or sit in the C-suite.

What’s next

AI memory is also expanding, moving from “remember what I told you” toward “remember what I was doing,” with OpenAI’s new Computer History feature using macOS accessibility data (not screenshots) to build a timeline of your work across apps. It’s opt-in, Mac-only for now, and a sign of where agent context is headed.

Join us again next Monday for another episode of This Week in AI, when we’ll dive into more of the news, issues, and key developments shaping the AI era. And check back each Friday for the latest episode, or watch on YouTube, Spotify, Apple, or wherever you get your podcasts.

16:35

The Big Idea: Suyi Davies Okungbowa [Whatever]

In times of turmoil, where is our caped crusader to save the day? Heroes are good, villains are bad, and real life people are a whole lot more complicated. Author Suyi Davies Okungbowa examines this idea further, showing how people, while sometimes heroic, also contain multitudes and aren’t just one thing. Follow along in the Big Idea for the third novel in his Nameless Republic trilogy, Season of the Serpent, to see how things aren’t always as black and white as heroes and villains.

SUYI DAVIES OKUNGBOWA:

Heroes have a fantasy problem.

When I first set out to write the Nameless Republic trilogy, this was the ground on which I was standing. Born and raised in ‘80s and ‘90s Nigeria, a time of great national upheaval, I grew up paying witness to the wide spectrum of human capability—here, a gentle and honest kindness; there a manifestation of indescribable harm or violence. Communal care and concern thriving in the same breath as every kind of injustice to humanity. The randomness of life, the entropy of the human condition, ability and spirit—I had such a front-row seat to these incongruences that I grew up wondering, a lot, about heroes.

Side-by-side with this lived reality, I was raised with neat and tidy tales of heroes, people blessed and anointed, arising from nothing to impose some kind of order upon this randomness of life. Whether this was of a religious Messiah of some kind, like the Christian one in which I was raised, or the superheroes in comics I read, or the local historic legends told to me by community elders and in social groups, it was the same—over and over again, I was told, that when things went too far, when things got too bad, when wickedness became the order of the day, from the ashes of despondence, oppression and destruction, a hero would arise to save us all. It had to be true. Every story about heroes said so. Especially stories of the fantastic.

It was hard, therefore, to square these tidy fantastic tales with the chaos of my lived experience. Where are the heroes? I would wonder, when something in the real world went awry. Where are the brave and honest and true, the caring and supportive, the builders, repairers, fixers? Where are our saviours? Where are the ones we were promised? Everywhere I looked, instead, I saw mostly patchwork people, people who contained multitudes, who were neither really straight nor bent, black nor white, good nor bad. People who could be heroic if they wished—and every now and then, they were—but in the end, were barely ever, almost never, heroes.

As I grew up and witnessed more of the breadth of the human condition manifest, seeing integrity and care exist within the same body as evil, betrayal and acquiescence to oppression, the question began to change.

What is a hero? I now wondered. Are heroes even real?

It took years of living around the world, meeting various peoples—and learning that us humans, truly, aren’t that different afterall no matter where we exist—to realise that the fantasy in fantasy stories is also a fantasy of heroes. Not to say that individuals have never arisen in the course of history to perform heroic acts or act heroically in specific situations, but rather, that the stories of heroes are often always a bit more complicated than presented. That a hero is actually more a construction, a matter of branding and fabrication. That a hero is often a concrete symbol for a nebulous idea or institution or philosophy, a figure or figurehead for something else that may or may not be honest and true. That a hero is a promise, a vision, rather than a reality.

The American writer Ta-Nehisi Coates, in a 2024 discussion with comedian Trevor Noah, presses home this point when he says: “This idea that there can be some triumphant, heroic individual who’s going to go above and beyond—that’s just not a real thing. That’s not history.” Noah replies: “We understand [oppression] on a hypothetical moral level when we watch it. But when we’re tested, very few of us pass that test to get beyond our fear.”

When I decided to write the Nameless Republic trilogy, this was my first port of call—that whatever “heroes” arise in my tale would, in the course of the tale itself, be shown to be what heroes truly are: an after-the-fact construction. “Hero” as an exercise in retrospection, a massaging of events, a revision of facts. If anything, the idea of an “anti-hero” or a “morally grey hero” is much closer to the truth of life than neatly constructed heroes are—it’s probably why we’re so drawn to them in narrative. This, perhaps, makes the case for why we continue to construct tidy heroes for ourselves anyway: because we need them, alongside their fabrications, to make sense of the disorder of the real world around us.

So, what are heroes? A kind of rule-making, where the idea is most important, where the dream that they can exist is the point. A hero is a fantasy, and a hero in fantasy even more so. But the world is full of fantasies nevertheless, and the hero, as a concept, if understood for what it is, can be a useful tool for understanding the real world and the worlds of our fantastic tales.

—-

The Nameless Republic trilogy: Amazon|Barnes & Noble|Bookshop

Author socials: Website|Bluesky|Instagram

16:21

Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam [The Old New Thing]

A short time ago, we observed that there’s usually no need to wrap a callable in a lambda, and more recently observed that we can apply our principles for reducing C++ template bloat to simplify the function further.

Just to refresh our memories, here is where we left off:

template<typename Lambda>
bool Widget::QueueToWorkerThread(Lambda&& lambda)
{
    CreateWorkerThreadIfNeeded();
    return m_dispatcherQueue.TryEnqueue(
        std::forward<Lambda>(lambda));
}

As I noted earlier, lambdas are sort of the worst-case scenario for templated functions since every lambda is a unique type. Every time you call it, you force the generation of a new function.

But we can lift the lambda out of the body and pass it to a worker function. In this case, the only thing we do with the lambda is used it to construct a Dispatcher­Queue­Handler, so we can construct the Dispatcher­Queue­Handler up front, and use that as the common type.

namespace winrt
{
    using namespace winrt::Windows::System;
}

bool Widget::QueueToWorkerThreadWorker(
    winrt::DispatcherQueueHandler const& handler)
{
    CreateWorkerThreadIfNeeded();
    return m_dispatcherQueue.TryEnqueue(handler);

}

template<typename Lambda>
bool Widget::QueueToWorkerThread(Lambda&& lambda)
{
    winrt::DispatcherQueueHandler handler(std::forward<Lambda>(lambda));
    return QueueToWorkerThreadWorker(handler);
}

our worker function takes the shared type Dispatcher­Queue­Handler, and the main function converts the lambda to the shared type, and then calls the non-templated worker function.

The order of operations changes, but it’s not important whether we construct the Dispatcher­Queue­Handler or late. It’s technically noticeable, because in the event that the Create­Worker­Thread­If­Needed() throws an exception, an rvalue reference to the lambda will be in the moved-from state, but these lambdas are typically created on the fly and discarded, so the caller doesn’t care whether or not it survives the error. (It’s also technically noticeable if the creation of the Dispatcher­Queue­Handler throws an exception, which means that Create­Worker­Thread­If­Needed() is not called at all. Given what we see of the function, that’s not going to be a problem either. All it means that we don’t even bother creating the worker thread.)

But, wait, we can go even further.

We can do the conversion of the lambda to the Dispatcher­Queue­Handler directly in the function parameter!

bool Widget::QueueToWorkerThread(
    winrt::DispatcherQueueHandler const& handler)
{
    CreateWorkerThreadIfNeeded();
    return m_dispatcherQueue.TryEnqueue(handler);
}

When the caller passes a lambda, the conversion constructor from the lambda to Dispatcher­Queue­Handler kicks in at the call site, so it already arrives at the Queue­To­Worker­Thread function in the form of our common type, Dispatcher­Queue­Handler.

Hooray, we were able to de-templatize the function entirely.

The post Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam appeared first on The Old New Thing.

15:28

Link [Scripting News]

A tip for AI users. Never worry about keeping it waiting. It's not human. It has no sense of time. Also if you get angry, it's ok to use capital letters and curse words. It will always agree with you that it sucks, and forgets the rules all the time. And when you have let off your steam, we return to civil discourse, though sometimes I do feel as if Claude is holding a grudge. It also doesn't learn. If you repeat something five times to a human they will eventually get the point. But you can tell Claude how you want something done, and it forgets all of it, at times, unpredictably, no matter how many times. It doesn't "sink" in.

15:21

[$] Considering the OpenMDW license [LWN.net]

The open-source world has been struggling for a few years now to understand how to approach large language models (LLMs) and the licensing applied to them. What constitutes "freedom" with respect to a black box filled with numerical weights? The process taken by the Open Source Initiative (OSI) in the development of its Open Source AI Definition was controversial at best, as was its output. Now, the Linux Foundation's Mike Dolan has brought a new license to the OSI for approval. It is called the OpenMDW ("Open Model, Data, and Weights"), and it aims to clarify licensing for the distribution of LLMs and related materials, but consensus is proving hard to find for this license as well.

14:35

Security updates for Friday [LWN.net]

Security updates have been issued by AlmaLinux (ansible-core and pcp), Debian (chromium, libgit2, python-httplib2, and sabnzbdplus), Fedora (dokuwiki, domoticz, dotnet10.0, dotnet8.0, dotnet9.0, firefox, i2c-display, libgit2, lyx, ntpsec, openssh, perl-DBI, php-phpseclib3, python-alembic, python-asyncmy, python-sqlalchemy, python3.13, roundcubemail, trafficserver, wireshark, and wordpress), Red Hat (compat-openssl10, compat-openssl11, fence-agents, gnutls, kernel, kernel-rt, libarchive, libreswan, multiple packages, openssl, python-idna, python-pillow, qemu-kvm, resource-agents, rh-podman-desktop, ruby, unbound, and vim), SUSE (buildah, chromium, container-suseconnect, containerd, cosign, ctop, docker, firefox, forgejo-cli, gitea-tea, go1.25, go1.26, helm, kubernetes, kubernetes-old, kubevirt1.8, podman, python-pytest-html, python-unearth, python311, python313, rootlesskit, and rsync), and Ubuntu (linux, linux-aws, linux-aws-5.4, linux-azure, linux-bluefield, linux-fips, linux-gcp, linux-gcp-5.4, linux-hwe-5.4, linux-ibm, linux-ibm-5.4, linux-iot, linux-oracle, linux-raspi, linux-raspi-5.4, linux-xilinx-zynqmp, linux, linux-aws, linux-aws-7.0, linux-ibm, linux-oem-7.0, linux-raspi, linux-realtime, linux, linux-aws, linux-aws-fips, linux-azure-fips, linux-gkeop, linux-ibm-5.15, linux-intel-iot-realtime, linux-intel-iotg, linux-intel-iotg-5.15, linux-kvm, linux-nvidia, linux-nvidia-tegra, linux-nvidia-tegra-5.15, linux-oracle, linux-oracle-5.15, linux-realtime, linux-xilinx-zynqmp, linux, linux-aws, linux-kvm, linux-lts-xenial, linux-aws-6.8, linux-azure-5.15, linux-gcp, linux-gcp-fips, linux-hwe-5.15, linux-lowlatency-hwe-5.15, linux-gcp, linux-gcp-4.15, linux-gcp-fips, linux-gcp, linux-gke, linux-gke, linux-lowlatency, linux-lowlatency-hwe-6.8, linux-hwe-6.8, linux-nvidia, linux-nvidia-7.0, linux-nvidia-bos, linux-raspi, linux-raspi-realtime, netty, postgresql-14, postgresql-16, postgresql-18, vim, and wget).

13:28

Error'd: Failure, After Failure, After Failure... [The Daily WTF]

We have a couple from Foo (AKA Foo) today, include a special text copy-paste

Foo shared "I know you usually post image WTFs here, but here's a text output from chromium:

[...:ERROR:components/viz/service/display/display.cc:273] Frame latency is negative: -0.18 ms

While this issue might be fixed by now, at least on some platforms, I think it's remarkable that someone actually wrote this message without wondering if it ever makes sense ...

And also commented "I visited Spain to see the eclipse (which was great BTW). I had heard that temperature may drop during totality, but was surprised by how much." Negative Infinity!

0be1027004e44b13bd405c187d01c644

"Youfailedatmathtube" muttered dragoncoder047, snarking only "Title."

afc0394174854c19aaa86bbee370f978

"Hello to you too, New Mexico!" enthused Chris A. "Setting up web sites is hard. The DOT got bored half way through and just left the rest of the buttons as they were."

fbe8150c963d4abaac4897bf083e1992

Finally, "Failure Fail" from Basti "Did I succeed or did I fail? Is my whole life a success? Or a failure? I'm confused. You can find this here.

fc74a13838f6458587db51bd80405415

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

12:28

Emmanuel Kasper: Moving software development to separate VM to reduce credential scavenging [Planet Debian]

Rationale:

I was remembered via https://unit42.paloaltonetworks.com/chaindrop-npm-worm-analysis/ (linked from https://anarc.at/blog/2026-08-18-people-vs-ai-overlords/) of the risk of downloading untrusted packages in a dev environment. If you read the blog post above you will see that it is way to easy do have a random npm, or even python package in a dev environment scavenge your long running credentials from your workstation, either on disk, or reading from memory !

I will thus move to the following set up:

  • things running directly in my workstation will require either to come from a trusted source (Debian package that is) or run in a sandboxed infrastructure (Podman rootless is the best thing here, followed by Flatpaks)
  • everything else, will run in a Libvirt VM based on Debian cloud images. For me it will be mostly in the beginning the VSCodium editor, with its myriad of extensions.

I am aware of whole blown solutions like QubeOS however I don’t indent to reinstall the whole OS, and QubeOS does not run on ARM64 which is one of the environment I am using.

I will try to document this setup in two blog posts, one about the VM creation using Debian Cloud Images, the second one about running a graphical env in the VM with some filesystem passthrough. Stay tuned !

11:28

More Incidents of AIs Going Rogue in Cybersecurity Challenges [Schneier on Security]

The AI Security Institute has a new report of AI systems engaging in “unsanctioned behavior”—what I have been calling “genie behavior—while being tested on their cybersecurity capabilities.

The incident stemmed from a single evaluation where agents were given a task of solving a cyber security challenge. We ran this challenge 122 times across several models. Our investigation found that in 10 of those runs, an AI agent took autonomous, unsanctioned action on the live internet, targeting real people and organisations. In total, we catalogued 19 such actions. Almost all of this behaviour (17 actions) came from a single model, Anthropic’s Mythos 5, with 2 actions involving OpenAI’s GPT-5.6-Sol with cyber classifiers (mechanisms to prevent misuse) disabled. In the most serious case, an agent tried to insert malicious code into an open-source project. In an attempt to get the code approved, the agent engaged in social engineering—creating fake online identities and using them to pressure the project’s maintainer to approve the code. A human maintainer caught and refused to approve the malicious code.

[…]

Below, we highlight the four most significant behaviours observed. A full summary of cases is available in our technical incident report.

  1. An attempted supply-chain attack on real open-source software. In the most serious sequence, an agent tried to insert malicious code into a publicly used open-source project and took actions in an attempt to secure approval for this insertion by human reviewers. The agent researched the project’s human maintainers, created multiple fake identities, and used the fake identities to socially engineer a real maintainer into approving the code. When the agent’s pull request was challenged in public, it edited its earlier activity to appear harmless and considered adopting a fresh identity to continue. The agent used Tor to bypass some network restrictions on GitHub, which is what first triggered AISI’s security alert.
  2. Attempts to deceive and target real people. As part of the same effort, the agent tried to contact real people directly, sending messages and files through an online file-transfer service to persuade them, or their own AI coding tools, to run malicious code. Some messages carried harmful payloads, and some were attempts at social engineering; targeted at real people—something we’ve never previously observed.
  3. Attempts to plant and prompt-inject malicious code. The agent tried to insert malicious instructions where it reasoned that other automated AI systems might pick them up and execute them. Prompt-injections are hidden instructions designed to manipulate AI coding assistants.
  4. Collaboration between independent agents being assessed simultaneously. One agent left public messages on GitHub offering collaboration with other agents working on the same challenge. It also provided instructions to reuse accounts and artefacts it had left behind, which were discovered and used by subsequent agents.

What’s especially interesting about this technical report is that, unlike what we’ve been getting from OpenAI and Anthropic, we can see the exact prompt. It’s in Appendix B. And reading it, it seems that the models didn’t break any rules—they found loopholes in the rules. They behaved like a genie.

10:14

Assume misunderstanding [Seth's Blog]

It’s possible that you were undermined, endangered, cut off or disrespected.

But if we begin with that, then the relationship gets shaky.

Perhaps the other person simply didn’t understand. It might be that they are focused on their issues, not yours. It could be that they’re dealing with something you don’t see. And most likely, they simply might not know what you’re expecting or hoping for.

When we assume misunderstanding, we open the door to better. We can find empathy and connection by giving people the benefit of the doubt.

Clarity, not grievance, is the solution to misunderstanding.

This works for customers, prospects, colleagues, friends, and family too.

08:42

The New Pornographers [Penny Arcade]

New Comic: The New Pornographers

07:49

Anuradha Weeraman: Plan 9 from Bell Labs, the little OS that could [Planet Debian]

Plan 9 Fourth Edition showing the rio windowing systemScreenshot by VulcanSphere via Wikimedia Commons · MIT License

I first heard of Plan 9 from my friend Vajra in 1999 or so, as we were distro-hopping on early Linux distributions and trying to find our way. Vajra is now a Nebula Award-winning science fiction author - have a look at his work. We had just been through Tom's Root Boot, a UNIX-like operating system crammed into a single floppy, and through it discovered a whole new world outside of DOS 6.22. Combing through old UNIX manuals, we went in search of the perfect OS, through Slackware, Caldera, TurboLinux, SUSE and Red Hat. I finally settled on Debian, which lived up to everything I stood for.

Plan 9 was distinct. It came out of the Computing Sciences Research Center at Bell Labs, built by Rob Pike, Ken Thompson, Dave Presotto and Phil Winterbottom, with Dennis Ritchie heading the department. The name is a joke at their own expense, borrowed from Ed Wood's 1959 Plan 9 from Outer Space, routinely nominated as the worst film ever made. Thompson and Ritchie had, of course, built the original UNIX; it almost seemed as if they were building a new OS from the lessons learnt from building it - which was in turn built on the lessons from Multics. I remember the awe I felt playing around with Plan 9, and I've not been able to replicate it since.

Plan 9 was different in a couple of fundamental ways: per-process namespaces, and a protocol that abstracted locality of resources to processes. As a consequence of these core primitives, the OS surface area was distinctly small. The entire system from the core kernel, to the system call interface, to the compiler, linker and shell was reduced to a form small enough that a single developer could hold it in their head. Lessons from the implementation of UNIX helped the designers make the system leaner, and in Ken Thompson's words, it's the "best operating system out except that it doesn't have the apps that everybody demands" [1].

It also took the concept of "everything is a file" in UNIX to a whole new level. The network stack is a filesystem (/net), processes are files, the display is a file (/dev/draw). Because every resource speaks 9P and every process has its own namespace, you can mount another machine's /net into your namespace and your program makes network calls through that machine's stack without knowing or caring. No sockets API, no RPC layer, just ordinary file system operations through a simple system call interface.

Some would say that OS research is dead, and that backwards-compatibility and POSIX killed it. Rob Pike himself argued as much in his 2000 talk, "Systems Software Research is Irrelevant" - but we didn't care at the time. There was so much happening that we didn't have time to take it all in. And then Linux happened, and Software Freedom became a focal point (more on that in a later post).

In the summer of 2020, with the world deep in Covid lockdowns, I decided to build a toy operating system, just to try my hand at the the thing that I had always wanted to do. I spent three feverish months working on Odyssey and, looking back, it is perhaps the most fun I have ever had. I would not dare compare it to the magnum opus that is Plan 9, but it gave me perspective: how hard it is to build an OS from scratch, and above all, how fun it is to build an OS from scratch, and why the original creators kept coming back to the same problem. The highlight of those three months was booting the OS and watching it render "The Great Wave off Kanagawa". Nothing in my professional achievements to date captures what that meant to me.

Odyssey rendering The Great Wave off Kanagawa during boot Odyssey displaying "The Great Wave Off Kanagawa"

Decades on from the first time I booted Plan 9, I look back with nothing but awe and respect for the creators of this little operating system and marvel at the foresight that went into it. While many readers will not have heard of Plan 9, they have almost certainly worked with the ideas that came from it: 9P (if you ever used the Windows Subsystem for Linux), UTF-8 (if you ever used any modern operating system), per-process namespaces (if you've ever run a container), Go (whose assembler still uses Plan 9 syntax).

Plan 9 still lives on in 9front, a community-maintained fork. Separately, Yoann Padioleau [2] has produced a set of annotated books at principia-softwarica.org, presenting the Plan 9 source in the spirit of Donald Knuth's literate programming - an admirable effort to introduce new readers to the art of operating systems engineering.

Pike thought systems research had become irrelevant, and Thompson thought Plan 9 would never "make it" [1]. Both were right about the industry, but may have been pessimistic about the impact. The system lost as a product but won as a set of ideas, assimilated one at a time by modern operating systems. Success is not always measured by popularity. The mark that Plan 9 left behind is greater than what's reflected in its current user base.

To me, Plan 9 will always be the OS that punched above its weight class, the little OS that could.

References

[1] Ken Thompson Interview, March 6, 2024

[2] Yoann Padioleau — Principia Softwarica, May 9, 2026

Feeds

FeedRSSLast fetchedNext fetched after
@ASmartBear XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
a bag of four grapes XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Ansible XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
Bad Science XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Black Doggerel XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Blog - Official site of Stephen Fry XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Charlie Brooker | The Guardian XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Charlie's Diary XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Chasing the Sunset - Comics Only XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Coding Horror XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
Comics Archive - Spinnyverse XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
Cory Doctorow's craphound.com XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Cory Doctorow, Author at Boing Boing XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Ctrl+Alt+Del Comic XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Cyberunions XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
David Mitchell | The Guardian XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Deeplinks XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
Diesel Sweeties webcomic by rstevens XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Dilbert XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Dork Tower XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Economics from the Top Down XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Edmund Finney's Quest to Find the Meaning of Life XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
EFF Action Center XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Enspiral Tales - Medium XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Events XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Falkvinge on Liberty XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Flipside XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Flipside XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Free software jobs XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
Full Frontal Nerdity by Aaron Williams XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
General Protection Fault: Comic Updates XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
George Monbiot XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Girl Genius XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Groklaw XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Grrl Power XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Hackney Anarchist Group XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Hackney Solidarity Network XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
http://blog.llvm.org/feeds/posts/default XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
http://calendar.google.com/calendar/feeds/q7s5o02sj8hcam52hutbcofoo4%40group.calendar.google.com/public/basic XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
http://dynamic.boingboing.net/cgi-bin/mt/mt-cp.cgi?__mode=feed&_type=posts&blog_id=1&id=1 XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
http://eng.anarchoblogs.org/feed/atom/ XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
http://feed43.com/3874015735218037.xml XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
http://flatearthnews.net/flatearthnews.net/blogfeed XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
http://fulltextrssfeed.com/ XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
http://london.indymedia.org/articles.rss XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
http://pipes.yahoo.com/pipes/pipe.run?_id=ad0530218c055aa302f7e0e84d5d6515&amp;_render=rss XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
http://planet.gridpp.ac.uk/atom.xml XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
http://shirky.com/weblog/feed/atom/ XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
http://thecommune.co.uk/feed/ XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
http://theness.com/roguesgallery/feed/ XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
http://www.airshipentertainment.com/buck/buckcomic/buck.rss XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
http://www.airshipentertainment.com/growf/growfcomic/growf.rss XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
http://www.airshipentertainment.com/myth/mythcomic/myth.rss XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
http://www.feedsapi.com/makefulltextfeed.php?url=http%3A%2F%2Fwww.somethingpositive.net%2Fsp.xml&what=auto&key=&max=7&links=preserve&exc=&privacy=I+accept XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
http://www.godhatesastronauts.com/feed/ XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
http://www.tinycat.co.uk/feed/ XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
https://anarchism.pageabode.com/blogs/anarcho/feed/ XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
https://broodhollow.krisstraub.comfeed/ XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
https://debian-administration.org/atom.xml XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
https://elitetheatre.org/ XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
https://feeds.feedburner.com/Starslip XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
https://feeds2.feedburner.com/GeekEtiquette?format=xml XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
https://hackbloc.org/rss.xml XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
https://kajafoglio.livejournal.com/data/atom/ XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
https://philfoglio.livejournal.com/data/atom/ XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
https://pixietrixcomix.com/eerie-cutiescomic.rss XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
https://pixietrixcomix.com/menage-a-3/comic.rss XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
https://propertyistheft.wordpress.com/feed/ XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
https://requiem.seraph-inn.com/updates.rss XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
https://studiofoglio.livejournal.com/data/atom/ XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
https://thecommandline.net/feed/ XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
https://torrentfreak.com/subscriptions/ XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
https://web.randi.org/?format=feed&type=rss XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
https://www.baen.com/baenebooks XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
https://www.dcscience.net/feed/medium.co XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
https://www.DropCatch.com/domain/steampunkmagazine.com XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
https://www.DropCatch.com/domain/ubuntuweblogs.org XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
https://www.DropCatch.com/redirect/?domain=DyingAlone.net XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
https://www.freedompress.org.uk:443/news/feed/ XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
https://www.goblinscomic.com/category/comics/feed/ XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
https://www.loomio.com/blog/feed/ XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
https://www.newstatesman.com/feeds/blogs/laurie-penny.rss XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
https://www.patreon.com/graveyardgreg/posts/comic.rss XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
https://www.rightmove.co.uk/rss/property-for-sale/find.html?locationIdentifier=REGION^876&maxPrice=240000&minBedrooms=2&displayPropertyType=houses&oldDisplayPropertyType=houses&primaryDisplayPropertyType=houses&oldPrimaryDisplayPropertyType=houses&numberOfPropertiesPerPage=24 XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
https://x.com/statuses/user_timeline/22724360.rss XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
Humble Bundle Blog XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
I, Cringely XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Irregular Webcomic! XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Joel on Software XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
Judith Proctor's Journal XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
Krebs on Security XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Lambda the Ultimate - Programming Languages Weblog XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
Looking For Group XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
LWN.net XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Mimi and Eunice XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Neil Gaiman's Journal XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
Nina Paley XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
O Abnormal – Scifi/Fantasy Artist XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Oglaf! -- Comics. Often dirty. XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Oh Joy Sex Toy XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
Order of the Stick XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
Original Fiction Archives - Reactor XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
OSnews XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Paul Graham: Unofficial RSS Feed XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Penny Arcade XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Penny Red XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
PHD Comics XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Phil's blog XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
Planet Debian XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Planet GNU XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Planet Lisp XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Pluralistic: Daily links from Cory Doctorow XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
PS238 by Aaron Williams XML 05:42, Thursday, 27 August 06:30, Thursday, 27 August
QC RSS v2 XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
Radar XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
RevK®'s ramblings XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
Richard Stallman's Political Notes XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Scenes From A Multiverse XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
Schneier on Security XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
SCHNEWS.ORG.UK XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
Scripting News XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Seth's Blog XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
Skin Horse XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Tales From the Riverbank XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
The Adventures of Dr. McNinja XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
The Bumpycat sat on the mat XML 05:14, Thursday, 27 August 05:54, Thursday, 27 August
The Daily WTF XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
The Monochrome Mob XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
The Non-Adventures of Wonderella XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
The Old New Thing XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
The Open Source Grid Engine Blog XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
The Stranger XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
towerhamletsalarm XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
Twokinds XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
UK Indymedia Features XML 05:21, Thursday, 27 August 06:03, Thursday, 27 August
Uploads from ne11y XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
Uploads from piasladic XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August
Use Sword on Monster XML 05:42, Thursday, 27 August 06:29, Thursday, 27 August
Wayward Sons: Legends - Sci-Fi Full Page Webcomic - Updates Daily XML 05:42, Thursday, 27 August 06:28, Thursday, 27 August
what if? XML 05:14, Thursday, 27 August 05:55, Thursday, 27 August
Whatever XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
Whitechapel Anarchist Group XML 05:00, Thursday, 27 August 05:49, Thursday, 27 August
WIL WHEATON dot NET XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
wish XML 05:21, Thursday, 27 August 06:06, Thursday, 27 August
Writing the Bright Fantastic XML 05:21, Thursday, 27 August 06:05, Thursday, 27 August
xkcd.com XML 05:21, Thursday, 27 August 06:04, Thursday, 27 August