@zosmaai/pi-llm-wiki 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mcp/index.ts ADDED
@@ -0,0 +1,487 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * LLM Wiki MCP Server
5
+ *
6
+ * Exposes wiki tools over the Model Context Protocol (MCP).
7
+ * Run: node mcp/index.js
8
+ * Or via package.json: pi install npm:@zosmaai/pi-llm-wiki && node mcp/index.js
9
+ *
10
+ * Environment:
11
+ * WIKI_ROOT — path to wiki vault (default: auto-detect from cwd)
12
+ * WIKI_MARKITDOWN_TIMEOUT_MS — PDF extraction timeout (default: 180000)
13
+ */
14
+
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { McpServer } from "@modelcontextprotocol/server";
18
+ import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
19
+ import * as z from "zod/v4";
20
+
21
+ // ─── Wiki Vault Detection ──────────────────────────────
22
+
23
+ interface VaultPaths {
24
+ root: string;
25
+ raw: string;
26
+ rawSources: string;
27
+ wiki: string;
28
+ meta: string;
29
+ dotWiki: string;
30
+ outputs: string;
31
+ discoveries: string;
32
+ }
33
+
34
+ /** Detect vault format at a directory. */
35
+ function detectFormat(dir: string): "new" | "legacy" | "none" {
36
+ if (existsSync(join(dir, ".llm-wiki", "config.json"))) return "new";
37
+ if (existsSync(join(dir, ".wiki", "config.json"))) return "legacy";
38
+ return "none";
39
+ }
40
+
41
+ function resolveVaultRoot(cwd: string): string | null {
42
+ // Check cwd first
43
+ if (detectFormat(cwd) !== "none") return cwd;
44
+
45
+ // Walk up
46
+ const parts = cwd.split("/");
47
+ for (let i = parts.length - 1; i >= 0; i--) {
48
+ const dir = parts.slice(0, i + 1).join("/") || "/";
49
+ if (detectFormat(dir) !== "none") return dir;
50
+ }
51
+ return null;
52
+ }
53
+
54
+ function getPaths(): VaultPaths {
55
+ const detectedRoot = resolveVaultRoot(process.cwd());
56
+ const root = process.env.WIKI_ROOT || detectedRoot || process.cwd();
57
+ const format = process.env.WIKI_ROOT
58
+ ? detectFormat(root) // Use format detection even with explicit WIKI_ROOT
59
+ : detectedRoot
60
+ ? detectFormat(root)
61
+ : "none";
62
+
63
+ if (format === "legacy") {
64
+ return {
65
+ root,
66
+ raw: join(root, "raw"),
67
+ rawSources: join(root, "raw", "sources"),
68
+ wiki: join(root, "wiki"),
69
+ meta: join(root, "meta"),
70
+ dotWiki: join(root, ".wiki"),
71
+ outputs: join(root, "outputs"),
72
+ discoveries: join(root, ".discoveries"),
73
+ };
74
+ }
75
+
76
+ return {
77
+ root,
78
+ raw: join(root, ".llm-wiki", "raw"),
79
+ rawSources: join(root, ".llm-wiki", "raw", "sources"),
80
+ wiki: join(root, ".llm-wiki", "wiki"),
81
+ meta: join(root, ".llm-wiki", "meta"),
82
+ dotWiki: join(root, ".llm-wiki"),
83
+ outputs: join(root, ".llm-wiki", "outputs"),
84
+ discoveries: join(root, ".llm-wiki", ".discoveries"),
85
+ };
86
+ }
87
+
88
+ function hasVault(): boolean {
89
+ const paths = getPaths();
90
+ return existsSync(join(paths.dotWiki, "config.json"));
91
+ }
92
+
93
+ // ─── Helpers ────────────────────────────────────────────
94
+
95
+ function readJson<T>(path: string, defaultVal: T): T {
96
+ try {
97
+ if (!existsSync(path)) return defaultVal;
98
+ return JSON.parse(readFileSync(path, "utf-8")) as T;
99
+ } catch {
100
+ return defaultVal;
101
+ }
102
+ }
103
+
104
+ // ─── MCP Server ─────────────────────────────────────────
105
+
106
+ const server = new McpServer({
107
+ name: "llm-wiki",
108
+ version: "1.0.0",
109
+ });
110
+
111
+ // ---- wiki_recall ----
112
+
113
+ server.registerTool(
114
+ "wiki_recall",
115
+ {
116
+ description:
117
+ "Search the wiki for pages relevant to a query. Returns matching page IDs, titles, types, and content previews.",
118
+ inputSchema: z.object({
119
+ query: z.string().describe("Search query — use the user's full request or key terms"),
120
+ max_results: z.number().optional().default(5).describe("Max results (default: 5, max: 10)"),
121
+ }),
122
+ },
123
+ async ({ query, max_results }) => {
124
+ if (!hasVault()) {
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text" as const,
129
+ text: "No wiki vault found. Set WIKI_ROOT or run wiki_bootstrap first.",
130
+ },
131
+ ],
132
+ isError: true,
133
+ };
134
+ }
135
+
136
+ const paths = getPaths();
137
+ const registry = readJson<{
138
+ pages: Record<string, { type: string; title: string; [key: string]: unknown }>;
139
+ }>(join(paths.meta, "registry.json"), { pages: {} });
140
+
141
+ const terms = query
142
+ .toLowerCase()
143
+ .split(/\s+/)
144
+ .filter((t) => t.length > 2)
145
+ .slice(0, 10);
146
+
147
+ if (terms.length === 0) {
148
+ return {
149
+ content: [{ type: "text" as const, text: "Query too short." }],
150
+ };
151
+ }
152
+
153
+ type Scored = { id: string; score: number };
154
+ const scored: Scored[] = [];
155
+
156
+ for (const [id, entry] of Object.entries(registry.pages)) {
157
+ let score = 0;
158
+ const title = String(entry.title || "").toLowerCase();
159
+ const type = String(entry.type || "").toLowerCase();
160
+
161
+ for (const term of terms) {
162
+ if (id.toLowerCase().includes(term)) score += 3;
163
+ if (title.includes(term)) score += 4;
164
+ if (type.includes(term)) score += 1;
165
+ }
166
+
167
+ const tags = String(entry.tags || entry.category || entry.domain || "").toLowerCase();
168
+ for (const term of terms) {
169
+ if (tags.includes(term)) score += 2;
170
+ }
171
+
172
+ if (score > 0) scored.push({ id, score });
173
+ }
174
+
175
+ scored.sort((a, b) => b.score - a.score);
176
+ const top = scored.slice(0, Math.min(max_results ?? 5, 10));
177
+
178
+ const results = top.map(({ id }) => {
179
+ const entry = registry.pages[id];
180
+ let preview = "";
181
+ const pagePath = join(paths.wiki, `${id}.md`);
182
+ if (existsSync(pagePath)) {
183
+ const content = readFileSync(pagePath, "utf-8");
184
+ preview = content
185
+ .replace(/^---[\s\S]*?---\n/, "")
186
+ .trim()
187
+ .slice(0, 200)
188
+ .replace(/\n/g, " ");
189
+ }
190
+ return {
191
+ id,
192
+ title: String(entry?.title || id),
193
+ type: String(entry?.type || "page"),
194
+ preview,
195
+ };
196
+ });
197
+
198
+ return {
199
+ content: [
200
+ {
201
+ type: "text" as const,
202
+ text: JSON.stringify(results, null, 2),
203
+ },
204
+ ],
205
+ };
206
+ },
207
+ );
208
+
209
+ // ---- wiki_search ----
210
+
211
+ server.registerTool(
212
+ "wiki_search",
213
+ {
214
+ description: "Search the wiki registry for pages matching a query.",
215
+ inputSchema: z.object({
216
+ query: z.string().describe("Search term"),
217
+ type: z
218
+ .string()
219
+ .optional()
220
+ .describe("Filter by page type (source, entity, concept, synthesis, analysis)"),
221
+ }),
222
+ },
223
+ async ({ query, type }) => {
224
+ if (!hasVault()) {
225
+ return {
226
+ content: [
227
+ {
228
+ type: "text" as const,
229
+ text: "No wiki vault found. Set WIKI_ROOT or run wiki_bootstrap first.",
230
+ },
231
+ ],
232
+ isError: true,
233
+ };
234
+ }
235
+
236
+ const paths = getPaths();
237
+ const registry = readJson<{
238
+ pages: Record<string, { type: string; title: string; [key: string]: unknown }>;
239
+ }>(join(paths.meta, "registry.json"), { pages: {} });
240
+
241
+ const q = query.toLowerCase();
242
+ const matches = Object.entries(registry.pages)
243
+ .filter(([id, entry]) => {
244
+ const matchesQuery =
245
+ id.toLowerCase().includes(q) ||
246
+ String(entry.title).toLowerCase().includes(q) ||
247
+ String(entry.type).toLowerCase().includes(q);
248
+ const matchesType = !type || String(entry.type).toLowerCase() === type.toLowerCase();
249
+ return matchesQuery && matchesType;
250
+ })
251
+ .map(([id, entry]) => ({
252
+ id,
253
+ title: entry.title,
254
+ type: entry.type,
255
+ }));
256
+
257
+ return {
258
+ content: [
259
+ {
260
+ type: "text" as const,
261
+ text:
262
+ matches.length > 0 ? JSON.stringify(matches, null, 2) : `No pages found for "${query}"`,
263
+ },
264
+ ],
265
+ };
266
+ },
267
+ );
268
+
269
+ // ---- wiki_status ----
270
+
271
+ server.registerTool(
272
+ "wiki_status",
273
+ {
274
+ description: "Show wiki health and stats: page counts, orphans, recent activity.",
275
+ inputSchema: z.object({}),
276
+ },
277
+ async () => {
278
+ if (!hasVault()) {
279
+ return {
280
+ content: [
281
+ {
282
+ type: "text" as const,
283
+ text: "No wiki vault found. Set WIKI_ROOT or run wiki_bootstrap first.",
284
+ },
285
+ ],
286
+ isError: true,
287
+ };
288
+ }
289
+
290
+ const paths = getPaths();
291
+ const registry = readJson<{
292
+ version: string;
293
+ last_updated: string;
294
+ pages: Record<string, { type: string; title: string; [key: string]: unknown }>;
295
+ }>(join(paths.meta, "registry.json"), {
296
+ version: "1.0",
297
+ last_updated: "",
298
+ pages: {},
299
+ });
300
+
301
+ const config = readJson<Record<string, unknown>>(join(paths.dotWiki, "config.json"), {});
302
+
303
+ const byType: Record<string, number> = {};
304
+ for (const entry of Object.values(registry.pages)) {
305
+ byType[entry.type] = (byType[entry.type] || 0) + 1;
306
+ }
307
+
308
+ return {
309
+ content: [
310
+ {
311
+ type: "text" as const,
312
+ text: JSON.stringify(
313
+ {
314
+ topic: config.topic || "Unknown",
315
+ mode: config.mode || "personal",
316
+ totalPages: Object.keys(registry.pages).length,
317
+ byType,
318
+ lastUpdated: registry.last_updated || "Never",
319
+ },
320
+ null,
321
+ 2,
322
+ ),
323
+ },
324
+ ],
325
+ };
326
+ },
327
+ );
328
+
329
+ // ---- wiki_retro ----
330
+
331
+ server.registerTool(
332
+ "wiki_retro",
333
+ {
334
+ description:
335
+ "Save an atomic insight from a completed task into the wiki. Creates a source packet and source page.",
336
+ inputSchema: z.object({
337
+ slug: z.string().describe("Unique kebab-case identifier (e.g. 'jwt-revocation-pattern')"),
338
+ title: z.string().describe("Short descriptive title (60 chars max)"),
339
+ body: z
340
+ .string()
341
+ .describe(
342
+ "Markdown body explaining what was learned. Include [[wikilinks]] to related pages.",
343
+ ),
344
+ category: z
345
+ .string()
346
+ .optional()
347
+ .describe("Category (e.g. frontend, architecture, devops, bugfix)"),
348
+ }),
349
+ },
350
+ async ({ slug, title, body, category }) => {
351
+ if (!hasVault()) {
352
+ return {
353
+ content: [
354
+ {
355
+ type: "text" as const,
356
+ text: "No wiki vault found. Set WIKI_ROOT or run wiki_bootstrap first.",
357
+ },
358
+ ],
359
+ isError: true,
360
+ };
361
+ }
362
+
363
+ const { saveInsight } = (await import("../extensions/llm-wiki/lib/retro.js")) as {
364
+ saveInsight: (
365
+ paths: Record<string, string>,
366
+ slug: string,
367
+ title: string,
368
+ body: string,
369
+ category?: string,
370
+ ) => { sourceId: string; packetPath: string; sourcePagePath: string };
371
+ };
372
+
373
+ const vaultPaths = getPaths();
374
+ const result = saveInsight(vaultPaths, slug, title, body, category);
375
+
376
+ return {
377
+ content: [
378
+ {
379
+ type: "text" as const,
380
+ text: `Insight saved: ${result.sourceId} — ${title}`,
381
+ },
382
+ ],
383
+ };
384
+ },
385
+ );
386
+
387
+ // ---- wiki_capture_source ----
388
+
389
+ server.registerTool(
390
+ "wiki_capture_source",
391
+ {
392
+ description: "Capture a URL, local file, or pasted text into an immutable source packet.",
393
+ inputSchema: z.object({
394
+ text: z.string().optional().describe("Text content to capture"),
395
+ url: z.string().optional().describe("URL to capture"),
396
+ file_path: z.string().optional().describe("Local file path to capture"),
397
+ title: z.string().optional().describe("Title for the captured source"),
398
+ }),
399
+ },
400
+ async ({ text, url: urlParam, file_path, title }) => {
401
+ if (!hasVault()) {
402
+ return {
403
+ content: [
404
+ {
405
+ type: "text" as const,
406
+ text: "No wiki vault found. Set WIKI_ROOT or run wiki_bootstrap first.",
407
+ },
408
+ ],
409
+ isError: true,
410
+ };
411
+ }
412
+
413
+ const vaultPaths = getPaths();
414
+ let result: { sourceId: string };
415
+
416
+ if (urlParam) {
417
+ const { captureUrl } = (await import("../extensions/llm-wiki/lib/source-packet.js")) as {
418
+ captureUrl: (
419
+ pi: never,
420
+ paths: Record<string, string>,
421
+ url: string,
422
+ signal?: AbortSignal,
423
+ ) => Promise<{ sourceId: string }>;
424
+ };
425
+ result = await captureUrl(
426
+ { exec: async () => ({ stdout: "", stderr: "", code: 0 }) } as never,
427
+ vaultPaths,
428
+ urlParam,
429
+ );
430
+ } else if (file_path) {
431
+ const { captureFile } = (await import("../extensions/llm-wiki/lib/source-packet.js")) as {
432
+ captureFile: (
433
+ pi: never,
434
+ paths: Record<string, string>,
435
+ filePath: string,
436
+ signal?: AbortSignal,
437
+ ) => Promise<{ sourceId: string }>;
438
+ };
439
+ result = await captureFile(
440
+ { exec: async () => ({ stdout: "", stderr: "", code: 0 }) } as never,
441
+ vaultPaths,
442
+ file_path,
443
+ );
444
+ } else if (text) {
445
+ const { captureText } = (await import("../extensions/llm-wiki/lib/source-packet.js")) as {
446
+ captureText: (
447
+ paths: Record<string, string>,
448
+ text: string,
449
+ title?: string,
450
+ ) => { sourceId: string };
451
+ };
452
+ result = captureText(vaultPaths, text, title);
453
+ } else {
454
+ return {
455
+ content: [
456
+ {
457
+ type: "text" as const,
458
+ text: "Provide one of: text, url, or file_path",
459
+ },
460
+ ],
461
+ isError: true,
462
+ };
463
+ }
464
+
465
+ return {
466
+ content: [
467
+ {
468
+ type: "text" as const,
469
+ text: `Source captured: ${result.sourceId}`,
470
+ },
471
+ ],
472
+ };
473
+ },
474
+ );
475
+
476
+ // ─── Main ───────────────────────────────────────────────
477
+
478
+ async function main() {
479
+ const transport = new StdioServerTransport();
480
+ await server.connect(transport);
481
+ console.error("🧠 LLM Wiki MCP Server running on stdio");
482
+ }
483
+
484
+ main().catch((err) => {
485
+ console.error("MCP Server error:", err);
486
+ process.exit(1);
487
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zosmaai/pi-llm-wiki",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "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.",
5
5
  "keywords": [
6
6
  "pi",
@@ -37,6 +37,7 @@
37
37
  "extensions",
38
38
  "skills",
39
39
  "prompts",
40
+ "mcp",
40
41
  "docs",
41
42
  "assets",
42
43
  "README.md",
@@ -62,7 +63,10 @@
62
63
  "extensions": ["./extensions"],
63
64
  "skills": ["./skills"],
64
65
  "prompts": ["./prompts"],
65
- "image": "https://raw.githubusercontent.com/zosmaai/pi-llm-wiki/main/assets/screenshot.png"
66
+ "image": "https://raw.githubusercontent.com/zosmaai/pi-llm-wiki/main/assets/screenshot.png",
67
+ "mcpservers": {
68
+ "llm-wiki": "node ./mcp/index.js"
69
+ }
66
70
  },
67
71
  "peerDependencies": {
68
72
  "@mariozechner/pi-coding-agent": "*",
@@ -71,6 +75,9 @@
71
75
  "engines": {
72
76
  "node": ">=18"
73
77
  },
78
+ "dependencies": {
79
+ "@modelcontextprotocol/server": "^2.0.0-alpha.2"
80
+ },
74
81
  "devDependencies": {
75
82
  "@biomejs/biome": "^1.9.4",
76
83
  "@mariozechner/pi-coding-agent": "^0.70.2",
@@ -17,17 +17,17 @@ Read the LLM Wiki skill at `.pi/skills/llm-wiki/SKILL.md` first. Also read `conf
17
17
 
18
18
  ## Steps
19
19
 
20
- 1. Read `config.yaml` → extract topics, keywords, feeds
21
- 2. Read `.discoveries/gaps.json` → knowledge gaps to fill
22
- 3. Read `.discoveries/history.json` → already-fetched URLs
20
+ 1. Read `.llm-wiki/config.yaml` → extract topics, keywords, feeds
21
+ 2. Read `.llm-wiki/.discoveries/gaps.json` → knowledge gaps to fill
22
+ 3. Read `.llm-wiki/.discoveries/history.json` → already-fetched URLs
23
23
  4. Search for new sources:
24
24
  - Web search each topic + latest keywords
25
- - Search for gaps from `.discoveries/gaps.json`
25
+ - Search for gaps from `.llm-wiki/.discoveries/gaps.json`
26
26
  - If `--topic` specified, focus search on that topic
27
27
  5. For each promising result:
28
28
  a. Fetch full content
29
- b. Save to `raw/articles/YYYY-MM-DD-slug.md` with frontmatter (title, url, discovered, topic)
30
- 6. Update `.discoveries/history.json`
29
+ b. Save to `.llm-wiki/raw/articles/YYYY-MM-DD-slug.md` with frontmatter (title, url, discovered, topic)
30
+ 6. Update `.llm-wiki/.discoveries/history.json`
31
31
  7. Report: "Discovered [N] new sources. Run `/wiki-ingest` to process them."
32
32
 
33
33
  **Rules:** Max 5-10 sources. Skip ads, listicles, duplicates. Prefer in-depth analysis.
@@ -7,7 +7,7 @@ topLevelCli: true
7
7
 
8
8
  # /wiki-ingest
9
9
 
10
- Process new files in `raw/` and integrate them into the wiki.
10
+ Process new files in `.llm-wiki/raw/` and integrate them into the wiki.
11
11
 
12
12
  ## User Arguments
13
13
 
@@ -17,18 +17,18 @@ Read the LLM Wiki skill at `.pi/skills/llm-wiki/SKILL.md` first to understand th
17
17
 
18
18
  ## Steps
19
19
 
20
- 1. Read `config.yaml` and `.discoveries/history.json`
21
- 2. If a specific path is given (e.g., `/wiki-ingest raw/articles/my-file.md`), process just that file
22
- 3. If no path given, scan all files in `raw/` and find ones not in history
20
+ 1. Read `.llm-wiki/config.yaml` and `.llm-wiki/.discoveries/history.json`
21
+ 2. If a specific path is given (e.g., `/wiki-ingest .llm-wiki/raw/articles/my-file.md`), process just that file
22
+ 3. If no path given, scan all files in `.llm-wiki/raw/` and find ones not in history
23
23
  4. For each new source:
24
24
  a. Read the full content
25
25
  b. Briefly discuss with the user: "This is about [topic]. Key points: [summary]. Any specific emphasis?"
26
- c. Create/update pages in `wiki/sources/`, `wiki/entities/`, `wiki/concepts/`
26
+ c. Create/update pages in `.llm-wiki/wiki/sources/`, `.llm-wiki/wiki/entities/`, `.llm-wiki/wiki/concepts/`
27
27
  d. Add `[[wikilinks]]` cross-references between related pages
28
28
  e. Flag any contradictions with existing wiki content
29
- 5. Update `wiki/INDEX.md` with all new/updated pages
30
- 6. Append to `wiki/LOG.md`
31
- 7. Update `.discoveries/history.json`
29
+ 5. Update `.llm-wiki/wiki/INDEX.md` with all new/updated pages
30
+ 6. Append to `.llm-wiki/wiki/LOG.md`
31
+ 7. Update `.llm-wiki/.discoveries/history.json`
32
32
  8. Report: "Ingested [N] sources → [M] pages created/updated. [X] contradictions flagged."
33
33
 
34
34
  **Rules:** Never modify raw/ files. Never fabricate information. Always cite sources.
@@ -19,16 +19,16 @@ Read the LLM Wiki skill at `.pi/skills/llm-wiki/SKILL.md` (or wherever the skill
19
19
 
20
20
  1. Ask the user for the wiki topic and mode (`personal` or `company`)
21
21
  2. Create the directory structure:
22
- - `raw/articles/`, `raw/papers/`, `raw/notes/`, `raw/assets/`
23
- - `wiki/entities/`, `wiki/concepts/`, `wiki/sources/`, `wiki/syntheses/`, `wiki/changes/`
24
- - `outputs/`
25
- - `.discoveries/`
26
- 3. Create `config.yaml` with the topic, mode, and default settings
27
- 4. Create `wiki/INDEX.md` with section headings organized by page type
28
- 5. Create `wiki/LOG.md` with initial entry
29
- 6. Create `wiki/DASHBOARD.md` with Dataview queries for Obsidian
30
- 7. Create `.gitignore` to exclude `outputs/` from version control if desired
22
+ - `.llm-wiki/raw/articles/`, `.llm-wiki/raw/papers/`, `.llm-wiki/raw/notes/`, `.llm-wiki/raw/assets/`
23
+ - `.llm-wiki/wiki/entities/`, `.llm-wiki/wiki/concepts/`, `.llm-wiki/wiki/sources/`, `.llm-wiki/wiki/syntheses/`, `.llm-wiki/wiki/changes/`
24
+ - `.llm-wiki/outputs/`
25
+ - `.llm-wiki/.discoveries/`
26
+ 3. Create `.llm-wiki/config.yaml` with the topic, mode, and default settings
27
+ 4. Create `.llm-wiki/wiki/INDEX.md` with section headings organized by page type
28
+ 5. Create `.llm-wiki/wiki/LOG.md` with initial entry
29
+ 6. Create `.llm-wiki/wiki/DASHBOARD.md` with Dataview queries for Obsidian
30
+ 7. Create `.gitignore` to exclude `.llm-wiki/outputs/` from version control if desired
31
31
  8. Initialize git repo if not already present
32
- 9. Report the structure and suggest first steps: "Drop sources into `raw/` and run `/wiki-ingest`"
32
+ 9. Report the structure and suggest first steps: "Drop sources into `.llm-wiki/raw/` and run `/wiki-ingest`"
33
33
 
34
- If `--mode company`, add the `change_detection: true` flag to config.yaml and add a `wiki/decisions/` folder.
34
+ If `--mode company`, add the `change_detection: true` flag to config.yaml and add a `.llm-wiki/wiki/decisions/` folder.
@@ -17,17 +17,17 @@ Read the LLM Wiki skill at `.pi/skills/llm-wiki/SKILL.md` first to understand th
17
17
 
18
18
  ## Steps
19
19
 
20
- 1. Scan all files in `wiki/`
20
+ 1. Scan all files in `.llm-wiki/wiki/`
21
21
  2. Check for:
22
22
  - **Contradictions:** Conflicting claims between pages
23
23
  - **Orphans:** Pages with zero inbound `[[wikilinks]]`
24
24
  - **Missing pages:** `[[links]]` pointing to non-existent files
25
25
  - **Stale claims:** Info superseded by newer sources
26
- - **Broken raw links:** References to `raw/` files that don't exist
26
+ - **Broken raw links:** References to `.llm-wiki/raw/` files that don't exist
27
27
  - **Knowledge gaps:** Topics mentioned but lacking their own page
28
28
  - **Quality:** Pages under 3 lines, pages with no sources or cross-refs
29
29
  3. If `--fix` flag is present: auto-fix broken links, create missing pages for frequently-linked concepts, add cross-refs to orphans. Flag contradictions for human decision.
30
- 4. Save report → `outputs/lint-YYYY-MM-DD.md`
31
- 5. Update `.discoveries/gaps.json`
32
- 6. Append to `wiki/LOG.md`
30
+ 4. Save report → `.llm-wiki/outputs/lint-YYYY-MM-DD.md`
31
+ 5. Update `.llm-wiki/.discoveries/gaps.json`
32
+ 6. Append to `.llm-wiki/wiki/LOG.md`
33
33
  7. Report key findings
@@ -11,11 +11,11 @@ Show a quick overview of wiki health and statistics.
11
11
 
12
12
  ## Steps
13
13
 
14
- 1. Count sources in `raw/` (recursive)
15
- 2. Count pages in `wiki/` (by type: entities, concepts, sources, syntheses)
16
- 3. Check `wiki/LOG.md` for last ingest, lint, and discover dates
14
+ 1. Count sources in `.llm-wiki/raw/` (recursive)
15
+ 2. Count pages in `.llm-wiki/wiki/` (by type: entities, concepts, sources, syntheses)
16
+ 3. Check `.llm-wiki/wiki/LOG.md` for last ingest, lint, and discover dates
17
17
  4. Check for orphan pages (zero inbound links)
18
- 5. Read `.discoveries/gaps.json` for known gaps
18
+ 5. Read `.llm-wiki/.discoveries/gaps.json` for known gaps
19
19
  6. Report:
20
20
 
21
21
  ```