How recursive.eco is built
recursive.eco is a Next.js and Supabase app where all content is one open JSON format: a grammar, an ordered list of items, some of them links to other grammars. Interchangeable viewers draw it. People, an in-app assistant and outside agents (over MCP) edit it, and every save is backed up to GitHub.
#One building block
- A grammar is a set of items: cards, hexagrams, chapters, videos, steps.
- A collection is a grammar whose items link to other grammars.
- A selection is a pick of items inside one grammar.
The format is public, under Apache-2.0: Grammar Format.
#Three places
- Explore (structures): what people published.
- Journal (process): cast, write, ask.
- Create (possibilities): make, import, share.
#Many views, one assistant
The same grammar opens as Cards, Playlist, Tree or Print, and every view reads the same data. One assistant works across the app. Outside agents get the same tools through an MCP server, so Claude or ChatGPT can build a grammar for its owner, and the owner keeps the decision to publish.
#The stack
| Layer | What |
|---|---|
| App | Next.js (App Router) and TypeScript, on Vercel |
| Landing and viewers | Static HTML and JavaScript, Tailwind built ahead of time |
| Data | Supabase: Postgres, sign-in, row-level security |
| Files | Cloudflare R2, through the S3 API |
| Versions | Each save of a grammar is committed to a GitHub repo |
| AI | Anthropic, Google and OpenAI models behind one assistant, paid with prepaid credits (Stripe) |
| Agents | An MCP server with the tools the assistant uses |
#The data model
Postgres holds two shapes of data.
- Documents for what varies. A grammar is one row with its content in a JSON column (
user_documents.document_data). A tarot deck, a book and a playlist have different shapes, so the shape lives in the data, not in a type flag. A smallsummarycolumn, kept up to date by a trigger, carries what lists need (name, cover, visibility), so lists don't read whole grammars. - Tables for what is fixed and filtered on. Shares into collections and their review state (
tools), watch progress (playback_progress), and credits, kept as a ledger (payment_transactions). - Access lives in the database. Row-level security decides who reads a row, so a Private grammar stays with its owner and the people they invite to edit.
This is a known pattern, often called a hybrid relational and document model. When a JSON field starts being filtered on, it can become an indexed generated column without rewriting the data.
#Open source we stand on
Open source is the nutritious part, the part we want to overflow. recursive.eco is built on:
- Next.js and React, in TypeScript
- Tailwind CSS
- Supabase and PostgreSQL
- dnd kit for drag and drop, Headless UI and Heroicons
- driver.js for the guided tours
- react-markdown, remark-gfm, marked and DOMPurify for text
- Mammoth and pdf2json for importing documents
- LangChain
- The AWS SDK for JavaScript (for R2), the Stripe and Resend libraries, React Email
- The Anthropic, Google and OpenAI client libraries
- QRCode.js
What we give back so far: the grammar format, under Apache-2.0. The viewers are planned for Apache-2.0 once they are separated from the app.