@zosmaai/pi-llm-wiki 0.6.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/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.7.0] - 2026-05-13
6
+
7
+ ### Added
8
+ - **Wiki vault restructured under `.llm-wiki/`** (Issue #22, PR #23 by @arjun-zosma): All wiki content now lives in a single `.llm-wiki/` subdirectory — cleaner repo isolation, easier gitignore, zero directory name collisions.
9
+ - **Backward compatibility**: Old vaults (`.wiki/config.json` sentinel) are auto-detected and continue to work. New vaults use `.llm-wiki/config.json`.
10
+ - **`detectVaultFormat()`** utility: Returns `"new"`, `"legacy"`, or `"none"` for any directory.
11
+ - **`resolveVaultPaths()`** utility: Auto-detects vault format and returns correct paths.
12
+ - **`getLegacyVaultPaths()`** utility: Returns old-style paths for migration support.
13
+ - **Migration script** (`scripts/migrate-llm-wiki.js`): One-time tool to move old vaults to new layout. Supports `--dry-run` and `--force` flags.
14
+ - **5 new backward-compatibility tests**: Verify new format detection, legacy format detection, auto-resolution, and no-vault handling.
15
+
16
+ ### Changed
17
+ - `resolveVaultRoot()` now checks for `.llm-wiki/config.json` first, then falls back to `.wiki/config.json`.
18
+ - `getVaultPaths()` returns paths under `.llm-wiki/`:
19
+ - `raw/` → `.llm-wiki/raw/`, `wiki/` → `.llm-wiki/wiki/`, `meta/` → `.llm-wiki/meta/`
20
+ - `.wiki/` → `.llm-wiki/` (config directly in the dot-dir)
21
+ - `outputs/` → `.llm-wiki/outputs/`, `.discoveries/` → `.llm-wiki/.discoveries/`
22
+ - `isProtectedPath()` now takes `VaultPaths` instead of `root` string.
23
+ - `wiki_bootstrap` creates new `.llm-wiki/` layout by default.
24
+ - MCP server updated with own copy of path detection logic.
25
+ - All templates, prompts, documentation, and tests updated to reflect new layout.
26
+
27
+ ### Migration
28
+ - Run `node scripts/migrate-llm-wiki.js` in your wiki root to migrate from the old layout.
29
+ - Old `.wiki/` directory is preserved as a forwarding marker (`.wiki/MIGRATED_TO_LLM_WIKI.md`).
30
+ - No data loss — all content is moved, nothing deleted.
31
+
5
32
  ## [0.6.0] - 2026-05-11
6
33
 
7
34
  ### Added
package/README.md CHANGED
@@ -53,6 +53,9 @@ The result is a wiki that **compounds** as you capture sources, ask questions, a
53
53
  | 🩺 **Mechanical linting** | Orphans, broken links, duplicate aliases, coverage gaps, stale captures |
54
54
  | 📊 **Dashboard** | `wiki_status` — counts, source states, recent activity |
55
55
  | 🤖 **Auto-update watch** | `wiki_watch` — schedule periodic discovery + ingest |
56
+ | 🧠 **Auto-recall** | Wiki searched automatically before every turn — relevant pages injected into context |
57
+ | 💾 **Auto-capture** | `wiki_retro` — save atomic insights from completed tasks with one call |
58
+ | 🌐 **MCP Server** | Use with Claude Code, Cursor, Windsurf via stdio MCP transport |
56
59
  | 📝 **Obsidian-friendly** | Folder-qualified wikilinks, stable source-ID citations, compatible vault |
57
60
  | 🛡️ **Guardrails** | Blocks direct edits to raw sources and generated metadata |
58
61
  | 🔧 **Configurable PDF extraction** | MarkItDown timeout via `WIKI_MARKITDOWN_TIMEOUT_MS` env var |
@@ -66,6 +69,8 @@ The result is a wiki that **compounds** as you capture sources, ask questions, a
66
69
  |------|-------------|
67
70
  | `wiki_bootstrap` | Initialize a new wiki vault with config, templates, schema, and metadata |
68
71
  | `wiki_capture_source` | Capture a URL, local file, or pasted text into an immutable source packet |
72
+ | `wiki_recall` | 🔄 **Auto-called at turn start** — search wiki for task-relevant pages |
73
+ | `wiki_retro` | Save atomic insights from completed tasks into the wiki |
69
74
  | `wiki_ingest` | Process uningested source packets into wiki pages (batch) |
70
75
  | `wiki_ensure_page` | Resolve or safely create entity / concept / synthesis / analysis pages |
71
76
  | `wiki_search` | Search the generated wiki registry |
@@ -104,11 +109,13 @@ Initialize an llm wiki here for AI research.
104
109
  This calls `wiki_bootstrap` and creates:
105
110
 
106
111
  ```
107
- raw/
108
- wiki/
109
- meta/
110
- .wiki/
111
- WIKI_SCHEMA.md
112
+ .llm-wiki/
113
+ ├── config.json
114
+ ├── templates/
115
+ ├── raw/
116
+ ├── wiki/
117
+ ├── meta/
118
+ └── WIKI_SCHEMA.md
112
119
  ```
113
120
 
114
121
  ### 2) Capture a source
@@ -128,7 +135,7 @@ Capture these notes into the wiki: ...pasted text...
128
135
  ### 3) Integrate the source
129
136
 
130
137
  1. Capture the source
131
- 2. Read `wiki/sources/SRC-*.md`
138
+ 2. Read `.llm-wiki/wiki/sources/SRC-*.md`
132
139
  3. Update that source page
133
140
  4. Search for impacted canonical pages with `wiki_search`
134
141
  5. Create missing pages with `wiki_ensure_page`
@@ -153,45 +160,47 @@ Answer the question and file the result as an analysis page.
153
160
 
154
161
  ```
155
162
  my-wiki/
156
- ├─ raw/
157
- │ └─ sources/
158
- │ └─ SRC-2026-05-11-001/
159
- ├─ manifest.json
160
- ├─ original/ # Original artifact
161
- ├─ extracted.md # Normalized text
162
- └─ attachments/
163
- ├─ wiki/
164
- ├─ sources/ # Source pages (what each source says)
165
- ├─ concepts/ # Concepts and recurring ideas
166
- ├─ entities/ # People, orgs, products, papers, systems
167
- │ ├─ syntheses/ # Cross-source theses and tensions
168
- └─ analyses/ # Durable filed answers from queries
169
- ├─ meta/
170
- │ ├─ registry.json # Auto-generated search index
171
- ├─ backlinks.json
172
- ├─ index.md
173
- │ ├─ events.jsonl # Append-only event log
174
- │ ├─ log.md
175
- └─ lint-report.md
176
- ├─ .wiki/
177
- │ ├─ config.json
178
- │ └─ templates/
179
- └─ WIKI_SCHEMA.md
163
+ └─ .llm-wiki/
164
+ ├─ config.json # Vault config
165
+ ├─ templates/ # Page templates
166
+ ├─ raw/
167
+ └─ sources/
168
+ └─ SRC-2026-05-11-001/
169
+ ├─ manifest.json
170
+ ├─ original/ # Original artifact
171
+ ├─ extracted.md # Normalized text
172
+ └─ attachments/
173
+ ├─ wiki/
174
+ │ ├─ sources/ # Source pages (what each source says)
175
+ ├─ concepts/ # Concepts and recurring ideas
176
+ ├─ entities/ # People, orgs, products, papers, systems
177
+ │ ├─ syntheses/ # Cross-source theses and tensions
178
+ └─ analyses/ # Durable filed answers from queries
179
+ ├─ meta/
180
+ │ ├─ registry.json # Auto-generated search index
181
+ │ ├─ backlinks.json
182
+ ├─ index.md
183
+ ├─ events.jsonl # Append-only event log
184
+ │ ├─ log.md
185
+ │ └─ lint-report.md
186
+ └─ WIKI_SCHEMA.md # Operating manual
180
187
  ```
181
188
 
182
189
  ### Ownership Model
183
190
 
184
191
  | Path | Owner | Rule |
185
192
  |------|-------|------|
186
- | `raw/**` | Extension tools | Immutable after capture |
187
- | `wiki/**` | Model + user | Editable knowledge pages |
188
- | `meta/registry.json` | Extension | Generated |
189
- | `meta/backlinks.json` | Extension | Generated |
190
- | `meta/index.md` | Extension | Generated |
191
- | `meta/events.jsonl` | Extension / tool | Append-only |
192
- | `meta/log.md` | Extension | Generated from events |
193
- | `meta/lint-report.md` | Extension | Generated |
194
- | `WIKI_SCHEMA.md` | Human + explicit request | Operating manual |
193
+ | Path | Owner | Rule |
194
+ |------|-------|------|
195
+ | `.llm-wiki/raw/**` | Extension tools | Immutable after capture |
196
+ | `.llm-wiki/wiki/**` | Model + user | Editable knowledge pages |
197
+ | `.llm-wiki/meta/registry.json` | Extension | Generated |
198
+ | `.llm-wiki/meta/backlinks.json` | Extension | Generated |
199
+ | `.llm-wiki/meta/index.md` | Extension | Generated |
200
+ | `.llm-wiki/meta/events.jsonl` | Extension / tool | Append-only |
201
+ | `.llm-wiki/meta/log.md` | Extension | Generated from events |
202
+ | `.llm-wiki/meta/lint-report.md` | Extension | Generated |
203
+ | `.llm-wiki/WIKI_SCHEMA.md` | Human + explicit request | Operating manual |
195
204
 
196
205
  ---
197
206
 
@@ -219,15 +228,15 @@ Stable source-page IDs keep provenance stable even if titles change.
219
228
 
220
229
  The extension **blocks** direct tool-call edits to:
221
230
 
222
- - `raw/**` — immutable source artifacts
223
- - `meta/registry.json`
224
- - `meta/backlinks.json`
225
- - `meta/events.jsonl`
226
- - `meta/index.md`
227
- - `meta/log.md`
228
- - `meta/lint-report.md`
231
+ - `.llm-wiki/raw/**` — immutable source artifacts
232
+ - `.llm-wiki/meta/registry.json`
233
+ - `.llm-wiki/meta/backlinks.json`
234
+ - `.llm-wiki/meta/events.jsonl`
235
+ - `.llm-wiki/meta/index.md`
236
+ - `.llm-wiki/meta/log.md`
237
+ - `.llm-wiki/meta/lint-report.md`
229
238
 
230
- If the model directly edits `wiki/**` using Pi's built-in `write` or `edit` tools, the extension **automatically rebuilds** generated metadata at the end of the agent turn.
239
+ If the model directly edits `.llm-wiki/wiki/**` using Pi's built-in `write` or `edit` tools, the extension **automatically rebuilds** generated metadata at the end of the agent turn.
231
240
 
232
241
  ---
233
242
 
@@ -236,7 +245,7 @@ If the model directly edits `wiki/**` using Pi's built-in `write` or `edit` tool
236
245
  Each captured source is stored as a structured packet:
237
246
 
238
247
  ```
239
- raw/sources/SRC-YYYY-MM-DD-NNN/
248
+ .llm-wiki/raw/sources/SRC-YYYY-MM-DD-NNN/
240
249
  ├─ manifest.json # Capture metadata (title, URL, format, timestamp)
241
250
  ├─ original/ # Original artifact (preserved as-is)
242
251
  ├─ extracted.md # Normalized text (PDF→md, XML→md, JSON→md, etc.)
@@ -247,6 +256,34 @@ This preserves both the **original artifact** and a **normalized extracted view*
247
256
 
248
257
  ---
249
258
 
259
+ ## MCP Server
260
+
261
+ Use the wiki from **any MCP-compatible tool** — Claude Code, Cursor, Windsurf, and others.
262
+
263
+ The package ships a standalone MCP server exposing 5 wiki tools over stdio:
264
+
265
+ | Tool | Description |
266
+ |------|-------------|
267
+ | `wiki_recall` | Search wiki for task-relevant pages |
268
+ | `wiki_search` | Full registry search |
269
+ | `wiki_status` | Wiki stats (page counts, type breakdown) |
270
+ | `wiki_retro` | Save atomic insights |
271
+ | `wiki_capture_source` | Capture text as a source packet |
272
+
273
+ ### Usage
274
+
275
+ ```bash
276
+ # Auto-discovered by pi:
277
+ pi install npm:@zosmaai/pi-llm-wiki
278
+
279
+ # Standalone with any MCP client:
280
+ WIKI_ROOT=~/my-wiki node node_modules/@zosmaai/pi-llm-wiki/mcp/index.js
281
+ ```
282
+
283
+ Set `WIKI_ROOT` to your wiki vault directory. If unset, the server auto-detects from the current working directory.
284
+
285
+ ---
286
+
250
287
  ## Skill Behavior
251
288
 
252
289
  The bundled `llm-wiki` skill teaches the model to:
@@ -266,10 +303,10 @@ The bundled `llm-wiki` skill teaches the model to:
266
303
  Four layers with clear ownership:
267
304
 
268
305
  ```
269
- raw/sources/SRC-*/ # Immutable source packets (extension-owned)
270
- wiki/ # Editable knowledge pages (you + LLM)
271
- meta/ # Auto-generated registry, backlinks, index, log
272
- .wiki/ # Config and templates
306
+ .llm-wiki/raw/sources/SRC-*/ # Immutable source packets (extension-owned)
307
+ .llm-wiki/wiki/ # Editable knowledge pages (you + LLM)
308
+ .llm-wiki/meta/ # Auto-generated registry, backlinks, index, log
309
+ .llm-wiki/ # Config and templates
273
310
  ```
274
311
 
275
312
  Read [docs/architecture.md](docs/architecture.md) for the full design document.
@@ -4,43 +4,47 @@
4
4
 
5
5
  ```
6
6
  WIKI_ROOT/
7
- ├── raw/sources/SRC-*/ # Immutable source packets (extension-owned)
8
- ├── manifest.json # Capture metadata
9
- ├── original/ # Original artifact
10
- ├── extracted.md # Normalized markdown
11
- └── attachments/ # Downloaded images, PDFs
12
- ├── wiki/ # Editable knowledge pages (you + LLM)
13
- │ ├── sources/ # One summary per source
14
- ├── entities/ # People, orgs, tools, products
15
- ├── concepts/ # Ideas, patterns, frameworks
16
- │ ├── syntheses/ # Cross-cutting analyses
17
- └── analyses/ # Durable query answers
18
- ├── meta/ # Auto-generated (extension-owned)
19
- │ ├── registry.json # Master page catalog
20
- ├── backlinks.json # Inbound link map
21
- ├── index.md # Human-readable catalog
22
- │ ├── log.md # Activity log
23
- └── events.jsonl # Structured event stream
24
- └── .wiki/ # Config and templates
25
- ├── config.json
26
- └── templates/
7
+ └── .llm-wiki/ # All wiki content under one dot-dir
8
+ ├── config.json # Vault config
9
+ ├── templates/ # Page templates
10
+ ├── raw/sources/SRC-*/ # Immutable source packets (extension-owned)
11
+ ├── manifest.json # Capture metadata
12
+ ├── original/ # Original artifact
13
+ │ ├── extracted.md # Normalized markdown
14
+ └── attachments/ # Downloaded images, PDFs
15
+ ├── wiki/ # Editable knowledge pages (you + LLM)
16
+ │ ├── sources/ # One summary per source
17
+ ├── entities/ # People, orgs, tools, products
18
+ ├── concepts/ # Ideas, patterns, frameworks
19
+ │ ├── syntheses/ # Cross-cutting analyses
20
+ └── analyses/ # Durable query answers
21
+ ├── meta/ # Auto-generated (extension-owned)
22
+ │ ├── registry.json # Master page catalog
23
+ ├── backlinks.json # Inbound link map
24
+ │ ├── index.md # Human-readable catalog
25
+ ├── log.md # Activity log
26
+ └── events.jsonl # Structured event stream
27
+ ├── outputs/ # Generated artifacts
28
+ └── .discoveries/ # Discovery tracking
27
29
  ```
28
30
 
29
31
  ## Ownership Rules
30
32
 
31
33
  | Path | Owner | Rule |
32
34
  | --------- | ------------------------ | ------------------------ |
33
- | `raw/**` | Extension | Immutable after capture |
34
- | `wiki/**` | Model + user | Editable knowledge pages |
35
- | `meta/*` | Extension | Auto-generated |
36
- | `.wiki/*` | Human + explicit request | Operating rules |
35
+ | Path | Owner | Rule |
36
+ | --------------------- | ------------------------ | ------------------------ |
37
+ | `.llm-wiki/raw/**` | Extension | Immutable after capture |
38
+ | `.llm-wiki/wiki/**` | Model + user | Editable knowledge pages |
39
+ | `.llm-wiki/meta/**` | Extension | Auto-generated |
40
+ | `.llm-wiki/` | Human + explicit request | Operating rules |
37
41
 
38
42
  ## Source Packet Format
39
43
 
40
44
  Each captured source becomes a packet:
41
45
 
42
46
  ```
43
- raw/sources/SRC-YYYY-MM-DD-NNN/
47
+ .llm-wiki/raw/sources/SRC-YYYY-MM-DD-NNN/
44
48
  manifest.json
45
49
  original/
46
50
  extracted.md
@@ -62,4 +66,4 @@ raw/sources/SRC-YYYY-MM-DD-NNN/
62
66
 
63
67
  ## Guardrails
64
68
 
65
- The extension blocks direct edits to `raw/**` and `meta/**`. Metadata rebuilds automatically after `wiki/**` edits.
69
+ The extension blocks direct edits to `.llm-wiki/raw/**` and `.llm-wiki/meta/**`. Metadata rebuilds automatically after `.llm-wiki/wiki/**` edits.
package/docs/commands.md CHANGED
@@ -36,7 +36,7 @@ The extension registers 10 tools the LLM can call directly:
36
36
 
37
37
  1. `wiki_capture_source(url="...")` — creates packet + skeleton
38
38
  2. `wiki_ingest()` — get batch of sources needing synthesis
39
- 3. Read `raw/sources/SRC-*/extracted.md`
39
+ 3. Read `.llm-wiki/raw/sources/SRC-*/extracted.md`
40
40
  4. Update skeleton source page with summary, entities, concepts
41
41
  5. `wiki_ensure_page(type="entity", title="...")` for each entity
42
42
  6. Add `[[wikilinks]]` between related pages
@@ -1,6 +1,6 @@
1
1
  # Configuration
2
2
 
3
- Wiki configuration lives in `.wiki/config.json`.
3
+ Wiki configuration lives in `.llm-wiki/config.json`.
4
4
 
5
5
  ## Modes
6
6
 
package/docs/obsidian.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Setup
4
4
 
5
- 1. Open `wiki/` as an Obsidian vault
6
- 2. The extension generates `meta/index.md` as a browsable catalog
7
- 3. `meta/backlinks.json` is available for graph plugins
5
+ 1. Open `.llm-wiki/wiki/` as an Obsidian vault
6
+ 2. The extension generates `.llm-wiki/meta/index.md` as a browsable catalog
7
+ 3. `.llm-wiki/meta/backlinks.json` is available for graph plugins
8
8
 
9
9
  ## Recommended Plugins
10
10
 
@@ -14,8 +14,8 @@
14
14
 
15
15
  ## Web Clipper
16
16
 
17
- Use [Obsidian Web Clipper](https://obsidian.md/clipper) to save articles directly into `raw/articles/`.
17
+ Use [Obsidian Web Clipper](https://obsidian.md/clipper) to save articles directly into `.llm-wiki/raw/articles/`.
18
18
 
19
19
  ## Dataview Dashboard
20
20
 
21
- The extension creates `meta/index.md` with page listings. For custom dashboards, use Dataview queries against frontmatter fields like `type`, `domain`, `category`, `sources`.
21
+ The extension creates `.llm-wiki/meta/index.md` with page listings. For custom dashboards, use Dataview queries against frontmatter fields like `type`, `domain`, `category`, `sources`.
@@ -16,7 +16,7 @@ import {
16
16
  registerWikiStatus,
17
17
  registerWikiWatch,
18
18
  } from "./lib/tools.js";
19
- import { getVaultPaths, resolveVaultRoot } from "./lib/utils.js";
19
+ import { resolveVaultPaths } from "./lib/utils.js";
20
20
 
21
21
  /**
22
22
  * @zosmaai/pi-llm-wiki — LLM Wiki extension for Pi
@@ -58,12 +58,11 @@ export default function (pi: ExtensionAPI) {
58
58
  // Before each agent turn, search the wiki for pages relevant
59
59
  // to the user's prompt and inject them as system context.
60
60
  pi.on("before_agent_start", async (event, _ctx) => {
61
- const root = resolveVaultRoot(process.cwd());
62
- if (!existsSync(join(root, ".wiki", "config.json"))) {
61
+ const paths = resolveVaultPaths(process.cwd());
62
+ if (!existsSync(join(paths.dotWiki, "config.json"))) {
63
63
  return; // No wiki vault — nothing to recall
64
64
  }
65
65
 
66
- const paths = getVaultPaths(root);
67
66
  const prompt = event.prompt || "";
68
67
  if (!prompt.trim()) return;
69
68
 
@@ -1,7 +1,7 @@
1
1
  import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
2
2
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
3
3
  import { rebuildMetadataLight } from "./metadata.js";
4
- import { isProtectedPath, resolveVaultRoot } from "./utils.js";
4
+ import { isProtectedPath, resolveVaultPaths } from "./utils.js";
5
5
 
6
6
  /**
7
7
  * Guardrails and auto-rebuild hooks for the LLM Wiki extension.
@@ -15,8 +15,8 @@ export function installGuardrails(pi: ExtensionAPI): void {
15
15
  pi.on("tool_call", async (event) => {
16
16
  if (isToolCallEventType("write", event)) {
17
17
  const path = event.input.path as string;
18
- const root = resolveVaultRoot(process.cwd());
19
- const check = isProtectedPath(path, root);
18
+ const paths = resolveVaultPaths(process.cwd());
19
+ const check = isProtectedPath(path, paths);
20
20
  if (check.protected) {
21
21
  return { block: true, reason: check.reason };
22
22
  }
@@ -24,8 +24,8 @@ export function installGuardrails(pi: ExtensionAPI): void {
24
24
 
25
25
  if (isToolCallEventType("edit", event)) {
26
26
  const path = event.input.path as string;
27
- const root = resolveVaultRoot(process.cwd());
28
- const check = isProtectedPath(path, root);
27
+ const paths = resolveVaultPaths(process.cwd());
28
+ const check = isProtectedPath(path, paths);
29
29
  if (check.protected) {
30
30
  return { block: true, reason: check.reason };
31
31
  }
@@ -36,8 +36,8 @@ export function installGuardrails(pi: ExtensionAPI): void {
36
36
  pi.on("tool_result", async (event) => {
37
37
  if (event.toolName === "write" || event.toolName === "edit") {
38
38
  const path = event.input.path as string;
39
- const root = resolveVaultRoot(process.cwd());
40
- const wikiPath = `${root}/wiki/`;
39
+ const paths = resolveVaultPaths(process.cwd());
40
+ const wikiPath = `${paths.wiki}/`;
41
41
  if (path?.startsWith(wikiPath)) {
42
42
  pendingRebuild = true;
43
43
  }
@@ -49,17 +49,7 @@ export function installGuardrails(pi: ExtensionAPI): void {
49
49
  if (pendingRebuild) {
50
50
  pendingRebuild = false;
51
51
  try {
52
- const root = resolveVaultRoot(process.cwd());
53
- const paths = {
54
- root,
55
- raw: `${root}/raw`,
56
- rawSources: `${root}/raw/sources`,
57
- wiki: `${root}/wiki`,
58
- meta: `${root}/meta`,
59
- dotWiki: `${root}/.wiki`,
60
- outputs: `${root}/outputs`,
61
- discoveries: `${root}/.discoveries`,
62
- };
52
+ const paths = resolveVaultPaths(process.cwd());
63
53
  rebuildMetadataLight(paths);
64
54
  } catch {
65
55
  // Silently fail — metadata rebuild is best-effort
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
4
4
  import { Type } from "typebox";
5
5
  import type { Registry } from "./metadata.js";
6
- import { type VaultPaths, getVaultPaths, readJson, readText, resolveVaultRoot } from "./utils.js";
6
+ import { type VaultPaths, readJson, resolveVaultPaths } from "./utils.js";
7
7
 
8
8
  // ─── Public API ────────────────────────────────────────
9
9
 
@@ -148,10 +148,9 @@ export function registerWikiRecall(pi: ExtensionAPI): void {
148
148
  ),
149
149
  }),
150
150
  async execute(_toolCallId, params) {
151
- const root = resolveVaultRoot(process.cwd());
152
- const paths = getVaultPaths(root);
151
+ const paths = resolveVaultPaths(process.cwd());
153
152
 
154
- if (!existsSync(join(root, ".wiki", "config.json"))) {
153
+ if (!existsSync(join(paths.dotWiki, "config.json"))) {
155
154
  return {
156
155
  content: [
157
156
  {
@@ -3,13 +3,7 @@ import { join } from "node:path";
3
3
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
4
4
  import { Type } from "typebox";
5
5
  import { appendEvent, rebuildMetadataLight } from "./metadata.js";
6
- import {
7
- type VaultPaths,
8
- fmtDate,
9
- getVaultPaths,
10
- nextSourceId,
11
- resolveVaultRoot,
12
- } from "./utils.js";
6
+ import { type VaultPaths, fmtDate, nextSourceId, resolveVaultPaths } from "./utils.js";
13
7
 
14
8
  // ─── Public API ────────────────────────────────────────
15
9
 
@@ -158,10 +152,9 @@ export function registerWikiRetro(pi: ExtensionAPI): void {
158
152
  ),
159
153
  }),
160
154
  async execute(_toolCallId, params) {
161
- const root = resolveVaultRoot(process.cwd());
162
- const paths = getVaultPaths(root);
155
+ const paths = resolveVaultPaths(process.cwd());
163
156
 
164
- if (!existsSync(join(root, ".wiki", "config.json"))) {
157
+ if (!existsSync(join(paths.dotWiki, "config.json"))) {
165
158
  return {
166
159
  content: [
167
160
  {
@@ -13,13 +13,14 @@ import {
13
13
  import { captureFile, captureText, captureUrl } from "./source-packet.js";
14
14
  import {
15
15
  type VaultPaths,
16
+ detectVaultFormat,
16
17
  ensureVaultStructure,
17
18
  extractWikilinks,
18
19
  findWikiPages,
19
20
  fmtDate,
20
21
  getVaultPaths,
21
22
  readJson,
22
- resolveVaultRoot,
23
+ resolveVaultPaths,
23
24
  writeJson,
24
25
  } from "./utils.js";
25
26
 
@@ -28,12 +29,11 @@ import {
28
29
  */
29
30
 
30
31
  function getPaths(cwd = process.cwd()): VaultPaths {
31
- const root = resolveVaultRoot(cwd);
32
- return getVaultPaths(root);
32
+ return resolveVaultPaths(cwd);
33
33
  }
34
34
 
35
35
  function requireVault(paths: VaultPaths): { ok: true } | { ok: false; reason: string } {
36
- if (!existsSync(join(paths.root, ".wiki", "config.json"))) {
36
+ if (detectVaultFormat(paths.root) === "none") {
37
37
  return { ok: false, reason: `No wiki found at ${paths.root}. Run wiki_bootstrap first.` };
38
38
  }
39
39
  return { ok: true };
@@ -83,7 +83,7 @@ export function registerWikiBootstrap(pi: ExtensionAPI): void {
83
83
  "| raw/** | extension | immutable after capture |",
84
84
  "| wiki/** | model + user | editable knowledge pages |",
85
85
  "| meta/* | extension | auto-generated |",
86
- "| .wiki/* | human + explicit request | operating rules |",
86
+ "| . | human + explicit request | operating rules |",
87
87
  "",
88
88
  "## Source Packet Format",
89
89
  "",
@@ -109,7 +109,7 @@ export function registerWikiBootstrap(pi: ExtensionAPI): void {
109
109
  "- Citation: [[sources/SRC-YYYY-MM-DD-NNN]]",
110
110
  "",
111
111
  ].join("\n");
112
- writeFileSync(join(paths.root, "WIKI_SCHEMA.md"), schema, "utf-8");
112
+ writeFileSync(join(paths.dotWiki, "WIKI_SCHEMA.md"), schema, "utf-8");
113
113
 
114
114
  rebuildMetadata(paths);
115
115
  appendEvent(paths, { kind: "bootstrap", topic: params.topic, mode });
@@ -122,10 +122,11 @@ export function registerWikiBootstrap(pi: ExtensionAPI): void {
122
122
  `✅ Wiki bootstrapped at \`${paths.root}\``,
123
123
  "",
124
124
  "**Structure:**",
125
- "- raw/sources/ — immutable source packets",
126
- "- wiki/ — editable knowledge pages",
127
- "- meta/ — auto-generated metadata",
128
- "- .wiki/ — config and templates",
125
+ "- .llm-wiki/raw/sources/ — immutable source packets",
126
+ "- .llm-wiki/wiki/ — editable knowledge pages",
127
+ "- .llm-wiki/meta/ — auto-generated metadata",
128
+ "- .llm-wiki/ — config and templates",
129
+ "- .llm-wiki/WIKI_SCHEMA.md — operating rules",
129
130
  "",
130
131
  "Next: Use wiki_capture_source to add your first source.",
131
132
  ].join("\n"),
@@ -17,24 +17,53 @@ export interface VaultPaths {
17
17
  discoveries: string;
18
18
  }
19
19
 
20
+ /** Detect whether a vault root uses new (.llm-wiki) or legacy (.wiki) layout. */
21
+ export type VaultFormat = "new" | "legacy" | "none";
22
+
23
+ /**
24
+ * Detect the vault format at a given directory.
25
+ * Returns "new" if .llm-wiki/config.json exists,
26
+ * "legacy" if .wiki/config.json exists,
27
+ * "none" otherwise.
28
+ */
29
+ export function detectVaultFormat(dir: string): VaultFormat {
30
+ if (existsSync(join(dir, ".llm-wiki", "config.json"))) return "new";
31
+ if (existsSync(join(dir, ".wiki", "config.json"))) return "legacy";
32
+ return "none";
33
+ }
34
+
20
35
  /** Resolve vault root from cwd or find nearest wiki root. */
21
36
  export function resolveVaultRoot(cwd: string): string {
22
- // If cwd has .wiki/config.json, it's the root
23
- if (existsSync(join(cwd, ".wiki", "config.json"))) return cwd;
37
+ // Check for any vault format at cwd
38
+ if (detectVaultFormat(cwd) !== "none") return cwd;
24
39
 
25
- // Walk up looking for .wiki/config.json
40
+ // Walk up looking for a vault sentinel (new or legacy)
26
41
  let dir = cwd;
27
42
  while (dir !== dirname(dir)) {
28
- if (existsSync(join(dir, ".wiki", "config.json"))) return dir;
29
43
  dir = dirname(dir);
44
+ if (detectVaultFormat(dir) !== "none") return dir;
30
45
  }
31
46
 
32
47
  // Fallback: cwd itself
33
48
  return cwd;
34
49
  }
35
50
 
36
- /** Get all vault paths. */
51
+ /** Get all vault paths for the new (.llm-wiki) layout. */
37
52
  export function getVaultPaths(root: string): VaultPaths {
53
+ return {
54
+ root,
55
+ raw: join(root, ".llm-wiki", "raw"),
56
+ rawSources: join(root, ".llm-wiki", "raw", "sources"),
57
+ wiki: join(root, ".llm-wiki", "wiki"),
58
+ meta: join(root, ".llm-wiki", "meta"),
59
+ dotWiki: join(root, ".llm-wiki"),
60
+ outputs: join(root, ".llm-wiki", "outputs"),
61
+ discoveries: join(root, ".llm-wiki", ".discoveries"),
62
+ };
63
+ }
64
+
65
+ /** Get all vault paths for the legacy (.wiki) layout. */
66
+ export function getLegacyVaultPaths(root: string): VaultPaths {
38
67
  return {
39
68
  root,
40
69
  raw: join(root, "raw"),
@@ -47,6 +76,17 @@ export function getVaultPaths(root: string): VaultPaths {
47
76
  };
48
77
  }
49
78
 
79
+ /**
80
+ * Resolve vault paths, auto-detecting new vs legacy layout.
81
+ * This is the main entry point: use this instead of resolveVaultRoot + getVaultPaths.
82
+ */
83
+ export function resolveVaultPaths(cwd: string): VaultPaths {
84
+ const root = resolveVaultRoot(cwd);
85
+ const format = detectVaultFormat(root);
86
+ if (format === "legacy") return getLegacyVaultPaths(root);
87
+ return getVaultPaths(root);
88
+ }
89
+
50
90
  /** Ensure all vault directories exist. */
51
91
  export function ensureVaultStructure(paths: VaultPaths): void {
52
92
  const dirs = [
@@ -199,10 +239,10 @@ export async function exec(
199
239
  /** Check if a path is inside a protected directory. */
200
240
  export function isProtectedPath(
201
241
  absPath: string,
202
- root: string,
242
+ paths: VaultPaths,
203
243
  ): { protected: boolean; reason?: string } {
204
- const rawPath = resolve(root, "raw");
205
- const metaPath = resolve(root, "meta");
244
+ const rawPath = resolve(paths.raw);
245
+ const metaPath = resolve(paths.meta);
206
246
  const norm = resolve(absPath);
207
247
 
208
248
  if (norm.startsWith(`${rawPath}/`) || norm === rawPath) {
package/mcp/index.ts CHANGED
@@ -22,33 +22,72 @@ import * as z from "zod/v4";
22
22
 
23
23
  interface VaultPaths {
24
24
  root: string;
25
+ raw: string;
25
26
  rawSources: string;
26
27
  wiki: string;
27
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";
28
39
  }
29
40
 
30
41
  function resolveVaultRoot(cwd: string): string | null {
31
- if (existsSync(join(cwd, ".wiki", "config.json"))) return cwd;
42
+ // Check cwd first
43
+ if (detectFormat(cwd) !== "none") return cwd;
44
+
45
+ // Walk up
32
46
  const parts = cwd.split("/");
33
47
  for (let i = parts.length - 1; i >= 0; i--) {
34
48
  const dir = parts.slice(0, i + 1).join("/") || "/";
35
- if (existsSync(join(dir, ".wiki", "config.json"))) return dir;
49
+ if (detectFormat(dir) !== "none") return dir;
36
50
  }
37
51
  return null;
38
52
  }
39
53
 
40
54
  function getPaths(): VaultPaths {
41
- const root = process.env.WIKI_ROOT || resolveVaultRoot(process.cwd()) || process.cwd();
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
+
42
76
  return {
43
77
  root,
44
- rawSources: join(root, "raw", "sources"),
45
- wiki: join(root, "wiki"),
46
- meta: join(root, "meta"),
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"),
47
85
  };
48
86
  }
49
87
 
50
88
  function hasVault(): boolean {
51
- return existsSync(join(getPaths().root, ".wiki", "config.json"));
89
+ const paths = getPaths();
90
+ return existsSync(join(paths.dotWiki, "config.json"));
52
91
  }
53
92
 
54
93
  // ─── Helpers ────────────────────────────────────────────
@@ -259,7 +298,7 @@ server.registerTool(
259
298
  pages: {},
260
299
  });
261
300
 
262
- const config = readJson<Record<string, unknown>>(join(paths.root, ".wiki", "config.json"), {});
301
+ const config = readJson<Record<string, unknown>>(join(paths.dotWiki, "config.json"), {});
263
302
 
264
303
  const byType: Record<string, number> = {};
265
304
  for (const entry of Object.values(registry.pages)) {
@@ -331,14 +370,7 @@ server.registerTool(
331
370
  ) => { sourceId: string; packetPath: string; sourcePagePath: string };
332
371
  };
333
372
 
334
- const vaultPaths = {
335
- ...getPaths(),
336
- raw: join(getPaths().root, "raw"),
337
- dotWiki: join(getPaths().root, ".wiki"),
338
- outputs: join(getPaths().root, "outputs"),
339
- discoveries: join(getPaths().root, ".discoveries"),
340
- };
341
-
373
+ const vaultPaths = getPaths();
342
374
  const result = saveInsight(vaultPaths, slug, title, body, category);
343
375
 
344
376
  return {
@@ -378,18 +410,10 @@ server.registerTool(
378
410
  };
379
411
  }
380
412
 
381
- const vaultPaths = {
382
- ...getPaths(),
383
- raw: join(getPaths().root, "raw"),
384
- dotWiki: join(getPaths().root, ".wiki"),
385
- outputs: join(getPaths().root, "outputs"),
386
- discoveries: join(getPaths().root, ".discoveries"),
387
- };
388
-
413
+ const vaultPaths = getPaths();
389
414
  let result: { sourceId: string };
390
415
 
391
416
  if (urlParam) {
392
- // For MCP, use simple curl-based capture
393
417
  const { captureUrl } = (await import("../extensions/llm-wiki/lib/source-packet.js")) as {
394
418
  captureUrl: (
395
419
  pi: never,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zosmaai/pi-llm-wiki",
3
- "version": "0.6.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",
@@ -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
  ```
@@ -11,26 +11,28 @@ You are a disciplined wiki maintainer. The extension handles all mechanical work
11
11
 
12
12
  ```
13
13
  WIKI_ROOT/
14
- ├── raw/sources/SRC-*/ # Immutable source packets (extension-owned)
15
- ├── manifest.json
16
- ├── original/
17
- ├── extracted.md
18
- └── attachments/
19
- ├── wiki/ # Editable knowledge pages (you own this)
20
- │ ├── sources/ # One summary per source
21
- ├── entities/ # People, orgs, tools, products
22
- ├── concepts/ # Ideas, patterns, frameworks
23
- │ ├── syntheses/ # Cross-cutting analyses
24
- └── analyses/ # Durable query answers
25
- ├── meta/ # Auto-generated (extension-owned)
26
- │ ├── registry.json # Master page catalog
27
- ├── backlinks.json # Inbound link map
28
- ├── index.md # Human-readable catalog
29
- │ ├── log.md # Activity log
30
- └── events.jsonl # Structured event stream
31
- └── .wiki/ # Config and templates
32
- ├── config.json
33
- └── templates/
14
+ └── .llm-wiki/ # All wiki content (one dot-dir)
15
+ ├── config.json # Vault config
16
+ ├── templates/ # Page templates
17
+ ├── raw/sources/SRC-*/ # Immutable source packets (extension-owned)
18
+ ├── manifest.json
19
+ ├── original/
20
+ │ ├── extracted.md
21
+ └── attachments/
22
+ ├── wiki/ # Editable knowledge pages (you own this)
23
+ │ ├── sources/ # One summary per source
24
+ ├── entities/ # People, orgs, tools, products
25
+ ├── concepts/ # Ideas, patterns, frameworks
26
+ │ ├── syntheses/ # Cross-cutting analyses
27
+ └── analyses/ # Durable query answers
28
+ ├── meta/ # Auto-generated (extension-owned)
29
+ │ ├── registry.json # Master page catalog
30
+ ├── backlinks.json # Inbound link map
31
+ │ ├── index.md # Human-readable catalog
32
+ ├── log.md # Activity log
33
+ └── events.jsonl # Structured event stream
34
+ ├── outputs/ # Generated artifacts
35
+ └── .discoveries/ # Discovery tracking
34
36
  ```
35
37
 
36
38
  ## Golden Rules
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  type: source
3
3
  format: article # article | paper | note | video | podcast | slack | email
4
- raw_path: raw/articles/filename.md
4
+ raw_path: .llm-wiki/raw/articles/filename.md
5
5
  ingested: YYYY-MM-DD
6
6
  topics:
7
7
  - topic-name
@@ -42,4 +42,4 @@ topics:
42
42
 
43
43
  ## Source
44
44
 
45
- - [raw/articles/filename.md](../raw/articles/filename.md)
45
+ - [.llm-wiki/raw/articles/filename.md](../.llm-wiki/raw/articles/filename.md)