@kybird/llm-wiki 0.2.0
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/LICENSE +21 -0
- package/README.md +168 -0
- package/TROUBLESHOOTING.md +103 -0
- package/bin/llm-wiki.js +102 -0
- package/lib/find-doc-root.js +93 -0
- package/lib/find-qmd.js +52 -0
- package/lib/init.js +236 -0
- package/lib/kanban-cmd.js +828 -0
- package/lib/kanban.js +363 -0
- package/lib/wiki-compile.js +362 -0
- package/lib/wiki-lint.js +272 -0
- package/lib/wiki-search.js +186 -0
- package/package.json +40 -0
- package/skills/kanban-plan/SKILL.md +71 -0
- package/skills/wiki-compile/SKILL.md +115 -0
- package/skills/wiki-lint/SKILL.md +57 -0
- package/skills/wiki-log/SKILL.md +157 -0
- package/skills/wiki-search/SKILL.md +39 -0
- package/skills/work-loop/SKILL.md +88 -0
- package/templates/doc/raw/.gitkeep +2 -0
- package/templates/doc/wiki/index.md +36 -0
- package/templates/githooks/pre-commit +77 -0
- package/templates/scripts/sync_agent_docs.bat +33 -0
- package/templates/scripts/sync_agent_docs.sh +25 -0
- package/templates/scripts/sync_skills.bat +26 -0
- package/templates/scripts/sync_skills.sh +40 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// wiki-search — grep 정확 매칭 + QMD 시맨틱 검색을 항상 병합해 출력한다.
|
|
2
|
+
// 원본: TTSTextViewer/.agents/skills/wiki-search/scripts/search.js
|
|
3
|
+
// 변경점:
|
|
4
|
+
// - __dirname '../../../../' 4단 종속 제거 → findDocRoot(), findQmd() 사용.
|
|
5
|
+
// - findstr(Windows 전용) → process.platform 분기 (win32=findstr, else=grep).
|
|
6
|
+
// - 2026-08-29 (개선계획 0-1): "QMD 성공 시 grep 건너뛰기" 분기 제거. QMD가 유사도로
|
|
7
|
+
// 뭐라도 물어오면 정확 문자열 매칭이 묻히는 구조라 색인이 싱싱할수록 재현율이
|
|
8
|
+
// 떨어졌다(plan.md 5.1(1)). 시맨틱은 대체재가 아니라 보완재 — 둘 다 항상 돌린다.
|
|
9
|
+
// grep 결과를 먼저 출력한다. 실무 검색어는 에러 메시지 붙여넣기가 대부분이라
|
|
10
|
+
// 정확 매칭이 첫 화면에 와야 한다.
|
|
11
|
+
// - 2026-08-29 (개선계획 0-2): grep에 순위를 부여했다. 키워드마다 Set에 합치던 것을
|
|
12
|
+
// 파일별 "매칭 키워드 수"로 집계해 내림차순 정렬하고, 파일명만 보여주던 것을
|
|
13
|
+
// 매칭된 줄 스니펫과 함께 출력한다 (plan.md 5.1(2)).
|
|
14
|
+
// - 2026-08-29 (개선계획 1-6): 수집(collect)과 렌더(render)를 분리. --json이면
|
|
15
|
+
// {schemaVersion: 1, kind: 'search-results', ...} 봉투로 출력 — 스킬 프롬프트가
|
|
16
|
+
// 사람용 출력 문자열에 깨지지 않게 하는 계약.
|
|
17
|
+
const { execSync } = require('child_process');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const { findDocRoot, loadConfig } = require('./find-doc-root');
|
|
21
|
+
const { findQmd } = require('./find-qmd');
|
|
22
|
+
|
|
23
|
+
const MAX_SNIPPETS_PER_FILE = 3;
|
|
24
|
+
const MAX_SNIPPET_LENGTH = 200;
|
|
25
|
+
|
|
26
|
+
function search(query, options = {}) {
|
|
27
|
+
if (!query) {
|
|
28
|
+
console.error('Usage: llm-wiki search "<search keywords>"');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const docRoot = findDocRoot();
|
|
33
|
+
const wikiPath = path.join(docRoot, 'wiki');
|
|
34
|
+
const rawPath = path.join(docRoot, 'raw');
|
|
35
|
+
const config = loadConfig(docRoot);
|
|
36
|
+
|
|
37
|
+
const result = {
|
|
38
|
+
schemaVersion: 1,
|
|
39
|
+
kind: 'search-results',
|
|
40
|
+
query,
|
|
41
|
+
// grep이 정확 매칭의 본체. QMD 여부와 무관하게 항상 채워진다.
|
|
42
|
+
grep: collectGrepResults(query, wikiPath, rawPath),
|
|
43
|
+
semantic: collectQmdResults(query, config),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (options.json) {
|
|
47
|
+
console.log(JSON.stringify(result, null, 2));
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
renderSearchText(result);
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function collectGrepResults(query, wikiPath, rawPath) {
|
|
55
|
+
// 따옴표는 findstr/grep 인용 규칙을 깨므로 키워드에서 제거.
|
|
56
|
+
const keywords = query.split(/\s+/)
|
|
57
|
+
.map(k => k.replace(/"/g, ''))
|
|
58
|
+
.filter(k => k.length > 1);
|
|
59
|
+
// 전부 1글자뿐인 극단 쿼리는 원문 하나를 통짜 키워드로.
|
|
60
|
+
if (keywords.length === 0 && query.trim()) keywords.push(query.trim());
|
|
61
|
+
|
|
62
|
+
const found = new Map(); // absPath → { keywords: Set, snippets: Map<lineText, true> }
|
|
63
|
+
const searchDirs = [wikiPath, rawPath];
|
|
64
|
+
const isWindows = process.platform === 'win32';
|
|
65
|
+
|
|
66
|
+
for (const dir of searchDirs) {
|
|
67
|
+
if (!fs.existsSync(dir)) continue;
|
|
68
|
+
for (const kw of keywords) {
|
|
69
|
+
try {
|
|
70
|
+
let grepCmd;
|
|
71
|
+
if (isWindows) {
|
|
72
|
+
// /C: 통짜 문자열 매칭(정규식 아님) — 에러 메시지의 . : ( 등이 그대로 걸린다.
|
|
73
|
+
// /M(files-only)을 쓰지 않는다 — 매칭 줄 자체가 스니펫이 된다.
|
|
74
|
+
grepCmd = `findstr /S /I /C:"${kw}" "${path.join(dir, '*.md')}"`;
|
|
75
|
+
} else {
|
|
76
|
+
// -F 고정 문자열(정규식 메타문자 무력화), -n 줄번호, -i 대소문자무시
|
|
77
|
+
grepCmd = `grep -rniF --include="*.md" -e "${kw}" "${dir}"`;
|
|
78
|
+
}
|
|
79
|
+
const output = execSync(grepCmd, { encoding: 'utf8' });
|
|
80
|
+
for (const line of output.split(/\r?\n/)) {
|
|
81
|
+
if (!line.trim()) continue;
|
|
82
|
+
const { file, snippet } = splitGrepLine(line);
|
|
83
|
+
if (!file) continue;
|
|
84
|
+
const abs = path.resolve(file);
|
|
85
|
+
if (!found.has(abs)) found.set(abs, { keywords: new Set(), snippets: new Map() });
|
|
86
|
+
const entry = found.get(abs);
|
|
87
|
+
entry.keywords.add(kw);
|
|
88
|
+
if (snippet && !entry.snippets.has(snippet)) entry.snippets.set(snippet, true);
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
// findstr/grep returns exit code 1 if no matches
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 정렬: 매칭 키워드 수 내림차순 → 스니펫 수 내림차순(밀도) → 경로명(안정화).
|
|
97
|
+
const files = [...found.entries()]
|
|
98
|
+
.map(([file, v]) => ({
|
|
99
|
+
file: file,
|
|
100
|
+
relativePath: path.relative(process.cwd(), file) || file,
|
|
101
|
+
title: path.basename(file, '.md'),
|
|
102
|
+
matchedKeywords: v.keywords.size,
|
|
103
|
+
totalKeywords: keywords.length,
|
|
104
|
+
snippets: [...v.snippets.keys()],
|
|
105
|
+
}))
|
|
106
|
+
.sort((a, b) =>
|
|
107
|
+
b.matchedKeywords - a.matchedKeywords ||
|
|
108
|
+
b.snippets.length - a.snippets.length ||
|
|
109
|
+
a.file.localeCompare(b.file));
|
|
110
|
+
|
|
111
|
+
return { keywords, files };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function collectQmdResults(query, config) {
|
|
115
|
+
const qmdPath = findQmd();
|
|
116
|
+
if (!qmdPath) return { available: false, collections: [] };
|
|
117
|
+
|
|
118
|
+
// 두 컬렉션 순회: 컴파일된 wiki + raw 로그.
|
|
119
|
+
const collections = [config.collections.wiki, config.collections.raw];
|
|
120
|
+
const results = [];
|
|
121
|
+
for (const coll of collections) {
|
|
122
|
+
try {
|
|
123
|
+
const output = execSync(`node "${qmdPath}" search "${query}" -c ${coll}`, { encoding: 'utf8', timeout: 30000 });
|
|
124
|
+
if (!isQmdEmpty(output)) results.push({ collection: coll, output: output.trim() });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
// collection missing or QMD error for this collection — try next
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { available: true, collections: results };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function renderSearchText(result) {
|
|
133
|
+
const { query, grep, semantic } = result;
|
|
134
|
+
console.log(`Keyword search (grep) for: "${query}"`);
|
|
135
|
+
|
|
136
|
+
if (grep.files.length === 0) {
|
|
137
|
+
console.log('No direct matches found.');
|
|
138
|
+
} else {
|
|
139
|
+
console.log(`\nDirect matches (${grep.files.length} file(s), ranked by matched keywords):`);
|
|
140
|
+
for (const f of grep.files) {
|
|
141
|
+
console.log(`- [[${f.title}]] (${f.relativePath}) — matched ${f.matchedKeywords}/${f.totalKeywords} keywords`);
|
|
142
|
+
const shown = f.snippets.slice(0, MAX_SNIPPETS_PER_FILE);
|
|
143
|
+
for (const snippet of shown) {
|
|
144
|
+
console.log(` │ ${snippet.length > MAX_SNIPPET_LENGTH ? snippet.slice(0, MAX_SNIPPET_LENGTH) + '…' : snippet}`);
|
|
145
|
+
}
|
|
146
|
+
if (f.snippets.length > shown.length) {
|
|
147
|
+
console.log(` … (${f.snippets.length - shown.length} more matching line(s))`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!semantic.available) {
|
|
153
|
+
console.log('\n(QMD not found — semantic search skipped. Install @tobilu/qmd to enable.)');
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
console.log(`\nSemantic search via QMD: ${query}`);
|
|
158
|
+
if (semantic.collections.length === 0) {
|
|
159
|
+
console.log('No semantic results.');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
for (const { collection, output } of semantic.collections) {
|
|
163
|
+
console.log(`\n--- Collection: ${collection} ---`);
|
|
164
|
+
console.log(output);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// QMD가 빈 결과를 반환하는지 확인 (에러가 아닌 "No results found." 케이스 감지)
|
|
169
|
+
function isQmdEmpty(output) {
|
|
170
|
+
if (!output || !output.trim()) return true;
|
|
171
|
+
return /^no\s+results\s+found\.\s*$/i.test(output.trim());
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// findstr/grep 출력 행에서 경로와 매칭 줄을 분리한다.
|
|
175
|
+
// findstr: <경로>.md:<내용>
|
|
176
|
+
// grep -n: <경로>.md:<줄번호>:<내용>
|
|
177
|
+
// 경계는 첫 `.md:`로 판정 — 윈도우 절대경로의 드라이브 콜론(`D:`)과 충돌을 피한다.
|
|
178
|
+
function splitGrepLine(line) {
|
|
179
|
+
const idx = line.indexOf('.md:');
|
|
180
|
+
if (idx === -1) return { file: null, snippet: null };
|
|
181
|
+
const file = line.slice(0, idx + 3);
|
|
182
|
+
const snippet = line.slice(idx + 4).replace(/^\d+:/, ''); // POSIX grep 줄번호 제거
|
|
183
|
+
return { file, snippet: snippet.trim() };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = { search };
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kybird/llm-wiki",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "LLM-friendly knowledge graph + kanban for AI coding agents. Raw daily logs → compiled wiki → merged semantic+grep search, and a card-per-file kanban the work-loop skill consumes unattended. Drop-in for any repo.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "kybird",
|
|
7
|
+
"bin": {
|
|
8
|
+
"llm-wiki": "bin/llm-wiki.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"lib/",
|
|
13
|
+
"skills/",
|
|
14
|
+
"templates/",
|
|
15
|
+
"TROUBLESHOOTING.md",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/kybird/llm-wiki.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/kybird/llm-wiki#readme",
|
|
23
|
+
"bugs": "https://github.com/kybird/llm-wiki/issues",
|
|
24
|
+
"optionalDependencies": {
|
|
25
|
+
"@tobilu/qmd": "^2.5.3"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"wiki",
|
|
32
|
+
"kanban",
|
|
33
|
+
"llm",
|
|
34
|
+
"ai-agent",
|
|
35
|
+
"knowledge-graph",
|
|
36
|
+
"agentic-memory",
|
|
37
|
+
"claude-code",
|
|
38
|
+
"work-loop"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kanban-plan
|
|
3
|
+
description: Planning loop — turn a plan into board cards the work-loop can consume. Cards are written only via the CLI; decompose with divergence guards, gate what isn't ready.
|
|
4
|
+
skill-version: 2
|
|
5
|
+
---
|
|
6
|
+
# When to use
|
|
7
|
+
|
|
8
|
+
- When the user plans work: a feature, a refactor, a research question, "이번 주 할 일 정리".
|
|
9
|
+
- When a work session reveals follow-up work — capture it as cards immediately instead of
|
|
10
|
+
letting it evaporate with the session (plan.md 4.1의 파편화가 이것이다).
|
|
11
|
+
- NOT during an unattended loop session — that runs `work-loop`, which consumes cards.
|
|
12
|
+
|
|
13
|
+
# Division of labor (plan.md 2.4)
|
|
14
|
+
|
|
15
|
+
- 기획(this skill) = **분해**: a plan becomes cards.
|
|
16
|
+
- 개발(`work-loop`) = **해소**: pick → done.
|
|
17
|
+
- QA = **수렴 강제**: fake dones get reverted; `board report` shows the ratio.
|
|
18
|
+
- The person watches progress through `llm-wiki board` / `board report` / `board --html`.
|
|
19
|
+
Plan so that this one screen is enough — 리뷰가 카드 수에 비례하면 무인의 의미가 없다.
|
|
20
|
+
|
|
21
|
+
# Before creating cards
|
|
22
|
+
|
|
23
|
+
1. `llm-wiki search "<keywords>"` — the wall may already have an anti-pattern page or an
|
|
24
|
+
abandoned card with the reason recorded. 폐기 사유는 가장 값비싼 정보다.
|
|
25
|
+
2. `llm-wiki board` — does a card for this already exist? Extend (`card edit`) or replace
|
|
26
|
+
it (`supersede`); never spawn a near-duplicate. Titles are identifiers (plan.md 3.5):
|
|
27
|
+
no numbers, no versions in titles.
|
|
28
|
+
|
|
29
|
+
# Decomposition rules (divergence guards, plan.md 2.3)
|
|
30
|
+
|
|
31
|
+
- One card = one context = one commit. If you cannot say what the commit would be, it is
|
|
32
|
+
too big — split it.
|
|
33
|
+
- Children must be **strictly smaller** than the parent. When children replace a parent,
|
|
34
|
+
`supersede` it — the parent dissolves, it is not marked done.
|
|
35
|
+
- Depth ≤ 3 (plan → subtask → task). Deeper than that means you are writing the work,
|
|
36
|
+
not planning it.
|
|
37
|
+
- Do not board what is not ready to start:
|
|
38
|
+
- Time condition → `card new "<t>" --not-before 2026-09-05`. `pick` skips it until then.
|
|
39
|
+
- Observational condition → create it, then `handoff <t> --question "조건: …"`. It waits
|
|
40
|
+
in review; anyone who can show the condition holds runs `resume <t> --note "근거"`.
|
|
41
|
+
|
|
42
|
+
# Question timing — start-of-work questions are the cheap ones
|
|
43
|
+
|
|
44
|
+
- In a session where the person is present (planning), ask **before** boarding a card:
|
|
45
|
+
an ambiguous spec answered now costs one question; answered after an unattended loop
|
|
46
|
+
hit the wall, it costs a parked card and a night of latency.
|
|
47
|
+
- The person is away, or the answer can arrive asynchronously: board the card and park it
|
|
48
|
+
immediately — `handoff <t> --question "…"` puts it in review with the question; when the
|
|
49
|
+
answer lands, `resume <t> --note "답: …"` sends it back to todo. handoff is "판정을
|
|
50
|
+
사람에게 넘기기", not "끝나고 물어보기" — timing follows whoever can answer.
|
|
51
|
+
- An unattended loop session cannot ask before starting (plan.md 2.1 — 승인 대기는
|
|
52
|
+
오프피크 낭비). There, questions are recorded at the wall and answered in bulk by morning.
|
|
53
|
+
|
|
54
|
+
# Card quality bar
|
|
55
|
+
|
|
56
|
+
- **Goal**: one sentence a stranger can act on (`--goal`). No goal, no card.
|
|
57
|
+
- **AC**: 1–4 items, each verifiable by running or looking at something objective
|
|
58
|
+
(`--ac`, repeat per item). If an AC can only be verified by "읽어보니 되는 것 같다",
|
|
59
|
+
rewrite it — the QA pass reverts evidence-free dones.
|
|
60
|
+
- **Dependencies**: `--depends "다른 카드 제목"` — real DAG edges only (cycles are rejected).
|
|
61
|
+
- **Notes** (`card edit --note`) are the append-only journal; timestamps are added by the CLI.
|
|
62
|
+
- Every write goes through the CLI. A hand-edited card file is out of contract — 사람은 읽기만.
|
|
63
|
+
|
|
64
|
+
# While the work runs
|
|
65
|
+
|
|
66
|
+
- Follow-up discovered mid-task → `card new` right away, then continue. The board is the
|
|
67
|
+
memory, not the session.
|
|
68
|
+
- Plan changed? `supersede` the stale cards. Direction abandoned? `abandon --reason` —
|
|
69
|
+
the reason is mandatory and flows into `doc/raw/` as anti-pattern material.
|
|
70
|
+
- Do not start cards yourself in a planning session — leave them in `todo` for the
|
|
71
|
+
work-loop. 계획과 실행이 같은 세션에 섞이면 파편화가 돌아온다.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wiki-compile
|
|
3
|
+
description: Parse raw logs to extract, synthesize, and deprecate project knowledge. Generates high-density grounded wiki pages and maintains the central index.
|
|
4
|
+
skill-version: 2
|
|
5
|
+
---
|
|
6
|
+
# When to use
|
|
7
|
+
- After accumulating raw logs in doc/raw/
|
|
8
|
+
- When establishing project-wide rules or identifying recurring failures
|
|
9
|
+
- Periodically to restructure the knowledge graph based on new evidence
|
|
10
|
+
|
|
11
|
+
# Action
|
|
12
|
+
|
|
13
|
+
## Phase 0: Preparation (Automation)
|
|
14
|
+
1. **Identify New Logs**: Run `llm-wiki compile list`. Detection is date **OR** content-hash
|
|
15
|
+
based (`doc/wiki/compile-state.json`) — same-day appends to an already-compiled log are
|
|
16
|
+
caught too. The listed logs are a real to-do list for Phases 1–3, not a formality.
|
|
17
|
+
2. **Context Loading**: Read the identified logs and the current `doc/wiki/index.md`.
|
|
18
|
+
|
|
19
|
+
## Phase 1: High-Density Extraction (LLM)
|
|
20
|
+
1. For each Case, extract:
|
|
21
|
+
- **Grounding**: Git hash, Confidence score (1-5), Evidence links.
|
|
22
|
+
- **Analytical Core**: The "Why" (First Principles) and "Trade-offs".
|
|
23
|
+
- **Taxonomy**: Concepts, Patterns, Anti-patterns.
|
|
24
|
+
2. Merge similar cases, favoring the one with the highest **Confidence** and most recent **Git Hash**.
|
|
25
|
+
3. **Disposition (MANDATORY, per Case)** — classify BEFORE writing any page, and state it in your output:
|
|
26
|
+
- **New**: no existing page covers this → create a page.
|
|
27
|
+
- **Update**: extends an existing page → edit that page, append the Case to its Grounding.
|
|
28
|
+
- **Merge**: duplicates/splits an existing page → fold into it; do not spawn a near-duplicate.
|
|
29
|
+
- **No material**: the Case is a one-off with no reusable lesson → skip it. Raw log is its archive.
|
|
30
|
+
A wiki that grows a page per Case diverges; thin pages dilute search. `No material` is a
|
|
31
|
+
first-class outcome, not a failure.
|
|
32
|
+
|
|
33
|
+
## Phase 2: Knowledge Promotion & Synthesis (LLM)
|
|
34
|
+
Synthesize extracted data into structured wiki pages. Use the following high-density templates:
|
|
35
|
+
|
|
36
|
+
**Verbatim rule**: quote error messages character-for-character from the raw log — never
|
|
37
|
+
paraphrase. `llm-wiki lint` back-matches every `### Error` quote against `doc/raw/`; a
|
|
38
|
+
summarized quote is reported as an evidence violation.
|
|
39
|
+
|
|
40
|
+
### Wiki Template (Concept)
|
|
41
|
+
```markdown
|
|
42
|
+
---
|
|
43
|
+
status: active | deprecated | draft
|
|
44
|
+
version_context: "e.g., Library X x.y"
|
|
45
|
+
tags: [domain, concept]
|
|
46
|
+
aliases: [synonyms]
|
|
47
|
+
created: YYYY-MM-DD
|
|
48
|
+
confidence: [1-5]
|
|
49
|
+
---
|
|
50
|
+
# [Concept Name]
|
|
51
|
+
[1-2 sentence summary]
|
|
52
|
+
## First Principles
|
|
53
|
+
## Details
|
|
54
|
+
## Related
|
|
55
|
+
## Grounding (References)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Wiki Template (Pattern)
|
|
59
|
+
```markdown
|
|
60
|
+
---
|
|
61
|
+
status: active | deprecated | draft
|
|
62
|
+
version_context: "e.g., Framework X x.y"
|
|
63
|
+
tags: [domain, pattern]
|
|
64
|
+
aliases: [synonyms]
|
|
65
|
+
created: YYYY-MM-DD
|
|
66
|
+
confidence: [1-5]
|
|
67
|
+
---
|
|
68
|
+
# [Pattern Name]
|
|
69
|
+
[1-2 sentence summary]
|
|
70
|
+
## The Rule
|
|
71
|
+
## Why it works
|
|
72
|
+
## Trade-offs
|
|
73
|
+
## Anti-Pattern
|
|
74
|
+
## Related
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Anti-pattern pages use `tags: [domain, anti-pattern]` and document the failure mode + prevention checklist.
|
|
78
|
+
|
|
79
|
+
## Phase 3: Conflict Resolution & Deprecation (LLM)
|
|
80
|
+
1. **Contradiction Detection**: If a new Case contradicts an old wiki page, mark the old one `status: deprecated` and add `superseded_by: [[new-page]]`.
|
|
81
|
+
2. **Merging**: If a new Case extends an old page, update the page and append the new Case to "Grounding (References)".
|
|
82
|
+
|
|
83
|
+
## Phase 4: Indexing & Health (Automation)
|
|
84
|
+
1. **Rebuild Index**: Run `llm-wiki compile index`. This automatically:
|
|
85
|
+
- Scans all files in `doc/wiki/` (including loose root files, classified by `tags`).
|
|
86
|
+
- Rebuilds the tables in `index.md`.
|
|
87
|
+
- Updates `Statistics` and `Last updated` date.
|
|
88
|
+
- Syncs the QMD search index (creates wiki + raw collections if missing, re-indexes, refreshes embeddings).
|
|
89
|
+
- Regenerates `doc/wiki/compile-state.json` (per-file hashes for same-day append detection).
|
|
90
|
+
|
|
91
|
+
⚠️ **`compile index` is a "compile complete" declaration.** Running only Phase 4 without
|
|
92
|
+
Phases 1–3 seals every raw log up to now as *compiled*. If the state file ever merges
|
|
93
|
+
badly or goes missing, the resolution is trivial: keep either side (or delete it) and run
|
|
94
|
+
`compile index` once — it is regenerated deterministically from the current `doc/raw/`.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
# QMD (semantic search) notes
|
|
99
|
+
|
|
100
|
+
`llm-wiki compile index` syncs the QMD search index when `@tobilu/qmd` is installed (optional). Without QMD, the wiki index still rebuilds and `llm-wiki search` falls back to grep.
|
|
101
|
+
|
|
102
|
+
## GPU vs CPU mode (`QMD_LLAMA_GPU`)
|
|
103
|
+
|
|
104
|
+
> **Variable name is `QMD_LLAMA_GPU`** — not `NODE_LLAMA_CPP_GPU`. The latter is read by nothing in the codebase and has no effect.
|
|
105
|
+
|
|
106
|
+
- Default: GPU used automatically when available.
|
|
107
|
+
- To force CPU (e.g., transient CUDA driver issue, VRAM pressure, or NVIDIA GPU asleep):
|
|
108
|
+
```bash
|
|
109
|
+
QMD_LLAMA_GPU=false llm-wiki compile index
|
|
110
|
+
```
|
|
111
|
+
- For a permanent override on a problematic machine, set it in your shell profile or a local `.env`.
|
|
112
|
+
|
|
113
|
+
## Troubleshooting build-time CUDA failures
|
|
114
|
+
|
|
115
|
+
Detailed CUDA Toolkit / MSVC / node-llama-cpp prebuilt-binary diagnostics (Windows + NVIDIA specific) live in **[TROUBLESHOOTING.md](../TROUBLESHOOTING.md)** in the package root. Consult it only if `compile index` prints `falling back to using Vulkan` or `CUDA error` messages.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wiki-lint
|
|
3
|
+
description: Validate knowledge graph integrity, detect logical conflicts, and generate a professional health report with Mermaid visualizations.
|
|
4
|
+
skill-version: 1
|
|
5
|
+
---
|
|
6
|
+
# When to use
|
|
7
|
+
- Before starting a major feature or refactor
|
|
8
|
+
- After a `wiki-compile` run to ensure quality
|
|
9
|
+
- Periodically to prune dead or contradictory knowledge
|
|
10
|
+
|
|
11
|
+
# Action
|
|
12
|
+
|
|
13
|
+
## Phase 1: Automated Integrity Check (Automation)
|
|
14
|
+
1. **Run Linter**: Run `llm-wiki lint`.
|
|
15
|
+
2. **Review Output**:
|
|
16
|
+
- **Broken Links**: List of `[[wikilinks]]` that point to non-existent files.
|
|
17
|
+
- **Missing Metadata**: Files missing required YAML fields or headers.
|
|
18
|
+
- **Version Drift**: Discrepancies between the project package manifest (package.json / pubspec.yaml / Cargo.toml / pyproject.toml) and wiki `version_context`.
|
|
19
|
+
|
|
20
|
+
## Phase 2: Knowledge Health & Staleness (LLM)
|
|
21
|
+
- Identify pages with `created:` dates older than 6 months for review.
|
|
22
|
+
- Flag concepts that may have been superseded by newer entries but lack `status: deprecated`.
|
|
23
|
+
|
|
24
|
+
## Phase 3: Conflict & Consistency Check (LLM)
|
|
25
|
+
- Detect pages that directly contradict each other (e.g., one says "always use X", another says "avoid X").
|
|
26
|
+
- When a contradiction is found, decide which is current and mark the other `deprecated` with `superseded_by:` pointing to the winner.
|
|
27
|
+
|
|
28
|
+
## Phase 4: Professional Health Report
|
|
29
|
+
Generate a summary in `doc/wiki/health_report.md` (or output to console):
|
|
30
|
+
|
|
31
|
+
### Report Template
|
|
32
|
+
```markdown
|
|
33
|
+
# 🩺 Wiki Health Report (YYYY-MM-DD)
|
|
34
|
+
|
|
35
|
+
## 📊 Knowledge Distribution
|
|
36
|
+
\`\`\`mermaid
|
|
37
|
+
pie title Knowledge Types
|
|
38
|
+
"Active Concepts" : [count]
|
|
39
|
+
"Active Patterns" : [count]
|
|
40
|
+
"Deprecated" : [count]
|
|
41
|
+
"Drafts" : [count]
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
## ⚠️ Critical Issues
|
|
45
|
+
- **Broken Links**: [List]
|
|
46
|
+
- **Version Drift**: [List]
|
|
47
|
+
- **Conflicts**: [List]
|
|
48
|
+
|
|
49
|
+
## 🛠️ Auto-Fix Summary
|
|
50
|
+
- [x] Fixed YAML indentation in 3 files
|
|
51
|
+
- [x] Normalized 2 concept titles
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Phase 5: Auto-Fixing
|
|
55
|
+
- Automatically fix common YAML formatting errors.
|
|
56
|
+
- Normalize link casing to match file names.
|
|
57
|
+
- Update `index.md` if any titles were normalized (run `llm-wiki compile index`).
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wiki-log
|
|
3
|
+
description: Record knowledge into raw memory with Karpathy-inspired Agentic Memory format. Captures errors, decisions, and discoveries with high-density grounding.
|
|
4
|
+
skill-version: 1
|
|
5
|
+
---
|
|
6
|
+
# When to use
|
|
7
|
+
- After an error occurs or a bug is fixed
|
|
8
|
+
- After making a design decision or architectural choice
|
|
9
|
+
- After verifying a hypothesis or benchmarking performance
|
|
10
|
+
- When discovering non-obvious behavior (library quirk, platform limitation)
|
|
11
|
+
- When documenting "why" something was done a certain way
|
|
12
|
+
|
|
13
|
+
# Input
|
|
14
|
+
- type: error | design | verification | discovery (default: error)
|
|
15
|
+
- task: what you tried to do or decided
|
|
16
|
+
- error: (for type=error) error message or incorrect behavior
|
|
17
|
+
- wrong_code: (for type=error) incorrect code that caused the issue
|
|
18
|
+
- fix_code: corrected or final code
|
|
19
|
+
- decision: (for type=design) the decision made and alternatives considered
|
|
20
|
+
- result: (for type=verification) test results, benchmarks, or measurements
|
|
21
|
+
- finding: (for type=discovery) what was discovered
|
|
22
|
+
- environment: key package versions or context
|
|
23
|
+
- is_migration_fix: boolean (true if due to version upgrade or deprecation)
|
|
24
|
+
- git_hash: (optional) current git commit hash for grounding
|
|
25
|
+
- confidence: (1-5) how certain are we about this knowledge
|
|
26
|
+
|
|
27
|
+
# Action
|
|
28
|
+
1. Determine Date Filename
|
|
29
|
+
- Use current date in format: YYYY-MM-DD.md
|
|
30
|
+
- File path: doc/raw/YYYY-MM-DD.md
|
|
31
|
+
|
|
32
|
+
2. Concept Drift Protection (MANDATORY)
|
|
33
|
+
- **Search before naming**: Use `llm-wiki search` or `ls doc/wiki/concepts/` to find existing concepts.
|
|
34
|
+
- Reuse existing names to maintain a dense, high-utility knowledge graph.
|
|
35
|
+
- **Collect aliases**: While searching, note every other name the same concept travels under
|
|
36
|
+
(Korean/English variants, error codes, product shorthand). Record them so compile can put
|
|
37
|
+
`aliases: [...]` in the wiki page frontmatter — search fails when the writer's word and the
|
|
38
|
+
searcher's word differ (plan.md 5.1(3)).
|
|
39
|
+
|
|
40
|
+
3. Verbatim Error Preservation (MANDATORY)
|
|
41
|
+
- The `### Error` section must contain the error message **character-for-character** — copy-paste,
|
|
42
|
+
never paraphrase or summarize. Later searches paste real error strings; a summarized message
|
|
43
|
+
deletes exactly the strings they would match.
|
|
44
|
+
|
|
45
|
+
4. Create Entry — choose format based on type:
|
|
46
|
+
|
|
47
|
+
### Type: error
|
|
48
|
+
```markdown
|
|
49
|
+
## Case N: [Title]
|
|
50
|
+
|
|
51
|
+
### Grounding
|
|
52
|
+
- Git Context: `hash:[git_hash]`
|
|
53
|
+
- Evidence: [path/to/artifact or log]
|
|
54
|
+
- Confidence: [1-5]/5
|
|
55
|
+
|
|
56
|
+
### Error
|
|
57
|
+
[error message or incorrect behavior]
|
|
58
|
+
|
|
59
|
+
### Environment Context
|
|
60
|
+
- Packages: [environment]
|
|
61
|
+
- Migration Issue: [Yes/No]
|
|
62
|
+
|
|
63
|
+
### Fix Code
|
|
64
|
+
[corrected code]
|
|
65
|
+
|
|
66
|
+
### Analysis
|
|
67
|
+
- Root cause: [brief explanation]
|
|
68
|
+
- Why it failed: [First principles analysis]
|
|
69
|
+
- How it was fixed: [explanation]
|
|
70
|
+
|
|
71
|
+
### Related Knowledge
|
|
72
|
+
- Concepts: [[concept-name]]
|
|
73
|
+
- Patterns: [[pattern-name]]
|
|
74
|
+
- **Anti-Patterns**: [[what-to-avoid]]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Type: design
|
|
78
|
+
```markdown
|
|
79
|
+
## Case N: [Title]
|
|
80
|
+
|
|
81
|
+
### Grounding
|
|
82
|
+
- Git Context: `hash:[git_hash]`
|
|
83
|
+
- Confidence: [1-5]/5
|
|
84
|
+
|
|
85
|
+
### Design Decision
|
|
86
|
+
[what was decided]
|
|
87
|
+
|
|
88
|
+
### Alternatives Considered
|
|
89
|
+
- Option A: [description] — [why rejected]
|
|
90
|
+
- Option B: [description] — [why rejected]
|
|
91
|
+
- Selected: [why chosen]
|
|
92
|
+
|
|
93
|
+
### Decision Code
|
|
94
|
+
[code implementing the decision]
|
|
95
|
+
|
|
96
|
+
### Analysis
|
|
97
|
+
- Context: [situation/constraint]
|
|
98
|
+
- **Trade-offs**: [Memory vs Speed / Cost vs Complexity]
|
|
99
|
+
- Reversibility: [High/Low]
|
|
100
|
+
|
|
101
|
+
### Related Knowledge
|
|
102
|
+
- Concepts: [[concept-name]]
|
|
103
|
+
- Patterns: [[pattern-name]]
|
|
104
|
+
- **Anti-Patterns**: [[rejected-design-pattern]]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Type: verification
|
|
108
|
+
```markdown
|
|
109
|
+
## Case N: [Title]
|
|
110
|
+
|
|
111
|
+
### Grounding
|
|
112
|
+
- Git Context: `hash:[git_hash]`
|
|
113
|
+
- Artifact: [path/to/benchmark_result.json]
|
|
114
|
+
- Confidence: [1-5]/5
|
|
115
|
+
|
|
116
|
+
### Hypothesis
|
|
117
|
+
[what was being tested]
|
|
118
|
+
|
|
119
|
+
### Results
|
|
120
|
+
[measurements, benchmarks]
|
|
121
|
+
|
|
122
|
+
### Analysis
|
|
123
|
+
- Confirmed/Refuted: [result]
|
|
124
|
+
- Key metrics: [numbers]
|
|
125
|
+
- Implications: [project impact]
|
|
126
|
+
|
|
127
|
+
### Related Knowledge
|
|
128
|
+
- Concepts: [[concept-name]]
|
|
129
|
+
- Patterns: [[pattern-name]]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Type: discovery
|
|
133
|
+
```markdown
|
|
134
|
+
## Case N: [Title]
|
|
135
|
+
|
|
136
|
+
### Grounding
|
|
137
|
+
- Git Context: `hash:[git_hash]`
|
|
138
|
+
- Evidence: [logs or data]
|
|
139
|
+
- Confidence: [1-5]/5
|
|
140
|
+
|
|
141
|
+
### Discovery
|
|
142
|
+
[what was found - non-obvious behavior]
|
|
143
|
+
|
|
144
|
+
### Analysis
|
|
145
|
+
- Why non-obvious: [Surprise factor]
|
|
146
|
+
- Impact: [how this affects the project]
|
|
147
|
+
- Action taken: [mitigation/leveraging]
|
|
148
|
+
|
|
149
|
+
### Related Knowledge
|
|
150
|
+
- Concepts: [[concept-name]]
|
|
151
|
+
- Patterns: [[pattern-name]]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
# Output
|
|
155
|
+
- File created or updated: doc/raw/YYYY-MM-DD.md
|
|
156
|
+
- Case anchor for direct linking: #case-N
|
|
157
|
+
- **Index Update**: Run `llm-wiki compile index` to make the new case searchable (rebuilds wiki index + syncs QMD search index). If QMD is not installed, the case is still found via grep fallback.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wiki-search
|
|
3
|
+
description: Retrieve relevant past knowledge. Filters out deprecated practices and follows migration trails.
|
|
4
|
+
skill-version: 1
|
|
5
|
+
---
|
|
6
|
+
# When to use
|
|
7
|
+
- BEFORE writing any code
|
|
8
|
+
- At the start of every task
|
|
9
|
+
|
|
10
|
+
# Input
|
|
11
|
+
- current task description
|
|
12
|
+
|
|
13
|
+
# Action
|
|
14
|
+
1. **Search via CLI (Recommended)**:
|
|
15
|
+
- Run: `llm-wiki search "<task keywords>"`
|
|
16
|
+
- Always runs BOTH grep exact matching AND QMD semantic search (when installed) and merges
|
|
17
|
+
them — grep results are ranked by matched-keyword count with line snippets.
|
|
18
|
+
- Prefer pasting the **verbatim error string** as the query; exact strings are what grep
|
|
19
|
+
guarantees to find.
|
|
20
|
+
|
|
21
|
+
2. **Follow Links**:
|
|
22
|
+
- Use bidirectional links `[[link]]` and tags to navigate related knowledge.
|
|
23
|
+
|
|
24
|
+
3. **Deprecation Check (CRITICAL)**:
|
|
25
|
+
- For every page found, check the YAML `status`.
|
|
26
|
+
- If `status: deprecated`, follow `superseded_by`.
|
|
27
|
+
|
|
28
|
+
# Output Format
|
|
29
|
+
- Warnings: Include any anti-patterns or recently deprecated methods found.
|
|
30
|
+
- Recommendations: Based ONLY on `status: active` patterns.
|
|
31
|
+
- Related cases: [[case-link]]
|
|
32
|
+
|
|
33
|
+
# Answer Archiving
|
|
34
|
+
- If this search produced a genuinely useful **synthesized answer** (spanning several pages,
|
|
35
|
+
the kind a future session will re-derive at real cost), promote it:
|
|
36
|
+
- Write `doc/wiki/answers/<topic>.md` — frontmatter: `status: active`, `created: YYYY-MM-DD`,
|
|
37
|
+
`tags: [...]`, `aliases: [...]`, plus the answer body with `[[links]]` back to sources.
|
|
38
|
+
- Next `llm-wiki compile index` lists it in the Answers section and it becomes searchable.
|
|
39
|
+
- Archive answers, not raw search dumps: a question answered in one page does not need this.
|