Skip to content

v0.45.0

Latest

Choose a tag to compare

@inkeep-internal-ci inkeep-internal-ci released this 30 Jul 17:40

Minor Changes

  • Blank lines you type in the visual editor now stay where you put them. Previously the editor showed the space while you were typing and then quietly took it back — switching to markdown source and returning, reloading the page, or a teammate opening the same document all collapsed a run of blank lines down to one.

    Before After
    Press Enter three times, reload — one blank line Press Enter three times, reload — three blank lines
    The file on disk kept your blank lines, the editor did not show them The editor shows what the file actually contains

    This covers blank lines between top-level blocks, which is where they come from when you press Enter. Two places still collapse them, both deliberately: runs at the very top or very bottom of a document, and runs inside a list, a quote, or a table cell — where CommonMark treats the blank line as meaningful structure rather than space. Nothing new is written into your files: no &nbsp;, no <br />, just the newlines that were already there.

    Worth knowing: blank lines still render as nothing when a document is published to GitHub or any other CommonMark renderer. This makes the editor honest about your file, it does not add vertical space to published output.

  • Keep your place when switching between the visual and Markdown editors. Toggling
    modes now keeps the block you were looking at in view in both directions instead
    of dropping you at an unrelated scroll position, and a plain toggle no longer
    disturbs either editor's own selection.

    Add a View in source action that jumps from the visual editor to the exact
    Markdown behind what you're looking at — centered, briefly highlighted, with the
    caret placed ready to edit. Reach it from the selection bubble menu, the desktop
    editor right-click menu, or the keyboard: ⌥⌘M toggles between visual and
    source, and ⌥⌘E opens the source for the block at the caret. The highlight
    respects your reduced-motion setting.

    Landing is honest about uncertainty rather than confidently wrong. If the
    document changes underneath a pending jump, or a block cannot be matched exactly,
    it settles on the nearest enclosing block and drops the highlight instead of
    guessing. Long documents keep working: the landing waits for the incoming editor
    to actually render, re-aims itself if content shifts while it settles, and gives
    up cleanly rather than fighting the page.

    Explicit navigation always wins over a mode switch that is still settling.
    Clicking a Problems-panel row, an outline entry, or a find/replace match takes
    you there even immediately after a flip, and the composer's scroll-to-bottom no
    longer pulls you off a landing.

  • Underline is now a real, savable format. The bubble-menu Underline button and Cmd+U have always been there, but nothing wrote the result to disk: the underline vanished the moment the document was saved, reloaded, or opened by a teammate. Underlined text pasted in from Word arrived as italic instead.

    Before After
    Cmd+U, reload the page — underline gone Cmd+U, reload the page — still underlined
    Paste underlined text from Word — comes in italic Comes in underlined
    Paste underlined text from Joplin or Logseq — formatting dropped Comes in underlined

    Underline is written as <u>text</u>, the same thing Typora, MarkText and Obsidian write, so files stay readable and portable. Documents that already spell it <ins>text</ins> — what Joplin and Logseq produce — are read as underline too and keep that spelling when saved, so importing a vault does not rewrite it under you.

    Worth knowing: markdown has no underline of its own, so this is HTML inside your file. It renders as underline in OpenKnowledge, in a published site, and when pasted into Word, Docs or Gmail. GitHub is the exception — it strips <u>, so the text shows up unformatted there. Files that use <ins> do keep their underline on GitHub.

    Underline can be combined with bold, italic, strikethrough and inline code on the same text.

  • Edits typed while something else is rewriting the same document no longer disappear. The bridge between the visual editor and the raw markdown behind it gained four safety nets, all default-on: a defer guard that holds back a rebuild which would overwrite a keystroke that has not propagated yet, a pre-drain flush that pushes a pending non-overlapping keystroke into the document before an agent write or undo rebuilds it, a loss detector that spots content dropped at the reconciliation boundary, and a fixed-point backstop that freezes a rebuild loop which oscillates instead of settling. The practical effect: typing through an agent write, a git pull that lands on the open document, or a same-second edit from a second window is far less likely to cost you a line.

    • Anything a safety net cannot save in place is written to a recovery checkpoint, and those checkpoints now appear in the Timeline as ordinary "Recovered content" versions you can preview and restore like any older version. Before this release the same checkpoints were written but reachable through no API and invisible in the UI, so rescued content was effectively lost anyway.
    • Undo in source mode is now a single origin-aware system. Cmd/Ctrl-Z undoes only what you typed, never a collaborator's or an agent's write. Previously CodeMirror's own history could revert content you never wrote.
    • Unsynced work survives more of the browser lifecycle: a tab flushes to the server when you switch away and resyncs when you come back, edits captured during a server-instance recycle land in a durable IndexedDB outbox so a tab crash mid-recycle no longer drops them, and a worker-homed presence heartbeat keeps a backgrounded tab from being pruned as offline by its peers. In the desktop app, a window holding unsynced work opts out of Chromium's background throttling until it is clean.
    • New project config leaves, each a kill-switch defaulting to on: bridge.deferGuard.enabled, bridge.preDrain.enabled, bridge.lossDetector.enabled, bridge.fixedPoint.enabled, bridge.flushOnHide.enabled, bridge.backgroundThrottle.enabled. Turn one off only to isolate a suspected regression.
    • New lossCapture.enabled and lossCapture.maxBytes config leaves plus a local event ring at .ok/local/loss-capture/ (roughly 12 MB before it rotates). It records which safety net fired, on which document, and when, and it is content-free by schema: a byte length and a digest, never document text. Nothing leaves your machine until you run ok diagnose bundle; set lossCapture.enabled: false for a sensitive workspace.

Patch Changes

  • Version history that a consolidation had folded away could be destroyed by routine checkpoint cleanup. Consolidation picked the single newest checkpoint to chain onto, without regard to what kind it was. The silent rescue checkpoints written when the editor bridge detects content loss are parentless, so whenever one of them happened to be newest, the new consolidation chained onto a dead end and the previous consolidation was left dangling. The next cleanup pass then deleted that dangling checkpoint's ref, and with nothing else pointing at it, its full content snapshot and every edit it had folded in became unreachable and were lost at the next git garbage collection. A same-second pair of consolidations could fork the chain the same way with no rescue checkpoint involved at all.

    Consolidation now adopts every dangling anchor rather than the single newest one, and only checkpoints whose retention cannot be emptied are eligible to anchor. Cleanup is non-destructive again. Two side effects of the old behavior are also fixed: a rescue checkpoint is no longer kept alive forever by being chained onto, so the retention budget that expires it now genuinely does, and the per-document activity history no longer goes silently empty after a rescue checkpoint lands following a consolidation.

  • Clicking Edit next to a frontmatter schema in Settings now reliably opens the Fields editor. Previously it could drop you on the read-only Source view instead, which was especially confusing when the schema was already the file open behind the Settings dialog, and the ignored request could then send you to Fields the next time you opened that file when you had asked for Source. Edit now takes effect whether or not the schema is already open.

  • On Windows, a project inside a git repository now correctly places .ok/ at the repository root when the path contains a shortened folder name. Windows keeps a legacy short alias for most long folder names — C:\Users\alexandra is also reachable as C:\Users\ALEXAN~1 — and the two spellings point at the same folder but read as different paths. OpenKnowledge compared the shortened form against the long form that git reports, concluded the repository was outside your home directory, and quietly skipped the promotion, leaving .ok/config.yml in the sub-folder you picked instead of at the repository root. Both spellings are now resolved to the same canonical path before the comparison, so the repository root is used as the project root as intended. Unaffected on macOS and Linux, which have no such aliases.

  • Sharing a folder with no documents in it now says so plainly instead of promising the link will work after the next sync. Git has no way to represent an empty folder, so the minted link 404s for the recipient and no push would ever fix it — but the share popover offered "Enable auto-sync", "How to push manually" and "Sync now", and running a sync turned the warning into "Synced. The link is up to date." over a link that still went nowhere. The popover now shows a warning naming the only real remedy, adding a document, and offers no sync buttons at all. The share_link MCP tool relays the same sentence to agents rather than the push advice, and the freshness signal on POST /api/share/construct-url gained an empty verdict so the two cases are also tellable apart in the logs. Folders that genuinely just need a push are unaffected, and a doc reports exactly as before at any size, including zero bytes.

  • Show comment annotations dimmed in the editor instead of hiding them.

    Text that looks like comment syntax (<!-- note -->, %%note%%) is claimed by
    the comment promoter the next time a document is re-derived. The resulting
    comment mark and comment block rendered display: none, so prose a user typed
    as ordinary text disappeared from the editor while the bytes on disk stayed
    intact, with no way to recover it from the WYSIWYG.

    Comments now render dimmed in the editing surface, with the delimiter form shown
    alongside the body and a dashed rail plus gutter marker on the block form so it
    reads as annotation rather than as a blockquote. The app's read-only views that
    mount the editor schema (skill viewer, rendered diff) show comment bodies dimmed
    too; only fully rendered markdown output still hides them, as literal HTML
    comments. Comments are still dropped from cross-app clipboard payloads, and
    bytes are untouched in both directions.

    To turn an annotation back into ordinary text, edit the delimiters in source
    mode (Cmd+/) — backslash-escaping either delimiter (\%\%) keeps the run as
    prose. There is no WYSIWYG control for this yet.

  • Two more places where the editor could replace what you had open with the copy on disk now leave a restorable version behind first.

    The first is a conflict between an agent and something else writing the same file. When an agent saves a document that another program changed underneath it, the copy on disk wins — that part is correct and unchanged, and the agent is still told its write did not land. But the open document was replaced outright, and anything you had typed into it that had not saved yet went with it, silently and with no way to undo. The second is the same situation for a skill or template edited from two places at once.

    Both now write a recovery checkpoint of the open document before replacing it, so what you had is restorable from version history, and both record the event so it shows up in a diagnostics bundle rather than disappearing without trace.

  • Stop two typed editor states from losing content on the next re-derivation.

    A hard break typed at the end of a block (Shift+Enter) was dropped at serialize time, so the break vanished with no trace in the bytes and none in the view. It is now re-spelled to <br />, the same lossless spelling the serializer already uses inside table cells and headings.

    An empty task item lost its checkbox and came back as a plain list item whose text was the literal [ ], at every position in the list. GFM cannot spell a task item with no content, so an empty one now serializes with a &#x20; the parse side takes back out, and the checkbox round-trips.

  • Screenshots attached to a bug report now show up in the report itself, instead of only inside the downloadable diagnostic bundle. Anyone triaging a report sees the picture immediately rather than having to download a zip and unpack it to find out what the reporter was looking at.

    Before After
    Report says a screenshot was included; nothing visible The screenshot is displayed in the report
    Triager downloads the bundle and unzips it to see anything Nothing to download for a look at the screen

    This was supposed to work already, and never did once. The intake tried to pull the screenshot out of the bundle after the upload, but the storage the bundle lands in refuses that read, so the step failed silently on every single report and the screenshot was quietly left out. The app now uploads the screenshot alongside the bundle rather than expecting the server to dig it back out, which removes the failing step entirely.

    Two things worth knowing. This takes effect for reports sent from this version onward, because the app is what supplies the screenshot now — reports already filed are unaffected. And re-sending a report from the report list in a later session sends it without the inline screenshot, since the capture is no longer in memory by then; the screenshot is still inside the bundle in that case.

    Unchanged: the screenshot is still opt-in via the checkbox in the report dialog, still previewed before you send, and unchecking it still means no screenshot leaves your machine.

  • Fix multiple self-closing MDX JSX tags on the same paragraph collapsing to text. The R23 autolink/void-HTML guard classified any <X… as self-closing when the paragraph contained any />, so A <Foo />, B <Bar />, C <Baz />. promoted every < up to the last one and lost the intermediate tags. It now decides self-closing per-tag by scanning that tag's own contents (quote- and brace-aware), skipping < characters that fall inside another uppercase tag's attribute region. Orphan uppercase openers stay guarded; quoted > / /> and <X> inside JSX expression braces round-trip cleanly.

  • Keep backlinks, graph data, and tags consistent across every document lifecycle path. Direct creates and duplicates, disk reconciliation, deletes, folder renames, project-skill moves, ignore-file changes, startup, and branch switches now pass through one ordered derived-index coordinator with shared admission, readiness, persistence, and invalidation rules.

    Derived-view queries wait for startup and branch replacement to settle instead of observing a partially rebuilt index. Rapid consecutive branch switches are serialized so one transition cannot release another transition's barrier.

    Durable creates, duplicates, renames, deletes, and persistence stores now return according to authoritative disk state. Derived projection and cache persistence remain best-effort, so coordinator shutdown or a delayed cache save cannot turn an already successful write into a failure.

  • Fix the outline not following your scroll position in Markdown source mode

    The outline pane now highlights the heading you are reading while you scroll the Markdown source view, the same way it already did in the rich-text view. The position marker, the highlighted row, and the row's accessibility state all keep up as you scroll, and clicking an outline row leaves that heading highlighted once the view settles.

    Headings written with Windows line endings are also recognized now. Previously a document saved with CRLF line endings produced an empty outline.

  • The Problems panel now offers a Fix all with AI button beside the deterministic fixer, in both the document and project scopes. It hands the whole scope to your preferred AI agent as one instruction, pointing it at the audit tool for the current list of lint violations and broken links and at lint with fix: true for the mechanically-fixable subset, so the agent reads live truth rather than a snapshot taken when you clicked.

    The deterministic button is now labelled Auto-fix rather than "Fix all", and both buttons explain themselves on hover. Previously a document whose problems had no automatic fix showed a single disabled "Fix all" with nothing to say for itself, which read as a bug rather than as "these need judgement"; now the AI action sits next to it, enabled, and the disabled Auto-fix says why it is off.

  • The Problems panel now names the validator behind each finding instead of tagging every row LINT — a frontmatter-schema failure reads FRONTMATTER and a markdownlint rule reads MARKDOWNLINT, so the two are distinguishable at a glance (the chip carries the producer, so the line below it now shows the bare rule code). Repeated findings collapse into one row with an instance count ("Frontmatter property is missing · 10 instances") that expands to the individual lines, each keeping its own Fix and Ask AI actions, instead of burying the rest of the plane under identical rows. The project-scope refresh icon finally explains itself on hover.


Also included: 0.42.2 through 0.44.0

These versions were tagged and built but never published — their release automation was blocked by a fault in the release pipeline itself, not by anything in the code. The changes shipped here in 0.45.0. Their notes are reproduced below so nothing that reached you is left undescribed.

v0.42.2

Patch Changes

  • Make the Report a bug dialog wider so report details, diagnostic options, and screenshot previews are easier to review.

v0.42.3

Patch Changes

  • Agents started from the desktop app now launch even when their CLI was installed through a JavaScript package manager's global bin (pnpm, bun, Volta, Yarn, or npm's user prefix). A desktop app opened from the Dock or Finder inherits a minimal PATH that omits locations like ~/Library/pnpm and ~/.bun/bin, so an agent such as Pi that ran fine in a terminal would fail to start with a "command not found" error. Agent and terminal launches now append the well-known tool directories and package-manager global bins to PATH — the same approach already used for git — so these agents start correctly. When a command still can't be found, the error now explains that Dock/Finder-launched apps don't see your shell's PATH.

v0.42.4

Patch Changes

  • Fixed a crash that could take the whole editor down to the "Something went wrong" screen during navigation — most visibly right after creating a new file, and also when a document was renamed, deleted, or moved out from under an open tab. The editor tracked its open-document pool with a value that was rebuilt from scratch on every pool change, including changes that altered nothing you could see, such as re-opening a document that was already open. Each rebuild re-rendered the app shell and handed the navigation layer a fresh set of callbacks, which prompted it to re-open the document again. When a document's identity changed underneath that cycle, it fed itself until React aborted the render with "Maximum update depth exceeded". The pool value is now reused when nothing observable has changed, so the cycle can no longer close.

v0.43.0

Minor Changes

  • Enter inside a table now works the way it does in Notion and Obsidian: it moves the cursor to the same column of the row below, and from the last row it creates a new row — so you can fill a table top to bottom without touching the mouse. Enter no longer splits a cell into multiple paragraphs (which markdown tables can't represent and used to resolve unpredictably); Shift+Enter is the way to get a line break inside a cell.

  • The slash menu now has an Emoji entry — type /emoji (or just /:) and an emoji picker opens right at your cursor, with search. Picking one inserts it as plain text, so it round-trips through markdown untouched.

  • Edits typed while something else is rewriting the same document no longer disappear. The bridge between the visual editor and the raw markdown behind it gained four safety nets, all default-on: a defer guard that holds back a rebuild which would overwrite a keystroke that has not propagated yet, a pre-drain flush that pushes a pending non-overlapping keystroke into the document before an agent write or undo rebuilds it, a loss detector that spots content dropped at the reconciliation boundary, and a fixed-point backstop that freezes a rebuild loop which oscillates instead of settling. The practical effect: typing through an agent write, a git pull that lands on the open document, or a same-second edit from a second window is far less likely to cost you a line.

    • Anything a safety net cannot save in place is written to a recovery checkpoint, and those checkpoints now appear in the Timeline as ordinary "Recovered content" versions you can preview and restore like any older version. Before this release the same checkpoints were written but reachable through no API and invisible in the UI, so rescued content was effectively lost anyway.
    • Undo in source mode is now a single origin-aware system. Cmd/Ctrl-Z undoes only what you typed, never a collaborator's or an agent's write. Previously CodeMirror's own history could revert content you never wrote.
    • Unsynced work survives more of the browser lifecycle: a tab flushes to the server when you switch away and resyncs when you come back, edits captured during a server-instance recycle land in a durable IndexedDB outbox so a tab crash mid-recycle no longer drops them, and a worker-homed presence heartbeat keeps a backgrounded tab from being pruned as offline by its peers. In the desktop app, a window holding unsynced work opts out of Chromium's background throttling until it is clean.
    • New project config leaves, each a kill-switch defaulting to on: bridge.deferGuard.enabled, bridge.preDrain.enabled, bridge.lossDetector.enabled, bridge.fixedPoint.enabled, bridge.flushOnHide.enabled, bridge.backgroundThrottle.enabled. Turn one off only to isolate a suspected regression.
    • New lossCapture.enabled and lossCapture.maxBytes config leaves plus a local event ring at .ok/local/loss-capture/ (roughly 12 MB before it rotates). It records which safety net fired, on which document, and when, and it is content-free by schema: a byte length and a digest, never document text. Nothing leaves your machine until you run ok diagnose bundle; set lossCapture.enabled: false for a sensitive workspace.
  • GitHub-style <div align="center"> wrappers now render the way GitHub shows them: the tag lines disappear and everything between them — headings, text, badge images — actually centers (left/right/justify work too). The content inside stays fully editable, and the <div align> markdown is preserved byte-for-byte on disk. Divs with other attributes keep their literal rendering.

  • Stop recovery-checkpoint cleanup from discarding the newest rescue point. Checkpoints written in the same second could not be ordered by their timestamps, so the sweep picked which one to drop essentially at random and could keep an older copy while permanently deleting the most recent one. Because loss-hardening writes one checkpoint per open document in a burst, the discarded copy could be a document's only recovery point. Cleanup now keeps every checkpoint it cannot confidently order, so it may hold slightly more than the retention budget rather than destroy the wrong one.

    Correct the Source editor entry in the keyboard shortcut help. It advertised undo-selection shortcuts that source mode does not have; those shortcuts still work in the code block editor and in code-shaped property fields, and are now listed there instead. Redo shortcuts are unchanged and continue to work on every platform.

  • Documents no longer get permanently stuck offline after the server restarts. Previously, if the restart took more than a couple of seconds, an open document could land in a state where it reconnected forever without ever syncing: the banner said "Connection lost, keep this tab open, your edits will sync when reconnected", but nothing it promised was going to happen. Switching to another document and back did not help, and anything typed while stuck was lost on reload. The client now treats a restarted server the same way whichever way it finds out about it, so the affected documents recover on their own and the edits typed during the outage are replayed instead of dropped.

Patch Changes

  • Fix the editor's main content being squeezed into the top of the pane with a large empty band below it. The bottom sessions dock could be left holding space while hidden and showing nothing, and its drag handle is disabled while hidden, so there was no way to reclaim the space. The dock now collapses whenever it reports a size while hidden, so that state can no longer persist, and it records a diagnostic when it has to repair itself so a recurrence leaves a trace. Separately, the dock's height is re-clamped to at most half the window whenever the window is resized — previously a height chosen on one display kept its old ceiling after a move to a smaller one.

  • Fix bold, italic, and other formatting being dropped from wiki links, images, inline math, tags,
    and line breaks.

    Formatting applied to an inline element was lost as soon as the document round-tripped through the
    collaboration layer. Writing **[[Page]]** in source mode, in the editor, or through the agent API
    produced [[Page]] on disk, and the emphasis could not be re-applied because it was discarded
    again on the next sync. A soft line break inside bold text split it into two separate bold runs.

    Before After
    **[[Page]]**[[Page]] **[[Page]]****[[Page]]**
    *![alt](img.png)*![alt](img.png) *![alt](img.png)**![alt](img.png)*
    **a<br>b****a**<br>**b** **a<br>b****a<br>b**

    This affects [[wiki links]], images, image references, footnote references, inline math, tags,
    inline JSX, and hard line breaks.

    Documents already saved without their formatting are not repaired automatically — the formatting
    has to be applied again. If you run multiple clients against one server, update them together:
    an older client editing a document alongside an updated one will strip the restored formatting.

  • The Default tile in Settings → Plugins → Themes now previews its own colors instead of borrowing the palette you currently have selected. Picking Dracula used to repaint the Default preview in Dracula's colors, so the grid gave you no way to see what switching back would actually look like. The Default tile now shows the app's own light or dark palette, following your light/dark preference, whichever theme is active.

  • Frontmatter schema settings are now just the on/off toggle.

    The Modified badge and the Reset-to-default button are gone. Both described the config file rather than the schema: "Modified" meant only "config.yml maps this file", on or off, and Reset removed that mapping. Neither is something you need a model of to decide whether a schema should validate your docs, and in practice the words did the opposite of explaining themselves. Reset in particular read as "refresh", so pressing it to reload the panel silently discarded every glob you had written. The Only modified filter went with them, since the concept it filtered on no longer appears anywhere in the surface. Search still narrows the list.

    Your globs are always kept. Turning a schema off leaves its appliesTo patterns in place, so turning it back on restores exactly what you had. The toggle never discards a mapping. If you want a schema out of config.yml entirely, edit the file — or delete the schema, which removes the file and its mapping together.

    Shorter delete confirmation. Deleting a schema no longer adds "Docs it validated keep their frontmatter; they just stop being checked." Nobody expected deleting a schema to rewrite their documents, so the reassurance mostly introduced the doubt it was trying to settle.

  • Bug reports sent from the desktop app now carry the evidence needed to diagnose an editor crash. Two pieces were missing. First, the detailed-diagnostics report is meant to be a superset of the basic one, but it was leaving out the app's own log file — the one the desktop app writes the editor's console messages into. Basic reports included it, detailed ones did not, so the most thorough report was the one that dropped the crash trail. Second, when the editor hit an error, the report recorded the error message but not React's component stack, which is the only part of a crash that still names real parts of the app in a released build; without it, a crash report read as a string of meaningless letters and numbers. Reports now include both, so a crash can be traced without asking you to copy anything out of a developer console by hand. Secrets in the newly included log are redacted the same way as everywhere else, and the component stack is trimmed to its most relevant frames.

  • Keyboard shortcuts no longer fire underneath an open dialog, command palette, or menu. Pressing ⌘T with the ⌘K palette up opened a new editor tab behind it, and the same leak affected ⇧⌘T, ⌃Tab, ⌘1–⌘9, ⌘L, ⇧⌘J, ⌘F, ⌘G, ⌘Z and ⌘⇧I — these are registered on the window, most of them in capture phase, so an overlay had no way to stop them from underneath. Every app-global shortcut now declines while a layer that owns the keyboard is open. Escape likewise dismisses only the topmost layer instead of also collapsing the graph panel or closing a diff pane behind it, and ⌘K no longer stacks the palette on top of another dialog while still dismissing the palette when it is the top layer. Editing keys the app never claimed — copy, paste, cut, select-all, undo, and arrow/Enter navigation inside the overlay — are untouched, and a hover-opened link panel no longer counts as owning the keyboard, so shortcuts keep working while the pointer rests on a link.

    On the desktop app, ⌘N, ⌘,, ⌥⌘S, ⌥⌘B and ⌘J arrive as native menu accelerators rather than as renderer key presses, so they can still fire while an overlay is open; those five are fixed in the browser only.

v0.43.1

Patch Changes

  • Pasting a copy of an entire document no longer makes the paste disappear. Selecting all, copying, and pasting produces a document that is an exact doubling of what was just saved, which is the same shape a stale browser cache produces when it merges an old copy back in. The persistence guard that watches for that corruption could not tell the two apart, so about two seconds after the paste it refused to save and rolled the open document back to the copy on disk. The pasted content vanished from under the cursor, and undo could not bring it back because the rollback arrives as a remote change that neither the server nor the editor tracks as undoable.

    The guard now distinguishes the two cases by when the doubling appears. A stale-cache merge shows up as soon as the document syncs, before the session has saved anything; a paste is an edit on a document that has already saved cleanly. Pastes are left alone and save normally. When the guard does still act on a genuine corruption, it now writes a recovery checkpoint of the pre-rollback document first, so that version stays restorable from version history instead of being lost.

v0.44.0

Minor Changes

  • Serve your knowledge base's MCP endpoint to your other devices through any HTTPS tunnel — ngrok, Cloudflare Tunnel, Tailscale, or a reverse proxy: run the tunnel against the stable remote port (default 24550, remote.port to change) and start the server with ok start --remote <url> (or set remote.url in .ok/config.yml and pass a bare --remote). The model is trust-the-tunnel: OpenKnowledge does not authenticate remote callers — anyone who can reach the tunnel URL has full read-write access, and restricting reach is the tunnel's job (private tailnet, ngrok OAuth, Cloudflare Access). The trade is always explicit: remote access is armed only by the --remote flag (never by config alone), every remote start prints a warning banner, and a server started without the flag refuses tunneled requests with a fix-it hint instead of serving them. The web UI is served from the same tunnel URL (/ = editor, /mcp = MCP — one port, one tunnel; browse and edit from your phone). Its collaborative surfaces work over the tunnel too: live editing and the Ask AI panel, which runs an agent on the machine hosting the server (using that host's own agent and credentials). Wrong-Host requests (DNS rebinding) are refused everywhere. Local loopback behavior is unchanged.