OneBook

One tree for all your notes.

OneBook is a block-based notebook. Notes, checklists, agent definitions, the prompt you sent and the answer that came back are all rows in one blocks table, sorted by a fractional position key and tied together by parent_id.

Electron desktop app. Your data stays in a file.

  • agentLiterature review agent
    • promptSummarise what we keep on RAG evaluation
      • completionThree families of benchmark, with the trade-offs
        • promptWhich of these fail on Chinese corpora?
          • contextSource: Lewis et al., 2020
        • noteRetrieval notes, filed by the agent
Two runs under one agent block — and a context block hanging off the second prompt. Every line in this drawing is a row in the same table.

Seven types, one table.

One schema, no side tables per type. Only a few of the seven get special handling from the engine.

One schema, no side tables per type. Only a few of the seven get special handling from the engine.
TypeInterfaceBehaviour
noteNoteMarkdown with GFM, math, Mermaid and highlighted code; CodeMirror to edit.
promptPromptA question you asked. Maps to the user turn.
completionCompletionThe answer, streamed in place. Maps to assistant. Not created by hand.
agentAgentThe block text is the system instructions; its children are that agent’s runs.
craftCraftProcedures, checklists, templates you reuse. Renders like a note.
scriptScriptJavaScript source, edited and highlighted as code. Running it isn’t wired up.
contextContextAnother block attached as reference material, injected as XML at run time.

Fold a branch, then follow a block back to the root.

Everything the drawing above showed, plus three rows it left out. Press a row to hide what hangs under it; select one and the panel beside it walks that block's parent_id up to the root.

  • agentLiterature review agent
    • promptSummarise what we keep on RAG evaluation
      • completionThree families of benchmark, with the trade-offs
        • promptWhich of these fail on Chinese corpora?
    • craftReview checklist for the next paper
A block has one parent and any number of children, so a path like this is one recursive query, not a join across tables.

A chat is a branch of the notebook.

Each follow-up hangs its own prompt block under the previous answer, so the ancestor chain is the message history. Building a request is a recursive CTE, not a session log.

Two follow-ups under the same answer make two branches, and both stay on the tree. Nothing overwrites anything.

WITH RECURSIVE strict_path AS (
  SELECT id, parent_id, position, 0 AS depth
  FROM blocks
  WHERE id = ? AND type = 'prompt'
    AND is_deleted = 0

  UNION ALL

  SELECT b.id, b.parent_id, b.position, sp.depth + 1
  FROM blocks b
  JOIN strict_path sp ON b.id = sp.parent_id
  WHERE b.type = 'prompt' AND b.is_deleted = 0
)
SELECT b.*, sp.depth
FROM strict_path sp
JOIN blocks b
  ON (b.parent_id = sp.parent_id
      OR (b.parent_id IS NULL
          AND sp.parent_id IS NULL))
 AND b.position <= sp.position
ORDER BY sp.depth DESC, b.position ASC

prompt → completion → prompt → completion, as nested rows. · block.repository.ts

Agents work inside the tree you already keep.

An agent is a block. Its text is the system instructions, and it gets seven tools for reading and writing blocks — so it can search the notebook, then file what it finds under the block you were looking at.

Those tools run in the main process against the same database the search panel reads, so anything an agent saves is yours to browse a moment later. When a tool call rewrites a block, OneBook puts a snapshot of the old text in the tree first.

  • getBlockread one block
  • getChildBlockslist children, in order
  • getBlockAncestorswalk up to the root
  • searchBlocksthe panel’s index, scope by ref_id
  • createBlockfile something under a parent
  • updateBlockreplace text or metadata
  • deleteBlocksoft delete, restorable

The whole tool surface. No tool calls the network.

The database is a file.

A project is a directory. Copying it is a backup; moving it to another machine carries the notes, the agents and the chat history with it.

There is no telemetry and nothing to sign in to. When a request does leave the machine, it goes directly to the provider you configured — and you can open the database with sqlite3 to see what is in it.

~/.onebook/settings.jsonapp preferences
~/.onebook/models.jsonyour provider keys
~/.onebook/projects.jsonthe project registry
~/.onebook/projects/<name>/db/data.dbSQLite, WAL mode
~/.onebook/projects/<name>/export/what you write out

Everything OneBook writes on disk.

Chinese search behaves like English search.

Title and content are indexed into an FTS5 table and ranked by MATCH. Chinese text is segmented with nodejieba before it reaches the index, so CJK does not need a trigram table or a prefix hack; a stopword list keeps the index down.

The search panel and the agents’ searchBlocks tool read the same index, which means an agent finds what you find.

blockstitle and content, one row per block.
block_ftsFTS5, porter tokenizer, Chinese segmented by nodejieba before indexing.
block_linksedges extracted from [[slug]] and ((id)) on save.
two readersthe search panel and the agents’ searchBlocks tool query the same table.

One index, two readers.

A [[slug]] link resolves to a live block.

A remark plugin parses [[slug]] links and ((block-id)) embeds, then resolves them into block cards you can click open. Slug text is normalised the same way on write and on read, so a link typed as “My Page” still finds my-page.

Saving extracts those references into block_links as block_link or block_embed rows, which makes a backlinks lookup a plain SELECT. The panel that shows them isn’t built yet.

[[My Page]]my-page
[[CRO 是什么?]]cro-是什么
[[ RAG Notes ]]rag-notes
((4f2c9a1e-…))an embed edge

Write path and read path share one normaliser.

What people keep in it

The tree is the whole interface, so these all work the same way: put a block somewhere, then put blocks inside it.

Research across many sources
One parent block per source, excerpts as children, [[slug]] links between them.
Comparing AI answers
Run the same prompt three times, or hand it to different agents, and keep the answers side by side.
Long articles and reports
Outline in blocks, collapse what you’re not editing, drag a section and its children somewhere else.
Agent workbench
Write the agent as a block, attach the notes it should see, let it post its findings back into the tree.
Meeting notes
Capture flat, then re-parent the action items under the project that owns them.
A corpus for AI
Content is already split into block-sized, indexed units, so retrieval is a query instead of an ingestion job.

Bring your own model.

Model access runs on the Vercel AI SDK, with 21 provider adapters registered.

  • OpenAI
  • Anthropic
  • Google
  • xAI
  • Mistral
  • Groq
  • DeepSeek
  • MoonshotAI
  • Alibaba
  • ByteDance
  • Cohere
  • Perplexity
  • Cerebras
  • Fireworks
  • Together
  • DeepInfra
  • Baseten
  • Hugging Face
  • OpenRouter
  • Ollama
  • OpenAI-compatible

Keys are stored in ~/.onebook/models.json and read only from the main process.

What isn’t built.

Roughly ordered by how close they are.

  • Backlinks panel and a link overview. The edges are already in block_links.
  • Markdown or JSON import and export, one block per file, so existing notes can move in.
  • Embeddings next to keyword search. sqlite-vec is in optionalDependencies; no code calls it.
  • Running script blocks in a sandbox.
  • Publishing a run as an artifact, and sync between machines.
  • Auto-update, packaging pipeline, CI.

Open the tree.

The docs start with a project folder and one note block. Everything else hangs off that.