Skip to content

Folios & daily notes

Carabase has two surfaces where content lives:

A daily_notes row exists for every calendar date you’ve used Carabase. Each row holds a Tiptap document — the same JSON structure your editor produces — that’s a sequence of blocks. The most important block type is logCard: a single thought, captured in the moment, with optional tags / folio assignments / timestamps.

Daily notes are the append-only journal of your work. Connectors (GitHub PRs, calendar events, Gmail) inject logCards onto the appropriate day. The dream cycle injects reflections at 3:30 AM. The agent injects progress updates from agentic flows.

Important property: every injected logCard carries a stable sha256 idempotencyKey in its attrs. Re-running the same import or re-firing the same connector is a no-op — no duplicates, no merge headaches.

A folios row is a topical notebook. Think of one as “everything related to project X” or “my notes on this book”. Each folio has a name (used as a ~folio tag in logCards), an optional README summary (free-text), and a timeline of LLM-generated synopses (auto-updated nightly by the folio-synthesis cron).

Folio content is composed of commits — a commits row groups one or more artifacts (chunks of text, embedded for retrieval). When you write into a folio (via the commit_to_folio MCP tool, or the dream injector, or an importer), the commitTextToFolio service splits the text into chunks, embeds each one, and links them via a single commit row.

A logCard “belongs to” a folio if its attrs.folios JSON array includes the folio’s name. The walker at src/services/folio-log-walker.ts is the canonical implementation — both the GET /api/v1/folios/:id/entries route and the nightly synthesis pass use it, so they always see the same membership.

Tags are lightweight (#meeting, #decision) and shared across daily notes. Folios are heavier — they have a synthesis cycle, a README, and an entry list. Use tags for ad-hoc filtering, folios for sustained topics.

A logCard can have many of both:

{
"type": "logCard",
"attrs": {
"tags": "[\"meeting\", \"decision\"]",
"folios": "[\"acmebase\", \"fundraise\"]",
"timestamp": "10:42",
"idempotencyKey": "<sha256>"
},
"content": [/* Tiptap children */]
}

Every connector (GitHub, Calendar, Gmail, Granola) reads a sync_rules row that says “for items matching these filters, inject logCards into this folio with these tags, and (optionally) feed them through the harvest pipeline for entity extraction.”

Multiple rules per connector are supported; routing is merged when an item matches more than one. See Sync Rules (TODO).

If you’re coming from Obsidian / Logseq / Notion / Bear / Apple Notes (via 3rd-party export) / Roam / Reflect, the importer at /admin/import parses your archive into the canonical Tiptap shape:

  • Date-bound notes → become logCards on the matching daily note
  • Free-floating notes → become folio commits

You configure routing (default folio, tags to apply, harvest opt-in) before committing. Every imported logCard carries an idempotencyKey derived from the source path, so re-importing the same archive is a no-op.

See Importer (TODO).