What OpenKnowledge writes to your system
Every file OpenKnowledge creates or changes — when, where, in-project vs. your home directory — plus the opt-outs and what leaves your machine (nothing by default).
OpenKnowledge keeps your knowledge base as plain markdown in your own project directory, but the tooling around it — the CLI, the MCP server, and the desktop app — also writes a handful of supporting files, some of them outside the project, in your home directory, your shell startup files, your editors' configs, and the OS credential store.
This page lists every one of them: when each write happens, what it is, and where it is written.
The short version
Nothing about your content leaves your machine by default. Diagnostic logs and telemetry stay on your machine. The things that can send data off it — semantic search, a diagnostic or bug-report bundle, and GitHub sync — are opt-in or on-demand. Two automatic exceptions, neither of which touches your documents: the desktop app checks for updates (sending its app version and channel), and on its first launch it opens your browser once to check for a pending share link. Counting skill installs on skills.sh is off unless you turn on Count skill installs publicly in Settings → Preferences; when on, installing a published skill reports the skill's name and source repository, once per skill (per project, for a skill installed into a project), and never for a private or local source. All of them are listed under What leaves your machine.
How to read this page
Writes fall into two buckets, and each table's Scope column tells you which:
- In-project — inside your project folder. Either committed (shared through git with your team) or gitignored (this machine only, under
.ok/local/or.git/). - Outside-project — your home directory (
~/.ok/,~/Library/...), your shell startup files (~/.zshrcand friends), your editors' user-level configs, or the OS credential store.
Stable and Beta home folders
Every ~/.ok/ path on this page belongs to Stable, except the shared entries listed below. OpenKnowledge Beta, and the ok-beta CLI, write the other files under ~/.ok-beta/ instead, and keep credentials in the OS credential store under the service open-knowledge-beta rather than open-knowledge. These entries stay under ~/.ok/ for both products:
~/.ok/machine-id, a random id that identifies this machine to project server locks.~/.ok/local/server-authority.sqlite, its SQLite rollback journal~/.ok/local/server-authority.sqlite-journal, and~/.ok/local/server-authority-leases/, created when a server starts to prevent overlapping projects or previews from writing the same content. The registry and lease files are owner-only (0600); Stable and Beta share them. A lease is held while its server owns the content and removed on successful shutdown or crash recovery. Uninstall keeps these shared coordination files. Never delete them while a server is running; see Ownership registry recovery.~/.ok/skills/, the user skills store.~/.ok/skills-lock.json, provenance for skills imported at Global scope.~/.ok/local/installed-skills.json,~/.ok/local/skill-placements.json, and~/.ok/local/skill-move-retained.json, the install markers, placement records (where each copy of a skill was written, and whether as a copy or a link), and unfinished-scope-move bookkeeping for Global-scope skills.
No product's uninstall removes ~/.ok/machine-id, and Stable's ok uninstall keeps every entry in this list. See the uninstall notes for how --purge-content treats the shared skills store.
If you run the desktop app or the packages/app dev server from source, it runs as a third product, dev, which keeps its files under ~/.ok-dev/ and its credentials under the service open-knowledge-dev, and shares the entries above. A CLI run from source stays Stable unless you set OK_CHANNEL=dev. See how a process picks its product.
OpenKnowledge installs one of two ways, and the footprint differs a little between them. Pick yours below — each tab lists the complete set of writes for that path. The opt-outs and what leaves your machine at the end apply to both.
Installing and launching the app
How the app lands depends on your platform:
- macOS — a signed
.dmgyou drag into/Applications. Because a.dmgapp can't put a CLI on yourPATHon its own, first launch asks, in one dialog, whether to register the MCP server with your AI editors and whether to addokto your shell'sPATH(both covered below, both with your consent). - Windows — a per-user installer: the app lands under
%LOCALAPPDATA%\Programs\, with no admin prompt. Stable addsokto your userPATHand registersopenknowledge://; Beta addsok-betaandopen-knowledge-betaand registersopenknowledge-beta://. These are registry values underHKCU\EnvironmentandHKCU\Software\Classes, removed by the matching uninstaller. Each product also registers itself for.mdand.mdxfiles underHKCU\Software\Classes, which can make it the default opener when you have not explicitly chosen one in Windows. Uninstall removes that product's Open With and file-handler registrations but does not restore a previous file-type default. To choose another opener, use Settings → Apps → Default apps. Your shell startup files are never touched. - Linux — a deb or rpm package: Stable installs to
/opt/OpenKnowledge/and symlinks/usr/bin/ok,/usr/bin/open-knowledge, and/usr/bin/openknowledge; Beta installs to/opt/OpenKnowledge Beta/and symlinks/usr/bin/ok-beta,/usr/bin/open-knowledge-beta, and/usr/bin/openknowledge-beta. Their desktop entries registeropenknowledge://andopenknowledge-beta://respectively, and each installs its own AppArmor profile on Ubuntu 24.04+ so the Chromium sandbox keeps working. Your shell startup files are touched only with your consent, as described below.
On every platform the app writes app-level state and logs on launch. The table below shows the macOS locations; Beta substitutes OpenKnowledge Beta for the app-data directory and uses its own updater cache. On Windows, Stable app state lives under %APPDATA%\OpenKnowledge\ and Beta under %APPDATA%\OpenKnowledge Beta\. On Linux, the corresponding defaults are ~/.config/OpenKnowledge/ and ~/.config/OpenKnowledge Beta/ (or the matching XDG directories). Stable keeps its command-line shortcuts under ~/.ok/ and Beta keeps its own under ~/.ok-beta/. When Beta sets up its PATH shim, it removes the ~/.ok/variants/beta/ folder that earlier Beta builds used.
On Linux, Stable keeps its PATH marker at $XDG_CONFIG_HOME/OpenKnowledge/path-install.json (default ~/.config/OpenKnowledge/path-install.json). On startup after upgrading, it migrates a valid legacy marker from ~/Library/Application Support/OpenKnowledge/path-install.json when the new marker is absent, preserving the recorded setup choices and removing only empty legacy folders.
| Path | What it is | Scope |
|---|---|---|
~/Library/Application Support/OpenKnowledge/state.json | Recent projects, window/view state, update channel, and your automatic-updates preference | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge/path-install.json | Records the PATH/shell changes it made and your PATH-consent choice, so they can be reverted | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge Beta/state.json | Beta's separate recent projects, window/view state, update channel, and automatic-updates preference | Outside-project (home dir) |
~/.ok-beta/path-install.json | Records Beta's separate PATH/shell changes and consent choice | Outside-project (home dir) |
~/.ok/logs/desktop.<date>.log | Desktop app + renderer log | Outside-project (home dir) |
~/.ok/mcp-status.json | Records your first-launch MCP-setup consent choice | Outside-project (home dir) |
~/Library/Caches/@inkeepopen-knowledge-desktop-updater/ | Staged auto-update downloads (electron-updater) | Outside-project (home dir) |
~/Library/Caches/com.inkeep.open-knowledge.ShipIt/ | Install log of the macOS update helper (Squirrel's ShipIt), which swaps the app bundle after the app has quit. The only record of why an update failed to install, so a bug report you send collects it — only this app's, never those of other applications that use the same update mechanism | Outside-project (home dir) |
~/Library/Logs/DiagnosticReports/ | Not written by OpenKnowledge at all — this is macOS's own crash-report directory, shared by every application on the machine. When the OS ends one of this app's processes it records why there, which is sometimes the only account of a session that stopped without a crash dump, so a bug report you send at the Detailed diagnostics level collects the reports macOS wrote for this app and its helper processes — only ours, never those of any other application, and never at the standard level. A report of ours still names the processes it was running alongside. A report also carries machine details macOS puts in every one of them — the account uid, the Mac model, and the name of the process that launched the app, which on a managed machine can be internal tooling — while the identifiers that would link your bundles to each other are replaced before bundling. ok diagnose bundle collects them too, on every run: that command produces the Detailed superset by design, and its summary tells you what the search found before it writes the zip | Outside-project (home dir) |
/Library/Logs/DiagnosticReports/JetsamEvent-*.ips; on Linux, the system journal and your own user journal; on Windows, the System and Application event logs | Written by the operating system, not by OpenKnowledge, with the one Linux exception described below. These are the operating system's own records, shared by every application on the machine, of the times it ended a process from outside: macOS's low-memory kills (jetsam), the Linux kernel's out-of-memory killer and systemd-oomd, and on Windows the crash and hang records of applications plus the system's records of shutdowns, restarts, power losses, and low-memory warnings. A process ended that way runs none of its own code, so this is often the only account of a session that stopped with no crash dump. A bug report you send at the Detailed diagnostics level reads the past week of these records, and ok diagnose bundle reads them on every run. From macOS and Linux it keeps only the records that name this app's processes. On macOS it keeps, for each of this app's processes in a report, the process id, its memory use and peak, and whether macOS ended it. On Linux it keeps the time, the action, the process name and id, and the unit name, and drops the machine name, the cgroup paths, and the account uid the journal line carries. The user journal is the one exception that OpenKnowledge itself writes to: when the Linux display server drops the app, its desktop process prints a display-connection error just before it exits, and your user journal records it. From your user journal it keeps only those errors from this app's own desktop process, matched against the process ids in its desktop logs, with the time, the process id, and the message cut to 200 characters. From the Windows Application log it keeps only this app's crash and hang records, with any value that looks like a file path removed. From the Windows System log it keeps the time and kind of every shutdown, restart, power loss, and low-memory warning on the machine, planned or not and whichever application they concerned, with no other detail. The result is state/os-termination-evidence.json in the zip, which a project's zip lists in manifest.json. A system-wide zip's README names it whenever records were kept | Machine-wide (OS logs) |
~/Library/Application Support/OpenKnowledge/Crashpad/ | Native crash minidumps, written by the OS crash handler (Electron's Crashpad) if the app ever crashes. Local-only: the crash reporter runs with uploadToServer: false, so no dump is ever uploaded automatically | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge/bug-report-dirty-shutdown.json | Dirty-shutdown sentinel — written on every launch, refreshed as it runs, and removed on a clean quit. The next launch reads it to tell an app crash (prompts you) from the endings that are not a crash: a reboot, an OS shutdown, or dying asleep (all suppressed and logged instead), an update install shutting the app down to replace its files (logged either way, and suppressed in almost every case: a shutdown the app had no chance to record, or one it cannot date because the previous session left no heartbeat, can still prompt so you are able to report it), and a death the app can date to more than a week ago, which is too stale to report usefully — the diagnostics a report would gather describe the day you sent it rather than the day it happened. A fresh crash dump still overrides those, the same as it does for a reboot, a suspend or an OS shutdown — except in the first 30 seconds after the app committed to quitting for an update install, where a dump is part of that same shutdown rather than a crash you could act on. A session that left neither a heartbeat nor a crash dump cannot be dated, so it is never treated as stale | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge/bug-report-crash-acks.json | Records which crash-report invitations you already answered or dismissed, so the same crash never re-prompts. Answering is what retires a crash: an invitation you simply never saw — because it went unanswered for a day, or the window it was waiting on never appeared — is dropped rather than answered, so that crash can be offered again the next time you open the app | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge/bug-report-main-thread-liveness.json | Main-thread liveness witness. A background worker rewrites it every five seconds while the app runs. The next launch can identify a main-thread block that had lasted at least 15 seconds at the last successful sample. A sample below that threshold does not rule out a shorter or recovered block, or a block after the worker stopped writing. Read only at the next launch; left in place on a clean quit and overwritten on the next run, through a .tmp- sibling during each write. The verdict lands in the desktop log a bug report carries; it does not change whether the app prompts you | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge/bug-report-main-thread-stall.json | Main-thread stall snapshot. When the liveness witness first sees the main thread blocked for at least 15 seconds, the same background worker writes this file at once, then briefly pauses the main thread to read where it is and resumes it straight away. It holds function names and script locations from the app's own code, and the Node.js runtime beneath it, at the moment of a freeze: at most 24 frames, never document content. A freeze inside native code only lets the pause land once the main thread returns to the app's code, so the file records how long that took, and a session that ended before then keeps the record written when the freeze was first seen. One snapshot per freeze; a later freeze in the same session overwrites it, through a .tmp- sibling during each write. A freeze the app recovers from is also noted in the desktop log as it recovers. Read at the next launch; left in place on a clean quit and overwritten by the next freeze. It does not change whether the app prompts you | Outside-project (home dir) |
~/Library/Application Support/OpenKnowledge/bug-report-main-exit.json | Main-process exit record. Written only when the main process exits without the app having marked a clean quit, for example when code ends the process directly instead of going through the normal quit path. It holds the session's identifier, the time, and the exit code. A crash or a forced kill never gets to write it, which is how the next launch tells those endings apart from an exit the app ran itself. Read only at the next launch, where the result lands in the desktop log a bug report carries; left in place and overwritten by the next such exit. It does not change whether the app prompts you | Outside-project (home dir) |
Stable registers openknowledge://; Beta registers openknowledge-beta://. Unless you turn off Download and install updates automatically in Settings → About & updates (see Desktop updates), both check for updates — on launch and periodically while running — against separate Stable/Beta paths on the OpenKnowledge update service at openknowledge.ai/updates, which redirects to the matching GitHub release asset and counts the update per version and channel (Stable alone can fall back to GitHub directly if the proxy is unreachable). On macOS and Windows an update on your channel downloads in the background and installs on the next quit; on Linux — where there is no apt/rpm repository — the app downloads the new deb/rpm from the release feed and asks you to authorize the install (a pkexec password prompt) each time. You can also check on demand from Check for updates… in the app and Help menus, from Check for updates in the Help (?) popover once the updater has started, or from Settings → About & updates, which also shows the installed version and opens its release notes. If the check finds a new version but its download fails, the app tells you so you can try again. The channel is fixed by the product you installed. Older Beta installations named OpenKnowledge continue receiving Beta updates in place, preserving their existing settings and CLI commands; they do not silently become the separately installed OpenKnowledge Beta app. Reinstall Stable from openknowledge.ai/download or Beta from openknowledge.ai/download/beta; Windows and Linux installers are available from GitHub Releases. Override the feed with OK_UPDATER_FEED_URL.
On its first launch the app also opens your default browser once to openknowledge.ai/continue, to check whether you installed from a share link and redeem it if so; the exchange completes over a short-lived local loopback listener.
Shell and PATH
So ok can work in your terminal too, the packaged app manages a PATH shim. This is macOS and Linux only, packaged-build-only, and disabled by OK_RECLAIM_DISABLE=1. It never uses sudo, never runs an admin prompt, and never installs a login item. (Windows doesn't need it: the Windows installer adds the bundled CLI to your user PATH itself, and never edits your shell files. OpenKnowledge no longer ships a Linux AppImage, but a build launched from one skips the shim too, because an AppImage has no fixed install location to link to.)
The first two rows below live in OpenKnowledge's own ~/.ok/ directory and are maintained automatically. The third — the only write into files OpenKnowledge doesn't own — happens only with your consent: the first-launch dialog has an "Add the ok command to your terminal" toggle (unchecked by default), and nothing is written to your shell config unless you check it.
| Path | What it is | Scope |
|---|---|---|
~/.ok/bin/ok, ~/.ok/bin/open-knowledge | Symlinks to the CLI bundled inside the app | Outside-project (home dir) |
~/.ok/env.sh | A managed shim that prepends ~/.ok/bin to your PATH | Outside-project (home dir) |
~/.zshrc, ~/.bash_profile, ~/.bashrc (Linux), ~/.config/fish/conf.d/open-knowledge.fish | A fenced managed block that sources ~/.ok/env.sh — written only if you consent in the first-launch dialog. The block is created in the startup file for your login shell, and maintained in any of these that already exists, except ~/.bashrc, which is only ever touched on Linux | Outside-project (shell config) |
~/.ok-beta/bin/ok-beta, ~/.ok-beta/bin/open-knowledge-beta | Beta-only symlinks to the CLI bundled inside OpenKnowledge Beta | Outside-project (home dir) |
~/.ok-beta/env.sh, ~/.config/fish/conf.d/open-knowledge-beta.fish | Beta's separate environment shim and fish startup file; other shells receive a separately fenced open-knowledge beta cli block | Outside-project (home dir / shell config) |
If you decline, only ok typed in an external terminal (Terminal, iTerm) is affected — the app's built-in terminal, the MCP server, and the "Open with AI" launches all work without it. You can add it later from File → Set up OpenKnowledge integrations…. Machines that already had the block from a version before the consent dialog are treated as consented: the block is left in place and maintained.
The managed block is clearly fenced so you can see and remove it:
# >>> open-knowledge cli >>>
# ! Contents within this block are managed by OpenKnowledge. Do not edit.
# ! Delete this whole block to opt out — OpenKnowledge will not re-add it.
[ -f "$HOME/.ok/env.sh" ] && . "$HOME/.ok/env.sh"
# <<< open-knowledge cli <<<Delete the block and the app won't re-add it — the removal is recorded and respected. Or set OK_RECLAIM_DISABLE=1 to disable all of this before first launch.
User-global Agent Skills
OpenKnowledge ships two user-global Agent Skills — open-knowledge-discovery (helps your coding agent recognize and route through OpenKnowledge projects) and open-knowledge-write-skill (a workflow for authoring new skills). They install into each detected editor's global skill folder (~/.claude/skills/, ~/.cursor/skills/, ~/.codex/skills/, ~/.opencode/skills/, ~/.lmstudio/skills/) plus the shared ~/.agents/skills/ hub.
Only open-knowledge-discovery is offered at first launch — it is what lets an agent recognize an OpenKnowledge project at all, so it is offered beside the MCP wiring. Every first-launch option starts unchecked, so nothing is installed unless you tick it. open-knowledge-write-skill is an authoring convenience with no bearing on whether your tools work, so setup neither installs it nor records a decision about it; it is offered the first time you open Settings → Skills Studio, and remains installable there afterwards.
Both are consent-gated, but at different moments. Leaving open-knowledge-discovery unchecked at first launch installs nothing and records no decision, so ok init or Skills Studio can still install it later. open-knowledge-write-skill has no first-launch step at all, so nothing is decided about it until you install it from Skills Studio — there is no option to decline it during setup, because setup never asks. Uninstalling either one from Settings → Skills Studio removes its copies and records that choice in ~/.ok/skill-state.yml; removing open-knowledge-discovery from Settings → Agent connections records the same choice once no copy of it is left. The desktop app, ok repair-skills, and a plain ok init all honor it, so a skill you removed is not re-added until you install it again from either pane or name it with ok init --skills <ids>. The desktop app never installs a skill nobody has chosen. ok start installs no user-global skills. Machines that already had the skills before the consent dialog are treated as consented (left in place).
Setting up a project
When you initialize or open a project, the app scaffolds the same project files the CLI's ok init creates, and registers the open-knowledge MCP server with the AI editors it detects. The MCP registration is surgical — it touches only its own entry and leaves your other settings, comments, and formatting byte-for-byte intact. "Its own entry" means the one named open-knowledge; if that name is already taken by something OpenKnowledge does not recognize, see Opt-outs in one place.
| Path | What it is | Scope |
|---|---|---|
.ok/, .ok/config.yml | Project directory and its config | In-project, committed |
.ok/.gitignore | Keeps machine-local runtime state (local/, principal.json, server.lock, …) out of git | In-project, committed |
.okignore | Paths excluded from the editor, search, and agents — see Ignore patterns | In-project, committed |
.mcp.json, .cursor/mcp.json, .codex/config.toml, opencode.json | Project-scoped MCP registration for the four MCP-capable project editors (Claude, Cursor, Codex, OpenCode), written regardless of what's installed so the repo is ready for teammates | In-project, committed |
.pi/extensions/open-knowledge.ts | Managed bridge extension connecting Pi (which has no MCP support) to the project | In-project, committed |
.claude/skills/, .cursor/skills/, .codex/skills/, .github/skills/, .opencode/skills/, .pi/skills/ | Project-local "rich" OpenKnowledge skill (SKILL.md) for Claude, Cursor, Codex, GitHub Copilot, OpenCode, and Pi | In-project, committed |
.ok/skills-lock.json | Provenance for imported skills — source, selected skill, commit/ref when available, content hash, publisher, and import time | In-project, committed |
~/.claude.json, ~/Library/Application Support/Claude/claude_desktop_config.json, ~/.cursor/mcp.json, ~/.codex/config.toml, ~/.copilot/mcp-config.json, ~/.config/opencode/opencode.json, ~/.openclaw/openclaw.json, ~/.gemini/config/mcp_config.json, ~/.lmstudio/mcp.json, ~/.hermes/config.yaml | User-level open-knowledge MCP registration, one per detected editor, so it's available in every project (~/.copilot/mcp-config.json only when ~/.copilot/ exists; ~/.openclaw/openclaw.json only when ~/.openclaw/ exists; ~/.gemini/config/mcp_config.json is Antigravity's shared IDE + agy config, only when ~/.gemini/ exists; ~/.lmstudio/mcp.json and ~/.hermes/config.yaml only when those apps are installed) | Outside-project (editor config) |
The Scope column assumes you share this setup with your team. New projects don't: they keep OpenKnowledge's config to yourself, adding every in-project path above to .git/info/exclude, so those files are written but stay out of git.
Beta uses its own entry
Each product registers under its own name, so Stable and Beta can both be connected to the same editor without overwriting each other. Stable uses open-knowledge; Beta uses open-knowledge-beta, with its own launcher that runs OpenKnowledge Beta and falls back to npx @inkeep/open-knowledge@beta. Everywhere this page names the open-knowledge entry, Beta's app, repair sweeps, and ok-beta init act only on open-knowledge-beta, and Beta's Pi bridge is .pi/extensions/open-knowledge-beta.ts. Agents see Beta's tools as mcp__open-knowledge-beta__*, and Pi sees them as ok-beta_*. The two apps do not share a project's server, though; see Stable and Beta on the same project.
Earlier releases of the separately installed OpenKnowledge Beta app registered under open-knowledge, and updating does not move that entry. If an editor's config has no open-knowledge-beta entry, reconnect that editor from Settings → Agent connections in OpenKnowledge Beta, then remove the old open-knowledge entry from the file listed under ok init if you don't also run Stable. An older Beta install still named OpenKnowledge keeps using open-knowledge; leave that entry in place.
A CLI process decides which product it belongs to in this order: the OK_CHANNEL environment variable (stable, beta, or dev; any other value is an error), then the name of the executable it runs as, and otherwise Stable. The CLI bundled in OpenKnowledge Beta resolves as Beta from its executable name, and Beta's launcher sets OK_CHANNEL=beta before it falls back to npx. A CLI run under plain Node, such as npx @inkeep/open-knowledge@beta init typed by hand, resolves as Stable and writes the open-knowledge entry unless you set OK_CHANNEL=beta.
dev is the product for building OpenKnowledge from source. An unpackaged desktop build and the packages/app dev server select it when OK_CHANNEL is unset, and ok init --dev-mcp does too. It registers as open-knowledge-dev, in project config only, never in your user-level editor config. A dev build claims the openknowledge-dev:// link scheme only when you set OK_DEV_PROTOCOL=1. Set OK_CHANNEL=stable to run a source build as Stable on purpose. A dev build never writes an MCP launcher for an installed product, and never hands OK_CHANNEL=dev to a CLI it does not control: its own CLI calls run the checkout's packages/cli/dist/cli.mjs, while terminals and agents it starts get no OK_CHANNEL. Build the checkout first: without packages/cli/dist/cli.mjs, those calls run the open-knowledge on your PATH as Stable, and the dev build refuses anything that would change Stable: signing in or out, storing a token, and cloning a project. Run pnpm build in the checkout, then restart the dev build. ok uninstall from an installed product leaves the dev footprint in place; delete ~/.ok-dev/ and the open-knowledge-dev credential yourself.
Upgrading Beta to its own home folder
Beta now keeps its data in ~/.ok-beta/ (see Stable and Beta home folders), so the first launch after this change starts fresh: settings, logs, saved themes, agent chat history, and your user config in global.yml, including any GitHub Enterprise Server host declarations, all begin empty. Beta also reads credentials from its own credential-store service, so sign in again. The data an earlier Beta wrote to ~/.ok/ stays there for Stable; copy ~/.ok/global.yml or ~/.ok/themes/ into ~/.ok-beta/ yourself if you want them in Beta too.
An earlier Beta stored its GitHub token in the OS credential store under the service open-knowledge. That token stays there and now belongs to Stable: signing out of Beta and uninstalling Beta both leave it in place. Remove it with Stable's ok auth signout, or delete it from your credential store directly.
While a project is open
The app runs a collaboration server for the open project. It keeps coordination state gitignored under .ok/local/, diagnostics in the product's user-level logs/projects/<project-hash>/, and a shadow git repo that powers the timeline and recovery features:
| Path | What it is | Scope |
|---|---|---|
.ok/local/server.lock | Advertise the running server's URL and capabilities (the ui capability marks a UI-serving server), and the product that started it (channel: stable, beta, or dev for a source build); see Stable and Beta on the same project | In-project, gitignored |
.ok/local/principal.json | Your local identity (id, email) for edit attribution | In-project, gitignored |
.ok/local/sync-state.json | GitHub-sync engine state | In-project, gitignored |
.ok/local/conflicts.json | Every conflict the app is holding a document for, including conflicts that involve no remote. A row for OpenKnowledge's own merge of the editor against disk embeds up to three full copies of the document body, so keep this file while any conflict is open. Deleting it loses those copies. If the app cannot read the file, it renames it to conflicts.json.corrupt-<timestamp> and leaves it in place | In-project, gitignored |
.ok/local/stale-external-writes.json | Recovery snapshot for a rejected stale external save. It can hold the acknowledged, rejected, and retained document text. Protection expires after 30 minutes, but an unresolved snapshot stays until you resolve the conflict | In-project, gitignored |
.ok/local/doc-notices.json | The notice a document or settings file shows after both versions of an edit were kept, or a version was saved to its history or the backup folder instead of merged, and, for a document or skill but not a settings file, a separate notice while a save of it is held, removed once that save lands or OpenKnowledge restarts with nothing held: document names, file paths, times, causes, and history entry ids, never document text. A notice is removed when you dismiss it, when its document is deleted, when the version it names leaves the timeline, or when more than 200 newer notices, counted across all branches, push it out. It follows its document through a rename, and each branch keeps its own. If the app cannot read the file, it starts with no notices | In-project, gitignored |
.ok/local/receipts.jsonl | One record per document OpenKnowledge has opened or saved: a hash of the version it and the file last agreed on, its size, and the file's identity and modification time. No document text. OpenKnowledge keeps the same record in memory while it runs, and a save of a Markdown, Mermaid, Excalidraw or plain-text document compares the file with that record first, so an outside edit is merged, or saved to history, instead of written over; settings files compare against the last version OpenKnowledge read or wrote instead, and other writers do not check it yet. After a restart the file is only used to count documents changed while OpenKnowledge was closed. Safe to delete: the next load rebuilds it | In-project, gitignored |
.ok/local/state.json | State-schema manifest | In-project, gitignored |
~/.ok/logs/projects/<project-hash>/last-spawn-error.log | Startup stderr from detached servers; starts over on the next attempt after reaching 256 KB | Outside-project (home dir) |
.ok/local/acp-agents.json | Read, not written: your own list of custom in-app agents, re-read every time the agent catalog is built | In-project, gitignored |
.ok/local/acp-launch-failures.log | In-app agent launches that failed: when, which agent, why, and the last lines the agent printed before it exited, so a bug report shows the cause without a re-run. Starts over once it passes 256 KB | In-project, gitignored |
.ok/local/last-server-exit.json | Why the collaboration server the app started last exited — a timestamp, its process id, the exit code, the signal that ended it, and which part of the app was watching. One record, overwritten on each exit; a server the app only attached to, or one you started yourself with ok start, leaves none. No document content or paths | In-project, gitignored |
.ok/local/last-server-crash.json | The collaboration server's own account of a crash it did not survive — a timestamp, the error message and stack, its process id, and how long it had been running. Written by the server itself, so it covers ok start too. Holds the most recent crash only | In-project, gitignored |
~/.ok/logs/projects/<project-hash>/spans-*.jsonl | Local diagnostic spans, rotated at ~50 MB | Outside-project (home dir) |
~/.ok/logs/projects/<project-hash>/server-*.jsonl | Local server logs, rotated at ~25 MB | Outside-project (home dir) |
.ok/local/cache/<branch>/backlinks.json | Backlink-graph cache | In-project, gitignored |
.ok/local/installed-skills.json | Per-project skill-install markers (which editors each skill is projected into) | In-project, gitignored |
.ok/local/agent-skill/open-knowledge/ | Runtime copy of the OpenKnowledge project skill (SKILL.md and references/), refreshed before in-app agent processes start. New in-app agent sessions receive this guidance automatically, even when the skill is not installed into an editor | In-project, gitignored with the local/ ignore rule |
.ok/local/skill-move-retained.json | Bookkeeping for a skill move between Project and Global scope that could not finish: which destination copy was kept, why, and what the source looked like at the time. Keyed by scope and skill name, one record each. A record clears when a later move of that skill completes, when the copy at the destination stops matching the one recorded, or when you delete that skill at that scope. No document content | In-project, gitignored |
.ok/local/terminal/claude-settings-{mcp,tools,mcp-tools}.json | Windows-only Claude launch settings written when Open in Claude requests MCP or tool preapproval; one of three possible files, overwritten rather than appended on each launch that uses that combination. macOS and Linux pass the same settings inline | In-project, gitignored |
.ok/local/comments/ | Comments left on documents, one JSON file each — the note, the passage it quotes, and whether it has been sent | In-project, gitignored |
.ok/worktrees/<branch>/ | Git worktree checkout created when you open a branch in its own window (project switcher); the path is also added to .git/info/exclude | In-project, gitignored |
.git/ok/ — or .git/worktrees/<name>/ok/ in a linked worktree, or the enclosing repo's .git/ok-<slug>/ when your project is a subfolder of a larger repo | Shadow git repo holding per-writer work-in-progress refs, plus the versions OpenKnowledge set aside when an outside change could not be merged: of documents, Mermaid, Excalidraw and plain-text files, global and external skills, and the project, per-machine (.ok/local/config.yml) and user (~/.ok/global.yml) settings files. Those are saved as their own history entries, which info/exclude does not filter, so a copy of this folder can carry per-machine settings, your user settings and global skill text; each kind keeps its 50 newest per document, with no time limit. Always inside a git admin dir, never in your content tree. Its own info/exclude file, written when OpenKnowledge opens the repo, keeps machine-local runtime state — .ok/local/ and .ok/worktrees/, plus the pre-.ok/local/ equivalents that older projects still keep at the .ok/ root (.ok/principal.json, .ok/server.lock, .ok/cache/, …) — the .tmp.<uuid> files an in-flight atomic write leaves behind, and your project's .git when it resolves to a directory inside the project under another name (a .git.nosync symlink or a separate git dir), out of every work-in-progress version, the way .ok/.gitignore keeps them out of git | In-project, gitignored (inside .git/) |
The project hash comes from the canonical project-folder path, so projects with the same name keep separate logs. Existing project-local diagnostic files are left in place; support bundles still collect them, using legacy/ entries when both old and current files exist.
When local diagnostic sinks are enabled, server startup removes inactive project log directories only when the directory and all recognized diagnostic files are older than seven days. With telemetry.localSink.enabled: false or OK_DISABLE_LOCAL_SINK=1, startup skips this cleanup; detached-server launch only refreshes its own stderr directory. Live servers remain protected even when quiet; uncertain ownership, symlinks, or unfamiliar contents prevent cleanup. This runs on later launches, not on a timer. ok deinit leaves these user-level diagnostics for that cleanup rather than deleting them immediately.
Diagnostic logs and telemetry are on by default but local-only — credential-bearing attributes are redacted ([REDACTED]) before anything is written, the files rotate at the size caps above, and the files stay local unless shared, including in a support bundle. Turn the local sink off with telemetry.localSink.enabled: false; see Configuration.
On each launch and project open, the app also runs repair sweeps: it rewrites existing open-knowledge MCP entries (in the editor configs above) to the current canonical form, and removes any stale open-knowledge-ui entry left in .claude/launch.json by an older OK version. It never adds an MCP entry to an editor that doesn't already have one. Same OK_RECLAIM_DISABLE=1 opt-out.
Skills are never installed by a sweep. OpenKnowledge writes a skill into editor folders only when you ask for one — the first-launch setup dialog, the Settings toggles, Skills Studio, or ok init. A launch does two housekeeping passes over installed editor skills and writes nothing new into those folders: it removes superseded pre-split open-knowledge copies OpenKnowledge itself left in your agent folders, and it removes a bundle you switched off that is still on disk.
Stable and Beta on the same project
Only one OpenKnowledge app serves a project at a time. server.lock records which product started the server, resolved the same way a CLI process picks its product. When OpenKnowledge Beta opens a project that Stable is serving, or the other way round, it does not connect to that server, take it over, or stop it on its own. It shows This project is open in another OpenKnowledge app, naming the app that holds it (for example OpenKnowledge (Stable)), and Restart server reports that the other app keeps the project. A lock that names a product this app does not know gets the same treatment. A server started by an unpackaged desktop build or the packages/app dev server names dev, so installed Stable and Beta treat it as another app too. The same dialog appears when another app's lock blocks the open in other ways too: its server is not answering, a server of this app collided with that lock, or a new server timed out because that lock was already held. This dialog is the only way the app stops another app's server.
Closing the other app's window does not free the project, because its server keeps running in the background. To move the project, choose the dialog's Stop … Server & Open Here button (for example Stop OpenKnowledge (Stable) Server & Open Here). Every window, editor, or agent connected to that server loses its connection to the project. Cancel is the default and stops nothing. From a terminal, ok stop --force in the project folder does the same. Without --force, ok stop declines, and exits 1, when the lock names a different app than the one its CLI resolves to.
A server you start with ok start, or one an editor's MCP connection starts, counts as the product its CLI resolves to. Under plain Node that is Stable unless OK_CHANNEL=beta is set, so OpenKnowledge Beta also refuses a project served that way. A server an editor's MCP connection started does not stop when that session ends. It stops on its own once nothing has had the project open for a while (30 minutes by default), so you can also wait for it. Stopping it from the dialog interrupts whatever the agent or editor is doing right now, and the agent's next request reaches the server the app opened.
A lock written by an earlier release has no channel, and both apps attach to it as before. An app from an earlier release does not read channel at all, so the rule holds only once both apps are on this release.
Home directory and credentials (~/.ok/)
Beta writes the ~/.ok/ entries below under ~/.ok-beta/ instead, except the shared Global-scope skill files (~/.ok/local/installed-skills.json, ~/.ok/local/skill-placements.json, ~/.ok/local/skill-move-retained.json, and ~/.ok/skills-lock.json), which every product keeps in ~/.ok/; see Stable and Beta home folders.
| Path | What it is | Sensitive? |
|---|---|---|
~/.ok/global.yml | User-global config (applies to every project) | No |
| OS credential store | Embeddings provider keys for semantic search, isolated by release channel, project and endpoint; service names and recovery are in credential store troubleshooting | Yes |
~/.ok/secrets.yml | Legacy embeddings keys awaiting verified migration, or the file fallback when no supported credential store is available. Written 0600; never in config.yml | Yes (0600) |
~/.ok/secrets.yml.embeddings-index, ~/.ok/secrets.yml.embeddings-index.required, ~/.ok/secrets.yml.embeddings-lock.sqlite | Credential inventory and cross-process coordination; contains project paths and endpoint names, never API keys | Local metadata (0600) |
~/.ok/auth.yml | Auth-token fallback, used only when the Keychain is unavailable. Written 0600 | Yes (0600) |
~/.ok/skill-state.yml, ~/.ok/skill-install-events.jsonl | Skill-install bookkeeping | No |
~/.agents/skills/<name>/, ~/.claude/skills/<name>/, … | Your global-scope skills, versioned in place in your home editor dirs (kept by ok uninstall unless --purge-content) | No |
~/.ok/local/installed-skills.json, ~/.ok/local/skill-placements.json, ~/.ok/local/skill-move-retained.json, ~/.ok/skills-lock.json | The same skill-install markers, placement records, unfinished-scope-move bookkeeping, and import provenance that a project keeps under its own .ok/, written under your home directory for Global-scope skills instead. Shared by every product: Beta writes these to ~/.ok/ too | No |
~/.ok/stats.jsonl | Local "open with AI" handoff stats — local-only, no phone-home | No |
~/.ok/agent-browser/<chat>/ | Only while Let agent chats use a browser is on: npm/, the folder that chat's browser server starts from, rebuilt each time it launches, and files/, everything the browser saves. Removed when you delete the chat in OpenKnowledge, or when you close a chat you never sent a message to; turning the setting off keeps it, and a closed chat you did message keeps it until you delete that chat, so delete the folder yourself to remove every chat's saved files at once | No |
_npx/<hash>/ in the npm cache that launch uses: your own npm cache (~/.npm unless your npm_config_cache says otherwise) when the agent runs through your system npx, or OpenKnowledge's managed Node.js runtime cache at ~/.ok/runtimes/cache/node when no usable system Node.js was found and the agent runs on that runtime | Written when OpenKnowledge installs or launches an in-app agent through npx, a custom command such as npx -y <package> included, and when the browser server a Claude Code or Codex chat starts while Let agent chats use a browser is on installs @playwright/mcp. OpenKnowledge repairs the entry only for catalog-managed agents and the browser server, never for custom agent commands or uv-managed adapters. When npm reports that the installed copy is missing as a catalog-managed agent starts, OpenKnowledge installs it again once. When npm reports that the entry is missing its package.json, OpenKnowledge deletes that one directory and relaunches the agent once, which installs it again. The browser server's entry is cleared the same way and reinstalled once | No |
~/.ok/themes/ | Your saved color themes from the Themes plugin, one Tinted Theming base16 YAML file per theme, written when you create or edit a theme | No |
~/.ok/edit-backups/discarded/projects/<project>/<document>/, ~/.ok/edit-backups/discarded/<skill>/ | A copy of a version OpenKnowledge set aside but could not save to the project's history, for example in a project with no shadow repo: the outside version of a Mermaid, Excalidraw or plain-text file, a skill's outside version that could not be merged, or a settings version that was replaced. Files of a project go in a folder for that project (<project> is a short hash of its content folder), so two projects with the same file keep separate copies; global and external skills keep one folder each. Each copy is named for the time it was kept, and the five newest per folder stay. The notice on the document, or in Settings, names the file | No |
~/.ok/mcp-status.json | First-launch MCP consent record | No |
~/.ok/logs/ (including projects/<project-hash>/), ~/.ok/bug-reports/ | Desktop and CLI logs, and bug-report bundles from ok bug-report and the app's Help → Report a bug… dialog (ok diagnose bundle writes into the project, under .ok/local/diagnostics/). Each report from the dialog also gets a small YAML record holding its send state and a secret-redacted copy of the note you wrote, so report history can still show what a report was about. The zip is deleted once the report is sent; the record is kept, and both go when you delete the report from report history. If that record ever can't be read back, OpenKnowledge leaves it exactly as it is rather than overwriting your note, and writes a second tiny .sent.yaml file beside it when a report does send, so history still shows it as sent instead of offering to send it again | No |
~/.ok/bin/, ~/.ok/env.sh | PATH shim (see Shell and PATH above) | No |
Auth tokens (for GitHub sync, sharing, and cloning) are stored in your OS credential store under the service name open-knowledge (open-knowledge-beta for Beta) — the Keychain on macOS, Credential Manager on Windows, and the Secret Service keyring (libsecret) on Linux. The ~/.ok/auth.yml file is only a fallback for headless environments where the credential store isn't reachable; when it becomes available, the token is migrated into it and the file copy is removed.
The Install for Claude Chat & Cowork command (command palette or Help menu) builds ~/Downloads/openknowledge.skill on demand and hands it to Claude Desktop for upload; the build is version-gated via ~/.ok/skill-state.yml.
Installing the package
Installing @inkeep/open-knowledge from npm (or invoking it with npx) drops the two CLI binaries plus a bundled native addon. Nothing is written to your home directory at install time — no lifecycle scripts run, and no skills are registered until you run ok init.
| Path | What it is | Scope |
|---|---|---|
ok, open-knowledge (on your PATH) | The two CLI binaries (identical entry point) | Outside-project (npm global/bin) |
<pkg>/dist/native/ | Bundled native addon, shipped inside the package: TOML editing on all platforms, plus a Windows-only reader of a process's creation time, which confirms that the process a server lock names is the server that wrote it | Outside-project (package dir) |
Opt out
Installing the package writes nothing outside its own directory, so there is nothing to opt out of here. The user-global skills are installed by ok init, and ok init --no-skills skips installing them for that run.
ok init
ok init turns a folder into an OpenKnowledge project. It scaffolds the project's .ok/ directory, and — unless you pass --no-mcp — registers the open-knowledge MCP server with the AI editors it detects. The MCP registration is surgical: it touches only the entry named open-knowledge and leaves your other settings, comments, and formatting byte-for-byte intact (if a config cannot be read or updated safely, it is left untouched and the reason is reported; follow that reason when repairing permissions, the path, or syntax. If it reports no format-preserving writer available, reinstall OpenKnowledge to restore its TOML writer or configure the integration manually).
| Path | What it is | Scope |
|---|---|---|
.ok/, .ok/config.yml | Project directory and its config | In-project, committed |
.ok/.gitignore | Keeps machine-local runtime state (local/, principal.json, server.lock, …) out of git | In-project, committed |
.okignore | Paths excluded from the editor, search, and agents — see Ignore patterns | In-project, committed |
.gitignore (project root) | Seeded (with .DS_Store) only when ok init creates a new git repo | In-project, committed |
.mcp.json, .cursor/mcp.json, .codex/config.toml, opencode.json | Project-scoped MCP registration for the four MCP-capable project editors (Claude, Cursor, Codex, OpenCode) regardless of what's installed — prepares the repo for teammates (with --scope project or both) | In-project, committed |
.pi/extensions/open-knowledge.ts | Managed bridge extension connecting Pi (which has no MCP support) to the project | In-project, committed |
.claude/skills/, .cursor/skills/, .codex/skills/, .github/skills/, .opencode/skills/, .pi/skills/ | Project-local "rich" OpenKnowledge skill (SKILL.md) for Claude, Cursor, Codex, GitHub Copilot, OpenCode, and Pi | In-project, committed |
.ok/skills-lock.json | Provenance for imported skills — source, selected skill, commit/ref when available, content hash, publisher, and import time | In-project, committed |
With --scope user or both (the default), ok init also registers the open-knowledge MCP server in each detected editor's user-level config, so it's available in every project:
| Path | Editor | Scope |
|---|---|---|
~/.claude.json | Claude Code | Outside-project (editor config) |
~/Library/Application Support/Claude/claude_desktop_config.json | Claude Desktop | Outside-project (editor config) |
~/.cursor/mcp.json | Cursor | Outside-project (editor config) |
~/.codex/config.toml | Codex | Outside-project (editor config) |
~/.copilot/mcp-config.json | GitHub Copilot CLI (only when ~/.copilot/ exists; respects COPILOT_HOME) | Outside-project (editor config) |
~/.config/opencode/opencode.json | OpenCode | Outside-project (editor config) |
~/.openclaw/openclaw.json | OpenClaw (only when ~/.openclaw/ exists) | Outside-project (editor config) |
~/.gemini/config/mcp_config.json | Antigravity (only when ~/.gemini/ exists) — shared by the IDE and the agy CLI | Outside-project (editor config) |
~/.lmstudio/mcp.json | LM Studio (only when installed; also checks ~/.cache/lm-studio/mcp.json) | Outside-project (editor config) |
~/.hermes/config.yaml | Hermes (only when ~/.hermes/ exists) | Outside-project (editor config) |
ok init also installs the user-global discovery skill — a short instruction file that teaches an agent host how to find and initialize OpenKnowledge — so it is available in every project. It is written only into the skills directories of agent hosts already present in your home directory, plus the shared ~/.agents/skills/ hub those hosts read. If none of them is present, nothing is written at all.
| Path | What it is | Scope |
|---|---|---|
~/.agents/skills/open-knowledge-*/ | Shared hub read natively by Codex, OpenCode, and Cursor | Outside-project (home dir) |
~/.claude/skills/open-knowledge-*/ | Written only when ~/.claude/ already exists | Outside-project (home dir) |
~/.lmstudio/skills/open-knowledge-*/ | Written only when ~/.lmstudio/ already exists (LM Studio reads these in agent mode) | Outside-project (home dir) |
~/.cursor/skills/open-knowledge-*/ | Written only when ~/.cursor/ already exists | Outside-project (home dir) |
~/.codex/skills/open-knowledge-*/ | Written only when ~/.codex/ already exists | Outside-project (home dir) |
~/.opencode/skills/open-knowledge-*/ | Written only when ~/.opencode/ already exists | Outside-project (home dir) |
~/.ok/skill-state.yml | Records which skill version is installed, so the step is skipped next time | Outside-project (home dir) |
~/.ok/skill-install-events.jsonl | Append-only local log of skill-install attempts | Outside-project (home dir) |
The install is non-fatal (ok init still exits 0 if it fails), version-gated (a no-op when the current version is already installed), and needs no network access. Skip it for one run with ok init --no-skills, or choose individual bundles with --skills <ids>. Skipping records nothing and removes nothing, so skills already on the machine are left alone. An installed bundle is remembered in ~/.ok/skill-state.yml and honored by every later install path. Leaving a skill unchecked at the first-launch prompt records nothing, so a later ok init still installs open-knowledge-discovery. To turn a built-in skill off for good, uninstall it from Settings → Skills Studio, or remove open-knowledge-discovery from Settings → Agent connections; either records a durable machine-wide choice: a plain ok init then reports it as turned off and leaves it uninstalled, and only naming it with --skills <ids> or installing it again from either pane brings it back. If ok init cannot read that file, it installs nothing for the skill and says so rather than risk reversing your choice. ok repair-skills explicitly repairs these user-global bundles. Its project sweep restores missing skill copies but leaves existing project copies unchanged; see Refresh agent guidance to update those.
Pi has no user-level MCP config. ok init writes its project-scoped bridge extension; using Pi inside OpenKnowledge can also add a folder trust grant, whose location respects PI_CODING_AGENT_DIR.
On Windows, Claude Desktop and OpenCode configs live under %APPDATA%\Claude\ and %APPDATA%\opencode\, and the MCP entry is a PowerShell launcher.
ok init also installs open-knowledge-discovery (the same skill first launch offers — pass --skills discovery,write-skill to add the authoring skill too), skipping any skill you turned off in Skills Studio or Agent connections unless you name it with --skills, and, for a project it is setting up for the first time, adds the OpenKnowledge paths to .git/info/exclude so .ok/ stays off your remote. Pass --shared to commit it instead. Re-running ok init on a project you already set up keeps that project's current choice. Switch modes later with ok config-sharing share / unshare (unshare refuses if an OK config file is already tracked); ok config-sharing status prints the current mode and the excluded paths.
Controlling it
--no-mcp— register nothing in any editor's MCP config.ok initstill scaffolds.ok/and writes the project-localopen-knowledgeskill; GitHub Copilot's copy is written only when Copilot already has an OpenKnowledge MCP entry.--scope user | project | both— where the MCP entry is written. In an interactive terminal,ok initprompts for this; scripted/CI runs default toboth, so pass the flag to constrain them.--no-skills— install no user-global skills on this run;--skills discovery,write-skill— install only the named bundles. Default installsdiscoveryonly, matching what the desktop's first launch offers, and skips a bundle you turned off in Skills Studio or Agent connections; naming a bundle with--skillsinstalls it even then.write-skillis opt-in here and in Settings → Skills Studio. Installing is recorded and honored by the desktop app too; skipping is not recorded, so it never affects another project. Neither flag affects the project-localopen-knowledgeskill, which is still written.--shared(vs--local-only) — commit.ok/rather than keeping it out of git.
ok start
ok start runs the collaboration server. Most of what it writes stays inside your project, gitignored under .ok/local/, plus a shadow git repo for the timeline and recovery features:
| Path | What it is | Scope |
|---|---|---|
.ok/local/server.lock | Advertise the running server's URL and capabilities (the ui capability marks a UI-serving server), and the product that started it (channel: stable, beta, or dev for a source build); see Stable and Beta on the same project | In-project, gitignored |
.ok/local/principal.json | Your local identity (id, email) for edit attribution | In-project, gitignored |
.ok/local/sync-state.json | GitHub-sync engine state | In-project, gitignored |
.ok/local/conflicts.json | Every conflict the app is holding a document for, including conflicts that involve no remote. A row for OpenKnowledge's own merge of the editor against disk embeds up to three full copies of the document body, so keep this file while any conflict is open. Deleting it loses those copies. If the app cannot read the file, it renames it to conflicts.json.corrupt-<timestamp> and leaves it in place | In-project, gitignored |
.ok/local/stale-external-writes.json | Recovery snapshot for a rejected stale external save. It can hold the acknowledged, rejected, and retained document text. Protection expires after 30 minutes, but an unresolved snapshot stays until you resolve the conflict | In-project, gitignored |
.ok/local/doc-notices.json | The notice a document or settings file shows after both versions of an edit were kept, or a version was saved to its history or the backup folder instead of merged, and, for a document or skill but not a settings file, a separate notice while a save of it is held, removed once that save lands or OpenKnowledge restarts with nothing held: document names, file paths, times, causes, and history entry ids, never document text. A notice is removed when you dismiss it, when its document is deleted, when the version it names leaves the timeline, or when more than 200 newer notices, counted across all branches, push it out. It follows its document through a rename, and each branch keeps its own. If the app cannot read the file, it starts with no notices | In-project, gitignored |
.ok/local/receipts.jsonl | One record per document OpenKnowledge has opened or saved: a hash of the version it and the file last agreed on, its size, and the file's identity and modification time. No document text. OpenKnowledge keeps the same record in memory while it runs, and a save of a Markdown, Mermaid, Excalidraw or plain-text document compares the file with that record first, so an outside edit is merged, or saved to history, instead of written over; settings files compare against the last version OpenKnowledge read or wrote instead, and other writers do not check it yet. After a restart the file is only used to count documents changed while OpenKnowledge was closed. Safe to delete: the next load rebuilds it | In-project, gitignored |
.ok/local/state.json | State-schema manifest | In-project, gitignored |
~/.ok/logs/projects/<project-hash>/last-spawn-error.log | Startup stderr from detached servers; starts over on the next attempt after reaching 256 KB | Outside-project (home dir) |
.ok/local/acp-agents.json | Read, not written: your own list of custom in-app agents, re-read every time the agent catalog is built | In-project, gitignored |
.ok/local/acp-launch-failures.log | In-app agent launches that failed: when, which agent, why, and the last lines the agent printed before it exited, so a bug report shows the cause without a re-run. Starts over once it passes 256 KB | In-project, gitignored |
.ok/local/last-server-crash.json | The server's own account of a crash it did not survive — a timestamp, the error message and stack, its process id, and how long it had been running. Holds the most recent crash only | In-project, gitignored |
~/.ok/logs/projects/<project-hash>/spans-*.jsonl | Local diagnostic spans, rotated at ~50 MB | Outside-project (home dir) |
~/.ok/logs/projects/<project-hash>/server-*.jsonl | Local server logs, rotated at ~25 MB | Outside-project (home dir) |
.ok/local/cache/<branch>/backlinks.json | Backlink-graph cache | In-project, gitignored |
.ok/local/installed-skills.json | Per-project skill-install markers (which editors each skill is projected into) | In-project, gitignored |
.ok/local/agent-skill/open-knowledge/ | Runtime copy of the OpenKnowledge project skill (SKILL.md and references/), refreshed before in-app agent processes start. New in-app agent sessions receive this guidance automatically, even when the skill is not installed into an editor | In-project, gitignored with the local/ ignore rule |
.ok/local/skill-move-retained.json | Bookkeeping for a skill move between Project and Global scope that could not finish: which destination copy was kept, why, and what the source looked like at the time. Keyed by scope and skill name, one record each. A record clears when a later move of that skill completes, when the copy at the destination stops matching the one recorded, or when you delete that skill at that scope. No document content | In-project, gitignored |
.ok/local/comments/ | Comments left on documents, one JSON file each — the note, the passage it quotes, and whether it has been sent | In-project, gitignored |
.git/ok/ — or .git/worktrees/<name>/ok/ in a linked worktree, or the enclosing repo's .git/ok-<slug>/ when your project is a subfolder of a larger repo | Shadow git repo holding per-writer work-in-progress refs (powers the timeline), plus the versions OpenKnowledge set aside when an outside change could not be merged: of documents, Mermaid, Excalidraw and plain-text files, global and external skills, and the project, per-machine (.ok/local/config.yml) and user (~/.ok/global.yml) settings files. Those are saved as their own history entries, which info/exclude does not filter, so a copy of this folder can carry per-machine settings, your user settings and global skill text; each kind keeps its 50 newest per document, with no time limit. Always inside a git admin dir, never in your content tree. Its own info/exclude file, written when OpenKnowledge opens the repo, keeps machine-local runtime state — .ok/local/ and .ok/worktrees/, plus the pre-.ok/local/ equivalents that older projects still keep at the .ok/ root (.ok/principal.json, .ok/server.lock, .ok/cache/, …) — the .tmp.<uuid> files an in-flight atomic write leaves behind, and your project's .git when it resolves to a directory inside the project under another name (a .git.nosync symlink or a separate git dir), out of every work-in-progress version, the way .ok/.gitignore keeps them out of git | In-project, gitignored (inside .git/) |
The project hash comes from the canonical project-folder path, so projects with the same name keep separate logs. Existing project-local diagnostic files are left in place; support bundles still collect them, using legacy/ entries when both old and current files exist.
When local diagnostic sinks are enabled, server startup removes inactive project log directories only when the directory and all recognized diagnostic files are older than seven days. With telemetry.localSink.enabled: false or OK_DISABLE_LOCAL_SINK=1, startup skips this cleanup; detached-server launch only refreshes its own stderr directory. Live servers remain protected even when quiet; uncertain ownership, symlinks, or unfamiliar contents prevent cleanup. This runs on later launches, not on a timer. ok deinit leaves these user-level diagnostics for that cleanup rather than deleting them immediately.
Diagnostic logs and telemetry are on by default but local-only — credential-bearing attributes are redacted ([REDACTED]) before anything is written, the files rotate at the size caps above, and the files stay local unless shared, including in a support bundle. Turn the local sink off with telemetry.localSink.enabled: false; see Configuration.
On each boot, ok start also runs repair sweeps: it re-checks a few things that drift as OpenKnowledge updates and rewrites any that have fallen out of the current canonical form — a no-op when nothing has changed, and it never adds an entry that isn't already there.
| What it re-checks | Where | Scope |
|---|---|---|
Existing open-knowledge MCP entries | The same editor configs ok init writes — both user-level (~/.claude.json, ~/.cursor/mcp.json, …) and project-level | Outside-project (editor config) and in-project |
Stale open-knowledge-ui entry in .claude/launch.json | Project | Removed if present — OK no longer writes launch.json |
Disable both repair sweeps with OK_RECLAIM_DISABLE=1. They leave installed editor skills alone. ok repair-skills explicitly restores missing project copies and repairs user-global bundles; refresh existing project guidance with ok init or the integration settings. Starting an in-app agent thread creates or refreshes the runtime skill copy listed above.
Projects initialized by an older CLI may lack the local/ rule in .ok/.gitignore, which leaves these runtime files visible in git status. Add local/ to that file or open the project in the desktop app, which updates it automatically. The runtime skill copy is always excluded from the knowledge base.
ok mcp
ok mcp is the stdio bridge your editor spawns to talk to the server. It routes tool calls to a running ok start backend (starting one on the first tool call that needs it — reads included). When it starts a backend, it captures startup stderr in the user-level project logs listed above.
Home directory and credentials (~/.ok/)
Beta writes the ~/.ok/ entries below under ~/.ok-beta/ instead, except the shared Global-scope skill files (~/.ok/local/installed-skills.json, ~/.ok/local/skill-placements.json, ~/.ok/local/skill-move-retained.json, and ~/.ok/skills-lock.json), which every product keeps in ~/.ok/; see Stable and Beta home folders. Upgrading from an earlier Beta that used ~/.ok/? See Upgrading Beta to its own home folder.
| Path | What it is | Sensitive? |
|---|---|---|
~/.ok/global.yml | User-global config (applies to every project) | No |
| OS credential store | Embeddings provider keys for semantic search, isolated by release channel, project and endpoint | Yes |
~/.ok/secrets.yml | Legacy embeddings keys awaiting verified migration, or the file fallback when no supported credential store is available. Written 0600; never in config.yml | Yes (0600) |
~/.ok/secrets.yml.embeddings-index, ~/.ok/secrets.yml.embeddings-index.required, ~/.ok/secrets.yml.embeddings-lock.sqlite | Credential inventory and cross-process coordination; contains project paths and endpoint names, never API keys | Local metadata (0600) |
~/.ok/auth.yml | Auth-token fallback, used when no OS credential store is reachable. Written 0600 | Yes (0600) |
~/.ok/skill-state.yml, ~/.ok/skill-install-events.jsonl | Skill-install bookkeeping | No |
~/.agents/skills/<name>/, ~/.claude/skills/<name>/, … | Your global-scope skills, versioned in place in your home editor dirs (kept by ok uninstall unless --purge-content) | No |
~/.ok/local/installed-skills.json, ~/.ok/local/skill-placements.json, ~/.ok/local/skill-move-retained.json, ~/.ok/skills-lock.json | The same skill-install markers, placement records, unfinished-scope-move bookkeeping, and import provenance that a project keeps under its own .ok/, written under your home directory for Global-scope skills instead. Shared by every product: Beta writes these to ~/.ok/ too | No |
~/.ok/stats.jsonl | Local "open with AI" handoff stats — local-only, no phone-home | No |
~/.ok/agent-browser/<chat>/ | Only while Let agent chats use a browser is on: npm/, the folder that chat's browser server starts from, rebuilt each time it launches, and files/, everything the browser saves. Removed when you delete the chat in OpenKnowledge, or when you close a chat you never sent a message to; turning the setting off keeps it, and a closed chat you did message keeps it until you delete that chat, so delete the folder yourself to remove every chat's saved files at once | No |
_npx/<hash>/ in the npm cache that launch uses: your own npm cache (~/.npm unless your npm_config_cache says otherwise) when the agent runs through your system npx, or OpenKnowledge's managed Node.js runtime cache at ~/.ok/runtimes/cache/node when no usable system Node.js was found and the agent runs on that runtime | Written when OpenKnowledge installs or launches an in-app agent through npx, a custom command such as npx -y <package> included, and when the browser server a Claude Code or Codex chat starts while Let agent chats use a browser is on installs @playwright/mcp. OpenKnowledge repairs the entry only for catalog-managed agents and the browser server, never for custom agent commands or uv-managed adapters. When npm reports that the installed copy is missing as a catalog-managed agent starts, OpenKnowledge installs it again once. When npm reports that the entry is missing its package.json, OpenKnowledge deletes that one directory and relaunches the agent once, which installs it again. The browser server's entry is cleared the same way and reinstalled once | No |
~/.ok/themes/ | Your saved color themes from the Themes plugin, one Tinted Theming base16 YAML file per theme, written when you create or edit a theme | No |
~/.ok/edit-backups/discarded/projects/<project>/<document>/, ~/.ok/edit-backups/discarded/<skill>/ | A copy of a version OpenKnowledge set aside but could not save to the project's history, for example in a project with no shadow repo: the outside version of a Mermaid, Excalidraw or plain-text file, a skill's outside version that could not be merged, or a settings version that was replaced. Files of a project go in a folder for that project (<project> is a short hash of its content folder), so two projects with the same file keep separate copies; global and external skills keep one folder each. Each copy is named for the time it was kept, and the five newest per folder stay. The notice on the document, or in Settings, names the file | No |
~/.ok/logs/ | CLI logs (cli.<date>.log), size- and age-capped, plus per-project server logs, spans, and startup stderr under projects/<project-hash>/ | No |
~/.ok/bug-reports/ | Bug-report bundles from ok bug-report — the desktop app's Help → Report a bug… dialog writes here too (ok diagnose bundle writes into the project, under .ok/local/diagnostics/). A report filed from the dialog also leaves a small YAML record beside its bundle, holding the report's send state and a secret-redacted copy of the note you wrote so report history can name it. That record outlives the bundle: the zip is deleted once the report is sent, and the record is kept until you delete the report from report history. If the record ever can't be read back, OpenKnowledge leaves it exactly as it is rather than overwriting your note, and writes a second tiny .sent.yaml file beside it when a report does send. That marker holds only the send time and the report's reference, never your note, and it is removed with the rest of the report | No |
Auth tokens (for GitHub sync, sharing, and cloning) are stored in your operating system's secure credential store when one is available — the macOS Keychain (service open-knowledge, or open-knowledge-beta for Beta), or the platform equivalent (Windows Credential Manager, Linux Secret Service) — falling back to a 0600 ~/.ok/auth.yml file on headless systems (a Linux server, CI) where none is reachable.
Versions saved before the shadow exclusions
The shadow repo's info/exclude is forward-only. Versions saved by an earlier OpenKnowledge build, and the work-in-progress commits folded into them, still carry the machine-local paths in their trees: the contents of .ok/local/, including principal.json and server.lock, and the caches and logs beside them. A project that predates .ok/local/ carries the same runtime state at the .ok/ root instead — .ok/principal.json, .ok/state.json, .ok/server.lock, .ok/ui.lock, .ok/sync-state.json, .ok/conflicts.json and .ok/last-spawn-error.log, alongside .ok/cache/ and .ok/tmp/. Opening the project on a current build drops those paths from the shadow repo's staging index and stops adding them to new versions; it does not rewrite the versions already written, and those older commits stay reachable from the versions that folded them. The same forward-only rule covers a git dir that resolves inside your project under a name other than .git (a .git.nosync symlink or a separate git dir): a current build stops staging it and drops it from the index, but versions an earlier build already wrote keep its contents.
All of it stays in the shadow git repo inside your own .git/ directory, which OpenKnowledge never pushes anywhere. A version you saved yourself is kept rather than expired, so this does not age out on its own. ok deinit removes the shadow repo along with the rest of a project's OpenKnowledge state.
Pi folder trust
When you use Pi inside OpenKnowledge and accept its bridge setup prompt, OpenKnowledge also grants Pi trust in the project folder. This applies to both the desktop app and the web app served by ok start; ok init writes the project bridge without adding this trust grant.
| Path | What it is | Scope |
|---|---|---|
~/.pi/agent/trust.json (or $PI_CODING_AGENT_DIR/trust.json) | Pi's trust store. Bridge setup can add an exact-folder trust decision so Pi can load the OpenKnowledge bridge | In-project or Outside-project (follows the trust destination) |
~/.ok/pi-trust/ | Records the previous decision and trust-store path when OpenKnowledge changes a folder's trust. An interrupted, unconfirmed change is not treated as proven ownership | Outside-project (home dir) |
<configured trust path>.lock | Temporary directory lock shared with Pi while accessing its trust store | In-project or Outside-project (follows the configured Pi directory) |
<resolved trust target>.ok.lock | Temporary OpenKnowledge lock coordinating access through different symlinks. For a linked trust file, this sits beside its destination | In-project or Outside-project (follows the trust destination) |
Pi's directory lock coordinates with Pi itself at the configured path. The separate OpenKnowledge lock uses the resolved destination so OpenKnowledge processes using different symlinks also coordinate. Pi's store and locks normally live outside the project; a custom configuration or symlink can place them inside it.
New Pi trust checks, grants, and ownership records use the real project directory, even when the project was opened through a symlink. The setup prompt shows that directory; if the symlink points elsewhere when setup begins, OpenKnowledge refuses the change and asks you to reopen the intended project and approve it again. OpenKnowledge also refuses a project path it cannot resolve or access, instead of falling back to an unverified spelling.
ok deinit, project cleanup selected during ok uninstall, and removing the Pi connection in Settings reverse recorded OpenKnowledge trust changes when the current exact-folder value still matches the recorded grant and no other Pi resources need it. Cleanup restores the previous exact-folder decision, or removes the entry if none existed. Other projects' entries, parent-folder decisions, and Pi's global trust default are preserved; a folder may still be trusted through those settings.
Every Pi trust grant made before ownership recording was introduced lacks a record and is preserved, including grants made by OpenKnowledge. There is no automatic backfill. Older entries under a non-canonical project spelling, such as a symlink path, are also preserved and named when found. Pi does not use those literal keys, and cleanup does not move them to the real-path key. An interrupted setup can leave a pending record that does not prove the trust write completed; setup and cleanup do not reconcile it while the folder remains trusted. To remove an unrecorded or non-canonical grant manually, close Pi and remove only the project's exact-folder key from its trust.json, leaving the other entries intact. The cleanup message names an entry's exact key and file when it can inspect that entry. If the project path is already unavailable when cleanup starts and ownership records can be read, cleanup names those records and their recorded locations without checking current trust decisions. If a later project-path check fails, the affected trust store is left pending with guidance to repair the path and retry. For manual cleanup using a record, inspect the intended destination and restore the recorded previous decision only if you choose to undo a current true entry, removing that key only when there was no previous entry. Parent-folder and global trust settings can still apply; see Pi's project trust rules.
Trust is also kept when other project resources need it, including Pi settings, extensions, skills, prompts, themes, system prompts, and inherited project skills. Cleanup lists up to three of those resources, reports how many more remain, and relinquishes its ownership record where one exists: later cleanup runs will not revoke that grant even if those resources are removed. Manage the retained decision in Pi or remove the exact-folder key manually as described above. Removing the grant may stop Pi from loading those resources. OpenKnowledge's own skill namespace is managed separately in the current project; ancestor skill roots remain outside that project's cleanup and can still require trust.
Bridge setup requires a project directory it can resolve and access, and refuses unreadable trust files or broken or cyclic trust-file symlinks. Cleanup reports a failure if a project path or required trust check cannot be verified, retains retry information, and tells you what to repair. For a missing project, cleanup checks for ownership records under both the supplied path and the missing path appended to its nearest resolvable, accessible ancestor's real path. Healthy directory aliases are followed for this additional record lookup only; it cannot recover a deleted symlink's former target or an ancestor's historical target. With no bridge or record at either checked path, cleanup treats the project as already absent. A record at either path, or an ancestor that cannot be resolved or accessed, requires repairing the project path before retrying. With neither a bridge nor a record and a verifiable project path, cleanup treats the trust store as unrelated and does not inspect it.
PI_CODING_AGENT_DIR changes the trust-store directory; it does not relocate the project's .pi/extensions/open-knowledge.ts bridge. When a bridge or record requires trust cleanup, OpenKnowledge checks the currently configured store as well as saved locations for recorded grants, even if the environment setting has changed. It reports retained exact keys it finds, including the supplied project spelling when it differs from the real path. It does not search arbitrary Pi directories or infer unknown historical aliases for older, unrecorded entries.
Opt-outs in one place
| To skip… | Do this |
|---|---|
The postinstall skill install (CLI) | npm install --ignore-scripts |
The shell-config PATH block (macOS and Linux app) | Leave "Add the ok command to your terminal" unchecked in the first-launch dialog (the default) |
All editor MCP registration in ok init | ok init --no-mcp |
User-global skills in ok init | ok init --no-skills |
The project-local open-knowledge skill | Not skippable at ok init, even with --no-mcp or --no-skills; ok deinit removes it |
| User-level (vs project) MCP writes | ok init --scope project |
Committing .ok/ to git | Off by default for a new project; ok init --shared commits it instead |
The repair sweeps and the desktop app's shell / PATH changes | OK_RECLAIM_DISABLE=1 (also delete the managed block from your shell config to remove the PATH entry) |
| Local diagnostic logs and telemetry | telemetry.localSink.enabled: false in config |
| Auto-starting the MCP server | OK_MCP_AUTOSTART=0 |
To review the footprint after the fact, ok diagnose reports what's on disk (and the desktop path-install.json records exactly which shell/PATH changes were made). To reverse it, ok deinit removes OpenKnowledge from one project and ok uninstall removes the global footprint, with optional project cleanup. It keeps the shared ~/.ok/ entries: no product's uninstall removes ~/.ok/machine-id, and Stable's keeps the rest of that list too. --purge-content also removes the user skills store at ~/.ok/skills/, which every product shares, whichever product you uninstall; it is skipped if an earlier uninstall step failed. Both keep your markdown and authored skills by default; OpenKnowledge's bundled skills are removed. Shared configs and their symlinks are preserved, and incomplete cleanup reports a failure while retaining state needed to retry. Both commands take --dry-run to preview. See the CLI reference for project selection and scripting behavior.
In the desktop app you don't need the CLI for finer control, and the split follows what each thing is. Settings → Agent connections lists every agent OpenKnowledge can wire up, grouped by how you reach it — In app, Terminal, External apps. Each row says whether OpenKnowledge can reach that agent's tools and offers the action that fits: Add MCP & skill when nothing is set up, Manage when something is, and Remove when the tool itself is present but you have turned it off. A tool that is not on this machine always leads with Install, or How to set up when OpenKnowledge has no download link for it; neither writes anything. When OpenKnowledge files are still on disk for a tool that is not on this machine, the row keeps whichever of Install or How to set up it already had, and adds a muted Remove link beside the hint — Not installed · OpenKnowledge files present, or Not detected on this machine · OpenKnowledge files present for a tool OpenKnowledge cannot launch directly. Where one tool has two rows — a CLI and its editor, sharing a single setup — that hint and link appear only when OpenKnowledge can confirm the other row's tool is also absent, so the row for the half you do not have never offers to delete a setup the other half is using — and when it cannot tell, it says nothing rather than guess. Both scopes are chosen in the same place: the dialog behind those actions groups what it writes under This project and This machine, so a project-scoped MCP config and a user-global one sit side by side, each naming the file it touches. Skills live on their own page at both scopes: Settings → Skills Studio carries the skills OpenKnowledge ships (user scope) or the project's own skill (project scope), each with an explicit Install/Uninstall button behind a confirmation naming every path it touches, plus the folders your AI tools read skills from. Removal keeps the guest discipline you would expect: only entries OpenKnowledge recognizably wrote are removed, and anything you customized is left intact.
One case works differently, and it is the only place OpenKnowledge replaces something it did not write. If the entry named open-knowledge is there but OpenKnowledge does not recognize it, because you edited it by hand or another tool claimed the name, that row is offered as an overwrite rather than left dead. It opens unticked with a warning naming the file, so nothing happens until you ask for it, and ticking it replaces that one entry outright rather than merging into it. Other servers in the file are untouched. This is offered only where the config is JSON; for Codex, Hermes, and Pi the entry is left alone, because on those formats OpenKnowledge merges its own keys into an existing entry instead of replacing it, and a merge would leave part of the entry you edited attached to a server OpenKnowledge starts. Removal never takes an unrecognized entry away, in any format.
What leaves your machine
None of your content, by default. Everything above is written to your own disk. The only ways data leaves your machine are these — all opt-in or on-demand, except two automatic actions that carry no document content (the desktop update check and a one-time share-link check on first launch):
| What | When | Where it goes |
|---|---|---|
| Diagnostic bundle | Only when you run ok diagnose bundle (you can inspect it first). On macOS it also carries the crash reports the OS recorded for this app and its helper processes (listed above), which are machine-wide rather than project-scoped; only this app's are collected, never another application's, though a report of ours still names the processes it was running alongside, and the summary printed before the zip is written says what that search found even when the answer is nothing. On every platform it also carries the past week of the operating system's records of this app being ended from outside (listed above), and the same summary says what that read found | Wherever you send it |
| In-app bug report | Only when you click Send in the desktop app's Help → Report a bug… dialog, or the Cmd+Shift+D / Ctrl+Shift+D shortcut that opens the same dialog — it builds a secret-redacted zip you can reveal and inspect first, and nothing is sent without that explicit click. The zip carries a picture of the app window unless you uncheck Screenshot in that dialog, and the preview there is the picture that would be sent. You can also attach up to three images by dropping them on the What happened? box, pasting them anywhere in the dialog (Cmd+V / Ctrl+V), or browsing with the paperclip in that box. Neither these images nor the screenshot are scanned or redacted, so review them before sending. A report started from an agent chat's Report a problem with this chat… also carries, unless you uncheck This conversation, the newest 4 MB of that chat's messages, tool calls, and their output, and the chat's metadata file, which names the chat's title, the project folder's path, the document the chat started from, and the agent and its settings. Known secrets are scrubbed from both. Images and other binary content in the chat, including images pasted into a message, are replaced by a note of their type and size, while text files attached to a message are included and scrubbed the same way. If the chat's messages can't be added, the review step says so and the report goes without the conversation. If only the metadata file can't be read, the report carries the messages without it, and the review step doesn't say so. A report started from the command palette, the Help popover, the Windows and Linux menu bar, or an agent chat's Settings menu photographs the screen with that palette or menu left out, and carries no marker, because the pointer was only choosing the command. To photograph the command palette itself, press the shortcut while it is open. Every other report you start yourself photographs the screen as it is, so an open menu or another person's document visible at the time is in the picture, and carries a marker drawn where your pointer was, since a screenshot never includes the cursor. No marker is drawn either if the pointer has not moved since the window loaded, or has since left the window. The invitation that appears on its own after a crash is the exception to all of this: it carries no picture at all. When the app holds a crash dump, the same dialog adds a Crash dump checkbox. It starts checked on the invitation that follows a crash with a dump available, and unchecked on a report you open yourself. A crash dump is a memory snapshot that can contain document content and can't be redacted, so it is attached only if that box is checked when you create the report, and you review the result before anything is sent. The invitation attaches the dump of the crash it was raised for, never a newer one; if that dump can't be added, the review step says so and the report goes without it. On macOS the zip also carries the update helper's install log (listed above), which is machine-wide rather than project-scoped; the zip's own README names it and says where it came from. At the Detailed diagnostics level — pre-checked on the invitation that follows a crash — it additionally carries the crash reports macOS itself recorded for this app and its helpers (also listed above), which are machine-wide for the same reason and named in the same README; only this app's are collected, never another application's, though a report of ours still names the processes it was running alongside, and the zip always says what that search found even when the answer is nothing. On every platform the same level also adds the past week of the operating system's records of this app being ended from outside (also listed above), listed in manifest.json for a project's zip and named in the same README for a system-wide zip whenever records were kept. The zip also carries a short send history of the bug reports previously generated on this machine — when each was generated and whether sending it succeeded — which is what makes a report that failed to send diagnosable at all. That history is machine-wide too, so it names the other projects you have filed reports from; it carries no document content, and the README names it the same way | Send uploads the zip to the bug-report intake: openknowledge.ai unless OK_BUG_REPORT_INTAKE_URL points elsewhere. If the upload fails, Send falls back to a prefilled email draft to support@inkeep.com that you send yourself, naming the zip to attach. If you gave an email address, OpenKnowledge also emails it when a fix for what you reported reaches a stable release, and first when it reaches a beta if it ships in one before stable, from updates@updates.openknowledge.ai through its mail provider (Resend); replies go to the team |
| Uninstall feedback | Only if you answer the optional "Before you go" screen or prompt. The macOS desktop asks after you confirm removal, before the app quits and cleanup starts; feedback can be sent even if cleanup later fails. Interactive ok uninstall asks only after successful cleanup. Skipping sends nothing; CLI runs with --yes, --json, or non-interactive input never ask | openknowledge.ai/api/feedback — the reason you picked, your note, your email address if you gave one, plus the app version and platform. It files one ticket for the team; nothing from your notes is included. If you gave an email address, OpenKnowledge also emails it when a fix for what you reported reaches a stable release, and first when it reaches a beta if it ships in one before stable, from updates@updates.openknowledge.ai through its mail provider (Resend); replies go to the team |
| Feedback form | Only when you click Send in the feedback form, opened from Help → Send feedback, the command palette's Send feedback command, or the feedback card in the window's bottom-left corner. Images you drop on, paste into, or attach to the message box go with it; like bug report images, they are not scanned or redacted | openknowledge.ai/api/feedback — your rating, the reasons you picked, your note, your email address if you gave one, up to three attached images, plus the app version and platform. In the desktop app the images upload first to the bug-report intake (openknowledge.ai unless OK_BUG_REPORT_INTAKE_URL points elsewhere) and the feedback carries links to them. If an image upload fails, the images go inline with the feedback to openknowledge.ai/api/feedback instead. If you gave an email address, OpenKnowledge also emails it when a fix for what you reported reaches a stable release, and first when it reaches a beta if it ships in one before stable, from updates@updates.openknowledge.ai through its mail provider (Resend); replies go to the team |
| Semantic search embeddings | Only when you enable semantic search and set a key — off by default | Your configured embeddings provider (OpenAI by default) |
| GitHub sync / share | When you sync, clone, publish, or share | GitHub |
| Update check | Automatically — on launch and periodically while the desktop app runs | OpenKnowledge update service (openknowledge.ai/updates), which redirects to GitHub; sends the app version and channel |
| First-launch share check | Once, automatically, on the desktop app's first launch | openknowledge.ai/continue — redeems a share link if you installed from one |
| Skill-install report | Only if you turn on Count skill installs publicly (off by default): the first time a published skill is actually installed — OpenKnowledge's own built-in and starter-pack skills, and skills you install from a skills.sh listing. Counted once per skill for machine-wide installs (the built-in bundles), and once per skill per project for skills installed into a project, since each project gets its own copy in its own editor dirs. Never re-sent on a re-run, a reinstall, an app launch, or reopening a project — an app launch that installs nothing sends nothing. A skill you install by typing a third-party repository yourself is not reported, and neither is a private, local, or internal-hostname source. A skill bundle you switched off is never installed and so is never reported | add-skill.vercel.sh — the skill's name, its source repository, and which agent tools it was installed for. No file contents. This is what gives a published skill an accurate install count. Turn it on in Settings → Preferences or by setting telemetry.skillInstallReports.enabled: true; DO_NOT_TRACK=1 / DISABLE_TELEMETRY=1 still suppress it |
npm/npx fetch | During CLI installation and catalog-managed in-app agent startup, including package admission probes, package downloads, and cache revalidation | Your configured npm registry (the public npm registry by default); package names, version constraints, and configured registry credentials, without document content |
uv/uvx fetch | When starting a catalog-managed Python in-app agent, including resolution and tool installation | Your configured Python package index (PyPI by default); package names, version constraints, and configured index credentials, without document content |
Local diagnostic logs and telemetry are scrubbed of credential-bearing attributes and never sent anywhere on their own.
See also
Configuration
Every config key and environment variable, including the telemetry and semantic-search settings referenced here.
CLI & web app
Install the CLI, run ok init / ok start, and the commands behind these writes.
Ignore patterns
Control which files the editor, search, and agents can see.
Core Concepts
Why the file system is the database, and how attribution works.