4 min read
Building Liner.media without raiding the cupboard
I started Liner.media a few weeks ago. It’s a music identity platform — natural-language prompts turn into playlists with an arc, the playlist becomes a poster, the poster outlives the listen. Letterboxd for records, more or less, with a print shop bolted to the side.
I want to write down how it got built, because the how is the part I’m trying to be honest about with myself.
What “know-how” I didn’t use
I’ve spent years near the music industry — recommendation work, listening infrastructure, the parts of taste graphs that don’t make it into press releases. The shortest path to shipping Liner would have been to lean on all of that. Re-use the embeddings I knew how to build because I’d built them before. Borrow the editorial framing I’d seen work at someone else’s house. Bring across an instinct for what an A&R team actually looks at when they’re deciding whether a track lands.
I didn’t want to do that. Not because it would be illegal — most of it wouldn’t be — but because the only version of this that’s worth making is the one I can defend from public materials. NDAs are a fact of life in this industry; my reaction to them shouldn’t be “wait until it lapses, then cash in.”
So the rule I gave myself was simple: anything in Liner has to be defensible from things a stranger could read. Spotify’s Web API docs. Apple’s MusicKit reference. Published papers on emotional embeddings. Letterboxd’s public mechanics. The pile of music magazines on my desk. No private data, no recalled internals, no “I happen to know that label X weights Y” — even when it would have been faster.
This is slower. It’s also the only version where I get to keep my own name on it.
The shape
There are six object types and one aesthetic. The objects: diary entries, playlists, lists, reviews, shows, posters. The aesthetic: a music magazine that happens to be a website, not a streaming app that happens to have a blog.
The landing page is built like a magazine cover — a masthead strip, a serif
headline that scales with clamp(), two columns of body copy, a single
poster as the cover image. The marketing copy lives under section rules
labelled § 01, § 02, § 03, like a print contents page. I went looking
for the references in places that aren’t tech: Apartamento, Cereal, The
New York Review of Books. I avoided the references in places that are:
Vercel templates, Stripe-clone gradients, anything that looks like every
other Y Combinator landing in 2026.
The stack, briefly
- Next.js 16.2 App Router, TypeScript strict
- Supabase for Postgres, auth, storage
- Anthropic Claude for the prompt → emotional arc translation
- Spotify Web API for track features and playlist sync
- Pixabay for the photo library that drives poster backgrounds
- Resend for the waitlist mail
- PostHog for the bare minimum analytics
- Vercel because that part isn’t interesting
Two things are worth saying out loud. First, there is no ORM and no state management library. Server Components do the reading, Server Actions do the writing, URL state does the rest. The codebase is small because the surface area is small. Second, every external call is wrapped in a Zod schema at the trust boundary, not because I expect Spotify to ship malformed JSON but because future-me deserves the type narrowing.
What Claude Code actually did
I built this in Claude Code, and I want to be specific about what that means, because “AI built my startup” is the laziest framing in the room right now.
What Claude Code did well: scaffolded routes, wrote the Supabase RLS
policies from a schema and a one-paragraph intent, ported the design tokens
into a Tailwind v4 @theme block without me having to remember v4’s syntax,
and caught the Next.js 16.2 breaking changes I would have walked into
otherwise. (params is async now. middleware.ts is proxy.ts. There are
others.)
What Claude Code didn’t do: decide that the landing page should read like a magazine cover. Decide that the brand was editorial restraint. Decide that the algorithm has six layers and that Layer 6 — editorial boost — is the one that makes Liner different from every other recommender that ever shipped. Decide that the print shop is a real second business, not a merch afterthought.
The taste calls aren’t agentic. They were never going to be. But the typing — the eight hundred lines of route handlers, the migrations, the loader states, the OG image generation, the email templates — that’s a real amount of time Claude Code gave me back, and I spent it on the parts that needed me.
What I learned worth keeping
A few things, in case I forget:
- Public-only is a real constraint, and it’s a good one. It forced me to re-derive things from first principles. Half of those re-derivations ended up better than the version I’d seen before, because the version I’d seen before was optimised for someone else’s KPIs.
- The aesthetic is the moat. If Liner looks like every other AI-music startup, no one will read past the headline, and the algorithm — however good — won’t get a chance to prove itself. I spent more time on type than on tracks. I’d do it again.
- Defer everything that isn’t the smallest honest version. I have a Notion full of features I want to build. None of them matter if the prompt-to-poster loop isn’t tight.
If you want to be on the waitlist, it’s at liner.media. If you want to argue with me about the algorithm, the editorial layer, or the choice of Spectral over Tiempos, the email’s in the footer.
The trick, again, is the ratio.