see what else worm-blossom has made!
worm-blossom

worm-blossom

2026Week 4109 Oct

“surviving and having fun”

Sammy and Aljoscha walk a slightly bewildered Emmy down a tunnel full of references to the first year of worm-blossom.
A teeny megaphone blaring out noise

Emmy joins worm-blossom

Aljoscha and I are happy to announce that Emmy Walker is officially joining as worm-blossom’s third member. Emmy caught our attention with their high quality contributions to Ufotofu, and has been a driving force behind sneakerweb. Emmy will immedatiately be joining the Pillow project. Also, we think they are pretty cool.

Emmy’s work in Glasgow over the past four years has straddled atomic physics and computer science, where their intrests inexorably slipped from “how do we move these atoms around?”, “what are sensible ways to control our experiments?”, and “how do we store and analyse our data?” to “how can we make kinder, more considerate software?”, and “how much good can we do for people with all the little bits of computer lying around?”. They may still, on occasion, be caught referring to themselves as a good-for-nothing atom-wiggler.

A drawing of Sammy, with a pencil between her fingers.

A little more than a year ago, I struck a bargain with Aljoscha: okay, he could refactor the entirety of the Willow Rust implementation, but we were going to start a weekly blog. On reflection, I think Aljoscha might have gotten two things he wanted.

Since then we’ve posted 52 weeks of editorials, musical compositions, and comics. We even released some software.

Publishing this website has kind of been like drawing a magic circle in that it made new friends and lovely people appear from nowhere. The spell itself seems pretty simple: just regularly tell people what you’re up to and show that you care about it. And don’t be afraid to show your frailties either.

As for the year ahead, I want to keep stretching the blog’s format and keeping it from settling into something too calcified. My favourite thing about this blog is its utter arbitrariness, its complete lack of internal taxonomy. Also I would like to add an About page.

Here’s to another year of worm-blossom.

And to a hard-earned weekend getaway for me!

~sammy

A drawing of Emmy, with fingers laced.

Happy anniversary, worm-blossom.org!

Chipping in with bits and pieces and getting to know Sammy and Aljoscha over the last year has been incredibly rewarding. Working on sneakerweb in the summer cemented for me that if there was any way to properly throw my time and attention behind these new friends and their project, I should take it. As they do, one thing led to another and now this mushroom-person is a person-person!

At the start of this week, I was pulling together a list of all the things I was looking forward to diving into:

  • Catching up on sneakerweb maintenance.
  • Making Ufotofu friendlier by writing guides on “how to” and “why to” work with it, and by adding some creature comforts to the API.
  • Making ufotofu weirder, by exploring some of the lovely (and useful!) structures that start appearing when you nest producers and consumers.
  • And, of course, the biggest, brightest, most exciting pieces - working on the Willow’25 side of the Pillow project, including implementing WTP and all that comes with it. I'll probably mostly be writing about this stuff next week.

As it turns out, this week has felt less like diving, and more like nest-building. I've been surrounding myself with snippets of source code, and decorating the resulting bundle with shiny pieces of relevant blog posts and papers. Now that I've gotten settled, though, expect new ufotofu features and a SummarisableStorage trait coming to a Codeberg repo near you very soon...

Of course, all of this pales in importance compared to the task of figuring out what thing I can contribute to the weekly update, alongside Sammy's art and Aljoscha's music. Maybe I could use some of the leftover bandwidth between the audible and the optical, and provide some heartfelt RF signals...? Okay, perhaps I'll hold out for a better idea.

~Emmy

A teeny megaphone blaring out noise

worm-blossom on Bandcamp

After uploading music here for a year, it is high time to publish it on bandcamp. This is how computer science development logs are supposed to work, right?

You can still conveniently listen to all the background tracks on the playlist on our site, but the bandcamp release lets you download the tracks as normal audio files. Neat! And we will upload other music there over time as well.

A drawing of Aljoscha, chin resting on his hand

After we uploaded the third weekly update to this site, I said to Sammy “And now imagine what this will look like after a full year of updates!” She reprimanded me that we’d have to get there first. And here we are, and it is every bit as dense and silly as we had hoped for.

For our very first update I had originally written a todo list of all worm-blossom related tasks I could think of, but then I never uploaded that list. So just for fun, here is what I thought we would have been doing over the past year. Some stuff I got right, some obviously not, and there’s still a lot yet to be done. But overall I’m happy with how much work we managed to complete.

I feel like we have somewhat dropped the ball on the original premise of the site — publishing useful incremental work instead of batching things into large, polished updates. Then again, our initial pace of being able to announce a useful bit of work for the first three months straight (!) was a pretty mad and unsustainable dash. While we should definitely stay vigilant to not drop back into prolongued silences, I think the current pace is a pretty good compromise.

I am somewhat sad how little progress I made on Macromania. On the one hand, a glorified templating language is more frivolous an undertaking than working on p2p protocols, so deprioritising it never felt wrong. But still, it has been a year, and of all our tooling it is the one we are currently using the most. Hopefully we can make it useful for others soon.

And that will of course be helped by Emmy joining our team cult huddle. They’ve been contributing and participating in a more limited capacity for a while, so I already know it will be great =)

Finally, because I forgot posting about this for two weeks straight: to generalise 2d zip-trees to 2d-G-trees, the internal set datastructure has to store items together with two subtrees per item: those of lesser x and lesser y coordinates, and those of lesser x and greater y coordinates. And each G-node then stores two additional subtrees: those of greater x and lesser y than the greatest (with respect to x coordinate first, y coordinate as tiebreaker) item in the G-node, and those of greater x and greater y. There you go, a definition of multidimensional G-trees. Insertion and deletion algorithms are left as an exercise to the reader (which is to say that properly writing them down would take too long right now =S).

~Aljoscha

Why is it called worm-blossom?!

← Previous instalment

why is this website called ‘worm-blossom’? In this series we will explain why in a concise manner.

Part 10: The answer

“Hey, can everyone hear me?”

A chorus of confirmations from the teahouse, a Mumble server hosted by mycologist and p2p contributor glyph. Also in attendance: Sam Andreae of p2panda, Aljoscha Meyer and Sammy Gwilym.

This has become a regular weekly call, a grab bag of hows-your-weekend-been, project funding woes, and bad (good?) ideas. A little cohesion of different p2p practitioners.

Aljoscha and Sammy have successfully collaborated on a TypeScript implementation of range-based-set-reconciliation. And more than that, Sammy integrated this into Earthstar by writing a monoid skip list, a concept she’d never heard of a few months prior. Aljoscha helped her with it, and they spent a lot of time on voice calls drawing diagrams (Sammy finds this is the best and maybe only way to wrap her head around these concepts).

Aljoscha is warming up to his ideas being applied to the real world. Sammy keeps goading him into further collaborations. Maybe a Rust implementation of Earthstar would be interesting? Its design would need a few adjustments, of course…

“What time are we doing this next week? The clocks go back this weekend…”

“Same time as always, just use the seasonal clock”

The seasonal clock which Cinnamon designed to gently usurp Sammy’s use of Swatch Internet Time, which she only knew about thanks to her teenage obsession with Phantasy Star Online. Which only had Internet Time because a Sega exec also believed in Negroponte’s dream of the internet uniting all humanity. How much did the executives of Swatch really believe in Internet time? Certainly not as much as their predecessors, the French Revolutionaries who first attempted to institute decimal time.

“Okay okay… so that’s 10am - 12am, then?”

“No, no, what’s it say on the seasonal clock?”

“Oh fine. Speak to you at worm - blossom”

2026Week 4002 Oct

“aesthetic sovereignty”

A two panel comic. In the first panel, we see an overhead view of three stone towers, tattered black flags flying. The text reads "Bleak, solitary, misshapen! Castle Misfortune!"
      
      In the second panel, we see Aljoscha walking in on Sammy, looking jolly. He asks "Sammy! Update today! Thought up any good gags for the comic?". In the foreground, we see Sammy snarling, hunched over, protectively hiding the castle comic she's been drawing.

Why is it called worm-blossom?!

← Previous instalment

why is this website called ‘worm-blossom’? In this series we will explain why in a concise manner.

Part 9: Inheritance

It is 2022, and Sammy doesn’t really feel like she knows what she’s doing.

A few weeks prior, Sammy had one last call with Cinnamon. From their hospital bed, Cinnamon told Sammy how she’s the right person to steward the Earthstar project. Sammy told Cinnamon through tears how much she’s going to miss them, how much they’ve taught her.

And now Sammy has inherited stewardship for the Earthstar project, which has just received its first ever bit of funding from NLnet. She’s not sure she is the right person for this. She doesn’t know anything about CRDTs or computer science. She’s faking this. Oh my god she is faking this and they are going to find out.

Fortuntately Cinnamon had the foresight to practice something they called ‘mortality driven development’. Knowing what was coming, they bequeathed a copious number of design documents, comments, and tests. Without these, Sammy would be truly lost. She has just enough guidance to cobble together the parts needed to fulfil her obligations, but there’s one thing really discombobulating her, and that’s sync.

Sammy knows Earthstar’s sync has theoretically the worst possible implementation imaginable: two peers exchange everything they have, and discard what they don’t need. Any claim to being conscious of network or bandwidth usage is simply a bald-faced lie. It’s inefficent, it’s untenable, it’s embarrassing.

A diagram of how Earthstar's sync used to work.

Browsing Secure Scuttlebutt one day, Sammy comes across a discussion on syncing append-only logs, and user arj mentions “You could do something like a set sync instead, Aljoscha has worked on that”. Sammy thinks: Aljoscha? That kind of depressed guy who told me not to use the thing he made? Sammy scours the README. Could this be it? She emails Aljoscha:

Dear Aljoscha,
I was very happy to come across your outline for efficient set reconciliation. I’m trying to work on more efficient sync for my project (Earthstar) and was wondering if I could apply this method to my problem?

Aljoscha replies:

I think things should be amendable to the earthstar situation, in fact earthstar was one of the reasons why I wanted to flesh this out in a thesis.

What? Aljoscha has been thinking about Earthstar already? What? Why? In their second call, Aljoscha tells Sammy how he’d spoken with Cinnamon six months prior on the thorny topic of set reconciliation, and how that had motivated him. Sammy tells Aljoscha how Cinnamon has since passed. Oh.

But maybe we could work together, asks Sammy. On a set reconciliation implementation for Earthstar? Aljoscha agrees, and has no idea what he’s getting himself into.

And in next week's final instalment, we find out why it’s called worm-blossom.

Next instalment →

A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

Last week, I embarked upon an experiment: could sneakerweb be made to work with Rocket, the multi-threaded web framework? The good news is that Ufotofu now has a compatibility layer with tokio (see announcement)! The bad news is that the answer is no, sneakerweb cannot work with Rocket.

We can get ufotofu and Willow’25 working with tokio, but only with the current_thread (i.e. single-threaded) flavour of tokio. Rocket requires a multi-threaded environment.

Ufotofu and willow25's incompatibility with a multi-threaded environment is due to our adherence to Frugal Async Rust. I am going to admit to not having strong opinions on this. I do wonder if I should be concerned that Willow and Ufotofu can't work in multi-threaded runtimes, or whether I happened to stumble into the one situation (Rocket) where this was a showstopper.

Instead I will be using a web framework compatible with tokio's single-threaded mode, probably Axum. The motivation remains using someone else's HTTP request handling and support for templating, something which we're kind of winging ourselves right now.

Otherwise I am doing some up-front work for next week's update.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

Another scattered week for me, rang in by a lovely choir reunion and then dominated by the cold incurred therein.

I did make some more progress on the WTP spec, but it still isn’t in a shape where I can meaningfully share it. I’m getting there.

Also, we held a call today with Olivia of wobbleweb, brainstorming ways forward for integration between wobbleweb and sneakerweb. As we were pondering the aesthetics of the Fediverse compared to those of myspace pages, Olivia coined this week’s motto of aesthetic sovereignty that immediately resonated with all of us.

And finally, I spent the worst day of the cold working on Macromania, porting in a half-daze several macro packages from the old version of macromania to the current version. Specifically, the new macromania-web package combines and improves upon three separate old packages:

  • There are macros for creating URL references, now supporting references to files living on different domains.
  • There are macros for moving assets (stylesheets, scripts, etc) in a web project from an input to an output directory, and for applying transformations (compilation, minification, etc) to the assets, now also supporting dynamically creating assets without any corresponding input file.
  • There are macros for automatically adding stylesheets and scripts dependencies to html files as they are registered by other macros.

Is this all overly complicated, niche, and of utter insignificance compared to progressing Willow? Probably, but on the other hand: We can finally render KaTeX on this site. In a principled way. We simply type <M>x^2</M>, and it automatically does the server-side rendering and embeds the necessary stylesheet on any page where we use this. And we did not even have to manually place the stylesheets (and fonts) anywhere. This may have required several days of coding (and years of idle designing), but if this isn’t the worm-blossom way, I don’t know what is. And Sammy agrees, I think.

(more seriously, this lays the foundations for several nontrivial website features that improve how we can communicate our ideas, and it is hard to overstate how important communication is to all we are trying to achieve)

~Aljoscha

2026Week 3925 Sept

“as long as at least one of us thinks we're a genius we should be okay”

Sammy's 8yo: two robots being connected to a computer so that they both do the same dance. The professor has snacks
A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

A little written field recording: the sound of my son sniffing behind me as I work, the chirps and beeps of a Popular Monster Collecting Game. School's back in and so are the colds.

One of the things I did this week was write the new Store tutorial. The workflow for these has solidified (and uh, expanded) since we first started publishing these. A month ago I pushed up a willow-tutorials repo with all of the tutorials in a single workspace. This repo acts as a space for drafting the tutorial code and also ensuring the things actually run. Then I generate a JSON dump of the willow25 APIs using rustdoc, and commit that to the willowprotocol.org repo, which has a macro for turning rustdoc output into definitions we can refer to on different pages (so that I can turn a reference of rs-willow25-storage-Store into a link that points directly to its corresponding documentation). Then I write up the steps of the tutorial itself, with code samples and output! It's a lot of rigamarole but I think these things come out pretty nice.

Slight tangent: one day I'm going to figure out how to explain the difference between owned and communal Meadowcap namespaces. I think I'm getting closer, it's about describing the most powerful capability each kind can have. I need to figure out how to convey this visually.

I've also started my work on support nodes for the new Pillow project. These support nodes are going to be configurable Willow peers which can communicate with any other peer which understands WTP. You'll be able to configure them with capabilities (so that they know what to sync), set storage limits (so that your Pi with 4gb of storage can pitch in), and configure if it should sync with other support nodes too. So it's got to be a little TCP server which can field WTP requests, and a HTTP server which serves up a web UI for administration.

In true 'I'm doing research for my project!!!' fashion, I've been looking at different Rust HTTP frameworks, and how they handle things like routing, validation, templating, etc. I quite like the look of Rocket, and I can easily imagine how to structure the routes I have planned using it. But I'd like to get some practice in with it before that. So here's my idea: I think I'm going to refactor sneakerweb to use Rocket for its web server. This will be very useful as sneakerweb's current HTTP server is single-threaded, and handles requests at a very relaxed pace, while Rocket's is multi-threaded. It will also make it much easier for us to add new pages to the sneakerweb server, and we'd like to make it possible to do pretty much everything you can through the CLI via a web UI as well. And with that, I'll feel confident enough using Rocket to use it for the Pillow project.

Speaking of sneakerweb, I have a lot of sneaky in-person events on the horizon, and this is lighting a fire under me to update sammy's guide to the sneakerweb, which to date has only been distributed in person. The first edition was a single page, the second edition has many pages and is set to be a real guide which teaches you how to do everything. Maybe it'll make sense to make a .snk containing this site available on the world wide web? I will confer with my colleagues.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

This week I began work on the new WTP specificiation. That’s it, nothing online to show for it yet.

But also, I had some thoughts that got me more excited to work on some important Macromania macros again. And those thoughts in turn are related to the sneakerweb. How so? About two years ago I was thinking a lot about scientific publishing, both in terms of the underlying incentive structures and logistics (they suck) and about the purely technical level of how PDF-based knowledge exchange has its drawbacks. I wrote the Cardboard specification as an alternative for PDFs: instead papers would be written as static websites, and bundled in archives that would allow shipping all (transitively) cited papers together with the paper itself. But then I never implemented software support for this specification or wrote any actual Cardboards. (The G-tree paper was a fruitful exploration of web-based scientific writing though.)

Last Saturday, out of nowhere, I remembered the Cardboard spec, and realised that the sneakerweb enables pretty much the same thing. And we already have running software. The minimal additional featureset I’d envision is a way for sneakerwebsites to specify other sneakerwebsites they depend on (i.e., link to). Perhaps as a simple /sneakerdeps.json file storing a json array of sneakerweb domains. This file would enable two key features: first, it would be possible to take a sneakerweb collection and extract from that everything required to fully and transitively browse a single starting website (or set of starting websites). And second, it would be possible to implement partial downloads of large “papers”: instead of downloading a .snk file containing all transitive dependencies, you’d download a .snk file containing only the starting website, and then you could recursively download its dependencies on demand (and whether you’d download eagerly or lazily, you could skip sneakerwebsites you already had available locally).

The sneakerdep mechanism could be useful for a whole bunch of things beyond scientific writing, in fact all sneakerwebsites that link to other sneakerwebsites would benefit from it. You could have nice software support where user agents could issue helpful warnings: both when a link to a dependency cannot be resolved because that dependency is unavailable, and when linking to a sneakerwebsite that is not listed as a dependency yet (to help authors keep their depencies up to date).

~Aljoscha

2026Week 3818 Sept

“we did end up here organically, but that isn't to say it was a good place to arrive at”

My thanks to Tommi for the lovely walk through Rotterdam today.
A teeny megaphone blaring out noise

sneakerweb 1.2.0

This week we're releasing sneakerweb 1.2.0, which importantly allows your sneakerweb collection to be browsed from Chromium and Webkit based browsers (like Chrome and Safari).

That problem was caused by the base16 encoding we previously used for domains, which basically resulted in hostnames which were too long. Domains now use a base32 encoding. Old base16 hyperlinks will still work in some browsers, but you'll want to update them to base32 links for full cross-browser support.

We’ve also added a sneakerweb remove command. This removes a domain and its data from your sneakerweb collection without blocking it. Hopefully this adds an extra level of nuance to curating your collection (and also makes it easier to experiment with publishing).

Commands like sneakerweb serve and sneakerweb publish now respect custom collection locations. So you can work with independent collections of sites. This is a stopgap to more complete collection organisation.

Downloadable builds are available at sneakerweb.org, and a complete list of changes can be found on the project's CHANGELOG.

Thanks to Emmy, slug, and interfect for their contributions to this release!

A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

We're resilient creatures that can adapt to a surprising amount of stress. Before reaching a breaking point, there are several other intermediate points where things start to get a bit wobbly and plans start to go awry.

As this is a blog about making things and about being a person who makes things, it seems negligent not to mention that I hit my wobbly point a while ago, and that it's been affecting my ability to make things.

Would you believe me, reader, if I told you that updating this website each week started to fill me with apprehension? This cute little blog where no-one is making the rules apart from myself (and some might argue, Aljoscha)? Which we update without fail every Friday for nearly a year?

Regardless of our stringent publishing schedule, I recognise that my apprehension is not really about worm-blossom.org. It's about me, the rapidly changing circumstances which have brought me to my wobbly point, and recognising that if I don't want to hit my breaking point I need to do something about it.

So I'll briefly mention what nourishes me right now — maybe the only thing that really nourishes me right now — which is being in the physical presence of other people who care. About what they're doing there, about each other. When I'm sitting in that I feel like I'm part of a circuit, that there's nothing more precious than to be part of that interchange.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

Between the final days of my vacation and then catching up with work (the semester is starting soon, so there's a flurry of admin stuff to prep for teaching), I had barely any time for worm-blossom. So nothing to report this week.

Instead, have a random programming language design sketch! Imagine a statically typed, object-oriented programming language where all method calls must be mediated through an interface. Classes do not have ad-hoc method implementations, they can only implement interfaces. And concrete classes cannot appear in type signatures, only interfaces can (with semantics analogous to those of using interfaces as types in Java, or to trait objects in Rust).

The impetus for this (slightly cumbersome) design is to combine the flexibility originally envisioned by OOP — every object can be transparently replaced by a different kind of object as long as the new object reacts to the same methods — with static typing. In a language like Java, you lose the fungibility of concrete types the moment you constrain a variable or argument to a specific class. This interface-only type system would enforce fungability everywhere.

This has some interesting properties: for example, an equals method would have to implement comparisons based on public trait methods rather than by accessing internals. This feels like a bit of a hassle, but also it makes sense philosophically: equality (or equivalence, more generally) must depend only on publicly observable properties rather than inaccessible state. A bit like whether a person is perceived as a good person depends only on their observable actions, not on the belief system sustaining their actions. This type system design applies that viewpoint consistently to all programming.

Generics play a fairly important role in this type system: compare the kinds of values that could be returned by newer(a: Entry, b: Entry) -> Entry with those that could be returned by newer<E: Entry>(a: E, b: E) -> E.

Finally, this language should probably have some unconventional type-level operators: A && B could denote the set of types implementing both the A and the B interface. And A || B could denote the set of types implementing at least one of the A and B interfaces. On the value level, there'd then be a match statement for different branches depending on whether a value of type A || B implements A or B.

But enough of that, I have emails to write and access rights to assign =S.

~Aljoscha

2026Week 3711 Sept

“hinged”

This illustration was sent into us from Youjung Noh, who makes the most lovely pencil drawings (and I was given express permission to turn this one pink). This illustration comes specifically from her Tangled Thoughts zine.
A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

Okay, so hear me out. I was listening to Kate Bush's Deeper Understanding while out on a walk. This is a song about someone who develops an unhealthy relationship with their computer via a piece of software which is able to talk back to them. The original version of this song was released in 1989.

The chat interface has now been around for decades. People have built new friendships, fallen in love, and built entire communities through speech bubbles filled with text.

And without that priming, without the education that on the other side of that speech bubble there is a living, breathing person, would any normal person have given LLMs a second look? Or would they have seen how absurd the premise is immediately?

This is but one of the many half baked thoughts I bothered others with after attending BYOW - A Webcraft Meetup. In my corner of the world it feels like I know of a lot of interesting, caring, talented people who for whatever reason never seem to get together. But we're all atomised away from each other. Why is that? The country I live in is dense and small. Is this the dark side of the bicycle, that anything further than 15 minutes away is just too far? (please keep tuning in for my broad and sweeping societal theories).

But back to the BYOW meetup. It was interesting that a lot of people were building shrines. Eulogies, making wishes, shrines to fandoms. There was always this big question of how the author went about the upkeep of the site, how pleasant or unpleasant that was and how they kept up with it anyway.

Speaking of which, while talking about this very website, I admitted that I still hadn't gotten today's update ready and was starting to feel nervous about it. And almost immediately help was offered. I've included a few contributions to this week's update from lovely people I met last night.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

This week I want to share some thoughts not about Willow but about the Sufficiently Good Media Formats, specifically about the problem of enabling efficient seeking to arbitrary timestamps in an audio or video file. As a bare minimum, you want to wrap the encoded samples in segments, say, of one second each. But how can we enable efficient access to specific segments?

The most straightforward way is to have a table of contents at the start of the file, specifying the location (i.e., the starting byte index) of all segments in sequence. The problem: with this scheme, you cannot emit a file in a single pass over the samples to encode. You have to first encode all samples and track the segment starts in memory, and then jump back to the space for the table of contents and fill it in. This requires O(n) memory, not good. You could also jump back and forth between appending a new segment and seeking to the table of content and adding a single item, but that's pretty inefficient (even when applying the obvious optimisation of batching things). And finally, the whole scheme precludes schemes that simply emit the bytes of the file as a single stream with no backwards-seeking (unless you do two separate passes, one for computing table of contents locations and one for actually appending samples).

A simple alternative would be to have the table of contents at the end of the file instead of the start. This makes it possible to emit everything in a single pass without seeking, but it also necessitates O(n) memory usage. So here are two alternative schemes, which I haven’t seen anywhere in the wild (though, admittedly, I haven’t thoroughly searched either — I’ve mostly had some fun trying to solve this from first principles). Both schemes enable finding arbitrary segments in logarithmic time, and allow for single-pass, O(1)-memory encoding.

The first scheme works by building a backwards skiplist over all segments: each segment specifies the location of the predecessor segment, and the location of another, possibly much older segment: the n-th segment specifies the location of the n-p-th segment, where p is the largest power of two that divides n and is strictly less than n. Finally, the very end of the file specifies the index of the start of the final segment.

This scheme lets you seek to any segment in logarithmic time: you seek to the end, obtain the start of the final segment, seek to there. Then you check whether the non-predecessor link overshoots your target segment. If it does, go to the predecessor segment, otherwise follow the non-predecessor link. Repeat until you find the target.

Producing these files requires O(log(n)) memory: you need to keep a table of the addresses of all segments whose index, in binary notation, consists of a number of ones followed by a number of zeros. Updating that table takes only O(1) amortised time, so the encoding process overall takes only O(n) time, the same as without any segment seeking scheme.

The other scheme is based on self-synchronising codes. First, you make sure that the contents of segments do not contain zero bytes (there are efficient techniques for that). Then, you prefix every segment with a zero byte, followed by its index.

Seeking works by guessing a likely location for the segment you are seeking for, and then scanning forward to the next zero byte and looking up the index of that segment. If you guessed wrong, you take a more refined guess and repeat. This guessing procedure can be simple binary search, it can try to estimate how long most segments are to compute a more likely location, or it can be a hybrid (that would/should combine the worst-case bounds of binary search with the far better average-case behaviour of computing indexes based on average segment length).

In the worst case, this scheme incurs a lot of overhead during seeking, spending time sequentially looking for the next zero byte. But on the other hand, non-adversarial files probably allow for faster seeking than the necessarily logarithmic approach of the skip-list scheme. And emitting these files adds no asymptotic overhead to the encoding process at all, which is quite neat.

I don’t yet know what to go with for the Sufficiently Good Media Formats, and I certainly will not make that decision before properly reviewing the state of the art. But instinctively, I do find the scheme based on self-synchronising codes very appealing...

~Aljoscha

We're listening to...

Neil D. Voss

A last hurrah of commercial tracker music, prompted by the limitations of the Nintendo 64. Kind of dark and brooding, I love it. ~sammy

The Sensual World
Kate Bush

Not only amazing for its anticipating of pathological human - machine interaction, I could listen to this album again and again.

2026Week 3604 Sept

“*everything*'s dying, Aljoscha”

A photographer, Rae Romero, came by my studio a few weeks back. My apologies for dithering.
A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

This week I've been working on things that aren't quite ready to be picked apart by the ravenous audience of worm-blossom.org.

The new worm-blossom 'mega bar' is now in operation across the many worm-blossom franchises. We deployed these two weeks ago, but the styling for each site wasn't completely right yet. Now you can skip across the worm-blossom-verse with ease.

I began working on new tutorials for Willow, now that the Store and Willow Drop Format APIs have been published. Writing a tutorial has the unfortunate outcome of making you see the things you've designed from a beginner's viewpoint. New areas for improvement have been identified.

Meanwhile I have been held in the grip of the phrase “nothing special”. When is “nothing special”... well, special? It's when you see how something has been assembled, and that all the parts are in fact quite boring, and that you too could make nothing special yourself if you wanted to.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

I took all my pondering over the WTP design and cast it into a single specification collection of Rust types for the different message types. This is a fairly dense artefact compared to an actual spec writeup, but I hope I can gather some feedback (from Heni in particular :3) nevertheless.

Aside from a continuous stream of Willow test vector improvements, that’s mostly it. I really hope that the WTP design will stay mostly stable; while it is fun to work on these designs it is also somewhat stressful, and I look forward to fleshing things out without reexamining the foundations all the time.

I will be offline for ten days of vacation now (again, what a decadent summer), for yet another choir trip. I prepared background music and an editorial for next week already, but I won’t be as responsive on the Discord server during that time. Sorry @Freckles =D

~Aljoscha

We're listening to...

Gang of Four
Adz had some Gang of Four playing at his birthday party, and I’ve been listening to this album quite a bit since. ~Aljoscha
Third Voice
Not music, but a long-form audio podcast I am re-listening to currently. What starts out as a fairly slow-paced and meandering space-western-fantasy thingy turns into a tight, suspenseful kinda-horror-story (?) with well-executed plot twists and masterful worldbuilding. A bit difficult to describe, but just really, really good entertainment. ~Aljoscha

2026Week 3528 Aug

“less thinking more fuzzing”

A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

Reader, it wouldn't be unreasonable to look at last weeks plans of ‘support peers’ and think: that’s just another name for a server. You couldn’t find enough peers, so you had to turn to an always-online machine somewhere. Cop-out.

Well: nuh-uh. In this editorial I will argue that we are doing something meaningfully different from traditional servers.

Servers are (hopefully) characterised by their high uptime, but they are not fungible. If a Mastodon instance’s server is down, we can’t point our mobile client at another server and expect to have the same functionality available to us.

Peers in a p2p network are fungible. We can connect to whatever we can and exchange as much data as possible. But a peer running on a mobile device has only very intermittent uptime. It may only be available when an app is in the foreground, which is not very often at all.

A non-fungible machine with low uptime is just… a crappy server, so that’s not a very interesting combination. But a fungible machine with high-er uptime feels like it’s relatively unexplored.

??? = Support peers. Though I think we can find a better name, something that distinguishes them from intermittently available peers.

What kinds of infrastructure are possible when high-uptime peers are fungible? Sure, you get a ‘swarm’ of high-uptime peers that are more resilient to outages, but… how about something more intentional, like a relay of peers turning on and off as solar power becomes available to them?

Servers are also usually far more capable machines than the devices they serve: more processing power, more storage, more authority. But we’d expressly like to enable peers which can provide high uptime but which have other constraints such as low storage or processing power. If we can prioritise the storage of recent data, operators of constrained devices like this are still able to meaningfully pitch in.

And those high uptime peers can even sync with each other! I think it’s meaningfully different from ordinary servers, and I hope we can use this as a tool to change how we think about supporting infrastructure.

Finally, some graphs to explain how Pillow bridges between p2panda and Willow.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

A good chunk of my worm-blossom time this week went into the Willow test vector repository. Before this week, that repo held inputs and expected outputs for a few Willow encodings, some of them outdated and thus actively misleading. Now everything is up-to-date again. Additionally, I started adding test data for more than just encodings: there is now also a directory for data-model related functions, such as determining whether an entry should overwrite another, or computing the lexicographic successor of a path (a task less trivial than it initially sounds).

There has been a flurry of other tasks on my mind, to the point where I started to feel a bit overwhelmed. Writing them all down is probably going to help, so here we go:

  • WTP design:
    • handling proofs of knowing the secret for a write capability,
    • unifying the different messages that all request entries as much as possible,
    • determining how/whether peers should pre-announce which features they implement,
    • mapping out which messages can be sent as responses to which other messages,
  • the ed25519 ambiguity issue of willow25
  • updating to the new major version of the ed25519 implementation we use in our Rust work,
  • mildly panicking about quantum computers breaking ed25519 in the not-entirely-unreasonably-far future,
  • planning Rust traits for Willow stores that allow aggregating metadata (for RBSR) and for splitting 3d-ranges into smaller ranges containing roughly equally many entries (again for RBSR),
  • more media file format details (in particular, I’m still exploring different mechanisms for enabling efficient seeking in audio/video files),
  • the Macromania website,
  • some macromania macros I should really write sooner rather than later (macros for integrating and possibly transforming assets for websites, macros for referencing these assets),
  • a data base file format for 3d Willow entry storage,
  • the prerequisite 3d-zip-tree work I need for that,
  • providing recommended ways of encrypting Willow data (and metadata) at rest as part of Willow25 (we already have generic designs, but no specific instantiation for Willow25 yet),
  • API and implementation designs for this encryption work in Rust,
  • figuring out how to make encrypted sneakerwebsites a thing (in a backwards-compatible way, ideally),
  • work on my writeup of p2p design principles/lessons,
  • plans for the first birthday of worm-blossom.org,
  • idle thoughts around more intentional background music tracks in the next year,
  • adding more Willow (and Bab) test vectors,
  • planning some test vector improvements,
  • sketching a design for a Willow-powered alternative to Email (that I will probably write more about in the future), and
  • a whole bunch of encryption issues pertaining to that Email alternative.
  • Bonus stuff:
    • sketching a type system for an object-oriented programming language where there are no concrete object types but only interface constraints,
    • sketching an engine for web-technology-powered text-based single-player RPGs, with beepbox integration for (reactive) soundtracks,
    • reflecting on Hannah Arendt’s On Revolution and how her thoughts on the origins and nature relate to technical protocol.

Jup, okay, in retrospect I can tell why I was feeling a bit stressed out this week.

~Aljoscha

Shout-outs!

Thank you to Freckles for all their& feedback on the Willow test vectors, and the resulting discussions. Whenever they& found an inconsistency, they& scoured the specifications and our Rust implementation for the cause, uncovering and reporting bugs in both — including a rather serious missing check in our capability verification implementation. It turns out providing test vectors does not only help other implementors debug their code, it also helps debug our own implementation. And it has been pleasant and fun!

Unsurprisingly enough, the reason they& started scrutinising the test vectors is that they& are doing a Willow implementation. It is written in Typescript and currently lives here. Willow in Typescript means Willow in the browser, and that is quite exciting!

Slug has contributed a command to our sneakerweb implementation for locally removing sneakerwebsites without blocking them. I’ve wanted to do exactly that multiple times by now, it’ll be great to have that in there. It was merged into a branch called fix-all-the-things, so it is going to make it into main any minute now I’m sure!

Also I want to point out how all sneakerweb contributors so far consistently have neat personal websites. Not exactly surprising if you think about it for more than two seconds, but still. It’s been neat browsing through this unexpected trickle of free-spirited digital places. Here’s the collection of those who linked to their website in their codeberg profile:

2026Week 3421 Aug

“and this is me starting with something that was *useful*”

A drawing of Sammy, with chin resting on her hand, a pencil between her fingers.

Back in March, Aljoscha and myself huddled at a hotel bar with adz, glyph, and sam from p2panda. We’d decided we were going to draft and submit a new grant proposal hours before said grant’s deadline. Collaboration between our projects had always seemed like a bit of a utopian idea, but we finally had convergent goals.

“Project title?” said Aljoscha, hovering his mouse over the empty form input.
“Hmmm… put Pillow” said adz. “We can always change it later”.

Pillow is a new collaboration between p2panda and worm-blossom. It’s a way for p2panda apps to quickly store and retrieve data from highly available peers. These highly available peers don’t know anything about p2panda data, but they do have decentralised, capability-powered permissions, can happily evict stale data, and can efficiently sync with each other. That’s because they’re Willow peers!

In this grant we’ll be implementing WTP, meaning that at long last Willow peers will be able to sync over the internet via range-based set reconciliation. We’ll also be developing WTP-powered servers with web interfaces for configuring capabilities, data eviction, and viewing storage usage.

The first users of these Willow ‘support peers’ will be p2panda apps, which will be able to interface with them via Pillow. The idea is that the Willow-powered peers don’t need to do all the stuff a p2panda peer usually does, and will be freed up to act as oblivious (but permissioned) storage.

Not only will we be working with the pandas on this project, but we’ll also be bringing a new member into worm-blossom (more on that later).

In the meantime, I’m getting back on my feet and using those feet to make silly announcement videos.

~sammy

A drawing of Aljoscha, fingers interlaced, with short hair!

I just came home from a productive walk with some realisations about message encodings for the WTP. These center around statefulness of peers, optimised relative encodings, and request cancellation.

The most basic requests are purely stateless: a peer issues the request, and then simply discards all state that pertains to it. Consequently, the (encoding of the) response must be fully self-contained. First realisation: such responses are indistinguishable from eagerly pushed messages — a peer might as well send such responses without ever having received a corresponding request, and the other peer would be unable to tell. I spent the past two weeks trying to argue against eagerly pushed messages, and now I feel a bit silly.

The other option are stateful requests: a peer issues a request, assigns it a request id, and keeps some state associated with the request. The response contains the request id, and can refer to the state for more efficient encodings. For example, when requesting a Willow entry in a specific namespace, the response encoding can omit that namespace. Second realisation: protocols can easily support both modes of operation. Requests can simply indicate whether responses should be standalone (allowing for stateless requesters) or whether they should be optimised (forcing the requester to keep state).

Moving on to message cancellation: as far I can tell, cancellation (by the requester) serves two important purposes. The obvious one is that it can prevent large responses from being sent only to be discarded upon arrival. The second, less obvious purpose is that cancellation allows the requester to free up any state it had to keep around to be able to decode and process an eventual response. This leads to the rather obvious third realisation: there is no sensible notion of cancellation for stateless requests — if a peer does not even record that it sent a request, it cannot later cancel it. And there is no state for it to free up anyway (though preventing pointless responses would still be desirable, of course).

For stateful requests, there is a more interesting dynamic going on. When using optimised response encodings that rely on state kept by the requester, the requestor cannot immediately clean up its state after sending a cancellation. Concurrently to sending the cancellation, the other peer might have sent a response, after all. And decoding that response requires the old state. Hence, realisation number four: stateful requests imply that cancellations must be confirmed by the other peer before state can be cleared.

This, frankly, is not great. Thankfully, there is a way by which to combine efficient encodings of responses to stateful requests with immediate, non-interactive cancellation: prefixing responses with their length allows the receiver to discard the response from the communication channel and then keep decoding the next messages even after having cleaned up the state that would have been required to properly parse the response. This was realisation number five.

I'm happy with this outcome: letting peers indicate whether their requests are stateful or stateless allows for incremental implementation of a protocol, by starting with the easier-to-implement stateless variants only. And stateful messages with their more efficient responses still do not force requesters to keep around state until their peer cooperates. This is a lot better than what the current Willow Confidential Sync draft offers (mandatory stateful encodings, mandatory cooperative cancellation).

What remains is a final meta realisation: it feels odd that I needed to come up with these approaches myself, after years of being active in the space. We really need better teaching material. I know I'm slightly peculiar in my emphasis on (bounded) state management in communication protocols, and I know that using state for optimising message encodings is a topic that will be skipped by anyone who wants to simply use a serialisation library and not think about encodings at all. But still, everything I've been writing about today is fundamental to how communication works. Guess I need to add yet another article-to-write to my todo list =S

~Aljoscha

guest article

What the pandas have been listening to lately.

glyph

Kawasaki by Remon Nakanishi
gives me the chills every time; remon’s vocals are utterly transporting. p.s. everything from DOYASA! Records is golden.

Straight drop by cootie catcher
i recently discovered the “twee” genre tag on bandcamp and am not afraid to admit that i love what it led me to.

Magpies by Tipper
sunset bike rides through the city in the summertime.

adz

Descubrimos un suspiro by Mabe Fratti
i love the whole record so much, can’t stop listening to it. ❤️

Untitled by Bill Orcutt
endless beautiful free solo improv chaos from one of my favorite guitarists.

Mirror by 13 Year Cicada
experimental pop band from berlin with a lot of fun mathy loops.

sam

Top of the World by Shonen Knife
this song always makes me happy.

~the pandas

A drawing of Aljoscha, fingers interlaced, with short hair!

It is now a few hours after writing my first editorial, and the consequences of these realisations for the WTP are starting to sink in. The initial WTP draft had both RequestGet messages for requesting individual entries (and the corresponding ResponseGet messages) and RequestPut messages for eagerly pushing an entry to the other peer. Here is the key insight: ResponseGet and RequestPut carry the same information. The only difference is that RequestPut uses an absolute encoding, whereas ResponseGet uses an encoding relative to the corresponding RequestGet message. In a design where the same messages can be encoded either absolutely or relatively, these two message types can merge into a single type.

And this can be an overarching design theme for the WTP. Instead of thinking of messages in terms of requests and responses, as many messages as possible should admit both absolute and relative encodings. Specifically this means:

  • Asking for an entry (and/or its payload): absolute only.
  • Sending an entry: absolute, or relative to anything that asks for one or more entries.
  • Sending a (part of a) payload: absolute, or relative to a message asking for a payload.
  • Asking for all entries in an area or range (and optionally supplying metadata — fingerprint, entry count, and/or total payload lengths — about one's own entries in that area or range): absolute, or relative to a message asking for a super-area or super-range.
  • Cancelling a “request”: relative to anything asking for one or more entries.

I want to note that where I write “absolute” encoding, that is only meant in the sense that the encoding is not relative to a dynamically indicated message. To make the encodings as efficient as possible, the spec might still use relative encodings even for standalone messages. To give an example: peers could be mandated to remember the last entry they sent. Each send-entry message could then be encoded relative to the previously-sent entry, allowing, for example, to indicate with a single bit that the current entry has the same namespace id as the previous one. The crucial point is that such encodings require only a constant amount of space, irrespective of the behaviour at runtime, whereas encodings relative to any previous message would require tracking state proportional to the number of previous messages. Another application of this technique will allow transmitting payload slices while keeping the corresponding entry and/or slice start purely implicit.

Aside from a certain elegance, breaking up the request-response dichotomy has a tangible benefit: this design allows peers to express and run both symmetric and asymmetric range-based set reconciliation. The old design was restricted to client-driven asymmetric reconciliation only, exactly because requests for ranges could not be sent in response to other such requests.

THIS IS SHAPING UP NICELY, I AM QUITE EXCITED!

~Aljoscha