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
Seven types, one table.
One schema, no side tables per type. Only a few of the seven get special handling from the engine.
| Type | Interface | Behaviour |
|---|---|---|
| note | Note | Markdown with GFM, math, Mermaid and highlighted code; CodeMirror to edit. |
| prompt | Prompt | A question you asked. Maps to the user turn. |
| completion | Completion | The answer, streamed in place. Maps to assistant. Not created by hand. |
| agent | Agent | The block text is the system instructions; its children are that agent’s runs. |
| craft | Craft | Procedures, checklists, templates you reuse. Renders like a note. |
| script | Script | JavaScript source, edited and highlighted as code. Running it isn’t wired up. |
| context | Context | Another 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 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 ASCprompt → 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.
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.
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.
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
- 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.