Build log — 07 · Seven invisible decisions
Seven invisible decisions.
Four months building a Pocket alternative as a solo Italian indie. Almost all of these are reversible. None of them are obvious from the outside. Each one slightly altered what Shelf became.
Filed in Verona · 14 May 2026 · ~10 minute read
Some time after Pocket announced the shutdown I still
have a folder on my disk called pocket-export-2025.html
that I haven't opened. The shutdown is what made me build Shelf. The
unopened folder is what made me think harder about what I was actually
building. This post is about the seven decisions I made while
building, almost all invisible from the outside, almost all reversible,
but each one slightly altering what Shelf became.
I am writing this on a Tuesday morning between two coffees. It is not polished. The audience I have in mind is the other solo maker reading on HN, not the marketing team I don't have.
§ 01 No backend.
The first decision was the one I never wrote down. Everything lives in
chrome.storage.local. There is no
Shelf API, no Postgres, no auth service, no S3 bucket, no Redis cache.
When you save an article it goes into the extension's local storage
slot on your machine and stays there. Nothing is shipped to a server
because there is no server. The library is files on your disk in the
most literal sense the browser allows.
This is the kind of choice that sounds ideological if you describe it on Twitter and pragmatic if you have ever maintained a production database for an indie product on your own. What it actually bought me was a flat baseline of operational cost: zero. No AWS bill that grows with users. No Postgres upgrade weekend. No paging alerts at 2am because the disk filled up. The privacy story is real, but honestly the bigger gift was the absence of a 3am pager.
The constraint shows up around five thousand items. The library viewer is a single-process React list and at that scale you can feel the render starting to chew. Most people will never hit five thousand saves but a handful will, and when they do I'll have to virtualize the list or move to IndexedDB for the cold tail. That is fine. The thing I keep telling myself is that constraint problems for users who exist are nicer to have than scale problems for users who don't.
What I gave up: cross-device sync, obviously. I said no to sync because sync without a backend is a research problem (CRDTs, conflict resolution, partial offline edits) and sync with a backend means I have a backend. For now the answer is export to Markdown or Notion or your Obsidian vault and let your existing sync layer do the work it already does well. I am not totally at peace with this. It is the thing I get asked about most and I keep almost...
§ 02 Markdown-export-first.
The second decision was: every saved item must be one keypress away from a plain Markdown file. Not a database row, not a proprietary binary, not an Air-table style record-with-fields. Markdown. The same format that obsidian and Logseq and a thousand quiet tools speak natively, the same format I have been writing my own notes in for the last four years.
Pocket's death taught me this in the most practical way possible. I tried to extract eleven years of saves and I got back an HTML file shaped like a 2008 bookmark export. The metadata I cared about (tags, highlights, position) was either lost or buried inside attributes I had to parse. When the company that holds your data decides to stop holding it, the format they hand you back is whatever they happened to choose in 2014. You don't get to negotiate.
So I inverted the model. Shelf exports the moment you ask it to. The Notion exporter is a layer over Markdown. The Obsidian and Logseq exporters are URL-handler invocations that hand the destination app a Markdown blob and let it file the result inside the vault. None of these exports require a Shelf server. None of them require you to ever come back to Shelf after the export. If I disappear tomorrow, your saves are already in your vault, and your vault is already on your disk.
The part where this gets philosophical: I have stopped thinking of Shelf as the place your library lives. Shelf is the place your library passes through. Your library lives in the folder you keep your notes in, in the workspace where you write, on the disk you sync. That is a weaker positioning to market against Pocket, which got to say "we hold your articles". I think it ages better. We'll see.
§ 03 Stripe direct over Lemon.
I built the entire billing layer on top of LemonSqueezy first. Their Merchant of Record model handles VAT for you, which when you are an Italian sole-proprietor with a forfettario regime sounds like a dream. I shipped it. It worked. (I tried Lemon Squeezy for about a week.) Then I read a couple of payout-denial threads on Indie Hackers and the same week Lemon's parent company quietly changed terms again and I started feeling that thing where the platform you're built on is making decisions about your business in rooms you're not in.
So I ripped it out over a weekend. The new stack is Stripe direct, with the license being a self-contained JWT my server signs at checkout and the extension verifies offline. EU VAT-OSS quarterly filing now sits on me rather than on Lemon, which is the honest cost of the switch. The benefit is the five percent MoR cut goes away. On a €4.99 monthly that is a rounding error. On a €99 lifetime times 200 founders that is roughly €1,000 I get to keep. Not the kind of money that funds a year, but the kind of money that buys you a few months of being slow.
The thing that matters more than the math: I wanted my business not to depend on a third party's account-management decisions. Stripe is also a third party, but Stripe is the third party that everyone in this industry has built workarounds for. If they freeze me I have a known set of moves. If Lemon freezes me I have a forum thread.
§ 04 No mobile app on purpose.
I have been asked four times in the last week when the iOS app is coming. The answer is: not from me. Not in 2026, probably not in 2027, maybe never. One person can support one platform well. Two platforms is two backlogs, two release cycles, two app stores breaking the same feature in different ways on the same Tuesday.
The pragmatic argument is also real. Long-form reading happens on a desktop browser. YouTube transcripts, podcast pages, ten-thousand-word essays from The Atlantic, the slow stuff Shelf actually exists for, all of it is desktop-first. The phone is good for triage and bad for patience. I am not the first to say this but I do believe it: the phone wants you to keep scrolling, and a shelf wants you to stop.
The actual mobile story for Shelf is the export. Your saves come out as Markdown files in your vault. Your vault syncs to your phone via whatever you already use. iCloud, Dropbox, Syncthing, the Obsidian paid sync. Read on the phone if you want. Just don't expect Shelf to be the thing doing the syncing.
§ 05 Founder tier capped at 200.
The Founder Lifetime is €99 paid once, Pro forever, including every feature that ships after it. The cap is 200 supporters. Past that the door closes. The math: €99 times 200 is about twenty thousand euros gross. After VAT and Stripe fees it is more like fifteen. That is six months of being slow without a venture conversation. It is what we used to call cassa upfront in the Italian way of running a tiny business: you take the deposit, you build the thing, you owe the people who paid.
The cap exists because lifetime deals are the kind of decision you regret in the third year. Two hundred founders paying once is finite. Five hundred founders paying once is the LTV trap that eventually forces you to either sunset the product or break the promise. I considered raising the cap to 300 at one point when the launch math looked tighter than I wanted. I decided no, because the number I wrote on the landing page is a promise to the people who paid early, and breaking that promise is a much more expensive decision than ten extra founders is a cheap one.
The Founder Wall is the public version of the cassa. Every founder gets a row, with the date they paid and the name they chose to use. It is partly thank-you, partly proof, partly the social pressure I impose on myself to keep shipping. When the wall is at 87 of 200 and someone is reading the landing page, the wall is the trust signal. When the wall is at 200 of 200 the offer is closed and the page just says so.
§ 06 Italian sole-prop, not LLC.
Shelf is operated by a ditta individuale, an Italian sole proprietorship with a P.IVA, registered under the regime forfettario flat-tax bracket. It is not an SRL (the Italian LLC equivalent), which would have given me limited liability and a corporate veil and the ability to bring on a partner cleanly, and which would also have cost roughly four thousand euros to incorporate plus a commercialista on retainer plus a notary plus the time. The sole-prop costs about zero to start and the tax handling stays manageable until I cross the forfettario revenue threshold.
The cost of this choice is real. Personal liability is unlimited. If Shelf gets sued (unlikely for a Chrome extension that does not collect data, but never zero), it is me being sued, not a company. At some point if revenue scales I will need to transform into an SRL, and that transformation has paperwork and tax friction and a commercialista bill. The benefit is that the alternative was waiting six months and four thousand euros to start, in a business where ninety percent of indie products never reach their first hundred paying users.
Ship today, restructure later. I will probably regret some piece of this in 2027. I will not regret having started.
§ 07 AI tagging behind the paywall.
This one is the decision I am least at peace with. The AI auto-tag in Shelf runs on-device when your Chrome has Gemini Nano available, which on a recent Chrome on a recent laptop it usually does. On-device inference has no per-token cost to me. Zero. So why is it in the Pro tier and not in the free one?
Two reasons, neither of them comfortable to write. The first is that roughly a third of users (older laptops, Linux Chromium builds, Chrome on a Chromebook with too little RAM) don't have Nano available and the auto-tag falls back to the Groq cloud API, which is fast and cheap but not free. If I made AI tagging a free-tier feature I would be eating that cloud cost for every fallback user, on a product that has no other revenue from them. The second reason is that the actual engineering is not the model call. It is the Smart Rules layer above it, the schema validator that catches when the model invents tags that aren't in your collection, the cascade routing logic that decides Nano-or-Groq-or-skip per save. The model is free. The plumbing is not.
The honest version of this pitch is: Pro is what funds the maker's hours. The AI features are a convenient gate because they map cleanly to the kind of reader who saves a lot and tags a lot and would benefit most from automation. They are also the features I will most easily improve over the next eighteen months as the on-device models get better.
If anyone asks me publicly why a free model is a paid feature, this paragraph is the answer.
Most of these decisions are still revocable. If sync becomes the hill I die on I'll build it. If the cap of 200 supporters fills in a week I'll think harder about what to do next. If the SRL transformation becomes urgent I'll pay the four thousand euros and the commercialista bill and be glad I waited.
The thing I'm finding hardest now is not the decisions themselves. It is the discipline of staying boring after them. Shipping the same small product week after week without re-deciding everything every Tuesday. Every Tuesday a new piece of news (a Show HN, a competitor launch, a Reddit thread, a Pieter Levels tweet) shows up and tries to reopen one of these decisions. Sometimes that is correct. Most of the time it is the kind of reactive churn that makes solo products feel like they have a team when they don't. That part nobody warns you about.
If you want to actually try the thing all of these decisions were about, it is at shelf-extension.com. Otherwise, thanks for reading this far.
— Riccardo
※ End of build log ※