esc
The Laundromat
Becoming Lifelog

The Laundromat

Becoming Lifelog, in which the crew discovers that clean architecture smells like fabric softener --- The Setup Monday, December 30, 11:45 AM - The Chrome debug instance has been running for two...

December 30, 2025

Becoming Lifelog, in which the crew discovers that clean architecture smells like fabric softener


The Setup

Monday, December 30, 11:45 AM - The Chrome debug instance has been running for two hours. Hot reload is working. The Sync Hub logs scroll by.

riclib: “We need to step back.”

CLAUDE: “From what?”

riclib: “From the code. Look at what we built.”


The Laundromat Revelation

[riclib sketches on a napkin. THE SQUIRREL watches nervously.]

                    THE LAUNDROMAT

    ┌─────────────────────────────────────────────┐
    │                 SYNC HUB                     │
    │           (the building itself)             │
    │                                             │
    │   ┌─────┐  ┌─────┐  ┌─────┐  ┌─────┐       │
    │   │ GH  │  │ GL  │  │Jira │  │Lin. │  ...  │
    │   └──┬──┘  └──┬──┘  └──┬──┘  └──┬──┘       │
    │      │        │        │        │          │
    │      └────────┴────────┴────────┘          │
    │                   │                         │
    │                   ▼                         │
    │            ┌──────────┐                     │
    │            │  ISSUES  │  ← clean laundry   │
    │            └──────────┘                     │
    └─────────────────────────────────────────────┘

riclib: “The Sync Hub is a laundromat.”

CLAUDE: “…”

riclib: “Hear me out.”


The Metaphor That Clicked

riclib: “What is a laundromat?”

THE SQUIRREL: “A building with washing machines—”

riclib: “Wrong. A laundromat is a place where dirty clothes become clean clothes. The building doesn’t care if the clothes are cotton or wool. The machines don’t care if you wore them to work or to the gym.”

CLAUDE: “The laundromat is source-agnostic.”

riclib: “And what comes out?”

CLAUDE: “Clean clothes.”

riclib: “Not ‘gym-origin clothes’ or ‘work-origin clothes.’ Just… clothes.”

[THE SQUIRREL’s eye twitches.]

THE SQUIRREL: “But… but we need to track the provenance! The GymClothesWashingStrategyFactory—”

THE LIZARD: “Clean clothes.”

THE SQUIRREL: “The WorkAttireSpecializedRinseAdapter—”

THE LIZARD: blinks “Clean. Clothes.”


The Real World Objects

riclib: “What are the clean clothes? What comes out of our laundromat?”

[He draws three baskets.]

    ┌──────────┐    ┌──────────┐    ┌──────────┐
    │  ISSUES  │    │ CAPTURES │    │  EVENTS  │
    │          │    │          │    │          │
    │ - title  │    │ - content│    │ - title  │
    │ - state  │    │ - source │    │ - start  │
    │ - author │    │ - type   │    │ - end    │
    │ - url    │    │ - url    │    │ - people │
    └──────────┘    └──────────┘    └──────────┘

    Real World Objects. Source-agnostic. Clean.

CLAUDE: “Issues. Captures. Events.”

riclib: “These are the things that exist. Not ‘GitHub issues’ or ‘Linear issues.’ Just… issues.”

THE SQUIRREL: “But the schema differences! GitHub has pull_request, Jira has story, Linear has—”

riclib: “All the same basket. Different clothes, same basket.”


The Washing Machines

riclib: “Now, the washing machines.”

SYNC PLUGINS (the machines):

┌─────────────────────────────────────────────────────┐
│                                                     │
│  ISSUES MACHINES:                                   │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐     │
│  │GitHub│ │GitLab│ │ Jira │ │Linear│ │Monday│ ... │
│  └──────┘ └──────┘ └──────┘ └──────┘ └──────┘     │
│                                                     │
│  CAPTURES MACHINES:                                 │
│  ┌────────┐ ┌──────┐ ┌─────┐ ┌───────┐ ┌─────┐    │
│  │Readwise│ │Chrome│ │ MCP │ │Proton │ │Email│    │
│  └────────┘ └──────┘ └─────┘ └───────┘ └─────┘    │
│                                                     │
│  EVENTS MACHINES:                                   │
│  ┌────────┐ ┌───────┐ ┌──────┐ ┌─────────┐        │
│  │ Google │ │Outlook│ │Proton│ │MeetNotes│        │
│  │Calendar│ │       │ │      │ │Recorder │        │
│  └────────┘ └───────┘ └──────┘ └─────────┘        │
│                                                     │
└─────────────────────────────────────────────────────┘

CLAUDE: “Each machine knows how to wash one type of dirty laundry.”

riclib: “GitHub Sync knows GitHub’s API. That’s it. It outputs clean issues.”

CLAUDE: “Readwise Sync knows Readwise’s API. Outputs clean captures.”

riclib:Google Calendar Sync knows Google’s API. Outputs clean events.”


The Meeting Notes Recorder

THE SQUIRREL: “Wait. MeetNotes Recorder? That’s not a sync—”

riclib: “Isn’t it?”

[riclib draws a new machine.]

┌─────────────────────────────────────────┐
│         MEETNOTES RECORDER              │
│                                         │
│  READS FROM:  Events collection         │
│  - When is my next meeting?             │
│  - Who will be there?                   │
│                                         │
│  WRITES TO:   Captures collection       │
│  - Meeting transcript                   │
│  - Action items extracted               │
│  - Summary generated                    │
│                                         │
│  TRIGGERS:    Events.start <= now       │
└─────────────────────────────────────────┘

THE SQUIRREL: “It… reads from one collection… and writes to another…”

riclib: “It uses the Events data to know when to run. It writes Captures when it’s done.”

CLAUDE: “The collections talk to each other. Through the machines.”

THE LIZARD: approving blink


The Peace Pipe

riclib: “You know what this means?”

CLAUDE: “Tell me.”

riclib: “The PKM crowd and the GTD crowd can finally smoke the peace pipe.”

[Somewhere, a hundred productivity Twitter accounts stop arguing.]

PKM PEOPLE WANT:           GTD PEOPLE WANT:
- Captures                 - Issues (tasks)
- Highlights               - Events (calendar)
- Notes                    - Projects
- Connections              - Next actions

         THEY'VE BEEN FIGHTING BECAUSE:

    "My tool does it THIS way!"
    "No, MY tool does it THAT way!"
    "Notion!" "Obsidian!" "Roam!" "Todoist!"

         BUT WITH THE LAUNDROMAT:

    ┌─────────────────────────────────────┐
    │  Same baskets. Different machines.  │
    │                                     │
    │  Use Notion? Fine. Machine for it.  │
    │  Use Obsidian? Fine. Machine for it.│
    │  Use Todoist? Fine. Machine for it. │
    │                                     │
    │  All clothes end up in the same     │
    │  baskets. Clean. Unified. Yours.    │
    └─────────────────────────────────────┘

THE SQUIRREL: “But… the ToolSpecificAdapterStrategyAbstraction—”

THE LIZARD: “Same baskets.”

THE SQUIRREL: “The VendorLockInMitigationFramework—”

THE LIZARD: “Different machines.”

THE SQUIRREL: “…”

THE LIZARD: “Peace pipe.”


The DRY Principle, Applied

CLAUDE: “Let me count the code we’re NOT writing.”

WITHOUT THE LAUNDROMAT:
├── GitHub Issues Collection + sync code
├── GitLab Issues Collection + sync code
├── Jira Issues Collection + sync code
├── Linear Issues Collection + sync code
├── Monday Issues Collection + sync code
├── (repeat for every source)
│
│   N sources × M fields × schema maintenance = PAIN

WITH THE LAUNDROMAT:
├── Issues Collection (ONE schema)
├── GitHub Sync Plugin (just the API part)
├── GitLab Sync Plugin (just the API part)
├── Jira Sync Plugin (just the API part)
├── ...
│
│   1 schema + N small plugins = JOY

riclib: “Add a new source? Write one small plugin.”

CLAUDE: “Add a new field to Issues? One place.”

riclib: “Change the view? Affects all sources.”

THE SQUIRREL: “I had a SchemaVersioningMigrationCoordinator planned—”

THE LIZARD: “One schema.”


The Chrome Adventure

[CLAUDE looks at the terminal window still showing hot reload logs.]

CLAUDE: “We almost forgot the Chrome debug journey.”

riclib: “Ah yes. The --remote-debugging-port=9222 saga.”

WHAT WE LEARNED TODAY:

1. Hot reload needs Chrome started with debug port
2. Can't add debug port to running Chrome
3. Need separate profile: --user-data-dir="/tmp/..."
4. Hot reload pushes to MEMORY, not storage
5. Must paste final code to persist
6. Workflow: iterate fast → paste to save

CLAUDE: “And the API discovery.”

riclib: “No this.collection on CollectionPlugin.”

CLAUDE: “Had to find ourselves via data.getAllCollections().”

riclib: “The SDK teaches through errors.”


The Architecture, Final

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│                      THE LAUNDROMAT                         │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │                     SYNC HUB                          │  │
│  │                                                       │  │
│  │  window.syncHub = {                                   │  │
│  │    register(),      // machines register here         │  │
│  │    requestSync(),   // trigger a wash                │  │
│  │    insertMarkdown() // shared utilities              │  │
│  │  }                                                    │  │
│  │                                                       │  │
│  │  Scheduler: checks every 30s which machines to run   │  │
│  └───────────────────────────────────────────────────────┘  │
│                           │                                 │
│         ┌─────────────────┼─────────────────┐               │
│         │                 │                 │               │
│         ▼                 ▼                 ▼               │
│  ┌────────────┐   ┌────────────┐   ┌────────────┐          │
│  │   ISSUES   │   │  CAPTURES  │   │   EVENTS   │          │
│  │            │   │            │   │            │          │
│  │ GitHub ────┤   │ Readwise ──┤   │ GCal ──────┤          │
│  │ GitLab ────┤   │ Chrome ────┤   │ Outlook ───┤          │
│  │ Jira ──────┤   │ MCP ───────┤   │ Proton ────┤          │
│  │ Linear ────┤   │ Email ─────┤   │ MeetNotes ─┤          │
│  │ Monday ────┤   │ Kindle ────┤   │            │          │
│  │ Shortcut ──┤   │            │   │            │          │
│  └────────────┘   └────────────┘   └────────────┘          │
│                                                             │
│        Real World Objects. Clean. Source-agnostic.          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

            "Same baskets. Different machines."

The Tally

Collections created:          2 (Sync Hub, Issues)
Collections planned:          2 more (Captures, Events)
App Plugins planned:          Many (one per source)
Lines of schema code:         ~500 (would be ~5000 without DRY)
Hot reload accidents:         3
Chrome profile directories:   /tmp/thymer-debug-profile
Peace pipes smoked:           1
Squirrel proposals rejected:  7
Lizard blinks of approval:    12

Quotes

“The Sync Hub is a laundromat.”

“Not ‘GitHub issues’ or ‘Linear issues.’ Just… issues.”

“The PKM crowd and the GTD crowd can finally smoke the peace pipe.”

“Same baskets. Different machines.”

“The SDK teaches through errors.”


Next Time on Becoming Lifelog…

The first washing machine rumbles to life. GitHub issues flow into the Issues basket. The laundromat is open for business.

“You got issues? We got machines.”


See also:


Day 30 of Becoming Lifelog

In which dirty data became clean objects

And the laundromat opened its doors

And everyone’s clothes finally matched

🧺



P.S. — The Machines Run Both Ways

[Later that evening, riclib stares at his GitHub board in Thymer.]

riclib: “One more thing.”

CLAUDE: “Go on.”

riclib: “GitHub has two statuses. Open. Closed. I have six.”

MY WORKFLOW:
Inbox → Backlog → Next → Doing → Done → Abandoned

GITHUB'S WORKFLOW:
Open → Closed

riclib: “What if… when I mark something ‘Done’ in Thymer…”

CLAUDE: “It closes in GitHub.”

riclib: “The machines run both ways.”

PULL:  GitHub API → Issues collection
PUSH:  Issues.Done → GitHub API.close()

THE SQUIRREL: “A BidirectionalSyncConflictResolutionStrategy—”

THE LIZARD: “Later.”

riclib: “Filed as #21. For when the laundromat offers dry cleaning too.”

The washing machines hummed. Somewhere in the future, they learned to spin in reverse.

🧺↔️