@zosmaai/pi-llm-wiki
Version:
Self-maintaining LLM Wiki for Pi — Karpathy-pattern knowledge base with immutable source capture, automated ingestion, search, linting, and Obsidian-compatible vault. auto-updating personal & company wiki.
467 lines (334 loc) • 15.7 kB
Markdown
# API Reference
All tools registered by the extension. Parameters marked `?` are optional.
13 tools are always registered. The 3 agent-trajectory tools
(`wiki_capture_trajectory`, `wiki_distill_skills`, `wiki_recall_skill`) are **opt-in,
off by default** (issue #80) — they are only registered when `llm-wiki.trajectories`
is `true`; enable with `/wiki-trajectories on`.
## wiki_bootstrap
Initialize a new LLM Wiki vault with the 4-layer architecture. Creates config, templates, schema,
and metadata scaffolding.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `topic` | `string` | ✅ | Main topic of the wiki |
| `mode` | `string` | — | `"personal"` or `"company"` (default: `"personal"`) |
| `root` | `string` | — | Root directory to bootstrap in (default: current working directory) |
**Returns**
```
details: { root: string, mode: string, topic: string }
```
Confirmation text includes the vault path, directory layout, and a prompt to capture the first source.
## wiki_capture_source
Capture a URL, local file, or pasted text into an immutable source packet and skeleton source page.
Provide exactly one of `url`, `file_path`, or `text`.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `url` | `string` | — | URL to fetch and capture |
| `file_path` | `string` | — | Absolute or relative path to a local file (PDF, md, txt, html, XML, JSON) |
| `text` | `string` | — | Pasted text content to capture directly |
| `title` | `string` | — | Title override (used for `text` captures; inferred from URL/file otherwise) |
**Returns**
```
details: {
sourceId: string, // e.g. "SRC-2026-06-03-001"
packetPath: string, // path to raw/sources/SRC-.../
sourcePagePath: string, // path to wiki/sources/SRC-....md (skeleton)
extractedPreview: string // first 300 chars of extracted content
}
```
Errors with `isError: true` if no vault exists or no source input is provided.
## wiki_ingest
Return a batch of uningested source packets for the LLM to synthesize. Does not write anything
itself — the model reads the returned extracted content, fills in the skeleton source page,
and creates entity/concept pages.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `source_id` | `string` | — | Process a specific source ID only; leave empty to get the next unprocessed batch |
| `batch_size` | `number` | — | Max sources to return (default: `3`, max: `5`) |
**Returns**
```
details: {
batch: string[], // source IDs in this batch, e.g. ["SRC-2026-06-03-001"]
remaining: number // sources still waiting after this batch
}
```
Each batch entry includes the source title, char count, and the path to read (`raw/sources/{id}/extracted.md`).
Returns a "all sources ingested" message with `{ ingested, total }` when nothing is pending.
## wiki_ensure_page
Resolve or safely create a canonical wiki page. Returns immediately if the page already exists
(no overwrite). Uses a built-in template when `content` is not provided.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `type` | `string` | ✅ | Page type: `"entity"`, `"concept"`, `"synthesis"`, `"analysis"`, `"requirement"`, `"skill"`, or `"case"` |
| `title` | `string` | ✅ | Human-readable page title; auto-slugified to a kebab-case filename |
| `content` | `string` | — | Full markdown content for the page; if omitted, the type-appropriate template is used |
**Returns**
```
details: { path: string, created: boolean }
```
`created: false` means the page already existed and was not modified.
## wiki_recall
Search both the personal (`~/.llm-wiki/`) and project (`.llm-wiki/`) vaults for pages relevant to
a query. Uses chunk-level scoring, weighted field matching, and pseudo-relevance feedback. Also
called automatically before every agent turn.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `query` | `string` | ✅ | Search query — use the user's full request or key terms |
| `max_results` | `number` | — | Maximum pages to return (default: `5`, max: `10`) |
**Returns**
```
details: {
query: string,
matches: Array<{
id: string, // folder-qualified page ID, e.g. "concepts/rag"
title: string,
type: string, // "source" | "entity" | "concept" | "synthesis" | "analysis"
preview: string, // best-matching chunk or page intro (~200 chars)
path: string, // absolute filesystem path to the .md file
score: number, // relevance score (higher = better)
vaultLabel?: string // "📓 personal" when result is from the personal vault
}>
}
```
Returns empty `matches: []` with a hint to use `wiki_retro` when the wiki has no matching pages.
## wiki_search
Exact keyword search across the generated registry. Faster and simpler than `wiki_recall` — no
scoring, no PRF, no vault layering. Use for lookups when you already know what you're looking for.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `query` | `string` | ✅ | Search term matched against page IDs, titles, and types |
| `type` | `string` | — | Filter results to a specific page type (e.g. `"concept"`, `"entity"`) |
**Returns**
```
details: {
query: string,
matches: Array<{ id: string, title: string, type: string }>
}
```
## wiki_retro
Save an atomic insight from a completed task as a single lightweight markdown file in
`wiki/sources/`. Does not create a full source packet. Rebuilds metadata immediately so the
insight is searchable in the same session.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `slug` | `string` | ✅ | Unique kebab-case identifier (e.g. `"jwt-revocation-pattern"`). Used as the filename and for lookups. |
| `title` | `string` | ✅ | Short descriptive title, 60 chars max. Noun phrase, not a sentence. |
| `body` | `string` | ✅ | Markdown content explaining what was learned. Include `[[wikilinks]]` to related pages. |
| `category` | `string` | — | Optional grouping label (e.g. `"frontend"`, `"architecture"`, `"devops"`, `"bugfix"`) |
**Returns**
```
details: { slug: string, title: string, category: string | null }
```
## wiki_observe
Record a timestamped, relevance-rated observation during a session. Saved to `wiki/sources/` with
`status: observation`. Immediately searchable via `wiki_recall`. Intended for mid-session capture;
use `wiki_retro` for end-of-task summaries.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `title` | `string` | ✅ | Short descriptive title, ≤80 chars. Noun phrase, not a sentence. |
| `content` | `string` | ✅ | Plain prose: what happened, was decided, or was learned. Preserve specifics (file paths, function names, error messages, numbers). |
| `relevance` | `"low" \| "medium" \| "high" \| "critical"` | ✅ | Retention priority. `low` = routine; `medium` = task context; `high` = non-trivial decisions; `critical` = persistent identity/preference or completed work that must not be redone. |
| `tags` | `string` | — | Space-separated tags for categorisation (e.g. `"auth backend migration"`) |
| `source_context` | `string` | — | What was being worked on (e.g. `"Adding authentication module"`) |
**Returns**
```
details: { slug: string, title: string, relevance: string, tags: string | null }
```
The slug is auto-generated as `obs-YYYY-MM-DD-{title-slug}`.
## wiki_lint
Deterministic health check of the wiki. Scans for orphan pages (no inbound links), missing pages
(linked but not created), and contradiction markers. Optionally auto-creates stub pages for
knowledge gaps cited in two or more pages.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `auto_fix` | `boolean` | — | When `true`, auto-creates stub concept pages for gaps mentioned in ≥2 pages (default: `false`) |
**Returns**
```
details: {
pages: number,
orphans: number,
missingPages: number,
contradictions: number,
reportPath: string, // path to the generated lint report .md file
gaps: number // knowledge gaps tracked in .discoveries/gaps.json
}
```
The lint report is written to `.llm-wiki/outputs/lint-YYYY-MM-DD.md`.
Contradictions are flagged by the presence of `⚠️ **Contradiction` markers in page content and
always require human review.
## wiki_status
Report wiki health and statistics from the generated registry. Reads pre-built metadata — does not
scan files directly.
**Parameters**
None.
**Returns**
```
details: {
topic: string,
mode: string, // "personal" or "company"
totalPages: number,
byType: Record<string, number>, // e.g. { concept: 4, entity: 2, source: 7 }
orphans: number,
gaps: number,
health: "✅ Good" | "⚠️ Warning" | "🔴 Empty"
}
```
Health is `"⚠️ Warning"` when orphan count exceeds 5, `"🔴 Empty"` when the registry has no pages.
## wiki_rebuild_meta
Force a full synchronous rebuild of all generated metadata: `registry.json`, `backlinks.json`,
`index.md`, `log.md`. Use when metadata appears out of sync with actual wiki files.
**Parameters**
None.
**Returns**
```
details: { pageCount: number }
```
## wiki_log_event
Append a structured event to `meta/events.jsonl` and regenerate `meta/log.md`. Every event is
timestamped automatically.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `kind` | `string` | ✅ | Event kind label (e.g. `"ingest"`, `"query"`, `"decision"`, `"integrate"`) |
| `details` | `object` | — | Arbitrary additional fields to store alongside the event |
**Returns**
```
details: { kind: string }
```
## wiki_watch
Print a ready-to-paste **POSIX crontab line** that runs the full wiki cycle (discover → ingest →
lint) on a schedule by invoking `pi -p "/wiki-run"` headlessly under `/bin/bash -lc` so the
user's shell profile (and the `pi` binary on npm-global / bun / nvm PATH) is imported. **Does
not schedule anything directly** — it returns the command for the user to install with
`crontab -e`. Calling agents should surface the output verbatim and avoid claiming the schedule
is active.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `interval` | `string` | ✅ | `"daily"` (8:00 AM), `"weekly"` (Monday 9:00 AM), `"hourly"`, or `"stop"` (prints crontab removal instructions) |
**Returns**
```
details: {
interval: string,
cronSchedule: string, // 5-field POSIX expression, e.g. "0 8 * * *"
label: string, // e.g. "Daily at 8:00 AM"
cronLine: string, // full crontab line, tagged "# llm-wiki-autoupdate"
installed: false // tool never installs — always false
}
```
Output is appended to `~/.llm-wiki/cron.log` (the directory is created by the cron line itself
via `mkdir -p`). On systems without `/bin/bash`, replace the wrapper with `/bin/sh -c` and
ensure `pi` is in cron's PATH yourself.
When `interval` is `"stop"`, returns `details: { action: "stop_instructions" }` with
instructions for removing the line via `crontab -e` (look for the `# llm-wiki-autoupdate` tag).
## wiki_capture_trajectory
Capture the just-completed task's tool-call trajectory into an immutable packet
(`raw/trajectories/TRJ-*`) with a self-contained summary (`extracted.md`). The working-memory
counterpart to `wiki_capture_source`. By default the trajectory is auto-extracted from the live
session; pass `steps` to override. **Opt-in** (issue #80): only available when
`llm-wiki.trajectories` is enabled (`/wiki-trajectories on`).
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `title` | `string` | — | Short descriptive title for the task (≤60 chars). Inferred from the prompt if omitted. |
| `task` | `string` | — | The task/prompt that started the work. Inferred from the session if omitted. |
| `outcome` | `string` | — | `"success"` (default), `"failure"`, or `"partial"` — recorded in the packet manifest |
| `steps` | `array` | — | Explicit trajectory steps (tool-call history). Omit to auto-extract from the live session. |
| `model` | `string` | — | Model that ran the task. Inferred from the session if omitted. |
**Returns**
```
details: {
trajectoryId: string, // e.g. "TRJ-2026-06-07-001"
packetPath: string, // path to raw/trajectories/TRJ-*/ (packet.json + extracted.md)
stepCount: number
}
```
Errors with `isError: true` if no vault exists, or with `error: "empty_trajectory"` when no
trajectory can be extracted and no `steps` are provided.
## wiki_distill_skills
Return a batch of captured trajectories that have not yet been distilled into `skill` pages. Does
not write anything itself — the model reads each packet and synthesizes reusable skill pages (via
`wiki_ensure_page(type="skill")`) that cite the trajectory IDs. A trajectory counts as "distilled"
once a `skills/` page links to it.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `trajectory_id` | `string` | — | Distill a specific trajectory only; omit for all undistilled |
| `batch_size` | `number` | — | Max trajectories to return (default: `3`, max: `5`) |
**Returns**
```
details: {
batch: string[], // trajectory IDs in this batch, e.g. ["TRJ-2026-06-07-001"]
remaining: number // undistilled trajectories still waiting after this batch
}
```
Each batch entry includes the title, step/tool-call counts, and paths to read
(`raw/trajectories/{id}/packet.json` and `extracted.md`). Returns an "all trajectories distilled"
message with `{ distilled, total }` when nothing is pending.
## wiki_recall_skill
Search distilled `skill` pages and past `case` pages for patterns relevant to the current task —
answers "have I done something like this before?". Filters layered recall (`searchWikiLayered`) to
skill/case pages. Call at the START of a task.
**Parameters**
| Name | Type | Required | Description |
|------|------|----------|-------------|
| `query` | `string` | ✅ | Search query — use the task description or key terms |
| `kind` | `string` | — | `"skill"`, `"case"`, or `"any"` (default) |
| `max_results` | `number` | — | Maximum pages to return (default: `5`, max: `10`) |
**Returns**
```
details: {
query: string,
kind: string,
matches: Array<{
id: string, // folder-qualified page ID, e.g. "skills/jwt-revocation"
title: string,
type: string, // "skill" | "case"
preview: string,
path: string,
score: number,
vaultLabel?: string // "📓 personal" when result is from the personal vault
}>
}
```
Returns empty `matches: []` with a hint to capture work via `wiki_capture_trajectory` /
`wiki_distill_skills` when nothing matches.
## Error Shape
All tools return `isError: true` in their result when a hard error occurs (no vault found, missing
required input). The `text` content will contain a human-readable explanation. Check for `isError`
before using `details`.
```ts
{
content: [{ type: "text", text: string }],
details: { error: string },
isError: true
}
```
The most common error is **"No wiki found — run wiki_bootstrap first"**, returned by every tool
except `wiki_bootstrap` itself when `.llm-wiki/config.json` does not exist in the resolved vault
root.