OpenKnowledge
Changelog

v0.66.1

Released Aug 29, 2026.

Patch Changes

  • Markdown comments now work when their body contains formatting, and they read as annotation instead of as punctuation.

    A comment written inline in a paragraph, %%note%% or <!-- note -->, was only recognized when its body was plain text. Put anything formatted inside it, bold, code, a link, and the comment stopped being a comment: the %% or <!-- characters showed up as literal prose and the body rendered at full weight alongside the rest of the sentence, so an annotation read as part of the document. The cause was that formatting splits the surrounding text, which left the opening and closing delimiters too far apart for the recognizer to pair them. It now pairs them across the split, in paragraphs, headings, list items, and table cells alike.

    One byte-level consequence, for the HTML form only: a comment written without inner padding re-saves in the conventional <!-- body --> shape, the same way a plain-bodied one always has. The %% form keeps its body verbatim, spaces included.

    Recognition stays deliberately narrow. A paragraph, heading, or table cell carrying more than one candidate pair (its several lines share one budget), an escaped delimiter, a pair inside a code span, or a mid-sentence body that is nothing but a single formatted word is left as prose rather than guessed at, because claiming one of those would rewrite what you wrote the next time the file saved.

    The editor no longer prints the delimiters. A comment used to carry a literal %% or <!-- on each side, and a standalone comment block carried a small marker naming it, so a paragraph with a few annotations in it was hard to read past the punctuation. Nothing else in the editor shows its own syntax: bold, code, and links all keep theirs out of the page. Comments now do the same. An inline comment is dimmed and italic under a dashed underline; a comment block is dimmed with a dashed left rail, which is what distinguishes it from a blockquote's solid one. The underline matters beyond decoration: without it a comment differed from ordinary emphasis by colour alone, and a reader who could not resolve that difference could publish text they meant to hide. The text itself is never hidden, because the same syntax can appear in prose you never meant as a comment. Source mode still shows the raw bytes, and that is where the delimiters are edited.

    On the choice to stop drawing them: Obsidian, whose %% syntax this is, does show the markers in its Live Preview — comments are the one exception to that mode's hide-the-syntax rule, and its users routinely add CSS to hide them. Obsidian reveals syntax near the cursor, which OpenKnowledge's block-canonical editing surface cannot replicate; a cursor-proximity reveal was tried here and set aside as too fidgety, so it is a not-now rather than a never. Reading views in both tools hide comments entirely.

    A related fix rides along in the ==highlight== recognizer, which had the same defect: a highlight whose body contained formatting dropped backslash escapes from the prose around it, and an escaped \== pair following one was claimed anyway. Both now hold.

    Readers were never affected: wherever a document renders to HTML rather than to the editor, both forms come out as real HTML comments, which browsers do not display.

  • Fixed openknowledge:// deep links (used by ok open, ok <file>, and shared links) sometimes opening a blank, unbranded Electron window instead of the OpenKnowledge desktop app.

    This happened when a development build of the desktop app had run on the machine at some point and registered itself as the handler for openknowledge:// links, then exited without cleanly unregistering — for example, if the process was killed rather than quit normally, or its checkout was later deleted. macOS kept routing links to that no-longer-valid registration instead of the installed app. The desktop app now re-claims its link handling every time it starts, the same way it already did on Windows and Linux, so a stale registration from an old development run gets corrected automatically the next time you open the app.

    On macOS, ok open and ok <file> no longer depend on that registration being correct in the first place: when a desktop install is found, they open it by its exact file-system location rather than asking macOS to figure out who owns openknowledge:// links, so they keep working even if a stale registration exists and the app hasn't been opened yet to repair it. Windows and Linux still resolve the link through the OS's own registration and rely on the per-boot repair above; making them equally independent of that resolution is tracked as a follow-up.

    Also worth knowing if you're developing the desktop app itself: a development instance still claims openknowledge:// machine-wide on macOS while it's running (needed so open openknowledge://... reaches the dev build during local testing), and now competes with the packaged app's own per-boot repair for the same registration — whichever one started most recently wins. A browser-clicked link between an unclean dev-mode exit and the next time you launch the installed app by hand may briefly reach the wrong place; opening the installed app once corrects it.

  • OpenKnowledge's user-global skills now install for LM Studio. LM Studio reads Agent Skills from ~/.lmstudio/skills, listed as Bionic Skills in its agent mode, but OpenKnowledge treated it as an MCP-only host, so skills were never written there and the Skills panel never listed anything installed under it. Installing a tool that reads the shared .agents/skills folder now makes that folder available as a skill destination. Two tools read it: LM Studio reads it for project skills rather than a .lmstudio/ folder, and OpenClaw reads it at user scope, so an OpenClaw user will see a ~/.agents/skills row appear too. OpenKnowledge previously offered the folder only once a project already used it, so the only way to make the first placement was to type the path into Add custom path. The folder stays neutral: it appears because something on your machine reads it, is never preselected, and carries no per-tool marks. It is offered as a destination but not as a merge target until it exists, so accepting an offer never creates the folder behind your back or relocates skills into it. With neither tool installed, nothing changes.

  • Back off pulls and pushes independently, and make the sync panel's file list readable at scale.

    Auto sync kept a single count of recent failures. Both loops added to it, but only the pull loop read it, and only a successful pull could clear it. A push that kept being rejected therefore stretched the interval of the very loop it defers to when its own retry is exhausted, and a push that recovered left the count standing until a pull happened to run. Each direction now keeps its own streak: 3 consecutive failures hold the next attempt for at least 5 minutes, 5 for at least 15, and 8 for at least an hour — floors rather than replacements, so a configured interval longer than the tier is never shortened to it. (Pull already had this ladder but applied it as a replacement, which could speed a slow interval up; it is now a floor there too.) The two counters are independent — push failures do not slow down pulls and vice versa — and either counter resets immediately on a manual trigger or on a success in that direction. Saving state written by an earlier version still restores its pull backoff.

    A push does not check for updates first — it sends, and reconciles only if the remote turns it back. Checking less often than you push therefore leaves each push to discover the remote moved and catch up before it can land, which costs nothing on a repository nobody else writes to and adds a round trip on every push when someone does. The sync settings note this where the two intervals are chosen, in Auto (Pull and Push) and only when the push interval is the shorter of the two. It is a note, not a restriction: fast pushes with slow update checks remain a reasonable setting for a repository you are the only author of.

    The panel listed every changed path as its own row, up to a hundred per section, each clipped at the end to fit. On a real working tree that produced a column of near-identical strings — every row showing the same visible prefix, with the filename that distinguished it cut off — and a panel tall enough to push the sync controls off screen. Paths are now grouped by folder, with the directory stated once in a group header and the rows carrying only what is left of the path. A directory shared by everything in a section is lifted out and stated once above the list. Sections start collapsed with their file count in view; folders holding a single file stay as plain rows rather than costing a click, and a long group shows its first few rows with the rest one click away. Hovering a row gives its full path, and a folder header its untruncated directory, and the list scrolls within its own bounds so the mode selector and the Pull and Push buttons stay put.

View v0.66.1 on GitHub