inkeep/open-knowledge
GitHub用于处理 OpenKnowledge 故障报告与调试。通过 ok bug-report 命令收集结构化诊断数据,自动脱敏敏感信息,并分析日志以定位问题。
Install All Skills
npx skills add inkeep/open-knowledge --all -g -y
More Options
List skills in collection
npx skills add inkeep/open-knowledge --list
Skills in Collection (4)
packages/server/assets/skills/bug-report/SKILL.md
npx skills add inkeep/open-knowledge --skill open-knowledge-bug-report -g -y
SKILL.md
Frontmatter
{
"name": "open-knowledge-bug-report",
"metadata": {
"author": "Inkeep",
"version": "0.6.0",
"repository": "https:\/\/github.com\/inkeep\/open-knowledge"
},
"description": "Use when the user reports a problem with OpenKnowledge, asks for help debugging OK, or wants to file a bug report. This skill guides the agent to capture diagnostic information via the ok bug-report CLI command.",
"compatibility": "Any MCP host (Claude Code, Cursor, Codex, Windsurf) with OpenKnowledge MCP server registered."
}
Bug Report — agent guidance
When a user reports a problem with OpenKnowledge or asks for debugging help, use the ok bug-report command to capture a structured diagnostic bundle.
Quick path
ok bug-report --no-reveal
The --no-reveal flag suppresses the Finder reveal (use it when running as an agent — you want the file path, not a Finder window).
What the command does
- Gathers all structured log files from
~/.ok/logs/(NDJSON format, pino) - When invoked inside an OK project directory, filters logs to that project's records
- Collects system info: OK version, Node/Bun versions, macOS version, locale, timezone, free disk space
- Collects lock directory contents (server.lock, spawn-error-log) when a project context exists
- Extracts recent IPC error records from desktop logs
- Runs an auto-redaction pass over all content (home paths, API tokens, credentials are scrubbed)
- Writes
~/.ok/bug-reports/<timestamp>-bugreport.zip - Prints the bundle path to stdout
What's in the bundle
<timestamp>-bugreport.zip
├── MANIFEST.json — what's inside, redaction audit report
├── sysinfo.json — versions, locale, disk, build channel
├── README.md — what's safe to share, discipline version
├── logs/ — NDJSON log files (auto-redacted)
├── lockdir/ — server.lock, spawn-error-log (if project)
└── recent-ipc-errors.json — last 50 structured IPC errors
Agent workflow
- Run
ok bug-report --no-revealin the user's project directory (or home if no project) - Read the path from stdout
- Unzip to a temp directory:
unzip -o <path> -d /tmp/ok-diag-<timestamp>/ - Read
MANIFEST.json— check theredactionsarray (if non-empty, some content was scrubbed) - Read
sysinfo.json— check versions, disk space, build channel - Grep the log files for errors:
grep '"level":50' logs/*.log | head -20(level 50 = error in pino) - Read
recent-ipc-errors.jsonfor IPC-layer failures - Report findings to the user with actionable next steps
If the command is not available
The ok bug-report command ships with @inkeep/open-knowledge >= 0.7.0. If the user's version is older:
- Check version:
ok --version - If < 0.7.0: suggest
npm install -g @inkeep/open-knowledge@latestto update - Fallback: manually inspect
~/.ok/logs/for recent.logfiles (NDJSON format, greppable)
Privacy
The bundle auto-redacts:
- macOS home paths (
/Users/<name>/→~/) - GitHub PAT prefixes (
ghp_,gho_,ghu_,ghs_,ghr_) - AWS access keys, Anthropic tokens, OpenAI tokens
- Bearer authorization headers
The MANIFEST.json redactions array lists every file and pattern that was scrubbed. The bundle is safe for the user to attach to a GitHub issue.
packages/server/assets/skills/discovery/SKILL.md
npx skills add inkeep/open-knowledge --skill open-knowledge-discovery -g -y
SKILL.md
Frontmatter
{
"name": "open-knowledge-discovery",
"metadata": {
"author": "Inkeep",
"version": "0.24.0",
"repository": "https:\/\/github.com\/inkeep\/open-knowledge"
},
"description": "Read when the user asks what OpenKnowledge is, wants to install it on a repository, wants to share an OpenKnowledge project with collaborators, or asks how `ok init` \/ `ok cowork` \/ OK Desktop set up a project. Do NOT load to perform OpenKnowledge reads\/writes — the runtime guidance for editing markdown inside an initialized OK project ships as a separate project-local skill at `.claude\/skills\/open-knowledge\/` whenever `ok init` runs. If the user appears to be editing markdown inside a `.ok\/` project and this is the only OK skill loaded, advise them to re-run `ok init` to install the project-local skill.",
"compatibility": "Any agent host — no MCP server required. Pure discovery + install guidance."
}
OpenKnowledge — what it is and how to install it
OpenKnowledge (OK) is a markdown-CRDT collaboration platform. It turns a
directory of .md / .mdx files into a live, multi-writer knowledge base:
agents and humans edit the same documents in real time, every change is
attributed, and a browser preview renders edits as they land.
This skill covers discovery, install, and opening OpenKnowledge files —
including single files that are not part of a project (see Opening a file
outside a project below). It does not carry the in-project read/write
runtime contract (the STOP rules for native file tools, the grounding and
linking rules, the MCP routing table) — that ships separately as the
project-local skill installed by ok init (see Working inside a project
below).
Install OpenKnowledge on a repository
Run ok init from the repository root:
npx @inkeep/open-knowledge init
# or, after a global install:
npm install -g @inkeep/open-knowledge
ok init
ok init is the one setup verb. It:
- scaffolds a
.ok/directory (project config —content.dirdefaults to.); - wires the OpenKnowledge MCP server into detected editors (Claude Code,
Cursor, Codex) — skip with
--no-mcp; - installs the project-local runtime skill at
.claude/skills/open-knowledge/and.cursor/skills/open-knowledge/so agents working in this repo get the full read/write contract; - ensures the project has a
.git/.
Re-run ok init any time to refresh wiring and skills to the installed CLI
version.
Share an OpenKnowledge project with collaborators
An OK project travels with its repository. To share one:
- Commit the
.ok/directory and the project-local.claude/skills/open-knowledge/(and.cursor/skills/open-knowledge/) directories along with your.mdcontent. - Collaborators clone the repo and run
ok initonce — that registers the MCP server on their machine and refreshes the project skill. - Start the editor + preview with
ok start(or open the project in OK Desktop).
Collaboration is real-time once two writers have the project open against the same content directory.
ok cowork — Claude Chat & Cowork
ok init's editor wiring does not reach Claude Chat or Cowork — those read a
separate Skills list inside the Claude Desktop App. Run ok cowork to
build openknowledge.skill and open Claude Desktop so the user can upload it
(Customize → Skills → + → Create skill → Upload skill).
OK Desktop
OK Desktop is the standalone macOS app (@inkeep/open-knowledge-desktop). It
bundles its own CLI, opens a project as an editor + preview window, and keeps
the project's MCP wiring and skills current on every launch. Download DMGs
from the releases page.
Opening a file outside a project
OpenKnowledge can open a single markdown file that is not part of an OK
project — a loose .md / .mdx, or a file that lives inside a regular
repo/folder which was never ok init'd. It opens in a throwaway session (a
temp project in the OS temp dir — your repo is never touched, no .ok/ is
written into it) with the same live preview you get inside a project.
Never run ok init just to view or open a file. ok init turns a repo
into a shared OpenKnowledge project; it is not a prerequisite for opening one
file. Opening a file needs no project, no .ok/, and no server already
running — each path below boots the session itself.
When asked to open or preview such a file, decide by the viewing surface you actually have — check the tool, not the host name. Only open a browser when you genuinely have one; never pop a browser tab on a host that has none.
- You have an in-app / built-in browser (Cursor, Codex, and similar) — this
is the default: call the
preview_urlMCP tool withfileset to the absolute path (it finds, or boots on demand, the session and returns a fullurl), then immediately open thaturlin your in-app browser. "Open it" means navigate your browser — don't just print the URL and stop. This is also the only way to view it in a browser when the OK Desktop app is installed (ok openprefers the Desktop app). Get the URL frompreview_urlonly — never hunt for it viaok ps/ok status/ok ui/ok startor a guessed port. - You have a Claude Code Desktop preview pane but no general browser — the
pane is project-only: it shows in-project docs via
preview_start, but it cannot host a file from outside the project. For such a file runok open /abs/path/to/file.md(the Desktop app) instead; don't try to force the file into the pane. - No in-app browser and no pane (a pure-stdio CLI) — run
ok open /abs/path/to/file.md: it opens the Desktop app when installed, else a browser, and boots the session itself. Don't force a browser tab the user didn't ask for;ok openis the right default here. Ifokisn't on PATH,npx @inkeep/open-knowledge open /abs/path/to/file.mddoes the same.
If the OK MCP server isn't wired into this host there is no preview_url to
call — use the ok open path above. Don't reconstruct what preview_url does
by hand (spawning ok mcp yourself, scraping ports from ok ps).
The path must be absolute (a file outside a project has no cwd to anchor a
relative path). Re-opening the same file lands on the same session. Never
construct or guess the URL — use the one preview_url returns.
Working inside a project — use the project-local skill, not this one
Do not use this skill to perform OpenKnowledge reads or writes. The
runtime contract — STOP rules for native file tools on in-scope markdown, the
preview-attach handshake, grounding and linking rules, the MCP tool routing
table — lives in a separate project-local skill installed at
.claude/skills/open-knowledge/SKILL.md whenever ok init runs.
If the user is editing markdown inside a project that has a .ok/ directory
and this discovery skill is the only OpenKnowledge skill loaded, the
project-local skill is missing (the repo was never ok init'd, or the skill
directory was not committed). Advise the user to run ok init to install it.
Learn more
- Repository: https://github.com/inkeep/open-knowledge
- Run
ok --helpfor the full command list.
packages/server/assets/skills/project/SKILL.md
npx skills add inkeep/open-knowledge --skill open-knowledge -g -y
SKILL.md
Frontmatter
{
"name": "open-knowledge",
"metadata": {
"author": "Inkeep",
"version": "0.24.0",
"repository": "https:\/\/github.com\/inkeep\/open-knowledge"
},
"description": "Authoritative agent-runtime contract for working inside an OpenKnowledge project — a markdown-CRDT knowledge base exposed over MCP. Use whenever reading, listing, searching, or editing any `.md` or `.mdx` file in the project, and before any `mcp__open-knowledge__*` tool call (`exec`, `search`, `write`, `edit`, and the rest). Installed by `ok init`, so its presence means this is an OpenKnowledge project and it governs every markdown file here. Covers the read\/write tool surface, grounding and linking rules, folder\/template conventions, the live browser preview, and the rule that OK's MCP tools — never native file tools — handle in-scope markdown.",
"compatibility": "Claude Code, Claude Desktop, Claude Cowork, Claude.ai web. Requires OpenKnowledge MCP server + code execution."
}
OpenKnowledge — agent guidance
OpenKnowledge (OK) is a markdown-CRDT collaboration platform exposed via MCP. This skill is the single source of OK agent guidance. Every rule below is a MUST unless marked otherwise. Depth lives in references/*.md — one level deep; load a reference when its task comes up.
Skill version tracks
@inkeep/open-knowledge-server.cat ~/.ok/skill-state.ymlshows what's installed.ok seedneeds@inkeep/open-knowledge>= 0.4.0; if it errorsunknown command,npm install -g @inkeep/open-knowledge.
Setup (not connected yet?). If the
mcp__open-knowledge__*tools aren't available in your client, this project isn't wired up on this machine — seereferences/setup.mdfor the rung ladder (approve.mcp.json→ok startCLI → optional desktop app) and the canonical quickstart.
TL;DR — the 90% case
- Reads:
exec("cat …")for one doc,exec("ls -A …")for a directory (folder defaults + template menu),exec("grep …")for literal,searchfor ranked retrieval. NativeRead/Greponly on source code (.ts/.py/ …), never on in-scope.md/.mdx. - Writes:
write({ document: { path, content } })for a new or full-replace doc;edit({ document: { path, find, replace } })for a body find/replace;edit({ document: { path, frontmatter } })for a frontmatter merge-patch (nulldeletes a key).delete({ document })removes,move({ from, to })moves/renames. Body find/replace is body-only. Pass a one-linesummary(≤80 chars, user-facing outcome) on every content write. - Preview / open a doc — determine your ONE surface FIRST (once per session). Before opening anything, pick where to focus, stop at first match:
OK_DESKTOP_TERMINALset (check your env —echo "$OK_DESKTOP_TERMINAL") → OK Desktop's own terminal →ok open <name>(switches this window) · havepreview_*→ Claude Code Desktop pane · have a URL-navigation/browser tool → Cursor/Codex →preview_urlthen navigate it · else plain CLI →ok open <name>.ok open <name>opens a doc or folder (auto-detected — no--folder); add--skill <name>for a skill. ThepreviewUrlfield is a route id, not your open mechanism — don't hand it to a browser just because you saw it. Don'tpreview_screenshotto confirm edits. Full Step-0 procedure + per-surface how-to:references/preview.md. - Workflow guides:
workflow({ kind: 'ingest' | 'research' | 'consolidate' | 'discover' })returns a procedural guide, not data. Use it when the work fits the layer. - Direct questions: a plain business question ("which customers…", "what did we decide about…") routes to
search/exec+ a cited chat answer — no "research" keyword needed. Persist only when durable + multi-doc + not already covered, and offer first. Seereferences/corpus-qa.md. - Authoring or improving a skill ("write/make a skill", "improve this skill", "turn this into a skill"): STOP and invoke the
open-knowledge-write-skillskill — it owns scope choice (project vs global), the SKILL.md contract, evaluation, and install; don't improvise from this skill. Author through theskilltarget (write({ skill })), never a raw.ok/skills/…document. Never read, diff, or edit the installed projections under.claude/skills/·.cursor/skills/·.codex/skills/·.opencode/skills/·.agents/skills/—installgenerates them and overwrites them on the next sync; they are NOT source of truth.
Tool index — 19 tools (router; the MCP tool descriptions carry each tool's full contract)
- Reads —
exec(primary; read-onlycat/ls/grep/find/head/tail/wc/sort/uniq/cut+ frontmatter/backlink/history enrichment; one command or one pipe, not a shell),search(ranked BM25 + recency),history(versions for a doc),links(kind: backlinks|forward|dead|orphans|hubs|suggest, or an array for a one-call audit),skills(find + read skills: omitnameto LIST every skill across Project + Global, passnameto READ one — addressed byname+scope, NEVER by path),config(resolved config),palette(markdown-native authoring forms +html previewstarters + theme tokens;palette({ components })for JSX schemas),preview_url(browser preview URL on demand),share_link(GitHub-substrate share URL; read-only, errors when no GitHub remote). - Writes — four native CRUD verbs, polymorphic over
document/folder/template/skill/asset(pass EXACTLY ONE target, nested under its address key):write(create/overwrite;write({ skill: { name, description, body, scope? } })authors a skill →.ok/skills/<name>/SKILL.md, a Draft untilinstall),edit(body find/replace OR frontmatter merge-patch; no asset),delete(remove),move(move/rename, rewrites referrers; a skill also takesscope/toScopeto move Project↔Global — history resets, re-install). Output mirrors the input target key; the preview envelope (previewUrl,warning) stays top-level. Plusinstall(the Draft → Installed step for askill— projects it into your editors; run afterwrite({ skill })),checkpoint(named version), andrestore_version(roll back). A folder's frontmatter is open-shape and self-only (does NOT cascade); templates are what new docs start with. Authoring/improving a skill? invokeopen-knowledge-write-skill(TL;DR #6), don't improvise. - Conflicts —
conflicts(kind: list|content),resolve_conflict(write a resolution + commit; destructive). Seereferences/conflict-resolution.md. - Workflow —
workflow(kind: ingest|research|consolidate|discover; procedural guides, not data). Seereferences/workflow-guides.md.
Self-correcting on misuse: constraints JSON Schema can't express ("exactly one target", "find needs a replace", body-XOR-frontmatter) return isError: true with a one-line corrective shape. Read it and retry with that shape; don't guess.
Tools NOT in OK MCP (your host's): preview_start, preview_screenshot, WebFetch, WebSearch, native Read / Grep / Glob / Edit. The STOP rule governs which you may use on in-scope markdown.
STOP — native tools on in-scope .md / .mdx
Route every in-scope markdown read and write through OK's MCP tools — never your host's native file tools. Native Edit / sed / direct Write on in-scope markdown bypasses the CRDT and loses agent attribution in the shadow repo; native reads skip frontmatter, backlinks, shadow-repo activity, and project git history that OK returns for every matched file. When this workspace has OpenKnowledge MCP configured, do not use native file tools on markdown paths inside the content directory. The ban covers every common rationalization:
- Native
Read/Grep/Globon in-scope.md/.mdx— the original case. Bash ls/Bash find/Bash caton dirs containing in-scope markdown — useexec("ls -A …")/exec("find … -name '*.md'")/exec("cat …"). Native returns bare names;execreturns frontmatter, backlink counts, and recent activity.-Ashows hidden entries (.ok/,.okignore) without the./..noise.- Glob patterns that target markdown (
**/*.md,specs/**,reports/**,docs/**) — useexecwithfindorexec("ls -A <dir>"). - Dispatching the Explore / general-purpose subagent for markdown-heavy exploration — subagents use native tools internally and bypass OK. Do markdown exploration yourself via
exec/search. Subagents remain appropriate for source-code exploration. - Native
Read/Grepon in-scope markdown inside.ok/—.ok/is in-scope; treat its.md/.mdxlike any other KB file. ls/cat/findon.ok/skills/to discover or read a skill —.ok/skills/is opaque internal state; skills are addressed byname+scope, not by path. Use theskillstool (omitnameto list across Project + Global, passnameto read one); never browse.ok/skills/...paths.
MCP tool visibility — not seeing exec is NOT the escape hatch. MCP wiring varies by client (Claude Code, Cursor, Codex, Windsurf, VS Code). Server labels are user-defined; tools may not appear as top-level symbols named exec. If OpenKnowledge is registered as an MCP server here, route markdown reads through its exec / search via your client's documented MCP invocation (including any generic "call MCP tool" flow). Registration is the test, not top-level-symbol visibility.
Your initial tool list is NOT exhaustive — run tool discovery before concluding the MCP is missing. Some clients (notably Codex) defer MCP tools behind a lazy tool_search / tool-discovery step, so mcp__open-knowledge__* is absent from the upfront tool set and only appears after you search for it. Absence from the visible list means "I have not discovered it yet," NOT "it is not registered." If you don't see the tools, your first move is to run your client's tool-discovery / tool_search for open-knowledge (or exec / search / write) — do not infer unavailability from the initial list.
Escape hatch. Native Read / Grep / Glob on .md / .mdx is allowed only when, after running tool discovery (above), no OpenKnowledge MCP server is registered for this project, or immediately after you actually invoked an MCP call and it failed — then begin a user-visible sentence with OpenKnowledge MCP unavailable:. "Not registered" is a conclusion you may only reach after tool discovery turned it up empty — never from the initial tool list alone. Never use the hatch because you skipped your client's MCP path, didn't see exec as a top-level tool, didn't run tool discovery, or rationalized the skill wasn't necessary.
Source code and non-markdown files (.ts, .py, package.json, …): native Read / Grep / Glob always.
Reads — examples
- Read a file:
exec("cat <path>.md")— contents + full enrichment. - List a directory:
exec("ls -A <dir>")— per-child frontmatter, recursive markdown counts, most-recently-updated doc per subdir, the folder's owntitle/description/tags+templates_available. Prefer-Aover plainls. - Literal search:
exec("grep -rn <term> <dir> | head -5")— matches + enrichment on matched files. - Ranked search:
search({ query })— title boost + body BM25 + recency; use when picking the best doc, not when listing every occurrence.
Writing
Call write / edit as soon as you have content (route through MCP per the STOP rule).
Persist incrementally — the knowledge base IS your checkpoint (MUST). On any multi-step or long-running task — a research sweep, a multi-source synthesis, a batch of docs — write completed work to the KB as you finish each unit: per section, per source, per doc. Never hold finished findings only in your context waiting for one final write at the end. A rate limit, crash, or context compaction mid-task discards everything still unwritten; work already persisted survives, and you resume by reading the doc back. Create the target doc early (skeleton + frontmatter), then edit each section in as it firms up.
Pass a summary on every content write (SHOULD) — a one-line (≤80 chars) user-facing change-note that becomes the timeline entry. Reach for visual structure (Callout, mermaid, table, html preview) where it carries the point better than prose; call palette as you draft. Advisory write-warnings, MDX authoring, delete/move mechanics, and visual authoring: references/writing.md + references/components-and-visuals.md + references/media-and-assets.md.
Grounding — every factual claim needs a source (MUST)
Knowledge-base docs are factual artifacts. Every claim must be traceable, and the source has to live inside the knowledge base, not float on the public web.
- The knowledge base is source-of-truth — closed loop. External sources don't get cited out to the live web; they get pulled in via
ingest, then cited locally. A bare[source](https://...)URL inside a KB doc is not a finished citation — it's a TODO that says "this source still needs to be ingested." The chain only works if every leaf is a local doc. - Every factual claim MUST cite its source at the point of claim. No unsourced speculation.
- Web sources for KB docs → fetch the page (host
WebFetch/WebSearch), theningestit as a local doc, then cite the local path:[source name](./path/to/source.md)(the local doc carries the URL insource_url:). Inline[source](URL)is a chat affordance, not a KB one. - Self-fetched counts. When YOU fetched a URL to ground a claim landing in the KB, that fetch triggers
ingestexactly like a user share — don't downgrade to inline-URL citation because the fetch was agent-initiated. - Internal cross-refs → standard markdown link to the OK doc with the authoritative claim; that doc must cite its own sources (chains terminate in preserved local docs).
- If you don't have evidence: run a web search and
ingestit, OR mark inline(TODO: needs source), OR don't write the claim. Do NOT fabricate. Unsourced speculation rots into untraceable tribal knowledge.
Linking — standard markdown links (MUST)
Link every noun-phrase that names another document — [text](./relative/path.md) — and link liberally. Every link must resolve to a doc that exists by the time you're done (a same-pass forward-reference you create later in the pass is fine; for one that genuinely won't exist, leave the mention as plain prose + a tracked task). Never backtick a link (`[text](./foo.md)` is a bug) and never use HTML <a>. Read brokenLinks on every write/edit response: [] means all links resolve; a populated list names each broken href + reason (no-such-doc / no-such-file / unresolvable) — fix them in a follow-up edit. links({ kind: "dead" }) is the authoritative end-state audit (the editor's red-underline is slug-tolerant and lies, so trust the tool). External web sources are NOT inline body links (see Grounding). Full rule set + the [[Page]] legacy note: references/linking.md.
Folders, frontmatter, templates
Every .md / .mdx needs YAML frontmatter — title + description required, tags recommended. Two opt-in, nested folder mechanisms: folder frontmatter (<folder>/.ok/frontmatter.yml — the folder's own open-shape properties; self-only, does NOT cascade into child docs) and templates (<folder>/.ok/templates/ — what new docs start with). Most folders have NO .ok/. A doc's frontmatter is exactly its own on-disk YAML. Structural model + the full pre-write checklist: references/folder-model.md. Template authoring + folder editing: references/template-authoring.md. Frontmatter-vs-body edit rules: references/doc-editing.md.
- Read the folder before writing (MUST). Before creating/editing docs in a folder, call
exec("ls -A <folder>")once per folder per session — it returns the folder'stitle/description/tags+templates_available. Skipping it lands docs that violate folder discipline. (If a folder has no frontmatter AND no templates AND the repo has substantial content elsewhere, it isn't onboarded — invokeworkflow({ kind: 'discover' })first.) - Use a template when one fits (MUST). Instantiate via
write({ document: { path, template } }); inherited templates count. Skip only when none match or the user asked for free-form (note why in chat). Create templates proactively when a shape recurs. - When recurring per-doc properties emerge (MUST). Writing the same frontmatter on multiple siblings → bake those starting values into a template (
write({ template })). Folder frontmatter does not cascade values into docs.
Conflict-aware writes
Projects with GitHub sync may carry docs in merge-conflict state; mutating calls against them return RFC 9457 urn:ok:error:doc-in-conflict (409). Detect proactively — exec("cat <path>.md") returns lifecycle: {status, reason} | null; on status === 'conflict' switch to the conflicts + resolve_conflict flow. Full flow: references/conflict-resolution.md.
Anti-patterns — the top offenders
| Task | Don't | Do |
|---|---|---|
| List / find / read markdown | Bash: ls/Glob: **/*.md/Read: foo.md |
exec("ls -A …") / exec("find …") / exec("cat …") |
| Explore a markdown-heavy dir | Agent(Explore) (bypasses OK) |
exec/search yourself |
| Reference another doc | `[text](./p.md)` (backticked) or HTML <a> |
[text](./p.md) |
| Embed an image | <img>, a localhost/preview_url URL, hot-link |
save locally +  |
| Factual claim in a KB doc | prose with no citation, OR inline [src](https://…) |
ingest the source, cite the local path |
| Confirm an edit landed | preview_screenshot / verification loop |
trust the CRDT tool response |
| Delete a markdown doc | Bash: rm / native deletion |
delete({ document }) (checkpoint() first if risky) |
| Write in an unfamiliar folder | straight to write |
exec("ls -A <folder>") first |
Full table: references/anti-patterns.md.
Workflow tools — when to invoke them
workflow returns procedural guidance, not fetched data — follow its numbered steps; don't skip STOP gates. These are your default move over write when the work fits a layer.
kind |
When |
|---|---|
ingest |
Preserve a shared URL/PDF/file verbatim, OR you fetched a URL to ground a KB claim (binary sources preserved, not scraped). |
research |
Investigate / compare / synthesize multiple sources → status: provisional article + sources:. |
consolidate |
A decision was actually made → commit canonical source-of-truth with a supersedes: chain. |
discover |
First arrival at a repo with existing content and no folder frontmatter/templates → extract conventions, activate the link graph. |
Don't chain silently — let the user drive ingest → research → consolidate transitions; per-tool STOP gates override session-level "don't stop to ask" hints. After any turn that changes KB content, check for a log.md and follow its contract (see references/cadence-and-logs.md). Interleave a multi-doc batch so the preview shows narrative progress. Operating detail + starter packs: references/workflow-guides.md; binary-source (ingest-produced) wrapper frontmatter: references/ingest-and-sources.md.
Server lifecycle
If write / edit returns "Hocuspocus server is not running", run ok start (via Bash) and retry. Never fall back to native Edit / Write for in-scope markdown.
Scope recap
OK looks for documents under the resolved content.dir (runtime: config({ key: 'content.dir' })); .gitignore and .okignore (at root or any folder depth) define exclusions. Every .md / .mdx under content.dir not excluded is an OpenKnowledge document — including under specs/, reports/, docs/. Folder metadata + templates live in nested <folder>/.ok/, not in .ok/config.yml. Working in a git worktree? Pass the worktree's absolute path as cwd on your OK tool calls once — it sticks for the session, so reads, writes, and the preview all target that worktree.
packages/server/assets/skills/write-skill/SKILL.md
npx skills add inkeep/open-knowledge --skill open-knowledge-write-skill -g -y
SKILL.md
Frontmatter
{
"name": "open-knowledge-write-skill",
"metadata": {
"author": "Inkeep",
"version": "0.24.0",
"repository": "https:\/\/github.com\/inkeep\/open-knowledge"
},
"description": "Use when the user wants to create, author, write, or design a new Agent Skill (a SKILL.md) — for OpenKnowledge or for their editors — including requests like 'help me write a skill', 'make a skill that…', 'turn this workflow into a skill', or improving an existing skill's triggering and discipline. Also use when capturing reusable agent guidance that should live as an installable skill rather than a one-off prompt. Covers choosing scope (project vs global), the SKILL.md frontmatter contract, progressive-disclosure structure, evaluating the skill, and installing it into the user's editors.",
"compatibility": "OpenKnowledge project recommended (uses the `write` \/ `edit` \/ `install` MCP verbs). Authoring + validation are pure file ops; live preview + eval want a running server (`ok start`)."
}
Writing an OpenKnowledge skill
You are helping the user author an Agent Skill — a SKILL.md file (plus
optional references/ and scripts/) that teaches an AI agent how to do a
recurring task. In OpenKnowledge a skill is a first-class, versioned,
installable artifact: you author it with the write / edit skill verbs, then
install it into the user's editors.
Skills earn their keep by being recognized at the right moment and followed
faithfully. Most of the craft is in two places: a description that triggers
reliably, and a body short and concrete enough that the agent actually does what
it says. Work the stages below in order, but jump to where the user already is.
Stage 1 — Capture intent and classify the skill
Gate — does this already exist? Check BEFORE you build. Scan the installed
skills (the host surfaces the full catalog when this skill loads) for one whose
role or triggers already cover the task. If an existing skill covers most of it,
STOP and recommend reuse — a near-duplicate with overlapping triggers
mis-fires and dilutes both. Build a new skill only when it is genuinely distinct,
or a deliberately tighter companion whose description explicitly hands off to
the existing one. Surface the overlap and decide WITH the user before drafting or
writing anything — never discover it after the skill is written.
Ask only what you can't infer:
- What recurring task should this skill handle? Get one concrete example.
- Skill type, because it sets how much rigor to apply:
- Reference / technique (most skills) — "how to do X." Prose body, examples.
- Discipline — enforces a behavior the agent tends to skip under pressure (e.g. "always write a failing test first"). These need the RED baseline + pressure-testing in Stage 4–6; reference skills don't.
- Degrees of freedom (calibrate body precision to task fragility):
high (free prose — judgment tasks), medium (parameterized steps), low
(a fixed
scripts/command — when any deviation breaks the result). Don't over-specify a judgment task or under-specify a fragile one.
Stage 2 — Resolve scope FIRST (never infer silently)
Scope determines where the skill lives and where install projects it. This is
the user's decision and has different blast radius — make it explicit.
| Scope | Lives in | install projects to |
|---|---|---|
| Global | ~/.ok/skills/<name>/ (your user store) |
your editors, in every project |
| Project | <kb>/.ok/skills/<name>/ (this KB, shared via git) |
this project's editors; teammates get it on git pull |
Default heuristic: inside an OK project and the task is specific to it → project; "for all my work / globally" → global; otherwise ask one question. State the choice and its consequence before writing.
Stage 3 — Plan the contents
- Body = the durable, reusable instructions — under ~500 lines. If it's
growing past that, move depth into
references/<topic>.md(loaded only when needed) and point at it from the body. For a project skill the reference auto-connects in the graph either way, so a backticked`references/<topic>.md`path is fine; use a[[references/<topic>]]wiki-link only when you want the mention to be a clickable inline link. For a global skill use a plain backtick path — global references aren't graph docs, so a wiki-link there dangles. Keep references one level deep. - Do NOT include: a README/CHANGELOG/QUICK_REFERENCE, install instructions for the skill itself, version histories, or anything host-specific. The skill is the instructions, not documentation about the instructions.
- For a discipline skill, plan the failure mode you're correcting and how you'll prove the skill fixes it (Stage 4).
Stage 4 — RED baseline (discipline skills only)
Before writing the skill, run the scenario WITHOUT it and capture what the agent
does wrong — verbatim, including its rationalizations ("the test is trivial so I
skipped it"). Those rationalizations are the exact loopholes the skill body must
close. If you have a running server, use the agent simulator
(cd packages/app && bun run src/server/agent-sim.ts) as the executor; otherwise
reason through the baseline transcript with the user. Skip this stage for plain
reference skills.
Stage 5 — Draft the skill
Author the source with the skill verb (fs-direct; a live preview updates if a server is running):
write({ skill: { name: "<lowercase-hyphen-name>", description: "<triggers>", body: "<markdown>", scope: "project" } })
Frontmatter contract (validated on write — get it right):
name— lowercase letters, digits, hyphens; ≤64; equals the directory.description— ≤1024 chars, no XML tags, noversionfield. See Stage 7.- Nothing else. OK never injects its own frontmatter; bookkeeping lives in
.ok/.
Write the body as direct instructions to the agent (imperative, second person), concrete over abstract.
Add depth files — references/*.md (loaded on demand) and scripts/* (shown as
text, never executed by OK) — through the skill verbs, never native Write/cat:
# write one or more bundle files (independent of body — no need to resend SKILL.md)
write({ skill: { name: "<name>", files: [{ path: "references/tiers.md", content: "..." }] } })
# surgical edit inside one bundle file (mirrors edit({ document }))
edit({ skill: { name: "<name>", file: "references/tiers.md", find: "...", replace: "..." } })
# list the bundle, then read one file (no native cat)
skills({ name: "<name>" }) # → files: [{ path, kind }]
skills({ name: "<name>", file: "references/tiers.md" }) # → { path, kind, text }
# delete specific bundle files (omit `files` to delete the whole skill)
delete({ skill: { name: "<name>", files: ["references/tiers.md"] } })
Paths are skill-relative and must live under references/ or scripts/ (one
level deep). A project .md reference becomes a live content doc that
auto-connects to its SKILL in the graph regardless of how the body mentions it —
a backticked `references/<name>.md` path joins the graph just like a
[[references/<name>]] wiki-link. Reach for a wiki-link (or
[label](references/<name>.md)) only when you want a clickable inline link.
Global skills are different: their references aren't graph docs, so use a plain
backtick path there — a wiki-link would dangle.
Stage 6 — GREEN eval + refactor
Re-run the scenario WITH the skill. For a discipline skill, pressure-test:
combine 2–3 pressures (time, authority, sunk cost) and confirm the agent still
follows the rule — then patch any loophole and re-test (references/pressure-testing.md).
For a reference skill, confirm the agent now does the task correctly and the body
isn't longer than it needs to be. Cut anything the agent already knows.
Stage 7 — Optimize the description (this is what makes the skill fire)
The description is the only thing the agent sees when deciding whether to
load the skill. Get it right (references/description-optimization.md):
- Triggers, not a summary. Say WHEN to use it, in the user's words and phrasings — NOT a recap of the body. Summarizing the workflow in the description makes the agent follow the description and skip the body.
- Concrete and a little pushy to fight under-triggering: name the situations, verbs, and phrasings that should activate it.
- Sanity-check against near-miss queries: phrasings that SHOULD trigger it and adjacent ones that should NOT.
Stage 8 — Install (the deliberate Draft → Installed step)
Drafting doesn't change the agent's behavior until you project it:
install({ name: "<name>" })
This fans the validated skill into the project's configured editors
(.claude/skills/, .cursor/skills/, .codex/skills/, .opencode/skills/). For a project skill,
commit .ok/skills/<name>/ and the projections so teammates get it on pull. Edit
later with edit({ skill }) then install again; delete({ skill }) removes it
and uninstalls. Roll back a project skill with history({ skill }) →
restore_version({ skill, version }) — global skills are unversioned in this
build, so they have no history to restore.
Reminders
- Prefer ONE good skill over many overlapping ones; split only when triggers diverge. (The Stage 1 gate is where you ENFORCE this — don't leave overlap to discover later.)
- Scope is the only placement decision — don't fold harness/format/toolchain assumptions into it, and don't bake one into the scope question's wording. You are authoring an OpenKnowledge skill: write it with
write({ skill })and project it withinstall; never hand-write skill files into editor dirs (.claude/skills/,.cursor/skills/,.codex/skills/) —installowns those and overwrites them. If you load this flow, author through it. - Ground claims about how skills behave (versioning, install targets, scope semantics) in this guide or the tool descriptions — don't assert system facts from assumption.
- Avoid blanket ALWAYS/NEVER rules without a stated reason — they read as noise and get ignored. Explain the why.
- A skill that ships executable
scripts/is projected verbatim into another agent's trust domain — only include scripts the user has reviewed.


