v0.46.0
Released Aug 3, 2026. Part of the OpenKnowledge changelog.
Minor Changes
Comments are the queue for your agent. Highlight a passage, say what's wrong, keep reading — the comment is filed against the exact words you picked, and nothing is sent until you decide the pass is done.
Before After Five things to fix meant five trips to a chat window Comment on each, send once Retype the passage so the agent can find it again The comment carries the words it points at Lose your place in the doc every time Never leave it The queue spans files. Comment on three passages here, open another file, comment on two more, then send. One agent turn, edits landing in both documents. Uncheck anything you changed your mind about before it goes.
Send now or send later. Writing a comment offers both: Add Comment files it for the batch, Send to AI hands it over immediately. Either way the comment box takes
@mentions of files, the same as the Ask AI composer, and mentions reach the agent as real paths.Sends find the conversation you're already in. With a chat open, the queue lands in it rather than starting a detached one; with none open, it starts one. The send button says which before you click it.
Comments are stored per-machine next to your content and are not committed — a comment here is a note to your own agent, not a message to a teammate.
A config key that was removed in a newer version no longer discards the rest of the file it appears in.
Config files accumulate keys that later releases retire. Until now, a single retired key anywhere in a file — your committed
.ok/config.yml, your user-global~/.ok/global.yml, or the per-machine.ok/local/config.yml— invalidated the whole file: every unrelated setting in it silently reverted to its default. A long-dead cosmetic setting left behind in a config could therefore switch off something you actively depend on, with nothing reporting a failure. In one case a retired sidebar preference sitting in a project-local config threw away an explicitautoSync.mode: full, so Git sync stopped running and stayed off.Now every config layer strips only the retired keys it finds, keeps every other setting at the value you wrote on disk, and reports each stripped key together with what replaced it. Genuinely broken files are unaffected by this change: invalid YAML and settings that fail validation are still rejected exactly as before. Only the handling of retired keys changed.
ok startno longer fails to start over a retired key in your committed.ok/config.yml. It strips the dead key, prints what it found and the replacement guidance, and starts. Previously one stale key could stop the tool from starting at all.ok config migratecan now reach your per-machine config. It defaults to every layer, so the bareok config migrateeach error message tells you to run now fixes the key wherever it lives. A new--scope project-localtargets.ok/local/config.ymlalone,--scope allis the explicit form of the new default,--scope bothkeeps its old project-plus-user reach, and--dry-runstill previews without writing. Migration only ever removes a retired key and reports its replacement — it never rewrites your other files on your behalf (for example, it will not create or edit.okignorefor a removedcontent.include, because that rewrite is not a faithful one-to-one translation).ok config validatenow reports all three config layers. It previously described only your user-global and committed-project files, so a retired key in the per-machine.ok/local/config.yml— the layer the reported bug lived in — got an unqualified✓. It now reads that layer too, so a stale key is findable without a running server. Reporting is read-only: an unreadable layer is described, never moved aside.- New endpoint
GET /api/config/diagnosticslists the retired keys currently present across your user, committed-project, and project-local configs, each identified by its scope, file, key path, and replacement guidance. It reads the files fresh on every request, so fixing a file is reflected on the next request without a restart, and it never returns your actual config values.
Settings that a retired key was suppressing now take effect. Some features deliberately fall back to a safe value when a config file cannot be trusted, and until now a retired key made a file untrusted. Those features therefore ignored what you had written in the same file. Now that a retired key leaves the file readable, your settings in it apply — which for an affected config is a real change in behavior, in both directions:
- External link previews. A project-local config carrying a retired key had link previews forced off, even when you had explicitly enabled them. Your explicit setting is now honored. If that file has no
linkPreviewssetting at all, the default (previews on) now applies, and hovering an external link sends its URL to the destination site where previously it did not. - Semantic search. A
search.semanticblock sitting alongside a retired key was discarded, leaving semantic search off. Your configured provider and model now apply, and enabling semantic search sends content to that provider. - Editor bridge safeguards. An explicit
bridge.*opt-out alongside a retired key was overridden back on. Your opt-out now takes effect.
If you rely on any of these being off, check the config file the diagnostics endpoint or
ok config validatereports a retired key in. A file that is genuinely unreadable (invalid YAML, or settings that fail validation) still falls back to the safe value exactly as before.Code and plain-text files (
.ts,.json,.css,.py,.yaml,.txt, and friends) now open as real editors instead of read-only previews — line numbers, syntax highlighting, and live collaborative editing, with every keystroke saved straight back to the file on disk. HTML, SVG, and lockfiles open the same way, straight from a click in the file tree. Markdown keeps its rich editor and Mermaid files keep their diagram editor.Editing the globs that scope a frontmatter schema to a set of docs got three fixes, all from the same root: once you pressed Enter, the pattern became something you could neither read accurately nor change.
Patterns read as you typed them. A committed pattern was displayed in capitals —
blog/**rendered asBLOG/**. The pattern on disk was always correct, so nothing was ever scoped wrong by this, but globs are case-sensitive and the display gave you no way to confirm what you had actually saved. The same fix reaches every place these value pills are used, including the schema editor's "Allowed values", where an enum ofDraft/Publishedwas shown asDRAFT/PUBLISHED.Double-click a pattern to edit it. Correcting
blogtoblog/**meant deleting the entry and retyping it from scratch. Double-clicking a pattern now lifts it back into the input with the text selected; the corrected pattern is written back in its original position, so an exclude that only applies to the includes before it stays where you put it. Enter or Space does the same thing from the keyboard, and Escape cancels.Problems point at the glob that caused them. A pattern matching zero docs was reported in a "Configuration problems" list that named the pattern but not which schema's input it came from — with several schemas and several globs each, you could see something was wrong without being able to tell what to fix. The offending pattern is now marked on the input itself, with the reason on hover, and that is its only home. Deleting a flagged pattern no longer flashes a warning about it on the way out: the problems channel is composed from the file on disk and briefly lags the edit, so a pattern you just removed still had a live finding for a moment. Problems about the schema file rather than a glob still appear in the list.
Skills become a first-class surface: find them, bring them in, and own them as versioned content.
Find a skill. Skills is now a destination rather than a settings tab. Its home leads with describing the skill you want, with Upload a skill and New from scratch as quiet actions beneath. The six most-installed skills on skills.sh render inline with a Browse all link, so installing something that already exists no longer starts by opening a modal.
Adding a skill opens one dialog with two tabs:
- Explore browses skills.sh — a most-installed grid on an empty query, keyword search otherwise — and imports a repository-backed or website-backed result in one click. Website publishers install through their
.well-knownskill index, including every declared file. When skills.sh is unreachable the surface degrades to a GitHub-topic search and the last-good grid, so it is never blank on a cold network. - Upload takes a
.zip/.skillbundle, a folder, or a remote source: a GitHubowner/repo, a git URL, a skills.sh skill-page URL, or a local path.
Skills you already have are left alone. Skills OK finds in your other tools (Claude plugins, plus the Claude, Codex, Cursor, OpenCode, Copilot, Pi, and Agents skill dirs) are never imported. They appear as read-only Detected rows, expand to their file tree (loaded lazily, so the sidebar never fetches a preview for every detected skill up front), and are editable in place — changes save straight to that editor's own copy.
One skill, one folder, many places. Every path lands the skill in the project's skill home (
.agents/skills/<name>/when you have one) as versioned content: history, restore, search, and attribution, with provenance in.ok/skills-lock.json. An identical re-import is a no-op; a name collision lands under<name>-importedrather than overwriting. A new location is a symlink to the source by default, or follows the form the skill's other locations already use; convert any single location when you want an independent copy. Imported scripts are stored as content and never executed.Installing a set, not a file at a time. When a preview belongs to a plugin or a website index, it discloses the siblings and opens a picker — each with its description, a select-all, and the level to install at — rather than a one-click "install all 41". The selection imports through a single server-side clone, so ten skills from one repo no longer re-clone it ten times, and one oversized bundle or misspelled name reports itself instead of failing the rest. Website installs also fetch bundle files concurrently and read the origin index once per selection: two skills from
open.feishu.cnwent from 39s to 9s. A plugin's hooks, commands, and MCP servers are named, never installed and never run.The
workflowMCP tool is retired. Its five procedures move into skill guidance, so they load on description match instead of costing tool-list tokens every turn.importtakes the freed slot, keeping the surface at 21 tools.ingestand brownfield onboarding move into the platformopen-knowledgeskill, which ships with everyok init.researchandconsolidateship with theknowledge-basepack;wikigenerate/refresh withcodebase-wiki. The platform skill now says plainly when a procedure needs its pack.
Starter packs ship focused skills. A pack directory may hold a root
SKILL.mdplus one subdirectory per member skill.software-lifecyclegainsframe-a-proposal,write-a-spec,record-a-decision,write-a-postmortem, andreview-a-design;knowledge-basepromotesresearchandconsolidateto member skills. Pack skills also gained task-based triggers, sosoftware-lifecyclefires on "record an architecture decision" rather than only on a folder-layout match.ok seed --pack <id>installs every skill a pack ships, and no longer reports "already seeded, nothing to do" when the folders exist but a skill is missing.Fixes
- Installing a skill into the
.agentshub no longer fails with "Placement path must be a project-relative directory outside .ok/." Asking for a location a skill already occupies is a satisfied request that changes nothing. - Skill preview tabs no longer duplicate. A preview's identity includes its source path, and that path moves (a plugin-cache path carries the version; a detected skill relocates when its installed copy is deleted), which minted a second tab with the same label — one of which looked impossible to close. Reopening reuses the tab already open for that skill and level, and a visible tab is always closable.
- Settings → Skills is slimmed to the install-targets picker; authoring and browsing live in the sidebar.
- Install counts read
2.7Mrather than2733k, in the active locale's units and separators.
Under the hood: a read-only cross-harness enumerator (
ok skills installed,GET /api/skills/installed), the skills.sh discovery and leaderboard proxies with defensive row-level parsing, the acquire/import pipeline, and the shared skill and Pack model — all exported from the new@inkeep/open-knowledge-core/skills-catalogsubpath. Remote imports require explicit opt-in before upstream changes auto-apply; local filesystem sources keep automatic refresh. Rename and scope-move preserve provenance, update eligibility, and copy projections. The canonical-component text in tool descriptions is split sowriteandeditstill list every component id while the authoring reference rideswritealone, trimming roughly 940 bytes of always-on context per turn.- Explore browses skills.sh — a most-installed grid on an empty query, keyword search otherwise — and imports a repository-backed or website-backed result in one click. Website publishers install through their
The terminal and agent conversations are now two separate panels instead of one shared dock. The terminal owns the bottom of the editor and still opens with ⌘J; agent conversations own the right panel and open with ⌘L. Both can be open at once, each keeps its own size, tabs, and reload state, and closing one leaves the other alone — so you no longer have to give up your terminal to see an agent. The dock-position toggle is gone with the split; a terminal that used to sit in the right panel moves to the bottom on first launch, and the right panel keeps the width you had set.
A new tab in the terminal panel opens a plain shell by default — you no longer get dropped into a CLI you never chose. The New button's dropdown still lists every terminal CLI, though, so you can start a tab directly in one; that choice sticks, and the + button, ⌘J, and ⇧⌘J repeat it until you pick Terminal again. The agents panel's New button remains dedicated to in-app agents. Sending a passage to AI — from the selection bubble, a code block's Ask action, or ⌘J with selected text — still uses your preferred AI and reveals the panel where it runs.
The agents panel now keeps a small tab on the right edge whenever it is closed, so a conversation is always one click away even if you have never opened the panel. The terminal no longer has an edge tab of its own — ⌘J and the View menu open it — which clears the bottom-right corner it used to share with the Ask AI composer.
The bottom Ask AI composer moves from ⌘L to ⇧⌘L (Ctrl+Shift+L on Windows and Linux), and now hides whenever either panel is open — both are already places to type a request, so it stepped aside rather than offering a third.
Patch Changes
The agent thread composer no longer carries an add-context
+. It opened a one-row menu whose only row was the comment queue, and that row was inert unless the queue had already loaded and had something in it, so in practice the button opened a menu that could not do anything. Attaching a batch there was also the weaker of the two paths: it folded the comments into your next message but left every thread queued, while the Comments panel's own Send to chat dispatches to the open session and actually closes the review requests. That panel is now the single way to send queued comments to an agent, and the composer's bottom bar is just the agent settings on the left with the context ring and send button on the right.The agent composer now shows one action button instead of Stop and Send at the same time. While the agent is working the button is Stop; as soon as you start typing it becomes Send, and your message queues behind the current turn the way it always has. This matches how other agent chats behave and keeps a single clear action in the corner of the composer. Because Stop is hidden while you have a draft, pressing Escape in the composer now stops the agent, and your draft is kept so you can still queue it. Hovering Stop shows the shortcut. A stop that hasn't taken effect yet keeps showing its spinner even if you keep typing, so you can always tell whether the agent heard you.
Picking a value in an agent thread's settings menu now applies. Choosing a model, permission mode, or reasoning effort from one of the menu's submenus closed the submenu and jumped focus to the message field without ever sending the change to the agent, so the setting silently stayed where it was. The composer card focuses its message field when you press its whitespace; because React delivers a portaled menu's events through the component that opened it, that handler was also claiming presses inside the menu. It now acts only on presses that land in the card itself.
Agent chat threads now scroll like a real chat client. The transcript keeps itself pinned to the newest output while an agent is streaming, but the moment you scroll up to read something it stops fighting you — and a button appears to jump back to the live edge when you're ready.
Before After Scrolling up mid-stream was undone by the next chunk snapping you back to the bottom Scrolling up holds; new output no longer yanks the view No way back to the latest message except scrolling by hand A jump-to-bottom button returns you to the live edge Reopening a past thread dropped you at the very bottom Reopening lands you at the last turn, with the previous message in view Sending a message still brings you straight to the bottom so you see your prompt and the reply. Long threads with many tool calls also render more cheaply, since off-screen rows are no longer laid out until they scroll into view.
The agent thread's working row is now the OK mascot changing shape instead of a spinner. It holds each pose, changes into the next, and holds again, with a squash and a squint on top so a long wait reads as effort rather than a stall. The status line beside it says what the agent is actually doing when a tool is running (reading, drafting, retrieving) and otherwise drifts through a pool of phrases on a randomized beat, so the row keeps moving without ever implying progress it cannot see. The line fades between phrases rather than cutting, and the whole row fades in when a turn opens. Under reduced motion the mascot holds a single pose and only the fades remain.
Color themes are now authored in base16, the format the wider theming ecosystem already uses, and they reach considerably more of the app.
The built-in palettes (Dracula, Catppuccin Frappé and Latte, Monokai, Gruvbox, Solarized) are reproduced from their canonical upstream schemes, and Settings → Plugins → Themes gains a "Paste a base16 scheme" field: drop in any of the several hundred published schemes as YAML or JSON — in either the current Tinted Theming layout or the original one — and it applies as-is. The sixteen slots are also editable by hand. An existing custom theme built from the older six-color picker is upgraded automatically rather than reset.
The reason for the format change is coverage. The previous palette used ad-hoc names like "surface" and "accent" that several surfaces had no way to consume, so picking a theme left them on hardcoded colors. base16's slots carry fixed roles that map onto those surfaces directly, and the following now follow the selected theme:
- Source-mode syntax highlighting. The CodeMirror editor was pinned to one of two bundled palettes regardless of theme. This also covers the diff view, the text viewer, the text-file editor, and the Mermaid editor.
- Terminal colors. All sixteen ANSI slots, so program output is themed, not just the terminal's background.
- Callouts. All fifteen accent colors.
- Fenced code blocks in the WYSIWYG editor, plus inline code, blockquotes, tables, links, highlight marks, and horizontal rules.
- Lint squigglies, broken-link underlines, and the file tree's problem indicators.
html previewembeds, which now receive the host's live token values instead of a build-time snapshot of the default theme, so an embed matches the surrounding editor.- The desktop window chrome on Windows and Linux — the titlebar overlay and window background take the active theme's colors rather than staying neutral.
Also fixes three keyframe animations (the sidebar push pulse and two settings flashes) that painted nothing in any theme, including the default one, because they wrapped a color token in
hsl().Screenshots attached to a bug report now actually appear in the report. The previous release added this and it did not work: the screenshot was still left out of every report, silently.
Before After Report says a screenshot was included; nothing visible The screenshot is displayed in the report The cause was a dropped field. The app asks "does this bundle include a screenshot?" and passes the answer along when sending, but the layer that hands the request from the window to the app's background process was rebuilding it field by field and had never been taught about that answer. The background process saw no answer, took that to mean the reporter had declined, and left the screenshot out. Because "reporter declined" is a perfectly normal outcome, nothing was logged and nothing looked broken.
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. Re-sending an older report from the report list still sends it without the inline screenshot, since the capture is no longer in memory by then.
The config-sharing "Local only" choice is now labeled Only me across every desktop surface that names it — the create/open-folder dialog's radio card (
SharingModeField), the Settings → Config sharing card (SharingSection), and the explanatory info tooltip (ConfigSharingInfoTooltip). Both radio cards now carry the same description spelling out the consequence: your project's OpenKnowledge setup stays on this computer and is not committed to git.(The
ok initCLI prompt keeps its own terminal-context wording and is unchanged.)The first-launch "Connect your AI tools to OpenKnowledge" dialog is easier to scan and more transparent about what it changes.
- Per-tool location tooltip. Each AI tool now has an info affordance that discloses exactly which config file and entry OpenKnowledge would write — for example
~/.cursor/mcp.json→mcpServers.open-knowledge, or~/.codex/config.toml→[mcp_servers.open-knowledge]. This matches the disclosure Settings → AI tools already provides, so both surfaces tell you the same thing before you commit to anything. - Detected tools first, the rest tucked away. The MCP connections list now shows the tools detected on your machine up front and collapses the rest behind a "Show N more tools" toggle, so the list isn't a wall of tools you don't use. If nothing is detected, every tool still shows (with its setup link) so you're never left with an empty list.
- A pointer after Skip. Because the dialog only appears once, choosing "Skip" now leaves a short note telling you these same choices live in Settings → AI tools & CLI, so the surface isn't lost.
No change to what gets written or when — this is about legibility of the choice, not the behavior behind it.
- Per-tool location tooltip. Each AI tool now has an info affordance that discloses exactly which config file and entry OpenKnowledge would write — for example
Stopped building the Linux AppImage. Its launcher requires FUSE 2, which current mainstream distributions no longer ship, so the file failed to start out-of-the-box on stock systems (verified on Debian 13, both architectures). Linux ships as a
.deb; updates will be delivered through the system package manager (apt repository), and the in-app auto-updater is now disabled on Linux accordingly. Users without install rights can use the npm CLI or the web app.Fixed the Create-new-project dialog showing "No location selected" instead of the remembered location on systems where the OS cannot resolve the Documents folder (seen on headless Windows Server sessions). The location probe no longer fails outright in that case: it uses the remembered parent when one exists, and falls back to
<home>/Documents/OpenKnowledgeotherwise.Make project-wide Fix all fast and keep the app usable while it runs. On a 2,400-document knowledge base the Problems panel took several seconds to open in project scope and a full sweep took minutes with the app locked up for most of it; the panel now opens in well under a second and the same sweep finishes in around a minute, with the window on screen, and the app stays responsive throughout. File groups start collapsed, so the panel shows a list of files and their problem counts instead of mounting every problem in the project at once — a new control next to Refresh expands or collapses them all in one click. Progress now advances in batches rather than on every file, which also stops screen readers announcing thousands of updates during a sweep. The sweep paces itself and retries when the server is briefly at capacity, so it no longer starves other work happening in the project and no longer reports files as unfixable when they were only refused. A running sweep can now be stopped: previously the only way out of a Fix all started by mistake was reloading the page. Files already fixed stay fixed, and the panel re-checks the project so the remaining count is accurate.
Fixed a crash that could take down the whole app window, replacing it with the error screen. It hit when the set of open side panels changed (switching between files, clicking a folder, closing the right chat panel, or collapsing the right side panes), and was most likely with the document panel collapsed and a right-hand column open. The layout engine ended up validating a saved multi-panel split against fewer panels than were on screen and threw
Invalid 2 panel layout: ....The underlying resizable-panels library is now patched to recover from that momentary mismatch, re-deriving a valid split for the panels that are actually present instead of throwing, so opening, closing, and switching panels no longer risks crashing the shell. The recovered layout keeps each panel at its intended width rather than snapping everything to an even split.
Fix a family of frontmatter-boundary bugs that could silently remove body content from a document's view while leaving the bytes on disk intact.
A document whose body opens with a
---rule pair and carries no frontmatter was re-read as if the span between the rules were YAML, so that content stopped reaching the editor. Compositions that derive one of their two sides now keep the boundary unambiguous — a freshly serialized body re-spells its leading rule, and the property panel keeps an explicit empty block when removing the last property would hand the body's own bytes to the frontmatter parser. Documents that carry real frontmatter are unaffected, and content the agent writes still lands byte-for-byte.Also fixed at the same seam: a frontmatter block with no trailing newline was destroyed when a body was appended to it (reachable from ordinary typing and from an agent append), and agent
append/prependsilently dropped a leading fenced span of the payload — eating body content when that span was not valid frontmatter. Such a payload is now refused with the same 400 the identical payload already returns forreplace; payloads carrying well-formed frontmatter are unchanged.Fixed path displays mangling Windows paths that resemble escape sequences. A folder such as
C:\Users\x64qarendered asC:\Usersdqain the "Will be created at" caption (and any other message that shows a path), because the localization runtime decoded\x/\uescape sequences inside interpolated values. Decoding now applies only to the translated message text itself; values pass through verbatim. The actual files on disk were always created at the correct path — this was display-only.Declared three missing runtime dependencies in the Linux
.debpackage (libasound2,libcups2,libgbm1). All three are directly linked by the app binary but were absent from the package's dependency list, so on a minimal system the package installed successfully and the app then failed to start with no window and no error dialog. Systems that already have these libraries (most desktop installs) were unaffected.The Linux desktop build now also produces an
.rpmpackage, so Fedora, RHEL, and other RPM-based distributions can install OpenKnowledge with their own package manager instead of unpacking a.debby hand. The.rpminstalls the same way the.debdoes — it puts the app in the launcher, registers theopenknowledge://links, and puts theokcommand on your PATH — and it declares its system library requirements under their Fedora/RHEL names so the package manager pulls in anything missing. Both x86_64 and aarch64 packages are built.Prose containing a brace expression — an MDX comment like
before {/* note */} after, or any{…}span with a*,_,~or an HTML entity inside it — no longer accumulates backslashes. The serializer was escaping the inside of those spans as if they were ordinary prose, but the parser reads a matched brace pair as an opaque expression and never removes the escape, so each backslash was escaped again on the next pass: one delimiter went from\*to three backslashes, then seven, then fifteen, doubling forever. Because every mode toggle, reload, remote refresh and agent write re-derives the document, a paragraph could grow without anyone editing it. Those spans are now written out exactly as typed and are byte-stable from the first save. Documents that already picked up extra backslashes stop growing; their existing bytes are left alone rather than rewritten.Switching to source mode no longer flashes the landing highlight on a block it could not verify, so a flash now always means you landed on the text you selected.
The underlying mis-landing is unchanged for now: on documents whose editor block structure and markdown source disagree about how many top-level blocks exist (for example after deleting the paragraph between two bullet lists, which leaves two adjacent lists the markdown source cannot distinguish from one), the "View in source markdown" jump and the plain mode toggle can land one or more blocks past the intended target — one block for each such divergence in the document. Those unverified landings simply no longer paint the highlight.
Stop background sync from popping a GitHub sign-in window on Windows.
On Windows, a project with a GitHub remote could open a "GitHub — Select an account" window every few minutes, unprompted, for as long as the app was running — even while syncing was healthy and pushing successfully. The window came from Git Credential Manager, the credential helper Git for Windows installs by default, not from OpenKnowledge's own sign-in flow. OpenKnowledge already told git not to prompt, but that setting only silences git's own terminal prompt and does nothing about a credential helper's graphical prompt, so every background fetch that missed the credential store put a dialog on the desktop.
OpenKnowledge's own git commands now run fully non-interactively, so a missing or expired credential can no longer surface as a surprise system dialog. Instead it appears where it belongs: the sync status shows "reconnect to resume syncing" with a Sign in button, on your schedule rather than interrupting whatever you were doing. The same applies to opening a shared branch, where a credential dialog could previously outlive the fetch that raised it and sit on your desktop with nothing behind it. macOS and Linux were unaffected in practice, since their usual credential helpers never draw a window.
Fix the skills.sh page link on imported skills, and correct the
writetool's skill bundle-path description.The provenance link in the Skills UI built its skills.sh URL as
/<publisher>/skills/<skill>, but that path's middle segment is the source repo, not a literalskills. It resolved only for publishers who happen to name their reposkills; for everyone else it pointed at a page for a repo that doesn't exist. skills.sh answers those with a placeholder stub rather than a 404, so the link looked fine and quietly showed the wrong skill. It now derives from the recorded source viaskillsShSkillLinks, which also covers website-catalog sources (/site/<hostname>/<skill>). Same correction applied to theimporttool'ssourcedocs and theopen-knowledge-write-skillguide.The
writetool advertised skill bundle files as accepting "any path —references/**,scripts/**,assets/**, …", but onlyreferences/andscripts/are accepted; anything else is rejected. An agent following the description got an error contradicting it.Show an Update button on OK's built-in skills, and make
ok init --no-skillsstate that it opts out machine-wide.The built-in skills (
open-knowledge-discovery,open-knowledge-write-skill) had no way to surface an available update. The server already synthesizes their provenance and supports re-pulling them, but the built-in preview tab hardcoded its header actions to nothing, so the hook that checks for updates never mounted. The tab now shows a source link and an Update button when the upstream copy differs. Updates stay manual — built-ins never auto-apply.ok init --no-skillsreportedskipped (opted out via --no-skills). Nothing was skipped: the decline is recorded against your home directory and both bundles are removed from every user-global skill directory, so running it once in a throwaway project turned the built-ins off for every project on the machine. The summary now says that, and names how to undo it.installUserSkillalso enforces the opt-out itself rather than trusting each caller to check first, so a declined bundle can't be reinstalled by a caller that forgets the gate.Count skill installs on skills.sh, and let the MCP verbs reach every file a skill ships.
Installing a skill you found on skills.sh never registered with the marketplace you chose it from, so its install count — the signal its listing ranks on — stayed flat no matter how many people installed through OK. Explore installs now report to skills.sh. So do built-in and starter-pack skills, once per skill per machine, never on the launch reclaim. A hand-typed
owner/repois not reported: you never visited the marketplace, so it is not told what you installed. Turn it off in Settings → Preferences, or withDO_NOT_TRACK/DISABLE_TELEMETRY. Private and local sources are never reported.Separately, the MCP
write/edit/deleteverbs and theskills({ name, file })read only accepted paths underreferences/orscripts/, while an import writes a skill's whole directory verbatim. OK could install a skill and then refuse to open its own files —mattpocock/skills/grill-meshipsagents/openai.yaml. Any path that stays inside the skill dir is now accepted; the traversal, absolute-path and NUL guards are unchanged.Two rough edges on the new text-file editing: large-but-ordinary files like an 800 KB lockfile now open editable (only pathologically large files stay on the read-only viewer), and the visual/markdown mode switcher no longer shows for code and text files, which only have one editing surface.
Fix the slash, wiki-link and tag pickers destroying typed text inside code blocks and inline code spans. All three menus used to open in a code context, and choosing an item deleted the characters you had typed there: the query vanished out of the fence and a chip landed after it, while a slash command replaced the whole code block with the chosen node and lost the fence's language tag. The menus now stay closed inside code, matching every other typing shortcut in the editor.