Wiki — Project Bootstrap
Wire the current project into the ~/llm-wiki agent wiki so wiki-aware skills can find context, scope, and the issue tracker convention. The wiki is the canonical surface for cross-session orientation; this skill is the on-ramp from a consumer project.
This is a prompt-driven bootstrap, not a deterministic script. Explore, present what you found, confirm with the user, then write.
What this skill produces
In the consumer project:
- Project instructions (
AGENTS.mdor the harness's equivalent — § Harness placement) populated fromtemplates/project-agents.md.templatewith three sections:## First read,## Wiki integration(carryingWIKI_SCOPE,WIKI_ISSUE_TRACKER,WIKI_TRIAGE_LABELS), and## Sub-agent spawning. - MCP registration guidance — only when the
wikiMCP server is not already available (plugin-bundled or user-registered). Shows the canonicalnpx @bartolli/kmd mcp --default-root <vault-path>JSON and lets the user place it.
Both are idempotent — if a section/entry already exists, update in place rather than duplicate.
In the vault, only when no vault exists yet (new-vault bootstrap):
- Barebone vault structure the MCP server requires — scaffolded by
kmd init(startervault.yamlwith emptyscopes, the 11 served templates, and theprojects/,research/,notes/domain dirs), the user's first scope then added tovault.yamlperreferences/vault-yaml.md§ Minimal starter. Two forms:kmd init <vault-dir> [--set-default]for a global vault,kmd init --localfor a vault the repo carries (§ Local vs global vault).
Mental model
The wiki itself
- Three domains (
projects/,research/,notes/) under~/llm-wiki/vault/ - A controlled vocabulary of project scopes defined in
~/llm-wiki/vault/vault.yamlunderscopes:— adding a new scope requires explicit user approval per the vault blueprint - Two MCP tools:
prime(scope, task?)for orientation,search(query, scope?, kind?, limit?)for retrieval — mirrored askmd prime <scope> [--task <text>]andkmd search <query>for a harness without MCP tools, same server in-process - Templates exposed as MCP resources at
wiki://template/{domain}/{kind}, or viakmd resource <uri>where the harness reads no resources (11 templates: project-{index, primer, spec, adr, plan, ops, story}, research-{index, article, src}, note) — served fromtemplates/at the vault root, re-read on every call; a missing file errors at resource-read time
A consumer project becomes wiki-aware by declaring WIKI_SCOPE: <scope> in its project instructions (AGENTS.md or the harness's equivalent). The agent reads this at session start and calls prime(scope) automatically — the wiki MCP tool, or kmd prime <scope> where the harness exposes no MCP tools.
Local vs global vault
Every kmd entry point (MCP server, hooks, bare CLI) resolves its vault through one chain: explicit argument > project tier > --default-root > $WIKI_VAULT > global default_vault (~/.kmd/config.yaml). Two setups fall out, and the bootstrap's first real decision is which one the project wants:
- Global vault (the common case): one personal wiki serves many projects.
kmd init <vault-dir> --set-defaultscaffolds it and records it as the machine default; registrations point at it via--default-root. - Project vault: the repo carries its own vault, living and dying with it.
kmd init --localfrom inside the repo scaffolds<git-root>/vault/plus a.kmd/state home (index and hook state stay in the repo, gitignored). No registration change is needed — the project tier resolves ahead of the default for every command run inside the repo. A team variant commits.kmd/config.yamlwith a repo-relativevault:path instead.
How the MCP server learns which project it serves differs per harness — § Harness placement, row Project-vault signal, names each. Gate hooks are project-aware everywhere without any of this — they read the project from each event.
When prime answers UNKNOWN_SCOPE
The error's valid scopes list names every scope of the vault that actually answered — read it first, it tells you which vault the server bound. Two distinct causes:
- The wrong vault answered (the listed scopes belong to the default/global wiki, not this project): the server bound the default instead of the project vault. Confirm with
kmd configfrom the project root — it prints the vault the chain resolves and the rank that won; that is what the MCP server should be serving. Then fix the harness's project signal:- Fix the harness's project signal — § Harness placement, Wrong vault bound, names the remedy per harness — and restart the session so the server re-binds.
- The right vault answered but the scope isn't in it: this is vocabulary, not resolution — route to step 2's scope flow; adding a scope to
vault.yamlalways takes explicit user approval.
Hooks resolving correctly while prime serves the wrong vault is the signature of case 1 — hooks read the project from each event, the MCP server binds once at launch from its own signal.
Wiki-aware skill constellation
/wiki is the on-ramp. The other wiki-aware skills form a workflow loop, each consuming what the previous produced:
| Skill | Reads | Writes |
|---|---|---|
/intent |
wiki state via prime(scope) (MCP tool or kmd prime); codebase (brownfield) |
index.md, primer.md, glossary.md, lazy adr-{topic}.md |
/to-stories |
conversation; glossary.md; existing ADRs |
thin plan-{name}.md + per-story plan/{name}/story-N-{slug}.md |
/triage |
story files | mutates triage_state / category in story frontmatter; adr-no-{slug}.md on wontfix |
/to-issues |
story files; codebase | refined ## Slices in story body; remote issues in GH/GitLab mode |
/tdd |
story scenarios as test spec; referenced specs | code + tests; ticks the slice, archives the story at the last tick |
/retro |
the session's own claims, gates, and drift from the slice in progress | small testable fixes in the current commit with a Decisions line; intents (max three) for what the hot context cannot fix; sightings bumps; a dated note under the scope's notes/ — invocable any time, never a story, never the primer |
/handoff |
fully-resolved stories; every plan's Story Index; the retro's residue | archive flips for the sweep's strays on approval, reconciled Story Index, the primer under budget in the canonical-dense register — gated on a retro note newer than the scope's last edit |
/to-triggers |
a stated rule, or a protocol rule that just failed to fire | tested trigger entries under vault.yaml triggers_extra — on demand, outside the loop |
Typical session arc for new work: /intent → /to-stories → /triage → /to-issues → /tdd (per slice) → repeat triage when stories complete or intents reach two sightings → /retro whenever drift is suspected and always before the close → /handoff closes the session. /to-triggers joins whenever a rule proves it needs to become a gate.
Companion skills (vault file editing)
When the agent edits files in the vault, four global skills cover Obsidian-flavored markdown and adjacent file types. They are NOT wiki-aware (no WIKI_SCOPE knowledge), but they handle the file format that the wiki uses:
| Skill | When to use |
|---|---|
obsidian-markdown |
Authoring .md files in the vault — wikilinks, callouts, embeds, frontmatter, tags. Triggers on most edits inside ~/llm-wiki/vault/. |
obsidian-bases |
Editing .base files in vault/views/. Bases are human-navigation surfaces (table/card views over the vault); agents rarely author them but should use this skill when asked. |
obsidian-cli |
Only when a live Obsidian instance is genuinely needed — plugin/theme dev, screenshots, Dataview re-render. Not the canonical search/read surface — use the wiki MCP search tool and filesystem Read instead. |
json-canvas |
Editing .canvas files (mind maps, flowcharts). Not in the standard wiki authoring loop. |
These compose with the wiki-aware skills: /to-stories writes story files (using wiki://template/project/story — MCP resource, or kmd resource <uri> — for structure and frontmatter), and obsidian-markdown handles the Obsidian-flavored body content (wikilinks, callouts) inside that file.
Harness placement
This skill runs anywhere SKILL.md skills are supported — same slash-invocation dialect — but where files land differs per harness:
| Claude Code | Codex | CoCo (Cortex Code) | Kiro (IDE and CLI) | |
|---|---|---|---|---|
| Skill files | wiki-sdd plugin, or ~/.claude/skills/wiki/ |
wiki-sdd plugin via codex plugin add |
wiki-sdd plugin, or ~/.snowflake/cortex/skills/wiki/ (.claude/skills/ is read too) |
the wiki-sdd power, imported from the Package folder (Powers panel → Add Custom Power → Import power from a folder); the skills ride the power |
| MCP registration | .mcp.json at the project root, or user-level settings |
plugin-bundled, or [mcp_servers.wiki] in ~/.codex/config.toml |
plugin-bundled, or mcpServers in ~/.snowflake/cortex/mcp.json |
power-bundled (mcp.json, activated on a keyword match) — it serves the machine default, so kmd config set default_vault <path> once per seat is the precondition; a project vault takes a workspace .kiro/settings/mcp.json from templates/mcp-entry-kiro.json.template — the operator's file; both merge, workspace wins |
| Project-vault signal | automatic (plugin maps the project dir) | export KMD_PROJECT_DIR="$PWD" in the launching shell |
automatic when launched from the project root; export KMD_PROJECT_DIR="$PWD" when using -w |
workspace-level .kiro/settings/mcp.json naming the project vault — the operator's file |
| Project instructions | CLAUDE.md or AGENTS.md (step 7) |
AGENTS.md |
AGENTS.md, CLAUDE.md, or CORTEX.md — all read |
AGENTS.md, read automatically; .kiro/steering/*.md when inclusion modes are wanted |
Project-vault signal, in detail: the Claude Code plugin maps the project directory automatically; CoCo's plugin server inherits the directory the session was launched from, so a project vault resolves on its own (but -w/--workdir does not move it — export KMD_PROJECT_DIR="$PWD" covers that case); Codex needs export KMD_PROJECT_DIR="$PWD" in the shell that launches it (its adapter README documents this — Codex gives plugin MCP servers no workspace signal of its own); the Kiro power's bundled server has no project signal and serves the machine default, so a project vault takes a workspace-level .kiro/settings/mcp.json naming it — the operator's file.
Wrong vault bound (prime answered from the default instead of the project vault):
- Claude Code (plugin): the mapping is automatic, so a wrong bind means the server predates the current session state — restart the session (or
/reload-plugins) so the plugin re-registers with the project directory. - CoCo: the server bound the directory the session was launched from. Relaunch from the project root, or
export KMD_PROJECT_DIR="$PWD"before starting — plugin MCP servers get a scrubbed environment, and the bundled registration forwardsWIKI_VAULTandKMD_PROJECT_DIRthrough it for exactly this. - Codex: the classic cause — no
KMD_PROJECT_DIRin the launching shell, often masked by an ambientWIKI_VAULTexport that pins the default.export KMD_PROJECT_DIR="$PWD", then restart the Codex session so the MCP server inherits it. - Kiro: the power's server serves the machine default — with none set (
kmd config set default_vault <path>) it dies at bind and the power lists no tools; a workspace.kiro/settings/mcp.jsonnaming the project vault, placed by the operator, and a reconnect.
Standalone registration placement:
- Claude Code: project-local
.mcp.json, or user-level settings — let the user choose the scope. - Codex:
[mcp_servers.wiki]in~/.codex/config.tomlwith the same command/args shape;env_vars = ["KMD_PROJECT_DIR"]lets a per-shell export reach the server for project vaults. - CoCo (Cortex Code):
mcpServersin~/.snowflake/cortex/mcp.json, same shape. Prefer a globally installedkmdas thecommandovernpx— CoCo gives plugin MCP servers onlyHOME,LOGNAME,PATH,SHELL,TERM, andUSER, so anything the server needs from the environment must be declared in the entry's ownenvblock (${VAR:-fallback}interpolates there). - Kiro (IDE and CLI):
.kiro/settings/mcp.json(workspace) or~/.kiro/settings/mcp.json(user), fromtemplates/mcp-entry-kiro.json.template— Kiro wraps the same entry inmcpServersand addsdisabledandautoApprove; pre-approvingprimeandsearchkeeps orientation friction-free, andenvvalues support${VARIABLE}expansion. The Kiro CLI can register the same server viakiro-cli mcp add(defer to its--helpfor current flags rather than guessing them).
Project instructions: Kiro picks up AGENTS.md automatically (always included, no inclusion modes); a .kiro/steering/ file is the native alternative when the user wants conditional inclusion — the same three sections apply.
Gate hooks on Kiro: the power carries no hook wiring — the standard has none, and Kiro loads none from a power — so this is the one harness where the bootstrap writes a file for the gates. Write ~/.kiro/hooks/wiki-sdd.json from the installed power's dev.kiro/hooks/wiki-sdd.json.template, replacing {{PACKAGE_ROOT}} with the installed power's absolute path — Kiro copies an imported folder into ~/.kiro/powers/installed/<name>/, so for this power it is ~/.kiro/powers/installed/wiki-sdd, and the template lives there too. Write nothing under .kiro/settings/ — a project vault's entry there is the operator's, and the seat's permissions deny the agent that path. The outcome, once the workspace is trusted and the session restarted: the gates live on the seat — prompt-time reminders, tool denies, validate + sync after vault writes, the handoff gate — through the engine on PATH at 0.17.1 or newer (npm i -g @bartolli/kmd).
Gate hooks
The plugin registers kmd hook on the harness's events — this bootstrap adds no wiring step, except on a harness that loads no hooks from a plugin, where § Harness placement names the one file the step writes. Three behaviors ride along: prompt-time reminders, tool gates, and auto validate + sync after every vault write (the resync protocol runs as an event; validation findings return as hook feedback and hold the sync until fixed). The bootstrap's only responsibilities toward them: declare repo: on each scope in vault.yaml so the engine resolves the active scope from the session's working directory, and leave the trigger sections empty — vault-owned triggers grow from observed failures (references/vault-yaml.md § Harness gate triggers), never from upfront speculation. When that moment arrives — the user says "add a rule/hook/trigger for…", or a prose rule just failed to fire — route to /to-triggers: it interviews the intent, authors the matching mechanics, dry-runs fire and near-miss cases, and writes vault.yaml only on approval.
Process
1. Explore
Read the current state. Don't assume.
git remote -v— does this repo have a remote? GitHub? GitLab? Or no remote?- Read the project-instructions file at the project root (
AGENTS.mdor the harness's equivalent — § Harness placement). Is there already a## Wikiblock? - Is a
wikiMCP server already registered for this project (§ Harness placement, row MCP registration)? - Read
vault.yamlin the vault root — thescopes:field is the authoritative scope vocabulary. - Check whether
primeandsearchtools from a wiki MCP server are already available in the session. Without them the same surface is the CLI:kmd prime,kmd search,kmd resource.
2. Determine scope
If vault.yaml does not exist (new vault): this is vault bootstrap, not just project bootstrap. First settle the § Local vs global vault decision with the user — a vault the repo carries versus one personal wiki serving many projects — then run the matching init form:
- Global:
kmd init <vault-dir> --set-default— scaffolds and records the machine default in one step (--set-defaultis the only non-interactive route to writingdefault_vault; an interactive TTY init offers it as a prompt). - Project:
kmd init --localfrom inside the repo — scaffolds<git-root>/vault/plus the.kmd/state home with its.gitignore; every kmd command run inside the repo resolves this vault from then on, no registration or env changes.
Either form scaffolds the starter vault.yaml (empty scopes), the 11 served templates, and the projects/, research/, notes/ domain dirs, refusing a non-empty target. Then add the user's first scope to the generated vault.yaml per references/vault-yaml.md § Minimal starter. The file is fail-loud — the MCP server and kmd tooling refuse to run on an invalid one — so validate (kmd validate) before continuing. Trigger sections start empty and stay empty at bootstrap; when the first rule earns a gate, /to-triggers authors it.
If the user declares a custom kind (an object-form kinds entry, now or later): offer to co-author its template at templates/{name}.md right away — protocol in references/vault-yaml.md § Custom kinds. A declared kind without its template draws a kmd validate warning until the file exists.
Ask the user which wiki scope this project belongs to. Show the scopes from vault.yaml as options.
If the user names a scope already in vault.yaml: proceed.
If the user names a scope NOT in vault.yaml: STOP. Per the vault blueprint, new scopes require explicit user approval. Surface this clearly — list the current scopes from vault.yaml and explain:
"
<requested-scope>is not in the wiki's scope vocabulary (currently:<comma-separated scopes from vault.yaml>). Adding a new scope requires updating~/llm-wiki/vault/vault.yamland is a deliberate vocabulary extension. Do you want to (a) approve adding<scope>to the vocabulary, (b) pick an existing scope, or (c) abort?"
If (a): add the new scope entry to vault.yaml's scopes: field (with status: active), AND offer to run /intent next to scaffold projects/{scope}/.
3. Determine issue tracker
Detect:
git remote -vshows agithub.comhost → recommendWIKI_ISSUE_TRACKER: githubgit remote -vshows agitlab.com(or self-hosted GitLab) host → recommendWIKI_ISSUE_TRACKER: gitlab- No remote, or user prefers offline-first → recommend
WIKI_ISSUE_TRACKER: local
State your recommendation with reasoning. Let the user override.
Behavior implications (mention briefly):
github/gitlab:/to-issuesmirrorsready-for-agentslices to the remote tracker; story files in the wiki remain canonical.local: slices and triage state live entirely in story files underplan/{plan-name}/story-N-{slug}.md; no remote calls.
4. Triage label vocabulary
Default to Matt Pocock's canonical roles:
needs-triage— story needs evaluationneeds-info— agent waits on user clarification (in a solo-operator context, this means the agent needs a decision from the user)ready-for-agent— fully specified, AFK-readyready-for-human— needs human implementation (judgment, external access, hardware)wontfix— will not be actioned
In a solo-operator context, needs-info semantically reads as "the agent is blocked on a user decision." This is the intended interpretation — flag it once during setup so the user understands the role mapping.
If the user wants to override any label string (because their issue tracker uses different conventions), capture the mapping in WIKI_TRIAGE_LABELS: as a JSON object.
Default: WIKI_TRIAGE_LABELS: {"needs-triage":"needs-triage","needs-info":"needs-info","ready-for-agent":"ready-for-agent","ready-for-human":"ready-for-human","wontfix":"wontfix","bug":"bug","enhancement":"enhancement"}
5. Detect MCP registration state
Check whether the wiki MCP server is already available to this session — look for it in the available tools list (a prime and search tool from a wiki-named server).
If a wiki-sdd plugin is installed: the plugin bundles the server registration; the vault resolves through the chain — the project tier first, then the plugin's configured default where the harness prompts for one, then $WIKI_VAULT, then the machine default. Nothing to register. One note before skipping to step 7: a project vault may additionally need the harness's project-vault signal (§ Harness placement) — without it, prime/search serve the default vault while the hooks correctly follow the project one.
If the skill is standalone (no plugin) and no wiki MCP server is available: the user needs to register it. Show the canonical registration JSON from templates/mcp-entry.json.template with the vault path filled in:
{
"mcpServers": {
"wiki": {
"command": "npx",
"args": ["-y", "@bartolli/kmd", "mcp", "--default-root", "/absolute/path/to/vault"]
}
}
}
--default-root vs a bare positional: --default-root keeps the resolution chain live — a project carrying its own vault wins over the registered default automatically. A bare positional ("mcp", "/path") pins that vault unconditionally and disables project awareness; offer it only when the user explicitly wants one registration locked to one vault.
Placement is harness-specific — § Harness placement, Standalone registration placement, names the file per harness. For any other harness, show the generic JSON and let the user place it per their harness's MCP docs; don't prescribe OS-specific paths.
6. Existing vault: bring it to the starter
Whenever a vault resolved in step 5 — global, project tier, or the one prime answered from — run the engine's report before writing project instructions:
kmd init --upgrade [<vault-root>]
Exit 0 means the vault is current with the engine's starter. Exit 1 means it is behind: the report names each missing kind, status, methodology, template file, or domain dir, and lists templates the vault holds in an edited form as differs (kept). Show the report verbatim. On the user's approval, apply it:
kmd init --upgrade [<vault-root>] --apply
The apply is additive and idempotent — it appends to vault.yaml in place, writes only missing template files, creates missing domain dirs, and never touches scopes, tags, triggers, or an edited template. Never narrate what the deltas will be; the report is the source of truth, and a vault scaffolded by this engine's kmd init is current by construction.
CLI route only — the two-tool MCP freeze leaves no resource for this. The session-start orientation also names a vault behind the starter, and a template file missing error from a served template names the same command.
7. Confirm and write the project instructions
Pick the file to edit: the project-instructions file the harness reads (§ Harness placement, row Project instructions). If one exists at the project root, edit it — the same template applies to every name. If none exists, ask which one to create — don't pick for the user.
Use the bundled template at templates/project-agents.md.template. Fill these placeholders:
| Placeholder | Source |
|---|---|
{{scope}} |
The validated scope from step 2 |
{{issue_tracker}} |
github / gitlab / local from step 3 |
{{triage_labels}} |
The JSON map from step 4 |
If a ## First read, ## Wiki integration, or ## Sub-agent spawning section already exists in the target file, update those sections in place rather than appending duplicates. Don't overwrite user edits to surrounding sections.
Per-scope adaptations to the template:
- The Sub-agent spawning section references
projects/{{scope}}/ops/ops-slicing-protocol. If that file doesn't exist in the vault, change "if it exists" to "if/when it exists" — keep the pointer so future readers know where to look. - The template adds two lines (
WIKI_ISSUE_TRACKER,WIKI_TRIAGE_LABELS) that aren't in the original minimal shape. They're inert if unused;/to-issuesreadsWIKI_ISSUE_TRACKER,/triagereadsWIKI_TRIAGE_LABELS.
Show the rendered template to the user before writing. Let them edit. Then write.
8. Done
Tell the user setup is complete and which wiki-aware skills will now read from these files. Mention they can edit the file directly later if WIKI_SCOPE or WIKI_ISSUE_TRACKER changes.
Suggest the next step:
- If
projects/<scope>/index.mdalready exists in the vault → "You're set up. Try/intentto refine intent or kick off a new workstream." - If it doesn't exist → "The vault doesn't have a scope folder for
<scope>yet. Run/intentto scaffold it."
Rules
- Never silently add a new scope to
vault.yaml. Always confirm with the user. - Never overwrite a non-empty project-instructions file without showing the diff first.
- Check for an existing wiki MCP server (plugin-bundled or user-registered) before offering to register one. If the
wiki-sddplugin is installed, its bundled registration already covers it. - Use
npx @bartolli/kmd mcp --default-root <vault-path>for standalone registration — don't constructpnpm/tsxdev paths, and don't pin the bare positional unless the user asks for a locked registration. Let the user choose where to place the registration (§ Harness placement). - Always check for existing
## First read,## Wiki integration,## Sub-agent spawningsections before writing — update in place if found. - Use the bundled
templates/project-agents.md.templaterather than emitting the structure inline. Edits to the template propagate to all future bootstraps. - Scaffold new vaults with
kmd init(<vault-dir> [--set-default]global,--localproject) — the engine embeds the template set; filenames are the server's URI→file contract and the content is served to future agents as-is; never author templates inline, rename files, or assemble the structure by hand. - Don't run
/intentautomatically — suggest it as the next step, but let the user invoke it.