Where your data lives
All your links live in a single Cloudflare D1 database (SQLite) named
linkbrain, bound to the Worker as env.linkbrain. There’s no other state.
The schema
Section titled “The schema”The source of truth for the data shape is the migrations/ directory —
0001_init.sql for the core columns and 0003_metadata.sql for the metadata
columns below. A saved link is one row:
| Column | Notes |
|--------|-------|
| id | Integer primary key |
| url | The link — unique (this is how duplicates are rejected) |
| title | Resolved title (OG title, <title>, or GitHub full name) |
| summary | AI-written summary, or scraped description as fallback |
| tags | Space-delimited, single-token tags (e.g. #api-gateway #backend) |
| note | Your personal note, if you added one |
| kind | github or web |
| saved_at | Timestamp, defaults to insert time |
Plus metadata columns (all default-valued, so old rows stay valid):
| Column | Tier | Notes |
|--------|------|-------|
| domain | auto | Hostname of the URL |
| image, site_name, author, published_at | auto | Scraped OpenGraph/article metadata (web links) |
| stars, language, license | auto | GitHub repo metadata |
| category | AI | Single bucket (article/video/repo/tool/paper/…) |
| key_points | AI | JSON array of 2–4 takeaways |
| details | AI | 3–5 sentence synopsis from the full content (article body / GitHub README) |
| status | you | unread / reading / read / archived |
| favorite | you | 0 / 1 |
| collection | you | Free-form grouping name |
| remind_at | you | YYYY-MM-DD to resurface (see /due) |
| shareable | you | 0 / 1 — 1 publishes the link to your List (/list) |
Full-text search
Section titled “Full-text search”Alongside links is an FTS5 virtual table, links_fts, indexing the URL,
title, summary, tags, and note. It’s an external-content table kept in sync
by an AFTER INSERT trigger on links. /find runs a
MATCH query against it ordered by relevance.
Migrations
Section titled “Migrations”Schema and data changes ship as checked-in SQL files in migrations/, applied
with wrangler d1 migrations apply linkbrain — never a manual “run this once”
step. 0001_init.sql creates the tables and trigger; 0002_seed.sql carries
over the links that existed under the original local SQLite bot, using
INSERT OR IGNORE so re-runs are no-ops.
Inspecting and backing up
Section titled “Inspecting and backing up”Query the database directly with wrangler:
# remote (production)npx wrangler d1 execute linkbrain --remote --command "SELECT COUNT(*) FROM links"
# local dev databasenpx wrangler d1 execute linkbrain --local --command "SELECT url, tags FROM links"