Earlier this week I started reading an ebook and was a bit irritated because the book did not show me a table of contents. This seems to be a regular thing in ebooks. Already earlier I have complained here about why ebooks, or perhaps mostly e-readers, make so little use of the affordances of digital files.

ePUB files are really XML in zipped archives. Since I left Amazon and the Kindle reader behind, all my ebooks are ePUB files. XML means that the files are machine readable and highly structured. That opens up possibilities to manipulate them.

I used Claude Code to ask a few questions about ePUB files and how they are treated by e-readers. E-readers deal differently with the information in an ePUB file. They may load a table of content into a local database, and use that to allow navigation, or ignore various pieces of information in the XML altogether.
For fun, I asked Claude Code to check the XML file of the ebook I was reading earlier this week, to see if it actually contained a table of contents that was just not shown to me in my reader. Turns out it did.

I also asked it, if it would take a lot to extract a table of contents from an ebook. It doesn’t, so I now have a first script that finds the table of contents if present, or builds one from the headers in the ePUB’s XML if not. The php script saves it to a markdown file that I can then use in my book notes, to group my thoughts and annotations.

In my Kobo reader, and in my Calibre reader the ToC information that the ePUB file provides outside the regular content of the book (NCX or xhtml), is accessible through the reader’s interface, but not part of the reading experience itself. I generally like my ToC to also be presented in the book, like it is in a paper one, and I actually prefer it not at the start as is usual but at the end, near notes, references, and literature lists, to have all the book’s metadata together to glance at. For that a ToC must be not separate from the book’s content, but within it. It would need to be in the ‘spine‘, the part that is presented for reading by readers.

If I annotate or highlight in a book, those are kept by an ereader separate from the book and refer to specific points inside the XML (through canonical fragment identifiers, CFI). You can alter an e-book, it’s XML after all, but that would shift the position of content fragments, and existing pointers from annotations and highlights would then point to the wrong lines in a book.
So if I add a ToC, grabbed from the existing metadata or constructed, inside an e-book, my preference to having it at the end is actually useful. Because if I add it to the end, it will not shift anything I may have annotated or highlighted already, messing up the pointers in the annotation file.

Next to extracting a ToC I’m also thinking about extracting other meta-information (like indexes, references, lists of images or tables) but a first glimpse into some ebooks suggests that those are not usually listed in the Manifest of an ebook, so would have to be constructed from clues inside the book.
However it will help me read non-fiction non-linearly if I could extract such things, e.g. the figures and tables present. It seems to me a number of such steps should be straightforward from the structure of an ePUB file, others need a parser to extract the right information and shape in a useful form, but still can be done with regular scripts (e.g. show me the first and last two paragraphs of a chapter to get a notion what it talks about), yet others do need a (local) LLM, e.g. to summarise each section of a book separately. I’ll see how far I can get, and learn about the ePUB format along the way, with deterministic code first to extend my personal and local toolkit on my computer.

Update 12-04-2026: I now have a script, that I run in my browser, which allows me to select an ebook from my Calibre library, and then explores it w.r.t. the table of contents, reference and literature sections, and images, and also pulls in the first and last few paragraphs of a chapter (which let’s me explore what a chapter is about, Adler style). All that gets turned into a markdown file that is then put in the corresponding book note in my Obsidian vault using the right template.

At PKM Summit this weekend one thing that stood out was that many have started creating their own tools, and were using vibecoding to create them.

While the term agency turned out to be unknown to almost all participants, that is of course what such tools create. The ability to do things, individually or as a group, in this case by creating your own tools to get there.
The power of finding new agency was felt and expressed by quite a few, and played a role in a good number of sessions too.

When I first encountered computers, in the early 1980s, creating your own stuff was the norm. It was almost the only option. Making the machine work for myself. Like software to keep my ham radio logs and print QSL cards.
These days I run a good many smaller and larger personal pieces of tooling on my laptop. Things like making it easy to search by date in my photos on Flickr, or posting to my website from my internal notes, or from within my feedreader.
Things that reduce friction, speed things up, reduce dependency on external systems.

Vibecoding, and especially the Claude Code style of vibe coding, is bringing people to create their own tools, who weren’t able to do so before. A pool of latent needs they can now tap into on their own.

Some I know are really now learning how a computer works under the hood through their vibe coding. Testing the limits of their machines, finding out how fast local stuff can be. Discovering the power of APIs, the utility of cron jobs, and learning how to run their own VPS or local servers.
Others are creating little tools that work the way they want. An app to present books from their collection in that one specific way just so. A mobile app for public transport built on your own existing commute patterns and nothing else. Apps pulling in data from several sources and presenting them in one interface that likely only makes sense to themselves.

Tools built by people realising they are pretty predictable to themselves, and that such highly localised and specifically contextualised predictability now lends itself to automation by the intended user themself.
Tools, in short, where, access to and control over data lies fully with the user, where applications are views on that data (and multiple apps use the same data), and interfaces queries on the data. Along the lines of Ruben Verborgh’s 2017 article “Paradigm Shifts for the Decentralised Web“ but then way more personal. The decoupling that is possible between data, applications and interfaces is even more powerful when you can do them all three for yourself. And then mash them up in any which way you want.

Vibecoding is allowing people to jump the barriers to entry to that. And judging by the stories they share, it feels like pole vaulting over them, not just clearing the barriers. That energy then propels them on to do more.

Over the past months I’ve also heard regularly how people are cancelling paid subscriptions to various online services, and switching to their personal tools that fit their use case much more precisely.

There are many ethical, political, and societal issues with much of the gen AI world, and how models come about, and how corporate vendors exploit and leverage their power.
Yet, where these things are not just consumed but used locally as a leg-up to a different level of self-reliance, it looks quite different. Something is brewing it feels like.
A shift, and I’d love to see more people explore and extend their own agency with such tools.

Favorited Ollama Claude Code integration by Ollama
Favorited LM Studio Claude Code integration by LM Studio blog

Last Friday I participated in a workshop by Frank Meeuwsen on using Claude Code. I’ve been reluctant to use Claude Code for the basic reason that it uses cloud run models by default. This means that my inputs and any context I provide leave my machine to be gobbled up into the data foraging models. Nevertheless it was fun, I improved on my existing personal feed reader (a presentation layer on top of FreshRSS that allows me to write responses while I’m reading feeds).

However tempting it is to continue vibecoding with Claude Code and watching it work its way through my coding requests, that is not the way to go. After some online searching I found the above two pages, that explain how to point the program Claude Code to use the local end point of either Ollama or LMStudio. That’s more like it!

Now I need to figure out which LLMs that can be downloaded (or run on a VPS perhaps) are best suited to the type of tasks I want to set it. For coding, local agents, translation, and semantic work. There can be multiple models of course, as I can switch them up or run them sequentially (and in parallel if I deploy them on a VPS I think).

Open models can be used with Claude Code through Ollama’s Anthropic-compatible API

Ollama documentation

This means you can use your local models with Claude Code!

LM Studio blog

Early December I blogged about wanting to build a stronger habit of bookmarking and annotating in Hypothes.is (which sends everything on to my notes in Obsidian). Over the past month that has worked out nicely, with steady additions to my bookmarks and annotations, unlike before.

In that early December posting I mentioned wanting to fix two things:

Today I made a first version of tool to allow me to share to Hypothes.is from mobile. I reused the same code I made for posting within my feedreader, but with added precautions and checks because it needs to live on the open web to function.

The reason I wanted to build my own tool is that one way of doing this, through a proxy server run by Hypothes.is, will be switched off by February. The suggested replacement for mobile somehow doesn’t work in my mobile browser. I don’t know why, and felt it’s better anyway to try and build my own thing.

In this first iteration, it’s a regular webform served from one of my domains, that I bookmarked. While browsing online, I can copy the URL and e.g. the title of a page to the clipboard, and then open and populate the webform by selecting the bookmark, adding a comment and some tags. Hitting submit, sends it all to Hypothes.is. This works best if you have a clipboard on your mobile that can have multiple entries, so you have the material for one or more bookmarks and annotations on it.

So my second fix from last month I’ve now created. Probably I will iterate a bit on this, to see if I can reduce the number of steps involved.

I’ve reached 2000 bookmarks and annotations in Hypothes.is. A large chunk of those 2000 bookmarks came this month, some 20% of them. Because, mostly I think, I’ve hit on the right mindset that makes bookmarking/annotating in hypothes.is a habit. Next to having a bit more energy and mental space in general than I had for a long time, that really helps too.

Exactly four years ago today I created my Hypothes.is account. I made my first annotation there only in April 2022, and started using it regularly in late August 2022.

Two thousand isn’t a whole lot of course. Annotation is not just bookmarking, and a single page can have many annotations. Still it is relatively more than the 3200 bookmarks I collected in Delicious over the span of eleven years, from summer 2004 to summer 2015, and the hundreds I saved to Evernote between 2016 and 2020. And it makes Hypothes.is the only new addition to my otherwise shrinking distributed online presence in the past years.


The graph of my annotations, a start in the fall of 2022, then a steady linear path for two years, followed by a little jump and a much flatter usage for a year, ending in a strong jump.

I noticed early this month that something seemed to be shifting in my annotations.
Three elements are part of that shift, and they combine to make a more active habit

  • I made it easier to bookmark and annotate, by reducing the friction to annotate from right inside my feedreader.
  • I let go of the internal voice that any annotation should be a ‘proper and serious’ annotation, a result of thinking. Annotation is an every day activity, creating the breadcrumbs that may result in deeper thinking later on in my notes. All annotations flow automatically into my local notes, where I can work with them and re-use them.
  • I start with a question or topic and wander where hyperlinks take me for 15 minutes or so. This is the type of browsing like it’s 1993, when that was the only way you could take in the world wide web (and actually for a short while: take in the entire web). It feels natural, and it feeds actual current interests, work-related, side interests and every day things. It makes annotation an every day activity for real.

The first two changes make it easier to start annotating. The last change makes the biggest difference, as it results in short bursts of new annotations in a steady rhythm.

Hypothes.is isn’t a widely used tool out on the open web. It is mostly used in educational settings, for classes and groups, and integrated into learning systems. It does have a few social features though, like the ability to not just follow (through RSS e.g.) but also respond to other people’s annotations. Like in the old days of Del.icio.us that is a way to find others interested in the same thing as you but from a different perspective and using different language to describe it. I have a small roll of Hypothes.is users. You can also check out who is annotating using similar tags to yours to find new people.

Yesterday Martijn Aslander demonstrated the personal information tools he recently created. I came away inspired. Perhaps not by the tools as such, and more because of the pathways of thinking it opened. And because everything was so blazingly fast. All vibe-coded, as he has no coding skills himself.
I can see how the way his brain works is aided by the structure and availability of information his personal toolbox provides him. However, I myself would be more interested in shaping a personal tool like this towards being able to facilitate me in my processes and habits, as well as let me work towards actual outputs.

The Digitale Fitheid (Dutch language platform) community (Digital Fitness, the English language platform) has a monthly face-to-face meet-up in Utrecht, and yesterday was this year’s last. In the morning E had attended a session by Frank Meeuwsen on how to use Claude Code to quickly build something from scratch. In the evening I joined Martijn’s session on what he is calling his ‘Theta OS‘.

Some observations.

  • Martijn’s Theta is mostly a dashboard on local information. It shows him lots of different pieces of information at a glance. Each of these things, hotel bookings, books, payments, tasks, quantified self measurements and more, can live and be accessed in their own little apps and silos, but he uses the dashboard to combine them in context. At the outset he said that having his own established ontology (in the information sense, not the philosophical) was a prerequisite. That sounds very true, as the purpose here is having an extremely personal tool. The value is in combining various information sources on purely personal criteria on the fly.
  • His tool stack is sqlite (a lightweight database, installed by default on my Mac), with node.js (to run javascript), and regular html and css for the front-end using the local webserver on his laptop. I didn’t have node.js on my Mac, installed it now to be able to try some things.
  • He is not a coder, so everything is vibe coded with Claude Code. And while maintaining that makes him able to quickly create things, he spent some 500 hours in Claude Code in the past months. Makes me wonder what he could have done in those 500 hours if he hadn’t used it. I do recognise that given his nature, a organised path of exploration and learning would not have been feasible, though might well have resulted in a similar proof of concept after 500 hours.
  • Because of this he wasn’t really able to conceptually discuss the results other than what it does on the front-end and what it means to him. When asked about the architecture of the tool he therefore asked Claude Code to whip up a description.
  • In working with Claude Code he did not feed it his personal information, but abstracted structures. E.g. to incorporate a CSV with personal information he would provide the structure and a bit of dummy data to get a parser or importer and change the database structures. Then use the importer for the actual data outside of Claude.
  • To Martijn Theta is for surfacing and combining little pieces of data and information. He also uses markdown notes a lot (with Obsidian as viewer), but Theta keeps all the small pieces out of his notes. Only when he combines things into something more informational he brings it into his markdown notes. I find this distinction makes sense, as I am usually adverse to ‘make Obsidian do everything for me’ type of efforts. I use several tools that work on my Obsidian notes but do not attempt to be part of Obsidian. Largely absent yesterday was the other way around in the demo / discussion: getting small bits out of Obsidian into his dashboard.
  • The entire thing as it is now is a tool that clearly and visibly had an evolutionary path, as opposed to a planned-for structure and design. This appeals to me a lot. It is the same with my own personal tools and system of notes. Others sometimes remark on how it would impossible for them to create something like it for themselves. Thing is, neither could I. The current state evolved over time, and does not lend itself to reconstruction. That this sense of evolution stands out to me after a few months of Martijn spending that 500 hours in total on his Theta OS too, to me is a strong argument in favor of his approach.
  • This is reinforced by how he clearly builds intensively on his own structures and habits. As I often remark too, I am predictable to myself, and it means any software tool you build for yourself can make choices based on that predictability. If I want to save something I know which attributes I care about, and in which form I want to have them available. If I make a shopping list I know the order of the supermarket shelves of the store I’ll visit. If I’m near a Dutch railway station in the evening, it is most likely I intend to take a train home, that type of thing. The same is true for my information strategies. I know where I store my book notes and how, as I’ve been doing it for ages etc.
  • Building on that predictability he makes functionalities in Theta highly contextual. If he bookmarks a LinkedIn profile, it means he wants a person note with a few distinct fields from the profile (e.g. current role and location), and bookmarking then means the creation of such a person note in the same way as all his existing person notes already are. If it’s a recipe it pulls out the recipe, converts cooking terms and measures to Dutch terms and measures, and makes the ingredients available to dump into a shopping list.
  • Similarly everywhere he has a ‘copy to clipboard’-button in his Theta, it has a contextually determined template, so he can paste it into something else in the way he needs it at the destination. I use those templates in different places already, the way I send a bookmark to my blog, my annotation tool, and how an annotation is imported into my Obsidian notes, how I save a webpage in markdown to my notes, are all determined by a template that takes the same basic information but styles and orders it differently based on purpose and destination.
  • That contextualisation sometimes needs persistent data from outside. He incorporates such data into his local database. E.g. all the place names for the Netherlands, so he can recognise a place name in his own material, or search with any of them across his material. Or the list of translated cooking terms mentioned above.
  • He created his own e-mail client interface (using IMAP to access his mail accounts). This allows him to create processing geared to his own routines. E.g. a button to process an e-mail as a hotel reservation, or as parcel delivery announcement, or to pull location or event data from etc. That information then surfaces in his dashboard where it is made useful. It resulted in a rather long row of specific processing contexts but I can definitely see the power of it. Like I tinker with my ‘ideal feedreader’, doing the same for an ‘ideal e-mail interface’ where the point is to not let things reside in e-mail but make it findable and useful outside of it makes a lot of sense. And again, because you are predictable to yourself it is obvious what ‘outside’ means in each instance.
  • He created ‘companion apps’ (using Mac’s Xcode to make them for iOS, I wonder if something similar for Android exists) for his phone, allowing him to access and work with information on the go.

On the train home, I started exploring both sqlite and node.js in more detail, to figure out if and how I may want to add it to my local personal tool set.
Can I use this to reignite my work on my personal toolsuite? That work is more aimed at facilitating myself in my processes and helping me achieve outputs.
Despite going to bed late, I woke unexpectedly early, given the holidays and weekend, and felt the need to explore more. So the session definitely kicked something in gear. It does need my personal approach of course, and I have plenty of relevant notes on this from the past years to use for it. Years ago, back in 2017, I already gave the effort a name too, Aazai.
I set up sqlite and node.js this morning to have a sandbox to try some building blocks out.