[idea:26w35]2026-08-30

Week 35

Contents

It was the penultimate week before the semester starts up again, and I got a decent amount of hacking done. Early in the week I minted an 0.6.0 release of Rheo. I did several rounds of iteration on rookery through building out a rookery to support my own personal note-taking and task management, which ultimately led to excising rookery releases from the canonical rheo-packages repo and resuscitating them in a standalone one. To support this I also minted 0.6.1 and 0.6.2 releases of Rheo towards the end of the week. One good and hard bike ride to kick the lungs back into shape and some other peripheral hacking and reading, too.

I explained some of the motivation for 0.6.0 last week, so I won’t go into the details here, but my Monday was consumed by releasing this and quality controlling its impact on all the existing Rheo sites I maintain. I also rewrote significant sections of Rheo’s documentation, in part because 0.6.0 adds some new concepts, and in part because some of it was messily synthesized by LLMs. I’m aiming not to have any of the documentation written by an LLM, but they’re inarguably useful for highlighting misalignments between code versions and the documentation in new releases. As a result of somewhat lazily saying “fine, template me the section” on a couple of occasions, some of the prose was giving that dumbly omniscient smell that results from giving LLMs too much control over a writing project.

Now that Rheo’s API is starting to stabilize, at least in my personal use of it, it’s perhaps useful to recall why I built it in the first place. The basic motivation for Rheo as a whole was to provide a wrapping around Typst that would be both durable and extensible for the ways in which I am personally interested in using the language. These ways include producing beautiful and usable EPUBs (a research project), and being the basis for a better local-first writing, note-taking, and task management workspace. I currently achieve a hacky version of the latter using Org-mode and Dropbox, but Typst promises to make the draft-to-publication workflow much smoother, whether ‘publication’ means export as a PDF, as HTML to include in a website, as an EPUB, or all three simultaneously.

When I started developing Rheo in late 2025, I fielded some questions from Shriram Krishnamurthi about why Rheo was necessary or useful in addition to Typst. There are a number of simple answers that I included in Rheo’s FAQ, such as that Rheo gives you EPUB export and arguably simpler project organization. I’d now also add that Rheo enhances the capabilities of the package ecosystem, and provides mechanisms to mix and match bundle export with Typst’s foundational export to PDF and experimental export to HTML. But Rheo shouldn’t really be considered a replacement for Typst so much as an experimental harness that wraps it and extends its capabilities without forking or rewriting it.

The slides package was the first real demonstration of this, as it allows you to export a PDF script and an HTML RevealJS slideshow from the same Typst source without any finicky wrapping around Typst compilation calls and appropriately linking in JS/CSS. But rookery is a project that showcases Rheo’s ambitions as an extensible Typst platform much more vividly, which is one of the reasons I’ve been so charged this week developing it out.

Most of my work on rookery this week was driven by an increasingly obsessive attempt to use it as the dashboard for organizing my academic life. As I’ve written in the rookery FAQ, one of the inspirations for rookery’s elementary notion of the ‘idea’ is Org-mode’s TODO system. My personal task management system has been more or less exclusively Org-mode todos for at least a couple of years. I typically view TODOs as a global list across all of my Org-mode files, meaning that I can drop a * TODO heading in any note at any time, and get it ‘filed’ in my list of all things:

I really like treatign TODOs as federated in this way, as it means that, in addition to showing up on my global list, TODOs are associated with a project and/or other relevant surrounding context, such as the notes for the meeting out of which they were seeded. (Clicking enter on any of the TODO lines in the view above takes me to the TODO’s original context if I want to reference it or iterate there, if the TODO involves writing or further note-taking.)

An idea in rookery was conceived as a (slightly generalized) TODO in the Org-mode sense. Rookery provides mechanisms to aggregate ideas that were hatched in various contexts, allowing them to be federated into global views or views over multiple hatching contexts, and always keeps the backlink to these hatching contexts. One of the packages I wrote this week was a skin over @rookery/core called @rookery/todos which recreates the Org-mode experience:

This is working nicely for the small part of my notes that I have ported over from my Org-mode system currently, 283 ideas in total. These ideas are a mix of conference deadlines, job postings, personal todos, meeting notes, and more Zettelkasten-style notes on entities such as academic institutions and individual academics. Ideas in rookery follow the core principle of associative archiving in that every idea exists in a flat search space. More pricipled ‘types’ (todos, meeting notes, entity entries) can then be specified through rookery’s tagging system, which is inspired by DEVONthink’s tag system. As everything in a rookery is just an idea with optional tags, someone searching it can combine these two core data types to efficiently filter the search space (search by tag) and match on content in ideas (fuzzy search that combs both title and content):

You might be thinking that this is all well and good for simple filters over ideas, but that a flat pool of strings is not a great data structure on which to build more complex metadata associated with ideas such as date lifecycles (created, updated, etc.). It’s of course possible to encode/serialize complex hierarchies and types as strings (created:2026-08-31, etc.); but this gets messy given that rookery wants to show the tags associated with an idea in its interface, as you can see in the pills beneath the search items in the image above.

Rookery tags are therefore actually not represented as an array of strings, but as a hash map. If an entry’s value in the hash map is none, then rookery treats that tag as viewer-facing and presents it in the interface as you would expect (see tags such as meeting, liminal, and tidbit in the screenshot above). If the value is not none, however, the tag is treated both as a regular tag and as a metadata entry on the idea. A tag in rookery can thus consist of metadata structures that make full use of Typst’s type system.

I’ve been working on a @rookery/timeline package, for example, associates a timeline-log with certain ideas, like so:

#let tags = (timeline-log: (
  (
    stage: "submitted",
    timestamp: datetime(day: 29, month: 4, year: 2026),
    note: [What went in ..],
  ),
  (
    stage: "under-review",
    timestamp: datetime(day: 31, month: 8, year: 2026),
    note: [Reception confirmed..],
    estimated: true,
  ),
  (stage: "accepted", timestamp: none),
  (stage: "held", timestamp: none),
))

This means that, in filters and search, we can then also filter according to the timeline-log of certain ideas, prioritizing ones with a deadline approaching. The metadata can then also be used to power custom UX elements exported from @rookery/timelinesuch as this stage-tracking footer shown in the standalone page of the idea:

In addition to @rookery/core, I now have prototypes for @rookery/search, @rookery/timeline, and @rookery/todos, which I am drafting in the 0.1.0 branch. I added a mechanism in Rheo 0.6.2 to read Rheo packages directly from git repos and branches configured in rheo.toml, which should allow me to iterate on the packages without having to constantly mint new releases. (I got up to rookery 0.6.0 this week before deciding that I had to do something about it so that the rheo-packages release stream wouldn’t be so noisy.)

None of this is live or released yet, as I want to at least notionally stabilize the @rookery/core API before minting an 0.1.0.

One serious bike ride this week on my gravel bike, which is noticeably more stable and safe than my road bike, especially on the downhills:

It wasn’t super long, but 150bpm over two hours is a good effort for me. (I have a dangerously low resting heart rate, around 45bpm, and have never clocked a heart rate over 190bpm in the last two years in which I’ve been actively monitoring it.) I was going to do a much longer ride (200+ km) on Wednesday to commute from Turin to Reggio Emilia, but got a puncture all of ten minutes in, and so walked my bike back to the Decathlon in dejection, bought a new tube and changed the tire, and got the train instead.

In preparation for that longer ride, I synthesized an audiobook of Matt Handelman’s The Mathematical Imagination: On the Origins and Promise of Critical Theory, which I’m about halfway through and really enjoying! Next week I will try to get back into writing book reviews on my main blog for this and Karatani’s Transcritique.