esc
Ten Years of Marginalia
Becoming Lifelog

Ten Years of Marginalia

Becoming Lifelog, in which a decade of highlights finds a home --- Previously on Becoming Lifelog... The browser had learned to listen. SSE streams flowed. GitHub issues migrated. The architecture...

December 26, 2025

Becoming Lifelog, in which a decade of highlights finds a home


Previously on Becoming Lifelog…

The browser had learned to listen. SSE streams flowed. GitHub issues migrated. The architecture was proven. And then someone mentioned Readwise.


The Setup

22:00 - The developer stares at the Readwise API docs.

riclib: “I have ten years of highlights in here.”

CLAUDE: “How many?”

riclib: “I don’t want to know.”

[A tail begins to twitch somewhere in the shadows]


The Squirrel Materializes

THE SQUIRREL: already mid-sentence “—we sync EVERYTHING! Every document! Every reading state! Every podcast timestamp! Build a complete mirror! Think of the QUERIES—”

riclib: “I just want my highlights.”

THE SQUIRREL: “YES! And to get the highlights we need the documents! And to contextualize the documents we need the reading progress! And for reading progress we need—”

CLAUDE: “What do you actually do with highlights?”

[The Squirrel freezes]

riclib: “I… highlight things I want to remember. And then I search for them when I need them.”

CLAUDE: “So you need: documents that have highlights. With the highlights in them.”

riclib: “Yes.”

CLAUDE: “Not documents without highlights.”

riclib: “Those are just… articles I saved and never read.”

THE SQUIRREL: “But the COMPLETENESS—”

THE LIZARD: blinks


The Design

22:15 - The whiteboard fills with what we don’t need:

Documents without highlights    → Skip
Reading progress               → Don't care  
Podcast timestamps             → Not highlights
Tags from Readwise             → We have our own
Full document content          → We have the source URL

What remains:

Documents WITH highlights      → Sync
The highlights themselves      → As blockquotes
User notes on highlights       → Preserve
LLM summaries                  → When available

THE SQUIRREL: “That’s… that’s leaving data on the table!”

THE LIZARD: “That’s not being an idiot.”


The Frequency Debate

22:30 - Implementation begins. The Squirrel circles.

THE SQUIRREL: “Poll every five minutes! What if you highlight something IMPORTANT? You need it IMMEDIATELY!”

CLAUDE: “When was the last time you highlighted something and immediately needed it in Thymer?”

THE SQUIRREL: “…”

CLAUDE: “…”

THE SQUIRREL: “…that’s not the POINT—”

riclib: “Readwise rate limits are strict. They’ll ban us.”

THE SQUIRREL: “Fine! Ten minutes!”

THE LIZARD: blinks twice

riclib: “Hourly. With a manual trigger for the impatient.”

THE SQUIRREL: “But—”

riclib: “That’s me. I’m the impatient. Hourly is fine.”


The Journal Question

23:00 - The first sync runs. Documents flow. Highlights land.

📚 Queued Readwise: Article about TypeScript (new, 4 highlights)
📚 Queued Readwise: Book about systems thinking (new, 12 highlights)
📚 Queued Readwise: Tweet thread about startups (new, 2 highlights)
📚 Queued Readwise: ...

And in the Journal:

23:01 highlighted **Article about TypeScript**
23:01 highlighted **Book about systems thinking**
23:01 highlighted **Tweet thread about startups**
23:01 highlighted **...**

riclib: “This is going to be noisy.”

CLAUDE: “Ten years of highlights. Every update logged.”

THE SQUIRREL: “Activity feeds! Notification badges! A timeline view with—”

riclib: “No. First highlight only. Updates are silent.”

CLAUDE: “The journal entry requires a verb. First sync: highlighted. Updates: no verb. No journal.”

THE LIZARD: approves with a slow blink

THE SQUIRREL: “But how will you KNOW when—”

riclib: “I was there. I highlighted it. I know.”


The Timezone Incident

23:30 - First sync completes. 147 documents. 892 highlights. Ten years of marginalia, landed.

23:45 - Second sync triggers.

⚠️ readwise API returned 400: {"errors": ["Field `updatedAfter` must be a valid ISO 8601 date time string"]}

CLAUDE: “Interesting.”

riclib: “What.”

CLAUDE: “The timestamp is 2024-12-26T23:45:00+01:00. Valid ISO 8601. Valid RFC3339. But the + in the URL…”

riclib: “Is being interpreted as a space.”

CLAUDE: “The server asked for documents updated after 2024-12-26T23:45:00 01:00.”

riclib: “Which is not a time.”

THE SQUIRREL: “We need a URL builder! A proper encoding layer! Abstract the—”

CLAUDE: url.QueryEscape()

THE SQUIRREL: “…what?”

CLAUDE: “One function. Wrap the timestamp. Done.”

[The Squirrel opens its mouth]

[The Lizard’s eye opens]

[The Squirrel closes its mouth]


The Sync Completes

00:15 - Ten years. All of it.

Documents synced:        147
Highlights captured:     892
Journal entries:         147 (first highlights only)
Subsequent updates:      Silent
Lines of code:           ~300
Dependencies added:      0 (bbolt already there)
API calls wasted:        1 (the timezone incident)
Squirrel proposals:      7
Squirrel proposals used: 0

riclib: scrolling through Thymer “There’s that article about passkeys. And the book about… oh, I forgot I read that.”

CLAUDE: “Ten years of ‘I should remember this.’ Now findable.”

THE SQUIRREL: “We could add semantic search! Embed the highlights! Build a—”

THE LIZARD: blinks

THE SQUIRREL: sighs, reaches for decaf


The Shape of a Highlight

Each record arrives like this:

## Summary
[LLM-generated summary, when Readwise provides one]

## Highlights

> The highlighted text, preserved exactly
> As blockquotes, because that's what they are
> Someone else's words that mattered to you

**Note:** Your annotation, if you left one

Not transformed. Not analyzed. Not fed into a knowledge graph.

Just… present. Searchable. Waiting for the day you need that one thing about passkeys, or that paragraph about attention, or what that author said about building in public.

THE SQUIRREL: “But the CONNECTIONS—”

THE LIZARD: “Will emerge. When they’re needed. Not before.”


The Moral

THE SQUIRREL: “So we built… a sync.”

CLAUDE: “We built a conduit. Readwise holds the highlights. Thymer makes them findable. The browser can’t listen, but the server polls hourly. The architecture we built for GitHub just… works.”

riclib: “Universal frontmatter interface. Write the adapter, get the sync.”

THE SQUIRREL: “But what about—”

THE LIZARD: “Next time.”


The Tally

Readwise documents:          Synced (with highlights only)
GitHub issues:               Synced  
Manual markdown:             Piped
Journal entries:             Timestamped
Browser limitations:         Worked around
Squirrel satisfaction:       Pending
Lizard approval:             ✅
Time:                        One evening

Tomorrow, a new highlight will appear in Readwise. An hour later, it’ll land in Thymer. Silent as a bookmark. Patient as marginalia has always been.

Ten years of “this is important.” Finally, somewhere it can be found.


🦎


Day 27 of Becoming Lifelog

In which a decade of highlights found a home

And the Squirrel learned that sync ≠ mirror

And we discovered that patience is a feature


See also:

The Saga (in which outside data flows in):

The References (highlight wisdom):

  • Readwise Reader - Where the highlights live
  • RFC 3339 - The timestamp format that needed escaping
  • bbolt - The sync state database (one file, no dependencies)