| name | wiki-ask |
| description | Answer a wiki question from a wiki's vault — from inside the wiki's repo with ZERO setup, or from anywhere by naming a registered project. Reads wiki content only (never edits it); may safe fast-forward a clean checkout to freshen the answer unless --no-refresh. Use when the user runs /wiki-ask [project] <question>, or asks "why is X built this way?", "what touches Project XYD?", "what's our standard for Y?", "who owns Z?", "how does <cross-repo flow> work?", or any question whose answer should come from a committed wiki. If they're inside a cloned wiki it just works with no name; otherwise it dispatches to a registered project. Answers with citations. Also manages the registry via /wiki-ask list|add|default|remove. |
/wiki-ask [project] — query a wiki, zero-config inside it or by name anywhere
This is a dispatcher. It figures out which wiki to answer from, then searches that wiki's
committed vault (concept pages, standards, decisions, scenarios) and answers with citations. Two
ways it finds the wiki, in order:
- You're inside a cloned wiki → it auto-detects it by walking up from your current directory.
No name, no registration. The fresh-clone path: clone a wiki,
cd in, ask.
- You name a registered project →
/wiki-ask <name> <question> from any directory.
It never edits wiki content. The only writes it makes are: the registry (via the
add/default/remove subcommands), and — to keep answers fresh — a safe git fetch +
merge --ff-only of a checkout that is already clean and on its default branch (step 4), which
only advances it to commits that already exist on the remote and is skipped with --no-refresh.
It never modifies, syncs, or creates a vault page.
The registry maps a short name → an absolute checkout path; it lives at
~/.claude/wiki-registry.json, managed by the bundled scripts under "${CLAUDE_SKILL_DIR}/scripts/".
A wiki's name comes from its committed vault/.wiki-meta.json (set via /wiki-name), else its
git remote, else its directory name.
Invocation: as a global skill this is /wiki-ask …; installed as the plugin it's the
namespaced /codebase-wiki:wiki-ask …. Both run this same skill. The scripts are referenced via
${CLAUDE_SKILL_DIR}, which resolves correctly in both cases.
Procedure
0. Management subcommands (registry, not query)
If the first whitespace token is list, add, default, or remove, run the helper and print
its result — do not treat it as a question:
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-registry.py" list
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-registry.py" add <name> <abs-path> [--vault <abs-vault>] [--desc "..."] [--default]
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-registry.py" default <name>
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-registry.py" remove <name>
For add, <abs-path> is a wiki checkout (has scripts/wiki-grep.py + vault/); use --vault
when the vault lives outside the checkout. Resolve a relative path against the user's cwd first.
(A project literally named "list"/"add" is implausible; if genuinely ambiguous, ask.)
1. Parse the query
Otherwise the input is [project] <question>, where project is optional. Treat the first
token as a project name only if it looks like one (a single bare word, matching a registered name
or a plausible slug); if in doubt, treat the whole input as the question and let auto-detection
(step 2) pick the wiki. A --no-refresh flag anywhere means "skip the safe auto-update in step 4"
— strip it out first.
2. Resolve which wiki to use → a checkout
Resolve in this order, stop at the first hit. Capture ROOT, VAULT_ROOT (the absolute vault dir
to read pages from), HAS_SCRIPTS, and the wiki's name for the answer.
2a. Explicit name given → look it up:
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-registry.py" resolve "<project>"
Prints {name, root, vault, vault_root, exists, vault_exists, has_scripts}, or
{error, available:[...]} on a miss. On a miss, before giving up, also try the cwd walk-up (2b)
in case they're standing in the wiki they named loosely; if that also doesn't fit, show
available and stop (never guess between registered wikis).
2b. No name → auto-detect from the current directory (the zero-config path):
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-locate.py" locate
2c. No name and not inside a wiki → the registry default:
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-registry.py" resolve
- A default exists → use it.
- No default but the registry has exactly one project → use that one.
- Several → list them and ask which (
available); don't guess.
- Empty → explain the two ways in:
cd into a cloned wiki and ask there, or register one with
make register (from inside a wiki) / /wiki-ask add <name> <path>. Stop.
3. Verify the checkout on disk (from the resolve/locate output)
exists: false (the root is gone) → tell the user the checkout for <project> moved or was
deleted; suggest re-pointing it: /wiki-ask add <project> <new-path>. Stop.
vault_exists: false (the vault dir is missing) → tell the user the vault for <project> isn't
on disk; suggest re-cloning or fixing --vault. Stop.
has_scripts: false (vault present, but no scripts/wiki-grep.py) → use the degraded path
in step 6b.
- Otherwise → step 6a (preferred).
4. Refresh the checkout first (safe auto-update)
Before searching, bring the checkout up to date so the answer reflects the latest committed pages
— but only when it's safe. Skip if the user passed --no-refresh:
python3 "${CLAUDE_SKILL_DIR}/scripts/wiki-refresh.py" "<ROOT>"
It prints JSON {action, reason, branch, default_branch, old_sha, new_sha, behind, dirty} and is
deterministically conservative: git fetch + merge --ff-only only when the tree is clean,
on its default branch, and behind the remote. It NEVER stashes, resets, force-merges, switches
branches, or touches a dirty tree.
action: "updated" → mention briefly ("refreshed the wiki — N new commit(s)") and
search the now-current vault.
action: "current" → say nothing about refresh; just answer.
action: "skipped" → answer on the current content, add a short caveat using reason
(e.g. "not refreshed — uncommitted changes" / "on branch 'tem-test'" / "offline").
action: "failed" (diverged history, fetch failed) → answer on current content and note
"couldn't auto-update (reason); run git pull in <ROOT> to refresh."
Whatever the result, always continue to answer — refresh is best-effort, never a blocker.
5. Decide on WIKI_VAULT_DIR
vault is null (vault is <root>/vault, the normal case): run the target's script by absolute
path, with no env and no cd. _lib.py derives the vault from the script's own location.
vault is set (an override): prefix the search commands with WIKI_VAULT_DIR="<vault_root>" so
the target's _lib._resolve_vault() reads the right vault.
6a. Search + answer (scripts present — preferred)
Run the target project's read-only search, mirroring /wiki-ask:
[WIKI_VAULT_DIR="<vault_root>"] python3 "<ROOT>/scripts/wiki-grep.py" "<question or key nouns>"
[WIKI_VAULT_DIR="<vault_root>"] python3 "<ROOT>/scripts/wiki-grep.py" --resolve "<term>" # if a concept is named
[WIKI_VAULT_DIR="<vault_root>"] python3 "<ROOT>/scripts/wiki-grep.py" --neighbors "<title>" # to widen context
(Include the WIKI_VAULT_DIR= prefix only when vault is set.) wiki-grep.py returns
vault-relative paths. Read the top 1–3 pages with the Read tool using absolute paths:
"<VAULT_ROOT>/<the relative path>". Prefer the page whose type fits the question
(standard/decision for "why / what's our rule", scenario for "how does the flow work",
concept for "what is X"). Follow [[links]] and source_mentions only as needed.
6b. Degraded search (vault present, scripts absent)
Use the Grep tool over "<VAULT_ROOT>" (case-insensitive) for the question's key nouns; open the
best-matching .md pages with Read; follow [[links]] by filename slug. Skip
--resolve/--neighbors (they need the scripts + .backlinks.json). Tell the user the
answer used a degraded search because that project's scripts/ is not on disk.
7. Answer with citations
Be direct and scannable. Cite each claim by page title and, when the page records it, its
source_refs (repo:path@sha). Prefer quoting the wiki's own "why" over re-deriving it. End with
the owning team(s) from the pages' owner field. Always state which wiki answered (e.g. "From
the payments wiki:").
8. On a miss
If the search returns nothing relevant, say that wiki doesn't cover it yet, name the closest pages
if any, and suggest running /wiki-sync in that wiki's repo — do not fabricate, and do not
silently switch to a different wiki.
Notes
- Never edits wiki content. No
/wiki-sync, no new pages, no edits to vault pages. The only
writes are the registry (add/default/remove) and the safe fast-forward in step 4 — which
only advances an already-clean, on-default-branch checkout to commits already on the remote, and
is skipped with --no-refresh.
- Refresh is safe by construction.
wiki-refresh.py refuses to touch a dirty tree, a
non-default branch, or diverged history — it can't clobber local work or your current branch.
- Naming a project bounds the search to one vault, so overlapping concept names across wikis
never bleed together — you only ever read under the one resolved
VAULT_ROOT.
- A page is due for re-verification when its
last_updated is newer than last_verified — read
the page's own frontmatter and mention the caveat if it looks stale.
- Read only what you need; synthesize — don't dump whole pages back to the user.