Minor Changes
-
Settings now tells you where a plugin's changes are stored and lets you search across the whole dialog.
Plugin panels carry a scope badge: markdownlint shows a "Project" badge (its rules are committed to config.yml and shared with your team) and Themes shows a "User" badge (personal to your device). Hover either badge for a one-line explanation of where the change is saved.
A search box is pinned at the top of the settings sidebar. Type to find any section, any Preferences/Theme setting, or any markdownlint rule by name, id, or alias, then jump straight to it: a section result switches panels, a setting result scrolls to and briefly highlights the field, and a markdownlint rule result opens the markdownlint panel already filtered to that rule. markdownlint rules only appear in search while the plugin is enabled. The search box stays put while the section list scrolls beneath it.
Patch Changes
-
Version-history recording is dramatically cheaper on large knowledge bases and slow (mounted/network) volumes. The background history snapshot now reuses a persistent git index so unchanged files are no longer re-read and re-hashed on every save cycle (up to ~11x faster tree builds on a 10k-file KB); switching git branches with many open documents batches its bookkeeping into a few git calls instead of four per document (a 100-document switch drops from ~15s to well under a second); and agent writes coalesce into the normal debounced history commit instead of forcing a full commit per write, while history reads still always reflect every completed write.
-
Opening a JSON markdownlint config file (
.markdownlint.json/.markdownlint.jsonc) now offers a toggle between a Source view and a Rules view. Source is the raw, read-only file (comments,extends, and formatting intact); Rules is the same searchable rule browser as Settings — flip rules on or off and edit their options, with changes written back to the file through the format-preserving writer (comments,extends, and trailing commas are preserved). Rule editing targets the project's root config, so a nested or not-yet-created config opens in Source with the Rules option disabled and an explanation. Your Source/Rules choice is remembered per user, separately from the markdown editor's own mode. -
Server-side diagnostics (file watcher, observer bridge, content filter, shadow repo, persistence, rename log, and the rest of the server package) now route through the structured pino logger instead of raw
console.*. Warnings and errors still print in theok startterminal, and every diagnostic now also lands in.ok/local/logs/server-current.jsonl— the file bug-report bundles collect — so watcher drop decisions, symlink-escape refusals, and bridge recovery paths are diagnosable from a bug report even when the server runs detached under the desktop app, where console output goes nowhere persistent. -
Link previews now load for content-heavy pages like GitHub and Wikipedia: the fetcher streams to the end of instead of rejecting once the page body exceeds the 512 KB cap.
-
Copying text from inside a table cell now copies just that text, not the whole Markdown table. Previously, drag-highlighting content in a table cell and copying it yielded the entire table — the
|pipes and the| -- |delimiter row — because the selection's content included the enclosing table structure. A text selection confined to a single cell now serializes to only the cell's content, with its inline formatting (inline code, bold, links, etc.) preserved exactly as it would be when copying the same text from a paragraph, and the table structure dropped. -
Raise the packaged desktop server's V8 old-generation heap limit to 16 GiB. Large projects can now use more memory for collaboration, indexing, and related server work before V8 reports an out-of-memory error.
-
Edits typed while the connection drops are no longer lost when the document recycles
Typing right after the editor lost its server connection (for example after switching windows) could silently destroy that edit: a short debounce timer recycles idle disconnected documents, and it only checked for unsynced edits when it was armed, not when it fired. An edit typed inside that window rode into the teardown; if the server identity changed before the next sync (an app update relaunch does exactly this), the edit was gone permanently. The recycle now re-checks for unsynced edits at fire time and leaves dirty documents alone, and the server-restart recovery replays a preserved edit at content level so it also survives a server identity change instead of being parked as an unresolvable CRDT delta.
-
Pasting bullet lists from rich-text sources no longer inserts blank lines before nested sections
Copying a tight bullet list from a rendered surface (Google Docs, Notion, Slack, ChatGPT, a web page) and pasting it into the editor used to synthesize blank lines between every item and before each nested sub-list, and swapped the bullet markers to
*. The HTML-to-markdown conversion now normalizes the rich-editor DOM shape (paragraph-wrapped list items, nested sub-lists) back to a tight list, and mints the editor's canonical-bullet marker. List items that genuinely contain multiple blocks (two paragraphs, a paragraph plus a code block) still paste as loose lists so their blocks stay separate. -
Local Git-backed workflows now inspect repositories consistently across the
okCLI, Desktop, and the collaboration server. This removes several places where each surface parsed.git,HEAD, refs, and remotes differently.- Linked worktrees now read
HEADfrom the worktree-specific Git directory while reading remotes, refs, and clone-wide excludes from the shared common Git directory. Folder validation, share-receive matching, branch display, andok config-sharingtherefore work the same in a linked worktree as in a primary checkout. - Shadow-repository setup now recognizes the nearest enclosing repository when an OpenKnowledge project is rooted in a subdirectory, while still refusing to promote a repository rooted at the user's home directory.
- Branch and remote inspection now handles loose and packed refs, symbolic refs, SHA-1 and SHA-256 object IDs, relative or absolute worktree pointers, and quoted or commented remote configuration through one shared implementation.
- Missing refs, malformed metadata, stale worktree pointers, inaccessible Git files, and unsafe ref paths are classified separately so sync and branch-watching code can fail safely instead of treating every read problem as a missing branch.
- Branch-switch conflict checks now wait for both Git probes to finish before returning an invalid-target error, preventing a leftover child process from racing repository cleanup.
No configuration or migration is required.
- Linked worktrees now read
-
Add a persistence staleness watchdog that bounds how long CRDT edits can sit unflushed to disk. If a document's in-memory edits ever fail to reach the on-disk markdown (for example after a transient disk error, since the store debounce only re-arms on the next edit), the server now detects the stale file within minutes and re-runs the store through the normal persistence path instead of leaving disk outdated until the next edit. The watchdog never overwrites external edits: any on-disk state the persistence layer has not reconciled makes it stand down and log instead. Three new counters (
persistenceStalenessDetected,persistenceStalenessForcedStores,persistenceStalenessStoodDown) surface these events alongside the existing persistence queue metrics; a sustained non-zeropersistenceStalenessStoodDownrate is the alertable one (unflushed edits pinned in memory would be lost on a restart). -
Copying text from inside quotes, lists, headings, and tables no longer includes the block's markdown syntax or fabricates structure on paste. Drag-highlighting text inside a blockquote, heading, bullet or task list item, code block, or footnote definition previously copied the block's markers (
>,#,-,- [ ], code fences,[^1]:) along with the text, and pasting into Open Knowledge or a markdown-aware app fabricated new structure — a bullet inside a table cell, an extra nesting level from a nested list item, a heading from a heading fragment. Rich-text (text/html) copies of partial selections likewise no longer carry the full block element into destinations like Docs, Notion, or Gmail. Whole-structure copies are unchanged: selecting an entire list, quote, or table still copies its full markdown, and copying the complete text of a single list item still copies it as that item.