diff --git a/.claude/commands/branch-plan.md b/.claude/commands/branch-plan.md new file mode 100644 index 0000000..cf66fa3 --- /dev/null +++ b/.claude/commands/branch-plan.md @@ -0,0 +1,51 @@ +--- +description: 設計 / 檢查 / 調整 branch 結構(atoms 目錄分類) +argument-hint: "[可選:propose | review | split | merge | rename ]" +--- + +## /branch-plan — Branch 結構規劃 + +Branch(`atoms//`)是這個知識庫的骨架。依 `CLAUDE.md` 與 `METHODOLOGY.md` Phase 1 的規範操作,**絕不自行新增 / 改名 / 合併 branch,必須由使用者確認**。 + +### 子指令(由 `$ARGUMENTS` 判讀) + +#### `propose`(預設,當 `atoms/` 還是空的) +- 讀使用者給的 raw/ 清單或對話中描述的知識領域 +- 提議一組 branch(每個附上一段 boundary 定義) +- 每個 branch 必須同時滿足四條件:**Independence / Scale(預期 5+ atoms)/ Clear boundary / Teaching independence** +- 只提議,**不建立目錄**;由使用者勾選後再實際建立 `atoms//` 資料夾 + +#### `review` +- 掃 `atoms/` 下每個 branch +- 依 CLAUDE.md「When to merge / remove」「When to split」條款給建議: + - Hollow(<3 atoms 且無成長軌跡)→ 考慮合併 / 併入 tag + - Overlap(>50% atoms 與另一 branch tags 重疊)→ 合併或重劃邊界 + - Bloat(>30 atoms 且自然成群)→ 考慮拆分 +- 把建議寫到 `lint-report.md` 的 `## Branch Review` 區塊 + +#### `split ` +- 讀 `atoms//` 所有 atoms +- 提議 2–3 個子群的分法,每個附新 branch 邊界 +- 使用者確認後: + 1. 建新 branch 目錄 + 2. 搬移 atoms、更新每顆 frontmatter `id` + 3. Recompile 受影響的 wiki 頁 + 4. `scripts/log-append.sh "Branch split: , "` + +#### `merge ` +- 讀兩 branch 所有 atoms,評估是否真的該合併 +- 使用者確認後:搬移 → 改 id → recompile → log + +#### `rename ` +- 改目錄、改所有 atom frontmatter 的 `id` 前綴、改所有 wiki 檔名前綴與 `[[link]]` +- 跑 `gen-index.sh` + `lint.sh` 確認無 ghost links +- log-append + +### 硬性規則 + +- **最終定奪在使用者**:AI 不知道你的教學定位與內容差異化,只提議 +- **Branch 只用小寫連字號**(`harness-engineering` 不是 `HarnessEngineering` 或 `harness_engineering`) +- **不要 `rm`**:被淘汰的 branch 整個搬到 `atoms/_archive//` + +### 使用者參數 +$ARGUMENTS diff --git a/.claude/commands/compile.md b/.claude/commands/compile.md new file mode 100644 index 0000000..0206a3f --- /dev/null +++ b/.claude/commands/compile.md @@ -0,0 +1,40 @@ +--- +description: 從 atoms/ 編譯 wiki 頁面(依 CLAUDE.md schema) +argument-hint: "[可選:branch 名稱或 topic,例如 mcp 或 mcp-server-design]" +--- + +## /compile — 編譯 atoms 為 wiki 頁面 + +依據 `CLAUDE.md` 與 `METHODOLOGY.md` Phase 6 執行 Compile 操作。 + +### 流程 + +1. **選定範圍**: + - 若 `$ARGUMENTS` 指定了 branch(例如 `mcp`),列出該 branch 所有 atoms,提議 3–8 顆一組的頁面切分 + - 若指定了 topic(例如 `mcp-server-design`),直接針對該主題選 atoms + - 若未指定,先讀 `atoms/` 結構,向使用者提議要 compile 的優先順序 +2. **並行鎖定檔名**:若要並行編譯多頁,**先**列好完整 slug 清單(`-.md`),取得使用者確認後再分派;agent 填內容不命名檔案。 +3. **逐頁編譯**: + - 檔名 `-.md`,全小寫連字號 + - 第一行必須是 `# Title` + - 相關概念首次出現用 `[[slug]]` 連結(slug 必須對應已存在的 wiki 檔) + - 1500–2500 字為目標;>2500 考慮拆,<800 考慮合併 + - 時間敏感主張用具體版本 / 日期(`v3.5`、`as of 2026-04`),避免 `目前` / `最新` / `現在` + - 頁尾列出來源 atoms:`*Compiled from atoms: branch/slug-a, branch/slug-b, ...*` +4. **收尾**: + ```bash + ./scripts/gen-index.sh + ./scripts/lint.sh + ./scripts/log-append.sh "Compile: 新增/更新 .md(來自 N 顆 atoms)" + ``` +5. 若 `lint.sh` 報 error(不是 warning),先修完再宣告完成。 + +### 硬性規則 + +- **不要 patch wiki 掩蓋 atom 層問題**:wiki 錯是因 atom 錯 → 回去修 atom 再 recompile +- **不要用粗體 / 斜體補救不清楚的寫作**:需要強調才看得懂 = 該重寫 +- **不要單顆 atom 一頁**:典型 3–8 顆 atoms 合成一頁 +- **並行 compile 一定要先鎖 slug**:否則會出現 `mcp-server.md` 與 `mcp-server-design.md` 這種命名碰撞 + +### 使用者參數 +$ARGUMENTS diff --git a/.claude/commands/ingest.md b/.claude/commands/ingest.md new file mode 100644 index 0000000..70d55a0 --- /dev/null +++ b/.claude/commands/ingest.md @@ -0,0 +1,35 @@ +--- +description: 從 raw/ 擷取新素材為 atoms(依 CLAUDE.md schema) +argument-hint: "[可選:要處理的 raw/ 子路徑或檔名,如 raw/posts-2026-04.md]" +--- + +## /ingest — 擷取原始素材為 atoms + +依據 `CLAUDE.md` 與 `METHODOLOGY.md` 的規範執行 Ingest 操作。 + +### 流程 + +1. **掃描 raw/**:若 `$ARGUMENTS` 有指定檔案 / 子路徑,只處理該範圍;否則列出 `raw/` 內所有新檔案並詢問要先處理哪一批。 +2. **Phase 2 分段分類**:對每段內容標記 `extract` / `skip` / `deferred`,並依 `METHODOLOGY.md` 表格的預期萃取率做為對照。 +3. **Phase 3 萃取**: + - 每顆 atom 一個核心主張(one atom, one claim) + - frontmatter 嚴格照 `CLAUDE.md` 的欄位,不要發明欄位 + - 檔名 `YYYY-MM-DD-.md`,全小寫、用連字號 + - 不知道該放哪個 branch 時列為 deferred candidate,**不要自行新增 branch**;先向使用者確認 +4. **首批校準**:第一批 10–20 段後,主動向使用者匯報分類與萃取品質,取得確認後再繼續。 +5. **收尾**: + ```bash + ./scripts/gen-index.sh + ./scripts/log-append.sh "Ingest: <來源> → /... 新增 N 顆 atoms" + ``` + +### 硬性規則 + +- **raw/ 唯讀**:不可修改 raw/ 下任何檔案 +- **atoms 不可變**:已建立的 atom 不可編輯;要更新請建新 atom + 舊 atom 加 `superseded_by` + 搬到 `_archive/` +- **保留作者語氣**:這是個人知識庫,不是中性百科 +- **不要複製貼上**:要精煉,不是加個標題就算 extract(見 METHODOLOGY.md 的「Bad atom vs Good atom」對照) +- **source_ids 必填**:沒有來源追溯的 atom 無法稽核 + +### 使用者參數 +$ARGUMENTS diff --git a/.claude/commands/lint.md b/.claude/commands/lint.md new file mode 100644 index 0000000..6bb39ad --- /dev/null +++ b/.claude/commands/lint.md @@ -0,0 +1,51 @@ +--- +description: 執行兩層 Lint(先 programmatic,再 LLM) +argument-hint: "[可選:programmatic | llm | full(預設 full)]" +--- + +## /lint — 兩層 Lint + +依據 `CLAUDE.md` 的 Lint 規範執行。 + +### 流程 + +參數 `$ARGUMENTS` 決定要跑哪層(預設 `full`)。 + +#### 1. Programmatic Lint + +```bash +./scripts/lint.sh +``` + +產出 `lint-report.md`,檢查四項: +- Ghost Links(指向不存在頁的連結)— **error** +- Orphan Pages(沒被任何頁連結過來的頁)— warning +- Format Violations(首行非 `# title`、檔名含大寫/底線)— **error** +- Outdated Markers(`最新版`、`截至 YYYY` 等時效字眼)— warning + +若有 error,先修;error 全清才繼續 LLM Lint。 + +#### 2. LLM Lint + +只在 programmatic 通過後執行。讀 `index.md` + 所有 `wiki/*.md`(**不讀 atoms** — Lint 檢的是 wiki 層品質),檢查: + +1. **Contradictions(矛盾)**— A 頁說 X 是 best practice,B 頁說 X 已 deprecated → 兩邊都標,附路徑與引文 +2. **Concept gaps(概念缺口)**— 多頁提到某概念但沒有專屬頁 → 列為候選新頁 +3. **Expired claims(過期主張)**— 版本號 / 日期 / 時效字眼 → 驗證或標記 +4. **Weak orphans(弱連結)**— 技術上有連結但與其他頁概念關聯薄弱 + +**輸出**:append 到 `lint-report.md` 的 `## LLM Lint` 區塊,依嚴重度排序(contradictions > concept gaps > expired > weak orphans)。 + +#### 3. 動作 + +- 決定要修哪些 → 改 atom → 重新 compile 受影響的 wiki 頁 +- 記錄:`./scripts/log-append.sh "Lint: 修正 N 項(contradictions: X, expired: Y ...)"` + +### 硬性規則 + +- **不要在 wiki 層硬修掩蓋 atom 問題**:錯在 atom,就回去改 atom +- **atoms 不可編輯**:發現 atom 錯 → 建新 atom + 舊的加 `superseded_by` + 搬 `_archive/` +- **不要刪 wiki 頁 / atom**:改用 `_archive/` + +### 使用者參數 +$ARGUMENTS diff --git a/.claude/commands/query.md b/.claude/commands/query.md new file mode 100644 index 0000000..3cfb802 --- /dev/null +++ b/.claude/commands/query.md @@ -0,0 +1,26 @@ +--- +description: 從 wiki 查答案(先讀 index.md 定位,不掃全庫) +argument-hint: "<問題>" +--- + +## /query — 從知識庫查詢 + +依據 `CLAUDE.md` 的 Query 規範執行。 + +### 流程 + +1. **讀 `index.md`** 定位:絕對不要一次載入整個 wiki。 +2. **載入命中的頁面**:只讀 index.md 指向的相關頁,合成回答。 +3. **明確區分**: + - 「這是 wiki 裡已有的內容」 + - 「這是我基於 wiki 的綜合推論」 +4. **引用來源**:列出你讀了哪些 wiki 頁(slug)。 +5. **回寫判斷**:若你的綜合回答本身值得留存(新的視角 / 整合),主動提議寫回為新 atom(告知建議 branch 與 slug,取得使用者同意後再建立)。 + +### 硬性規則 + +- **別把 wiki 當 source of truth** — atoms 才是。若答案有疑問,追到 atom。 +- **不要硬編造**:wiki 沒有就老實說沒有;不要拿訓練資料填空而不標示。 + +### 使用者問題 +$ARGUMENTS diff --git a/.claude/commands/refresh.md b/.claude/commands/refresh.md new file mode 100644 index 0000000..6864b9d --- /dev/null +++ b/.claude/commands/refresh.md @@ -0,0 +1,28 @@ +--- +description: 重建 index.md、追加 log.md(任何變更後必跑) +argument-hint: "<這次變更的一句話描述>" +--- + +## /refresh — 變更後收尾 + +任何 Ingest / Compile 或動到 wiki 之後,一定要跑這個,保持 `index.md` 與 `log.md` 同步。 + +### 流程 + +1. **重建 index**: + ```bash + ./scripts/gen-index.sh + ``` +2. **記錄變更**: + ```bash + ./scripts/log-append.sh "$ARGUMENTS" + ``` + 若 `$ARGUMENTS` 為空,先向使用者要一句話描述(例如 `"Compile: 新增 mcp-server-design.md(來自 5 顆 atoms)"`)。 +3. **檢查 log.md 第一行是否正確、日期是否正確**(`log-append.sh` 會 prepend 在 header 後)。 + +### 何時不需要 lint + +`/refresh` 不自動跑 lint。動過 wiki 頁(新增 / 修改)後請另外執行 `/lint`。 + +### 使用者參數 +$ARGUMENTS diff --git a/.gitignore b/.gitignore index ff26aa3..acc0cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,10 @@ lint-report.md # Personal notes / analysis (not for the public repo) GAP-ANALYSIS.md +# ─── Secrets ─── +.env +.env.* + # ─── Python / OS / editor noise ─── Python/ __pycache__/ diff --git a/CLAUDE.md b/CLAUDE.md index 651769c..bcfecf9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,8 +1,40 @@ -# CLAUDE.md — Schema for LLMs operating this repo +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +--- + +## Quick commands + +All scripts live in `scripts/` and require Bash (Git Bash or WSL on Windows). + +```bash +# After every Ingest or Compile run — in this order: +bash scripts/gen-index.sh # rebuild index.md +bash scripts/log-append.sh "what you did" # append to log.md + +# After Compile, also run: +bash scripts/lint.sh # programmatic Lint → lint-report.md +``` + +### Claude Code skills (invoke from chat) + +| Skill | When to use | +|-------|-------------| +| `/ingest` | Extract atoms from raw/ material | +| `/compile` | Synthesize atoms into wiki pages | +| `/query` | Answer a question from the wiki | +| `/lint` | Run both programmatic + LLM Lint layers | +| `/refresh` | Rebuild index.md + append log.md | +| `/branch-plan` | Design or audit branch structure | + +--- + +## Schema for LLMs operating this repo You are operating on a knowledge base built on the LLM Wiki pattern (Karpathy 2026), with four optimizations: an atom layer, topic-branch organization, two-layer Lint, and parallel-compile naming locks. -This file is the formal spec — read it before touching anything. Mental model, operations, file formats, lifecycle rules, and what you must never do. +Read everything below before touching anything. Mental model, operations, file formats, lifecycle rules, and what you must never do. --- diff --git a/scripts/gen-index.sh b/scripts/gen-index.sh index 42691a4..cf27558 100644 --- a/scripts/gen-index.sh +++ b/scripts/gen-index.sh @@ -9,23 +9,10 @@ WIKI_DIR="$(cd "$(dirname "$0")/../wiki" && pwd)" INDEX="$WIKI_DIR/../index.md" # ─── Branch order and display names ─── -# Edit this array for your branches. Leave empty (declare -a BRANCHES=()) -# to auto-discover by filename prefix and capitalize display names automatically. -# -# Reference implementation uses these 11 branches in this order: -declare -a BRANCHES=( - "harness-engineering|Harness Engineering" - "mcp|MCP" - "ai-skills|AI Skills" - "vibe-coding|Vibe Coding" - "ai-agent|AI Agent" - "self-media|Self-Media" - "product-business|Product & Business" - "claude-code|Claude Code" - "context-engineering|Context Engineering" - "career-mindset|Career & Mindset" - "developer-workflow|Developer Workflow" -) +# Edit this array once your branch set stabilizes. Empty array = auto-discover +# branches by filename prefix (everything before first hyphen), and capitalize +# display names automatically. +declare -a BRANCHES=() # ─── Auto-discover branches if not overridden ─── if [ ${#BRANCHES[@]} -eq 0 ]; then @@ -86,11 +73,11 @@ for entry in "${BRANCHES[@]}"; do echo "| Slug | Title |" >> "$INDEX" echo "|------|-------|" >> "$INDEX" - for f in $(printf '%s\n' "${FILES[@]}" | sort); do + while IFS= read -r f; do slug=$(basename "$f" .md) title=$(head -1 "$f" | sed 's/^# //') echo "| [[$slug]] | $title |" >> "$INDEX" - done + done < <(printf '%s\n' "${FILES[@]}" | sort) echo "" >> "$INDEX" done diff --git a/scripts/lint.sh b/scripts/lint.sh index 1d3229a..8f0a18a 100644 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -19,7 +19,7 @@ for f in "$WIKI_DIR"/*.md; do [ -f "$f" ] || continue slug=$(basename "$f" .md) # Skip index and log - [[ "$slug" == "index" || "$slug" == "log" ]] && continue + [[ "$slug" == "index" || "$slug" == "log" || "$slug" == "_template" || "$slug" == "README" ]] && continue SLUGS["$slug"]=1 done @@ -32,7 +32,7 @@ FOUND_GHOST=0 for f in "$WIKI_DIR"/*.md; do [ -f "$f" ] || continue slug=$(basename "$f" .md) - [[ "$slug" == "index" || "$slug" == "log" ]] && continue + [[ "$slug" == "index" || "$slug" == "log" || "$slug" == "_template" || "$slug" == "README" ]] && continue # Extract all [[...]] links while IFS= read -r link; do @@ -66,7 +66,7 @@ done for f in "$WIKI_DIR"/*.md; do [ -f "$f" ] || continue slug=$(basename "$f" .md) - [[ "$slug" == "index" || "$slug" == "log" ]] && continue + [[ "$slug" == "index" || "$slug" == "log" || "$slug" == "_template" || "$slug" == "README" ]] && continue while IFS= read -r link; do target="${link%%|*}" @@ -97,7 +97,7 @@ FOUND_FORMAT=0 for f in "$WIKI_DIR"/*.md; do [ -f "$f" ] || continue slug=$(basename "$f" .md) - [[ "$slug" == "index" || "$slug" == "log" ]] && continue + [[ "$slug" == "index" || "$slug" == "log" || "$slug" == "_template" || "$slug" == "README" ]] && continue # 3a. First line must be # title first_line=$(head -1 "$f") @@ -135,7 +135,7 @@ PATTERNS='最新版|目前最新|currently v|latest v|just released|剛出|剛 for f in "$WIKI_DIR"/*.md; do [ -f "$f" ] || continue slug=$(basename "$f" .md) - [[ "$slug" == "index" || "$slug" == "log" ]] && continue + [[ "$slug" == "index" || "$slug" == "log" || "$slug" == "_template" || "$slug" == "README" ]] && continue matches=$(grep -nE "$PATTERNS" "$f" 2>/dev/null) if [ -n "$matches" ]; then