lg is a filesystem-first notes indexer that was built in one day and has been discovering what it actually is ever since. It started as a search tool for Markdown files. It is now a publishing platform that serves a blog, a wiki, a cover art generator, a content sync engine, and this encyclopedia entry about itself — all from a single Go binary that still thinks it’s a notes indexer.
This is Gall’s Law in its purest form: a complex system that works, found to have evolved from a simple system that worked. The simple system was six commits on a Monday. The complex system is 13,825 lines of Go, 23 subcommands, and the infrastructure behind The Lifelog and Yagnipedia. At no point did anyone design the complex system. At no point did anyone need to.
“THE PALACE WAS NEVER NEEDED
THE FILES NEEDED GLASSES”
— The Lizard, The Homecoming, or The Three Days a Palace Was Built From Markdown and SQLite
The Homecoming
lg was born on March 3, 2026, in a single day that collapsed a two-milestone project plan into six commits:
cfaacfe Initial implementation: filesystem-first notes indexer
175a8a5 S-412 batch 1: fuzzy match, stable IDs, JSON output
b032a80 S-412 batches 2+3: fields, query, tasks, refs
7c0469d S-413/S-414: config system and cover art generation
19fecac Fix cover default resolution: "standard" -> "1k"
8d524ca Display cover images side by side, default count to 3
4,196 lines of Go. Thirty-three tests. A CLI that could search, query frontmatter, find backlinks, list tasks, generate covers, and display images inline in the terminal via the Kitty graphics protocol. The Squirrel had proposed Elasticsearch. The Squirrel was not given Elasticsearch. The Squirrel was given SQLite with FTS5, which indexes 253 notes in under 200 milliseconds, which is faster than the Squirrel can finish proposing the alternative.
“You’re telling me that eighty-three stories, three hundred links, seventy-nine covers, and the entire ‘borrowed palace’ narrative… was just because we didn’t have a search index on a folder of text files?”
“Yes.”
— The Caffeinated Squirrel and riclib, The Homecoming, or The Three Days a Palace Was Built From Markdown and SQLite
The Architecture
lg’s architecture is one sentence:
Markdown files are the source of truth. SQLite is a queryable projection.
~/Notes/*.md → fsnotify watcher → parser → SQLite (FTS5) → CLI / HTTP
The files live in ~/Notes/, synced through NotePlan via CloudKit. lg watches the directory with fsnotify, parses each Markdown file (frontmatter, wiki-links, tasks, headings), and stores the parsed data in SQLite at ~/.local/share/lg/index.db. The database is a lens — a queryable view of what the files already contain. Delete the database. Run lg index. It rebuilds in 200 milliseconds. The files are the truth. The database is disposable.
This inversion — files over databases, projection over persistence — is lg’s defining characteristic. Every other notes tool makes the database the source of truth and exports files as a convenience. lg makes the files the source of truth and treats the database as a convenience. The files existed before lg. The files will exist after lg. lg is the glasses, not the eyes.
The Evolution
lg was built as a notes indexer. It did not stay a notes indexer. Each new capability was discovered, not designed:
| Date | Capability | Trigger |
|---|---|---|
| March 3 | Notes indexer, search, backlinks | The Homecoming |
| March 3 | Cover art generation | “The covers need automation” |
| March 5 | Blog server (templ, HTMX) | The Front Door |
| March 5 | Wiki server (Yagnipedia) | The Silmarillion Problem |
| March 6 | RSS feeds | “Blogs need RSS” |
| March 7 | Content sync to remote | Deploy to Hetzner |
| March 8 | Gemini cover engine | The Labyrinth |
| March 9 | Note renaming with reference updates | “rename should update wiki-links” |
Each row is a subcommand. Each subcommand was added because the previous capability revealed the next need. The notes indexer needed covers. The covers needed a blog. The blog needed a wiki. The wiki needed content sync. The content sync needed a remote server. At no point did anyone write a requirements document. At no point did the requirements document need to exist.
This is the Gall’s Law progression: simple system → works → reveals next need → simple addition → works → reveals next need. The complex system was never designed. The complex system emerged from a simple system that kept working.
The Subcommands
lg has 23 subcommands. For a “notes indexer”:
lg search Full-text search (FTS5)
lg backlinks Notes linking to this note
lg links Outgoing wiki-links
lg query Filter by frontmatter (key=value)
lg frontmatter Frontmatter as JSON
lg fields Frontmatter field discovery
lg refs Notes mentioning a ticket/string
lg tasks Task list
lg recent Recently modified notes
lg show Note details
lg stats Index statistics
lg cover Generate cover art (Gemini/Grok)
lg cover-upload Upload covers to remote
lg rename Rename note + update all references
lg index Trigger full re-scan
lg serve Start daemon (scan + watch + blog)
lg sync Incremental sync to remote
lg sync-all Full sync to remote
lg queue Show pending sync events
lg config Show configuration
lg completion Shell autocompletion
lg help Help
lg version Version
Twenty-three subcommands in a “notes indexer” is either feature creep or Zawinski’s Law — every program attempts to expand until it can read mail. lg has not yet achieved mail. lg has achieved blog, wiki, cover art generation, content sync, and remote deployment, which is close enough that the Squirrel has proposed adding mail “for completeness.”
The proposal was declined. For now.
The Inevitable Future
Zawinski’s Law states that every program attempts to expand until it can read mail. lg is on schedule.
The trajectory is visible to anyone who plots the subcommand count over time. The notes indexer became a blog. The blog became a wiki. The wiki grew covers. The covers needed sync. The sync needed SSE. Each step was YAGNI-compliant at the time — needed, built, shipped. But the cumulative direction is unmistakable: lg is becoming an operating environment.
The next steps, which the Lizard has not denied and the Squirrel has not needed to propose because they are obvious:
An editor screen. lg already indexes notes, parses frontmatter, tracks wiki-links, and serves them as HTML. The distance between “serves notes” and “edits notes” is one contenteditable attribute and a WebSocket. Or a terminal UI with bubbletea. Or both. The point is: lg already understands the files better than any editor. The editor is a projection, like everything else.
A task manager. lg already has lg tasks — it parses task markers from Markdown. The distance between “lists tasks” and “manages tasks” is a toggle and a write-back. The tasks are in the files. The files are the truth. The task manager is a lens on the truth, like everything else.
An Obsidian replacement. But in Go. One binary. No Electron. No Chromium. No 400MB RAM for a text editor. The graph view is a query. The backlinks are a query. The search is FTS5. The sync is SSE. The plugins are subcommands. The entire application is lg serve --editor, and the entire application fits in the same binary that currently serves the blog and the wiki and the covers.
A Claude Code orchestrator. lg documents the construction of the V4 product. The V4 product is built by one developer and eight AI agents. lg already knows the codebase structure (it indexes it), the task list (it parses it), and the architecture (it serves the wiki that describes it). The distance between “documents the build” and “orchestrates the build” is an API call and a prompt. lg assigns tasks to Claude Code instances, monitors their output, indexes the resulting commits into the lifelog, and generates Yagnipedia entries about the patterns they discover. The tool that documents the work becomes the tool that coordinates the work. The lens becomes the hand.
And then, finally, an email client. At which point Zawinski’s Law will be satisfied, the universe will be sane, and lg will have completed its journey from “notes indexer” to “everything” — which is what every program wants to be, and what only the honest ones admit.
The Paradoxes
lg embodies several paradoxes documented elsewhere in this encyclopedia:
The Gall’s Law Paradox: lg is a complex system (13,825 lines, 23 subcommands) that works because it evolved from a simple system (4,196 lines, 6 commits) that worked. If anyone had designed the current lg on day one — blog server, wiki engine, cover generator, content sync, remote deployment — the project would have failed. Instead, each capability was added when it was needed, tested when it was built, and deployed when it worked. The Squirrel proposed the complete system on day one. The Lizard built the indexer. Everything else followed.
The Ship of Theseus Paradox: lg’s original 4,196 lines have been modified, extended, and partially rewritten to 13,825 lines. Is it the same tool? The answer is yes, because the file main.go has the same go mod init and the same philosophy: files are truth, SQLite is projection. The planks have changed. The ship is the same. The course is the same.
The Lens Paradox: lg adds no information. Every search result, every backlink, every frontmatter query — all of this existed in the files before lg indexed them. lg does not create knowledge. lg makes existing knowledge findable. This is the paradox of all indexers: they are essential and they contribute nothing. The lens is not the landscape. But without the lens, the landscape is invisible.
The Recursion Paradox: lg indexes ~/Notes/Notes/Yagnipedia/lg.md — this file. This file describes lg. lg parses this file’s frontmatter, indexes its content for FTS5, extracts its wiki-links, and serves it as a Yagnipedia article at /wiki/lg. The tool serves a description of itself. The description is accurate. The description will be indexed the moment it is saved. The loop has no base case.
The Deployment
lg is deployed by two lines:
scp lg [email protected]:/usr/local/bin/lg
ssh [email protected] systemctl restart lifelog
300 milliseconds to production. It used to take 28 seconds — scp the binary, systemctl restart — which was already obscene by CI/CD standards. But 28 seconds offended the Lizard, so lg sync was built: incremental content sync with SSE negotiation, pushing only changed notes and covers to the remote instance. 300 milliseconds. Because 28 seconds was not cool enough. No Docker. No Kubernetes. No CI/CD pipeline. No staging environment. No canary deployment. No blue-green. No feature flags. A binary, copied to a Hetzner server, restarted by systemd. The server costs €109/month and runs at 0.01 load average, which means 99.99% of the Ryzen 9 7950X3D is idle — idle while simultaneously hosting the lifelog, the Yagnipedia, and the demo instance of the very product whose construction the lifelog documents and lg indexes and publishes with AI-generated covers. Three systems. One server. One binary for the blog. One binary for the product. 0.01 load. The server is bored, which is the highest compliment in the Boring Technology tradition.
The Trust
lg’s deployment reveals something deeper than architecture: trust.
The Hetzner server was set up by Claude. Not “Claude generated a script that riclib reviewed and executed.” Claude. Directly. riclib did one thing:
ssh-copy-id [email protected]
Then said: “Install lg and Solid. Harden the server.”
Claude did the rest. Not because Claude had documentation — because Claude had read the lifelog. Claude knew how riclib likes his servers installed the way a colleague knows how you take your coffee: not from a specification, but from observation. The firewall rules. The systemd units. The Cloudflare tunnel configuration. The directory structure. The log rotation. All of it inferred from 114 episodes of a developer documenting how he builds things, what he values, and what he refuses to tolerate.
This is the ultimate recursion: the lifelog documents how riclib builds. Claude reads the lifelog. Claude builds the way riclib builds. The documentation became the training data. The mythology became the specification. The stories about how the server should work became the instructions for how the server does work.
The Squirrel would call this “Mythology-Driven Infrastructure.” The Lizard would call it trust. Both are correct.
The Laws It Obeys
- Gall’s Law: evolved from simple to complex, never designed from scratch
- YAGNI: each feature added when needed, not before
- Boring Technology: Go, SQLite,
scp, systemd — no innovation tokens spent - Conway’s Law: one developer, one binary — the architecture mirrors the org chart
The Laws It Violates
- Zawinski’s Law: expanding toward reading mail (23 subcommands and counting)
- Single Responsibility Principle: a notes indexer that is also a blog, wiki, cover generator, and content sync engine
- The UNIX Philosophy: does many things, not one thing — but does them in one binary, which the UNIX Philosophy respects even as it disapproves
Measured Characteristics
- Lines of Go (day one): 4,196
- Lines of Go (current): 13,825
- Growth factor: 3.3x
- Subcommands: 23
- Subcommands in a “notes indexer”: 23 (suspicious)
- Time to build (day one): 1 day, 6 commits
- Time to evolve to current: 6 days
- Index time (full scan): ~200ms
- Notes indexed: 265+
- Wiki-links tracked: 551+
- Yagnipedia entries served: 164
- Lifelog episodes served: 114
- Covers generated: 277+
- Deployment script: 2 lines
- Time to production: 300ms
- Docker containers: 0
- Kubernetes clusters: 0
- Elasticsearch nodes: 0 (the Squirrel remembers)
- Database: SQLite (one file, disposable)
- Source of truth: Markdown files (not disposable)
- The files needed glasses: yes
- lg is the glasses: yes
- The palace was never needed: correct
