Search Results: "zed"

25 August 2026

Antoine Beaupr : A more nuanced view of LLMs

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.

24 August 2026

Vincent Bernat: An interactive tour of the spanning tree protocol

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.1 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).2 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 bridge3 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.

Note While you scroll, the current simulation stays in view so you can look at it while reading. Uncheck this box to disable this behavior: .

All examples run in your browser, powered by MSTPD an open-source user-space4 implementation of RSTP.5

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:6 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:7
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).8
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.9 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 the device 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.10
: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 keeps forwarding because it 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:11
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 has 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 to the start one last time: 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.12 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. 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.13 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 simulation 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.14 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.15
: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 bridge from the root. The topology below is too big for BPDUs from R1 to reach beyond S20.16
: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 identifier 4096.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.17

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.18 Some topologies can take a bit more time to recover when the root bridge becomes unavailable.19
: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 interactive widgets. 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. The sprites for Stan and Blobby come from Craftpix, the coffee cups from Yanin.
  2. 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.
  3. From here, I use bridge instead of the more common word switch.
  4. The Linux kernel only runs STP. It delegates the other protocols to user space.
  5. 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.
  6. 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.
  7. To inspect the BPDUs crossing a link, select it, click the Download packets button, and open the file with Wireshark.
  8. A backup port only exists if the bridge has several ports on the same collision domain. This should not happen in a switched network.
  9. 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.
  10. 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.
  11. 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.
  12. 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.
  13. This timer makes RSTP resistant to packet loss.
  14. 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.
  15. An alternative would be Ethernet Ring Protection Switching (ERPS) another protocol I had never heard of until researching this article.
  16. 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.
  17. 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.
  18. 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.
  19. 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.

David Bremner: Reproducing Org mode configuration

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

23 August 2026

Russ Allbery: Long delayed haul

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.

Wouter Verhelst: Programming and GR 2026 002

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.

19 August 2026

Antoine Beaupr : The people vs the AI overlords

Also in this series:
In a post to oss-security, my (Debian) co-developer Russ Allbery stated that "open source software [OSS] is coming face to face with a motivation crisis that has been building for a long time". His point is essentially that large language models (LLMs1) are making the existing OSS community crisis worse. For him, it's the flood of code reviews, but he argues that varies according to people's desires, for others it's security issues and so on. I think Russ is right, but I would argue there's something much bigger than our open communities going on here, and it's about the entire field of computing. This pressure is on all of us, regardless of whether we work on open source software or not.

How people use models People using LLMs in their workflow have radically changed how programming works, even for people who claim to avoid vibe-coding. And I'm sorry to single out one poor maintainer here: it's not you, Brian, you're just one example among many. But this is typical use of those models nowadays:
Once it s done, I ll use /code-review and let Claude spawn sub-agents to do a full review of the new code. This usually finds some problems, even problems that the main Claude instance didn t find during its validation. I usually keep running /code-review again and again after finding and fixing issues, until there aren t any left.
Think about what that means for a minute. This is automation built to fire up dozens of agents crunching at a problem for minutes if not hours of GPU compute time, in parallel. This is essentially a couple of shelves in a datacenter rack, totally maxed out on power and cooling, abstracted behind a cute little /code-review command. The author, here, is rightly concerned that "Anthropic could pull the rug out and require API pricing", which is perhaps a code word for "charging something closer to actual costs". Brian also pays lip service to environmental and societal costs but those are largely abstracted away, so let's keep that conversation aside here as well, as we have discussed it before anyways. But clearly, this way of working has an (externalized) cost, to say the least.

Paying for non-free tools For decades my work has been focused on free and open source software. I've long stopped using proprietary operating systems like Windows or Mac, and even before that switch, I was mostly using free software on those platforms, partly out of principle, but also because I was too poor. So the tools of my trade are free, and I build free tools with them. It feels like we're going backwards: when I was in school, a millennia ago, my classmates didn't have access to a compiler and were wondering how they would scrape the money to buy a compiler like Borland's or Microsoft's. I had a compiler built into my operating system (FreeBSD at the time), so that wasn't a problem for me. For them, it was a significant expense, but at least those expenses (or more shady sourcing of programs) were a one-shot deal. Fast forward 30 years, and software is rented: you pay monthly for Adobe's Photoshop and Microsoft's office suite just like you pay for Netflix, Disney+ or Spotify2. And now you need to add dozens (if not hundreds of dollars) of monthly credits to access LLMs on top of that. So, now we have to pay to get anything done? This is peak enshitification of our job: first they steal our work to train their models, and then they sell it back to us at a profit.

Attacking the engineers AI is coming for our jobs, as engineers, if not everyone, according to the narrative. For a while now, our job market has deteriorated: less jobs, for less pay. Lots of skilled engineers looking for work and finding crap jobs then still looking while working. This is not by accident.3 We engineers have a lot of power, it is not organized, but that's just a couple of unions away (easy!). Tech overlords know this, so they are attacking our profession, directly, by forcing us to train and use models that they can control. Even in environments where programmers are not forced to use LLMs, the mere pressure of other people's LLM-generated work is huge. One can be forced to review LLM outputs, or just peer pressured you into producing more. We're now supposed to accelerate delivery, because models can presumably do things so much better and faster. With supply chain security becoming such a large vector that we now have worms crawling around developers accounts on NPM, increasing the delivery cadence seems like a really bad idea.4 The LLM hype is part of the larger wave of cyberwar against workers, against water, against the Earth, against all the people. This is not a matter of individually "adapting to the reality" or personal choice, but a political, social, hard problem we need to address collectively.

  1. I again prefer the term LLM to "AI" because models do not possess intelligence. I did use it in the title because click baiting is apparently important, but I stopped short of calling this one "Rage Against the Machines" because that would be the title of every blog post I have ever made.
  2. Yes, I know that Visual Studio is kind of free now, but I wouldn't be surprised if they turn that into a rental as well, because why not.
  3. Beyond sabotaging the job market, Sam Altman event wants to sell "intelligence as a utility" something that is just a really bad idea but especially shows how megalomaniac those people are.
  4. This brings back memories of another era, walking us back decades in terms of computer security.

18 August 2026

John Goerzen: AI in Debian: The Vote, Proposals, and Nuance

Let me start with a hypothesis:
For human developers, using coding LLMs magnifies their difference in skill levels.
I am one that rarely thinks things are always black and white. Back in March, I wrote Artifial Intelligence: Shades of Gray. Since then, I ve had more of a chance to experiment with LLMs myself. I also happen to work for an employer that is taking a very pragmatic approach to LLMs: teams and individuals use it as they see fit, but if they are causing considerable expense, they have to justify it. In various settings, I have seen the egregious examples of AI slop we all know about. As I wrote in March, I have seen it both waste more time than it saves, and save a ton of time. I have come to see that, as a tool, it is most valuable when it is running under the supervision of an experienced engineer. It is at its worst when it has no such supervision; the vibe coding and other low-quality slop we see. A coding agent is like a junior developer or research assistant. When properly supervised, they help projects move along more quickly by letting a senior developer focus on the more difficult, less mundane aspects of the project. But one couldn t expect a junior developer to consistently deliver high-quality code and architecture on their own. Let s put a pin in this idea and look at the story in Debian. LLM use in Debian There is a vote happening in Debian around the use of LLMs. In typical Debian fashion, there are 8 options to choose from, many of them similar. Most of these proposals acknowledge there are different types of tasks done in Debian, but the proposals don t differentiate between them well. Let me do so here. These are some of the LLM-relevant tasks people in Debian perform: I m going to focus my remarks here on packaging upstream software for Debian, since this is by far the most time-consuming developer task project-wide. It matters to our users that we get this right, and packaging quality is one of the things that sets Debian apart from other distros. Packaging things for Debian requires knowledge of some specific tools, such as debhelper, that aren t widely used anywhere else. In most cases, it is fairly rote time-consuming work. In other words, by its design, it requires people with senior-level skills to do grunt work. I can t overstate how massive a burden this grunt work is. I maintain some packages for Go and Rust. By Debian policy, all of those packages dependencies must also exist as Debian packages, and be used to build against. When upstream adopts a newer version of some library, it can unleash cascading dependencies that can take hours to sort out. Worse, the Rust team and the Go team use entirely different ways of managing packages (Go uses one Git repo per package, while Rust has a monorepo with specialized scripts to import Cargo packages and generate Debian ones). On top of that, we can t just modify things like usual; we have to use quilt. And on top of that, I m also a backports maintainer, so all the work (and usually even more) has to be done there also. Now let s pull on that pin from the earlier conversation. This is exactly the kind of scenario that a well-supervised coding LLM is most effective in. I could see a seasoned developer saving hours, maybe even days, by turning over the mundane tasks of managing trees of cascading dependencies over to a coding tool and verifying and directing the process. (Yes, I have been using em-dashes for years; LLMs have copied people like me, not the other way around! This post was not written with any AI assistance.) Actually, this is almost a dream scenario for a coding assistant. The result is time-consuming to formulate but easy to review, which is the opposite of the way these things often go. I can assure you with 100% certainty that humans aren t adding a lot of value in this process. It would be wrong to believe that a human is carefully reading every line of code in dozens of updated or new library packages. The problem set is too big, the time too short, and the code too varied and complex. Coding agents seem to be most effective when there are strong test suites that they can test changes against. Debian builds, especially of modern packages, tend to have this property. Many packages have test suites that are run during build. And, if the package builds in an isolated environment (and especially if its downstream dependencies do also), then there is a decent chance that it s fairly correct. Maybe needing some manual tweaking here and there, but generally a successful build is a reasonable indicator. You can argue that it would make more sense for Debian to just include dependencies in source packages, along with some version information to support security rebuilds, and I d tend to agree with you. But we are where we are. This would be one of the more significant leaps forward in developer productivity, but it complicates things like copyright reviews. Where are LLMs run? What is the environmental impact? Most of the proposals seem to make the assumption that LLMs must always run in some large, hosted datacenter. As I noted in my March article, I have had credible results on even an older GPU running on solar power. That said, it is undeniable that LLMs are fueling a datacenter boom, and this in turn is producing a significant new demand for resources. Most notably for the global scale: electricity, which is sometimes generated using carbon-emitting technologies. Bill McKibben, who has been a leading voice in the fight against climate change since the 1980s, has made some interesting points recently: he s noted that solar power is the fastest kind of generation we can build, and a number of large AI companies are investing heavily in solar, even to the point of fully offsetting new datacenter s needs. On the other hand, he s also noted that some companies are buying inefficient and dirty gas turbines. It is decidedly a mixed bag. The heavy investment in solar can have knock-on positive effects for infrastructure. Obviously, not every picture here is rosy. This analysis doesn t touch on the real land and water use situation, either. On the other hand, if an LLM allows me to do in an hour what I would have done in a day, that s a day of not heating or cooling the work area generally not sustaining a human for the purpose of writing code for Debian. HVAC energy consumption dwarfs my GPU, and I d imagine probably also the slice of LLM energy used. Holistically, I would have to conclude the picture is mixed. It is possible to use LLMs in a pretty green way, and also in a pretty dirty way. Assuming Conditions Never Change A flaw in most of these proposals is they assume that the conditions at this present moment will always hold. In fact, that the conditions at the present moment will not continue is something both AI cheerleaders and AI skeptics agree on. For instance: Ed Zitron has done a ton of research into the financing side of AI, and has concluded that the current model is unsustainable and headed for a significant bubble burst. I m not positioned to personally evaluate those claims, but if that happens, what is the result? Perhaps it is a steeply increasing cost of inference for the frontier models, slower pace of training/evolution for them, etc. In a recent episode of Oxide and Friends, Simon Willison discussed the open weight models that are now available. They have been making remarkable strides in efficiency and capabilities, to the point where $50,000 of hardware can now run high-end open weight models with capabilities that are at least in the same ballpark as the American frontier models. This puts running high-end models locally squarely within reach of universities and small- to medium-sized businesses, with power requirements that can be met with standard commercial solar and wind installations. The lack of nuance in the more restrictive proposals is particularly concerning. Proposal A doesn t allow the use or assitance of LLMs . So it bans my solar-powered GPU. It bans using LLMs to find security issues. It bans all sorts of things that don t seem to be ban-worthy, alongside the things that do. And it codifies it in the very hard-to-change social contract. That proposal, and some like it, seem to imply that all LLM output is bad. I grant you that AI slop is a real and legitimate concern, and many Open Source projects have to deal with it. On the other hand, we have all seen first-hand how the security of the Linux kernel has benefited dramatically from AI analysis. It is certain that black hats are using these tools. If we refuse to use modern security tools, our security will be compromised (and what is the environmental and social impact of THAT?) I find the statement Generative AI is characterized by producing output of a nature that would ordinarily be produced and consumed by humans to be particularly interesting. The same was once said of compilers. The Real Concerns You might think from reading this that I am some AI cheerleader. I m not. I share the ethics of the FLOSS movement, and have for decades. I abhor the power and lack of ethics that many big names in the field are running with at the moment. I ve had to put up Anubis on this blog, for instance. I have personally experienced the effects of AI slop, especially at review time. This is a real problem, though I don t think the more draconian policies are likely to help (the looser you must disclose stand a fighting chance, but I m not sure they would help, either.) Done poorly, AI threatens developer burnout by overwhelming them with poor code and verbose but useless explanations. Done well, AI can help prevent developer burnout by automating tedious and low-value tasks. Shouldn t our goal be that humans submit work to Debian, using tools they prefer, and take responsibility for it? Does it matter if someone uses ed, vim, emacs, or vscode? If they use LSP or just run gcc manually? I d say we benefit from the diversity. Wouldn t we be better off to benefit from the diversity here, and judge work as we always have: on its merits, not what tools were used to create it? Fundamentally, a GR is a long and arduous process. It s not easy to reverse later. Amending the Social Contract is even longer and more arduous (I should know; I may have been the first one to try). The LLM landscape is fast-moving. None of us can really predict where it will be in a year. Will the current market leading companies even still exist? Will it be at all credible to refuse to use AI-assisted security tools? What is the most effective way to deal with AI slop? What level of utility will we be able to achieve with models run locally? Some of these proposals would make sense if drafted in some way short of a GR, which would allow more maneuverability as the landscape changes. Brief analysis of the options Considering the proposals: In favor of nuance I find that black-and-white thinking is almost always something to be avoided. I see it too often. I see it in politics, I see it in our software, I see it in discussions around AI. Are there deeply unethical things happening in AI? Absolutely. Are they doing some impressive things? Also yes. We have accepted this nuance in other areas. For instance, almost all the hardware Debian runs on has closed-source hardware, and has components manufactured or assembled in countries with some of the worst human rights records on the planet. I m not saying this is a great state of affairs. It is something we should speak up about and act upon. But the worse state of affairs would be no Debian because the hardware is impure .

16 August 2026

Bits from Debian: Debian turns 33!

It has now been thirty-three years since the Debian project was announced to the world by Ian Murdock, on August 16, 1993. This anniversary is an opportunity to reaffirm the goals, characteristics, and qualities of the Debian project: it s an association of individuals who have made common cause to create a free operating system. Our distribution is characterized by a commitment to software freedom, as enshrined in the Debian Social Contract and the Debian Free Software Guidelines. It focuses on security and stability. This stability is crucial to Debian position in the free software ecosystem. With our users as our priority, Debian makes special efforts regarding accessibility with Debian-Accessibility and diversity with our Outreach Programs. Debian Day is a great opportunity to get together, whether for a local meetup, or simply to grab a coffee with other members of the Debian community. Check out the Debian Day wiki to see if there is a celebration near you. And if there isn't, maybe you can organize it next year! Today is also an opportunity for you to start or resume your contributions to Debian. For example, you can install the how-can-i-help package and see if there is a bug in any of the software that you use that you can help to fix, contribute small tips on how to install Debian on your machines to our wiki pages, or put a Debian live image in an USB memory and give it to some person near you, who still didn't discover Debian. Thanks to everybody who has contributed to develop our beloved operating system in these 33 years, and Happy birthday Debian!

13 August 2026

Jonathan Dowland: DIY skate punch-out

The punch set-up
the punched boot
Since I wrote about my fly30 ice skates, I'd continued to battle pain around the navicular bone in my feet. The action that seems to have finally fixed it was to perform a "punch out": a very localized remoulding of the area of the boot that presses against the sore area. I basically followed the process from this helpful YouTube video. I narrowed down the exact spot by borrowing some lipstick and transferring it from my navicular bone to the boot lining, then making that more permanent with a sharpie. My punch was a spare part from a radiator valve which I packed with US cents (I couldn't fit any UK coins in). For the receiving-end, I tried another part from the radiator valve but I think it wasn't sufficiently larger than the punch to work well, so I swapped that out for a spoon.
take 2 take 2
I didn't have a temperature sensor I could use and I used a heat gun rather than a hairdryer, so I YOLO'd it a little. Some of the wrap on one of my boots is now distorted from where I didn't move the heat gun enough. It only took a minute or two to get the boot hot enough to be flexible. I set a 15 minute timer once the clamp was in place. I've only skated one session since I did this but the pain seems to have gone! It's remarkably freeing to be skating without constantly trying to manage pain. Now I can focus on technique.

11 August 2026

Colin Watson: Free software activity in July 2026

About 95% of my Debian contributions this month were sponsored by Freexian. You can also support my work directly via Liberapay or GitHub Sponsors. OpenSSH Now that Ubuntu 26.04 LTS has been released, I ve been getting back to the GSS-API key exchange package split in our OpenSSH packaging. Once I started testing my draft openssh-gssapi source package, I realized that I needed to make some changes in the main openssh source package first in order to support it. The dependency from openssh-server to openssh-client was awkward, as was the (related) fact that openssh-client contained shared documentation for other OpenSSH binary packages. After some thought, I created a new openssh-common binary package, moved shared documentation and the ssh-keygen program to that, and dropped dependencies on openssh-client which were no longer necessary (fixing #699473 and #1070098 in the process). This caused a couple of regressions (#1141420 and #1141550) that I had to fix, and more subtly it also caused a number of autopkgtest regressions in other packages because openssh-client is no longer in base images as a result of a dependency from openssh-server. I believe I have fixes for all of these either pending review or merged (one of which I did in August rather than July): I upgraded from 10.3p1 to 10.4p1, and in the process contributed a GSS-API option handling fix upstream. I made openssh-ssh1 s package description more accurately describe the package, thanks to suggestions from Matthias Lang. Installer team With support from a Freexian customer, I reviewed, tested, edited, and merged a patch to add VLAN support. I described the details of what I did in a comment. This has been vaguely on my to-do list since, er, about 2014, so it was very satisfying to get it sorted out. Python packaging New upstream versions: Other build/test failures: I fixed some other bugs: I adopted transaction for the Python team. I attended the Python BoF at DebConf remotely, although a badly-timed fibre outage in the village I live in really didn t help. Code reviews Other bits and pieces Dan Poltawski pointed out in a Fediverse post that the project history didn t list Sruthi as the current DPL. I fixed that, although it doesn t look as though the fix is in the published version yet. I upgraded yubihsm-shell to 2.8.0.

Freexian Collaborators: Debian Contributions: DebConf 26 organization, d-i VLAN support and more! (by Anupa Ann Joseph)

Debian Contributions: 2026-07 Contributing to Debian is part of Freexian s mission. This article covers the latest achievements of Freexian and their collaborators. All of this is made possible by organizations subscribing to our Long Term Support contracts and consulting services.

DebConf 26 organization, by Lucas Kanashiro, Santiago Ruano Rinc n, Stefano Rivera and Antonio Terceiro The 27th Annual Debian Conference was held in Santa Fe, Argentina, and several Freexian fellows were quite busy by being involved in the organization team.
  • Santiago continued helping with duties related to the local team, e.g. preparing or proof-reading some announcements, reviewing the proposed food and the menus for the different diet required.
  • During the conference, Kanashiro and Santiago also carried over tasks related to the content of the conference, including updating the schedule as it became necessary during the event.
  • Stefano worked within the core video team, setting up equipment in talk rooms and coordinating the live video streaming. Stefano also supported the front desk and local organisers as a website developer and conference book-keeper.
  • Antonio kept working on website maintenance, specially in support of the content team. During DebConf he also ran a hands-on workshop to help interested contributors get started with developing the DebConf websites.

d-i VLAN support, by Colin Watson In environments that use IEEE 802.1Q VLANs, some hosts (such as routers attached to trunk ports) may need to apply VLAN tags themselves rather than relying on switches to do so. There has been a long-running request to add support for these to the Debian installer with a proposed patch set put together by several people over the years, and a Freexian customer asked us to help get this over the line. Colin reviewed the latest version of the patch set, applied a number of corrections, added Netplan support, spent some time testing a variety of possible paths through the installer, and landed this. There s also now documentation for this in the next version of the installation guide.

Miscellaneous contributions
  • Carles wrote documentation for installing Mailman3 and migrating from Mailman2. Added it into Mailman3 upstream documentation.
  • Carles, using po-debconf-manager: reviewed 2 packages, submitted 2 packages
  • Carles organized Catalan translation update. Created a Debian Wiki page to have an overview of the work / coordination during next months. Reviewed and submitted some pages.
  • Carles improved the documentation for building the debian.org Web in MR 1154 and MR 1557. Fixed debian-reference documentation. Added sections on Mutt Wiki page (handling of mailto, viewing HTML parts web browser), update and improve bash-completion Wiki page. Added a troubleshooting section in Signal Wiki.
  • Thorsten did another upload of hplip to fix RC bugs. He also spent some time taking care of older bugs. Most of the time such bugs had been fixed in a previous upload but haven t been closed in the BTS. He also uploaded a new upstream version of foomatic-db. Last but not least, he gave some user support with the package epson-inkjet-printer-escpr. There seems to be a new software available for Epson printers. Unfortunately the license is not compatible with DFSG and so this software will never make it into Debian.
  • During DebCamp 26, the Golang team had a dedicated Sprint to transition the Golang toolchain (namely on dh-golang) to make builds aware of the module defined upstream with the aim of solving important issues. To help in these efforts, Santiago made changes in the Salsa CI pipeline and documented on how to use it to check if a package requires adjustments after the toolchain update.
  • Santiago continued co-mentoring Aryan Karamtoth on the Linux livepatching project, specifically providing feedback about the implementation of dlp-tools.
  • Stefano reviewed and merged a migration of Debian reimbursements from wkhtmltopdf to weasyprint, unblocking an upgrade to Debian trixie.
  • Stefano s cPython upstream merge request adding multiarch tags to stable ABI extensions was finally merged.
  • Stefano iterated on his upstream cPython merge request to add CI coverage for Debian s multi-arch expectations.
  • Stefano uploaded Python 3.15.0 beta 4 to Debian experimental.
  • Stefano uploaded Python 3.13 to trixie, fixing a regression in a previous trixie point update he made.
  • Helmut continued to report undeclared file conflicts.
  • Helmut sent patches for three cross build failures.
  • Helmut proposed a MR to port piuparts to pathlib.
  • Antonio has done quite some work on Debian CI, including rebuilding the Debian CI armhf/armel worker VMs, and releasing debci 4.2, implementing a backup scheme, and several improvements to the codebase such as improving the incus-lxc backend in preparation for switching to the upcoming switch to using it by default as announced in the latest bits from the ci.debian.net operators.
  • Emilio helped with transitions, particularly with Python 3.14 as default and Perl 5.42. During the Perl transition, an issue was identified with how britney schedules autopkgtests for binNMUs, and that testing was reverted for the time being.
  • Colin restructured openssh-* binary packages to better support the upcoming GSS-API package split. This caused several autopkgtest regressions in other packages because openssh-server no longer depends on openssh-client, all of which have fixes either pending review or merged now.
  • Lucas started a discussion around the creation of a Debian packaging video course for newcomers in the context of the Outreach team.
  • Lucas reviewed some contributions to ruby3.4 and provided feedback.
  • Anupa worked with Jean-Pierre Giraud on the point release announcements for Debian 13.6 and Debian 12.15.
  • Anupa joined Jean-Pierre Giraud to prepare the Micronews for DebConf 26 press coverage.

6 August 2026

Bits from Debian: DebConf26 closes in Santa Fe and DebConf27 announced

DebConf26 group photo - click to enlarge On Saturday 25 July 2026, the annual Debian Developers and Contributors Conference came to a close. Over 270 attendees representing 35 countries from around the world came together for a combined 90 events (including some which took place during the DebCamp) including more than 27 Talks, 21 Short Talks, 29 Birds of a Feather sessions ("BoF" informal meeting between developers and users), 8 workshops, and activities in support of furthering our distribution and free software, learning from our mentors and peers, building our community, and having a bit of fun. The conference was preceded by the annual DebCamp hacking session held 13 through 19 July where Debian Developers and Contributors convened to focus on their individual Debian-related projects or work in team sprints geared toward in-person collaboration in developing Debian. As has been the case for several years, a special effort has been made to welcome newcomers and help them become familiar with Debian and DebConf by organizing a sprint "New Contributors Onboarding" every day of Debcamp, followed more informally by mentorship during DebConf. Half a dozen new contributors joined the sessions and learned about Debian, free software, packaging and much more. This year, a week-long DebCamp session was dedicated to auditing, patching, and modernizing the Go ecosystem in Debian and enable the transition triggered by the recent upload of dh-golang enabling GO111MODULE=on by default in Experimental. In order to make the conference more accessible for local participants, a local language track was included in the schedule for talks in Spanish, as was done at DebConf19 in Brazil. The actual Debian Developers Conference started on Monday 20 July 2026. In addition to the traditional "Bits from the DPL" talk, the continuous key-signing party, lightning talks, and the announcement of next year's DebConf27, there were several update sessions shared by internal projects and teams. Many of the hosted discussion sessions were presented by our technical core teams with the usual and useful "Meet the Technical Committee", three talks about Linux Kernel, early boot and improving Debian s kernel and installer support for Chromebooks, and about twenty BoFs and talks about Debian packaging policy, Debian infrastructure, security and privacy. This year, and echoing ongoing discussions within the Free Software community, Artificial Intelligence and Age Verification have been the subject of several talks. The Python, Perl, Ruby, Go, and Rust programming language teams also shared updates on their work and efforts. More than 17 BoFs and talks about community, diversity, and local outreach highlighted the work of various teams involved in not just the technical but also the social aspect of our community The schedule was updated each day with planned and ad hoc activities introduced by attendees over the course of the conference. Several traditional activities took place: a poetry performance, the traditional Cheese and Wine party, the Group Photos, and the Day Trip. For those who were not able to attend, most of the talks and sessions were broadcasted live and recorded. One can find the seventy hours of recorded videos available via the conference schedule, or alternatively through this link. Almost all of the sessions facilitated remote participation via IRC and Matrix messaging apps or online collaborative text documents which allowed remote attendees to "be in the room" and ask questions or share comments with the speaker or assembled audience. DebConf26 saw over 341 T-shirts, a day trip, and up to 130 meals planned per day. All of these events, activities, conversations, and streams coupled with our love, interest, and participation in Debian and F/OSS certainly made this conference an overall success both here in Santa Fe, Argentina and online around the world. The DebConf26 website will remain active for archival purposes and will continue to offer links to the presentations and videos of talks and events. Next year, DebConf27 will be held in Asahikawa, Hokkaido, Japan, from Sunday September 5th to Saturday September 11th, 2027. As tradition follows before the next DebConf the local organizers in Japan will start the conference activities with DebCamp with a particular focus on individual and team work towards improving the distribution. DebConf is committed to a safe and welcome environment for all participants. See the web page about the Code of Conduct on the DebConf26 website for more details on this. Debian thanks the commitment of numerous sponsors to support DebConf26, particularly our Platinum Sponsors: Infomaniak, and Proxmox, and our Gold Sponsors : Freexian, and Viridien. We also wish to thank our Video and Infrastructure teams, the DebConf26 and DebConf committees, our host nation of Argentina, and each and every person who helped contribute to this event and to Debian overall. Thank you all for your work in helping Debian continue to be "The Universal Operating System". See you next year! About Debian The Debian Project was founded in 1993 by Ian Murdock to be a truly free community project. Since then the project has grown to be one of the largest and most influential Open Source projects. Thousands of volunteers from all over the world work together to create and maintain Debian software. Available in 70 languages, and supporting a huge range of computer types, Debian calls itself the universal operating system. About DebConf DebConf is the Debian Project's developer conference. In addition to a full schedule of technical, social and policy talks, DebConf provides an opportunity for developers, contributors and other interested people to meet in person and work together more closely. It has taken place annually since 2000 in locations as varied as Scotland, Bosnia and Herzegovina, India, Korea, France. More information about DebConf is available from https://debconf.org/. About Infomaniak Infomaniak is an independent, employee-owned Swiss technology company that designs, develops, and operates its own cloud infrastructure and digital services entirely in Switzerland. With over 300 employees more than 70% engineers and developers the company reinvests all profits into R&D. Its public cloud is built on OpenStack, with managed Kubernetes, Database as a Service, object storage, and sovereign AI services accessible via OpenAI-compatible APIs, all running on its own Swiss infrastructure. Infomaniak also develops a sovereign collaborative suite messaging, email, storage, online office tools, videoconferencing, and a built-in AI assistant developed in-house and as a privacy-respecting solution to proprietary platforms. Open source is central to how Infomaniak operates. Its latest data center (D4) runs on 100% renewable energy and uses no traditional cooling: all the heat generated by its servers is captured and fed into Geneva's district heating network, supplying up to 6,000 homes in winter and hot water year-round. The entire project has been documented and open-sourced at d4project.org. About Proxmox Proxmox develops powerful, yet easy-to-use open-source server solutions. The comprehensive open-source ecosystem is designed to manage divers IT landscapes, from single servers to large-scale distributed data centers. Our unified platform integrates server virtualization, easy backup, and rock-solid email security ensuring seamless interoperability across the entire portfolio. With the Proxmox Datacenter Manager, the ecosystem also offers a "single pane of glass" for centralized management across different locations. Since 2005, all Proxmox solutions have been built on the rock-solid Debian platform. We are proud to return to DebConf26 as a sponsor because the Debian community provides the foundation that makes our work possible. We believe in keeping IT simple, open, and under your control. Contact Information For further information, please visit the DebConf26 web page at https://debconf26.debconf.org/ or send mail to press@debian.org.

4 August 2026

Petter Reinholdtsen: FreeCAD MCP with llama.cpp, toy or tool?

After seeing a video a few months ago demonstrating how a proprietary CAM solution uses machine learning and large language models to automatically generate CNC instructions, and successfully testing it on a real CNC, I began wondering if the same could be achieved with free software. I still do not know the answer, but I may be getting closer to finding out. Two weeks ago, I came across the video "I Connected Claude AI to FreeCAD (And It Models Parts Like an Engineer)" by Make Form, which introduced me to the FreeCAD MCP project. Even though the video creator apparently believes it is acceptable to download and run random binaries from the Internet on a local machine (his setup uses UCX), I do not. I would probably have left the project alone entirely if I had not noticed that all of its dependencies are already available in Debian. This significantly boosted my motivation, so I set out to test it using packages built from source on Debian rather than relying on untrusted binaries. The first hurdle was that the MCP SDK for Python was not present on my Debian Forky test machine. I initially believed it was missing from Debian altogether, but it has been available in Debian Unstable for about a month and is only absent from Forky because some automated tests fail on architectures like riscv64 and s390. Fortunately, backporting it was straightforward using apt-get source -b python3-mcp . The next hurdle involved an outdated version of the Validators Python library. Since I am a member of Debian's Python team, which maintains this package, updating it to a sufficient version for FreeCAD MCP was relatively easy. I could not upgrade to the latest upstream release due to a new dependency on an Ethereum-related library, so I settled on a 2024 version. With those dependencies in place, I proceeded to create a Debian package for FreeCAD MCP. I had previously submitted a request for packaging of FreeCAD MCP to gauge interest while deciding whether to prioritize maintaining it myself. Because salsa.debian.org blocks access from Tor users like myself, I published my draft packaging scripts in a Git repository on Codeberg as the Debian FreeCAD MCP project and got it working with the FreeCAD 1.1 version in Forky. I initially struggled with the button controls for the MCP feature, which led me to submit a pull request titled "Fixed startup sync of checkable toolbar buttons" proposing a fix. Once this confusion was resolved and the MCP setup was enabled via the GUI, I was able to run FreeCAD completely headless using xvfb-run on a machine without an X server to generate models. I am using a private LLM service running the Debian package of llama.cpp with the Qwen 3.6 model downloaded from Hugging Face, configured with a maximum context window of 105k tokens. I also tested the Bonsai model on my test laptop; initially, its context window was too small (8k and 16k could not accommodate the FreeCAD MCP instructions), but even after increasing it to 32k, it proved useless for generating FreeCAD models so far. I've used Claw Code, Aider and Open Code with my server so far, and for this test I ended up with OpenCode because it was easy to set up to use an MCP. Because none of my LLM services are set up to be multimodal (capable of processing both text and images in this case), I configured the MCP to return only textual feedback from FreeCAD. I am unsure if this is a major limitation, though I suspect it might be. My testing experience remains limited, with no clear successes yet. Part of the issue likely stems from my ability to provide effective instructions for modeling 3D objects (I am relatively new to FreeCAD, English is not my first language, and I lack a precise vocabulary for describing construction features to an LLM). Nevertheless, the LLM has demonstrated the capacity to create 3D models in FreeCAD. In one of my first tests, I asked it to generate a cube and then produce CAM/G-code instructions for a CNC machine. It did output G-code (which remains untested), but I was surprised to find that it bypassed FreeCAD's built-in CAM module entirely and instead generated an external Python script to produce the code. This was not quite what I intended, though my instructions were probably unclear. The Qwen model with OpenCode seems to strongly prefer programming directly; it frequently executes Python snippets inside FreeCAD to achieve its goals rather than using the standard sketch-and-extrude workflow I am accustomed to. In another test, I asked the LLM to create a parameterized pipe assembly to see which of FreeCAD's parametric tools it would choose, but found no evidence of traditional parametric features in the output. When prompted, the LLM explained that the parameters were embedded directly in the Python script used to generate the model, rather than in native FreeCAD features. With more explicit instructions, it eventually created a FreeCAD spreadsheet to manage the parameters. The resulting model looked much closer to my expectations and could have been useful with further refinement. My so far last experiment was less successful: I asked it to design a pipe clamp, but the LLM repeatedly failed to position the clamping screws in a way that would actually secure the brackets around the pipe. It is unclear whether this limitation lies with the model, my prompt, or other factors. Based on my testing so far, I am uncertain whether FreeCAD MCP is merely a fun toy or a genuinely useful tool. I will only commit time to maintaining it in Debian if it proves to be practically valuable. I would welcome feedback from anyone who has experience with the project, preferably via the original request-for-packaging mailing list thread. Alternatively, I am available in the FreeCAD and Debian AI IRC channels for further discussion. As usual, if you use Bitcoin and wish to support my activities, please send donations to 15oWEoG9dUPovwmUL9KWAnYRtNJEkP1u1b.

2 August 2026

Russ Allbery: Term::ANSIColor v6.0.0 TRIAL release

Yesterday, I uploaded Term::ANSIColor v6.0.0-TRIAL to CPAN for early testing. This release will raise the minimum required Perl version to 5.12, dropping support for Perl 5.8 and 5.10. When I did the same with podlators a couple of years ago, it upset a few people and one of them asked me to make this sort of test release in the future. Hopefully this will help. I have not run the normal release machinery and haven't archived this release in the normal places, since I intend it to be transient. It's only on CPAN, where people can retrieve it for testing. Once v6.0.0 is released, few traces of this TRIAL release will be left. This doesn't appear to be how other people use the TRIAL mechanism, but it felt more comfortable to me. If I have to make substantial changes, I'll consider changing my approach. I plan on turning this into the v6.0.0 release in about a month or two, hopefully with only documentation changes. Term::ANSIColor is a "very upstream" core module with a lot of dependencies, and CPAN (unlike some of the archives that followed it, such as PyPI) doesn't support conditionally retrieving packages based on the current Perl version. This release may therefore be disruptive for people who are still trying to support Perl 5.8 and 5.10, since CPAN installation tools may attempt to install an incompatible Term::ANSIColor version. I'm sad that this will be the result, since I know some people still care about those versions. I'm pressing forward with updating my Perl modules anyway, though. I realized that honoring other people's desire for stability to such a degree that I was unable to use Perl features added more than 15 years ago was destroying my motivation to work on these Perl modules at all. So I've decided on a very slow and gradual approach where I'm going to keep pushing the minimum supported version forward but try to give people a lot of warning. Personally, I think it's time to let ancient versions of Perl go and follow the Lyon Amendment about supported Perl versions. When we're talking installing new modules for software released more than 15 years ago, we're talking about special limited environments and retrocomputing more than what I would consider routine software maintenance. Those tasks should expect to need different tools and a different workflow so that they can pin historical versions. Since this isn't something I'm personally interested in, my willingness to expend time and energy to assist is limited. As you can probably tell, I still feel nervous about pressing forward in this way, but I think this is the approach that lets me continue to enjoy maintaining these Perl modules. It's been 29 years for Term::ANSIColor, but I still enjoy fixing bugs in it and putting out a new release from time to time, particularly if I can clean up the code a bit each time I touch it.

31 July 2026

Otto Kek l inen: Estonia, the country of the fit and the wit

Featured image of post Estonia, the country of the fit and the witWhile many Western democracies seem to be in a state of decay and are no longer the safe, civilized and prosperous countries they once were, there are still some European countries that are governed well. One of those that stand out is Estonia. Estonia is probably most well known for multiple software companies that originated from there, such as Wise, Bolt, Pipedrive and Skype. The government itself is also famous for being early in issuing government IDs with an embedded smart chip for online authentication already in the 1990s. Via the national portal at eesti.ee all residents can access extensive eServices ranging from viewing their health benefits to filing taxes. Estonia has also been running an e-Residency program since 2014, where they issue digital ID cards to foreigners, making it easy for them to remotely log into the government portals and for example, establish businesses, file annual reports and so forth. Note that the e-Residency is not a path to physical residency. Estonia does, however, have a separate Digital Nomad visa program that makes it easy for non-EU citizens to also physically establish themselves in Estonia, assuming, of course, you meet the criteria, which includes, among others, a minimum monthly income of 3960 from outside Estonia. EU citizens naturally have free mobility inside the EU and can simply get an apartment and register as a resident in Estonia if they so choose. And there are plenty of reasons to do so.

Estonians value health, education and entrepreneurship I moved to Estonia about one and a half years ago. In my observations Estonia strikes me as a country that values health, education (in particular programming and natural sciences) and entrepreneurship highly. I don t know how Estonians achieve it, but they look pretty fit and rarely obese. Estonia has rye bread and sauna in their culture just like Finland, and in addition the flat terrain and well-planned bike routes and extensive network of parks (and pull-up bars everywhere) seem to create an environment where it is easy to live in a healthier way. The consumption of processed foods and candy also seems relatively low among Estonians. The gym chain MyFitness also seems to be present everywhere. Even the Tallinn airport has a calisthenics workout station right at the departure gates, which anyone is free to use while waiting for their flight to take off. One of the top longevity influencers in Europe, Siim Land, is Estonian. Estonia has lots of good bike paths, parks and outdoor gyms There is even a calisthenics station with pull-up bar and more at the departure gates at Tallinn airport Estonians also seem to value the school system highly. The government has been actively raising teacher pay and has a stated goal of reaching 120% of the national average by 2027. The students are also expected to value the education and respect their teachers. According to the TALIS 2024 survey (OECD s international teacher survey), Estonian teachers spend significantly more time on actual teaching and learning and waste less time on interruptions or keeping classroom order compared to the OECD average. This is among the highest rates internationally, meaning they spend relatively little time on maintaining order or dealing with disruptions. While the international education benchmark PISA scores have been dropping globally, Estonia has consistently been climbing the ranks in past decades. In the latest PISA study (from 2022), Estonia ranked number one in Europe for reading, mathematics and science. In the overall results, Estonia ranked seventh globally, only behind countries such as Japan, Korea and Singapore. Valuing entrepreneurship is evident in how the taxation system is set up in Estonia. Famously, in Estonia, companies can defer taxes on annual earnings and reinvest all of their profit in growing the company. Taxes are due only later, when paid out from the company, for example as dividends. For individuals, receiving dividends from any Estonian or foreign company is tax-free as long as the company paying dividends already paid corporate tax on the same income. The tax system is also very simple. For all individuals, all types of income, including salary and capital gains, are always taxed at a flat rate of 22%. This removes the incentive for anyone to try to convert income into different types, setting up holding company structures and other optimizations as there is no gain. All entrepreneurs can simply focus on growing their business and forget extra bureaucracy. There is also no marginal tax rate cliff to stop working at everyone is encouraged to always try to produce as much value as they can. A simple tax system is also reflected in the fact that anyone can easily read all tax rules that apply to individuals in plain English on the Estonian tax authority website, and one does not need to hire any accountants simply to file taxes. Estonia also has a very straightforward investment account system: any person can freely open a self-directed investment account at any brokerage at no extra cost and report it as such to the tax authority, and then use it to save for an apartment, retirement, or other purposes, and defer all income taxes until withdrawal. There are no caps or time limits, and all residents are encouraged to save and invest as much as they can and thus take responsibility for their own wealth accumulation. It seems that culturally Estonians respect people who are active and progress in their careers and businesses more than in other countries. Unlike in Finland, successful people are admired and living on government welfare is not romanticized. At the same time, the government benefits are less generous so people can t live comfortably on them and, for example, many of the asylum seekers Estonia accepted have since left on their own initiative to other European countries in search of better benefits.

Low crime, high trust Another thing that strikes me when walking the streets of Tallinn is that there are no drug addicts, beggars, thugs or the like. The difference compared to, for example, Vancouver (where I lived previously) is stark. In public buildings, people leave their coats and bags hanging in the lobby while visiting. Private houses and apartment block yards are not fenced. In my building, I noticed people even leave their bikes unlocked in the bike shed. I have also seen the staff of a coffee stall in a shopping mall going for a break and leaving everything unattended, not worrying that anyone would take anything while the staff is away. Nobody is stealing anything from the unattended coffee shop while staff is having a break at  lemiste shopping mall This is not just my personal experience. According to the Numbeo crime index, Estonia has one of the lowest crime rates in the world. Also, comparing drug and property crime stats, for example, Finland has twice as much crime per capita, and places like Vancouver in Canada almost five times more. I don t have any clear explanation for why crime is so much lower in Estonia, but some suggest that higher social cohesion and lower levels of welfare contribute to people standing to lose more if they behave antisocially. Compared to Finland, Estonia also more readily jails repeat offenders, and those who are put on trial will experience a swifter court process thanks to simplified legal processes and more efficient governance.

Moving to Estonia: quick checklist Moving to Estonia is very easy for any EU citizen, in particular if your work is not location-dependent (e.g., remote work or an online business) and you are simply looking for the cleanest and safest environment to live in. First, check into a hotel in Tallinn, check out various neighborhoods to figure out what area you like (my favorites are Kalaranna, Kalamaja, Noblessner and Volta) and start browsing available apartments in English at kv.ee. Most professionals speak fluent English, so there should not be any difficulty in reaching out to people by email or phone. Tallinn is famous for the old town The economic boom of recent decades created a lot of new construction, with Kalaranna being among the newest areas The next step is to buy a local prepaid SIM card at e.g., an R-Kiosk or a convenience store as signing up for other matters later on will require an Estonian phone number. Once you have an apartment and e.g., signed a rental agreement, you can register in the population registry online. After that, you have proof you are a local resident with an address and telephone number in Estonia. With local resident status, you can go to the police station to get a local ID card. Don t bother scheduling an appointment, just go to the Tammesaare police station in Tallinn, take a queue number and wait. Once it is your turn, they will guide you on how to use the photo booth, fingerprint registration device, and file your application. A few days later you will receive an email confirming whether your application was accepted, and after a few more days, you will get another email notifying you that your ID card has been printed and is available for pick-up at the same location. This will also be your first practical experience of how fast and efficient the government in Estonia is. Once you have the local ID card, you can use the smart card feature to log into all the government eServices and sort out the rest of the relocation process, such as registering tax residency and getting a family doctor. The main eServices portal in Estonia: eesti.ee

How did Estonia evolve to be like this? After Estonia regained its independence after the fall of the Soviet Union in 1991, the first elected government in 1992 was led by a very progressive 31-year-old Prime Minister Mart Laar, who managed to set up some very good policies and laid the foundation of a society that has evolved well in the decades since. Estonia was very lucky to have people in power in the 1990s who didn t simply copy what other Western countries were doing, but who tried to think about things from first principles and create Estonia s own model for efficient and fair governance. As a post-Soviet country, the population had also been vaccinated against overly socialist and unrealistic ideals, and everyone had a healthy distrust of the government s ability to solve problems and emphasis was placed on people s liberty to work for themselves as they best see fit. The improvement in living standards over the past 35+ years has also been witnessed by the population, and voting behavior supports keeping the country on the same trajectory. General living standards still continue to improve as the nominal wage growth sits at around 6%, clearly above the annual inflation rate of about 3%. In 2026, the Estonian economy is expected to grow about 2.4%, which is faster than the EU average. The growth in Estonia is not the result of any accounting tricks - Estonia is part of the euro and can t print its own currency, nor has it been funding the public sector with excessive debt. With a 24% debt-to-GDP ratio, Estonia consistently ranks as one of the most responsibly managed countries among advanced Western economies. As wages in Estonia soon catch up with the EU average, and higher defence spending has forced the government to raise taxes in recent years, the economic growth that Estonia has enjoyed for 35+ years since it exited the Soviet Union might slow down a bit in future years. The policies that fueled this growth in living standards, however, are likely to stay.

The tiger leap There is one specific government policy in Estonia s history that I think should be highlighted in particular. Estonia was very progressive by announcing the Tiigrih pe (Tiger Leap) program in 1996 with the goal of equipping all schools with computers and teaching all students the basics of programming. This surely had a large influence on why Estonia has so many successful software companies, why the government eServices are so mature that even neighboring countries like Finland are striving to copy the Estonian government s IT architecture called X-road. The Tiigrih pe project was originally suggested in the mid-1990s by Toomas Hendrik Ilves, then ambassador of Estonia to the United States, Canada and Mexico, and later President of Estonia in 2006 2016. While he was a psychologist by education, he was also a self-taught amateur programmer and used his political influence to promote sensible adoption of information technology in both Estonia and the EU. The history of Estonia has several prominent figures who were not lawyers by profession but engineers, scientists and historians who were very practical in their political decisions, which I think is now reflected in how government processes were formed. The video below shows how the Estonian government advertises itself and what values they choose to highlight:

Should other countries adopt policies from Estonia? Of course, not everything is perfect in Estonia either. The fertility rate of 1.16 in Estonia is very low. This trend is present globally, but in Estonia it is way below the EU average. Also, the service culture is something that needs to improve in Estonia. While services are in general fast and efficient, the attitude of people working in cafes and stores does not reflect a willingness to fill in gaps if the standard process falls short, nor are visitors actively made to feel welcome as individual humans, but are treated as mere process inputs. However, many of the things listed earlier I think should be studied by policymakers elsewhere. Societies are complex systems and there is of course no guarantee that copying a single policy to another country with different ethnicities, history and ingrained culture would lead to the same policy outcomes. But considering that Estonia is a small country without favorable geography and no natural resources, and that it started out from a place of total chaos, low economic activity and high crime in 1992 to rise to what it is now in 2026, the success it has seen is surely largely a result of good policies, governance and culture that other countries can and should mimic.

30 July 2026

Clint Adams: not ninpo

The UX of jj's builtin merge editor finally became too much for me. So, I looked at the list of merge tool options, saw vimdiff, and thought, Oh, cool, I know how to use vimdiff. So, I launched jj config edit --user, added a ui section, and set merge-editor to vimdiff. With the new config, I ran jj resolve again. It was at that point that I realized that I do not, in fact, know how to use vimdiff: I only know how to use vimdiff with two buffers. What appeared in my terminal was a 4-pane monstrosity. Why are there four panes? I'm trying to resolve conflicts between only two changes on only one file. For a moment, I nearly go down a rabbit hole, because this says that by default, vimdiff is barely useable [sic]. Should I be installing some addon or a Python script? Apparently there are tradeoffs. I just want to resolve these conflicts without doing line-by-line approvals for how ever many hours that would take. Accordingly, I ran away in terror, installed meld, set merge-editor to meld, and went clicky-clicky in the GUI. I'm not happy using a GUI, but at least it didn't have a mysterious extra buffer to confuse and taunt me.
Posted on 2026-07-30

27 July 2026

Dirk Eddelbuettel: #057: Conditionally Quieten Compilers

Welcome to post 57 in the R4 series. R packages with compiled codes can use the file src/Makevars to set compilation flags. We often rely on this to set libraries, include directories or compilation options. When using external libraries, be it header-only or via headers and linking, we are often experiencing compilation noise when these libraries tickle warnings under generally-recommended flags such as -Wall -pedantic. Two packages I maintain are clearly repeat offenders here: Eigen, and BH. Both cam generate pages and pages of compiler output. This is generally not great as it may hide genuine warnings from our own code. What makes matters worse is that some of the available and specific options for the compilers are treated by R CMD check as non-portable leading to a nag on package checking. Examples are -Wno-parentheses, -Wno-maybe-uninitialize or -Wno-nunnull. I have long resorted to adding these to my per-user ~/.R/Makevars. When added there, compilation is quieter, but R CMD check still nags here where the option is set but not at CRAN or r-universe. A situation that is not ideal but what somewhat stable . More recently, I realized there was an available check we can use to conditionally add extra compilation flags but leave them off by default. That makes local development quiet allowing us to focus on the quality of our additions here without noise from third-party libraries we may use. At the same time we do not need to do anything else to let CRAN do its work. The check we now use is whether there is a .git/ directory present. If so, we are indeed building from local sources and can add extra flags. If not, we are likely building from a tar.gz source archive which is the case for CRAN and hence do not set these. An example use is this recent additional to package qlcal where this bit of R code is invoked from a minimal shell script configure and replaces the stub @XTRAFLAGS@ in src/Makevars.in (or src/Makevars.win.in)
if (dir.exists(".git"))  
    ## development from a .git directory can use these flags
    xtraflags <- "-Wno-nonnull -Wno-deprecated-declarations"
  else  
    ## else build from tarball so stick with existing flags
    xtraflags <- ""
 
win <- if (Sys.info()[["sysname"]] == "Windows") ".win" else ""
infile <- file.path("src", paste0("Makevars", win, ".in"))
outfile <- file.path("src", paste0("Makevars", win))
lines <- readLines(infile)
lines <- gsub("@XTRAFLAGS@", xtraflags, lines)
writeLines(lines, outfile)
With this change, local compilation is quiet, yet CRAN has nothing to nag about (as seen at the qlcal results page). Similarly, one can also check from an actual configure file written in autoconf. Here is a similar example from RcppEigen (showing some relevants parts of the whole file)
# PKG_CXXFLAGS initialized earlier ...

## Check if building locally
AC_MSG_CHECKING([whether .git/ exists])
if test -d "$srcdir/.git"; then
    AC_MSG_RESULT([yes, adding extra flags])
    AC_SUBST([PKG_CXXFLAGS],["$ PKG_CXXFLAGS  -Wno-ignored-attributes -Wno-maybe-uninitialized"])
else
    AC_MSG_RESULT([no, consider adding '-Wno-ignored-attributes -Wno-maybe-uninitialized' to ~/.R/Makevars])
fi

AC_SUBST([PKG_CXXFLAGS], ["$ PKG_CXXFLAGS "])
AC_CONFIG_FILES([src/Makevars])
AC_OUTPUT
Once again, with this change compilation is quiet locally, yet unaffected at CRAN. Just what we want. Give it a try in your packages.

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 now sponsor me at GitHub.

Valhalla's Things: Late Victorian Vampire Shirt

Posted on July 27, 2026
Tags: madeof:atoms, craft:sewing, FreeSoftWear
A woman wearing an old-style white shirt with lots of fullness, wide and long sleeves and ruffles at the collar that spread out framing the neck, down the center front to underbust height, covering the slit and at the cuffs, reaching to mid-hand. The shirt is gathered at the waist with a belt, and worn over the bottom garment to show that it reaches to mid tight. Drama levels in the pose are pretty low. The recurring joke is that because of some health issues, in summer I dress like a Victorian Vampire. But how would an actual Late Victorian Vampire dress? Picture her, she would look like some kind of eccentric gentlewoman, as vampires usually do, probably with a style that is a bit conservative, rather than following the latest fashions. Same woman, same shirt, posing as a vampire ready to attack a victim. Drama levels increasing. Now, she wouldn t probably wear men s shirts. But what if she was a lesbian1 vampire? Wouldn t she need a fancy, frilly shirt to go with her tailored cycling suit when she s out seducing the more active ladies in the neighbourhood? Or maybe not. It s not making a lot of sense, is it? But I do have a lot of shirt fabric in my stash2, and I could use a few more shirts that were practical and comfortable, but also somewhat over the top. For the practical and comfortable I went to my trusted 1880s shirt, while for the over the top part I looked at inspiration from the earlier 18th century frilly shirts, and their later imitations. I decided to use some nice cotton batiste I had bought quite a few years ago to make one of my first historically inspired shirtwaists: I may have a tendency to buy a bit more fabric than actually needed by the pattern, but that s what everybody does, right? For the ruffles I decided to use a lighter weight cotton voile, also from the stash. the top edge of a ruffle being whipstitched over some gathered fabric; the rest of the unfinished shirt is visible in the background. At the front, I wanted the ruffle to be inserted in the yoke, but I was also whipstitching the gathers to it to make them neater, so I started bu attaching the yoke lining to the gathered front, then I whipstitched the ruffle to the front, catching each gather, and finally I whipstitched the other yoke on the ruffle and the rest of the gathered front. The front of a shirt: the body was gathered into a yoke, but it has been unpicked and pulled out to extend a bit past the end of it, into where the collar will be sewn. And then after sewing the collar, I realized that this way the slit would have remained open in the front (or the collar too narrow), so I had to unpick the front part of the yoke, and sew it again, this time leaving an excess of fabric as wide as half the placket width from the pattern, to be sewn directly in the collar band. From then, things progressed smoothly, with some interruptions, until I got to the first sleeve, which I failed to insert twice, as one does. The same shirt worn without the ruffle at the collar, with just what looks like a mandarin collar, closed with a clip with an amethyst. Drama levels have gone way down. On the third attempt, with a different method, I succeeded, I tried the shirt on, and it already felt extra. Close up of the collar on a table: at the center back of the shirt collar there is a buttonhole, and a double button is used to keep the detached collar in place, while at the front both the shirt collar and the detached collar have buttonholes. But it could be even more extra. With some ruffles also at the collar. Same close up, but now the collar has been closed with a clip-on earring with an amethyst and some small fake clear stones, and it looks as if the skirt had a ruffle collar and a jewel button (or a pin). The shirt had been made with a simple collar band, and I could have just added the ruffle to it, but I also wanted to be able to wear it with other detachable collars, so I decided to make another collar band with ruffles, to wear on top. And that was mostly it, except for the reinforcement patches at the side seams and cuffs: I love having them, because they make the seam end neater and stronger, but they are a bit of a hassle to make, so they got postponed a few days. Same woman and shirt, back with the ruffled collar, in a pose like that of an artist that is fainting for futile reasons. Drama levels over the top. But finally, the shirt was done. And I tried it on, and it was good. But now I really need a pair of cycling breeches, don t I?

  1. ok, maybe straight passing bi? anyway.
  2. I have no idea how they got there.

20 July 2026

Jonathan Dowland: Interzone digital

(no, this isn't a blog post about Joy Division songs) Last time I wrote about Interzone, I was discussing issue #294, the first published under new management in a paperback-sized format ("JB6"). The format and presentation of the magazine was fantastic: it fit in a lot of my pockets, and was packed with 15 stories as well as the regular columns, in full colour with fantastic layouts and illustrations. Sadly there was only one more physical issue before Interzone was forced to become a digital-only publication.
IZ issues 294 and 295 IZ issues 294 and 295
I don't want to dwell on the sad necessity to move to digital. Interzone continues on, celebrating the milestone issue #300 in 2024. Subscriptions are managed via Patreon. Issue #305 just came out. Instead I wanted to write a small bit about how I engaged with the paper magazine, and the difficulties I've had trying to engage with not just Interzone but any magazine-style publication in a digital context. With most fiction, I read linearly: start the beginning and read to the end, in order. That works well for me with e-readers. But for magazines (and most non-fiction) I don't, I jump around: usually starting with the table of contents, I might pick a short column to start, or jump into the middle of the "book reviews" section to read about a specific book. I might skip sections entirely. I find it very difficult to read like this with an e-reader. I think this is partly because I reference the depth of the paper book or magazine, its thickness, to orient myself. But it's also partly the limitations of e-ink.
My tick-list for an issue of IZ My tick-list for an issue of IZ
For print-Interzone, I used to start by inserting a small piece of paper inside the cover (the delivery slip was ideal). On this I listed the stories within and ticked them off when I read them (sometimes I double-ticked if I really liked a story). That helped me to remember, perhaps months or years later, whether I'd read all the stories or not, and which I liked. I could do something similar on some e-readers: the Remarkable for instance. But it's far from convenient to do on most e-ink devices. Interzone digital is available as both ePUB, the most common format for e-books, and PDF. For reading on my regular Kobo e-reader, PDFs don't work very well at all. I think this is generally true of most e-readers. Interzone was (and is) a well-designed magazine. The value of it was not just the content of the text, but the context: how the stories were presented; the accompanying art (most often colour in recent decades), but also the typesetting. ePUB doesn't specify much of that stuff exactly: it leaves that up to the client and the client's preferences. And there's a lot of advantages to that: Prefer a different font face or size? No problem. And most importantly for accessibility: If reading in ePUB makes Interzone available to more readers then that's a great thing. But sadly a lot is lost, IMHO.
IZ #305 on iPad Mini IZ #305 on iPad Mini
The solution I'm trying is to read the PDF version on the iPad Mini I resurrected earlier in the year. Despite being an Internet tablet, since it's not really usable for browsing the web anymore it's strangely still a distraction-free device. In fact it's pretty much single-purpose for reading Interzone and the odd other book which benefits from being read as PDF. I can appreciate the stylistic choices made in the page-setting as they were intended; I can quickly jump around the issue without waiting for an e-ink refresh; I get full colour; and whilst it would be tiring to read for a long time on the iPad screen, for the length of articles or stories in a magazine, this isn't a problem. It's not a solution for tracking what I've read (that version of ipadOS is too old to support clumsily scrawling on PDF pages with your fingers, at least in the Books app) but it otherwise seems to work well, so I'll see how it goes.

18 July 2026

Bits from Debian: DebConf26 welcomes its sponsors

Alt DebConf26 by Romina Molina DebConf26, the 27th edition of the Debian conference is taking place at the Facultad de Ingenier a en Ciencias H dricas of the Universidad Nacional del Litoral, in Santa Fe, Argentina. We appreciate the organizers for their hard work, and hope this event will be highly beneficial for those who attend in person as well as online. This event would not be possible without the help from our generous sponsors. We would like to warmly welcome the sponsors of DebConf26, and introduce them to you. We have two Platinum sponsors. Our Gold sponsors are: Our Silver sponsors are: Bronze sponsors: And finally, our Supporter level sponsors: A special thanks to the Facultad de Ingenier a y Ciencias H dricas - FICH UNL, our Venue Partner! Thanks to all our sponsors for their support! Their contributions enable a diverse global community of Debian developers and maintainers to collaborate, support one another, and share knowledge at DebConf26.

Next.

Previous.