
Llm Wiki
- 36 installs
- 6 repo stars
- Updated May 10, 2026
- godstale/llm-wiki
Operate an agent-maintained personal knowledge base: ingest sources, query, lint, rebuild the graph, manage ontology, and update or delete pages.
About
A standard operating procedure for a markdown wiki that transforms raw input into structured source/entity/concept pages with wikilinks, then supports query, synthesize, lint, graph, and lifecycle commands. A developer uses it to build and maintain a linked personal knowledge base with an agent.
- Ingest to structured pages with case-sensitive wikilinks
- Query, synthesize, lint, graph, and ontology commands
Llm Wiki by the numbers
- 36 all-time installs (skills.sh)
- Ranked #902 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Jul 24, 2026 (Skillselion catalog sync)
npx skills add https://github.com/godstale/llm-wiki --skill llm-wikiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 36 |
|---|---|
| repo stars | ★ 6 |
| Last updated | May 10, 2026 |
| Repository | godstale/llm-wiki ↗ |
What it does
Operate an agent-maintained personal knowledge base: ingest sources, query, lint, rebuild the graph, manage ontology, and update or delete pages.
Files
LLM Wiki: Agent SOP
This is the main "Operating Manual" for the LLM Wiki project. It manages the lifecycle of knowledge: Ingest → Query → Lint → Graph.
🧭 Core Workflow Index
For detailed instructions, refer to the specialized reference files.
| Stage | Action | Reference |
|---|---|---|
| Ingest | `/wiki-ingest [<file>\ | --from <dir>]` |
| Query | /wiki-query <question> | references/query-advanced.md |
| Save | /wiki-synthesize [slug] | SKILL.md#wiki-synthesize |
| Maintain | /wiki-lint \ | /wiki-graph |
| Edit | /wiki-update \ | /wiki-delete |
| Ontology | /wiki-ontology-* | references/ontology-commands.md |
---
🏗️ Project Layout
wiki/
index.md # Catalog of all pages (Update EVERY ingest)
log.md # Chronological record (Append-only)
history.json # Ingest registry (Always use Write tool)
sources/ # Summaries (kebab-case.md)
entities/ # People/Projects (TitleCase.md)
concepts/ # Ideas/Theories (TitleCase.md)
syntheses/ # Saved query answers
originals/ # Read-only archive
ontologies/ # (OPTIONAL) Structured YAML dataTemplates & Schema → references/templates.md | Wikilinks: [[PageName]] (Case-Sensitive)
---
📥 Ingest Process
Main Goal: Transform raw input into structured wiki pages and archive the original.
1. Analysis: Read source. Determine title/slug. 2. Strategy: Select mode (Full vs. Summary-Only).
- Summary-Only:
.xlsx,.pptx,.pdf> 30p, or--summary-onlyflag.
3. Execution:
- Write
wiki/sources/<slug>.md. - Update
wiki/index.mdusing hierarchical categorization (e.g.,Hobby/Cycling) — seereferences/ingest-advanced.mdfor rules and defaults. - Create/Update
wiki/entities/andwiki/concepts/.
4. Registration: Update wiki/history.json and append to wiki/log.md.
Advanced flags (`--to`, `--precision`, `--no-interview`, etc.) → `references/ingest-advanced.md`
---
🔍 Query & Synthesis
/wiki-query
1. Discover relevant pages from wiki/index.md, wiki/synthesis-map.md, and wiki-hub.md. 2. Gather context from sources/, entities/, concepts/, and ontologies/. If a file is in wiki-hub.md, cite the external source repo. 3. Synthesize answer with [[PageName]] citations. Structural filters (class:, type:, AND/OR) → `references/query-advanced.md`
/wiki-synthesize
Saves the last query answer to wiki/syntheses/<slug>.md. 1. Generate slug from question. 2. Update wiki/synthesis-map.md (append-only) and wiki/log.md.
---
🛠️ Maintenance & Lifecycle
#maintenance
- /wiki-lint: Check orphans, broken links, stale summaries. (Report:
wiki/lint-report.md). Ifwiki-hub.mdexists, ignore/lower severity of broken links originating from imported external files. - /wiki-graph: Rebuild
graph/graph.jsonandgraph/graph.html.
#lifecycle
- /wiki-sources: List ingested sources from
history.json. - /wiki-update <slug>: Refresh a source from its original file.
- /wiki-delete <slug>: Soft-delete source (keep in history, remove pages).
---
🔗 Wiki-Hub Architecture Support
When a wiki-hub.md file exists at the project root, it acts as the authoritative registry for external files.
1. External Source Citation
- During
/wiki-query, the agent MUST checkwiki-hub.mdfor any file used in the answer. - If the file is listed as an imported source, the citation should include the external repository information (e.g.,
[[PageName]] (Source: repo-name)).
2. Linting Exceptions
/wiki-lintshould read the## Imported Sourceslist inwiki-hub.md.- Broken link warnings for files listed in the hub should be suppressed or marked as "External" to avoid unnecessary noise from links pointing to non-imported dependencies.
3. File Integrity
- Do not overwrite, modify, or delete files tracked in
wiki-hub.mdwithout explicit user confirmation. These files are managed externally via the hub.
---
⚠️ Gotchas & Critical Rules
- READ-ONLY: Never modify
wiki/originals/. - CONSISTENCY:
wiki/index.mdmust be updated on every ingest to keep query discovery working. - HISTORY: Always read-merge-write
wiki/history.json. - CLEANUP: When deleting, check for orphaned entity/concept pages.
.DS_Store
.vscode/
.idea/
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Node
node_modules/
dist/
build/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# Python
__pycache__/
*.py[cod]
*.so
.Python
env/
venv/
.venv/
pip-log.txt
pip-delete-this-directory.txt
# Logs
logs
*.log
# Etc
references/wiki-hub/
references/llm-wiki-test/
docs/
AGENTS.md — LLM Wiki Project Context
Instructions for AI agents (Codex, Copilot, and other general-purpose agents) working in this repository.
What This Repo Is
llm-wiki is an agent skill package — not a runnable application. It ships as SKILL.md (the agent instruction file) plus supporting Python scripts and reference files. The repo is the skill distribution package; users install it and invoke it via slash commands in their own wiki projects.
Slash Commands
All commands are defined in SKILL.md and executed inside the user's wiki project:
| Command | Purpose |
|---|---|
| `/wiki-ingest [file\ | --from <folder>] [--to <folder>]` |
/wiki-query <question> | Query the wiki and present the answer |
/wiki-synthesize [slug] | Save the most recent query answer as a synthesis |
/wiki-lint | Health-check for broken links, orphans, contradictions |
/wiki-graph | Build interactive vis.js knowledge graph |
/wiki-sources | List all ingested sources |
/wiki-update <slug> | Re-ingest an existing source |
/wiki-delete <slug> | Remove a source and its derived pages |
Directory Layout (User's Wiki Project)
raw/ # Drop zone for unprocessed docs
wiki/
index.md # Catalog — updated on every ingest
log.md # Append-only change log
overview.md # Living synthesis
history.json # Registry of all ingested sources
synthesis-map.md # Index of saved query syntheses (append-only)
originals/ # Read-only archive of source docs
sources/ # kebab-case.md — one summary per source
entities/ # TitleCase.md — people, orgs, products
concepts/ # TitleCase.md — ideas, frameworks, theories
syntheses/ # kebab-case.md — saved query answers
graph/ # graph.json + graph.htmlKey Invariants
wiki/log.md— append-only, never edit past entrieswiki/synthesis-map.md— append-only, never edit past entrieswiki/originals/— read-only after ingest, never modify archived fileswiki/index.md— must be updated on every ingestwiki/history.json— always read → merge → overwrite with Write tool- Wikilinks are case-sensitive:
[[OpenAI]]≠[[Openai]] - Source slugs in
sources:frontmatter must exactly match the filename without extension - All scripts run from the wiki project root (
python scripts/...)
Wiki Page Frontmatter
Every .md file in wiki/ requires YAML frontmatter:
---
title: "Page Title"
type: source | entity | concept | synthesis
tags: []
sources: [slug1, slug2]
last_updated: YYYY-MM-DD
---Naming Conventions
- Sources & Syntheses:
kebab-case.md - Entities & Concepts:
TitleCase.md
Python Scripts
python scripts/lint.py --save # health check → wiki/lint-report.md
python scripts/build_graph.py --open # rebuild graph + open browser
python scripts/file_to_markdown.py --input_dir raw/ # convert pdf/docx/pptx/xlsx → .md
pip install -r scripts/requirements.txt # networkx, markitdown, tqdmPython is optional — agent-based fallbacks for all commands are defined in SKILL.md.
Recommended Workflow
/wiki-ingest raw/my-doc.md
/wiki-query "What does this say about X?"
/wiki-synthesize ← save the answer for future queries
/wiki-lint ← check for broken links after bulk ingests
/wiki-graph ← rebuild visualizationReference Files
| File | Purpose |
|---|---|
references/templates.md | Page frontmatter templates |
references/folder-managing.md | PARA method rules for --to flag |
references/ingest-advanced.md | Batch ingest, PARA, Context Interview |
references/query-advanced.md | Structural filters for /wiki-query |
references/ontology-commands.md | Ontology feature (opt-in) |
references/graph-html.md | vis.js HTML template |
Changelog
All notable changes to llm-wiki are documented here.
Format follows Keep a Changelog.
---
[Unreleased]
---
[1.0.0] — 2026-04-19
Added
- `/wiki-ingest` — ingest source documents into the knowledge base
- Reads and summarizes source files into
wiki/sources/ - Extracts entity pages (
wiki/entities/) and concept pages (wiki/concepts/) - Moves originals to
wiki/originals/after processing - Updates
wiki/index.mdandwiki/overview.mdautomatically - Supports
.mdand.txtnatively; delegates.pdf,.docx,.pptx,.xlsxto companion skills - Falls back to
scripts/file_to_markdown.pywhen companion skills are unavailable - Post-ingest validation: checks for broken wikilinks and missing index entries
- `/wiki-query` — query the knowledge base with natural language
- Reads
wiki/index.mdto identify relevant pages - Synthesizes answers with
[[wikilink]]citations - Falls back to
wiki/originals/for detail-heavy questions - Offers to save answers as synthesis pages in
wiki/syntheses/
- `/wiki-lint` — health-check the wiki
- Orphan page detection (no inbound wikilinks)
- Broken
[[wikilink]]detection - Missing entity page detection (entity mentioned 3+ times, no dedicated page)
- Contradiction detection across sources
- Stale summary detection
- Data gap suggestions
- Agent-based mode (no Python required) and Python script mode (
scripts/lint.py)
- `/wiki-graph` — build an interactive knowledge graph
- Extracts nodes from all wiki pages (sources, entities, concepts, syntheses)
- Extracts edges from
[[wikilinks]]and infers topical connections - Outputs
graph/graph.jsonand self-containedgraph/graph.html(vis.js) - Agent-based fallback when Python is unavailable
- Python script mode:
scripts/build_graph.py --open
- `scripts/build_graph.py` — standalone Python graph builder
- `scripts/lint.py` — standalone Python lint checker
- `scripts/file_to_markdown.py` — convert PDFs, Word docs, and Office files to
.md - `scripts/requirements.txt` — Python dependencies (
networkx) - `references/templates.md` — page templates for sources, entities, concepts, and syntheses
- `references/graph-html.md` — self-contained vis.js HTML template for graph output
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What This Repo Is
llm-wiki is a Claude Code skill — not a runnable app. It ships as SKILL.md (the agent instruction file) plus supporting Python scripts and reference files. Users install it into their Claude skills directory and invoke it via slash commands in their own wiki projects.
The repo itself is the skill distribution package, not a wiki.
Slash Commands (Skill Entry Points)
All commands are defined in SKILL.md:
| Command | Purpose |
|---|---|
| `/wiki-ingest [file\ | --from <folder>] [--to <folder>]` |
/wiki-query <question> | Query the wiki and present the answer |
/wiki-synthesize [slug] | Save the most recent query answer as a synthesis |
/wiki-lint | Health-check for broken links, orphans, contradictions |
/wiki-graph | Build interactive vis.js knowledge graph |
Python Scripts
Run from the project root of the user's wiki project (not from this repo):
# Lint
python scripts/lint.py
python scripts/lint.py --save # save report to wiki/lint-report.md
# Build graph
python scripts/build_graph.py --open # rebuild + open browser
python scripts/build_graph.py --report --save
# Convert non-markdown files to .md before ingesting
python scripts/file_to_markdown.py --input_dir raw/Install dependencies:
pip install -r scripts/requirements.txt # networkx, markitdown, tqdmArchitecture
SKILL.md ← agent instruction file (the actual skill)
scripts/
build_graph.py ← outputs graph/graph.json + graph/graph.html (vis.js)
lint.py ← structural + graph-aware health checks
file_to_markdown.py ← converts pdf/docx/pptx/xlsx → .md
requirements.txt
references/
templates.md ← page frontmatter templates (source/entity/concept/synthesis)
folder-managing.md ← PARA method rules used by --to flag
graph-html.md ← self-contained vis.js HTML template
wiki-hub/ ← WiKi-Hub extension (separate skill)The scripts fall back gracefully: networkx is optional in build_graph.py; agent-based fallbacks for all commands are defined in SKILL.md so Python is never required.
Wiki Directory Layout (User's Project)
When deployed, the skill manages this structure in the user's wiki project:
raw/ # Drop zone — files moved out after ingest
wiki/
index.md # Catalog (updated every ingest)
log.md # Append-only change log
overview.md # Living synthesis
originals/ # Read-only archive of source docs
sources/ # kebab-case.md — one summary per source
entities/ # TitleCase.md — people, orgs, products
concepts/ # TitleCase.md — ideas, frameworks, theories
syntheses/ # kebab-case.md — saved query answers
graph/ # graph.json + graph.htmlKey Invariants
wiki/log.mdis append-only — never edit past entrieswiki/originals/is read-only after ingest — never modify archived fileswiki/index.mdmust be updated on every ingest — stale index breaks/wiki-query- Wikilinks are case-sensitive:
[[OpenAI]]≠[[Openai]] - Source slugs in frontmatter
sources:must exactly match the source filename without extension graph/graph.htmlis self-contained — JSON is inlined, not loaded from disk- All scripts use
Path.cwd()as the repo root — run from the wiki project root, not from the scripts directory
Claude API Integration — Prompt Caching
When automating wiki workflows via the Claude API (e.g. batch ingestion scripts, CI pipelines), apply prompt caching to the skill content to avoid re-tokenizing on every call:
import anthropic
skill_content = open("SKILL.md").read()
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
system=[
{
"type": "text",
"text": skill_content,
"cache_control": {"type": "ephemeral"} # cache for up to 5 min
}
],
messages=[{"role": "user", "content": "/wiki-ingest raw/my-doc.md"}]
)When to include reference files in the cache block: only load the reference files that the current operation needs (e.g. add references/ingest-advanced.md content to the cached block for batch ingest jobs). Loading all reference files unconditionally wastes the cache budget.
Cache TTL: 5 minutes. For long-running batch jobs, re-create the client or re-send the system block before TTL expires to keep the cache warm.
See Anthropic prompt caching docs for full details.
---
PARA Folder Structure (--to flag)
When /wiki-ingest --to <folder> is used, the skill applies PARA categorization:
00_Inbox/01_Projects/02_Areas/03_Resources/04_Archives- Creates subfolder:
YYYYMMDD_<slug>_<ShortDescription>/ - Updates
source_filefrontmatter to point to new path instead ofwiki/originals/
GEMINI.md - LLM Wiki Project Context
This file provides instructional context for AI agents working within the LLM Wiki project.
Project Overview
LLM Wiki is an agent-maintained personal knowledge base framework designed for Claude Code. It automates the lifecycle of personal knowledge management: Ingest → Query → Lint → Graph.
- Purpose: To transform raw documents (PDFs, Word docs, Markdown, etc.) into a structured, searchable, and visualized wiki.
- Core Workflow:
1. Ingest: Convert and summarize raw files into wiki/sources/, extracting entities and concepts. 2. Query: Use the agent to synthesize answers across multiple wiki pages with citations. 3. Lint: Perform structural and semantic health checks (broken links, orphans, contradictions). 4. Graph: Generate an interactive HTML visualization of the knowledge network.
Key Components
- `SKILL.md`: Defines the agent's behavior and slash commands (
/wiki-ingest,/wiki-query,/wiki-synthesize,/wiki-lint,/wiki-graph). - `scripts/`: Python utilities for complex tasks:
lint.py: Structural and graph-aware wiki health checks.build_graph.py: Generatesgraph/graph.jsonandgraph/graph.html.file_to_markdown.py: Batch converts non-markdown files to.md.- `wiki/`: The core knowledge base:
sources/: Summaries of individual documents.entities/: Hub pages for people, projects, and organizations (TitleCase).concepts/: Hub pages for ideas, frameworks, and theories (TitleCase).originals/: Read-only archive of the original source files.- `references/`: Technical documentation and templates (
templates.md,folder-managing.md).
Setup & Commands
Prerequisites
- Python 3.10+ (optional but recommended for scripts).
- Claude Code with the
llm-wikiskill installed.
Installation
# Install the skill to Claude Code
npx skills add godstale/llm-wiki
# Install Python dependencies for scripts
pip install -r scripts/requirements.txtKey Commands
- Ingest:
/wiki-ingest raw/document.pdf(or use natural language: "ingest this file"). - Query:
/wiki-query "What are the core themes of X?" - Synthesize:
/wiki-synthesize— save the most recent query answer towiki/syntheses/. Run after/wiki-query. - Lint:
python scripts/lint.py --saveor/wiki-lint. - Graph:
python scripts/build_graph.py --openor/wiki-graph.
Development Conventions
Wiki Page Format
Every markdown file in the wiki/ directory MUST have YAML frontmatter:
---
title: "Page Title"
type: source | entity | concept | synthesis
tags: []
sources: [slug1, slug2]
last_updated: YYYY-MM-DD
---Use [[WikiLinks]] for internal navigation. Links are case-sensitive and should match the filename (without extension).
Naming Conventions
- Sources & Syntheses:
kebab-case.md(e.g.,market-research-2024.md). - Entities & Concepts:
TitleCase.md(e.g.,OpenAI.md,MachineLearning.md).
Folder Management (PARA)
When moving original files using the --to flag in /wiki-ingest, follow the PARA structure defined in references/folder-managing.md:
00_Inbox,01_Projects,02_Areas,03_Resources,04_Archives.- Filename format:
YYYYMMDD_Slug_Description.
Usage Guidelines for Agents
- Maintain Integrity: Never modify files in
wiki/originals/. - Update the Index: Always update
wiki/index.mdafter an ingestion. - Audit Links: Regularly run
/wiki-lintto fix broken[[WikiLinks]]. - Wiki-Hub Registry: If a
wiki-hub.mdfile exists at the root, treat it as the authoritative registry for external, imported wiki files. Do not overwrite or delete files tracked inwiki-hub.mdwithout warning the user. - Be Concise: Wiki summaries should be 2–4 sentences, focusing on key claims and connections.
MIT License
Copyright (c) 2026 Young-Bae Suh
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
llm-wiki (한국어 가이드)
Claude Code로 운영되는 개인 지식 베이스. 문서를 넣으면 Claude가 수집(ingest), 검색(query), 검사(lint), 시각화(graph)를 모두 처리합니다 — API 키나 별도 스크립트 없이도 동작합니다.
ingest → query → lint → graph---
목차
- 설치
- 프로젝트 구조
- 명령어 전체 목록
- /wiki-ingest — 문서 수집
- /wiki-query — 지식 검색
- /wiki-synthesize — 검색 결과 저장
- /wiki-lint — 위키 건강 검사
- /wiki-graph — 지식 그래프 시각화
- /wiki-sources — 수집 이력 조회
- /wiki-update — 소스 페이지 갱신
- /wiki-delete — 소스 페이지 삭제
- /wiki-ontology — 온톨로지 관리
- 페이지 형식
- Python 스크립트
- 주의사항
---
설치
npx로 설치 (권장)
npx skills add godstale/llm-wiki전역 Claude Code 스킬 디렉터리(~/.claude/skills/llm-wiki)에 설치됩니다.
프로젝트 단위로 설치하려면:
npx skills add godstale/llm-wiki --project수동 설치
# 전역 설치 (모든 프로젝트에서 사용 가능)
cp -r llm-wiki ~/.claude/skills/llm-wiki
# 프로젝트 단위 설치
cp -r llm-wiki .agents/skills/llm-wikiPython 의존성 (선택)
lint.py, build_graph.py 스크립트를 사용할 때만 필요합니다. Python 없이도 에이전트 기반 폴백으로 모든 기능이 동작합니다.
pip install -r ~/.claude/skills/llm-wiki/scripts/requirements.txt---
프로젝트 구조
스킬을 설치한 뒤 위키 프로젝트에 아래 디렉터리를 만들어두면 됩니다. 하위 디렉터리는 수집 과정에서 자동으로 생성됩니다.
raw/ # 드롭존 — 수집 전 원본 문서를 여기에 넣어 두세요
wiki/
index.md # 전체 페이지 카탈로그 (수집마다 자동 갱신)
log.md # 추가 전용 변경 이력
overview.md # 모든 소스를 아우르는 살아있는 요약
history.json # 수집한 소스 레지스트리
ontology.yaml # (선택) 프로젝트 온톨로지 스키마
synthesis-map.md # 저장된 검색 합성물 인덱스 (추가 전용)
originals/ # 원본 문서 읽기 전용 보관소
sources/ # 소스 요약 페이지 (kebab-case.md)
entities/ # 사람, 기업, 프로젝트, 제품 (TitleCase.md)
concepts/ # 아이디어, 프레임워크, 이론 (TitleCase.md)
syntheses/ # 저장된 검색 답변 (kebab-case.md)
graph/ # graph.json + graph.html (자동 생성)시작하려면 raw/와 wiki/만 만들면 됩니다.
---
명령어 전체 목록
| 명령어 | 설명 |
|---|---|
| `/wiki-ingest [파일\ | --from 폴더] [--to 폴더]` |
/wiki-query <질문> | 위키를 검색하고 답변 생성 |
/wiki-synthesize [slug] | 최근 검색 답변을 합성물로 저장 |
/wiki-lint | 깨진 링크, 고아 페이지, 모순 등 검사 |
/wiki-graph | 인터랙티브 지식 그래프 생성 |
/wiki-sources | 수집 이력 목록 조회 |
/wiki-update <slug> | 기존 소스 페이지 재처리 및 갱신 |
/wiki-delete <slug> | 소스 페이지 및 관련 페이지 삭제 |
/wiki-ontology-init | 온톨로지 스키마 초기화 |
/wiki-ontology-show | 현재 온톨로지 구조 출력 |
/wiki-ontology-validate | 위키 페이지와 온톨로지 정합성 검사 |
슬래시 명령어 외에 자연어로도 동작합니다:
- "raw/my-article.md 수집해줘"
- "query: 주요 테마가 뭐야?"
- "위키 검사해줘"
- "지식 그래프 만들어줘"
---
/wiki-ingest — 문서 수집
원본 문서를 읽어 위키 페이지를 생성하고 인덱스를 갱신합니다.
기본 사용법
/wiki-ingest raw/my-article.md # 파일 하나 수집
/wiki-ingest # raw/ 폴더 전체 일괄 수집옵션
| 옵션 | 설명 |
|---|---|
<file> | 단일 파일 수집 (예: raw/my-article.md) |
--from <folder> | raw/ 대신 다른 폴더를 소스로 사용 |
--to <folder> | 원본을 PARA 구조 하위 폴더에 복사 |
--no-copy | 원본 복사 생략 (--to와 함께 사용 불가) |
--force-new | 중복 슬러그도 새 항목으로 강제 생성 |
--force-update | 중복 슬러그를 기존 항목에 덮어쓰기 |
--no-interview | 온톨로지 Context Interview 건너뜀 |
--batch-defaults | 일괄 수집 시 첫 파일 인터뷰 답변을 이후 파일에 재사용 |
--summary-only | 전체 변환 없이 요약 및 메타데이터만 추출 |
지원 파일 형식
.md, .txt — 직접 처리 .pdf, .docx, .pptx, .xlsx — raw/에 넣으면 자동 변환 후 수집
수집 전략
| 조건 | 전략 |
|---|---|
--summary-only 플래그 | 요약만 추출 |
.xlsx / .xls | 요약만 추출 |
.pptx / .ppt | 요약만 추출 |
.pdf 30페이지 초과 | 요약만 추출 |
| 그 외 모든 파일 | 전체 내용 처리 |
중복 처리
wiki/history.json에서 슬러그 중복을 먼저 확인합니다:
- `--force-new`: 오늘 날짜를 붙여 새 항목 생성 (예:
my-article-20260421) - `--force-update`: 기존 항목 덮어쓰기
- 플래그 없을 때 중복 발견: 업데이트 / 새 항목 / 취소 중 선택 요청
- 삭제된 슬러그: 신규 수집으로 처리 (슬러그 재사용,
status: "active"설정)
수집 후 자동 처리 항목
1. wiki/sources/<slug>.md — 소스 요약 페이지 생성 2. wiki/originals/<slug>.md — 원본 보관 3. wiki/index.md — 카탈로그 갱신 (카테고리 분류) 4. wiki/overview.md — 전체 요약 갱신 5. wiki/entities/ — 관련 엔티티 페이지 생성/갱신 6. wiki/concepts/ — 관련 개념 페이지 생성/갱신 7. wiki/history.json — 수집 레지스트리 갱신 8. wiki/log.md — 변경 이력 추가
인덱스 카테고리 분류 기준
| 카테고리 | 내용 |
|---|---|
기술/개발 | 코드, 도구, API, 프로그래밍, 소프트웨어, 하드웨어, 개발 워크플로 |
업무/프로젝트 | 업무 회의, 직장 메모, 회사 프로젝트, 커리어 |
개인/생활 | 계정, ID, 비밀번호, 주소, 가족, 금융, 가정 |
여행 | 여행 계획, 트레킹, 교통, 숙박, 장소 |
임시메모 | 의미 있는 단어 10개 미만, 단편 스니펫, 모호한 컨텍스트 |
---
/wiki-query — 지식 검색
위키 전체를 읽고 질문에 대한 답변을 합성합니다.
/wiki-query 주요 소스들의 공통 테마는?
/wiki-query Claude API 프롬프트 캐싱 방법은?동작 방식
1. wiki/synthesis-map.md에서 관련 기존 합성물 탐색 2. wiki/index.md를 읽어 관련 페이지 파악 3. 관련 페이지 최대 10개 읽기 4. 요약이 부족하면 source_file 원본까지 읽기 5. [[PageName]] 위키링크 인용을 포함한 마크다운 답변 제공 6. ## Sources 섹션에 참조 페이지 목록 출력 7. 💾 이 답변을 저장하려면: /wiki-synthesize 안내 출력
고급 필터
구조적 필터(class:, type:, AND/OR/NOT, context.phase 같은 점 표기 필드 경로)는 references/query-advanced.md를 참조하세요.
---
/wiki-synthesize — 검색 결과 저장
가장 최근 /wiki-query 답변을 재사용 가능한 합성물 페이지로 저장합니다.
/wiki-synthesize # 자동 슬러그 생성
/wiki-synthesize my-custom-slug # 슬러그 직접 지정동작 방식
1. 현재 세션의 최근 쿼리 질문과 답변을 가져옴 2. 질문에서 kebab-case 슬러그 생성 (또는 지정 슬러그 사용) 3. 답변에서 엔티티, 개념, 관계 추출 4. wiki/syntheses/<slug>.md 작성 5. wiki/synthesis-map.md에 항목 추가 (추가 전용) 6. wiki/log.md에 이력 추가 7. 출력: ✅ Saved synthesis: [[syntheses/<slug>]]
세션 내에 쿼리가 없으면: "No query found in this session. Run `/wiki-query <question>` first."
---
/wiki-lint — 위키 건강 검사
/wiki-lint또는 Python 스크립트로:
python scripts/lint.py
python scripts/lint.py --save # wiki/lint-report.md에 저장검사 항목
| 항목 | 설명 |
|---|---|
| 고아 페이지 | 인바운드 [[링크]]가 없는 페이지 |
| 깨진 링크 | 존재하지 않는 페이지를 가리키는 [[위키링크]] |
| 누락 엔티티 페이지 | 3개 이상 페이지에서 언급되지만 전용 엔티티 페이지가 없는 이름 |
| 모순 | 소스 간 상충하는 주장 교차 검증 |
| 오래된 요약 | last_updated가 관련 개념/엔티티 페이지보다 오래된 소스 페이지 |
| 데이터 공백 | 위키가 답할 수 없는 질문과 필요한 소스 유형 제안 |
wiki/ontology.yaml이 있을 경우 온톨로지 관련 추가 검사(7~12개 항목)도 실행됩니다.
검사 완료 후 wiki/lint-report.md에 저장할지 물어봅니다.
---
/wiki-graph — 지식 그래프 시각화
위키 페이지와 위키링크 연결을 인터랙티브 HTML 그래프로 시각화합니다.
/wiki-graph또는 Python 스크립트로:
python scripts/build_graph.py --open # 재빌드 후 브라우저 열기
python scripts/build_graph.py --report --save # 보고서 포함 저장출력: graph/graph.json + graph/graph.html (vis.js 기반, 완전 독립 실행형)
노드 색상
| 타입 | 색상 |
|---|---|
source (소스) | #4CAF50 (녹색) |
entity (엔티티) | #2196F3 (파란색) |
concept (개념) | #FF9800 (주황색) |
synthesis (합성물) | #9C27B0 (보라색) |
---
/wiki-sources — 수집 이력 조회
수집된 모든 소스의 현황을 테이블로 출력합니다.
/wiki-sources출력 형식:
| Slug | Title | Ingested | Last Updated | Status |
|---|
각 활성 소스에 대해 생성된 페이지, 엔티티, 개념 수도 함께 표시됩니다.
---
/wiki-update — 소스 페이지 갱신
기존 소스를 다시 처리하여 소스 페이지, 엔티티, 개념을 갱신합니다.
/wiki-update my-article원본을 재보관하지 않고 소스 페이지를 덮어쓰며, 엔티티/개념 페이지는 병합 방식으로 갱신됩니다.
---
/wiki-delete — 소스 페이지 삭제
소스 페이지와 해당 소스에서만 참조되는 고아 엔티티/개념 페이지를 삭제합니다.
/wiki-delete my-article삭제 전에 삭제 대상 목록을 보여주고 확인을 요청합니다. wiki/history.json에는 감사 추적을 위해 항목이 유지되며 status: "deleted"로 표시됩니다.
삭제 후 /wiki-lint로 남은 깨진 링크를 확인하세요.
---
/wiki-ontology — 온톨로지 관리
온톨로지는 선택 기능입니다. wiki/ontology.yaml이 없으면 모든 명령어가 기본 방식으로 동작합니다.
| 명령어 | 설명 |
|---|---|
/wiki-ontology-init | 대화형 인터뷰로 wiki/ontology.yaml 생성 |
/wiki-ontology-show | 현재 온톨로지 구조와 클래스 목록 출력 |
/wiki-ontology-validate | 위키 페이지와 온톨로지 스키마 정합성 검사 |
온톨로지를 정의하면 수집 시 Context Interview가 실행되고, 엔티티/개념 페이지에 클래스 및 속성 메타데이터가 자동으로 추가됩니다. 그래프 시각화에서도 타입별 색상 구분과 단계(phase) 레인이 활성화됩니다.
자세한 내용은 references/ontology-commands.md를 참조하세요.
---
페이지 형식
모든 위키 페이지는 아래 프런트매터 형식을 사용합니다:
---
title: "페이지 제목"
type: source | entity | concept | synthesis
tags: []
sources: [] # 이 페이지와 관련된 소스 슬러그 목록
last_updated: YYYY-MM-DD
---페이지 간 연결은 [[PageName]] 위키링크를 사용합니다.
네이밍 규칙
| 타입 | 위치 | 네이밍 |
|---|---|---|
| 소스 | wiki/sources/ | kebab-case.md |
| 엔티티 | wiki/entities/ | TitleCase.md |
| 개념 | wiki/concepts/ | TitleCase.md |
| 합성물 | wiki/syntheses/ | kebab-case.md |
---
Python 스크립트
모든 스크립트는 위키 프로젝트 루트에서 실행해야 합니다.
# 마크다운 아닌 파일을 수집 전에 변환
python scripts/file_to_markdown.py --input_dir raw/
# 위키 건강 검사
python scripts/lint.py
python scripts/lint.py --save
# 지식 그래프 생성
python scripts/build_graph.py --open
python scripts/build_graph.py --report --save---
주의사항
- `raw/`는 드롭존 — 수집 후에도 파일이 그대로 남아 있습니다 (원본은
wiki/originals/로 복사됨) - `wiki/originals/`는 읽기 전용 — 수집 후 절대 수정하지 마세요
- `wiki/index.md`를 항상 최신 상태로 — 인덱스가 오래되면
/wiki-query가 제대로 동작하지 않습니다 - `wiki/log.md`는 추가 전용 — 과거 항목은 절대 편집하지 마세요
- `wiki/synthesis-map.md`는 추가 전용 — 과거 항목은 절대 편집하지 마세요
- 위키링크는 대소문자 구분 —
[[OpenAI]]와[[Openai]]는 다른 페이지입니다 - 소스 슬러그는 파일명과 일치 —
sources:프런트매터의 슬러그는 확장자 없는 소스 파일명과 정확히 일치해야 합니다 - 스크립트는 프로젝트 루트에서 실행 —
scripts/디렉터리 안에서 실행하면 경로 오류가 발생합니다 - `graph/graph.html`은 독립 실행형 — JSON이 인라인으로 포함되어 있어 별도 파일 없이 열립니다
---
확장 — WiKi-Hub
다른 사람의 위키를 현재 프로젝트에 병합할 수 있는 WiKi-Hub 스킬도 있습니다.
- GitHub: godstale/WiKi-Hub
- 설치:
npx skills add godstale/wiki-hub
---
라이선스
MIT
llm-wiki
An agent-maintained personal knowledge base for Claude Code. Drop in source documents, and Claude ingests, queries, lints, and visualizes your knowledge — no API key or Python scripts required.
한국어 가이드: README.ko.md
ingest → query → lint → graph---
Installation
Using npx (recommended)
npx skills add godstale/llm-wikiThis installs the skill to your global Claude Code skills directory (~/.claude/skills/llm-wiki).
To install at project level instead:
npx skills add godstale/llm-wiki --projectManual installation
# Global (available in all projects)
cp -r llm-wiki ~/.claude/skills/llm-wiki
# Project-level
cp -r llm-wiki .agents/skills/llm-wikiPython dependencies (optional)
Required only for the lint.py and build_graph.py scripts. The agent-based fallback works without them.
pip install -r ~/.claude/skills/llm-wiki/scripts/requirements.txt---
Project Setup
Create this directory structure once in your wiki project:
raw/ # Drop zone — place source documents here before ingesting
wiki/
index.md # Catalog of all pages (auto-maintained)
log.md # Append-only change log (auto-maintained)
overview.md # Living synthesis across all sources (auto-maintained)
originals/ # Full source docs after ingest — read-only archive
sources/ # One summary page per source document
entities/ # People, companies, projects, products
concepts/ # Ideas, frameworks, methods, theories
syntheses/ # Saved query answers
graph/ # Auto-generated graph data (graph.json, graph.html)You only need to create raw/ and wiki/ to start. Subdirectories are created automatically during ingest.
---
Usage
All commands work as slash commands or natural language in Claude Code.
Ingest a document
/wiki-ingest raw/my-article.md- Reads the source file
- Creates a summary page in
wiki/sources/ - Extracts and creates entity and concept pages
- Moves the original to
wiki/originals/ - Updates
wiki/index.mdandwiki/overview.md
Supported file types: .md, .txt. For .pdf, .docx, .pptx, .xlsx — place the file in raw/ and Claude will convert it automatically (requires the pdf, docx, pptx, or xlsx skill, or the file_to_markdown.py script as fallback).
Query the knowledge base
/wiki-query what are the main themes across all sources?- Reads the index to find relevant pages
- Synthesizes a markdown answer with
[[wikilink]]citations - Offers to save the answer as a synthesis page in
wiki/syntheses/
Lint the wiki
/wiki-lintChecks for:
- Orphan pages (no inbound links)
- Broken
[[wikilinks]] - Missing entity pages (mentioned 3+ times, no dedicated page)
- Contradictions between sources
- Stale summaries
- Data gaps
Option A — Python script (structural + graph-aware):
python scripts/lint.py
python scripts/lint.py --save # save report to wiki/lint-report.mdOption B — Agent-based (no Python needed): just run /wiki-lint.
Build the knowledge graph
/wiki-graphGenerates an interactive HTML visualization of all wiki pages and their wikilink connections.
Option A — Python script (preferred):
python scripts/build_graph.py --open
python scripts/build_graph.py --report --saveOutputs graph/graph.json and graph/graph.html, then opens in the browser.
Option B — Agent-based fallback: runs automatically when Python is unavailable.
---
Page Format
Every wiki page uses this frontmatter:
---
title: "Page Title"
type: source | entity | concept | synthesis
tags: []
sources: [] # list of source slugs that inform this page
last_updated: YYYY-MM-DD
---Use [[PageName]] wikilinks to link to other wiki pages.
Naming conventions
| Type | File location | Naming |
|---|---|---|
| Source | wiki/sources/ | kebab-case.md |
| Entity | wiki/entities/ | TitleCase.md |
| Concept | wiki/concepts/ | TitleCase.md |
| Synthesis | wiki/syntheses/ | kebab-case.md |
---
Natural language triggers
You don't have to use slash commands. Claude also responds to:
- "ingest raw/my-article.md"
- "query: what are the main themes?"
- "lint the wiki"
- "build the knowledge graph"
---
Utilities
Convert non-markdown files to .md before ingesting:
python scripts/file_to_markdown.py --input_dir raw/---
Gotchas
- `raw/` is a drop zone — files are moved to
wiki/originals/after ingest; only unprocessed files remain - Never modify `wiki/originals/` — read-only archive of source documents
- Always keep `wiki/index.md` up to date — stale index breaks
/wiki-query - Wikilinks are case-sensitive —
[[OpenAI]]≠[[Openai]] - Source slugs must match filenames — the slug in
sources:frontmatter must equal the source.mdfilename without extension - `wiki/log.md` is append-only — never edit past entries
- Scripts run from project root —
python scripts/build_graph.pymust be run from your wiki project directory
---
Extensions
WiKi-Hub
You can merge other people's wikis into your current project using the WiKi-Hub skill. This allows for seamless knowledge sharing and collaboration across different wiki repositories.
- GitHub Repository: godstale/WiKi-Hub
- Installation:
npx skills add godstale/wiki-hub
---
License
MIT
1. Folder Structure: The PARA Method
Organize folders by Actionability to maximize searchability and accessibility.
- 00_Inbox: A place to dump all unsorted files. Should be emptied regularly.
- 01_Projects: Active work with deadlines and specific goals. (e.g., 2026_NewProduct_Launch_Plan)
- 02_Areas: Ongoing responsibilities without deadlines that require continuous management. (e.g., Finance, Health, Self-Development)
- 03_Resources: Topics of interest you don't need now but may need later. (e.g., Design References, Reading Notes, Code Snippets)
- 04_Archives: Completed projects or materials no longer actively managed. Too valuable to delete, but no need to keep visible.
---
2. File Naming Rules: Search and Sort
Set naming rules so files can be found by sorting alone, without needing to search.
- Date goes first: Use
YYYYMMDDformat. - Bad: MeetingMinutes_Final.docx
- Good: 20260420_MeetingMinutes_v01.docx
- Use structured keywords: The name alone should hint at the content.
- Recommended format:
[Date]_[ProjectName]_[Description]_[Version] - Example:
20260420_MarketingPlan_Draft_v01.pdf - Version control: Use
v01,v02, etc. to avoid confusion from names like "final" or "realfinal".
---
3. Operating Routine (The Key)
Maintaining the habit matters more than the system itself.
1. Empty the Inbox every morning/evening: Move files from the desktop or downloads folder to their proper location (folders 01–04). 2. Keep it simple: Limit folder depth to 3–4 levels maximum. Too deep means too hard to find. 3. Optimize for search: Avoid special characters or complex symbols in folder names. Use intuitive, plain words.
Bonus Tip: When creating a file, ask yourself: "What keyword would I search for to find this a year from now?" That keyword should become the file name.
With this structure as a foundation, gradually adapt it to fit your own work environment — and you'll have a much more organized digital workspace.
Graph HTML Template
Self-contained vis.js page for graph/graph.html. Replace /* GRAPH_JSON_PLACEHOLDER */ with the actual graph.json content inlined as a JavaScript object.
<!DOCTYPE html>
<html>
<head>
<title>LLM Wiki Knowledge Graph</title>
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<style>
body { margin: 0; font-family: sans-serif; background: #1a1a1a; color: #eee; }
#graph { width: 100vw; height: 95vh; border: none; }
#controls { padding: 8px; background: #222; display: flex; gap: 12px; align-items: center; }
input { background: #333; color: #eee; border: 1px solid #555; padding: 4px 8px; border-radius: 4px; }
.legend { display: flex; gap: 10px; font-size: 13px; }
.legend span { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: 4px; vertical-align: middle; }
</style>
</head>
<body>
<div id="controls">
<input id="search" placeholder="Search nodes..." oninput="filterNodes(this.value)" />
<div class="legend">
<span style="background:#4CAF50"></span>source
<span style="background:#2196F3"></span>entity
<span style="background:#FF9800"></span>concept
<span style="background:#9C27B0"></span>synthesis
</div>
</div>
<div id="graph"></div>
<script>
const graphData = /* GRAPH_JSON_PLACEHOLDER */;
const nodes = new vis.DataSet(graphData.nodes.map(n => ({
id: n.id, label: n.label,
color: { background: n.color || '#9E9E9E', border: '#fff' },
font: { color: '#eee' }
})));
const edges = new vis.DataSet(graphData.edges.map(e => ({
from: e.from, to: e.to,
color: { color: e.color || '#555' },
dashes: e.type === 'INFERRED' || e.type === 'AMBIGUOUS',
title: e.type + (e.confidence ? ' (' + e.confidence + ')' : '')
})));
const network = new vis.Network(
document.getElementById('graph'),
{ nodes, edges },
{ physics: { stabilization: false }, interaction: { hover: true } }
);
function filterNodes(q) {
const lower = q.toLowerCase();
nodes.forEach(n => {
nodes.update({ id: n.id, hidden: !!(q && !n.label.toLowerCase().includes(lower)) });
});
}
</script>
</body>
</html>Ingest Advanced Reference
Loaded by the agent when /wiki-ingest is called with non-default flags or non-markdown input files.
---
Batch Mode
When no specific file is given (or --from <folder>):
1. Glob all files in source folder (non-recursive for raw/; recursive when --from is explicit) 2. For each file, compute slug and check wiki/history.json:
- `--force-new`: date-suffix slug (e.g.
my-article-20260421); skip prompt. If that slug also exists, increment counter (-20260421-2, etc.) - `--force-update`: overwrite existing entry; skip prompt
- Neither flag: skip files with existing active slug; log warning listing skipped files
3. Process each non-skipped file in sequence (single-file ingest steps) 4. Print summary: files processed / pages created / files skipped (with reason) / files copied
`--batch-defaults`: interview only the first file fully; reuse its answers as defaults for subsequent files, asking "use same defaults?" (yes/edit/skip) per file.
---
Destination Folder Rules (--to <folder>)
Applies PARA folder structure from references/folder-managing.md:
1. Determine PARA category from destination path or content:
00_Inbox·01_Projects·02_Areas·03_Resources·04_Archives- If
--topath already starts with00_–04_, use as-is - Otherwise ask the user which category applies (or infer from content if confident)
2. Create subfolder: YYYYMMDD_<slug>_<ShortDescription>/ inside the destination
- Example:
03_Resources/20260420_my-article_Reading-Notes/ - Use today's date for
YYYYMMDD
3. Copy original file(s) into that subfolder; set source_file frontmatter to the new path
4. Do NOT create or modify wiki/originals/ when --to is specified
---
Ingest Strategy Selection
| Priority | Condition | Strategy |
|---|---|---|
| 1 | --summary-only flag | summary-only |
| 2 | .xlsx or .xls | summary-only |
| 3 | .pptx or .ppt | summary-only |
| 4 | .pdf and page count > 30 | summary-only |
| 5 | Everything else | full |
Announce before proceeding: "Using summary-only strategy for `<filename>` (reason: <reason>)."
---
Full Strategy: Convert Non-text Files
1. Agent tools first — invoke the appropriate skill:
.docx/.doc→docxskill.pptx/.ppt→pptxskill.xlsx/.xls→xlsxskill.pdf→pdfskill
Save extracted text as <original-name>.md in the same raw/ directory.
2. Fallback: python tools/file_to_markdown.py --input_dir raw/
Proceed with Agent-Based Ingest once .md is available.
---
Summary-Only Ingest
For dense spreadsheets, large PDFs, presentation decks where raw content is not meaningful as prose.
1. Read the file directly with the appropriate skill (do not save a converted .md):
.xlsx/.xls→xlsxskill (sheet names, headers, row counts, key values).pptx/.ppt→pptxskill (slide titles, section headers, speaker notes).pdf→pdfskill (first 3 pages + TOC if present)
2. Extract metadata:
| Field | Source |
|---|---|
title | File name, title slide, or first heading |
purpose | Inferred from content type / section headers |
content_type | spreadsheet / presentation / spec / report / other |
author / team | Author field, metadata, path context |
created_at | File metadata, header date, or filename date pattern |
scope | What the document covers (subject, time period, teams, systems) |
sheet_names | (spreadsheets) list of sheet names |
slide_count | (presentations) number of slides |
sections | Top-level headings or sheet names as bullet list |
key_values | Up to 5 important data points visible without deep reading |
3. Write `wiki/sources/<slug>.md`:
---
title: "<Title>"
type: source
ingest_mode: summary-only
content_type: <spreadsheet|presentation|spec|report|other>
source_file: wiki/originals/<slug>.<ext>
created_at: <YYYY-MM-DD or blank>
author: <name or blank>
team: <team or blank>
tags: []
sources: []
last_updated: <YYYY-MM-DD>
---
## Purpose
<One paragraph: what this document is for and who uses it.>
## Scope
<Subject, time period, teams, systems.>
## Structure
<Bullet list of sheets / sections / slides with one-line descriptions.>
## Key Values
<Up to 5 important data points, figures, or decisions.>
## How to Use
Load the original file at `<source_file>` for full data.4. Skip deep entity/concept extraction — only create pages when a name is explicit and prominent (e.g. team name in the filename). Do not enumerate every cell reference.
5. Continue from ingest step 6 (copy original, update index, log).
When `/wiki-query` loads a summary-only source: the source page answers "what is this file and where is it." If the query requires actual data, read source_file on demand and answer from raw content — then optionally offer to update the source page with newly surfaced data.
---
Context Interview (ontology-aware)
Run after loading wiki/ontology.yaml (step 2a) and before writing the source page (step 5). Skip when wiki/ontology.yaml is absent or --no-interview is passed.
Procedure
1. Scan document for auto-inferable values:
artifact_type: match file patterns and content cues (e.g. "retrospective" → Meeting, "decision doc" → Decision, default → Document)authored_at: extract from date header, frontmatter, or filenameauthored_by: extract from explicit author line, email signature, or git metadatarelates_tocandidates: entities/concepts mentioned 2+ times that are in the wiki or ontology
2. Present inferred values and gaps:
🔍 Document Context Interview — raw/<filename>
Auto-detected (confirm or correct):
✓ artifact_type : Meeting (keyword match: "retrospective")
✓ authored_at : 2026-04-18 (from document header)
? authored_by : ? (not detected)
? phase : ? (ontology phases: Discover / Build / Validate)
? relates_to : detected mentions: TeamAlpha, SprintGoal-Q2
Please clarify (answer all or skip any):
Q1. 작성자는? Actor instance — [Alice, Bob, Carol] 또는 +new
Q2. Phase? [Discover / Build / Validate]
Q3. Activity instance? 예: sprint-12, design-review-01
Q4. 감지된 mentions의 관계?
- TeamAlpha → [part_of / owned_by / authored_by / skip]
- SprintGoal-Q2 → [achieves / references / part_of / skip]3. Inline schema validation — act immediately, do not defer:
- Phase not in
workflow.phases[].id→ warn; offer to pick an existing phase or add the new one to the ontology - Unknown
class:→ warn; show valid classes from the ontology; offer to correct or proceed as-is - Unknown
relations[].predicate→ warn; show valid predicates; offer to correct or proceed as-is - Missing required properties for the chosen
class:(fields listed inaxes.<Axis>.default_classes.<ClassName>.properties) → list the missing fields; offer to fill now or skip (will appear again in/wiki-ontology-validate) - New target names → offer: "`<name>` is new. Create stub page? (yes/no)" → on yes, create minimal page with "TODO" body
- Violations do not block ingest — all are collected and printed as a
⚠ Schema warningsblock at the end of ingest (step 5)
4. Write answers to source frontmatter under context: block — schema per references/ontology-commands.md (Page Frontmatter with Ontology section)
5. Ingest-time schema summary: After writing all pages for this source, if any violations were collected in step 3, print:
⚠ Schema warnings for <slug>:
- Unknown class `ClassName` — valid classes: [Person, Team, Role, ...]
- Missing required properties for Task: owner, deadline
- Unknown predicate `custom_rel` — valid predicates: [owns, produces, achieves, ...]
Run /wiki-ontology-validate for a full cross-wiki report.Omit this block entirely when there are no warnings.
6. Propagate to entity/concept pages: write inverse predicates where declared:
owns↔owned_by(bidirectional)part_of↔contains(bidirectional)achieves→ no declared inverse
---
Hierarchical Index Management
The wiki uses an N-level hierarchical categorization system for wiki/index.md.
Category Syntax
- Use
/as a separator for levels (e.g.,Hobby/Travel/SouthAmerica). - Case-sensitive; prefer TitleCase or established project terms.
Default Top-Level Categories (Level 1)
The skill provides these as the foundation. Always try to map new content to one of these first:
정치: 국내외 정치, 행정, 외교.경제/경영: 금융, 산업, 기업, 재테크.기술/과학: IT, AI, 기초과학, 우주, 환경.사회: 교육, 노동, 사건사고, 인구, 지역이슈.문화/생활: 예술, 여행, 건강, 라이프스타일.기타: 개인자료, 시스템/에이전트 관련 자료, 기타 미분류 자료.
Index Markdown Mapping
Map levels to Markdown headers in wiki/index.md:
- Level 1 (
Hobby) →## Hobby - Level 2 (
Hobby/Cycling) →### Cycling - Level 3 (
Hobby/Travel/SouthAmerica) →#### SouthAmerica - (and so on)
Management Rules
1. Dynamic Creation: If a specific sub-category (Level 2+) is required by content but doesn't exist, create it under the appropriate parent. 2. Modification: If a category path changes, update all entries under that section and move the section header. 3. Deletion: If a category section becomes empty after a deletion, remove the header. 4. Maintenance: Always maintain entries as - [Title](sources/slug.md) — mandatory summary under the most specific matching header.
---
Argument Parsing Rules
- File path (has extension or resolves to a file) → single-file ingest
- Folder path (no extension, resolves to a directory) → treat as
--from <folder> --fromand--tocan be combined with a single file path--no-copy+--totogether → warn the user and abort--force-new+--force-updatetogether → warn the user and abort--summary-onlyis compatible with all other flags
---
history.json Entry Schema
Written in step 12 of Agent-Based Ingest. Always use the Write tool — read existing file first, merge the entry, then overwrite.
{
"<slug>": {
"slug": "<slug>",
"title": "Page Title",
"ingested_at": "ISO8601",
"last_updated": "ISO8601",
"source_file": "wiki/originals/<slug>.md",
"pages_created": ["sources/<slug>.md"],
"entities_created": ["entities/EntityName.md"],
"concepts_created": ["concepts/ConceptName.md"],
"ingest_mode": "full|summary-only",
"status": "active"
}
}| Field | Description |
|---|---|
ingested_at | Set only on first ingest; never overwritten |
last_updated | Updated on every ingest/update |
entities_created | Paths relative to wiki/ |
status | "active" or "deleted" — never remove deleted entries |
Ontology Commands Reference
Loaded when running /wiki-ontology-init, /wiki-ontology-show, /wiki-ontology-validate, or when ontology-aware checks are needed in /wiki-lint or /wiki-graph.
---
/wiki-ontology-init
Interactive ontology builder. Produces wiki/ontology.yaml + wiki/ontology-guide.md.
Arguments:
- (none) → full interview (Stages 0–8)
--edit <stage>→ revisit one stage (project,actor,activity,artifact,objective,resource,context,workflow,relations)--regen-guide→ only rewritewiki/ontology-guide.mdfrom existingwiki/ontology.yaml--from-template→ copyreferences/ontology-template.yamlverbatim; skip interview
Flow:
1. Read references/ontology-template.yaml (skeleton) and references/ontology-interview.md (full interview script — follow it precisely) 2. If wiki/ontology.yaml exists and no flags → ask: (a) edit a stage, (b) full re-interview (overwrites), (c) cancel 3. Run interview per references/ontology-interview.md:
- Stage 0: Project Profiling (type, name, description, period)
- Stage 1: Actor Axis
- Stage 2: Activity Axis + workflow phases
- Stage 3: Artifact Axis
- Stage 4: Objective Axis
- Stage 5: Resource Axis (off by default)
- Stage 6: Context Axis (off by default)
- Stage 7: Relations Confirmation
- Stage 8: Review & Save
4. Write wiki/ontology.yaml (Write tool — never shell echo) and wiki/ontology-guide.md 5. Append to wiki/log.md: ## [YYYY-MM-DD] ontology-init | <N> classes, <M> relations, workflow=<phase_count> 6. Offer to create stub entity/concept pages for named instances given during interview
Output:
✅ Ontology saved to wiki/ontology.yaml
✅ Guide saved to wiki/ontology-guide.md
Active axes: Actor, Activity, Artifact, Objective
Classes: 14 | Relations: 11 | Phases: 5
Next: /wiki-ingest | /wiki-ontology-validate | /wiki-ontology-init --edit <stage>---
/wiki-ontology-show
1. If wiki/ontology.yaml absent → "No ontology configured. Run `/wiki-ontology-init` to create one (optional — the wiki works without it)." 2. Read wiki/ontology.yaml and render:
Project: <name> (<type>) — <description>
Period: <start> → <end>
Active Axes & Classes:
Actor : Person, Team, Role
Activity : Task, Phase, Meeting, Decision
Artifact : Document, Deliverable
Objective: Goal, Milestone, Risk
(Resource: off)
(Context : off)
Workflow: Discover → Design → Build → Validate → Release
Relations: owns, produces, consumes, achieves, part_of, precedes, authored_by, based_on3. Tail with instance counts: "14 entities, 6 concepts currently tagged with a class." 4. No wiki/log.md append (read-only command).
---
/wiki-ontology-validate
(... existing validate content ...)
---
/wiki-ingest-ontology
Extracts structured knowledge from a source document into a machine-readable YAML file.
Arguments:
<file>→ path to the source document.--schema <type>→ (optional) specific domain schema.
Flow:
1. Preparation: Read the source file and references/ontology-data-template.yaml. 2. Knowledge Extraction:
- Identify domain entities (tools, libraries, components).
- Identify domain concepts (theories, skills, patterns).
- Map relationships (X is part of Y, X requires Z).
- If
--schema roadmapis used, prioritize extraction of 'Phases', 'Topics', and 'IDE/Tools' as seen in developer roadmaps.
3. Storage:
- Generate a slug from the filename.
- Write
wiki/ontologies/<slug>.yamlusing the universal template.
4. Registration:
- Check if
wiki/ontology-registry.mdexists. Create it if not. - Append the new entry:
- [[<slug>]] — Knowledge data extracted from [[sources/<slug>]].
5. Log: Append to wiki/log.md: ## [YYYY-MM-DD] ontology-ingest | <slug>.
Output:
✅ Knowledge extraction complete.
✅ Data saved to: wiki/ontologies/<slug>.yaml
✅ Registered in: wiki/ontology-registry.md
Next: Run /wiki-query to use this data in analysis.---
Ontology Checks for /wiki-lint (checks 7–12)
Run only when wiki/ontology.yaml exists. Add to the lint report after standard checks 1–6.
7. Unknown class (ERROR) — class: values not in any axis's default_classes 8. Unknown predicate (ERROR) — relations[].predicate not declared in relations: block 9. Unknown phase (ERROR) — context.phase not in workflow.phases[].id 10. Domain/range violation (ERROR) — source class not in predicate's domain, or target class not in range
- Example:
{predicate: produces}onclass: Document—producesexpectsdomain: [Activity]
11. Missing required properties (WARNING) — instances with a declared class: that are missing properties listed in that class's properties: array. Report each missing field by name (e.g. "Task wiki/entities/TaskX.md missing: owner, deadline"). 12. Workflow gaps (WARNING) — Activity instances with no context.phase, or phases with zero instances
Ontology Violations Report Format
## Ontology Violations
### Errors (N) — schema contract broken
- Unknown class `ClassName` in `wiki/entities/Foo.md`
- Unknown predicate `custom_relation` in `wiki/sources/bar.md`
- Unknown phase `Shipping` in `wiki/sources/baz.md` (declared phases: Discover, Build, Validate)
- Domain violation: `{predicate: produces}` on `wiki/entities/TeamAlpha.md` (class: Team) — expects domain [Activity]
### Warnings (M) — data gaps
- Missing property `owner` on Task instance `wiki/entities/TaskX.md`
- Missing property `deadline` on Task instance `wiki/entities/TaskX.md`
- Phase `Validate` has no associated Activity instances---
Ontology-Aware Graph Building (/wiki-graph)
When wiki/ontology.yaml exists, override type-based node coloring with axis-based colors:
| Axis | Color |
|---|---|
| Actor | #1976D2 |
| Activity | #388E3C |
| Artifact | #F57C00 |
| Objective | #7B1FA2 |
| Resource | #5D4037 |
| Context | #546E7A |
- Set
group= axis name (enables vis.js clustering by axis) - Add
phaseto the node (for phase-labeled lane positioning when workflow is declared)
Typed edges (from relations: and context.relates_to frontmatter arrays):
{ "from": "<source id>", "to": "<target id>", "type": "typed", "predicate": "owns", "label": "owns" }When a predicate has a declared inverse, draw a single directed edge — do not create a duplicate reverse edge.
graph.json extended format when ontology is active:
{ "nodes": [...], "edges": [...], "ontology_active": true, "phases": ["Discover","Build","Validate"], "built": "YYYY-MM-DD" }---
Ontology-Specific Gotchas
- Ontology is opt-in — every command works without
wiki/ontology.yaml; ontology features are additive - Never edit `wiki/ontology.yaml` silently — only
/wiki-ontology-initand--editmay modify it - `ontology-guide.md` is derived — regenerated from
ontology.yaml; direct edits are lost on--regen-guide - Unknown classes/predicates do not block ingest — printed as inline
⚠ Schema warningsat end of ingest; full report at/wiki-ontology-validate - Context Interview answers belong in `context:`, not in the page body — do not duplicate into narrative sections
- `--summary-only` sources are read on demand by `/wiki-query` — original file is the authoritative data source
- Entity/concept frontmatter is derived from the ontology, not from fixed templates — field names must match the class's
properties:array inwiki/ontology.yaml
---
Schema Migration
When you change wiki/ontology.yaml (rename a class, remove a property, change predicate domain/range, modify phase ids):
1. Increment project.schema_version in wiki/ontology.yaml 2. Run /wiki-ontology-validate — it lists all pages that now violate the updated schema 3. For each ERROR: update the page frontmatter, or run /wiki-update <slug> to re-derive from the original source 4. For each WARNING: fill missing properties directly on the page, or leave for later 5. Append to wiki/log.md: ## [YYYY-MM-DD] schema-migration | v<N> → v<N+1>: <what changed>
Breaking changes (must migrate): class rename or removal, property rename or removal, predicate rename or removal, phase id change. Non-breaking changes (no migration needed): adding a new class, property, predicate, or phase; changing descriptions.
---
Page Frontmatter with Ontology
When wiki/ontology.yaml is active, the ontology class definition is the authoritative schema for entity and concept pages. Derive field names from axes.<Axis>.default_classes.<ClassName>.properties — do not invent fields not declared there.
Source page — context: block
Added by /wiki-ingest during the Context Interview:
---
title: "Sprint 12 Retrospective"
type: source
class: Meeting # ontology class name
tags: [meeting]
date: 2026-04-18
source_file: wiki/originals/sprint12-retro.md
sources: []
last_updated: 2026-04-18
context:
authored_by: Alice # Actor instance name (must match entity page)
authored_at: 2026-04-18
phase: Build # workflow.phases[].id value
activity: sprint-12 # Activity instance name
artifact_type: Meeting # class from Artifact or Activity axis
relates_to:
- {target: TeamAlpha, predicate: part_of}
- {target: SprintGoal-Q2, predicate: achieves}
---Entity page — class: and relations: blocks
---
title: "TeamAlpha"
type: entity
class: Team # must match a class in wiki/ontology.yaml
tags: []
sources: [sprint12-retro, design-doc-v2]
last_updated: 2026-04-18
properties: # fields from class's properties: array
lead: Alice
domain: backend-services
relations:
- {predicate: owns, target: TaskX}
- {predicate: part_of, target: ProjectAlpha}
---Concept page — same extension pattern
---
title: "SprintGoal-Q2"
type: concept
class: Goal # typically from Objective or Context axis
sources: [sprint12-retro]
last_updated: 2026-04-18
properties:
parent_goal: YearlyOKR-2026
target_date: 2026-06-30
metric: "<measurable target>"
status: on-track
relations:
- {predicate: part_of, target: YearlyOKR-2026}
---Field rules
class:must match a class name declared inwiki/ontology.yamlunder some axis'sdefault_classes.relations[].predicatemust match a key underrelations:inwiki/ontology.yaml.relations[].targetis an entity/concept name — case-sensitive, must match the page filename without extension.context.phasemust match aworkflow.phases[].idwhen phases are declared.- All ontology fields are optional — omitting them degrades gracefully to non-ontology behavior.
- Unknown values are not an ingest-time error; they produce inline
⚠ Schema warningsand are fully reported by/wiki-ontology-validate.
# ============================================================
# Universal Ontology Data Template — LLM Wiki
# ============================================================
# This template defines the structure for individual knowledge
# data files generated via `/wiki-ingest-ontology`.
#
# These files live in `wiki/ontologies/<slug>.yaml`.
# ============================================================
version: 1
source_slug: "<original-source-slug>"
title: "<Title of the Knowledge Domain>"
last_updated: "YYYY-MM-DD"
# ---------- 1. Entities (WHO/WHAT) ----------
# Tangible objects, people, tools, organizations, etc.
entities:
- id: "unique-id-kebab-case"
label: "Display Name"
class: "ClassName" # Must match a class in wiki/ontology.yaml if exists
properties:
# Key-value pairs specific to this entity
# e.g., category: "Testing", version: "1.0"
description: "Brief description of the entity"
# ---------- 2. Concepts (IDEAS/METHODS) ----------
# Abstract ideas, frameworks, skills, goals, etc.
concepts:
- id: "unique-id-kebab-case"
label: "Display Name"
class: "ClassName"
properties:
# Key-value pairs specific to this concept
description: "Brief explanation of the concept"
# ---------- 3. Relationships (CONNECTIONS) ----------
# How the entities and concepts are linked.
relationships:
- source: "subject-id"
predicate: "predicate_name" # e.g., part_of, requires, leads_to
target: "object-id"
metadata:
# Optional context for the relationship
strength: "primary | secondary"
context: "Brief reason for connection"
# ---------- 4. Metadata & Tags ----------
tags: []
metadata:
original_file: "path/to/original"
confidence_score: 0.0 # Agent's confidence in extraction
Ontology Init Interview Script
Detailed conversation flow for /wiki-ontology-init. The agent should follow these stages in order, but may shorten or skip stages when the user's answers make later questions unnecessary.
Global rules
- Load the template first. Read
references/ontology-template.yamland use its structure as the skeleton. Every question maps to a section of the output YAML. - Default-heavy, user-lean. Always propose a default and ask "OK? / change? / skip?" instead of open-ended questions when possible.
- Progressive disclosure. Complete one stage, show a mini-summary, then ask "Continue to next stage?" — the user can stop and resume later.
- Idempotent. If
wiki/ontology.yamlalready exists, read it first and treat the interview as an edit session. Offer the user "Which stage do you want to revisit?" instead of starting from scratch. - Example-driven. When asking about a class or relation, show 1–2 concrete examples tailored to the user's project type (from Stage 0).
- Write incrementally. Save progress to
wiki/ontology.yamlafter each stage, so an interrupted session can resume.
---
Running Example
All "Dialogue example" blocks below follow the same scenario for coherence:
- Project: QuickNotes — a small SaaS team building a note-taking app
- Users: 5-person team (PM, 2 engineers, 1 designer, 1 QA)
- Timeline: 2026-04 → 2026-10 (MVP to public launch)
When the user's project differs, adapt the examples but keep the same shape (propose → confirm → record).
Legend for dialogue blocks:
💬 Agent — the question or proposal
✍️ User — a plausible answer
⚙️ Action — what the agent records to ontology.yaml (and optionally commits to disk)---
Stage 0 — Project Profiling
Purpose: Identify project type so later stages can tailor questions and defaults.
Questions:
1. "이 위키를 어떤 프로젝트의 지식베이스로 사용하시나요?
- (a) software-project — 소프트웨어 개발
- (b) research — 연구/논문 작성
- (c) product — 제품 기획·운영
- (d) campaign — 마케팅/캠페인
- (e) operations — 조직 운영/상시 업무
- (f) personal — 개인 학습/독서 노트
- (g) other — 자유 기술"
2. "프로젝트 이름과 한 문장 설명을 알려주세요."
3. "기간이 정해져 있나요? (start_date, end_date — ongoing이면 각각 null)"
Output (partial ontology.yaml):
version: 1
project:
name: "..."
type: "..."
description: "..."
start_date: ...
end_date: ...Type-based defaults the agent should apply in later stages:
| type | Actor focus | Activity focus | Artifact focus | Objective focus | Resource | Context |
|---|---|---|---|---|---|---|
| software-project | Team, Role | Task, Phase | CodeArtifact, Deliverable | Requirement, Milestone | off | on (Technology) |
| research | Person | Experiment*, Phase | Report, Design | Goal, KPI | off | on (Domain) |
| product | Team, Stakeholder | Task, Decision | Document, Deliverable | Goal, KPI | on | off |
| campaign | Team, Stakeholder | Event, Task | Report, Design | KPI | on | off |
| operations | Role, Team | Meeting, Decision | Report | KPI, Risk | on | off |
| personal | Person | — | Document | Goal | off | off |
| other | all off; ask individually |
*Add Experiment as a custom Activity class when type=research.
Offer these defaults explicitly: "For a <type> project, I suggest activating: <axes>. Keep these defaults or customize?"
Dialogue example
💬 Agent: 이 위키를 어떤 프로젝트의 지식베이스로 사용하시나요? (a) software-project / (b) research / (c) product / (d) campaign / (e) operations / (f) personal / (g) other
>
✍️ User: a. 사실은 제품이기도 한데 코드 중심이라 software-project 쪽이 맞아요.
>
💬 Agent: 이해했습니다. software-project로 진행하겠습니다. 프로젝트 이름과 한 문장 설명은요?
>
✍️ User: QuickNotes — 팀원 5명이 만드는 SaaS 메모 앱입니다.
>
💬 Agent: 기간은요? (시작·종료일, ongoing이면 각각 null)
>
✍️ User: 2026-04-01 시작, 10월 말 퍼블릭 런칭 예정.
>
⚙️ Action: write partial ontology.yaml:>
```yaml
version: 1
project:
name: "QuickNotes"
type: "software-project"
description: "5-person team building a SaaS note-taking app"
start_date: 2026-04-01
end_date: 2026-10-31
```
>
💬 Agent: software-project에 대한 기본 구성은 Actor: Team·Role / Activity: Task·Phase / Artifact: CodeArtifact·Deliverable / Objective: Requirement·Milestone / Context: Technology 입니다. Resource(Budget/Tool)는 기본 off입니다. 이대로 진행할까요, 아니면 수정하시겠어요?
>
✍️ User: 예산은 추적 안 해도 되는데 Tool(쓰는 서비스들)은 기록하고 싶어요.
>
⚙️ Action: MarkResource.active = truewith onlyToolclass enabled in Stage 5; continue.
---
Stage 1 — Actor Axis (WHO)
Purpose: Define the subjects that own, act, and decide.
Questions:
1. "이 프로젝트에 참여하는 주체 중 위키에서 추적하고 싶은 것을 골라주세요. 기본 제공: Person, Team, Role, Organization, Stakeholder.
- 사용할 클래스에 ✓
- 빼고 싶은 것 표시
- 추가할 커스텀 클래스가 있나요? (예: Vendor, Customer, Reviewer)"
2. For each activated class, ask: "이 클래스에 어떤 속성이 필요한가요? 기본값은 <default properties> 입니다. 유지/추가/삭제?"
3. (Seed instances — optional) "현재 알고 있는 팀이나 핵심 인물을 2~3명 예시로 알려주시겠어요? 이름, 역할, 소속 정도면 됩니다. 나중에 채워 넣어도 괜찮습니다."
- If answered: create seed pages in
wiki/entities/withclass:frontmatter. - If skipped: move on.
Output: populated axes.Actor.default_classes in ontology.yaml, optionally seed entity files.
Dialogue example
💬 Agent: 이 프로젝트에서 추적할 주체를 고르세요. 기본: Person, Team, Role (Organization, Stakeholder는 5인 팀에는 과할 수 있어 일단 빼두었습니다). 어떤가요?
>
✍️ User: Person은 필요 없을 것 같아요 — 5명이라 Role이면 충분해요. Team도 하나뿐이라 빼죠.
>
💬 Agent: 그럼 Role 하나만 남기겠습니다. 속성은 기본값 [responsibilities, reports_to] 입니다. 유지할까요?>
✍️ User:reports_to는 빼고
>
💬 Agent: 알겠습니다. 지금 알고 있는 역할 2~3개 예시로 알려주시겠어요? (건너뛰어도 됩니다)
>
✍️ User: PM: 민수 / Eng-Lead: 지영 / Designer: 수빈
>
⚙️ Action: update ontology:
>
```yaml
axes:
Actor:
active: true
default_classes:
Role: {properties: [responsibilities, email], folder: entities}
```
>
그리고wiki/entities/PM.md,Eng-Lead.md,Designer.md3개 seed 파일을class: Role+properties: {email, responsibilities}뼈대로 생성.
---
Stage 2 — Activity Axis (WHAT HAPPENS)
Purpose: Define work units and temporal structure.
Questions:
1. "큰 단계(phase) 가 있나요? 있다면 순서대로 알려주세요. 예) Discover → Design → Build → Validate → Release."
- If yes: populate
workflow.phaseswith{id, order}. - If no: leave
workflow.phases: [].
2. "일상적으로 다루는 작업 단위가 뭔가요?
- Task / Ticket / Story / Experiment / Sprint 등
- 어떤 속성이 필요한가요? (owner, deadline, status, priority가 기본)"
3. "Meeting, Decision 로그를 남기나요?"
- yes → activate Meeting, Decision
- no → remove from defaults
4. "Event 클래스가 필요한가요? (예: 런칭일, 발표회, 컨퍼런스 등)"
Output: populated axes.Activity.default_classes and workflow.phases.
Dialogue example
💬 Agent: 큰 단계(phase)가 있나요? software-project 기본 제안: Discover → Design → Build → Validate → Release.
>
✍️ User: 좀 달라요 — Design은 Build랑 겹쳐서 같이 가고, 그 대신 Alpha → Beta → GA 이렇게 가요. 앞에 Planning 하나 더요.
>
💬 Agent: 네, Planning → Alpha → Beta → GA 4단계로 기록합니다.
>
✍️ User: 그게 좋겠어요.
>
💬 Agent: 일상 작업 단위는요? 기본: Task — [owner, status, deadline, priority].>
✍️ User: 우리는 Jira 티켓 단위라 Ticket이 맞겠네요. 속성에 ticket_id 추가해주세요.>
💬 Agent:Task대신Ticket클래스로 저장하고 속성은[ticket_id, owner, status, deadline, priority].
>
💬 Agent: Meeting / Decision 로그를 남기시나요?
>
✍️ User: Decision만요. 회의록은 매번 남기기 부담스러워서.
>
💬 Agent: Event 클래스는요? (런칭일, 데모데이 같은 거요)
>
✍️ User: GA 런칭 이벤트가 있으니 넣어주세요.
>
⚙️ Action: update ontology:
>
```yaml
axes:
Activity:
active: true
default_classes:
Ticket: {properties: [ticket_id, owner, status, deadline, priority], folder: entities}
Phase: {properties: [starts_at, ends_at, order], folder: entities}
Decision: {properties: [made_by, made_at, rationale, alternatives], folder: entities}
Event: {properties: [date, type], folder: entities}
workflow:
phases:
- {id: planning, order: 1}
- {id: alpha, order: 2}
- {id: beta, order: 3}
- {id: ga, order: 4}
```
---
Stage 3 — Artifact Axis (OUTPUTS)
Purpose: Define the documents and deliverables the project produces.
Questions:
1. "이 프로젝트에서 만들어지는 주요 산출물 유형은? 기본 제공: Document, Deliverable, CodeArtifact, Design, Report.
- 사용할 것 선택
- 추가 커스텀 (예: Contract, Prototype, Dataset)"
2. "산출물에 life-cycle(상태)이 있나요? 기본: draft → review → approved → published.
- 그대로 사용 / 커스텀 / 생략"
3. "속성 확정 — 각 Artifact 클래스의 필수 필드를 확인하세요 (author, date, version, status 등)."
Output: populated axes.Artifact.default_classes.
Dialogue example
💬 Agent: software-project 기본 산출물: CodeArtifact, Deliverable, Document. 여기에 디자인도 중요하니 Design을 추가 권장. Report는 잘 안 쓰일 것 같아 기본 제외했어요.
>
✍️ User: 네 그게 맞아요. Dataset은 없으니 추가 안 해도 돼요.
>
💬 Agent: 산출물 life-cycle(상태)은 기본draft → review → approved → published인데, 코드 중심 프로젝트는 보통draft → review → merged → released쪽을 많이 쓰시는데 바꿀까요?
>
✍️ User: 후자가 맞아요. released는 사실상 태깅된 릴리즈고 merged는 PR 머지죠.>
💬 Agent: CodeArtifact 속성은 기본 [repo, path, owner, language] — 추가·수정할 부분 있나요?>
✍️ User: pr_url 추가해주세요. 어느 PR에서 나왔는지 보려고요.>
⚙️ Action: update ontology:
>
```yaml
axes:
Artifact:
active: true
default_classes:
CodeArtifact: {properties: [repo, path, owner, language, pr_url], folder: entities}
Deliverable: {properties: [produced_by, consumed_by, status, acceptance_criteria], folder: entities}
Design: {properties: [author, iteration, format], folder: entities}
Document: {properties: [author, date, version, status], folder: entities}
lifecycle: [draft, review, merged, released]
```
---
Stage 4 — Objective Axis (WHY)
Purpose: Goal hierarchy and risk tracking.
Questions:
1. "목표 계층이 있나요? 기본 제공: Goal, Requirement, Milestone, KPI, Risk.
- 전체 계층 사용 / 일부만 / 전부 생략"
2. (Goal이 활성화되면) "최상위 목표 1~3개를 알려주시겠어요? 나중에 추가해도 됩니다."
3. "Risk 추적이 필요한가요? (probability, impact, mitigation 속성이 기본으로 들어갑니다)"
Output: populated axes.Objective.default_classes, seed Goal pages in wiki/concepts/ optionally.
Dialogue example
💬 Agent: software-project 기본 목표 계층: Requirement, Milestone. Goal은 상위 개념(예: 제품 비전), KPI는 지표 중심. Risk는 별도 질문.
>
✍️ User: Goal은 있어야 해요 — "MVP to public launch"가 최상위 goal이에요. Requirement랑 Milestone도 다 써요. KPI는 데이터가 없으니 일단 제외.
>
💬 Agent: 최상위 Goal을 1~3개 등록해둘까요? 나중에 추가해도 됩니다.
>
✍️ User: "Ship QuickNotes GA by 2026-10-31", "5k DAU in 3 months post-launch" 두 개.
>
💬 Agent: Risk 추적은요? (probability/impact/mitigation 속성 자동 포함)
>
✍️ User: 네 필요해요. 5인 팀이라 리스크 관리가 중요하거든요.
>
⚙️ Action: update ontology and seed goal pages:
>
```yaml
axes:
Objective:
active: true
default_classes:
Goal: {properties: [parent_goal, target_date, metric, status], folder: concepts}
Requirement: {properties: [priority, source, status, acceptance_criteria], folder: concepts}
Milestone: {properties: [date, exit_criteria, status], folder: concepts}
Risk: {properties: [probability, impact, mitigation, owner], folder: concepts}
```
>
그리고wiki/concepts/ShipQuickNotesGA.md,5kDAUPostLaunch.md2개 seed 파일을class: Goal+properties: {target_date}로 생성.
---
Stage 5 — Resource Axis (WITH WHAT)
Purpose: Budget, tools, assets. Default OFF.
Questions:
1. "예산을 추적하나요? (Budget 클래스 — amount, currency, period, owner)" 2. "도구/라이선스를 추적하나요? (Tool 클래스 — vendor, license, cost)" 3. "고정 자산을 추적하나요? (Asset 클래스 — type, location, owner)"
If all three are no: keep axes.Resource.active: false. If any yes: set active: true and activate only the requested classes.
Dialogue example
💬 Agent: Stage 0에서 Tool은 추적하겠다고 하셨죠. Budget과 Asset은요?
>
✍️ User: Budget은 회계팀 건이라 빼고, Asset도 없어요. Tool만요.
>
💬 Agent: Tool 속성 기본값은 [vendor, license, cost, owner]입니다. 그대로 쓸까요?>
✍️ User:cost는 빼고url추가해주세요 — 각 서비스 링크 남기고 싶어서요.
>
⚙️ Action:
>
```yaml
axes:
Resource:
active: true
default_classes:
Tool: {properties: [vendor, license, url, owner], folder: entities}
```
---
Stage 6 — Context Axis (BACKGROUND)
Purpose: Domain / technology / constraints. Default OFF.
Questions:
1. "여러 도메인(산업/분야)을 넘나드는 프로젝트인가요? → Domain 클래스" 2. "기술 스택을 명시적으로 추적하나요? → Technology 클래스" 3. "외부 제약(법률, 규제, 시간)을 문서화해야 하나요? → Constraint 클래스"
Activate only what the user says yes to.
Dialogue example
💬 Agent: software-project는 기본적으로 Technology 클래스 추천합니다. 단일 도메인이면 Domain은 필요 없고, Constraint는 컴플라이언스가 있을 때만.
>
✍️ User: SaaS라 개인정보보호(GDPR)는 대비해야 해요. Technology는 당연히 필요하고 Domain은 필요 없어요.
>
💬 Agent: Technology + Constraint 활성화합니다. Technology 속성 기본 [category, version, vendor] 유지?>
✍️ User: 네.
>
⚙️ Action:
>
```yaml
axes:
Context:
active: true
default_classes:
Technology: {properties: [category, version, vendor], folder: concepts}
Constraint: {properties: [type, source, hard_or_soft], folder: concepts}
```
---
Stage 7 — Relations Confirmation
Purpose: Filter the default predicate vocabulary.
Presentation: Show a table of all predicates from references/ontology-template.yaml, with the ones whose domain/range reference only inactive classes pre-marked as "hide".
Example (rendered to user):
Active predicates for your project:
[✓] owns (Actor → Activity/Artifact/Objective)
[✓] produces (Activity → Artifact)
[✓] achieves (Activity/Artifact → Objective)
[✓] precedes (Activity → Activity)
[✓] authored_by (Artifact → Actor)
[ ] consumes — (Resource axis is off; hidden)
[ ] reports_to — (Role/hierarchy not used; hidden)
Add / remove predicates? Or add custom ones?Output: finalized relations: block.
Dialogue example
💬 Agent: 활성 예측 관계는 다음과 같이 제안합니다 — 제외/추가 있으신가요?
>
```
[✓] owns (Role → Ticket/CodeArtifact/Goal)
[✓] produces (Ticket → CodeArtifact/Deliverable)
[✓] achieves (Ticket/CodeArtifact → Goal/Milestone)
[✓] precedes (Ticket → Ticket)
[✓] blocks (Ticket → Ticket)
[✓] authored_by (Document/Design → Role)
[✓] part_of (any → any)
[✓] requires (Ticket → Technology/Tool)
[ ] reports_to — hidden (Role hierarchy 사용 안 함)
[ ] consumes — hidden (Budget 비활성)
```
>
✍️ User: reviews 관계 하나 추가할 수 있나요? PR 리뷰 관계 남기고 싶어요. Role → CodeArtifact.>
⚙️ Action: add custom predicate:
>
```yaml
relations:
reviews: {domain: [Actor], range: [CodeArtifact], inverse: reviewed_by}
```
>
…plus the 8 pre-checked default predicates. Hidden predicates omitted.
---
Stage 8 — Review & Save
1. Show the full assembled ontology.yaml to the user. 2. Ask: "저장할까요? (yes/no/edit <stage>)" 3. On yes:
- Write
wiki/ontology.yamlwith the Write tool. - Generate
wiki/ontology-guide.md— a human-readable summary of the ontology (one section per axis, listing active classes and their purpose). - Append to
wiki/log.md:
## [YYYY-MM-DD] ontology-init | <N> classes, <M> relations, workflow=<phase_count> 4. Output:
✅ Ontology saved to wiki/ontology.yaml
✅ Guide saved to wiki/ontology-guide.md
Next: run /wiki-ingest — new ingests will use the ontology for context tagging.
To revisit a stage: /wiki-ontology-init --edit <stage-name>Dialogue example
💬 Agent: 아래가 최종 ontology.yaml 입니다 (요약):
>
```
project: QuickNotes (software-project, 2026-04-01 → 2026-10-31)
axes:
Actor (1 class): Role
Activity (4 classes): Ticket, Phase, Decision, Event
Artifact (4 classes): CodeArtifact, Deliverable, Design, Document
Objective (4 classes): Goal, Requirement, Milestone, Risk
Resource (1 class): Tool
Context (2 classes): Technology, Constraint
relations (9): owns, produces, achieves, precedes, blocks, authored_by,
part_of, requires, reviews
workflow: Planning → Alpha → Beta → GA
```
>
저장할까요? (yes / no / edit <stage>)
>
✍️ User: 좋아요, 저장해주세요.
>
⚙️ Action:
>
1.Write→wiki/ontology.yaml(full content from incremental saves)
2. Generate andWrite→wiki/ontology-guide.md
3. Append to wiki/log.md: ## [2026-04-21] ontology-init | 16 classes, 9 relations, workflow=44. Print final summary:
>
```
✅ Ontology saved to wiki/ontology.yaml
✅ Guide saved to wiki/ontology-guide.md
Active axes: Actor, Activity, Artifact, Objective, Resource, Context
Classes: 16 | Relations: 9 | Phases: 4
Next: /wiki-ingest will ask for document context on new ingests.
To revisit: /wiki-ontology-init --edit <stage-name>
```
---
ontology-guide.md Template
# Ontology Guide — <Project Name>
> Human-readable summary of `wiki/ontology.yaml`. Auto-generated.
> Regenerate via `/wiki-ontology-init --regen-guide`.
## Project
- **Type:** <type>
- **Period:** <start> → <end>
- **Description:** <description>
## Active Axes
### Actor — Who
Active classes:
- **Team** — lead, members, domain
- **Role** — responsibilities, reports_to
(...repeat per active axis...)
## Workflow
<phase list in order, or "No fixed phases">
## Key Relations
- `owns` — Team owns Task (who's responsible)
- `produces` — Task produces Deliverable
- (...)
## How to Use
- Run `/wiki-ingest <file>` — you'll be asked to tag the document with
phase, author, and related entities from this ontology.
- Run `/wiki-query class:Task AND context.phase=Build` — structural filter.
- Run `/wiki-ontology-validate` — check instances against the schema.# ============================================================
# Universal Ontology Template — LLM Wiki
# ============================================================
# Starting skeleton for `wiki/ontology.yaml`.
#
# How to use:
# 1. Run `/wiki-ontology-init` — the skill interviews you and
# produces `wiki/ontology.yaml` based on this template.
# 2. Or copy this file manually to `wiki/ontology.yaml` and edit.
#
# Principles:
# - The 6 axes below cover most project knowledge bases.
# Keep what you need; deactivate the rest via `active: false`.
# - `default_classes` are EXAMPLES. Add, rename, or delete freely.
# - `relations` is a common predicate vocabulary. Extend if needed.
# - Ontology is a HINT, not a hard constraint. Documents may still
# introduce entities outside this schema; the wiki will accept
# them (they just won't have a `class:` tag).
# ============================================================
version: 1
project:
name: "<your-project-name>"
# type: rough classification — tailors interview questions and defaults
type: "<software-project | research | product | campaign | operations | personal | other>"
description: "<one-sentence project description>"
start_date: null # YYYY-MM-DD or null
end_date: null # YYYY-MM-DD or null (null = ongoing)
# schema_version: increment when making breaking changes (class rename/removal,
# property rename/removal, predicate rename/removal, phase id change).
# Non-breaking additions (new class/property/predicate/phase) do not require a bump.
# After bumping: run /wiki-ontology-validate and fix ERRORs; log in wiki/log.md.
schema_version: 1
# ============================================================
# 6 Upper Axes — flip `active: false` to disable an axis entirely
# ============================================================
axes:
# ---------- 1. Actor (WHO) ----------
# Subjects that act, decide, own, or are affected.
Actor:
active: true
description: "Who acts, owns, decides, or is affected"
default_classes:
Person: {properties: [role, team, email], folder: entities}
Team: {properties: [lead, members, domain], folder: entities}
Role: {properties: [responsibilities, reports_to], folder: entities}
Organization: {properties: [type, external], folder: entities}
Stakeholder: {properties: [interest, influence], folder: entities}
# ---------- 2. Activity (WHAT HAPPENS) ----------
# Work units, phases, events, decisions.
Activity:
active: true
description: "Tasks, phases, meetings, decisions, events"
default_classes:
Task: {properties: [owner, status, deadline, deliverables, priority], folder: entities}
Phase: {properties: [starts_at, ends_at, order], folder: entities}
Meeting: {properties: [attendees, date, decisions], folder: entities}
Decision: {properties: [made_by, made_at, rationale, alternatives], folder: entities}
Event: {properties: [date, type], folder: entities}
# ---------- 3. Artifact (OUTPUTS) ----------
# Things produced — documents, code, designs.
Artifact:
active: true
description: "Documents, deliverables, code, designs, reports"
default_classes:
Document: {properties: [author, date, version, status], folder: entities}
Deliverable: {properties: [produced_by, consumed_by, status, acceptance_criteria], folder: entities}
CodeArtifact: {properties: [repo, path, owner, language], folder: entities}
Design: {properties: [author, iteration, format], folder: entities}
Report: {properties: [author, period, audience], folder: entities}
# ---------- 4. Objective (WHY) ----------
# Goals, requirements, KPIs, risks.
Objective:
active: true
description: "Goals, milestones, requirements, KPIs, risks"
default_classes:
Goal: {properties: [parent_goal, target_date, metric, status], folder: concepts}
Requirement: {properties: [priority, source, status, acceptance_criteria], folder: concepts}
Milestone: {properties: [date, exit_criteria, status], folder: concepts}
KPI: {properties: [target, measurement, frequency], folder: concepts}
Risk: {properties: [probability, impact, mitigation, owner], folder: concepts}
# ---------- 5. Resource (WITH WHAT) ----------
# Budget, tools, assets, time.
Resource:
active: false # OFF by default — enable if you track budget/tools
description: "Budget, tools, time, assets"
default_classes:
Budget: {properties: [amount, currency, period, owner], folder: entities}
Tool: {properties: [vendor, license, cost, owner], folder: entities}
Asset: {properties: [type, location, owner], folder: entities}
# ---------- 6. Context (BACKGROUND) ----------
# Domain, technology, constraints.
Context:
active: false # OFF by default — enable for cross-domain projects
description: "Domain, technology, constraints"
default_classes:
Domain: {properties: [industry, expertise], folder: concepts}
Technology: {properties: [category, version, vendor], folder: concepts}
Constraint: {properties: [type, source, hard_or_soft], folder: concepts}
# ============================================================
# Cross-Axis Relations (Predicates)
# ============================================================
# Conventions:
# - `domain` / `range` use axis names (Actor, Activity, ...) or
# class names (Team, Task, ...), OR the string `any` for polymorphic.
# - `inverse` — reverse predicate name (optional).
# - `transitive` — chained relations imply further links (optional).
# ============================================================
relations:
# --- Responsibility / Assignment ---
owns: {domain: [Actor], range: [Activity, Artifact, Objective], inverse: owned_by}
assigned_to: {domain: [Actor], range: [Activity], inverse: has_assignee}
approves: {domain: [Actor], range: [Decision, Deliverable]}
reports_to: {domain: [Actor], range: [Actor], transitive: true}
# --- Causality / Production ---
produces: {domain: [Activity], range: [Artifact]}
consumes: {domain: [Activity], range: [Artifact, Resource]}
requires: {domain: [Activity, Artifact], range: [Activity, Artifact, Resource]}
blocks: {domain: [Activity], range: [Activity]}
achieves: {domain: [Activity, Artifact], range: [Objective]}
# --- Structural ---
part_of: {domain: any, range: any, transitive: true, inverse: contains}
# --- Temporal ---
precedes: {domain: [Activity], range: [Activity], transitive: true}
concurrent_with: {domain: [Activity], range: [Activity]}
# --- Provenance / Reference ---
authored_by: {domain: [Artifact], range: [Actor]}
based_on: {domain: [Artifact], range: [Artifact]}
references: {domain: [Artifact], range: any}
# ============================================================
# Workflow (Optional)
# ============================================================
# Declare phase ordering. Used by `/wiki-query` for temporal
# filtering and `/wiki-graph` for phase-colored lanes.
# Leave `phases: []` if the project has no fixed phase order.
# ============================================================
workflow:
phases: []
# Example:
# phases:
# - {id: discover, order: 1, description: "Research & requirements"}
# - {id: design, order: 2, description: "Architecture & specs"}
# - {id: build, order: 3, description: "Implementation"}
# - {id: validate, order: 4, description: "QA & review"}
# - {id: release, order: 5, description: "Deploy & handoff"}
Query Advanced Reference
Loaded when /wiki-query uses structural filters (class:, type:, AND/OR/NOT, dotted field paths).
---
Structural Filter Syntax
If a query begins with class:, type:, tags:, or any dotted field path, and/or uses AND/OR/NOT, treat it as a structural filter rather than semantic search.
Grammar
expr := term (('AND' | 'OR') term)*
term := 'NOT'? (atom | '(' expr ')')
atom := field op value
field := IDENT ('.' IDENT)* e.g. class, context.phase, properties.owner
op := ':' | '=' | '!=' | '~=' (':' == '='; '~=' is substring/membership)
value := QUOTED_STRING | BARE_WORDSemantics
- Field lookup = dotted path on page frontmatter dict. Missing field = never matches.
=on a list (e.g.tags=draft) → list contains the value as an element=on a scalar → case-insensitive equality~=→ substring match (for lists: any element contains the substring)!=→ negation of=; pages without the field do match!=
Examples
class:Ticket AND context.phase=alpha
type:source AND tags~=meeting
(class:Risk AND properties.impact=high) OR class:Goal
NOT type=entity
what are the main themes? # plain natural-language query (unchanged)---
Option A — Python Script (preferred for structural filters)
python scripts/query_filter.py "class:Ticket AND context.phase=alpha"
python scripts/query_filter.py --list-fields # print available frontmatter fields
python scripts/query_filter.py --paths-only "class:Goal" # pipe-friendly outputThe script reads every page's frontmatter, runs the parser + evaluator, and prints matching paths. The agent then reads the matched pages and synthesizes an answer (query steps 3–6).
---
Option B — Agent-Based Structural Query
When wiki/ontology.yaml exists and a structural filter is detected:
1. Either invoke scripts/query_filter.py (preferred) or parse the expression manually 2. Glob wiki/entities/ and wiki/concepts/; match pages whose frontmatter satisfies the constraints 3. For source pages, match class: and context.* fields 4. Return matching pages as a structured list with links, then optionally synthesize narrative 5. If no match → "no instances match" and suggest relaxing the filter
LLM Wiki Page Templates
Source Templates
Default Source
Use for articles, papers, reports, book chapters, research summaries.
---
title: "Source Title"
type: source
tags: []
date: YYYY-MM-DD
source_file: raw/...
sources: []
last_updated: YYYY-MM-DD
---
## Summary
2–4 sentence summary.
## Key Claims
- Claim 1
- Claim 2
## Key Quotes
> "Quote here" — context
## Connections
- [[EntityName]] — how they relate
- [[ConceptName]] — how it connects
## Contradictions
- Contradicts [[OtherPage]] on: ...Diary / Journal
Use when source is a personal diary or journal entry.
---
title: "YYYY-MM-DD Diary"
type: source
tags: [diary]
date: YYYY-MM-DD
source_file: raw/...
sources: []
last_updated: YYYY-MM-DD
---
## Event Summary
## Key Decisions
## Energy & Mood
## Connections
## Shifts & ContradictionsMeeting Notes
Use when source is meeting notes or a transcript.
---
title: "Meeting Title"
type: source
tags: [meeting]
date: YYYY-MM-DD
source_file: raw/...
sources: []
last_updated: YYYY-MM-DD
---
## Goal
## Key Discussions
## Decisions Made
## Action Items---
Entity Page
wiki/entities/EntityName.md — TitleCase filename
---
title: "Entity Name"
type: entity
tags: []
sources: [slug1, slug2]
last_updated: YYYY-MM-DD
---
One-paragraph description.
## Appearances
- [[source-slug]] — context of appearanceWith ontology active: also add class: <ClassName> (must match a class in wiki/ontology.yaml axes) and a properties: block with the fields listed in that class's definition. Derive field names from the ontology — do not invent fields not declared there. Add relations: for typed links. Full frontmatter schema → references/ontology-commands.md.
---
Concept Page
wiki/concepts/ConceptName.md — TitleCase filename
---
title: "Concept Name"
type: concept
tags: []
sources: [slug1, slug2]
last_updated: YYYY-MM-DD
---
One-paragraph definition.
## Discussed In
- [[source-slug]] — how it appearsWith ontology active: same extension as Entity Page — class:, properties:, and relations: derived from the ontology class definition. Full frontmatter schema → references/ontology-commands.md.
---
Synthesis Page
wiki/syntheses/kebab-case-slug.md — slug derived from the query question
---
title: "Query: <short question title>"
type: synthesis
date: YYYY-MM-DD
tags: []
sources: [slug1, slug2]
entities: [Entity1, Entity2]
concepts: [Concept1, Concept2]
relations:
- [Subject, predicate, Object]
last_updated: YYYY-MM-DD
---
## Question
<original question>
## Answer
<synthesized answer with [[wikilink]] citations>
## Extracted Relationships
- Subject → predicate → Object
## Sources
- [[PageName]] — what it contributed`entities` and `concepts` list the wiki pages discovered during this query. `relations` captures subject–predicate–object triples extracted from the Q&A; these are also summarised in wiki/synthesis-map.md.
import argparse
from tqdm import tqdm
from pathlib import Path
from markitdown import MarkItDown
def convert_directory_to_md(input_dir: Path, delete_source: bool = False):
"""
Converts all files in a dictory to a Markdown format. Original files in the folder will be deleted.
:param input_dir: str
The Path object pointing to the directory to process.
:param delete_source: bool = False
Whether to delete the original source files. Defaults to False.
"""
md = MarkItDown(enable_plugins=False)
# get list of files to convert
files_to_process = [f for f in input_dir.rglob('*') if f.is_file()]
if not files_to_process:
print(f"No files found in {input_dir}!")
return
for file_path in tqdm(files_to_process, desc="Converting Files"):
# skip hidden files and existing markdown files
if file_path.name.startswith('.') or file_path.suffix.lower() == '.md':
print(f"Skipping conversion of {file_path.name}")
continue
# convert filepath to md
output_path = file_path.with_suffix(".md")
try:
# convert
result = md.convert(str(file_path))
# save to .md
output_path.write_text(result.text_content, encoding="utf-8")
# optional remove original file
if delete_source:
file_path.unlink()
tqdm.write(f"Converted: {file_path.name}")
except Exception as e:
tqdm.write(f"FAILED: Could not convert '{file_path.name}'. Reason: {e}")
def main(args):
# set Paths
input_path = Path(args.input_dir).resolve()
print("-" * 40)
print(f"Input Directory: {input_path}")
print("-" * 40)
# execute
try:
convert_directory_to_md(input_path, args.delete_source)
print("\nConversion process complete.")
except FileNotFoundError:
print(f"\nError: Input directory not found at {input_path}")
except Exception as e:
print(f"\nAn unexpected error occurred during execution: {e}")
if __name__ == "__main__":
"""Command-line arguments."""
parser = argparse.ArgumentParser(description="Convert all files in a directory to Markdown and delete originals.")
parser.add_argument(
"--input_dir",
type=str,
help="The path to the directory containing files to convert."
)
parser.add_argument(
"--delete_source",
action="store_true",
help="Whether to delete the original source files."
)
args = parser.parse_args()
main(args)
#!/usr/bin/env python3
from __future__ import annotations
"""
Lint the LLM Wiki for health issues.
Usage:
python tools/lint.py
python tools/lint.py --save # save lint report to wiki/lint-report.md
Checks:
- Orphan pages (no inbound wikilinks from other pages)
- Broken wikilinks (pointing to pages that don't exist)
- Missing entity pages (entities mentioned in 3+ pages but no page)
- Contradictions between pages
- Data gaps and suggested new sources
"""
import re
import json
import argparse
import statistics
from pathlib import Path
from collections import defaultdict
from datetime import date
REPO_ROOT = Path.cwd()
WIKI_DIR = REPO_ROOT / "wiki"
GRAPH_DIR = REPO_ROOT / "graph"
GRAPH_JSON = GRAPH_DIR / "graph.json"
LOG_FILE = WIKI_DIR / "log.md"
def read_file(path: Path) -> str:
if not path.exists():
return ""
try:
return path.read_text(encoding="utf-8")
except UnicodeDecodeError:
try:
return path.read_text(encoding="utf-16")
except UnicodeDecodeError:
return path.read_text(encoding="latin-1")
def all_wiki_pages() -> list[Path]:
return [p for p in WIKI_DIR.rglob("*.md")
if p.name not in ("index.md", "log.md", "lint-report.md")]
def extract_wikilinks(content: str) -> list[str]:
return re.findall(r'\[\[([^\]]+)\]\]', content)
def page_name_to_path(name: str) -> list[Path]:
"""Try to resolve a [[WikiLink]] to a file path."""
candidates = []
for p in all_wiki_pages():
if p.stem.lower() == name.lower() or p.stem == name:
candidates.append(p)
return candidates
def find_orphans(pages: list[Path]) -> list[Path]:
inbound = defaultdict(int)
for p in pages:
content = read_file(p)
for link in extract_wikilinks(content):
resolved = page_name_to_path(link)
for r in resolved:
inbound[r] += 1
return [p for p in pages if inbound[p] == 0 and p != WIKI_DIR / "overview.md"]
def find_broken_links(pages: list[Path]) -> list[tuple[Path, str]]:
broken = []
for p in pages:
content = read_file(p)
for link in extract_wikilinks(content):
if not page_name_to_path(link):
broken.append((p, link))
return broken
def find_missing_entities(pages: list[Path]) -> list[str]:
"""Find entity-like names mentioned in 3+ pages but lacking their own page."""
mention_counts: dict[str, int] = defaultdict(int)
existing_pages = {p.stem.lower() for p in pages}
for p in pages:
content = read_file(p)
links = extract_wikilinks(content)
for link in links:
if link.lower() not in existing_pages:
mention_counts[link] += 1
return [name for name, count in mention_counts.items() if count >= 3]
# ── Graph-aware checks ──────────────────────────────────────────────
def load_graph_data() -> dict | None:
"""Load graph.json if it exists. Returns None if missing (graceful degradation)."""
if not GRAPH_JSON.exists():
return None
try:
return json.loads(GRAPH_JSON.read_text(encoding="utf-8"))
except (json.JSONDecodeError, IOError):
print(" [warn] graph.json is corrupted — skipping graph-aware checks")
return None
def _build_degree_map(graph_data: dict) -> dict[str, int]:
"""Build node_id -> degree mapping from graph edges."""
degrees: dict[str, int] = {}
for node in graph_data.get("nodes", []):
degrees[node["id"]] = 0
for edge in graph_data.get("edges", []):
degrees[edge["from"]] = degrees.get(edge["from"], 0) + 1
degrees[edge["to"]] = degrees.get(edge["to"], 0) + 1
return degrees
def _build_community_map(graph_data: dict) -> dict[str, int]:
"""Build node_id -> community_id mapping from graph nodes."""
return {
node["id"]: node.get("group", -1)
for node in graph_data.get("nodes", [])
}
def check_hub_stubs(graph_data: dict, pages: list[Path], min_content_chars: int = 500) -> list[dict]:
"""Find god nodes (degree > μ+2σ) with suspiciously short content."""
degrees = _build_degree_map(graph_data)
deg_values = list(degrees.values())
if len(deg_values) < 2:
return []
mean_deg = statistics.mean(deg_values)
std_deg = statistics.stdev(deg_values)
threshold = mean_deg + 2 * std_deg
# Map node_id -> page path
node_to_path: dict[str, Path] = {}
for p in pages:
nid = p.relative_to(WIKI_DIR).as_posix().replace(".md", "")
node_to_path[nid] = p
results = []
for node_id, deg in degrees.items():
if deg <= threshold:
continue
path = node_to_path.get(node_id)
if not path:
continue
content_len = len(read_file(path))
if content_len < min_content_chars:
results.append({
"node_id": node_id,
"degree": deg,
"content_len": content_len,
"path": str(path.relative_to(REPO_ROOT)),
})
return sorted(results, key=lambda x: x["degree"], reverse=True)
def check_fragile_bridges(graph_data: dict) -> list[dict]:
"""Find community pairs connected by only 1 edge."""
comm_map = _build_community_map(graph_data)
cross_comm: dict[tuple[int, int], list[dict]] = {}
for edge in graph_data.get("edges", []):
ca = comm_map.get(edge["from"], -1)
cb = comm_map.get(edge["to"], -1)
if ca < 0 or cb < 0 or ca == cb:
continue
key = (min(ca, cb), max(ca, cb))
cross_comm.setdefault(key, []).append(edge)
return [
{
"comm_a": pair[0],
"comm_b": pair[1],
"bridge_from": edges[0]["from"],
"bridge_to": edges[0]["to"],
}
for pair, edges in sorted(cross_comm.items())
if len(edges) == 1
]
def check_isolated_communities(graph_data: dict) -> list[dict]:
"""Find communities with zero external edges (knowledge silos)."""
comm_map = _build_community_map(graph_data)
# Build community -> members
comm_members: dict[int, list[str]] = {}
for node_id, comm_id in comm_map.items():
if comm_id < 0:
continue
comm_members.setdefault(comm_id, []).append(node_id)
# Track which communities have external edges
has_external = set()
for edge in graph_data.get("edges", []):
ca = comm_map.get(edge["from"], -1)
cb = comm_map.get(edge["to"], -1)
if ca >= 0 and cb >= 0 and ca != cb:
has_external.add(ca)
has_external.add(cb)
results = []
for comm_id, members in sorted(comm_members.items()):
if len(members) < 2: # skip single-node "communities"
continue
if comm_id not in has_external:
results.append({
"community_id": comm_id,
"node_count": len(members),
"members": members[:10], # cap display
})
return results
def run_lint():
pages = all_wiki_pages()
today = date.today().isoformat()
if not pages:
print("Wiki is empty. Nothing to lint.")
return ""
print(f"Linting {len(pages)} wiki pages...")
# Deterministic checks
orphans = find_orphans(pages)
broken = find_broken_links(pages)
missing_entities = find_missing_entities(pages)
print(f" orphans: {len(orphans)}")
print(f" broken links: {len(broken)}")
print(f" missing entity pages: {len(missing_entities)}")
# ── Graph-aware checks ──
graph_data = load_graph_data()
hub_stubs: list[dict] = []
fragile_bridges: list[dict] = []
isolated_comms: list[dict] = []
if graph_data and graph_data.get("nodes") and graph_data.get("edges"):
print(" running graph-aware checks...")
hub_stubs = check_hub_stubs(graph_data, pages)
fragile_bridges = check_fragile_bridges(graph_data)
isolated_comms = check_isolated_communities(graph_data)
print(f" hub stubs: {len(hub_stubs)}")
print(f" fragile bridges: {len(fragile_bridges)}")
print(f" isolated communities: {len(isolated_comms)}")
elif graph_data:
print(" [skip] graph.json has no data — skipping graph-aware checks")
else:
print(" [skip] no graph.json — run build_graph.py first for graph-aware checks")
# Compose full report
report_lines = [
f"# Wiki Lint Report — {today}",
"",
f"Scanned {len(pages)} pages.",
"",
"## Structural Issues",
"",
]
if orphans:
report_lines.append("### Orphan Pages (no inbound links)")
for p in orphans:
report_lines.append(f"- `{p.relative_to(REPO_ROOT)}`")
report_lines.append("")
if broken:
report_lines.append("### Broken Wikilinks")
for page, link in broken:
report_lines.append(f"- `{page.relative_to(REPO_ROOT)}` links to `[[{link}]]` — not found")
report_lines.append("")
if missing_entities:
report_lines.append("### Missing Entity Pages (mentioned 3+ times but no page)")
report_lines.append("> [!warning] Action Required\n> Run `python3 generate_missing_entities.py` to automatically materialize these missing hubs.")
for name in missing_entities:
report_lines.append(f"- `[[{name}]]`")
report_lines.append("")
if not orphans and not broken and not missing_entities:
report_lines.append("No structural issues found.")
report_lines.append("")
# ── Graph-Aware Issues section ──
report_lines.append("## Graph-Aware Issues")
report_lines.append("")
if not graph_data:
report_lines.append("> [!tip]")
report_lines.append("> Graph-aware checks were skipped. Run `python tools/build_graph.py` first, then re-run lint.")
report_lines.append("")
elif not graph_data.get("nodes") or not graph_data.get("edges"):
report_lines.append("> [!tip]")
report_lines.append("> Graph data is empty. Ingest sources and run `python tools/build_graph.py` to populate.")
report_lines.append("")
else:
# Hub stubs
report_lines.append(f"### Hub Pages with Insufficient Content ({len(hub_stubs)} pages)")
if hub_stubs:
report_lines.append("These hub nodes carry disproportionate connectivity but have thin content:")
report_lines.append("")
report_lines.append("| Page | Degree | Content Length | Status |")
report_lines.append("|---|---|---|---|")
for hs in hub_stubs:
status = "🔴 stub" if hs["content_len"] < 250 else "🟡 thin"
report_lines.append(f"| `{hs['path']}` | {hs['degree']} | {hs['content_len']} chars | {status} |")
else:
report_lines.append("No hub stubs detected — all high-degree nodes have sufficient content.")
report_lines.append("")
# Fragile bridges
report_lines.append(f"### Fragile Bridges ({len(fragile_bridges)} community pairs)")
if fragile_bridges:
report_lines.append("These community connections rely on a single edge — one broken link isolates them:")
for fb in fragile_bridges:
report_lines.append(f"- Community {fb['comm_a']} ↔ Community {fb['comm_b']} via `{fb['bridge_from']}` → `{fb['bridge_to']}`")
else:
report_lines.append("No fragile bridges — all community connections have redundant links.")
report_lines.append("")
# Isolated communities
report_lines.append(f"### Isolated Communities ({len(isolated_comms)} communities)")
if isolated_comms:
report_lines.append("These communities have zero external connections — knowledge silos:")
report_lines.append("")
report_lines.append("| Community | Nodes | Members |")
report_lines.append("|---|---|---|")
for ic in isolated_comms:
members_str = ", ".join(ic["members"][:5])
if ic["node_count"] > 5:
members_str += ", …"
report_lines.append(f"| {ic['community_id']} | {ic['node_count']} | {members_str} |")
else:
report_lines.append("No isolated communities — all clusters have external connections.")
report_lines.append("")
report = "\n".join(report_lines)
import sys
sys.stdout.reconfigure(encoding='utf-8')
print("\n" + report)
return report
def append_log(entry: str):
existing = read_file(LOG_FILE)
LOG_FILE.write_text(entry.strip() + "\n\n" + existing, encoding="utf-8")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Lint the LLM Wiki")
parser.add_argument("--save", action="store_true", help="Save lint report to wiki/lint-report.md")
args = parser.parse_args()
report = run_lint()
if args.save and report:
report_path = WIKI_DIR / "lint-report.md"
report_path.write_text(report, encoding="utf-8")
print(f"\nSaved: {report_path.relative_to(REPO_ROOT)}")
today = date.today().isoformat()
append_log(f"## [{today}] lint | Wiki health check\n\nRan lint. See lint-report.md for details.")
networkx>=3.2
markitdown>=0.0.1
tqdm>=4.0.0
pyyaml>=6.0
scala Roadmap
1. Related roadmap 정보 및 다른 roadmap 파일과의 관계성
이 로드맵은 Scala 학습과 연관되어 있거나, 학습 전후로 계속해서 참고하기 좋은 다른 로드맵으로 다음 네 가지를 제시하고 있습니다.
- Backend (백엔드) 로드맵
- Data Engineer (데이터 엔지니어) 로드맵
- MLOps 로드맵
- Java 로드맵
2. 로드맵 구성요소간 전후관계 및 세부 구성 항목
Scala 로드맵의 전반적인 흐름은 언어 소개 및 개발 환경 설정으로 시작하여, 언어의 핵심 문법과 구조를 다루는 '기본기 학습(Learn the Basics)', 이후 '도구 및 생태계(Tools, Ecosystem & Platforms)', '프레임워크 및 라이브러리', '심화 주제(Advanced Topics)'로 뻗어나가는 구조를 갖추고 있습니다.
각 단계와 세부 항목은 다음과 같습니다.
단계 1: 소개 및 환경 설정 (Introduction & Setting Up Scala)
- Introduction (소개): Docs(문서), Courses(강의), Books(도서), YouTube.
- Setting Up Scala (환경 설정):
- Pick your IDE (주요 IDE): IntelliJ IDEA, VS Code, Vim, Zed.
- Secondary Options (보조 옵션): Emacs, Sublime.
단계 2: 기본기 학습 (Learn the Basics)
- 문법 기초 및 제어문: Variables & Constants(변수와 상수), Operators(연산자), Conditionals(조건문), Loops(반복문), Try/Catch.
- 객체 지향 개념: Object(객체), Class(클래스), Trait(트레이트).
- 데이터 타입 및 제네릭:
- Main Data Types: Integers, Strings, Booleans, Unit, Float, Nothing.
- Generic Types: Type Hierarchy, Type Parameters, Conversions.
- 자료구조 및 컬렉션 (Data Structures):
- Array, Seq, Range, List, Vector, Set, Map, Mutable Collections.
- 함수 및 메서드 (Functions & Methods): Method Calls, Anonymous Func / Lambda(익명 함수/람다), Total/Partial Funcs, Funcs returning Funcs.
- 컬렉션 및 문자열 다루기:
- Common Collection Methods: collect / collectFirst, find, filter, flatMap, foldLeft, foreach, map.
- Working with Strings: Regex(정규표현식).
- 패턴 매칭 (Pattern Matching): Case Classes, Sealed Traits, apply Method, Enums, Case Objects, unapply Method.
- 에러 처리 및 지연 평가:
- Error Handling: Option, Either, Try, for comprehension.
- Laziness (지연 평가): Lazy vals, by-name Parameters, Lazy Collections(Iterators, Views, LazyList).
- 기타 기본기:
- Scope & Visibility: private / protected, package, Implicit Parameter.
- Recursion (재귀): Tail Recursion, Trampolines.
- Early returns.
단계 3: 도구, 생태계 및 플랫폼 (Tools, Ecosystem & Platforms)
- Build Tools (빌드 도구):
- Scala-centered (Scala 중심): ScalaCLI, sbt, Mill.
- Common to JVM (JVM 공통): Gradle, Maven.
- Ecosystems (생태계): Cats, ZIO, Li Haoyi, Akka / Pekko, No Ecosystem.
- Platforms (플랫폼): JVM, Scala Native, Scala.js.
단계 4: 프레임워크 및 라이브러리 (Frameworks and Libraries)
- Testing (테스트):
- Unit Testing: ScalaTest, mUnit, uTest, JUnit, ZIO Test, specs2.
- Integration / Performance Testing: ScalaTest, Gatling.
- Effect Systems: Cats Effect, ZIO.
- Backend (백엔드): Scalatra, sttp, AkkaHTTP, Play, Tapir, http4s.
- GUI (그래픽 사용자 인터페이스):
- Web: Slinky, Calico, Laminar, React.js.
- Desktop: ScalaFX, JavaFX.
- Android: scala-android-plugin, Scala on Android.
- Concurrency (동시성): Ox, Gears, Streaming(FS2, Kyo, Akka & Peko Streams, ZIO Streams).
- Distributed Computing (분산 컴퓨팅): Spark, Akka, Pekko.
- Data Handling (데이터 처리):
- Database: Slick, ScalikeJDBC, Doobie, Quill.
- JSON: PlayJSON, Circe, Jsoniter, uPickle.
- 추가 분야: Video game Engines (Indigo, CosPlay, LibGDX w/ Scala), GraalVM Native Image.
단계 5: 심화 주제 (Advanced Topics)
(참고: 심화 주제는 순차적으로 배울 필요 없이 프레임워크나 라이브러리를 탐색하며 필요할 때 학습하는 것을 권장합니다.)
- Referential Transparency(참조 투명성), Pure Functions(순수 함수).
- Monads(모나드), Category Theory(카테고리 이론).
- Capture Checking, Capabilities.
- Variance, Context Bounds.
- Type System (타입 시스템) & Macros: Typeclasses, Macros. 관련 라이브러리로는 Monocle, Shapeless, Chimney, Scalameta, Magnolia가 있습니다.
Ontology Registry
Index of structured knowledge data files generated from wiki sources.
- [[scala]] — Knowledge data extracted from [[sources/scala]]
{"color":"DEFAULT","isTrashed":false,"isPinned":false,"isArchived":false,"textContent":"AI 개발 학습 참고 자료 목록\n\n현재 사용 중인 자료:\n- \"AI MCP Agent\" (집필 예정 도서, 목차 초안 기준으로 스터디 중)\n → LangChain, RAG, Agent, LangGraph, MCP 전반 커버\n- LangChain 공식 문서 (python.langchain.com)\n- FastAPI 공식 문서 (fastapi.tiangolo.com)\n- Nomad Coders Next.js 강의 (유료, 진행 중)\n\n찾아봐야 할 자료 (아직 못 찾음):\n- Chroma Vector DB 실전 예제 (LangChain + Chroma 통합 튜토리얼)\n- Next.js + FastAPI 연동 예제 프로젝트\n- Docker Compose로 FastAPI + Next.js + Chroma 전체 스택 묶는 방법\n- Ollama 기반 로컬 임베딩 모델 활용법\n\n읽을 예정:\n- \"파이썬으로 만드는 AI 서비스\" (서점에서 봐뒀음)\n- LangGraph 공식 튜토리얼 (멀티 에이전트)\n\n커뮤니티:\n- LangChain 한국 사용자 Discord 가입 예정","title":"AI 개발 학습 자료","userEditedTimestampUsec":1745107620000000,"createdTimestampUsec":1745107620000000}
{"color":"DEFAULT","isTrashed":false,"isPinned":false,"isArchived":false,"textContent":"AI 기반 개인 지식관리 서비스 개발 계획\n\n목표: 개인 메모·문서를 자동 구조화하고 자연어로 질문할 수 있는 RAG 기반 위키 시스템 구축\n운영 방식: 완전 로컬 실행 (클라우드 의존 없이)\n\n주요 기능:\n1. PDF·Word·메모 등 다양한 형식 자동 분류 및 인덱싱\n2. 자연어 질의응답 (RAG 기반, 로컬 LLM 사용)\n3. 개념 간 연관성 자동 추출 및 시각화\n4. 웹 UI에서 질문하고 결과 확인\n\n필요 기술 스택:\n- Backend: Python, FastAPI (Django 아님, 성능상 이유)\n- AI/ML: LangChain, Vector DB (Chroma 우선 검토, 이후 Pinecone 고려)\n- Embedding: Ollama 로컬 임베딩 모델 활용\n- Frontend: Next.js (React 기반, SSR 필요)\n- 인프라: Docker Compose로 전체 서비스 묶기\n- DB: SQLite (메타데이터), Chroma (벡터)\n\n목표 일정: 2026년 9월까지 MVP 완성","title":"AI 개인 프로젝트 목표","userEditedTimestampUsec":1745107440000000,"createdTimestampUsec":1745107440000000}
{"color":"DEFAULT","isTrashed":false,"isPinned":false,"isArchived":false,"textContent":"베트남 하노이 여행 예산 계획\n\n총 예산: 1,600,000원 (2인 기준 합산)\n여행 기간: 2026년 6월 13일(토) ~ 6월 19일(금) (6박 7일)\n참여 인원: 2명 (부부)\n\n예산 항목별 계획:\n- 항공권: 별도 메모 참고 (왕복 예약 완료)\n- 숙소: 별도 메모 참고 (예약 완료)\n- 공항↔시내 교통: 별도 메모 참고\n- 현지 교통 (그랩 등): 약 50,000원\n- 식비: 예산에서 항목 제외 후 남은 금액으로 충당\n- 관광/입장료: 예산에서 항목 제외 후 남은 금액으로 충당\n- 쇼핑: 예산에서 항목 제외 후 남은 금액으로 충당\n\n비고: 식비, 관광, 쇼핑은 따로 배정하지 않고 잔여 예산 전체를 자유롭게 활용 예정\n현지 물가가 저렴하므로 넉넉히 쓸 수 있을 것으로 기대","title":"베트남 여행 예산 계획","userEditedTimestampUsec":1745107320000000,"createdTimestampUsec":1745107320000000}
{"color":"DEFAULT","isTrashed":false,"isPinned":false,"isArchived":false,"textContent":"항공권: 인천 - 하노이 (왕복)\n항공사: 비엣젯 항공 (VJ)\n날짜: 2026년 6월 13일(토) 출발 - 6월 19일(금) 귀국\n가격: 왕복 482,000원 (유류할증료 및 제세공과금 포함)\n수하물: 20kg 위탁수하물 포함\n\n가는 편: 인천 07:00 → 하노이 내이바이 09:40 (현지시각 기준, 비행시간 4시간 40분)\n오는 편: 하노이 21:00 → 인천 다음날 02:30\n\n예약 번호: VJ20260613-8821\n결제: 신한 현대 카드 (마일리지 적립 완료)","title":"베트남 여행 항공권","userEditedTimestampUsec":1745107200000000,"createdTimestampUsec":1745107200000000}