Skip to content

Notes - Markdown vault with chat co-writing

The Notes view is a personal Markdown vault (an Obsidian-style alternative) built into the Hive app. It gives you a file tree with a name filter, a source + live-preview Markdown editor, plus first-class Claude, Codex, OpenCode, or OpenRouter chats rooted in the vault so you can talk about, organize, and co-write your notes.

Notes live in an S3-compatible bucket as the shared source of truth and are synced to a local directory on each node, so agents operate on real local files (fast, and Claude Code needs a real filesystem).

Enabling the vault

Add a [notes] section to the daemon's config.toml on the node you connect to:

toml
[notes]
enabled = true
bucket = "my-notes"                       # S3 bucket (sync is off without this)
endpoint = "https://s3.amazonaws.com"     # omit for AWS; set for MinIO/R2/B2
region = "us-east-1"                      # many S3-compatible providers accept "auto"
access_key = "AKIA..."                    # falls back to AWS_ACCESS_KEY_ID env var
secret_key = "..."                        # falls back to AWS_SECRET_ACCESS_KEY env var
local_dir = "~/.hive/notes"               # default: <data_dir>/notes (node-local)
user = "daniel"                           # root the vault in this OS user's home (node-local)
sync_interval_secs = 300                  # background pull cadence (min 60)
  • Local-only is fine. With enabled = true but no bucket, the vault works entirely locally (editor, agents); it just never reaches S3.
  • Credentials. Keys may live in config.toml or be injected at runtime via the standard AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY environment variables (leave access_key / secret_key unset to use them).

Configuring from the app

You don't have to hand-edit config.toml. The Notes view has a settings gear (top right) that opens a Notes vault settings dialog - the same fields as above (enable sync, local directory, bucket, endpoint, region, access/secret keys, sync interval). Saving writes the [notes] section to the connected node's config.toml and takes effect without a restart. When the vault isn't configured yet, the "vault not configured" hint also offers a Configure vault button that opens the same dialog.

Saving also replicates the shared S3 settings to every node in the cluster (see Cluster replication below), so you only configure the vault once and every node can serve it - no need to repeat the settings on each node.

Per-node directory and user. The dialog has a Node picker (shown when the cluster has more than one node): choose a node to view and edit its local vault directory and OS user. These two fields are node-local - only the S3 settings replicate. The User home dropdown lists the node's OS user accounts; picking one roots that node's vault under the user's home directory (e.g. /home/<user>/.hive/notes). This is useful when the daemon runs as root or via systemd but you want your notes in your own home directory. Leave it on Daemon user (default) to use the daemon process's home / data directory. A ~-prefixed or relative Local vault directory resolves under the selected user's home; an absolute path is used as-is. The field has a Browse button that opens a directory picker rooted on the targeted node, so you can pick an existing folder (or create one) instead of typing the path by hand.

The dialog never displays stored S3 secrets: once a key is saved it shows as "stored"; leave the field blank to keep it, type to replace it, or tick Clear to remove it. The dialog works at both desktop and phone widths.

A Test connection button in the S3 section checks that the saved configuration can reach the bucket (it builds the store and lists the bucket without changing anything) and reports the object count or the exact error. It uses the saved config, so save any edits before testing.

If [notes] is absent, the Notes view shows a "vault not configured" hint.

Preferred serving node

The node selector above the vault chooses which online cluster node serves Notes. Hive remembers the preferred node on this device and routes the entire Notes workflow to it: listing, reading, editing, search, file operations, settings, manual sync, and the S3 connection test. Choose Use connected node to clear the preference and return to the daemon the app is connected to.

If the preferred node is offline, Hive shows an Offline badge and stops Notes operations. It does not silently fall back to another vault, so the app cannot show or modify a different node's working copy by surprise. Choose another online node or explicitly switch back to the connected node.

Using the view

  • File tree (left): the whole vault, folders first. Click a folder to collapse/expand, a note to open it. Use the Collapse all / Expand all toggle in the tree header to fold or unfold the whole vault at once. On desktop the tree panel is hidden by default; collapse it with the panel button next to the filter box, and re-open it from the slim rail that takes its place on the left edge. That choice is remembered for the current app session and resets to hidden when the app restarts. On desktop, drag the handle on the tree's right edge to resize it (180-480 px); the width persists across restarts via localStorage["hive-notes-tree-width"].
  • Row actions: right-click a row (desktop) or tap its kebab (, touch) for a context menu - open, new note in a folder, new folder inside a folder, collapse/expand that folder, collapse/expand all, rename, and delete.
  • New creates a note (a .md extension is added if you omit one); parent folders are created as needed.
  • New folder (the folder button next to the tree's filter box, or right-click the tree background) creates an empty folder without a note in it. Use / for nested folders; missing parents are created too, and the new folder's ancestors are expanded so it is visible right away.
  • Drag and drop (desktop): drag files from your OS onto a folder row to upload them into that folder, or onto the tree background to drop them in the vault root; the target is outlined while you drag. Drag a row onto a folder to move that note or folder there. Names that collide get the same " copy" suffix a paste does, so a drop never overwrites an existing note, and uploads are capped at 25 MiB per file. Touch devices use the row menu's cut/paste instead (HTML drag is a pointer affordance).
  • Editor (center): a CodeMirror Markdown editor with a live preview. Toggle source / split / preview in the editor toolbar; the chosen mode is a per-device preference that persists across restarts. In split mode, drag the divider between the source and preview panes to rebalance them (20-80%); the ratio persists via localStorage["hive-notes-editor-split"]. The editor auto-saves a short delay after you stop typing (so the agent and S3 always see your latest words); Ctrl/Cmd+S still saves on demand. The editor and preview font size is configurable in app Settings → Notes → Font size (a per-device preference, synced with the rest of your UI preferences). The preview understands Obsidian-flavoured Markdown - see Obsidian-flavoured Markdown below.
  • Drop files into a note: dragging files from your OS onto the open note uploads them to the vault's attachments/ folder and links them at the cursor - images as ![[attachments/pic.png]] embeds (which render inline in the preview), other types as [[attachments/report.pdf]] wikilinks. The note is marked dirty and auto-saves like any other edit.
  • Info panel (desktop): the panel button in the editor toolbar opens a right rail with the note's Outline (click a heading to jump), Backlinks (other notes that link here - click to open at the reference), and Tags (click to search the vault for that tag).
  • Attachment previews: opening an image, audio, video, or PDF file from the tree shows a read-only viewer instead of the text editor; any other binary type shows an info card with a Download button (desktop only). The tree uses type-specific icons for these files.
  • Inline images: a Markdown image whose path points at a file in the vault (![alt](assets/diagram.png), relative to the note, or /-prefixed for vault-absolute) renders inline in the preview pane. External http(s)/data: image URLs render as usual. Attachments load on demand (capped at 25 MiB) and are never edited from the app - drop them into the vault folder or let the agent in a Notes chat manage them.
  • Name filter: the search box at the top of the file tree filters the tree to files and folders whose name matches; matching folders keep their ancestors visible. It does not search note contents.
  • Chat: the toolbar Chat button opens a normal Hive chat rooted in the Notes vault - see Notes chats below.

On phones the two panes become a bottom switcher (Files / Editor); all surfaces respect the safe-area insets. The info panel is desktop-only.

Obsidian-flavoured Markdown

On top of GitHub-Flavoured Markdown, the preview renders the Obsidian syntax most notes rely on. Everything is rendered in the existing source / split / preview panes - there is no separate "live preview" editing mode.

  • Wikilinks - [[Note]], [[Note|alias]], and [[folder/Note]] link to another note, resolved the way Obsidian does (exact path first, then a unique basename match). Click one in the preview to open it; a link whose target doesn't exist is shown in red. [[Note#Heading]] jumps to a heading. In the source editor, typing [[ pops up an autocomplete of every note in the vault.
  • Embeds / transclusion - ![[image.png]] embeds a vault image (or audio / video / PDF) inline, and ![[Note]] (or ![[Note#Heading]]) transcludes that note's content into the current one. The embedded note's title links back to the source; embeds inside an embed degrade to plain links rather than recursing.
  • Tags - #tag (including nested #area/topic) renders as a pill. Click it to open the full-text search seeded with that tag, or use the Tags section of the info panel.
  • Callouts - > [!note], > [!warning], > [!tip], etc. render as coloured callout blocks. An optional title after the type (> [!info] Heads up) is used as the callout heading.
  • Math - inline $E = mc^2$ and block $$ ... $$ are typeset with KaTeX.
  • Diagrams - fenced ```mermaid blocks render as Mermaid diagrams (loaded on demand; the diagram theme follows the app's light/dark setting).
  • Code highlighting - fenced code blocks are syntax-highlighted with highlight.js, with colours that follow the app theme.

Backlinks and tag search reuse the vault's native full-text search, so they work on every platform (including mobile) without any extra index.

Spellcheck

The source editor can spellcheck notes offline. Enable it in Settings → Appearance → Notes → Spelling check and pick one or more languages (Czech, Slovak, English US/UK, German, Polish, Spanish, French). Checking runs entirely on the device with Hunspell dictionaries - note text never leaves the app, and a dictionary is only downloaded and loaded for the languages you select.

  • Underlines - words rejected by every selected language get a red wavy underline in the source pane. A word accepted by any selected language is fine, so mixed-language notes work naturally.
  • Fixes - click or tap an underlined word to get suggested corrections; picking one replaces the word in place. Suggestions from all selected languages are merged and ranked by closeness to the typed word.
  • Personal dictionary - Add to dictionary in the same popup accepts the word everywhere from then on. Custom words are stored as a hive-* preference, so they ride along with cluster preference sync and account cloud sync. Ignore skips the word for the current session only.
  • What is skipped - code blocks and inline code, URLs, [[wikilinks]], #tags, and identifier-like words (CamelCase, ALL-CAPS) are never checked.

The checker runs in a background worker, so even the large Slavic dictionaries (a few MB each) don't block typing; very large notes (over ~200 kB) skip checking entirely.

The Search button in the toolbar (or Ctrl+Shift+F) opens a standalone search dialog that looks inside every note in the vault - distinct from the sidebar's name filter, which only matches file and folder names.

  • Query: matched as a plain substring (never a regex) with ripgrep-style smart-case - case-insensitive unless the query contains an uppercase letter.
  • Results: one row per matching line, showing the matched text (the query highlighted) with the file name and line number at the end of the row. Binary files, dotfiles, and dot-directories are skipped; a broad query is capped at 500 hits.
  • Preview: selecting a result (single click, or the arrow keys) shows a few lines of surrounding context below the list, with the matched line highlighted.
  • Open: double-click a result, press Enter, or use the Open button in the preview header to jump to the note with the cursor placed on the match and the line scrolled into view. On phones this switches to the editor pane.

Search runs natively on the daemon over the synced local vault, so it works on every platform - including mobile, where no external search binary exists.

Command palette

Pressing F1 anywhere in the Notes view opens a command palette - a fuzzy-searchable list of every Notes action, mirroring the full-text search modal. Type to filter, navigate with the arrow keys, and press Enter (or click) to run the selected action; Esc closes it.

The palette only lists actions that are runnable right now: open-note actions (rename, delete) appear when a note is open, the S3 Pull/Push entries appear only when sync is configured, and folder collapse/expand entries reflect the current state. Chat about notes starts a Notes chat and links the open note when one is selected. Each row shows its keyboard shortcut where one is bound.

Notes chats

Notes no longer has a separate agent pane or private agent transcript. A Notes chat is an ordinary first-class Hive chat whose workspace is the node's Notes vault. It appears in Chats with a Notes badge and uses the same provider and model picker, transcript, composer, streaming progress, permission controls, Stop action, rename, delete, persistence, resume, and cluster reopening as every other chat.

Notes Chat is available only when the serving node is the daemon the app is connected to. When a remote preferred node serves the vault, the Chat action is disabled because chat execution is still rooted on the connected daemon. Switch to the connected node before starting a Notes chat.

  • Start from Notes. Select Chat in the Notes toolbar, or use Chat about notes in the command palette. Hive opens the normal New chat dialog with the Notes vault selected. If a note is open, it is prelinked to the new chat.
  • Start from Chats. Select New chat, choose Notes vault as the workspace, then choose Claude, Codex, OpenCode, or OpenRouter and an optional model. Notes chats stay in the regular chat rail alongside dedicated-workspace chats.
  • Link note files. In a Notes chat, use Link notes in the shared composer to search the vault and attach one or more vault-relative paths. Linked notes appear as chips in your message. The daemon validates that every path stays inside the vault and adds the paths to the agent prompt as Linked notes: context.
  • Browse and open. Use the Notes browse control in the chat header or composer to inspect the vault. Selecting a linked note opens it in the Notes editor, so you can move between the conversation and the source file.
  • Read and update. The agent runs with the vault as its working directory and can read or edit linked notes and other vault files. Ask it to summarize, reorganize, create, or update notes in the same conversation.
  • Provider permissions. Claude Notes chats use acceptEdits and allow WebFetch and WebSearch. Codex Notes chats use workspace-write access with approval prompts disabled. These defaults let either provider edit the vault, and let Claude turn a linked web source into a note.
  • Vault instructions (AGENTS.md + CLAUDE.md). The daemon seeds an AGENTS.md with Notes co-writing guidance and a thin CLAUDE.md that links to it (@AGENTS.md) when they are missing. Existing files are never overwritten. Edit them to shape agent behavior; they sync like other vault files.
  • Live co-editing. A vault file watcher notifies the Notes editor when an agent changes a file. A clean open buffer reloads the change, while normal optimistic concurrency protects unsaved local edits.

Sync model

  • Push on save. Saving (or creating/deleting/renaming) a note through the app uploads it to S3 immediately, independent of the poll.
  • Periodic pull and push. Every sync_interval_secs, each node lists the bucket and downloads any object newer than its local copy, then pushes its own local changes (and deletions) back up. This runs on every node whether or not a client is connected, so edits made on disk - for example by the Notes chat agent or a terminal session - propagate to S3 and the rest of the fleet without anyone opening the app. After syncing it notifies connected apps (the view re-lists, and a non-dirty open note re-reads).
  • Manual sync. When sync is configured, the Notes toolbar shows Pull (download remote changes now), Push (upload notes changed since the last sync now), and a Synced … ago indicator of the node's last successful sync. These trigger the same engine as the periodic poll without waiting for the next tick - handy to confirm a freshly-configured vault is actually reaching S3.
  • Change tracking. A hidden .hive-sync.json manifest in the vault root maps each note's path to the sha256 of the bytes last synced. Push consults it to upload only notes whose content actually changed and rewrites it afterward; per-save push, delete, and pull keep it current. It is an optimization only - a missing or corrupt manifest just makes the next push re-upload everything.
  • Conflict resolution is last-write-wins by modification time. Pull and push are symmetric: on pull a remote object only overwrites a local note when it is newer and its bytes differ; on push a locally changed note only overwrites its S3 object when the local mtime is strictly newer than the remote, so the background push never clobbers a newer remote edit (it leaves that for the next pull). Simultaneous edits of the same note on two nodes keep the newer one and lose the older edit - there are no conflict-copy files in this version.
  • Deletions. A local delete is mirrored to S3 - both the app's explicit delete and a file that disappears on disk and was previously synced (the background push removes it from the bucket so other nodes drop it on pull). Deleting a folder removes the folder's object and every object beneath its prefix, so the notes inside it do not survive in the bucket and reappear on the next pull. Remote deletions are not propagated to a node's local copy (a node never deletes a note it didn't delete itself).
  • Names with non-ASCII / reserved characters. Object keys are stored under their real UTF-8 names (a folder Práce is the S3 key Práce/...), so the bucket stays readable for any external S3 client (e.g. Obsidian sync plugins). Pull still percent-decodes keys before writing to disk, which keeps it compatible with objects written by earlier builds.
  • Self-healing of legacy encoded keys. Earlier builds stored keys in a percent-encoded form (Pr%C3%A1ce instead of Práce), and older ones also wrote those encoded names to disk, re-encoding the % on every cycle (%C5%A0pajzka, %25C5%25A0pajzka). Sync repairs both automatically: pull moves a legacy encoded object to its real-name key (byte-identical, last-write-wins against any existing clean twin) and deletes the encoded one, while a stray local copy whose name decodes to an existing clean note is removed instead of re-uploaded. The whole bucket converges to clean UTF-8 keys within a sync cycle or two. A legitimately %-bearing filename (one whose decoded form is not a different existing note) is never touched.

Cluster replication

The vault data is shared through S3, but each node also needs the S3 settings (bucket, endpoint, region, credentials, enable flag, interval) to sync and serve it. Those settings are replicated across the cluster so notes survive leader changes and stay reachable when the node you originally configured is offline.

  • Configure once. Saving the notes settings on any node stamps a write timestamp, persists them locally, and broadcasts them to every peer (PeerMessage::SyncNotesConfig). Each node applies the shared fields to its own [notes] config and starts syncing the vault from S3.
  • Last-writer-wins. A peer only applies an incoming config when its timestamp is newer than what it already has, so an out-of-order or stale broadcast cannot clobber a fresher setting.
  • local_dir stays node-local. Only the shared S3 fields are replicated; each node keeps its own working-copy directory (default <data_dir>/notes).
  • Catch-up on reconnect. A node that was offline when the settings changed receives the current config when it rejoins the cluster, then resyncs the vault.
  • Pull on promotion. When a node becomes leader it pulls the vault from S3 immediately rather than serving a copy that may be a sync-interval stale, so a leadership change never hands the app an out-of-date vault.
  • Credentials spread to every node. Because each node syncs independently, the S3 access/secret keys are stored on every node's config.toml. This is required for notes to remain available when any single node goes down.
  • Choose which node serves notes. Without a preference, the connected node serves Notes. A per-device preferred node routes Notes operations through the cluster to that node. Hive requires the selected node to be online and never falls back to a different vault silently.

Wire protocol

Client → daemon (ClientMessage): ListNotes, ReadNote, ReadNoteBinary (base64 bytes + MIME for attachments and inline images), WriteNote (base_sha256 for optimistic concurrency), CreateNote, UploadNote (base64 bytes for a dropped attachment; exclusive, so an existing path errors instead of being overwritten), DeleteNote, RenameNote, CopyNote, CreateFolder, SearchNotes, GetNotesSettings / SetNotesSettings, SyncNotes (direction: pull / push / both), and TestNotesS3. Every request carries an optional node_id; when present, the connected daemon forwards it to that serving node. A standalone daemon rejects an explicit remote target instead of falling back locally.

Daemon → client (ServerMessage): NoteList (vault_dir + flat FsEntry tree + last_sync_unix), NoteContent, NoteBinary (base64 data + mime), NoteSaved, NoteWriteConflict, NoteActionResult, NoteSearchResults, NoteError, NotesChanged (broadcast after a sync pulls remote changes), NotesSettings, NotesSettingsError, NotesSyncResult (per-direction change counts + last-sync time), and NotesS3TestResult. Routed responses echo the target node_id, and mutation and search replies also echo their request_id. The app ignores a delayed reply from a previously selected node, so changing the preferred node cannot replace the current vault state with stale data. S3 settings still replicate cluster-wide (PeerMessage::SyncNotesConfig, last-writer-wins); each node keeps its own working copy and can be selected as the serving node. See Cluster replication above.

Limitations (v1)

  • Last-write-wins only; no Obsidian-style conflict copies.
  • No graph view, and no "live preview" inline-rendering edit mode - rich rendering happens in the preview pane (source / split / preview).
  • Backlinks and tag listings reflect the vault as it exists at the moment the panel loads; they refresh when you reopen a note, not continuously as you type.
  • The preview HTML is rendered from your own trusted vault content and is not sanitised; treat the vault as you would your own files.
  • Attachment viewers are read-only. Add files by dropping them onto the tree or into an open note, or ask an agent in a Notes chat to manage them. Inline-image refs must resolve to a file in the vault (or be an external URL).
  • Chat co-editing is not a true three-way merge: if you type in the brief window between the agent writing a note and the editor reloading it, the next auto-save can hit a write conflict (resolve it with the editor's overwrite prompt).
  • The vault file watcher binds the resolved vault directory and re-binds when that directory changes in settings; if a watcher fails to start, agent edits still reach the editor on the next periodic sync rather than instantly.

Hive - remote AI coding agents over WebSocket.