@zosmaai/pi-llm-wiki 0.6.0 → 0.6.2
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 +27 -0
- package/README.md +89 -52
- package/docs/architecture.md +30 -26
- package/docs/commands.md +1 -1
- package/docs/configuration.md +1 -1
- package/docs/obsidian.md +5 -5
- package/extensions/llm-wiki/index.ts +3 -4
- package/extensions/llm-wiki/lib/guardrails.ts +8 -18
- package/extensions/llm-wiki/lib/recall.ts +3 -4
- package/extensions/llm-wiki/lib/retro.ts +3 -10
- package/extensions/llm-wiki/lib/tools.ts +11 -10
- package/extensions/llm-wiki/lib/utils.ts +48 -8
- package/mcp/index.ts +49 -25
- package/package.json +1 -1
- package/prompts/wiki-discover.md +6 -6
- package/prompts/wiki-ingest.md +8 -8
- package/prompts/wiki-init.md +11 -11
- package/prompts/wiki-lint.md +5 -5
- package/prompts/wiki-status.md +4 -4
- package/skills/llm-wiki/SKILL.md +22 -20
- package/skills/llm-wiki/templates/pages/source.md +2 -2
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
│
|
|
161
|
-
│
|
|
162
|
-
│
|
|
163
|
-
├─
|
|
164
|
-
│
|
|
165
|
-
│
|
|
166
|
-
|
|
167
|
-
│ ├─
|
|
168
|
-
│
|
|
169
|
-
├─
|
|
170
|
-
│ ├─
|
|
171
|
-
│
|
|
172
|
-
|
|
173
|
-
│ ├─
|
|
174
|
-
│ ├─
|
|
175
|
-
│
|
|
176
|
-
├─ .
|
|
177
|
-
│ ├─
|
|
178
|
-
│ └─
|
|
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
|
-
|
|
|
187
|
-
|
|
188
|
-
|
|
|
189
|
-
|
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
|
|
|
193
|
-
|
|
|
194
|
-
|
|
|
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
|
-
-
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
-
|
|
226
|
-
-
|
|
227
|
-
-
|
|
228
|
-
-
|
|
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
|
|
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/
|
|
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.
|
package/docs/architecture.md
CHANGED
|
@@ -4,43 +4,47 @@
|
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
WIKI_ROOT/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
│
|
|
12
|
-
├──
|
|
13
|
-
│ ├──
|
|
14
|
-
│
|
|
15
|
-
|
|
16
|
-
│ ├──
|
|
17
|
-
│
|
|
18
|
-
├──
|
|
19
|
-
│ ├──
|
|
20
|
-
│
|
|
21
|
-
|
|
22
|
-
│ ├──
|
|
23
|
-
│
|
|
24
|
-
|
|
25
|
-
├──
|
|
26
|
-
└──
|
|
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
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
| `.wiki
|
|
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
|
|
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
|
|
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
|
package/docs/configuration.md
CHANGED
package/docs/obsidian.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
## Setup
|
|
4
4
|
|
|
5
|
-
1. Open
|
|
6
|
-
2. The extension generates
|
|
7
|
-
3.
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
62
|
-
if (!existsSync(join(
|
|
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,
|
|
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
|
|
19
|
-
const check = isProtectedPath(path,
|
|
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
|
|
28
|
-
const check = isProtectedPath(path,
|
|
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
|
|
40
|
-
const wikiPath = `${
|
|
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
|
|
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,
|
|
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
|
|
152
|
-
const paths = getVaultPaths(root);
|
|
151
|
+
const paths = resolveVaultPaths(process.cwd());
|
|
153
152
|
|
|
154
|
-
if (!existsSync(join(
|
|
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
|
|
162
|
-
const paths = getVaultPaths(root);
|
|
155
|
+
const paths = resolveVaultPaths(process.cwd());
|
|
163
156
|
|
|
164
|
-
if (!existsSync(join(
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
"| .
|
|
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.
|
|
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
|
-
//
|
|
23
|
-
if (
|
|
37
|
+
// Check for any vault format at cwd
|
|
38
|
+
if (detectVaultFormat(cwd) !== "none") return cwd;
|
|
24
39
|
|
|
25
|
-
// Walk up looking for
|
|
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
|
-
|
|
242
|
+
paths: VaultPaths,
|
|
203
243
|
): { protected: boolean; reason?: string } {
|
|
204
|
-
const rawPath = resolve(
|
|
205
|
-
const metaPath = resolve(
|
|
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
|
-
|
|
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 (
|
|
49
|
+
if (detectFormat(dir) !== "none") return dir;
|
|
36
50
|
}
|
|
37
51
|
return null;
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
function getPaths(): VaultPaths {
|
|
41
|
-
const
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
3
|
+
"version": "0.6.2",
|
|
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",
|
package/prompts/wiki-discover.md
CHANGED
|
@@ -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
|
|
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
|
|
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.
|
package/prompts/wiki-ingest.md
CHANGED
|
@@ -7,7 +7,7 @@ topLevelCli: true
|
|
|
7
7
|
|
|
8
8
|
# /wiki-ingest
|
|
9
9
|
|
|
10
|
-
Process new files in
|
|
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
|
|
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
|
|
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/` (respecting `.gitignore` — skip any matched files) 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
|
|
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
|
|
30
|
-
6. Append to
|
|
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.
|
package/prompts/wiki-init.md
CHANGED
|
@@ -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
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
- `.discoveries/`
|
|
26
|
-
3. Create
|
|
27
|
-
4. Create
|
|
28
|
-
5. Create
|
|
29
|
-
6. Create
|
|
30
|
-
7. Create `.gitignore` to exclude
|
|
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
|
|
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
|
|
34
|
+
If `--mode company`, add the `change_detection: true` flag to config.yaml and add a `.llm-wiki/wiki/decisions/` folder.
|
package/prompts/wiki-lint.md
CHANGED
|
@@ -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
|
|
20
|
+
1. Scan all files in `.llm-wiki/wiki/` (respecting `.gitignore` — skip any matched files)
|
|
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
|
|
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 →
|
|
31
|
-
5. Update `.discoveries/gaps.json`
|
|
32
|
-
6. Append to
|
|
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
|
package/prompts/wiki-status.md
CHANGED
|
@@ -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
|
|
15
|
-
2. Count pages in
|
|
16
|
-
3. Check
|
|
14
|
+
1. Count sources in `.llm-wiki/raw/` (recursive, respecting `.gitignore`)
|
|
15
|
+
2. Count pages in `.llm-wiki/wiki/` (by type: entities, concepts, sources, syntheses, respecting `.gitignore`)
|
|
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
|
```
|
package/skills/llm-wiki/SKILL.md
CHANGED
|
@@ -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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
│
|
|
19
|
-
├──
|
|
20
|
-
│ ├──
|
|
21
|
-
│
|
|
22
|
-
|
|
23
|
-
│ ├──
|
|
24
|
-
│
|
|
25
|
-
├──
|
|
26
|
-
│ ├──
|
|
27
|
-
│
|
|
28
|
-
|
|
29
|
-
│ ├──
|
|
30
|
-
│
|
|
31
|
-
|
|
32
|
-
├──
|
|
33
|
-
└──
|
|
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](
|
|
45
|
+
- [.llm-wiki/raw/articles/filename.md](../.llm-wiki/raw/articles/filename.md)
|