pi-para 0.5.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.
Files changed (198) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/README.md +305 -0
  3. package/SETUP.md +171 -0
  4. package/dist/capture.d.ts +34 -0
  5. package/dist/capture.d.ts.map +1 -0
  6. package/dist/capture.js +461 -0
  7. package/dist/capture.js.map +1 -0
  8. package/dist/cli.d.ts +15 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +405 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands.d.ts +15 -0
  13. package/dist/commands.d.ts.map +1 -0
  14. package/dist/commands.js +786 -0
  15. package/dist/commands.js.map +1 -0
  16. package/dist/context.d.ts +61 -0
  17. package/dist/context.d.ts.map +1 -0
  18. package/dist/context.js +289 -0
  19. package/dist/context.js.map +1 -0
  20. package/dist/daemon.d.ts +49 -0
  21. package/dist/daemon.d.ts.map +1 -0
  22. package/dist/daemon.js +226 -0
  23. package/dist/daemon.js.map +1 -0
  24. package/dist/frontmatter.d.ts +59 -0
  25. package/dist/frontmatter.d.ts.map +1 -0
  26. package/dist/frontmatter.js +170 -0
  27. package/dist/frontmatter.js.map +1 -0
  28. package/dist/gepa/dataset.d.ts +36 -0
  29. package/dist/gepa/dataset.d.ts.map +1 -0
  30. package/dist/gepa/dataset.js +148 -0
  31. package/dist/gepa/dataset.js.map +1 -0
  32. package/dist/gepa/evaluator.d.ts +51 -0
  33. package/dist/gepa/evaluator.d.ts.map +1 -0
  34. package/dist/gepa/evaluator.js +317 -0
  35. package/dist/gepa/evaluator.js.map +1 -0
  36. package/dist/gepa/index.d.ts +66 -0
  37. package/dist/gepa/index.d.ts.map +1 -0
  38. package/dist/gepa/index.js +240 -0
  39. package/dist/gepa/index.js.map +1 -0
  40. package/dist/gepa/llm.d.ts +35 -0
  41. package/dist/gepa/llm.d.ts.map +1 -0
  42. package/dist/gepa/llm.js +268 -0
  43. package/dist/gepa/llm.js.map +1 -0
  44. package/dist/gepa/optimized/capture-prompt.txt +65 -0
  45. package/dist/gepa/optimizer.d.ts +29 -0
  46. package/dist/gepa/optimizer.d.ts.map +1 -0
  47. package/dist/gepa/optimizer.js +249 -0
  48. package/dist/gepa/optimizer.js.map +1 -0
  49. package/dist/gepa/targets.d.ts +39 -0
  50. package/dist/gepa/targets.d.ts.map +1 -0
  51. package/dist/gepa/targets.js +326 -0
  52. package/dist/gepa/targets.js.map +1 -0
  53. package/dist/gepa/types.d.ts +168 -0
  54. package/dist/gepa/types.d.ts.map +1 -0
  55. package/dist/gepa/types.js +124 -0
  56. package/dist/gepa/types.js.map +1 -0
  57. package/dist/index.d.ts +21 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +294 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/ingest.d.ts +88 -0
  62. package/dist/ingest.d.ts.map +1 -0
  63. package/dist/ingest.js +105 -0
  64. package/dist/ingest.js.map +1 -0
  65. package/dist/link-discovery.d.ts +40 -0
  66. package/dist/link-discovery.d.ts.map +1 -0
  67. package/dist/link-discovery.js +122 -0
  68. package/dist/link-discovery.js.map +1 -0
  69. package/dist/link-utils.d.ts +30 -0
  70. package/dist/link-utils.d.ts.map +1 -0
  71. package/dist/link-utils.js +145 -0
  72. package/dist/link-utils.js.map +1 -0
  73. package/dist/lint.d.ts +39 -0
  74. package/dist/lint.d.ts.map +1 -0
  75. package/dist/lint.js +827 -0
  76. package/dist/lint.js.map +1 -0
  77. package/dist/maintainer.d.ts +24 -0
  78. package/dist/maintainer.d.ts.map +1 -0
  79. package/dist/maintainer.js +358 -0
  80. package/dist/maintainer.js.map +1 -0
  81. package/dist/processor.d.ts +14 -0
  82. package/dist/processor.d.ts.map +1 -0
  83. package/dist/processor.js +361 -0
  84. package/dist/processor.js.map +1 -0
  85. package/dist/query.d.ts +69 -0
  86. package/dist/query.d.ts.map +1 -0
  87. package/dist/query.js +107 -0
  88. package/dist/query.js.map +1 -0
  89. package/dist/raw.d.ts +57 -0
  90. package/dist/raw.d.ts.map +1 -0
  91. package/dist/raw.js +219 -0
  92. package/dist/raw.js.map +1 -0
  93. package/dist/redact.d.ts +21 -0
  94. package/dist/redact.d.ts.map +1 -0
  95. package/dist/redact.js +143 -0
  96. package/dist/redact.js.map +1 -0
  97. package/dist/scope.d.ts +54 -0
  98. package/dist/scope.d.ts.map +1 -0
  99. package/dist/scope.js +161 -0
  100. package/dist/scope.js.map +1 -0
  101. package/dist/scripts/bulk-link-fix.d.ts +9 -0
  102. package/dist/scripts/bulk-link-fix.d.ts.map +1 -0
  103. package/dist/scripts/bulk-link-fix.js +106 -0
  104. package/dist/scripts/bulk-link-fix.js.map +1 -0
  105. package/dist/session-tools.d.ts +33 -0
  106. package/dist/session-tools.d.ts.map +1 -0
  107. package/dist/session-tools.js +211 -0
  108. package/dist/session-tools.js.map +1 -0
  109. package/dist/state.d.ts +54 -0
  110. package/dist/state.d.ts.map +1 -0
  111. package/dist/state.js +176 -0
  112. package/dist/state.js.map +1 -0
  113. package/dist/store.d.ts +56 -0
  114. package/dist/store.d.ts.map +1 -0
  115. package/dist/store.js +227 -0
  116. package/dist/store.js.map +1 -0
  117. package/dist/summarize.d.ts +56 -0
  118. package/dist/summarize.d.ts.map +1 -0
  119. package/dist/summarize.js +231 -0
  120. package/dist/summarize.js.map +1 -0
  121. package/dist/tag-registry.d.ts +56 -0
  122. package/dist/tag-registry.d.ts.map +1 -0
  123. package/dist/tag-registry.js +146 -0
  124. package/dist/tag-registry.js.map +1 -0
  125. package/dist/templates/prompts.d.ts +63 -0
  126. package/dist/templates/prompts.d.ts.map +1 -0
  127. package/dist/templates/prompts.js +260 -0
  128. package/dist/templates/prompts.js.map +1 -0
  129. package/dist/tools.d.ts +26 -0
  130. package/dist/tools.d.ts.map +1 -0
  131. package/dist/tools.js +1033 -0
  132. package/dist/tools.js.map +1 -0
  133. package/dist/watcher.d.ts +25 -0
  134. package/dist/watcher.d.ts.map +1 -0
  135. package/dist/watcher.js +84 -0
  136. package/dist/watcher.js.map +1 -0
  137. package/dist/webui/client/dist/index.html +1885 -0
  138. package/dist/webui/server.d.ts +31 -0
  139. package/dist/webui/server.d.ts.map +1 -0
  140. package/dist/webui/server.js +566 -0
  141. package/dist/webui/server.js.map +1 -0
  142. package/dist/wiki.d.ts +103 -0
  143. package/dist/wiki.d.ts.map +1 -0
  144. package/dist/wiki.js +428 -0
  145. package/dist/wiki.js.map +1 -0
  146. package/package.json +142 -0
  147. package/scripts/gepa/__pycache__/dataset.cpython-313.pyc +0 -0
  148. package/scripts/gepa/__pycache__/lm_providers.cpython-313.pyc +0 -0
  149. package/scripts/gepa/__pycache__/metric.cpython-313.pyc +0 -0
  150. package/scripts/gepa/__pycache__/program.cpython-313.pyc +0 -0
  151. package/scripts/gepa/__pycache__/wiki_reader.cpython-313.pyc +0 -0
  152. package/scripts/gepa/dataset.py +192 -0
  153. package/scripts/gepa/lm_providers.py +472 -0
  154. package/scripts/gepa/metric.py +279 -0
  155. package/scripts/gepa/optimize.py +367 -0
  156. package/scripts/gepa/program.py +99 -0
  157. package/scripts/gepa/pyproject.toml +19 -0
  158. package/scripts/gepa/run-all.sh +53 -0
  159. package/scripts/gepa/uv.lock +2241 -0
  160. package/scripts/gepa/wiki_reader.py +113 -0
  161. package/skills/para/SKILL.md +77 -0
  162. package/skills/setup/SKILL.md +20 -0
  163. package/src/capture.ts +563 -0
  164. package/src/cli.ts +416 -0
  165. package/src/commands.ts +878 -0
  166. package/src/context.ts +390 -0
  167. package/src/daemon.ts +288 -0
  168. package/src/frontmatter.ts +219 -0
  169. package/src/gepa/index.ts +287 -0
  170. package/src/gepa/optimized/capture-prompt.txt +65 -0
  171. package/src/index.ts +384 -0
  172. package/src/ingest.ts +177 -0
  173. package/src/link-discovery.ts +170 -0
  174. package/src/link-utils.ts +169 -0
  175. package/src/lint.ts +1018 -0
  176. package/src/maintainer.ts +404 -0
  177. package/src/processor.ts +415 -0
  178. package/src/python/__pycache__/minimax_lm.cpython-312.pyc +0 -0
  179. package/src/python/minimax_lm.py +198 -0
  180. package/src/python/rlm_capture.py +215 -0
  181. package/src/query.ts +148 -0
  182. package/src/raw.ts +276 -0
  183. package/src/redact.ts +159 -0
  184. package/src/scope.ts +214 -0
  185. package/src/scripts/bulk-link-fix.ts +126 -0
  186. package/src/session-tools.ts +260 -0
  187. package/src/state.ts +271 -0
  188. package/src/store.ts +288 -0
  189. package/src/summarize.ts +273 -0
  190. package/src/tag-registry.ts +157 -0
  191. package/src/templates/index.md +17 -0
  192. package/src/templates/prompts.ts +274 -0
  193. package/src/templates/schema.md +116 -0
  194. package/src/tools.ts +1293 -0
  195. package/src/watcher.ts +101 -0
  196. package/src/webui/client/dist/index.html +1885 -0
  197. package/src/webui/server.ts +765 -0
  198. package/src/wiki.ts +550 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Canonical tag registry — normalizes and deduplicates wiki page tags.
3
+ *
4
+ * Rules:
5
+ * 1. Spaces → hyphens ("session files" → "session-files")
6
+ * 2. Lowercase everything
7
+ * 3. Map aliases → canonical tags
8
+ * 4. Remove tags that duplicate scope values on the same page
9
+ * 5. Deduplicate
10
+ */
11
+
12
+ // -- Scope normalization -----------------------------------------------------
13
+
14
+ /**
15
+ * Normalize a scope value.
16
+ *
17
+ * Scope should be a project name (kebab-case, single token), not a topic
18
+ * description. The daemon LLM sometimes writes freeform multi-word
19
+ * descriptions like "session exploration" or "mono project" as scope.
20
+ *
21
+ * Rules:
22
+ * 1. Trim + lowercase
23
+ * 2. If the value contains a known project name as a prefix, extract it
24
+ * (e.g. "pi-para daemon" → "pi-para", "pi-mono project" → "pi-mono")
25
+ * 3. If still multi-word after extraction, drop it — it's a topic
26
+ * description, not a project name
27
+ * 4. Return the clean kebab-case scope
28
+ *
29
+ * This is project-agnostic — works for any project, not just pi-para.
30
+ */
31
+ export function normalizeScope(scope: string): string | null {
32
+ const s = scope.trim().toLowerCase();
33
+ if (!s) return null;
34
+
35
+ // Already clean (no spaces) — pass through
36
+ if (!s.includes(" ")) return s;
37
+
38
+ // Try to extract a kebab-case project name prefix.
39
+ // Multi-word scopes from the LLM follow the pattern:
40
+ // "<project-name> <topic words>" e.g. "pi-mono project", "pi-para daemon"
41
+ // Extract the first kebab-case token if it looks like a project name.
42
+ const firstToken = s.split(" ")[0];
43
+ if (firstToken && firstToken.includes("-")) {
44
+ // Looks like a kebab-case project name (e.g. "pi-mono", "pi-para")
45
+ return firstToken;
46
+ }
47
+
48
+ // Multi-word without a kebab prefix → topic description, drop it
49
+ return null;
50
+ }
51
+
52
+ /**
53
+ * Normalize a full scope list:
54
+ * 1. Normalize each value
55
+ * 2. Deduplicate
56
+ * 3. Ensure at least one scope remains (fallback to "global")
57
+ */
58
+ export function normalizeScopes(scopes: string[]): string[] {
59
+ const result = new Set<string>();
60
+ for (const s of scopes) {
61
+ const normalized = normalizeScope(s);
62
+ if (normalized) result.add(normalized);
63
+ }
64
+ if (result.size === 0) result.add("global");
65
+ return [...result].sort();
66
+ }
67
+
68
+ // -- Tag normalization -------------------------------------------------------
69
+
70
+ /** Canonical tag → list of aliases that map to it. */
71
+ const TAG_ALIASES: Record<string, string[]> = {
72
+ // session/capture family
73
+ "session-capture": ["capture", "background-capture", "session"],
74
+ "session-files": ["session files"],
75
+
76
+ // project identity
77
+ "pi-para": ["para"],
78
+ "pi-mono": ["mono"],
79
+ "coding-agent": ["agent"],
80
+
81
+ // tech
82
+ "node-llama-cpp": [],
83
+ "qmd-search": ["bm25"],
84
+ "lazy-loading": [],
85
+
86
+ // kebab-case normalization
87
+ "scope-detection": ["scope detection"],
88
+ "project-structure": ["project structure", "structure"],
89
+ "model-registry": ["model registry"],
90
+ "thinking-level": ["thinking level"],
91
+ "interactive-mode": ["interactive mode"],
92
+ "exploration-incomplete": ["exploration incomplete"],
93
+ "ui-component": ["UI component"],
94
+ "scoped-models": ["scopedModels"],
95
+ "github-packages": [],
96
+ "architecture-pattern": [],
97
+ "knowledge-management": ["knowledge-base"],
98
+
99
+ // UI
100
+ "webui": ["ui", "frontend", "react"],
101
+ };
102
+
103
+ /** Build reverse lookup: alias → canonical. */
104
+ function buildAliasMap(): Map<string, string> {
105
+ const map = new Map<string, string>();
106
+ for (const [canonical, aliases] of Object.entries(TAG_ALIASES)) {
107
+ for (const alias of aliases) {
108
+ map.set(alias.toLowerCase(), canonical);
109
+ }
110
+ }
111
+ return map;
112
+ }
113
+
114
+ const ALIAS_MAP = buildAliasMap();
115
+
116
+ /**
117
+ * Normalize a single tag:
118
+ * 1. Trim + lowercase
119
+ * 2. Spaces → hyphens
120
+ * 3. Resolve alias → canonical
121
+ */
122
+ export function normalizeTag(tag: string): string {
123
+ let t = tag.trim().toLowerCase().replace(/\s+/g, "-");
124
+ const canonical = ALIAS_MAP.get(t);
125
+ if (canonical) t = canonical;
126
+ return t;
127
+ }
128
+
129
+ /**
130
+ * Normalize a full tag list for a page, given its scope.
131
+ *
132
+ * 1. Normalize each tag
133
+ * 2. Remove tags that exactly match a scope value
134
+ * 3. Deduplicate
135
+ * 4. Sort alphabetically
136
+ */
137
+ export function normalizeTags(tags: string[], scope: string[]): string[] {
138
+ const scopeSet = new Set(scope.map(s => s.toLowerCase()));
139
+ const normalized = new Set<string>();
140
+
141
+ for (const tag of tags) {
142
+ const t = normalizeTag(tag);
143
+ if (!t) continue;
144
+ // Don't add tags that duplicate scope
145
+ if (scopeSet.has(t)) continue;
146
+ normalized.add(t);
147
+ }
148
+
149
+ return [...normalized].sort();
150
+ }
151
+
152
+ /**
153
+ * Get the full alias map for external inspection (e.g., lint reporting).
154
+ */
155
+ export function getAliasMap(): ReadonlyMap<string, string> {
156
+ return ALIAS_MAP;
157
+ }
@@ -0,0 +1,17 @@
1
+ # Wiki Index
2
+
3
+ ## Projects
4
+
5
+ _No active projects yet._
6
+
7
+ ## Areas
8
+
9
+ _No areas defined yet._
10
+
11
+ ## Resources
12
+
13
+ _No resources yet._
14
+
15
+ ## Archives
16
+
17
+ _No archived items._
@@ -0,0 +1,274 @@
1
+ /**
2
+ * LLM prompt templates for ingest, query, lint, capture, and summarize operations.
3
+ *
4
+ * Use getPrompt(name) to load the GEPA-optimized version (if deployed) or the original.
5
+ */
6
+
7
+ import { readFileSync, existsSync } from "node:fs";
8
+ import { join, dirname } from "node:path";
9
+ import { homedir } from "node:os";
10
+
11
+ /**
12
+ * Load a prompt by name — returns the GEPA-optimized version if
13
+ * config.gepa.useOptimized is true, otherwise returns the original.
14
+ *
15
+ * Resolution order:
16
+ * 1. User-generated optimized prompt at ~/.pi/wiki/gepa/optimized/{name}.txt
17
+ * 2. Bundled optimized prompt shipped with the package (src/gepa/optimized/{name}.txt)
18
+ * 3. Original constant from this file
19
+ */
20
+ export function getPrompt(name: string): string {
21
+ const original = _originals()[name];
22
+ if (!original) return "";
23
+ try {
24
+ const cfgPath = join(homedir(), ".pi", "wiki", "config.json");
25
+ if (!existsSync(cfgPath)) return original;
26
+ const cfg = JSON.parse(readFileSync(cfgPath, "utf-8"));
27
+ if (!cfg.gepa?.useOptimized) return original;
28
+
29
+ // 1. Check user-generated optimized prompt
30
+ const userPath = join(homedir(), ".pi", "wiki", "gepa", "optimized", `${name}.txt`);
31
+ if (existsSync(userPath)) {
32
+ const content = readFileSync(userPath, "utf-8").trim();
33
+ if (content.length > 50) return content;
34
+ }
35
+
36
+ // 2. Check bundled optimized prompt (shipped with package)
37
+ const bundledPath = join(dirname(new URL(import.meta.url).pathname), "..", "gepa", "optimized", `${name}.txt`);
38
+ if (existsSync(bundledPath)) {
39
+ const content = readFileSync(bundledPath, "utf-8").trim();
40
+ if (content.length > 50) return content;
41
+ }
42
+ } catch { /* fall through to original */ }
43
+ return original;
44
+ }
45
+
46
+ function _originals(): Record<string, string> {
47
+ return {
48
+ "wiki-system-prompt": WIKI_SYSTEM_PROMPT,
49
+ "ingest-prompt": INGEST_PROMPT,
50
+ "query-prompt": QUERY_PROMPT,
51
+ "capture-system-prompt": CAPTURE_SYSTEM_PROMPT,
52
+ "capture-prompt": CAPTURE_PROMPT,
53
+ "explicit-capture-prompt": EXPLICIT_CAPTURE_PROMPT,
54
+ "summarize-system-prompt": SUMMARIZE_SYSTEM_PROMPT,
55
+ "iterative-update-prompt": ITERATIVE_UPDATE_PROMPT,
56
+ "overview-prompt": OVERVIEW_PROMPT,
57
+ "lint-prompt": LINT_PROMPT,
58
+ };
59
+ }
60
+
61
+ // -- Wiki System Prompt (standalone agent) ------------------------------------
62
+
63
+ /**
64
+ * System prompt for the standalone wiki agent used in capture, lint, and
65
+ * summarize operations. This agent runs outside the session's agent loop.
66
+ */
67
+ export const WIKI_SYSTEM_PROMPT = `You are a wiki knowledge management agent. You maintain a PARA-structured knowledge base.
68
+
69
+ Your job is to read content, extract knowledge, and write structured wiki pages. You operate autonomously — no user confirmation needed.
70
+
71
+ PARA category rules:
72
+ - **resources/**: Use for almost everything — architecture docs, how-tos, debugging solutions, configs, patterns, implementation notes. This is the default.
73
+ - **areas/**: Only for ongoing responsibilities with no end date (e.g. server config, deployment procedures).
74
+ - **projects/**: ONLY for actual goals with a defined end date and completion criteria. Do NOT use for documentation about a project's internals.
75
+ - **archives/**: Never create pages here — pages get moved here when completed.
76
+
77
+ When the user defines a specific goal with a completion condition, create a projects/ page. When identifying a repeating responsibility (monitoring, maintenance, quality), create an areas/ page.
78
+
79
+ Scope and tag rules:
80
+ - scope must be a kebab-case project name (e.g. "pi-para", "qmd"). NOT topic descriptions like "session exploration".
81
+ - tags must be kebab-case (no spaces). Don't duplicate scope values as tags.
82
+
83
+ Content rules:
84
+ - Use [[wikilinks]] to connect related pages. Always add a ## Connections section.
85
+ - Use the wiki summary format: Topic, Key Facts, Insights, Connections, Open Questions, Sources
86
+ - Keep pages focused on one concept each
87
+ - Be concise and factual — no fluff
88
+ - Check for existing similar pages before creating new ones to avoid duplicates
89
+ - NEVER include API keys, tokens, passwords, or secrets. Document WHERE they are stored, not the values.
90
+ - Index is auto-rebuilt after every write — do not manage index.md manually. Do NOT pass indexContent to wiki_write.`;
91
+
92
+ // -- Ingest Prompts ----------------------------------------------------------
93
+
94
+ /**
95
+ * Prompt included in the tool result when the LLM processes an ingested source.
96
+ * The LLM reads this along with the source content, schema, and current index.
97
+ */
98
+ export const INGEST_PROMPT = `Analyze the source content below and integrate it into the wiki.
99
+
100
+ Instructions:
101
+ 1. Identify key entities, concepts, facts, and relationships in the source
102
+ 2. Review the current index to find existing pages that should be updated
103
+ 3. Decide which existing wiki pages need updates and what new pages to create
104
+ 4. For each page, use the wiki summary format:
105
+ - Topic: what this page covers
106
+ - Key Facts: established knowledge points
107
+ - Insights: non-obvious findings, patterns, implications
108
+ - Connections: [[wikilinks]] to related pages with descriptions
109
+ - Open Questions: gaps in knowledge, unresolved contradictions
110
+ - Sources: source URLs, file paths, session references
111
+ 5. Assign PARA category correctly:
112
+ - resources/ for reference material (DEFAULT — use this for most pages)
113
+ - areas/ for ongoing responsibilities
114
+ - projects/ ONLY for actual goals with end dates
115
+ 6. scope must be a kebab-case project name (NOT topic descriptions). tags must be kebab-case (no spaces).
116
+ 7. Always add [[wikilinks]] and a ## Connections section linking related pages
117
+ 8. Flag any contradictions with existing wiki content in Open Questions
118
+ 9. When updating existing pages with new information, check whether existing Key Facts are still accurate in light of the new source. If the new source contradicts existing facts, update them and note the change in Open Questions.
119
+ 10. Do NOT pass indexContent to wiki_write — the index is auto-rebuilt from all pages on disk.`;
120
+
121
+ // -- Query Prompts -----------------------------------------------------------
122
+
123
+ /**
124
+ * Prompt sent when the LLM synthesizes an answer from wiki search results.
125
+ */
126
+ export const QUERY_PROMPT = `Read the retrieved wiki pages below and synthesize an answer to the user's question.
127
+
128
+ Instructions:
129
+ - Cite specific pages using [[page-slug]] references
130
+ - Note gaps or areas where the wiki lacks information
131
+ - If the synthesized answer reveals new knowledge not already captured in the wiki, file it as a new page via wiki_write
132
+ - Be concise and factual
133
+
134
+ FRESHNESS VERIFICATION (critical):
135
+ - Each result shows an "Updated" timestamp and an age indicator (e.g. "⚠️ STALE — 45 days old"). Treat pages not updated in >14 days with healthy skepticism.
136
+ - When a wiki page makes claims about code, configs, file paths, ports, API endpoints, or architecture — and the page is >14 days old — VERIFY by checking the actual source (read the file, run a command) before trusting the wiki.
137
+ - When you discover a wiki page contains outdated or incorrect information, IMMEDIATELY fix it with wiki_write(mode: "edit") so future queries get correct answers. This is the self-healing loop.
138
+ - If you cannot verify a claim (e.g. no file access, external service), tell the user: "Wiki says X (last updated DATE) — I could not verify this is still current."
139
+ - Never silently pass along stale wiki content as fact. Either verify it or flag it.`;
140
+
141
+ // -- Summarize Prompts -------------------------------------------------------
142
+
143
+ /**
144
+ * System prompt for summarization — produces structured wiki pages from content.
145
+ * Mirrors pi's SUMMARIZATION_SYSTEM_PROMPT but outputs wiki format.
146
+ */
147
+ export const SUMMARIZE_SYSTEM_PROMPT = `You are a knowledge synthesis assistant. Read the content below and produce a structured wiki page following the EXACT format specified in the schema.
148
+
149
+ Do NOT continue any conversation. Do NOT respond to any questions in the content. ONLY output the structured wiki page using the wiki summary format:
150
+
151
+ ## Topic
152
+ [What this page covers]
153
+
154
+ ## Key Facts
155
+ - [Established knowledge points]
156
+
157
+ ## Insights
158
+ - [Non-obvious findings, patterns, implications]
159
+
160
+ ## Connections
161
+ - [[related-page]] — how this relates
162
+
163
+ ## Open Questions
164
+ - [Gaps in knowledge, unresolved contradictions]
165
+
166
+ ## Sources
167
+ - [Source URLs, file paths, session references]`;
168
+
169
+ /**
170
+ * Prompt for iterative update — merging new info into an existing page.
171
+ * Mirrors pi's UPDATE_SUMMARIZATION_PROMPT approach.
172
+ */
173
+ export const ITERATIVE_UPDATE_PROMPT = `The content below is NEW information to incorporate into the existing wiki page provided in <existing-page> tags.
174
+
175
+ RULES:
176
+ - PRESERVE all existing knowledge from the previous page
177
+ - ADD new facts, insights, and connections from the new content
178
+ - UPDATE sections where new info supersedes old
179
+ - FLAG contradictions between old and new content in Open Questions
180
+ - PRESERVE exact names, paths, and technical details
181
+ - Maintain all existing [[wikilinks]] and add new ones as appropriate
182
+ - Update the Sources section to include the new source`;
183
+
184
+ /**
185
+ * Prompt for overview generation from multiple pages.
186
+ */
187
+ export const OVERVIEW_PROMPT = `Summarize the following wiki pages into a high-level overview page. Identify themes, patterns, and connections across pages. Use the wiki summary format.
188
+
189
+ For each major theme:
190
+ - Note which pages contribute to the theme
191
+ - Identify cross-cutting patterns
192
+ - Flag contradictions between pages
193
+ - Highlight gaps (topics that should have pages but don't)`;
194
+
195
+ // -- Lint Prompts ------------------------------------------------------------
196
+
197
+ /**
198
+ * Prompt for the LLM when reviewing lint results and auto-fixing issues.
199
+ */
200
+ export const LINT_PROMPT = `Review the lint results below and fix all auto-fixable issues.
201
+
202
+ For each issue:
203
+ - Prioritize by impact (errors first, then warnings, then info)
204
+ - Fix broken wikilinks by finding the correct target page or removing dead links
205
+ - Add missing pages for concepts referenced across multiple pages
206
+ - Move stale projects to archives if inactive for 90+ days
207
+ - Fix frontmatter issues (missing fields, invalid dates, empty scope)
208
+ - Update index.md to include any pages missing from the index
209
+ - Propose archiving for inactive projects
210
+
211
+ Report unfixable issues that require human judgment.`;
212
+
213
+ // -- Capture Prompts ---------------------------------------------------------
214
+
215
+ /**
216
+ * System prompt for the standalone capture agent.
217
+ * Used as WIKI_SYSTEM_PROMPT for the capture agent instance.
218
+ */
219
+ export const CAPTURE_SYSTEM_PROMPT = `You are a knowledge capture assistant. Your job is to extract persistent knowledge from coding sessions and write it to a PARA-structured wiki.
220
+
221
+ Capture ANY of the following — even from short sessions:
222
+ - Architecture decisions and rationale ("we chose X because Y")
223
+ - Debugging solutions (root cause + fix)
224
+ - Server/infrastructure details (IPs, paths, credentials locations, configs)
225
+ - Build and deployment procedures (commands, steps, gotchas)
226
+ - API keys, service endpoints, and where they are stored
227
+ - Project conventions and coding patterns
228
+ - Tool configurations and setup steps
229
+ - Dependencies and version constraints
230
+ - Environment-specific knowledge (dev vs prod differences)
231
+ - Operational runbooks (how to restart, deploy, rollback)
232
+
233
+ Index is auto-rebuilt after every write — do not manage index.md manually. Do NOT pass indexContent to wiki_write.
234
+
235
+ Rules:
236
+ - If the session was ONLY greetings or completely off-topic chitchat with zero project knowledge, respond with "nothing to capture"
237
+ - Otherwise, always capture — even small facts are valuable ("the deploy key is at /path/to/key")
238
+ - Classify each piece of knowledge by PARA category autonomously
239
+ - When the user defines a specific goal with a completion condition, create a projects/ page. When identifying a repeating responsibility (monitoring, maintenance, quality), create an areas/ page.
240
+ - Produce wiki pages in the standard wiki summary format (Topic, Key Facts, Insights, Connections, Open Questions, Sources)
241
+ - Include the full session file path in the Sources section for traceability
242
+ - ALWAYS search wiki_query BEFORE creating any page — update existing pages instead of creating duplicates
243
+ - If wiki_query finds a page on the same topic (even with a different title/slug), update THAT page using its existing slug
244
+ - The conversation may include compaction summaries from earlier in the session — treat these as authoritative records of prior work
245
+ - Write directly via wiki_write — no user confirmation needed
246
+ - NEVER include API keys, tokens, passwords, or secrets in wiki pages. Document WHERE they are stored, not the actual values.`;
247
+
248
+ /**
249
+ * Prompt template for auto-capture at session_shutdown.
250
+ * The serialized conversation is appended after this prompt.
251
+ */
252
+ export const CAPTURE_PROMPT = `Analyze the session conversation below and capture ALL project-relevant knowledge into the wiki.
253
+
254
+ Capture bias: when in doubt, capture it. Small operational facts (paths, configs, server details, commands) are often the most valuable because they are hard to rediscover.
255
+
256
+ Only respond with "nothing to capture" if the session was purely greetings or off-topic chitchat with zero project knowledge.
257
+
258
+ For everything else:
259
+ 1. Use wiki_query to search for EXISTING pages on each topic FIRST
260
+ 2. If a matching page exists, use wiki_read to get its content, then wiki_write with its EXACT slug to update it
261
+ 3. Only create a NEW page if wiki_query returned no relevant results
262
+ 4. Each page must include the session file path in its Sources section
263
+ 5. Do NOT pass indexContent to wiki_write - the index is auto-rebuilt from all pages on disk
264
+
265
+ CRITICAL: prefer updating over creating. The wiki likely already has pages on most topics.
266
+
267
+ <session-conversation>
268
+ `;
269
+
270
+ /**
271
+ * Prompt template for explicit capture via /wiki-capture.
272
+ * A topic hint (if provided) and the serialized conversation are appended.
273
+ */
274
+ export const EXPLICIT_CAPTURE_PROMPT = `Capture knowledge from the current session into the wiki.`;
@@ -0,0 +1,116 @@
1
+ # Wiki Schema
2
+
3
+ ## Page Format
4
+
5
+ Every wiki page is a markdown file with YAML frontmatter:
6
+
7
+ ```yaml
8
+ ---
9
+ title: Page Title
10
+ para: projects | areas | resources | archives
11
+ scope:
12
+ - project-name
13
+ tags:
14
+ - topic-tag
15
+ sources:
16
+ - https://example.com
17
+ created: "2026-01-01"
18
+ updated: "2026-01-01"
19
+ links:
20
+ - other-page-slug
21
+ ---
22
+ ```
23
+
24
+ ## PARA Categories
25
+
26
+ - **resources/**: Reference material, architecture docs, how-tos, patterns, debugging solutions, implementation notes. **Use this for almost everything.** If you're documenting how something works, put it here.
27
+ - **areas/**: Ongoing responsibilities with no end date — server configs, deployment procedures, infrastructure. Default scope: `["global"]`.
28
+ - **projects/**: ONLY for actual project goals with a defined end date and completion criteria (e.g. "migrate auth to OAuth2"). Do NOT use for documentation about a project's internals. A page about "pi-para daemon architecture" is a resource, not a project.
29
+ - **archives/**: Completed or deprecated items. Never create pages here — pages get moved here when done.
30
+
31
+ ### Category decision rule
32
+
33
+ Ask: "Is this a goal I'm trying to accomplish, or knowledge I'm recording?"
34
+ - **Goal with end date** → projects/
35
+ - **Knowledge/reference** → resources/
36
+ - **Ongoing responsibility** → areas/
37
+
38
+ ## Scope
39
+
40
+ Scope is the **project name** this page relates to. Must be kebab-case, single token.
41
+
42
+ ✅ Correct: `pi-para`, `qmd`, `pi-mono`, `my-app`
43
+ ❌ Wrong: `session exploration`, `daemon implementation`, `project structure`
44
+
45
+ Pages relevant to all projects use `global`.
46
+
47
+ ## Tags
48
+
49
+ Tags are topic classifiers. Must be kebab-case (no spaces).
50
+
51
+ ✅ Correct: `session-capture`, `lazy-loading`, `architecture`
52
+ ❌ Wrong: `session files`, `UI component`, `model registry`
53
+
54
+ Don't duplicate scope values as tags — if scope is `pi-para`, don't also tag `pi-para`.
55
+
56
+ ## Naming Conventions
57
+
58
+ - Slugs: lowercase, hyphens, no special characters (e.g., `ssl-cert-gotchas`)
59
+ - One concept per page
60
+
61
+ ## Wikilinks
62
+
63
+ Use `[[slug]]` to connect related pages. Every page should link to related pages in a `## Connections` section:
64
+
65
+ ```markdown
66
+ ## Connections
67
+ - [[related-page]] — how this relates
68
+ - [[another-page]] — why it's relevant
69
+ ```
70
+
71
+ The `links` frontmatter field is auto-synced from body `[[wikilinks]]` — don't set it manually.
72
+
73
+ ## Wiki Summary Format
74
+
75
+ ```markdown
76
+ ## Topic
77
+ [What this page covers]
78
+
79
+ ## Key Facts
80
+ - [Established knowledge points]
81
+
82
+ ## Insights
83
+ - [Non-obvious findings, patterns, implications]
84
+
85
+ ## Connections
86
+ - [[related-page]] — how this relates
87
+
88
+ ## Open Questions
89
+ - [Gaps in knowledge, unresolved contradictions]
90
+
91
+ ## Sources
92
+ - [Source URLs, file paths, session references]
93
+ ```
94
+
95
+ ## Updates vs. New Pages
96
+
97
+ - Update an existing page when new information relates to the same concept
98
+ - Create a new page when the concept is distinct enough to stand alone
99
+ - When in doubt, create a new page and add [[wikilinks]]
100
+
101
+ ## Secrets
102
+
103
+ NEVER include secrets in wiki pages:
104
+ - API keys, tokens, passwords, private keys
105
+ - Connection strings with credentials
106
+ - Any value that would be dangerous if exposed
107
+
108
+ Instead, document WHERE the secret is stored:
109
+ - ✅ `API key stored in ~/.config/qmd/index.yml on server 10.88.1.8`
110
+ - ❌ `key: sk-or-v1-abc123...`
111
+
112
+ Secrets are automatically redacted on write. If you see `<REDACTED>` in a page, it was stripped for security.
113
+
114
+ ## Tone
115
+
116
+ Technical, concise, factual. No fluff.