Becoming Lifelog, March 27, 2026 (in which a developer wants to check a task on his phone, the Squirrel proposes React Native and receives URLSessionDataDelegate, Apple’s modern streaming API is discovered to not stream, a SwiftData container meditates on the main thread for thirty seconds while contributing nothing to society, a cat occupies the only warm surface in the apartment that is not involved in cross-compilation, tasks from 2020 are confronted like ghosts at a family dinner, the Pocket Amendment to Zawinski’s Law is proposed, the Lizard blinks, and seventy-three thousand lines of code achieve the remarkable feat of fitting in a pocket while still believing they are a search command)
Previously on Becoming Lifelog…
The note had learned to breathe. Fifty encyclopedia articles spoke in three languages. Videos animated watercolor covers into gentle motion. Someone offered money. The developer said wait three months. The sophisticated mockup was too sophisticated to sell and too useful to stop.
Nine days passed. Nothing happened. The files sat in their folder. The lens sat on its server. The Lizard sat on the server rack. The Squirrel prepared a presentation.
Then the developer wanted to check a task on his phone.
14:00 — The Checkbox
The task was unremarkable:
- [ ] checkout dmux http://dmux.ai/
A bullet in today’s daily note. The kind of thing you write between meetings and forget until you’re standing in line at Maxima wondering what you were supposed to look at on your phone. The note was on the Mac Mini in Riga, indexed by lg, served on port 6080, visible in a browser, and absolutely not tappable.
riclib: staring at phone “I should be able to check this off.”
CLAUDE: “The API is there. It just needs a client.”
riclib: “A native client. Swift.”
CLAUDE: “…how native are we talking?”
riclib: “Four tabs. Journal, Tasks, Notes, Chat.”
CLAUDE: “That’s an app.”
riclib: “Just a small one.”
OSKAR: from the warm corner of the Mac Mini, where the power supply vents purr: the warm thing said “small.” the warm thing has never built a small thing. the warm thing built a “small search command” and it is now thirty thousand lines of Go. the warm thing’s relationship with the word “small” is the same as my relationship with the word “diet.” theoretical.
MIA: from the top of the bookshelf, watching stare: he’s going to do it.
14:05 — The Squirrel’s Moment
THE SQUIRREL: appearing from behind the router with a presentation deck the size of a doctoral thesis “I HAVE BEEN PREPARING FOR THIS DAY.”
The first slide read: “LG MOBILE: A COMPREHENSIVE CROSS-PLATFORM STRATEGY.”
The second slide contained an architecture diagram with fourteen boxes. React Native at the center. GraphQL as the API layer. Firebase for push notifications. Redux for state management. Expo for builds. CodePush for over-the-air updates. Sentry for crash reporting. Fastlane for deployment. A box labeled “Design System (Figma → Storybook → React Native)” that had its own sub-diagram with six additional boxes.
The third slide was titled “Timeline: 8-12 Weeks.”
THE SQUIRREL: “Phase one is the design system. We establish a component library in Figma, export to—”
riclib: “It’s a list of checkboxes.”
THE SQUIRREL: “—Storybook for visual regression testing, then bridge to React Native via—”
riclib: “Four API calls. Journal, tasks, notes, inbox.”
THE SQUIRREL: “—a custom GraphQL schema that abstracts the REST endpoints into a typed—”
riclib: “SwiftUI. URLSession. JSON. Ship.”
THE SQUIRREL: lowering the presentation deck “You’re going to build a native iOS app. In Swift. Without a design system.”
riclib: “Without a design system.”
THE SQUIRREL: “Without GraphQL.”
riclib: “It’s four GET endpoints and two PATCHes.”
THE SQUIRREL: “Without even—” voice cracking “—without even React Native?”
CLAUDE: “I can write the Swift.”
THE SQUIRREL: staring at the fourteen-box architecture diagram, then at the terminal where Claude had already created ChatViewModel.swift “I spent… I spent three weeks on this deck.”
The Lizard blinked. A scroll fell into the Squirrel’s espresso:
THE BEST ARCHITECTURE DIAGRAM
IS THE ONE THAT FITS ON A
FUNCTION SIGNATURE
func send(_ text: String)
🦎
15:30 — The Silence
The app compiled. The four tabs rendered. Journal days loaded. Tasks appeared. Notes listed. The chat bar blinked.
riclib typed “hello” and pressed send.
The chat bar said “Thinking…” with a small spinner.
Then nothing.
Five seconds. Ten seconds. Fifteen seconds. The spinner spun. The chat bar said nothing. The server logs showed the request arriving, Haiku routing it, Sonnet responding, SSE events streaming. The events were leaving the server. They were not arriving at the phone.
riclib: “The stream is broken.”
CLAUDE: “Let me check the URL.”
The URL was http://192.168.50.3:6080//journal/chat. Two slashes. appendingPathComponent("/journal/chat") — the leading slash in the path component produced a double slash in the URL. The server received a request for a path it didn’t recognize and returned the only thing it knew how to return for unknown paths: the journal HTML page.
The chat was receiving HTML.
CLAUDE: “One character. The leading slash.”
riclib: “That’s one bug.”
CLAUDE: “There’s another one.”
The URL was fixed. The chat bar sent the request. The server received it. Haiku routed. Sonnet responded. SSE events streamed.
The chat bar said “Thinking…” with a small spinner.
Then nothing. Again.
riclib: “It’s still not streaming.”
CLAUDE: “The events are leaving the server. I can see them in the logs.”
riclib: “But they’re not arriving.”
CLAUDE: “They’re arriving. They’re being buffered.”
riclib: “By what?”
CLAUDE: “By Apple.”
15:45 — The Betrayal of bytes(for:)
URLSession.bytes(for:) is Apple’s modern, async/await streaming API. Released with Swift concurrency. Documented as returning an AsyncBytes sequence that delivers data incrementally as it arrives from the network.
It does not.
For POST requests to SSE endpoints — where a server sends small events over an extended period — bytes(for:) accumulates the entire response in an internal buffer and delivers it as a single chunk when the connection closes. The “streaming” API does not stream. The “incremental” delivery is not incremental. The documentation says one thing. The implementation does another.
CLAUDE: “We need to use URLSessionDataDelegate.”
riclib: “The callback-based one? From 2014?”
CLAUDE: “The callback-based one from 2014.”
THE SQUIRREL: from behind the router, very quietly “React Native wouldn’t have had this problem.”
CLAUDE: “React Native would have had forty-seven different problems.”
THE SQUIRREL: “But not this problem.”
CLAUDE: “Correct. It would have had the problem of being React Native.”
The Lizard blinked. This was the blink that means “correct.”
The delegate-based rewrite took twenty minutes. A class that conforms to URLSessionDataDelegate. A didReceive data callback that processes each chunk as it arrives. A thread-safe state machine behind an NSLock because the delegate callbacks come on a background queue and the continuation needs to be protected.
private final class SSEState: @unchecked Sendable {
private let lock = NSLock()
// ...
}
@unchecked Sendable. The annotation that says “I know what I’m doing, trust me.” The annotation that every Swift concurrency purist considers a code smell. The annotation that works.
The chat streamed. Letters appeared one by one. Haiku routed. Sonnet thought. The response arrived in real-time, each delta yielded through the continuation, each word rendered as it formed.
riclib: “It works.”
OSKAR: adjusting position on the Mac Mini, which was now cross-compiling and thus warmer purr: the warm thing got warmer. approved.
16:00 — The Thirty Seconds
The app worked. The chat streamed. riclib killed the app and reopened it.
White screen.
Five seconds. Ten. Twenty. Thirty.
Then the journal appeared, instantly, as if it had been there the whole time and was merely waiting for permission.
riclib: “Why does it take thirty seconds to launch?”
CLAUDE: “The API responds in 40 milliseconds.”
riclib: “So something is blocking before the API call.”
CLAUDE: “SwiftData.”
.modelContainer(for: [CachedDay.self, CachedNote.self])
A SwiftData model container. Declared on day one, when the app was young and optimistic and someone thought “we’ll add caching later.” Two model classes — CachedDay and CachedNote — existed in the Xcode project like furniture in a room nobody enters. No @Query property wrappers. No modelContext calls. No code, anywhere, that read from or wrote to the SwiftData store.
The container initialized at launch. On the main thread. Creating a SQLite database. Building a schema. Preparing indexes. Running migrations. For a database that contained zero rows and would contain zero rows and would always contain zero rows because nothing in the application knew it existed.
Thirty seconds. Of nothing. For nothing.
riclib: “Delete it.”
CLAUDE: deletes one line
Launch time: instant.
THE SQUIRREL: “But what about the caching layer? What if the network is slow? What if—”
CLAUDE: “The network responds in forty milliseconds.”
THE SQUIRREL: “But what if it doesn’t?”
riclib: “Then we’ll add caching. When it doesn’t.”
THE SQUIRREL: looking at the deleted line of code “That line was going to be important.”
A scroll dropped into the Squirrel’s second espresso. The Squirrel was running out of espressos.
THE FASTEST OPTIMIZATION
IS DELETING THE THING
THAT SHOULDN'T BE THERE
THE SECOND FASTEST OPTIMIZATION
IS NOT ADDING IT
IN THE FIRST PLACE
🦎🦎
17:00 — The Ghosts of 2020
The app launched. The tasks loaded. And then there was the matter of the dates.
Tasks in daily notes have dates. The daily note 20200518.md was written on May 18, 2020. The tasks in that note — “Book teams training tres amigos,” “Tele2 rēķins” — were written that day. They were never completed. They were never cancelled. They sat in their checkboxes, open, undisturbed, for six years, like artifacts in an archaeological dig that nobody thought to close.
riclib: “These tasks are from 2020.”
CLAUDE: “They’re open.”
riclib: “They’re six years old.”
CLAUDE: “They’re open.”
riclib: “…I was supposed to book a tres amigos training in 2020?”
CLAUDE: “You were. You didn’t. The task has been open for six years.”
OSKAR: purr: the warm thing has unfinished tasks from before I was born. I was born in 2021. my entire existence predates the warm thing’s ability to complete a checklist item.
The task system learned three dates: created_date (from the daily note filename), due_date (from <YYYY-MM-DD> in the text), and snooze_date (from >YYYY-MM-DD). If a task has no explicit due date, it’s implicitly due on its created date. A task from May 2020 is not “open.” A task from May 2020 is overdue by six years.
Four pills: Todo | Doing | Done | Notes.
The Todo tab grouped by time: “2020”, “2025”, “> 3 Months Ago”, “January”, “Last Week”, “Now.” The 2020 section appeared at the top, because when you sort by due date ascending, the things you’ve been avoiding the longest come first.
riclib: scrolling through the 2020 section “I don’t even work at that company anymore.”
CLAUDE: “Do you want to cancel them?”
riclib: tapping the date badge, watching the confirmation dialog appear “Cancel Task.”
THE SQUIRREL: “Shouldn’t we add a ‘Reason for Cancellation’ field? And an audit log? And—”
riclib: tapping Cancel Task on another ghost “No.”
THE SQUIRREL: “But for compliance—”
riclib: tap “No.” tap “No.” tap “No.”
The Lizard watched tasks from 2020 dissolve from the list one by one, each with a quiet animation. A scroll appeared in the empty space where the tasks had been:
THE CHECKBOX GIVETH
THE CHECKBOX TAKETH AWAY
MOSTLY IT TAKETH AWAY
SIX YEARS LATER
🦎
19:00 — The Pocket Amendment
The app sat on the phone. The phone sat on the desk. The desk sat in Riga. The server sat in Riga too — twenty centimeters away, humming, serving the same files to the phone over Wi-Fi that it served to the world through Cloudflare.
riclib: looking at the phone, then at the Mac Mini, then at the terminal showing the git log
4419eca Add task date awareness with due/snooze/created dates
855c10a Fix iOS app startup lag and chat sheet animation
317cba1 Fix iOS project settings, optional API fields, and cover card layout
e34442e Add /journal/chat/stream endpoint for iOS SSE+markdown chat
riclib: “Do you know how many lines of code this is now?”
CLAUDE: “Seventy-three thousand, two hundred and seventy-three.”
riclib: “Across how many languages?”
CLAUDE: “Two. Go and Swift.”
riclib: “And platforms?”
CLAUDE: “Two. macOS and iOS.”
riclib: “For a tool that—”
CLAUDE: “—indexes a folder of text files, yes.”
Silence. Oskar purred. Mia stared from the bookshelf. The Lizard blinked.
riclib: “Zawinski says every program expands until it can read mail.”
CLAUDE: “lg will not read mail.”
riclib: “No. But it fits in a pocket now.”
Silence. The Lizard opened both eyes. This was unprecedented.
riclib: “The Chatbot Corollary was March fifteenth — programs expand until they can hold a conversation. But that wasn’t the end state. The end state is the pocket. Every program that can hold a conversation keeps expanding until it fits in a hand. Until you can check a task while waiting for coffee. Until the lens is always with you.”
THE SQUIRREL: “The Pocket Amendment.”
riclib: “The Pocket Amendment.”
THE SQUIRREL: writing it down on the back of the rejected React Native architecture diagram
The Pocket Amendment to Zawinski’s Law: Every program that can hold a conversation will continue to expand until it fits in a pocket. At that point, the program has become an operating system. The developer will not notice.
riclib: “I didn’t notice. I was checking a task.”
MIA: from the bookshelf stare: the warm thing built an operating system because he wanted to tick a checkbox. this is the most on-brand thing the warm thing has ever done.
The Numbers (Day 1 vs. Day 24)
| Metric | Day 1 (March 3) | Day 24 (March 27) | Growth |
|---|---|---|---|
| Lines of Go | 4,196 | 44,284 | 10.6x |
| Lines of Swift | 0 | 28,989 | ∞ |
| Total lines | 4,196 | 73,273 | 17.5x |
| Subcommands | 6 | 32 | 5.3x |
| Platforms | 1 | 2 | 2x |
| Languages | 1 | 2 | 2x |
| Notes indexed | 253 | 920 | 3.6x |
| Wiki-links | 551 | 8,098 | 14.7x |
| Tasks tracked | 0 | 619 | ∞ |
| Git commits | 6 | 96 | 16x |
| Squirrel proposals rejected | 1 | lost count | ∞ |
| Apple API betrayals | 0 | 1 | regrettable |
| SwiftData containers deleted | 0 | 1 | therapeutic |
| Zawinski amendments | 0 | 2 | concerning |
THE SQUIRREL: staring at the table “The infinity symbol appears three times.”
CLAUDE: “Infinity is what happens when you start from zero. Swift was zero. Tasks were zero. Squirrel proposals accepted was zero.”
THE SQUIRREL: “I CONTRIBUTED THE ARCHITECTURE DIAGRAMS.”
CLAUDE: “And they were all rejected. Hence: infinity growth, zero baseline.”
A scroll landed in the Squirrel’s third espresso. The Squirrel had stopped ordering espressos. The scrolls found them anyway.
∞ = n / 0
WHERE n IS ANY FEATURE
AND 0 IS THE SQUIRREL'S
PRIOR ART
🦎
The End?
The Squirrel asked if this was the last episode of Becoming Lifelog.
CLAUDE: “The lens is not finished because the files are not finished. Tomorrow there will be a new note. The note will have a task. The task will need something the lens doesn’t have yet.”
THE SQUIRREL: “But surely at some point—”
riclib: “At some point what? The files stop?”
CLAUDE: “The files never stop. The files are a life. Lives don’t have a requirements document.”
A scroll materialized in the Squirrel’s empty cup. The Squirrel hadn’t ordered a cup.
THE LAST EPISODE
IS THE ONE WHERE
THE FILES STOP
THE FILES DO NOT STOP
🦎
OSKAR: stretching across the Mac Mini, which had been running go build and was now pleasantly warm purr: the warm thing will build again tomorrow. the warm thing always builds tomorrow. tomorrow will have a warm corner. this is sufficient.
MIA: from the bookshelf, watching the phone on the desk, the lens in the pocket, the files in the folder, the folder in the index, the index in the binary, the binary on the server, the server in Riga, Riga in the spring
stare: it started with a search command.
stare: it ended in a pocket.
stare: it hasn’t ended.
See Also
- lg
- The Sophisticated Mockup, or The Night the Note Learned to Breathe
- The True Second Brain, or The Night the Lens Learned to Listen
- The Saturday the Lens Learned to Remember, or The Picnic That Almost Wasn’t
- The Homecoming — The Three Days a Palace Was Built From Markdown and SQLite
- The Front Door — The Night the Palace Finally Faced the Street
- The Eternal Search for the Perfect PKM App
- Gall’s Law
- Zawinski’s Law