CLI & web app
Install the ok CLI and run the OpenKnowledge web app in your browser — on any platform, including Intel Macs and servers.
For the smoothest experience, use the desktop app — it ships for macOS 13 or later, Windows, and Linux. Anywhere else (an Intel Mac, a server), or when you'd rather stay in the terminal, install the ok CLI from npm and run the same editor as a local web app in your browser.
Prerequisites — Verify Node and Git are installed
Open a terminal and run:
node --version
git --version- Node.js 24+. OpenKnowledge requires Node.js 24 or higher. Download from nodejs.org.
git. OpenKnowledge uses Git for timeline and recovery. Install it from git-scm.com.
Install
Install the OpenKnowledge CLI globally so you can run ok from anywhere:
npm install -g @inkeep/open-knowledgeSet up a project
Run ok init in any folder to turn it into an OpenKnowledge project. It scaffolds a .ok/ directory and registers the OpenKnowledge MCP server with the AI editors it detects on your machine (Claude Code, Claude Desktop, Cursor, Codex, OpenCode, OpenClaw, Pi, Antigravity, LM Studio, Hermes). It only ever adds its own entry — your other settings, comments, and formatting are left untouched.
cd my-project
ok initok init asks two questions: where to register the MCP server (user-level, project-level, or both) and whether to share the OpenKnowledge config files with your team (committed alongside your content) or keep them local to this machine.
In a sub-folder of a git repo, ok init sets the project up at the git root — one .ok/ per repo — and the whole repo becomes the content scope. Pass --content-dir <dir> to limit content to one folder (ok init --content-dir . scopes it to the folder you run in); the choice is saved as content.dir in .ok/config.yml. For scripts, --json prints a structured JSON summary. ok init also installs the user-global open-knowledge-discovery skill, the same one the desktop's first launch offers, unless you uninstalled it in Settings → Skills Studio; --skills discovery,write-skill adds the authoring skill, and --no-skills installs none on that run. open-knowledge-write-skill is otherwise one click away in Settings → Skills Studio.
ok init refuses to set up a project in your home directory or at the top of a drive (/, C:\, a network share root) and exits with status 64. Make a folder for the project and run it there. The desktop app's Open folder refuses the same folders, plus system folders such as /usr or C:\Windows.
If an editor shows “left unchanged”
OpenKnowledge prints left unchanged (<reason>) when it cannot safely read or update an editor's config. This can mean a permission problem, a path that is not a regular file, invalid JSON/TOML/YAML, duplicate MCP server blocks, or an unusually large file. The config stays byte-for-byte untouched. Follow the printed reason and then re-run ok init. Correct permissions or the path for an access failure, or repair syntax for a parse failure. For no format-preserving writer available, reinstall OpenKnowledge to restore its TOML writer, or add the MCP entry manually as described in the Codex integration guide.
Once you have initialized your project, launch the app in your browser:
ok startOne server on one port serves everything — the editor, the API, the MCP endpoint, and real-time collaboration — and the editor opens in your browser automatically (pass --no-open-browser to skip that). Running ok start again for the same project while its server is already up prints the running server's URL and exits.
ok start also takes -p/--port and --bind to pick the address, --idle-shutdown (off or a duration like 30m) to control when an unused server exits, --only server to run without the editor UI, and --mode app to hand off to the desktop app instead of running a server in the terminal (with the desktop app installed).
The browser needs no flag: ok start always runs the browser server unless you pass --mode app. Bare ok, with no subcommand, opens the desktop app when it is installed and otherwise runs the same browser server; it also runs the browser server when its output is not an interactive terminal, over SSH, or on Linux without DISPLAY or WAYLAND_DISPLAY, unless OK_FORCE_DESKTOP=1 is set. Set OK_FORCE_BROWSER=1 to make bare ok always run the browser server.
Idle shutdown is on by default at 30 minutes — a server with no connected clients exits so it doesn't linger. If you keep a session open for a long time without interacting, pass --idle-shutdown off (or a longer duration) to keep it running.
For a complete list of every file OpenKnowledge creates or changes — during install, at runtime, and in the desktop app — see What OpenKnowledge writes to your system.
Overlapping projects and previews
A second project or single-file preview cannot start over content already owned by another server. A verified refusal names the existing live session; close it before opening the overlapping project or preview. An unverified refusal protects only overlapping content. A failed lease probe names the affected content, lease path and underlying failure; an unsupported ownership protocol instead names the compatibility problem. Check access and retry a temporary read failure; unsupported ownership protocols require compatible runtimes, not deleting another runtime's record. In particular, close a loose-file preview before turning its containing folder into an OpenKnowledge project. Single-file sessions otherwise remain independent when they edit different files.
A nested project marked by its own .ok/config.yml belongs to its own server. The parent cannot read or write the nested project's documents; explicit API requests return 403. If a nested project is created while the parent is running, restart the parent before opening the child. Removing a nested project's marker does not expand a running parent's scope either: restart the parent to adopt that content.
Restart all existing OpenKnowledge servers after updating so every runtime uses the same ownership protection. The protection is local to one OS account and requires a writable home registered for that account; changing HOME or a project's config does not select a separate ownership registry.
Ownership registry recovery
If startup reports a registry version mismatch, update all OpenKnowledge runtimes to compatible versions. For a permissions error, make the OS account's home writable; protection is never silently disabled. The shared registry must be on a local filesystem that honors SQLite file locks. Network-mounted homes and filesystems with broken locks do not provide this protection.
After a server crashes, is forcibly terminated or the computer restarts, its released filesystem lease lets the next server recover ownership automatically on macOS, Windows and Linux. Recovery never depends on a PID, hostname or timeout. A missing or damaged lease leaves only its recorded content protected; disjoint projects can still open. A corrupt registry or a retired, nonempty pre-release format affects the whole registry and needs manual recovery. Run ok stop all and confirm every OpenKnowledge server under that OS account has exited, including desktop, terminal, MCP-spawned and preview sessions. Then back up and remove the registry file named in the error (~/.ok/local/server-authority.sqlite) together with its -journal sidecar if present, keeping them together as one backup, and restart the desired projects. Never remove or replace the registry while a server is running: doing so would discard its ownership claim.
Open a doc, folder, or file
ok open takes a doc name, a folder, or a path to a Markdown file.
ok open <path-to-your-file.md>The output names the absolute project root OpenKnowledge resolved for the argument you gave, so you can tell which project it acted on without running a second command. When the resolved root itself sits inside another project, the output names both, once.
To choose the project yourself, pass --project <dir>. It is honored wherever it appears: --project <dir> or --project=<dir>, before or after the target, and with or without the .md extension on the path. If it cannot be honored, the command exits non-zero with a message saying why instead of quietly resolving somewhere else.
If you don't have a project initialized, this still works. The file opens directly in the WYSIWYG/source editor without any of the version history or open with AI frills.
Clone from GitHub
You can pull repositories directly from GitHub and open them with OpenKnowledge:
ok clone <owner/repo>ok clone accepts a full https://github.com/... URL or the owner/repo shorthand. It clones the repository, initializes OpenKnowledge if it isn't already, and starts the local server — open the printed Editor URL in your browser.
Pin a branch with -b <branch>:
ok clone <owner/repo> -b <branch>If the branch no longer exists, ok clone falls back to the repository's default branch.
Before checking out any files, ok clone checks the repository's symlinks. If a link points outside the repository, at its root, or into a .git folder or OpenKnowledge's private state, it removes the clone and names up to five refused links, each with its reason.
A public repo clones without authentication. For a private repo, sign in first:
ok auth loginIf you're already logged in with the gh CLI, you can skip this step.
ok auth also provides status (show who's logged in), repos (list repositories you can access), signout (remove stored credentials), pat (store a GitHub Personal Access Token), and token (store an access token for any other git host). Every subcommand takes --host <hostname>. For a host that is not GitHub, status reports the stored token without verifying it: it exits 0 when a token is stored and 1 when none is, and its --json output carries "unverified": true with the stored username. GitHub Enterprise hosts must be declared as git.hosts.<host>.provider: github in ~/.ok/global.yml (~/.ok-beta/global.yml for ok-beta) before commands contact them. See configuration.
Without --host, commands select the recognized GitHub origin, or github.com when no origin exists. An unrecognized origin requires explicit host selection for login, pat, repos and signout, so they cannot contact or clear credentials for a different host by accident. status on a non-GitHub host reports the stored token without contacting any API; on a GitHub host, status and repos contact GitHub APIs. signout --host <hostname> only removes local credentials and works for any host, including one whose declaration has been removed.
Sync with a Git remote
Sync a project with its remote from the terminal:
| Command | What it does |
|---|---|
ok sync | Commit, pull, and push to the remote |
ok pull | Pull changes from the remote |
ok push | Push commits to the remote |
Each command goes through the running OpenKnowledge server when one is up. Otherwise it runs git directly. When the remote's URL is https:// and names github.com or a declared GitHub Enterprise host exactly, in lowercase and with no port, and OpenKnowledge has a GitHub sign-in for it (which account is used), that sign-in replaces your git credential helpers for HTTPS requests to that host during the command, though a ~/.netrc entry for the host or a password in the remote URL is still used first. A submodule or extra push URL that writes the same host with an explicit :443 or in different letter case gets the same sign-in, and is never sent to your own credential helpers.
Requests to another host, a non-default port or a plain http:// URL use your own git credentials. A token stored with ok auth token --host <host> --username <username> overrides them for an HTTPS host only when the request goes through the running server; run directly, these commands keep your own git credentials. The username is what git sends with the token: oauth2 for GitLab, your Gitea username, x-bitbucket-api-token-auth for a Bitbucket API token or x-token-auth for a Bitbucket repository or workspace access token, and any value for Azure DevOps. Pass --json for JSONL progress events when scripting. See Git sync for how syncing works.
Without a running server, ok pull and ok sync check every symlink the pull would add, retarget or remove before writing anything, and refuse the whole update if one would be unsafe: it points outside the repository, into private .git or OpenKnowledge state, at a file that may hold secrets, or somewhere that cannot be checked. The command exits with an error naming up to five refused links, each with its reason, followed by a count of any others and what to do next. With a server running, the command only triggers the pull, and the refusal appears in the app's sync indicator instead. The full rules, including links both sides changed, links that pass through them, names spelled more than one way, and the Git 2.38 requirement for three-way pulls, are in Incoming changes with unsafe symlinks.
Manage local servers
Each project runs its own local server. These commands let you see and stop them:
| Command | What it does |
|---|---|
ok status | Show whether a server and UI are running for the current project |
ok ps | List every running OpenKnowledge server on your machine |
ok stop | Stop the server for the current directory — or pass a port, path, or PID to stop a specific server, or all to stop every server. Declines when the server's lock records a different OpenKnowledge app (Stable or Beta) than the CLI's own, naming that app, and when something is still connected to the target, naming how many clients are attached. Either way it exits 1; pass --force to stop it anyway. A lock with no recorded app is stopped as before, and a server it cannot reach is stopped without the connected-clients check |
ok clean | Remove a stale lock file left behind by a crash (never touches live servers) |
ok clean retains a lock and exits 1 if it cannot read it, it records another machine, or it has no recorded owner and its PID is still running locally. A PID that has exited is not running even while it lingers as a defunct entry in the process table, so ok clean prunes the lock naming it. The error names the lock and explains what to check. For an unverified owner, inspect the named local PID and stop it if it is an OpenKnowledge server; do not delete the lock while that process is running.
ok status, ok ps, and the server-lock health check distinguish an unverified owner from a foreign host. ok status --json uses state: "unverified-owner" and includes the PID, with server liveness reported as unknown. ok ps --json uses the same status, displayStatus: "unverified", and null for unrecorded host, port, and start time. The directory is the project root for current .ok/local and legacy .ok locks; it is null when a custom lock location does not establish a project root. Such records are not signal authority for ok stop, including with --force.
Remote Control
Serve this project's web UI and /mcp endpoint to your other devices through any HTTPS tunnel, both on one URL. See the Remote Control overview for the full setup and access-control model. Use Connect remote agents to point agents at the URL.
| Command | What it does |
|---|---|
ok start --external-url <url> | Declare the canonical external origin clients dial (sets server.externalUrl for this run) — its host joins the Host/Origin allowlists and issued URLs. External exposure additionally requires consent (OK_ALLOW_EXTERNAL=1 or server.allowExternal). For remote MCP use also set OK_IDLE_SHUTDOWN=off — the idle timer only counts editor (WS) connections and would stop the server under a live remote agent. Add --bind <address> to serve a non-loopback listen address. |
More commands
| Command | What it does |
|---|---|
ok seed | Scaffold a starter pack into the project (--list-packs to browse, --pack <id> to choose, --root <dir> to nest in a subfolder, --dry-run to preview) |
ok preview | Show what content the watcher will track (read-only) — the quick check after a content.dir or .okignore change |
ok migrate notion <dir> | Clean up a Notion export in place, dry-run unless --apply (see migrating from Notion) |
ok config validate | Validate the merged config (defaults → user → project) |
ok config migrate | Remove keys the schema no longer reads from your config files (--dry-run to preview; --scope to narrow — defaults to every layer) |
ok skills installed | List every skill installed across your agents (read-only, cross-harness) |
ok skills import <source> | Import a skill as versioned content from skills.sh, a GitHub owner/repo, a git URL, or a local path |
ok bug-report | Package a support bundle — recent app logs, the project's server logs and lock diagnostics, and system info — as an auto-redacted zip under ~/.ok/bug-reports/ (~/.ok-beta/bug-reports/ for ok-beta), revealed in your file manager when it's done (--no-reveal to skip). Collects the same standard set as the desktop app's Help → Report a bug…; ok diagnose bundle produces the full superset (telemetry spans, live server state) into the project's .ok/local/diagnostics/ |
Global flags
Every command takes --cwd <path> to run from another directory, --log-level <level> (silent, error, warn, info, debug, or trace), and --no-color to disable color output. ok start runs quiet by default; --log-level debug turns everything on.
Commands that run for you
The rest of the CLI exists mostly for tooling and automation. Your AI editor spawns ok mcp to talk to the knowledge base. ok start repairs existing editor connection settings; it leaves installed editor skills alone. Run ok repair-skills explicitly to restore missing project skill copies and repair user-global bundles. To update an existing project skill, follow Refresh agent guidance. ok diagnose and ok bug-report produce support bundles when something goes wrong. Run ok --help for an overview of all commands.
Remove OpenKnowledge
ok deinit [path] reverses ok init for one project (the current project when path is omitted): it removes the project's .ok/ directory, OpenKnowledge's editor MCP entries, its own git-exclude lines, and shadow repo, leaving your markdown untouched. Shared editor settings and their symlinks are preserved; ignore rules for shared config files stay while those files still exist.
ok uninstall removes the global footprint: running servers, credentials, the PATH shim, OpenKnowledge's editor MCP entries and bundled skills, app data, and ~/.ok. It keeps the ~/.ok entries every product shares: ~/.ok/machine-id, the user skills store ~/.ok/skills, ~/.ok/skills-lock.json, the Global-scope skill bookkeeping in ~/.ok/local/installed-skills.json, ~/.ok/local/skill-placements.json, and ~/.ok/local/skill-move-retained.json, plus the shared ownership registry ~/.ok/local/server-authority.sqlite, its -journal file, and ~/.ok/local/server-authority-leases/. These coordination files stay even with --purge-content. It removes only the running product's footprint: ok-beta uninstall removes ~/.ok-beta and Beta's credentials and leaves Stable's ~/.ok alone. No product's uninstall removes ~/.ok/machine-id. With --purge-content, either product also removes the shared ~/.ok/skills, unless an earlier uninstall step failed. See Stable and Beta home folders. Your markdown and other skills in your editors' skill directories stay. An interactive run lets you select projects to deinitialize; --yes removes only the global footprint unless you also pass --all-projects, which covers current, recent, and discovered running projects. The CLI binary stays installed; the command ends by printing how to remove it (npm uninstall -g @inkeep/open-knowledge for the install above).
Both ok deinit and ok uninstall wait for servers to exit before deleting their state. If a server cannot be safely stopped or an integration cannot be cleaned up, the command reports the problem and retains state needed for repair and retry. Applied cleanup exits 1 when anything remains unresolved. With --yes --json, inspect failed[] for those items and their reasons; skipped[] covers intentionally preserved entries. Repair the reported problem and rerun the command.
On Windows, confirming that a running server really is the process the lock names uses OpenKnowledge's bundled native component. Removal refuses rather than signalling a process it has not identified, and the refusal names which of two things went wrong. If the component could not be loaded, reinstalling OpenKnowledge restores it — the same remedy as for its TOML writer. If the component loaded but Windows refused the query, reinstalling will not help: that is usually a permissions difference, so rerun from an account that can inspect the server process. Either way you can instead stop the server yourself and confirm it has exited, then rerun. The failure detail itself is recorded in ~/.ok/logs (~/.ok-beta/logs for ok-beta), not printed.
ok deinit needs the project's .ok/ directory; once that directory is gone, it reports nothing to remove. Remove any retained Pi trust entry manually using its reported exact key and file, as described in installation details.
Malformed filesystem residue does not by itself establish a running server. Cleanup can skip it after process and listener inspection succeeds and finds no associated live candidate. A read failure, incomplete inspection, or associated live server remains a blocker. A process that has exited is not a live server, and its unreadable working directory does not make the inspection incomplete, even while the process lingers as a defunct entry in the process table. Global-only uninstall can retain foreign-owned or ownership-unverified project state after the same local inspection; selecting project deinitialization keeps those ownership checks strict. Dead PID-only locks are recoverable. Human output lists root blockers once; JSON failed[] includes both direct failures and blocked dependent operations, with blocked[] providing the dependent subset.
Both commands print their plan and ask before acting; --dry-run previews without changing anything. Once ok uninstall has finished successfully, an interactive run also asks one optional question about why you're leaving — you can skip it, and --yes, --json, and non-interactive runs never ask. Anything you do answer is sent to us.
On the macOS desktop app, App menu → Uninstall OpenKnowledge… lets you choose projects to deinitialize, confirm removal, and answer or skip the optional "why are you leaving?" screen. The progress window stays visible while the original app quits and cleanup runs, so shutdown cannot recreate its settings. The same window then reports the result: successful cleanup guides you through dragging the app to the Trash; incomplete cleanup points to a retained log so you can repair the problem and retry.
To remove the desktop app on the other platforms: on Windows, uninstall OpenKnowledge from Settings → Apps → Installed apps; on Linux, remove the package with your package manager (sudo apt remove openknowledge on Debian/Ubuntu, sudo dnf remove OpenKnowledge on Fedora/RHEL). Run ok uninstall first if you also want the rest of the footprint cleaned up — it works the same on every platform.