feat(daemon-beta t2): template 代裝——embed v1.18.0 快照(36檔)/冪等不覆寫/daemon 啟動自動鋪/template-install 子命令;scan 加 SkipDirNames 防 system-dev 與 CLAUDE.md 被當知識掃

- 測試 3 支新增全綠(首鋪/冪等護用戶檔/掃描跳 template 產物——第三支先紅抓到 CLAUDE.md 洩入再修綠)
- CLI 實跑:新鋪 36 檔→重跑 0 新檔(冪等證據)
This commit is contained in:
2026-07-24 12:18:37 +08:00
parent b355165180
commit 73a5a67b72
41 changed files with 2917 additions and 1 deletions
+1
View File
@@ -0,0 +1 @@
1.18.0
@@ -0,0 +1,30 @@
# [主題] — Architecture Decision Record
> 日期:[YYYY-MM-DD]
> 狀態:[提議中 / 已採納 / 已廢棄]
> 影響範圍:[哪些子系統 / 模組]
---
## 背景
[遇到了什麼問題,需要做這個決定?]
## 決定
**[結論,一句話。]**
## 原因
[詳細說明為什麼這樣決定。]
## 放棄的選項
| 選項 | 放棄原因 |
|------|---------|
| [選項 A] | [原因] |
| [選項 B] | [原因] |
## 影響與後續
[這個決定影響哪些地方?有什麼技術債或需要注意的事?]
@@ -0,0 +1,39 @@
# SDD 生命週期鐵律(不可違反)
> 來源:leo 2026-07-17 拍板。
> 適用:`system-dev/docs/3-specs/` 下的「規格 SDD」(requirements/design/tasks 三件式資料夾)。
> **不適用**:派工表/sprint 檔、journeys/ 卷宗、TEMPLATE-sdd、README、pending-changes.md——它們不是 SDD,不掛 status。
## 狀態標記(機器可查)
每個 SDD 資料夾的 `design.md` 最上方掛 YAML frontmatter
```yaml
---
status: active # active | draft | paused | closed
superseded_by: "" # closed 且被取代時填接替的 SDD 資料夾名
---
```
- `active`:現行規格,全 repo 開發任務唯一對應源。**任何時刻整個 repo 最多一份。**
- `draft`:起草中,尚未採納。
- `paused`:動過工、暫停中;恢復=升回 active(先收掉現任 active)或被新 SDD 繼承。
- `closed`:已完成或被取代;被取代者填 `superseded_by` 並移入 `3-specs/archive/`
## 五條鐵律
1. **單一活性**:任何時刻只允許一份 `status: active`。所有開發任務必須對應這份 SDD 的 tasks。找不到對應任務 → 停下來問,不准直接做。
2. **禁止自行建立 SDD**:CC 在任何情況下不得主動建新 SDD。收到使用者意見先分類:澄清問題→回答即可不動文件;任務層變更(不影響核心設計)→更新現行 SDD 的 tasks 區段並標日期與原因;規格層變更(核心設計/方向改變)→走第 3 條,不准直接改 spec。
3. **規格變更只有一條路**:產出 change proposal 寫入 `system-dev/docs/3-specs/pending-changes.md`(變更摘要與觸發原因+影響分析:現行 SDD 哪些任務作廢/修改/不受影響/尚未完成),然後**停止**,等使用者明說「confirm」。沒 confirm 就繼續依現行 SDD 工作。多個 proposal 可並存緩衝區、由人一次裁決——CC 的速度導向影響分析,不是規格增生。
4. **開新 SDD 的唯一時機**:使用者 confirm 一份規格層 proposal 時,依序:
a. 舊 SDD 未完成且仍有效的任務**逐條搬入**新 SDD 的 tasks——**這步做完前不准寫任何程式碼**(強迫顯式盤點,遺漏會在 d 的清單被看到,而不是三天後才發現)。
b. 舊 SDD frontmatter 改 `status: closed, superseded_by: <新SDD>`,資料夾移入 `3-specs/archive/`
c. 新 SDD 的 changelog 首行記錄:繼承自哪份、為何取代。
d. 向使用者列出「已搬移任務清單」與「已作廢任務清單」請求最終確認。
5. **每次 session 開始**:先讀現行 active SDD 與 pending-changes.md,回報三個數字——「現行規格〈名稱〉+未完成任務 N+待裁決 proposal M」——再開始工作。若回報出現兩份 active=規則已被違反,當場糾正。
## 硬約束(不信任單點自律,用結構保證不變量)
- `.claude/hooks/sdd-guard.sh`PreToolUse Write|Edit):active 數 >1 → 任何寫檔一律擋;寫 code 檔需恰好 1 份 active。
- `scripts/sdd-active-check.sh`:獨立檢查,pre-commit / CI 可掛,違反 exit 1。
- 誠實限制:hook 只擋語法層明顯違規,繞道可行但留痕可審;不聲稱不可繞過。
@@ -0,0 +1,80 @@
---
status: draft # active | draft | paused | closed(生命週期鐵律見 ../SDD-LIFECYCLE.md
superseded_by: "" # closed 且被取代時填接替的 SDD 資料夾名
---
# [子系統名稱] — Design
> 建立:[YYYY-MM-DD] | 最後更新:[YYYY-MM-DD]
> 負責人:[名稱]
---
## 一句話說明
[這個子系統做什麼,一句話。]
---
## 背景與問題
[為什麼需要這個子系統?解決了什麼問題?]
---
## 範圍
### 包含(In Scope
- [這個 SDD 涵蓋的功能]
### 不包含(Out of Scope
- [明確排除的功能,避免 CC 自行延伸]
---
## 設計
### 架構概覽
[用文字或 ASCII 描述系統結構]
```
[元件 A] → [元件 B] → [元件 C]
```
### 關鍵決策
| 決策 | 選擇 | 原因 | 放棄的選項 |
|------|------|------|----------|
| [問題] | [選擇] | [原因] | [其他選項] |
### API / 介面定義
[端點、資料格式、輸入輸出規格]
### 資料模型
[資料結構、欄位說明]
---
## 技術限制
- [不能用什麼]
- [必須相容什麼]
- [效能要求]
---
## 驗收標準
完成的定義(CC 完成任何 task 前必須確認):
- [ ] [可客觀驗證的條件,例如:POST /api/xxx 回傳 200]
- [ ] [...]
---
## 相關文件
- [連結到相關 ADR]
- [連結到相關 SDD]
@@ -0,0 +1,50 @@
# [子系統名稱] — Tasks
> 權威來源:此檔案是進度真相,不是 CLAUDE.md 或對話。
> 規則:動手前標 [🔄],完成立刻標 [x],不批次更新。
---
## Phase 1[Phase 名稱]
### 前置條件
- [ ] [這個 Phase 開始前必須完成的事]
### Tasks
- [ ] 1.1 [task 描述]
- 驗收:[客觀可驗證的完成標準]
- 注意:[CC 容易犯的錯,可選]
- [ ] 1.2 [task 描述]
- 驗收:[...]
---
## Phase 2[Phase 名稱]
> 前置條件:Phase 1 全部完成
- [ ] 2.1 [task 描述]
- 驗收:[...]
---
## 完成定義
整個 SDD 完成 = 以下全部達成:
- [ ] 所有 tasks 標 [x]
- [ ] 驗收標準通過(有客觀證據)
- [ ] design.md 與實作一致(如有出入需更新)
---
## 狀態說明
| 標記 | 意義 |
|------|------|
| `[ ]` | 未開始 |
| `[🔄]` | 進行中(當前 session|
| `[x]` | 完成(有驗收證據)|
| `[~]` | 暫緩(說明原因)|
| `[!]` | 阻擋中(說明阻擋原因)|
@@ -0,0 +1,15 @@
# Pending Changes(規格變更緩衝區)
> 規則來源:`SDD-LIFECYCLE.md` 第 3、4 條。
> 規格層變更(核心設計/方向改變)**只有這一條路**CC 把 change proposal 寫進「待裁決」——
> 變更摘要與觸發原因+影響分析(現行 SDD 哪些任務作廢/修改/不受影響/尚未完成)——然後**停止**,
> 等使用者明說「confirm」才依第 4 條開新 SDD;沒 confirm 就繼續依現行 SDD 工作。
> 多個 proposal 可並存,由人一次裁決。本檔不是 SDD,不掛 status。
## 待裁決
(無)
## 已裁決
(無——裁決後從「待裁決」移到這裡留底,標 confirmed / rejected 日期。)
@@ -0,0 +1,81 @@
# Logseq 任務 marker 解析(單一真相源)
> **這是「Logseq 原生任務語法」解析的唯一權威規格。** 任何要從 Logseq graph
> 抓任務狀態的功能,一律 import 這份、不得各寫一份自己的 mapping。
>
> **已知兩個消費者**(共用同一套解析,見各自 issue):
> 1. **vault 萃取**`/wiki-extract`template#5):marker → 卡片 frontmatter `task_status`。
> 2. **tasks→Project 投影**`system-dev/workflows/tasks-project-sync.*`template#4):
> 當投影來源是 Logseq graphnotes/kb)時,用這份判斷任務與狀態。
>
> 兩者**只共用「怎麼 parse」**(哪幾行是任務、marker 是什麼、正規狀態是什麼、跳過什麼);
> parse 完各自要「拿狀態做什麼」(寫卡 vs 投影 issue)不同,那部分各管各的。
---
## 為什麼不是 GFM checkbox(規格更正,leo 2026-07-04 發現)
Logseq 的原生任務**不是** GFM 的 `- [ ]` / `- [x]`,而是**大寫 marker 開頭的 block**
```
- TODO AI 查看 leo21c 內所有 Repo,找到本地 Repo 搬到 Gitea
- DOING 建立知識總庫,可查所有子庫
- DONE 手機和電腦 Logseq 可以被放進知識總庫
```
若照舊規格只抓 `- [ ]` checkbox**notes / kb 兩個 Logseq graph 的任務會全數漏抓**。
> 兩種源、兩套語法、同一條下游管線:
> - **SDD `tasks.md`**(各 repo `system-dev/docs/3-specs/**`)→ GFM checkbox(現行不變)。
> - **Logseq graphnotes / kb** → 本檔的大寫 marker。
---
## 解析規格
### 1. 任務行辨識(regex
```
^\s*- (TODO|DOING|NOW|LATER|WAITING|DONE|CANCELED|CANCELLED)\s+
```
- marker 必須是 block`-` bullet)的**開頭第一個 token**、全大寫、後接空白。
- `CANCELED` 與英式 `CANCELLED` 皆收(Logseq 兩種都產)。
- marker 後面到行尾(或到子 bullet 之前)是**任務內文**。
### 2. marker → 正規狀態(task_status
| Logseq marker | 正規 task_status |
|---------------|------------------|
| `TODO``LATER` | `todo` |
| `DOING``NOW` | `in-progress` |
| `WAITING` | `blocked` |
| `DONE` | `done` |
| `CANCELED``CANCELLED` | `closed` |
> `LATER`/`NOW` 是 Logseq「排程視圖」用的同義 markerLATER≈TODO、NOW≈DOING),
> 正規化後與 TODO/DOING 併軌,下游不必區分。
### 3. 必須跳過的東西(別當任務內文)
Logseq 的任務 block 底下常掛時間戳與屬性行,這些**不是內文**,解析時整段略過:
- **`:LOGBOOK:``:END:` 區塊**:marker 被點擊計時產生的時間戳紀錄。
遇到 `:LOGBOOK:` 那行起、到 `:END:` 那行止(含兩端),整塊丟掉。
- **屬性行 `key:: value`**:如 `collapsed:: true``id:: 65a...``SCHEDULED:: <...>`
`DEADLINE:: <...>`。凡符合 `^\s*[\w-]+:: ` 的行都是屬性,不是內文。
`SCHEDULED`/`DEADLINE` 的日期若下游要用可另抓,但**不得當任務描述文字**。)
### 4. 巢狀子 bullet
任務 block 底下縮排的子 bullet 是該任務的補充說明(非獨立任務,除非子 bullet 自己也帶 marker)。
萃取時可併入該任務的描述脈絡;投影時只取母 block 那行當任務標題。
---
## 自檢(實作或 LLM 執行前跑一遍)
- [ ] 用的是大寫 marker regex**不是** `- [ ]` checkbox。
- [ ] 八個 marker 全部覆蓋(含 `LATER`/`NOW`/`CANCELLED` 別漏)。
- [ ] `:LOGBOOK:...:END:``key:: value` 屬性行有跳過,沒混進任務文字。
- [ ] 狀態用上表**正規名**`todo`/`in-progress`/`blocked`/`done`/`closed`),不是原始 marker 字面。
+56
View File
@@ -0,0 +1,56 @@
# 文件分類索引
> CC 整理文件時的分類依據。找不到分類就問,不要猜。
---
## 分類規則
| 目錄 | 放什麼 | 判斷標準 |
|------|--------|---------|
| **1-vision/** | 為什麼做這個 | 產品願景、北極星、設計哲學 |
| **2-architecture/** | 系統怎麼設計的 | 架構圖、技術棧、元件關係 |
| **2-architecture/decisions/** | 為什麼這樣設計 | ADR,選A不選B的原因 |
| **3-specs/** | 要做什麼 | SDD,每個子系統一個目錄 |
| **4-guides/** | 怎麼做 | 部署、開發流程、CLI 用法 |
| **5-records/** | 發生過什麼 | 歷史記錄,不修改只增加 |
| **5-records/incidents/** | 生產問題復盤 | 故障原因、時間線、改進方案 |
| **5-records/test-reports/** | 測試結果 | 壓測報告、驗收記錄 |
| **6-user/** | 給使用者看的 | README、安裝教學、FAQ |
---
## CC 整理文件時的判斷流程
```
這個文件是...
├── 有明確子系統 + 設計內容? → docs/3-specs/[子系統]/
├── 解釋為什麼做某個決定? → docs/2-architecture/decisions/
├── 說明怎麼操作? → docs/4-guides/
├── 記錄發生過的事? → docs/5-records/
├── 給外部使用者看的? → docs/6-user/
└── 以上都不確定? → 列為「待確認」,問負責人
```
---
## SDD 結構(docs/3-specs/ 下每個子系統)
```
docs/3-specs/[子系統名]/
├── design.md ← 設計文件(要做什麼、怎麼做、邊界在哪)
└── tasks.md ← 任務清單([ ] 未開始 [🔄] 進行中 [x] 完成)
```
CC 動手前必須有這兩個檔案。找不到就停手。
---
## system-dev/wiki/ — CC 的記憶空間(CC 維護,人不手動編輯)
| 檔案 | 用途 | 更新時機 |
|------|------|---------|
| `INDEX.md` | wiki 導引 | 新增 wiki 檔案時 |
| `mistakes.md` | CC 已知誤解 + 避坑 | 每次被糾正後 |
| `status.md` | 當前進度 + 下一步 | 每次 session 結束 |
| `decisions-summary.md` | 架構決策摘要 | 重大決策後 |
+260
View File
@@ -0,0 +1,260 @@
---
name: wiki-cowork-scan
description: "掃描本機 Documents 下所有裝了 system-dev-template 的資料夾,自動整理 LLM Wiki。支援一般專案、Logseq vault、Obsidian vault 三種結構,偵測方式與 install.sh 一致。觸發時機:使用者說「整理 wiki」「幫我掃 wiki」「更新我的 wiki」「wiki 掃描」,或 Cowork cron 定期觸發。"
---
# Wiki Cowork Scan
## 核心原則
這個 skill 與 Claude Code 的 `/wiki-init` `/wiki-capture` 共用同一套規則:
| 層 | 規則 |
|------------|-------------------------------------------|
| raw source | 只讀,不動 |
| `system-dev/wiki/` | 唯一輸出地點,只增不覆 |
| `CLAUDE.md` | 不動 |
| `logseq/``.obsidian/``assets/` | 絕對不動 |
**CC 和 Cowork 輸出格式相同,任何一方整理過的內容,另一方看到就跳過或補充,不覆蓋。**
---
## 第一步:發現所有目標資料夾
掃描 `~/Documents`(遞迴深度 3 層),找出所有含 `system-dev/wiki/` 的資料夾。
```
~/Documents/
project-a/system-dev/wiki/ ← ✅ 目標
Logseq/system-dev/wiki/ ← ✅ 目標
其他資料夾/ ← ❌ 跳過
```
找到後列出清單,告訴使用者:「找到 N 個 wiki 資料夾,開始整理。」
---
## 第二步:對每個資料夾偵測 vault 類型
進入每個目標資料夾的**根目錄**`system-dev/wiki/` 的上兩層),依序判斷:
### 判斷順序(與 install.sh 一致)
```
if 根目錄有 logseq/ 資料夾
→ vault 類型:Logseq
→ raw sourcepages/、journals/
→ 忽略:logseq/、assets/
else if 根目錄有 .obsidian/ 資料夾
→ vault 類型:Obsidian
→ raw source:根目錄下所有 .md(排除 .obsidian/ 內的檔案)
else
→ vault 類型:一般專案
→ raw sourcedocs/ 下所有 .md
```
---
## 第三步:讀取現有 wiki 狀態
進入 `system-dev/wiki/`,讀取:
- `INDEX.md`:目前已有哪些 wiki 頁面(多角度視圖入口)
- `status.md`:上次整理時間、進度
- `principles.md`(如果有):本專案跨全局的設計原則——整理時必須服從
目的:**知道哪些已整理過,只處理新增或有變動的 raw source**,不重複整理。
---
## 第四步:整理規則
### 核心判準:push vs pullwiki 是給 AI 看的)
整理任何內容前,先判斷它該進 **push 檔****cardspull**——判準是「**CC 做事時會不會被動看見**」:
- **push 檔**`status.md` / `mistakes.md` / `principles.md`):CC session 開始就被 hook 注入。給「CC 不會主動查、但不看就出事」的東西。
- **pull**`cards/`):CC 想到要查才看見。一切知識內容(原文摘要、AI 筆記、決策、概念…)都寫成 cards。
| 內容 | 去哪 | 理由 |
|------|------|------|
| 當前進度、下一步 | `status.md`(push 全文) | 時態狀態,不看會重做 |
| 跨全局設計原則(一行一條,≤15) | `principles.md`(push 全文) | 會被遺忘的盲區,CC 設計時必服從 |
| 踩坑、被糾正的誤解 | `mistakes.md`(push 摘要+按需展開) | 防 CC 不自覺的盲區 |
| 決策、原文摘要、概念知識、其餘一切 | `cards/<bucket>/`(pull) | 知識內容;CC 面對時自然會查 |
> `decisions-summary.md` 已**降級為 cards + INDEX 決策視圖**(決策=知識內容)。既有的保留為相容,不刪。
> CC 與 Cowork **共用此判準**,產出一致:任一方寫進 push 檔或 cards,另一方看到就跳過或補充,不覆蓋。
### 讀 raw source
逐一讀取 raw source 的 `.md` 檔。跳過:
- 檔名以 `.` 開頭的隱藏檔
- `.wikiignore` 裡列出的 glob pattern(如果存在)
- 含有 `<!-- wiki:ignore -->` 標記的區段
### 整理邏輯
每個 raw source 檔案,判斷:
1. **INDEX.md 裡已有對應條目,且 raw source 未修改** → 跳過
2. **INDEX.md 裡已有條目,但 raw source 有新內容** → 更新對應 wiki 頁面,補充新資訊,不刪舊內容
3. **INDEX.md 裡沒有對應條目** → 新建 wiki 頁面
### Wiki 卡片格式(概念原子卡,存到 `cards/<bucket>/`
```markdown
---
tags: [知識管理, AI協作, 方法論]
gloss: 一句話定義這個概念是什麼(給下游語義 normalize 用,選填、deep tier 才產)
---
# 概念全名
← [[<bucket>/00-INDEX]]
**來源**`[raw source 相對路徑]`
**最後更新**YYYY-MM-DD
## 摘要
[一句話核心]
## 重點
- [自包含改寫的要點,不寫「詳見原文」]
## 實體
> 本卡內文的關鍵實體(也是 graph node)。名+描述一起供下游 embedding normalize。
> AI 生產、人不必讀;集中放、一實體一行、不縮排、不重複。
- **原子筆記**atomic note/卡片原子化)— 每張卡只承載一個不可再分論點的知識記錄單元。
- **傳統筆記**(大鍋炒筆記)— 把多主題混雜在同一篇、難精確引用的記錄方式。
## 關聯
### 內文知識關係(內文實體間;端點=上方 `## 實體` 的正規名,一字不差)
- 原子筆記 >> 對立於 >> 傳統筆記
- 傳統筆記 >> 犧牲 >> 精確引用
### 卡片關係(卡對卡)
- [[本卡]] >> 謂詞(動詞短語) >> [[他卡]]
```
### 架構:三層 + 標籤橫切(183 卡實證)
```
INDEX.md ← 頂層:標籤視圖(非資料夾列表)
TAXONOMY.md ← 標籤字典(受控擴充:先查重再登記)
cards/<bucket>/
├── 00-INDEX.md ← 桶子索引(固定名,容器:只連不重寫)
└── <概念全名>.md ← 概念原子卡
```
- **資料夾只是儲存桶,分類由 frontmatter `tags:` 承載**——不繼承原稿目錄,由 AI 重新組織。
- **桶子索引固定名 `00-INDEX.md`**`00-` 排序最前、一眼可辨,載入任何桶先讀它。
- **frontmatter `tags:` 而非行內 `#tag`**:內文常用 `#`(如 `#猜想`),行內標籤會讓 ingest 分不清「分類」與「內文範例」污染 graph;frontmatter 零歧義。標籤只能用 `TAXONOMY.md` 列出的;**禁止繞過字典在卡片直接冒新標籤**,但字典可受控擴充(遇新軸先查重、確認非同義詞,再登記進本 repo 的 TAXONOMY.md)。
- **麵包屑帶路徑**H1 次行 `← [[<bucket>/00-INDEX]]`。指 `00-INDEX` 因固定名跨桶撞名,**一律帶路徑**;卡片間連結用裸 `[[卡名]]`
### 使用 typed-edge 三元組(抓內文實體關係,不只卡對卡)
用**帶語義的三元組** `A >> 謂詞 >> B` 寫進 `## 關聯`。**重點是抓內文裡的實體關係**——卡對卡(`[[卡A]] >> 謂詞 >> [[卡B]]`)只是把既有雙鏈加個動詞、資訊量幾乎沒增加;知識圖譜的價值在內文概念間的關係(`原子筆記 >> 對立於 >> 傳統筆記`,這些 A/B 是內文概念、不是卡標題)。
格式 `A >> 謂詞 >> B`,規則:
1. **方向性**:必須讀成「A(謂詞)B」一句通順的話;A、B 順序=主→賓真實方向。
2. **謂詞用動詞 / 動詞短語**(反駁、奠基於、犧牲),天然帶方向。**禁名詞當謂詞**——`>> 存儲格式 >>``>> 操作體驗 >>` 讀不通,是錯的。
3. **謂詞自由書寫但別太天馬行空**:寫「參考/參照」皆可(下游 embed 自動聚類同義謂詞),別寫「瞄了一眼」這種抓不到同義的。
4. **內文三元組端點用裸文字**(非 `[[wikilink]]`),避免在 Logseq 產生大量紅色斷鏈;卡對卡那層才用 `[[]]`
5. **向後相容**:純 `[[A]]` 仍合法(無類型邊),盡量補謂詞。
> **★ 硬自檢(Haiku 量產必備護欄)★** —— 內文三元組的「端點 = `## 實體` 詞條」
> `A >> 謂詞 >> B` 的 A、B 必須與 `## 實體` 某個粗體正規名【一字不差】。**寫完後逐條自檢**:把 A、B 拿去 `## 實體` 找有沒有完全相同的正規名,沒有 → 這條錯了。
> 修法擇一:(a) 改用實體表已有的詞;(b) 端點確是重要實體 → 補進 `## 實體` 再指它。
> 禁止:端點帶括號註解、端點是整句補語、端點是形容詞短語。
> (實證:光寫規則 Haiku 會略過,端點對不齊 14 條;寫成自檢動作後 14→0。跑 1-2 張看不出,跑 12 張才暴露。)
`>>` 為分隔語法,全程一致即可。這是 Karpathy LLM Wiki「知識互連」的強化版——連結不只存在,還帶類型與方向。
### 萃 glossnode 一句說明,供下游語義 normalize)
每張卡=一個 entity / graph node。deep tier 改寫時,frontmatter 補一句 `gloss:`——這個 node 是什麼的一句定義。下游 KBDB 對「entity 名 + gloss」一起做 embedding 求相似度,自動歸一同義詞(比只對名字準、比手維護 alias 表自動)。
- **在知識生產的當下、由整理者(CC / Cowork)建**:gloss 跟三元組同階段萃,**不留給下游 ingest 臨時補**——下游只有單檔/跨庫視角,編不出貼合的 gloss。
- **選填、deep tier 才產**:淺萃不浪費。
- **gloss ≠ 摘要**`gloss` 是 frontmatter 給機器 normalize 的定義句(「X 是…」);`## 摘要` 是給人讀的核心句。
- **兩層 gloss**:① frontmatter `gloss:` 描述「卡標題」這個 node;② `## 實體` 區塊的每行描述句,描述「內文實體」這些 node。**內文實體也是 graph node、也需描述句**才能被下游 embedding normalize`黃仁勳` vs `Jensen Huang` 靠描述拉近向量)。
- **實體要描述、謂詞不用**:實體同義詞字面差遠需描述拉近;謂詞同義詞字面本就近,裸詞 embed 自動聚類。
- **對齊下游 envelope**frontmatter `gloss:``## 實體` 詞條對應 ingest envelope 的 `nodes[].gloss`
> **改寫時必守**:① 絕不寫入 raw source(只往 `cards/<bucket>/` 寫,事後驗 raw source 0 異動);② 檔名=卡片全名,冒號用全形「:」、斜線用全形「/」,全程一種字元避免斷鏈。
---
## 第五步:更新 INDEX.md 和 status.md
### INDEX.md 格式(頂層 = 標籤視圖)
頂層 INDEX 按 `TAXONOMY.md` 的軸聚類,指向各桶子索引(帶路徑),不是平鋪頁面列表:
```markdown
# Wiki Index
> 最後更新:YYYY-MM-DD HH:MM | 來源:cowork-scan | 總卡數:N
### 知識管理
- [[pkm/00-INDEX]] — PKM 知識管理(N 卡)
### AI 協作
- [[ai/00-INDEX]] — AI 協作(M 卡)
```
桶子索引 `cards/<bucket>/00-INDEX.md` 是容器(只連不重寫,H2/H3 分節列出該桶卡片)。
### status.md 更新
在現有內容**末尾追加**(不覆蓋):
```markdown
## YYYY-MM-DD HH:MMcowork-scan
- vault 類型:[Logseq / Obsidian / 一般專案]
- 掃描檔案:N 個
- 新增頁面:N 個
- 更新頁面:N 個
- 跳過:N 個(未變動)
```
---
## 第六步:回報結果
整理完所有資料夾後,輸出摘要:
```
✅ Wiki 整理完成
資料夾 1~/Documents/project-a
類型:一般專案
新增:3 頁,更新:1 頁,跳過:12 頁
資料夾 2~/Documents/Logseq
類型:Logseq vault
新增:5 頁,更新:2 頁,跳過:47 頁
總計:8 頁新增,3 頁更新
```
---
## 絕對禁止
- ❌ 修改任何 raw source 檔案
- ❌ 修改 `CLAUDE.md`
- ❌ 動 `logseq/``.obsidian/``assets/` 資料夾
- ❌ 刪除 `system-dev/wiki/` 裡已有的頁面(只增補,不刪除)
- ❌ 把機敏資訊(密碼、金鑰、個資)寫進 wiki(遇到跳過並記錄)
- ❌ 整理沒有 `system-dev/wiki/` 的資料夾(那不是這個 skill 的目標)
+36
View File
@@ -0,0 +1,36 @@
# .wikiignore — 不想被編入 wiki 的內容(像 .gitignore
#
# 三層防護的 L1(檔案層)。CC 在 /wiki-init、/wiki-capture 掃描文件時,
# 命中這裡 pattern 的「整個檔案」不讀、不編入 wiki。
#
# 語法:一行一個 glob pattern,相對專案根目錄。# 開頭是註解。
#
# ── 同場另兩層 ──────────────────────────────────────
# L2 行內標記:檔案要編入,但某段不要 → 在該段前後包:
# <!-- wiki:ignore -->
# 這幾行不會被編入 wiki
# <!-- wiki:end -->
# L3 機械底線:萬一機敏值仍被寫進 system-dev/wiki/wiki-secret-scan.sh 會 exit 2 擋下。
#
# 三層的分工:L1 整檔排除(你主動列)|L2 局部遮蔽(你標記)|L3 兜底攔截(自動掃)。
# ────────────────────────────────────────────────────
# ── 機敏檔案(預設就該排除)──────────────────────
.env
.env.*
*.pem
*.key
*.p12
*.pfx
*credentials*
*secret*
**/secrets/**
# ── 個資 / 客戶資料(依專案調整)────────────────
# customers/**
# *personal-data*
# ── 草稿 / 暫存(不值得進記憶)──────────────────
# **/draft/**
# *.tmp.md
# SCRATCH.md
+60
View File
@@ -0,0 +1,60 @@
# system-dev/wiki/ — LLM 記憶系統
> 新 session 開始時從這裡導航。
> 目的:讓 CC 不需要重新學習已知的事。
> 維護者:CC(人不手動編輯這裡)
---
## push 檔(session 開始由 hook 主動注入,CC 行動前必看見)
| 檔案 | 注入形態 | 內容 |
|------|---------|------|
| `status.md` | 全文 | 當前進度、下一步(時態狀態)|
| `principles.md` | 全文(一行一條)| 跨全局設計原則,行動前必服從 |
| `mistakes.md` | 標題+一行症狀,全文按需展開 | 踩過的坑、被糾正的誤解(防不自覺盲區)|
> 為什麼這三個 push 而非 pull:它們是「CC 不會主動查、但不看就出事」的盲區。詳見 `/wiki-init` 的「push vs pull」。
---
## pullcards/CC 按需檢索)
一切知識內容——原文摘要、AI 筆記、決策、概念知識——都寫成 `cards/<bucket>/` 的概念原子卡。
`decisions-summary.md` 已降級為 cards(決策=知識內容);既有的保留為相容。
---
## 維護規則
1. 只增不刪——記錄 append,內容改了加新條目說明「舊的已更新」
2. status.md 每次 session 結束更新;mistakes/principles 一發現就 append
3. principles 一行一條、≤15 條(超過代表該合併或下放成 card)
4. **新增一個檢索角度 = 在下方「多角度視圖」加一節,不開新實體檔、不問用戶**
---
## 多角度視圖(由 /wiki-init、/wiki-capture 填入)
INDEX 是**所有檢索角度的入口**,不只標籤。原文是唯讀 SSoT,wiki 是改寫過的記憶。
新增角度只要在這裡加一節(如「決策角度」「原則角度」),指向對應 cards 或 push 檔——**不必新增實體特殊檔**。
### 標籤角度(按 `TAXONOMY.md` 的軸聚類,指向桶子索引)
```markdown
#### 知識管理
- [[pkm/00-INDEX]] — PKM 知識管理(N 卡)
#### AI 協作
- [[ai/00-INDEX]] — AI 協作(M 卡)
```
### 決策角度(取代舊 decisions-summary.md 的視圖)
```markdown
- [[某決策卡]] — 一句話結論(YYYY-MM-DD
```
> 結構:INDEX(多角度入口)→ `cards/<bucket>/00-INDEX.md`(桶子索引,固定名)→ 概念原子卡。
> 指 `00-INDEX` **一律帶路徑** `[[bucket/00-INDEX]]`(固定名跨桶撞名);卡片間用裸 `[[卡名]]`。
> 分類由卡片 frontmatter `tags:` 承載,標籤字典見 `TAXONOMY.md`。詳見 `/wiki-init` 規範。
+50
View File
@@ -0,0 +1,50 @@
# TAXONOMY.md — 標籤字典(本 repo 專屬)
> wiki 卡片的 frontmatter `tags:` **只能用這裡列出的標籤**。
> 這不是凍結——字典**可以擴充**,只是**禁止繞過字典在卡片裡直接冒新標籤**。
> 維護者:CC(由 /wiki-init 初始化、隨 wiki 演進受控擴充)。
>
> **遇到現有軸都裝不下的內容時,照這個流程(先查、後擴、登記)**:
> 1. **先查既有**:現有標籤真的都不合,還是只是同義詞?(`知識管理` vs `KM` vs `筆記管理` 是同一軸,別重造)
> 2. **確實是新軸** → 把新標籤加進本檔(附一句定義),再用。不必停下來問人,但「先登記再使用」這道查核不能省。
> 3. 自由增生才是要防的——同義標籤散開會讓同類卡片分散、下游聚類失準。受控擴充(先查重、再登記)不會。
>
> **字典是每個 repo 各自的**:跨 repo 引擎靠各 repo 自己一致的 taxonomy 接合,不是逼所有 repo 共用一份。
> 知識型 vault 的領域軸(知識管理/學習認知)和開發 repo(子系統/基礎設施)本來就該不同。
---
## 分類採雙軸(一張卡可多重歸屬)
分類由 **frontmatter `tags:`** 承載,不靠資料夾、不靠行內 `#tag`
一張卡同時掛「領域 1-3 個 + 形態 0-2 個」,可從任一軸過濾。
### 領域(主軸,每卡 1-3 個)
> 由 /wiki-init 依專案性質提出。以下為 PKM / 知識型 vault 的實證一組,請按你的專案調整:
- `知識管理`
- `學習認知`
- `AI協作`
- `生產力`
- `系統設計`
- `工具教學`
(一般開發專案的領域軸可能是:`子系統A` / `子系統B` / `基礎設施` / `前端` / `後端` …)
### 形態(副軸,每卡 0-2 個)
- `方法論`
- `工具實作`
- `觀點主張`
- `架構設計`
- `案例經驗`
---
## 規則
1. **先查重、再登記、才使用**:禁止繞過字典在卡片直接冒新標籤;新標籤先確認非現有同義詞,加進本檔(附定義)再用。
2. **領域 vs 形態分開**:領域是「講什麼主題」,形態是「以什麼形式呈現」,不要混。
3. **頂層 INDEX.md 的標籤視圖依本字典的軸聚類**——字典改了,INDEX 視圖跟著更新。
4. **新增領域軸要慎**:領域是檢索骨架,動它影響全庫聚類;形態軸(呈現形式)擴充較安全。不確定就先用現有最接近的,並在卡片或本檔註記「待人類複核此分類」。
@@ -0,0 +1,14 @@
# 架構決策摘要
> 遇到設計判斷時查這裡。
> 完整脈絡在 system-dev/docs/2-architecture/decisions/。
---
(初始化時為空,隨專案進行 append)
格式:
## [主題] — [YYYY-MM-DD]
**結論**[一句話]
**原因**[簡短說明]
**詳細**system-dev/docs/2-architecture/decisions/[對應檔案]
+25
View File
@@ -0,0 +1,25 @@
# CC 已知誤解 + 避坑方法
> 做新功能前讀一遍。
> 格式:每條必須有症狀 + 正確做法 + 原因。
---
## 快速檢查清單(做任何事前)
- [ ] 有對應 SDD 嗎?沒有 → 停手
- [ ] 這次修改會影響哪些模組?有沒有連帶破壞?
- [ ] 驗收標準是什麼?有客觀證據嗎?
---
## 誤解記錄
(初始化時為空,隨專案進行 append)
格式:
⚠️ MISTAKE: [錯誤描述,一句話]
症狀: [CC 通常怎麼表現這個錯]
正確做法: [應該怎麼做]
原因: [為什麼會錯]
日期: [YYYY-MM-DD]
+18
View File
@@ -0,0 +1,18 @@
# principles — 跨全局設計原則(push:CC 行動前必服從)
> 這個檔由 hook 在 session 開始**全文注入**,讓 CC 設計任何東西前都先看見這些準繩。
> 為什麼 push 而非寫成 card:原則是「會被遺忘的盲區」——沒推到眼前,CC 設計時很可能沒想到要服從就做了。
>
> 規則:**一行一條**,精煉成準繩(不是長篇論述)。≤15 條;超過代表某些該合併、或下放成 card。
> 發現新的跨全局原則 → append 一行。累積原則只改這個檔,**不必問用戶開新檔**。
> 區分:原則 = 反覆適用的準繩(這裡);單次選擇 = 決策(寫成 card);踩過的坑 = mistakes.md。
---
## 原則
<!-- 一行一條。範例格式:
- **不污染用戶根目錄**:工具產物收進專屬資料夾,不在用戶根目錄撒檔、不跟用戶自己的檔混。
-->
(尚未填入。由 /wiki-init 或 /wiki-capture 依本專案累積。)
+22
View File
@@ -0,0 +1,22 @@
# 當前狀態
> 更新時間:[初始化時填入]
> 每次 session 結束必須更新此檔。
---
## 正在做
(初始化後填入)
## 下次 session 第一件事
(初始化後填入)
## 待負責人確認
(無)
## 已知問題
(無)
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
# tasks-project-sync.local.sh — 本地觸發端(投影的「本地一半」)
#
# 來源:issue #16;設計:system-dev/docs/3-specs/tasks-project-projection/design.md
#
# ── 為什麼有這支(職責邊界)──────────────────────────────────────
# arcrun workflow 跑在遠端 CF Workers,沒有本地 fs / git / shell。
# 所以「讀 tasks.md / git diff / 回寫 <!-- gh:id -->」這三件本地事
# 不能放進 workflow(arcrun 也沒有對應零件,這是架構邊界、不是缺口)。
# 這支就是那「本地一半」:分類好增量 → 交給 acr run 打 GitHub。
#
# 這支(本地):讀 tasks.md → git diff → 分類四動作 → acr run 投影 → 回寫新 id
# │
# ▼
# tasks-project-sync.yaml(遠端):foreach → switch → github API
#
# ── 怎麼觸發(守 flag 紅線)─────────────────────────────────────
# push 後「本機觸發單次」,非 cron、非輪詢、非 GitHub Actions。
# 掛載點建議:本機 git post-push 類 hook,或叫 CC 在 push 後跑這支一次。
# ⚠️ 具體掛載點與「分類四動作」的精確 parse,待 leo21c 端到端驗證後定稿;
# 目前是 code-done 骨架,標出該做什麼、邊界在哪,不假裝已通。
#
# ── 用法 ───────────────────────────────────────────────────────
# tasks-project-sync.local.sh <owner> <repo> <project_id>
#
# 前置:acr 在 PATH、github_token 已 acr creds push、workflow 已 acr push。
set -euo pipefail
OWNER="${1:?需要 owner}"
REPO="${2:?需要 repo}"
PROJECT_ID="${3:?需要 GitHub Projects v2 node id}"
# 多組 SDD 全同步:glob 掃所有 tasks.md(新 folder 自動成組,免手動登記)。
GLOB="system-dev/docs/3-specs/*/tasks.md"
# ── 1. 分類增量(git diff 知道改了哪幾行 → 四動作)──────────────
# 這裡是「本地一半」的核心。實作策略(待端到端驗證後落地):
# - 拿 push 前後的 git diff,限定 $GLOB 範圍,只看動到的行。
# - 每行 task 解析:有無 `<!-- gh:N -->` id、checkbox 是否 [ ]→[x]、文字/負責人/日期變動。
# - 行不見(diff 的刪除行)且原本有 id → archive。
# - 子系統 = 該 tasks.md 的 folder 名(當 label 分組)。
# - 產出 tasks_json 陣列(格式見 yaml 註解)。
#
# ⚠️ 刻意不在這支用 TS/Python 刻複雜 parser(守薄殼)。複雜分類交給 CC 在 push 後
# 讀 diff 直接產 tasks_json;這支保持「薄殼 + 交棒 acr run」。若未來證明需要可重用的
# parser 零件,那屬於 arcrun 零件缺口 → 回報 issue #16 由 arcrun 端補,不在此自刻。
#
# 佔位:實際 tasks_json 由 CC 依上述策略產生後填入。
TASKS_JSON="${TASKS_JSON:-[]}"
if [ "$TASKS_JSON" = "[]" ]; then
echo "(無增量 → 本次 no-op,不呼叫 GitHub"
exit 0
fi
# ── 2. 交給遠端 workflow 投影 ───────────────────────────────────
acr run tasks_project_sync \
-i owner="$OWNER" \
-i repo="$REPO" \
-i project_id="$PROJECT_ID" \
-i tasks_json="$TASKS_JSON"
# ── 3. 回寫新 task 的 id(唯一對 md 的寫入,只在 create 時做一次)──
# create 動作的回傳 issue number → append `<!-- gh:N -->` 到該行末。
# ⚠️ 防迴圈:回寫造成 working tree 變動,這次回寫「不得」再觸發一輪投影
# (否則 push→觸發→回寫→又一個 diff→又觸發…)。實作時觸發端要排除
# 「只動到 <!-- gh:N --> 註解」的 diff,或回寫走 [skip-sync] 標記。
# 具體機制待端到端驗證定稿。
echo "(新 task 的 id 回寫:待端到端驗證後接上 acr run 的回傳 → append <!-- gh:N -->"
@@ -0,0 +1,152 @@
# tasks-project-sync — tasks.md ⇄ GitHub Project 單向投影
#
# 來源:issue #16;設計:system-dev/docs/3-specs/tasks-project-projection/design.md
#
# ── 這份 workflow 的職責邊界(很重要,別搞混)──────────────────
# arcrun workflow 在 Cloudflare Workers / WASM 上「遠端」執行,沒有本地檔案系統、
# 沒有 git、沒有 shell。所以「讀 tasks.md / 跑 git diff / 把 <!-- gh:id --> 回寫 md」
# 這三件事 **不是、也不該是 workflow 的步驟**——它們由本地觸發端(CC / push 後本機腳本)
# 先做完,把「分類好的 task 增量」當 input 餵進來(acr run -i tasks_json=...)。
#
# 本地端(住 templateCC/shell 跑):讀 tasks.md → git diff → 分類四動作 → 回寫 id
# │ acr run tasks-project-sync -i ...(把增量餵進來)
# ▼
# 遠端 workflow(這份 yaml):foreach 增量 → switch 動作 → github API 投影
#
# → 因此本 workflow 只負責「拿到分類好的增量後,打 GitHub API 投影成 issue/Project」。
# 單向:只寫 GitHub,永不回改 tasks.md(回寫 id 是本地端的事,且只在新 task 做一次)。
#
# ── 輸入(由本地觸發端用 acr run -i 餵)──────────────────────────
# owner GitHub repo owner(例:your-github-account
# repo GitHub repo 名
# project_id GitHub Projects v2 的 node id(投影目標,唯讀看板)
# tasks_json 本地分類好的增量陣列,每筆形如:
# { action: "create|close|edit|archive",
# gh: 42, # 已有 id 的帶上(create 無)
# title: "...", body: "...",
# subsystem: "wiki-architecture", # = SDD folder 名,當 label 分組
# assignee: "...", due: "..." }
#
# ── credential ─────────────────────────────────────────────────
# github_tokenacr auth-recipe scaffold github → 填 credentials.yaml → acr creds push
#
# ⚠️ 端到端(acr push 真部署 + acr run 真投影)尚未經 leo21c 驗證。
# 本檔為 code-done 骨架;真部署時 GitHub API 的欄位細節(Projects v2 GraphQL
# 可能要按實測微調,屆時於 issue #16 回報。
name: tasks_project_sync
description: >
把 SDD tasks.md 的待辦增量單向投影成唯讀 GitHub Projectissue CRUD + 加進 Project)。
本地端先讀檔/git diff/分類/回寫 id,這份只負責拿增量打 GitHub API。md 當家、單向、不反向同步。
# ── flow(三元組:A >> 關係詞 >> B)─────────────────────────────
# 對每筆增量 → 依 action 路由到四種 GitHub 動作。
flow:
- "input >> 完成後 >> each_task"
- "each_task >> 對每個 task >> route_action"
# 四種動作(issue 定案):新增/關閉/編輯/封存
- "route_action >> 完成後 >> gh_create"
- "route_action >> 完成後 >> gh_close"
- "route_action >> 完成後 >> gh_edit"
- "route_action >> 完成後 >> gh_archive"
# 新建的 issue 投影進 Project(唯讀看板)
- "gh_create >> 完成後 >> add_to_project"
config:
# 逐筆迭代本地餵進來的分類增量
each_task:
component: foreach_control
iterator: task
# 依 action 欄位分流到四種 GitHub 動作
route_action:
component: switch
key: "{{task.action}}"
cases:
create: gh_create # 有文字、無 id → 建 issue(id 由本地端回寫 md)
close: gh_close # 有 id 且 [ ]→[x] → 關 issue
edit: gh_edit # 有 id 且 文字/負責人/日期改 → 編輯 issue
archive: gh_archive # id 在但整行不見 → 關閉/封存
# ── 動作 1:建 issueREST POST /repos/:owner/:repo/issues)──
# 回傳的 issue number 由本地觸發端接住、回寫 <!-- gh:number --> 到那一行。
# ⚠️ 用 http_requestarcrun registry 沒有 github 零件,21 內建確認過);
# auth 走 credential{{creds.github_token}}acr creds push 上傳,不寫死 token)。
gh_create:
component: http_request
url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues"
method: POST
headers:
Accept: "application/vnd.github+json"
Authorization: "Bearer {{creds.github_token}}"
User-Agent: "arcrun-tasks-project-sync"
body:
title: "{{task.title}}"
body: "{{task.body}}"
labels:
- "{{task.subsystem}}" # 子系統 label 分組(= SDD folder 名)
assignees:
- "{{task.assignee}}"
# ── 動作 2:關 issuestate=closed)──
gh_close:
component: http_request
url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{task.gh}}"
method: PATCH
headers:
Accept: "application/vnd.github+json"
Authorization: "Bearer {{creds.github_token}}"
User-Agent: "arcrun-tasks-project-sync"
body:
state: closed
# ── 動作 3:編輯 issue(標題/內文/負責人)──
gh_edit:
component: http_request
url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{task.gh}}"
method: PATCH
headers:
Accept: "application/vnd.github+json"
Authorization: "Bearer {{creds.github_token}}"
User-Agent: "arcrun-tasks-project-sync"
body:
title: "{{task.title}}"
body: "{{task.body}}"
assignees:
- "{{task.assignee}}"
# ── 動作 4:封存(行不見 = 關閉,標 not_planned 表示非完成而是移除)──
gh_archive:
component: http_request
url: "https://api.github.com/repos/{{owner}}/{{repo}}/issues/{{task.gh}}"
method: PATCH
headers:
Accept: "application/vnd.github+json"
Authorization: "Bearer {{creds.github_token}}"
User-Agent: "arcrun-tasks-project-sync"
body:
state: closed
state_reason: not_planned
# ── 投影進 GitHub Projects v2GraphQL)──
# Projects v2 只有 GraphQLREST 沒有。用 http_request 打 /graphql。
# ⚠️ 待 leo21c 端到端驗:addProjectV2ItemById 需要 content node idissue 的 GraphQL id
# 非 issue number),實測時可能要多一步「先查 issue node id」。屆時於 #16 回報。
add_to_project:
component: http_request
url: "https://api.github.com/graphql"
method: POST
headers:
Accept: "application/vnd.github+json"
Authorization: "Bearer {{creds.github_token}}"
User-Agent: "arcrun-tasks-project-sync"
body:
query: >
mutation($project: ID!, $content: ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $content}) {
item { id }
}
}
variables:
project: "{{project_id}}"
content: "{{gh_create.node_id}}"