v0.62.0
Minor Changes
Agent threads now deliver Open Knowledge tools more reliably across ACP agents, and pi gets them for the first time.
- pi agent threads: Open Knowledge has always integrated with pi through its extension system rather than MCP. Starting a pi thread in a project that isn't wired yet now offers a one-tap consent card that installs the bridge extension and marks the project trusted in pi. The card spells out what approving commits you to — pi folder trust covers every extension in the folder, not only Open Knowledge's, and it names any other extensions already there — and both the extension and the trust entry stay until you remove Open Knowledge from the project, which now also revokes the trust entry. Declining leaves the thread fully usable without Open Knowledge tools; reopening that thread won't re-ask, but the next pi thread will.
- Cursor agent threads in a wired project got no Open Knowledge tools at all: Cursor requires separate approval for a configured MCP server, so a configured entry there is not a loaded one, and Open Knowledge was standing down on the assumption that it was. It now always injects for Cursor.
- The MCP server entry handed to agents over stdio now uses an absolute command path and carries the same
PATHthe agent itself was launched with, fixing silent tool absence under agents that launch MCP servers with a stripped environment, or when the app was started from the Dock with a minimalPATH. - Threads whose agent ends up with no Open Knowledge tool transport at all now log a warning instead of failing silently, and the server records which delivery channel each session's injection landed on.
Title bug-report history rows by what was reported.
A history row used to say what state its send was in, never what the report was about. Two reports filed the same afternoon rendered as two identical cards separated only by a timestamp. Rows are now titled by the first useful line of the note that went with the report, with the send-state badge kept on that same line and the bundle level, timestamp, size, reference and failure reason collapsed into one secondary line beneath it. The rows are also a real list now, so a screen reader announces one item per report and reads each row's title first.
Retrying a report from history now includes your note. Earlier retries silently dropped it, so a resend reached us with the reporter's own words missing, and the email draft it falls back to named the file to attach but not what had gone wrong. Both now carry the note the original send did.
Making that work meant saving the note locally for the first time: a redacted copy is written alongside the report when the bundle is created, so it survives the send that deletes the bundle. Reports generated before this update have no saved note, so they fall back to a project-based title, or to "Untitled report" when the report is not tied to a project (a system-wide report, or one made with
ok bug-report).The desktop app now runs on Electron 43, moving off a runtime that reaches end of life and picking up two majors of upstream Chromium and Node fixes.
Three known behavior changes come with it.
On every platform, file and folder pickers now open in your Downloads folder rather than wherever you last browsed. The runtime no longer restores the last-used directory between pickers, so Open Folder, Open file, and the project pickers all start there until you navigate away.
On Linux only — macOS and Windows are unaffected:
- Dragging the divider to resize the terminal when it is docked to the right collapses the column instead of resizing it. Moving the terminal between the bottom and right docks still works, and so does resizing on the other platforms. If you hit it, move the terminal to the bottom dock.
- Pickers no longer start with hidden files and folders visible, so a dot-directory such as
.claude/worktreesis not shown until you navigate to it yourself. The runtime dropped the option this relied on, because the desktop environment now treats that visibility as the user's choice rather than the app's.
New projects now keep their OpenKnowledge config to yourself by default. Setting up a project asks whether to share that setup with your team, and the answer now starts at Only me, so
.ok/,.mcp.json, and the project skills are written but excluded from git until you choose to share them. Previously the answer started at Shared, which meant a user who never opened the setting committed their config by omission.This applies to both entry points.
ok inituses the new default when it is scaffolding a project for the first time; re-running it on a project that already has.ok/keeps whatever posture that project is in, so a scripted re-run cannot un-share a team's repo. The desktop app's setup dialogs pre-select the same option, and both still take an explicit answer:ok init --shared(or--local-only), the prompt in an interactive terminal, or the radio cards in the dialogs.If you rely on a committed
.mcp.json— Claude Code's cloud routines do, since they run against a fresh clone and see only what is committed — choose Shared during setup, or runok config-sharing shareafterwards.ok config-sharing statusprints the mode a project is in and the paths it excludes.
Patch Changes
In-app agents are no longer marked Beta, and the native File → Open with AI menu item now picks the same agent every other launcher does. That menu item used to jump straight to the first installed external app, so it could open a different agent than the sparkle menu right beside it; it now goes through the shared launcher selection — your saved choice first while it is still enabled, otherwise an in-app agent, then a terminal CLI, then an external app. Terminal and external apps remain available everywhere they were, and an explicitly chosen one stays chosen. The Beta badge and the "In app (beta)" screen-reader label are gone from the agent menus and from Configure agents; the unrelated beta-channel and plugin Beta markers are unchanged. Editor and getting-started documentation now describes the in-app route and the current menu order instead of the old installed-app default.
OpenKnowledge now suggests Codex in the agent picker when you are already signed into Codex Desktop, even if you have never installed the
codexcommand line tool. Previously the only thing that could put an agent in the "In app" list unprompted was finding its CLI on your PATH, which meant a Codex Desktop user saw no Codex row despite having everything needed to use it — the adapter brings its own runtime, and Codex Desktop and the CLI share the same sign-in. The catalog now reports an existing sign-in as a second, independent signal alongside the PATH check, and either one is enough.The signal only ever adds an agent to the list, never removes one. Not finding a sign-in means nothing, since Codex can keep credentials in a system keyring with nothing on disk to find; and finding one is not proof the session still works, since an expired sign-in stays on disk until you run
codex logout. So a suggested agent may still ask you to sign in. Agents you have turned on yourself are unaffected, as always.Documentation: the editor's agent-handoff reference now matches the picker that ships. It names the External apps rows as they render (Claude Desktop, ChatGPT Desktop, Cursor Desktop), says that the terminal tab strip's + dropdown both switches what a new tab starts and opens one, and states how detection and Configure agents combine — detection supplies each section's default, including In app, and Configure agents overrides that default in both directions. No behavior changed.
Agent thread settings now survive archiving and resuming. Picking up an archived conversation started a fresh agent session on the agent's own defaults, so a thread you had set to a particular model quietly went back to answering on a different one while the settings menu still showed your choice. The settled model, reasoning effort, and mode are now captured before the resume response overwrites them and re-applied to the new session, in the same order a new thread applies them, so an option the agent has since retired is skipped rather than failing the resume. An agent that resumes without reporting its configuration is re-sent the values rather than trusted, since in that case the cached ones describe the session that ended.
Changing a setting on an archived conversation also works now instead of being silently dropped. There is no agent to apply it to yet, so the choice is recorded against the thread and applied to the session the resume starts, and the menu says so rather than leaving a pick that appears to have done nothing.
Agents now know to look things up rather than guess at what OpenKnowledge can do. The shipped skills describe the core editing flow, so a request touching anything outside it depended on the agent already happening to know the feature existed. Both skills now point at the documentation site and the source repository.
Re-run
ok initin an existing project to pick this up. The project-local skill is seeded only when absent, so opening an already-initialized project does not refresh it. The user-global discovery skill does refresh on upgrade.Opening a new tab with the agent panel up no longer leaves the panel stuck at zero width. The panel looked like it had closed, but the app still considered it open, so the edge tab that reopens it stayed hidden and the chat could not be brought back without a reload. The editor's row of side columns remembers a set of widths for each combination of columns on screen, and a new tab took the document side pane out of that combination, which swapped in the widths that arrangement last had. Those were usually from a session with the agent panel closed. The document side pane now stays in the row at all times, empty and zero width on views that have nothing to put in it, so the combination never changes and no swap happens on any view.
The agent activity view opened from a folder now shares that same pane rather than a second one of its own. It picks up the pane's width and can be dragged closed, where before it could only be dismissed by clicking the agent's avatar again.
Fixed blank editor tabs ("New tab") not responding, and made closing a tab mean closing it.
Opening a second blank tab in Skills left it unselectable — clicking it, or even creating it, kept the first one active. And with a single blank tab open in either Skills or Files, its close button did nothing: the tab was closed and then immediately recreated, so nothing appeared to happen.
Both came from the same place. Navigation resolves from the URL hash, and the resolver re-runs whenever the workspace changes so that a target which could not be resolved yet — a document whose file list is still loading — resolves as soon as its data lands. Document tabs are unaffected because the resolver recognizes when the requested tab is already the active one. The Skills home and the empty-hash blank tab are addressed by hash alone, with no tab to recognize, so each re-run re-asserted them from scratch.
Blank tabs now select independently. Closing your last tab — blank or document — now leaves the editor's empty state instead of replacing it with a fresh blank tab, and opening a project with nothing open shows that empty state directly rather than a placeholder whose close button appeared to do nothing. The empty state is what a blank tab was rendering anyway, so nothing is lost.
A blank tab still appears while other tabs remain open, deliberately. Closing the last Files tab with Skills tabs still open (or the reverse) keeps the surface you were on — otherwise focus falls through to the other surface's tab and the sidebar switches under you. Returning to the app root behaves the same way, because that placeholder is also what deselects the tab you left; without it, a folder created from the sidebar would land inside whichever folder was last open.
Multi-word searches in the command palette and settings search now find commands regardless of word order. Typing "report bug" in ⌘K showed no commands at all, because a command was only offered when everything you typed appeared as one uninterrupted run of text inside its name and keywords. "Report a bug" has a word between the two, so it did not qualify, and neither did "branch switch" for Switch worktree or "project sync" in settings search. The file results in the same dialog already matched word by word, which is why the file half of the list filled in while the command half stayed empty.
A command is now offered when every word you typed appears somewhere in its name or keywords, in any order and not necessarily next to each other. Commands that matched before still match, and rows keep their existing position in the list. Note that because commands are listed above file results, a multi-word query that previously found only files may now preselect a command, so Enter runs the command rather than opening the file.
Searching "close terminal" also offers Hide Terminal, and offers it first. Kill Terminal answers to "close" as well, and it ends a running shell without asking, so leaving it as the only result for a phrase that means "put the panel away" in most editors would have been a trap.
Commands in the ⌘K palette are now findable by the words people actually search for, not only the words in their names. Commands are named for what they are, while users search for what they want to do, so "delete file" did not find Move to Trash, "open settings" did not find Settings, and "file bug" did not find Report a bug. Across a sweep of seventy realistic phrasings, thirty-one returned nothing at all.
Thirty-five search terms were added across twenty-one commands, nineteen distinct words in all, each one chosen because a measured phrasing failed without it. "new document" and "create note" now reach New file, "show in folder" reaches Reveal in Finder, "change branch" reaches Switch worktree, and "go back" reaches Back. Panels that change their own name as you use them — Show Terminal becomes Hide Terminal once it is open — now answer to both verbs, so "show agents" and "hide files" work whichever state the panel is in rather than only half the time.
No command was renamed, and nothing that matched before stopped matching. One consequence worth knowing: a few ordinary single words now reach a command that they did not before, and commands are listed above file results. In a project containing a file called note, typing "note" and pressing Enter opens the New file dialog rather than the document, where previously it opened the document. Arrow down to the file, or keep typing, to reach it.
Crash reports from the desktop app now record when the previous session was last known alive, and whether the machine ended it. When the app finds that a session ended without shutting down cleanly it offers to send a report, and until now that report said a crash had happened but never said when. The app already refreshes a liveness timestamp about once a minute while it runs, which dates the death to within roughly a minute, but that timestamp only ever reached the log on the path where the prompt is suppressed and no report is produced. Without it the only bound on when a session died was the gap between its last log line and the next launch, which routinely runs to hours, so readings as different as "it died hours ago and the relaunch was late" and "it stayed hung until the moment it relaunched" were equally consistent with the report, while pointing at completely different problems.
Reports now also carry the two markers that say the machine ended the session rather than the app failing: whether it was asleep, and whether the operating system was shutting down. When a session leaves a crash dump behind, the separate log line that would otherwise have recorded those is never written, so the report is the only record, and their absence used to be indistinguishable from an ordinary crash. All of these are written as explicitly empty when a session's file predates them, so "we could not tell" stays distinguishable from a value that went missing. Nothing new is collected about you or your documents: all three are timestamps the app already kept for its own restart handling.
Every dialog now leaves the window movable. Reaching for the title bar while a dialog was open used to count as a click outside it, so the dialog closed instead of the window moving — and there was no way to drag the window at all without answering the dialog first. The title-bar band stays draggable behind the backdrop now, and dialogs are held clear of it, so the band never covers a dialog's own heading or buttons. The top edge of the screen no longer dismisses a dialog on click; Escape, the close button, and the rest of the backdrop still do.
Pressing the document-panel shortcut (⌥⌘B) twice in quick succession no longer leaves the panel stuck shut. The second press was meant to reopen the panel the first one closed, but if it landed quickly enough it repeated the close instead — doing nothing visible, and leaving the toolbar button reporting a state the app disagreed with. The panel also recorded "closed" as your preference on the way out, so the wrong state could follow you into the next session. The same guard now covers the sidebar shortcut (⌥⌘S), which had a narrower version of the same gap.
A menu item chosen while a window is still opening now takes effect once the window is ready, instead of doing nothing. Toggling the terminal, the sidebar or the agent panel during launch, by menu or by keyboard shortcut, could be silently discarded: the menu bar is live from the moment the window appears, but the part of the window that listens for menu commands only starts listening after the first frame is drawn, and anything sent in between was dropped with no error and no retry. On a cold or busy machine that gap is seconds wide, which is exactly when someone reaches for a shortcut.
Commands that arrive early are now held and applied the moment the window can act on them, with two deliberate limits. Pressing the same show-or-hide shortcut repeatedly during that gap counts as one request rather than several, so pressing it twice because nothing happened opens the terminal instead of opening and immediately closing it. And commands that destroy something, closing a tab or window, killing a terminal, deleting or trashing a file, are never held: what they act on is decided when they run, so applying one late would aim it at whatever happens to be selected by then rather than at what you were looking at when you pressed it.
Picking a starter pack in the launcher now shows what the pack adds on a screen of its own, before the project details. Previously the create-project dialog carried the project name, location, subfolder choice, AI-tool setup and the pack's full list of folders, templates and skills at the same time, which buried the parts you actually fill in. Reviewing the pack and setting up the project are now separate steps, with an explicit "Use this starter pack" between them.
The "+N more" affordance no longer opens its own picker — it opens the same dialog on its pack grid, so both ways into a starter pack follow one flow. "Change pack" is available from both the review and the details screen.
The details screen now says whether the pack's skills will be installed, since that depends on the AI-tools checkbox that sits alongside it — unticking it visibly cancels the skills rather than quietly dropping them from what you were shown.
Agent-side reads (
exec cat,search, native reads) no longer take over the workspace tab. Follow-the-file now only reacts to write-shaped tool calls, so Claude exploring the doc index while it works can't yank you off what you were reading.Follow-the-file no longer yanks the editor to an ACP agent's presence
currentDocwhen the write happened minutes ago. The 3-second keepalive was refreshingentry.tspast the 5-second staleness guard even when the doc itself hadn't been touched. Presence entries now carry a separatedocTsset only whencurrentDocis written, and the client staleness check reads that instead.Numbered and bulleted lists in ACP agent messages render with consistent spacing between items and between blocks inside an item, and multi-paragraph items no longer collapse onto a single line — Streamdown's
[&>p]:inlineon<li>was folding sibling paragraphs and letting code-block margins push items apart unevenly.The problem count on a file-explorer row is now a control instead of a label. Clicking it, or focusing it and pressing Enter or Space, opens that file and shows the Problems panel listing its problems, expanding the right rail if it was collapsed and switching a panel left in project scope back to the clicked file. Keyboard activation moves focus into the panel, while pointer activation preserves pointer focus. The badge already told you to open the Problems panel for details, and now it takes you there rather than leaving you to find the tab yourself. Tabbing through the file explorer now stops on the count of each row that has problems, which is how the badge becomes reachable without a pointer. It keeps the accessible name and tooltip it always had, and a click carrying cmd, ctrl, shift, or alt still belongs to the tree, so multi-select on a badged row is unchanged.
Zoom-in on a large Mermaid diagram can now reach 1:1 and past it. Panzoom's
maxScalewas a multiplier on the SVG's already-fit painted size, so a diagram that mermaid shrank to fit the container capped below its natural size. The Mermaid host now divides the ceiling by the fit ratio, soMERMAID_ZOOM_MAXbehaves as "max natural zoom" regardless of the diagram's size.Two-finger trackpad scroll now pans a standalone
.mmddocument's Mermaid canvas, and ⌘/Ctrl-scroll zooms it. Codefenced fences still ignore the wheel so scrolling over an inline diagram continues to scroll the page.Pasting an image into the agent composer no longer attaches it twice. About a quarter of pastes produced two identical thumbnails from one Cmd+V, and the second had to be removed by hand.
A pasted image arrives on the clipboard event through two accessors that describe the same payload:
items, which also carries non-file entries, andfiles, which is the file-only subset of it. The composer read both and dropped anything it had already seen, keyed on the file's name, size, and last-modified time. That key is unstable for a paste. A pasted image has no file on disk, so the browser builds a fresh file object for each read and stamps its last-modified time with the clock at that moment rather than deriving it from the payload. Whenever the two reads landed in different milliseconds — measured at 4 of 15 pastes — the keys disagreed, the second copy looked like a new file, and both were attached.The composer now treats
itemsas the authoritative list and only consultsfileswhenitemsyields nothing, which is what an older host or a synthetic event does. One payload is read once, so there is nothing to de-duplicate and no timestamp to depend on. Dragging files from Finder is unchanged; it was never affected, because a real file on disk reports the same last-modified time to both reads.Attaching the same picture twice on purpose also renders correctly now. The pending-attachment strip identified each thumbnail by filename and the leading bytes of its content, which two copies of one image share, so the two tiles collided on a single identity.
Fixed a Claude ACP failed-to-start with
npm error Override without name: @modelcontextprotocol/sdk>zod. When the project you opened lives inside a monorepo whose rootpackage.jsonuses pnpm's flatparent>childoverride syntax, npm's arborist would walk up from the agent's cwd, hit that file, and reject the flat key before the agent could initialize.npx-kind ACP spawns now run from an OK-owned dir under ~/.ok/ so arborist doesn't discover the ancestor workspace; the agent still receives its actual workspace over the ACP session handshake.Floating surfaces anchored inside the editor now stay inside the editor pane.
The formatting toolbar and the comment composer used to escape it. Selecting a passage taller than the visible area and then scrolling left them floating above the pane over the document tab strip, or below it over the Ask AI composer and the status footer. Both now clamp to the same visible region: below the toolbar, above the Ask AI composer and any conflict-resolution footer, and inside the pane's side edges. The toolbar still disappears once the selected passage is completely out of sight, and the comment composer stays put while it holds a draft so an in-progress comment is never lost to a scroll.
The same fix reaches two more surfaces that had the same defect. The slash, wiki-link, and tag pickers used to overhang the pane's right edge whenever the cursor sat past the middle of a line, and could extend below the pane over the Ask AI composer. They now stay inside the pane, and their list shortens to fit the room actually available beside the cursor instead of covering the line being typed on. The markdown-lint hover callout used to paint over the editor toolbar when its line sat near the top of the pane, and to overhang the right edge near the end of a line. It now stays inside the pane on both axes.
The theme setting in Settings → Preferences is now the same card picker you saw during first-launch setup, instead of a row of plain text pills. Each of System, Light, and Dark shows a small preview of what that mode looks like, and the selected card is marked with a check. Picking one still applies immediately and saves to your config, and the cards remain fully keyboard-navigable with arrow keys. Both screens now list the options in the same order — System, then Light, then Dark — so the layout doesn't shift between where you first set your theme and where you later change it.
The first-launch setup screen now closes the way you'd expect when you opened it yourself. Reopening it — from the command palette, the menu bar, the File menu, or the "Connect tools" button on the Claude Code banner — gives you a close button, a Cancel action, and click-outside-to-close, exactly like every other dialog in the app. Its first, unprompted appearance is unchanged: that one still asks for a real decision and offers "Skip for now" rather than a way to wave it away. Closing a reopened one now leaves your setup exactly as it was — no marker is written at all, so a completed setup stays completed with its original date intact.
Confirmation dialogs no longer freeze the window in place. Because they can't be dismissed by clicking outside, their backdrop was suppressing the title-bar drag region underneath it, so the window couldn't be moved until the dialog was answered — including on that first-run setup screen.
ok start --single-fileno longer deletes the directory it runs in. Previously, running it from inside an initialized OK project silently adopted that project as the session's "throwaway" root and recursively deleted it — content,.git, everything — when idle shutdown fired; from a non-project directory it refused to start withMissingOkConfigError. The command now provisions its own temp project root when--project-diris absent (removing it on shutdown), requires any provided--project-dirto be a throwawayok-ephemeral-*temp dir (seeding the synthesized config into it when bare; anything else — an ordinary directory or a real initialized project — is refused with a clear message instead of written to), and the ephemeral cleanup refuses to remove any directory that does not resolve to anok-ephemeral-*temp dir — symlinks included — so no flag combination can point the reap at real data.--project-dirwithout--single-fileis now rejected instead of silently ignored, ephemeral sessions no longer inherit the enclosing project'sserver.*settings — the user-global~/.ok/global.ymllayer still applies, matchingok <file>, and flags and env still override — and both flags are hidden fromok start --help— they are the desktop spawn contract, andok <file>is the supported way to open one file.Updating no longer immediately asks you to update again. Releases often land less than an hour apart, so the build waiting behind the "ready to install" banner was frequently already superseded by the time you clicked it — and the check that runs as the app comes back up would spot the newer one and put the banner straight back, replacing the "Updated to Version X" confirmation you had just earned.
Clicking Relaunch now re-checks first. If a newer build has appeared since the banner was raised, the app fetches that one and installs it instead, showing "Getting the latest version…" while it does — so finishing an update leaves you on the newest build available at the moment you asked for it. On macOS and Windows, where updates install on quit, a build that arrives in the minutes right after an update is downloaded and staged silently rather than announced, and installs the next time you quit. On Linux the banner is the only way to apply an update, so it appears as before.
This also fixes a class of failed installs. The app could previously call into the installer while a newer build was still being written into place, which surfaced as an update that failed and then worked on retry. Two things close that: a relaunch now waits for any download in progress instead of racing it, and a build that is already staged is no longer needlessly re-staged on every hourly check.
The server now answers API requests as soon as it starts instead of staying silent for up to a minute or more on some Windows machines. Boot-time git housekeeping (history-repo gc configuration, rename-log garbage collection, shadow maintenance) used to run before the server declared itself ready, and every API endpoint waited on that; on hosts where antivirus scanning makes each git subprocess launch slow — a common Windows Defender configuration — the housekeeping burst serialized into a 60-90 second window where
ok statusreported the server alive but every request timed out, and MCP clients such as Claude Desktop repeatedly reported the server unreachable right after a restart. The same window also produced spurious "block timeout reached" git errors in the server log. Housekeeping now runs in the background after the server is ready, so requests are served immediately and the housekeeping still completes; shutdown waits for any in-flight housekeeping so it can never race a project teardown.Shutting down, restarting, or signing out of Windows no longer makes Open Knowledge report the previous session as a crash. On the next launch you were asked to send a bug report for a session that had ended perfectly normally, and the report carried no evidence of anything going wrong, because nothing had.
Open Knowledge already suppressed that prompt when the machine ended a session rather than the app, but it recognized only signals that Windows does not send. Windows announces an ending its own way, to each window rather than to the application, and the app was not listening for it. That left Windows the only platform where a normal shutdown was indistinguishable from a crash, so it was always reported as one.
The app now records that announcement the moment it arrives, along with what Windows says about it — a sign-out is distinguishable from a machine powering down, which is detail the other platforms never had. Windows does not separate a restart from a shutdown, so neither do we.
Suppression stays deliberately narrow. A session that ends without any announcement at all, as in a power cut or a forced power-off, still prompts, and so does anything that leaves a genuine crash record behind. A shutdown you cancel does not leave a mark that would quietly hide a later crash.