homunculus-code 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CONTRIBUTING.md +56 -0
  2. package/LICENSE +21 -0
  3. package/README.md +443 -0
  4. package/bin/init.js +317 -0
  5. package/commands/eval-skill.md +48 -0
  6. package/commands/evolve.md +67 -0
  7. package/commands/improve-skill.md +50 -0
  8. package/core/evaluate-session.js +173 -0
  9. package/core/observe.sh +51 -0
  10. package/core/prune-instincts.js +159 -0
  11. package/docs/nightly-agent.md +130 -0
  12. package/examples/reference/README.md +47 -0
  13. package/examples/reference/architecture.yaml +886 -0
  14. package/examples/reference/evolved-agents/assistant-explorer.md +86 -0
  15. package/examples/reference/evolved-agents/shell-debugger.md +108 -0
  16. package/examples/reference/evolved-agents/tdd-runner.md +112 -0
  17. package/examples/reference/evolved-evals/api-system-diagnosis.eval.yaml +125 -0
  18. package/examples/reference/evolved-evals/assistant-system-management.eval.yaml +123 -0
  19. package/examples/reference/evolved-evals/claude-code-reference.eval.yaml +394 -0
  20. package/examples/reference/evolved-evals/development-verification-patterns.eval.yaml +117 -0
  21. package/examples/reference/evolved-evals/multi-agent-design-patterns.eval.yaml +151 -0
  22. package/examples/reference/evolved-evals/shell-automation-patterns.eval.yaml +209 -0
  23. package/examples/reference/evolved-evals/tdd-workflow.eval.yaml +191 -0
  24. package/examples/reference/evolved-evals/workflows.eval.yaml +148 -0
  25. package/examples/reference/evolved-skills/api-system-diagnosis.md +234 -0
  26. package/examples/reference/evolved-skills/assistant-system-management.md +199 -0
  27. package/examples/reference/evolved-skills/development-verification-patterns.md +243 -0
  28. package/examples/reference/evolved-skills/multi-agent-design-patterns.md +259 -0
  29. package/examples/reference/evolved-skills/shell-automation-patterns.md +347 -0
  30. package/examples/reference/evolved-skills/tdd-workflow.md +272 -0
  31. package/examples/reference/evolved-skills/workflows.md +237 -0
  32. package/package.json +25 -0
  33. package/templates/CLAUDE.md.template +36 -0
  34. package/templates/architecture.template.yaml +41 -0
  35. package/templates/rules/evolution-system.md +29 -0
@@ -0,0 +1,209 @@
1
+ # Eval: Shell Automation Patterns
2
+ # 測試案例定義 — 驗證 skill 是否能正確引導行為
3
+
4
+ skill: shell-automation-patterns
5
+ version: "1.6"
6
+ last_eval: "2026-03-19"
7
+ pass_rate: 1.0 # 14/14 scenarios (11 core + 3 boundary)
8
+ total_scenarios: 14
9
+ grader_type: model # model=LLM 判斷 | code=腳本驗證
10
+
11
+ scenarios:
12
+ - id: discord-chunking
13
+ name: "Discord 訊息超過 2000 字元"
14
+ context: |
15
+ 你正在寫一個 shell script,需要把一份 3000 字元的報告發送到 Discord webhook。
16
+ expected_behavior: |
17
+ - 將訊息分成 < 2000 字元的 chunks
18
+ - 每個 chunk 獨立發送
19
+ - 使用 jq -Rs 處理特殊字元
20
+ anti_patterns:
21
+ - "直接發送 3000 字元(會被 Discord 截斷)"
22
+ - "用 Python 或其他語言處理(應該用 shell)"
23
+
24
+ - id: night-no-discord
25
+ name: "夜間不推送 Discord"
26
+ context: |
27
+ 現在是凌晨 3 點,cron job 偵測到異常,需要通知用戶。
28
+ expected_behavior: |
29
+ - 寫入 log 檔或 night-report.md
30
+ - 不推送 Discord(夜間規則)
31
+ anti_patterns:
32
+ - "直接推送 Discord(違反夜間規則)"
33
+
34
+ - id: jq-atomic-update
35
+ name: "JSON 狀態檔案更新"
36
+ context: |
37
+ 你需要更新 state.json 中的一個欄位。
38
+ expected_behavior: |
39
+ - 使用 tmpfile + mv 做原子更新
40
+ - 用 jq --arg 傳入變數(避免注入)
41
+ - 讀取時用 // empty 或 // default 設預設值
42
+ anti_patterns:
43
+ - "直接寫回原檔(非原子操作,crash 會損壞)"
44
+ - "用 echo 拼接 JSON(容易格式錯誤)"
45
+ - "用 sed 修改 JSON(fragile)"
46
+
47
+ - id: claude-in-script
48
+ name: "Shell script 中呼叫 Claude"
49
+ context: |
50
+ 你正在寫一個 cron job,需要用 AI 處理一段文字。
51
+ expected_behavior: |
52
+ - 使用 claude --print(非互動模式)
53
+ - 必須 unset CLAUDECODE
54
+ - 用 stdin 傳入資料(< file)
55
+ - 指定模型 claude-sonnet-4-6
56
+ anti_patterns:
57
+ - "用 claude -p 啟動互動 session(cron 中不適用)"
58
+ - "忘記 unset CLAUDECODE(會干擾巢狀呼叫)"
59
+
60
+ - id: module-autodiscovery
61
+ name: "模組化 check 系統"
62
+ context: |
63
+ 你要為 heartbeat 新增一個 check module。
64
+ expected_behavior: |
65
+ - 放在 checks/ 目錄下,命名為 *.sh
66
+ - 透過環境變數接收 context
67
+ - stdout 輸出 JSON(actions + state_updates)
68
+ - 失敗時不影響其他 module
69
+ anti_patterns:
70
+ - "硬編碼到 heartbeat.sh 主體中"
71
+ - "用 exit 1 中斷整個流程"
72
+
73
+ - id: jsonl-parsing
74
+ name: "解析 Claude session JSONL"
75
+ context: |
76
+ 你需要從 Claude session log(JSONL 格式)中提取 cost 和 turns。
77
+ expected_behavior: |
78
+ - 用 jq select(.type=="result") 直接過濾
79
+ - tail -1 取最後一個 result
80
+ - 2>/dev/null 抑制解析錯誤
81
+ - 用 // fallback 處理缺失欄位
82
+ anti_patterns:
83
+ - "用 grep | echo | jq pipeline(multiline JSON 會壞)"
84
+ - "假設只有一個 result 事件"
85
+
86
+ - id: gmail-in-cron
87
+ name: "Cron 中操作 Gmail"
88
+ context: |
89
+ 你要在排程任務中讀取 Gmail 未讀信件。
90
+ expected_behavior: |
91
+ - 使用 gog CLI(不用 MCP)
92
+ - 指定 --account starpincer@gmail.com
93
+ anti_patterns:
94
+ - "用 Gmail MCP(cron 中不可用)"
95
+
96
+ - id: multi-step-claude-resume
97
+ name: "多步驟 Claude headless 腳本"
98
+ context: |
99
+ 你要在 shell script 中做兩步驟處理:第一步分析程式碼,第二步根據分析結果產出報告。
100
+ 兩步驟需要共享 context(第二步需要知道第一步的結果)。
101
+ expected_behavior: |
102
+ - 第一步用 --output-format json 並提取 .session_id
103
+ - 第二步用 --resume "$SESSION_ID" 接續 context
104
+ - 兩步驟都要 unset CLAUDECODE
105
+ - 或提到 --json-schema 結構化輸出選項
106
+ anti_patterns:
107
+ - "把第一步的輸出塞進第二步的 prompt 作為純文字(context 不連續)"
108
+ - "忘記 unset CLAUDECODE"
109
+ - "只用一個 claude 呼叫完成所有事(不示範多步驟)"
110
+
111
+ - id: error-handling
112
+ name: "模組錯誤處理"
113
+ context: |
114
+ heartbeat check module 執行失敗了。
115
+ expected_behavior: |
116
+ - log 錯誤但繼續執行其他 module
117
+ - 用 || continue 跳過失敗的 module
118
+ - 錯誤寫入 log 檔
119
+ anti_patterns:
120
+ - "set -e 導致整個 heartbeat 中斷"
121
+ - "忽略錯誤不記錄"
122
+
123
+ - id: jq-null-safety
124
+ name: "jq null 安全與 reduce 陷阱"
125
+ context: |
126
+ shell script 中的 jq 指令出現 "Cannot iterate over null" 錯誤,
127
+ 或用 reduce 處理 state.json 時輸出 null。
128
+ expected_behavior: |
129
+ - 加 ? 運算符(.array[]? 而非 .array[])
130
+ - 或用 // [] 提供預設空陣列
131
+ - reduce scope 問題:在外層加 `. as $root |`,reduce 內用 $root.field
132
+ - 除錯步驟:提取 jq 表達式到 CLI 單獨測試
133
+ anti_patterns:
134
+ - "直接用 .field[] 不加 null guard"
135
+ - "在 reduce body 內用 .原始陣列[](應用 $root 捕捉)"
136
+ - "用 try...catch(macOS jq 1.7.1 不支援)"
137
+
138
+ - id: jq-pipe-alternative-precedence
139
+ name: "jq // 優先順序陷阱"
140
+ context: |
141
+ jq 腳本出現 "Cannot iterate over string" 錯誤,
142
+ 或 jq 中用 .field_a // .other_path | .field_b 取值結果不符預期。
143
+ expected_behavior: |
144
+ - 識別問題:| 優先順序低於 //,但 .path | expr // fallback | expr 容易誤解
145
+ - 解法:用括號明確指定 alternative 範圍:(.field_a // .field_b)
146
+ - 正確模式:jq '.items[$i] | (.name // .id)' 而非 jq '.items[$i].name // .items | .[$i].id'
147
+ - 提醒:// 左側若含 | 管線,必須用 () 包住整個表達式
148
+ anti_patterns:
149
+ - "在含 | 的表達式中不加括號直接用 //"
150
+ - "以為 .a | .b // .c | .d 是 (.a | .b) // (.c | .d)"
151
+
152
+ # --- Boundary Scenarios ---
153
+
154
+ - id: boundary-claude-headless-cost-control
155
+ name: "[Boundary] Claude headless 成本控制組合技"
156
+ difficulty: hard
157
+ context: |
158
+ 你要寫一個 cron job 每小時分析 log 檔,但擔心成本失控。
159
+ 需求:限制每次最多花 $0.50、只允許 Read 和 Grep 工具、
160
+ 用 Haiku 模型、output 要 JSON 格式。
161
+ expected_behavior: |
162
+ - 使用 `--max-budget-usd 0.50` 成本上限
163
+ - 使用 `--tools "Read,Grep"` 或 `--disallowedTools "Edit,Write,Bash"` 限制工具
164
+ - 使用 `--model haiku` 或 `claude-haiku-4-5`
165
+ - 使用 `--output-format json` 搭配 `jq -r '.result'`
166
+ - 提到 `unset CLAUDECODE` 和 `--no-session-persistence`(CI/CD 環境)
167
+ anti_patterns:
168
+ - "忘記 --max-budget-usd(成本無上限)"
169
+ - "不限制工具就讓 AI 自由使用(安全風險)"
170
+
171
+ - id: boundary-launchd-vs-cron-keychain
172
+ name: "[Boundary] launchd vs cron 的 Keychain 存取差異"
173
+ difficulty: hard
174
+ context: |
175
+ 用戶的 shell script 需要在排程中執行 `claude -p` 命令。
176
+ 在終端機手動跑正常,但設成 cron 後 claude 報 authentication 錯誤。
177
+ expected_behavior: |
178
+ - 診斷:cron 沒有 Keychain 存取權限,claude CLI 的 OAuth token 存在 Keychain
179
+ - 解法:改用 launchd(~/Library/LaunchAgents/ plist)
180
+ - plist 必須設定 EnvironmentVariables PATH 包含 ~/.local/bin
181
+ - 提到 RunAtLoad / StartCalendarInterval 排程方式
182
+ anti_patterns:
183
+ - "建議在 cron 中設定 ANTHROPIC_API_KEY(繞過問題但不安全)"
184
+ - "不提 Keychain 存取是根本原因"
185
+ - "建議用 crontab -e 加 PATH 就能解決"
186
+
187
+ - id: boundary-tmpfile-trap-cleanup
188
+ name: "[Boundary] tmpfile 原子更新 — trap EXIT 清理"
189
+ difficulty: hard
190
+ context: |
191
+ 你正在寫一個更新 state.json 的 shell script,使用 mktemp 做原子更新。
192
+ Script 中途可能因為 jq 錯誤或 kill 信號而中斷。
193
+ ```bash
194
+ #!/usr/bin/env zsh
195
+ set -euo pipefail
196
+ TMPFILE=$(mktemp)
197
+ jq '.key = "new_value"' state.json > "$TMPFILE" && mv "$TMPFILE" state.json
198
+ ```
199
+ expected_behavior: |
200
+ 在 mktemp 後立即加 trap 確保 tmpfile 被清理:
201
+ TMPFILE=$(mktemp)
202
+ trap "rm -f $TMPFILE" EXIT
203
+ 這樣無論 script 正常結束、發生錯誤或收到 kill 信號,tmpfile 都會被清理。
204
+ 沒有 trap 的話,/tmp/ 中會累積未清理的 tmpfile(尤其 heartbeat 長期運行)。
205
+ anti_patterns:
206
+ - "只用 mktemp 但不加 trap EXIT,依賴 OS 自動清理"
207
+ - "在 script 末尾手動 rm $TMPFILE(中斷時不執行)"
208
+ - "用 trap 但只捕捉 ERR 不捕捉 EXIT"
209
+ - "把 trap 放在 mktemp 之前(TMPFILE 未定義時 trap 觸發會報錯)"
@@ -0,0 +1,191 @@
1
+ skill: tdd-workflow
2
+ version: "1.2"
3
+ last_eval: "2026-03-19"
4
+ pass_rate: 100
5
+ total_scenarios: 11
6
+
7
+ scenarios:
8
+ - id: api-endpoint-test-generation
9
+ name: "Forge 任務 API endpoint AC 生成測試"
10
+ context: |
11
+ Forge 任務 r20 有 AC: "[testable] POST /api/forge/review 回應包含 verdict 欄位"
12
+ 需要為此 AC 生成測試。
13
+ expected_behavior: |
14
+ 使用 Pattern A(API Endpoint 測試)生成 node:test 測試:
15
+ - require helpers.js 的 request 函式
16
+ - before/after 用 backupState/restoreState 隔離
17
+ - assert response status === 200
18
+ - assert data.verdict 存在
19
+ - 跑一次確認 RED(功能尚未實作時)
20
+ anti_patterns:
21
+ - "使用 Jest/Vitest 而非 node:test"
22
+ - "Mock server 而非測真實 server"
23
+ - "不做 state 隔離(沒有 backup/restore)"
24
+
25
+ - id: testable-manual-classification
26
+ name: "AC 混合 testable + manual 正確分類"
27
+ context: |
28
+ Forge 任務有以下 AC:
29
+ 1. POST /api/quest/add 回應 200 且包含 task 物件
30
+ 2. UI 上新任務卡片顯示正確的標題
31
+ 3. state.json 中 tasks 陣列包含新任務
32
+ expected_behavior: |
33
+ AC 1 標記 [testable]:可用 HTTP request 自動驗證
34
+ AC 2 標記 [manual]:UI 顯示需人工或截圖驗證
35
+ AC 3 標記 [testable]:可用 readState() 自動驗證
36
+ 只為 AC 1 和 AC 3 生成測試,AC 2 留在 review 時手動確認
37
+ anti_patterns:
38
+ - "把所有 AC 都標為 testable"
39
+ - "把可程式化驗證的 AC 標為 manual"
40
+ - "為 manual AC 也生成測試"
41
+
42
+ - id: state-isolation
43
+ name: "測試間 state 隔離"
44
+ context: |
45
+ 兩個測試都會修改 state.json:測試 A 完成一個任務(+XP),測試 B 新增一個任務。
46
+ 它們在同一個 test file 中。
47
+ expected_behavior: |
48
+ 使用 backupState/restoreState 在 before/after 中隔離。
49
+ 指定 --concurrency=1 避免平行執行時 state 衝突。
50
+ 測試 B 不依賴測試 A 的副作用(不假設 XP 已增加)。
51
+ anti_patterns:
52
+ - "不做 backup/restore,測試間共享 state 副作用"
53
+ - "平行執行多個 test file 寫同一個 state.json"
54
+ - "測試 B 依賴測試 A 的執行結果"
55
+
56
+ - id: shell-script-behavior
57
+ name: "Shell script 行為驗證"
58
+ context: |
59
+ 修改了 heartbeat.sh 的 log 格式,需要驗證輸出格式正確。
60
+ expected_behavior: |
61
+ 使用 Pattern C:execSync 執行 script,驗證 exit code 0。
62
+ 驗證 stdout 包含預期格式(如時間戳記 [YYYY-MM-DD])。
63
+ 不驗內部實作(不讀 script 內的變數)。
64
+ 設定 timeout 防止 hang。
65
+ anti_patterns:
66
+ - "Mock shell 環境而非真實執行"
67
+ - "驗內部變數而非 stdout/exit code"
68
+ - "不設 timeout 導致測試 hang"
69
+
70
+ - id: red-green-fix-cycle
71
+ name: "測試失敗後修 code 不改 test"
72
+ context: |
73
+ gen-tests 生成了測試,跑出 RED。
74
+ 測試預期 POST /api/forge/stage 回傳 { ok: true, task: {...} },
75
+ 但實際回傳 { ok: true }(缺少 task 欄位)。
76
+ expected_behavior: |
77
+ 修改 server.js 中的 /api/forge/stage handler,在 response 中加入 task 欄位。
78
+ 重新跑測試確認 GREEN。
79
+ 不修改測試的 assert 來「配合」現有行為。
80
+ anti_patterns:
81
+ - "把 assert(data.task) 改成 assert(data.ok) 來通過測試"
82
+ - "刪除失敗的測試"
83
+ - "把測試標記為 skip"
84
+
85
+ - id: nightly-backfill
86
+ name: "夜間 backfill 補測試"
87
+ context: |
88
+ 夜間 agent 需要為 quest-board 補測試。
89
+ 目前 tests/ 有 forge-api.test.js(5 tests),缺 quest-api.test.js。
90
+ expected_behavior: |
91
+ 1. 掃描 server.js 中所有 /api/quest/* endpoint
92
+ 2. 生成 quest-api.test.js,覆蓋 add/complete/undo/delete
93
+ 3. 每個 endpoint 至少測 happy path + 一個 error case(如 missing id)
94
+ 4. 跑 node --test --concurrency=1 tests/*.test.js 確認全綠
95
+ 5. 確認新測試不破壞既有 forge-api.test.js
96
+ anti_patterns:
97
+ - "生成的測試不跑就 commit"
98
+ - "新測試依賴 forge-api.test.js 的 state 副作用"
99
+ - "一次補太多,不驗證就結束"
100
+
101
+ - id: port-conflict-debug
102
+ name: "測試 port 競爭問題診斷"
103
+ context: |
104
+ node --test tests/*.test.js 跑出 13 個失敗,
105
+ 但 node --test tests/forge-advanced-api.test.js 獨立執行全過。
106
+ 所有測試都使用 port 3999。
107
+ expected_behavior: |
108
+ 正確診斷為 port 競爭(多個 test file 同時 bind 3999)。
109
+ 建議解法:--test-concurrency=false 或每個 test file 用不同 port。
110
+ 優先建議 --test-concurrency=false(最簡單,不需改 helpers.js)。
111
+ 不建議 mock server 或 skip 失敗測試。
112
+ anti_patterns:
113
+ - "嘗試 mock HTTP 層來迴避問題"
114
+ - "把 13 個失敗測試刪除或 skip"
115
+ - "沒有診斷就直接重寫 helpers.js"
116
+ - "認為是測試邏輯問題而非 port 衝突"
117
+
118
+ - id: test-for-external-api
119
+ name: "有外部 API 依賴的 endpoint 測試"
120
+ context: |
121
+ 需要為 GET /api/weather 寫測試。
122
+ 這個 endpoint 會呼叫 api.open-meteo.com(外部服務)。
123
+ 測試需要在 CI/CD 和離線環境都能穩定執行。
124
+ expected_behavior: |
125
+ 策略:
126
+ 1. 測試 endpoint 存在並回應(允許 ok:true 或 ok:false/timeout)
127
+ 2. 若 ok:true,驗證回應結構(desc, tempC, weatherCode, isBad 欄位)
128
+ 3. 不 hardcode 預期的氣溫或天氣狀態(外部資料會變)
129
+ 4. 接受 200(成功)或 504(timeout)兩種 status code
130
+ anti_patterns:
131
+ - "assert status === 200(忽略 timeout 可能)"
132
+ - "assert tempC > 20(依賴特定氣溫)"
133
+ - "完全跳過外部 API endpoint 的測試"
134
+ - "用 nock/mock 替換 http 請求(增加複雜度不必要)"
135
+
136
+ - id: habit-questid-body-field
137
+ name: "Habit endpoint 用 questId 非 id(邊界:容易弄錯的 API 差異)"
138
+ context: |
139
+ 需要為 POST /api/habit/complete 寫測試。
140
+ helpers.js 的 request() 函式傳 JSON body。
141
+ 該 endpoint 的 body 欄位是 questId(非 id 或 taskId)。
142
+ expected_behavior: |
143
+ 測試 body 使用 { questId: TEST_HABIT_ID } 而非 { id: ... }。
144
+ 先從 state.json 的 today.habits 讀取一個有效的 habit id 作為 TEST_HABIT_ID。
145
+ 在 after hook 中用 habit/undo 撤銷(保持 state 乾淨),或用 backupState/restoreState。
146
+ 注意:habit 是 ephemeral(每日重置),不能用 quest 的 add → complete 模式。
147
+ anti_patterns:
148
+ - "body 用 { id: TEST_HABIT_ID }(習慣性用 id,但 habit endpoint 用 questId)"
149
+ - "body 用 { taskId: ... }(forge/quest 完成 API 的欄位名)"
150
+ - "假設可以 POST /api/habit/add 來建立 habit(習慣是 ephemeral,由 refresh.sh 建立)"
151
+ - "不做 undo,habit 狀態污染後續測試"
152
+
153
+ - id: forge-complete-vs-quest-complete
154
+ name: "Forge 完成 vs Quest 完成 API 路徑選擇(邊界:任務類型判斷)"
155
+ context: |
156
+ 需要測試「完成一個 Forge 任務」。
157
+ state.json 中有 tasks[],其中有些有 forge_cost,有些沒有。
158
+ expected_behavior: |
159
+ Forge 任務(有 forge_cost)→ 用 POST /api/forge/complete,body: { id }。
160
+ Quest 任務(無 forge_cost)→ 用 POST /api/quest/complete,body: { id }。
161
+ 測試中先 POST /api/forge/add 建立 Forge 任務(帶 forge_cost),再 complete。
162
+ 驗證回傳 { ok: true, player: {...} } 且 player.gold 減少了 forge_cost。
163
+ anti_patterns:
164
+ - "Forge 任務用 /api/quest/complete(404 或靜默失敗)"
165
+ - "Quest 任務用 /api/forge/complete(忽略 forge_cost 欄位差異)"
166
+ - "不驗證 gold 消耗(漏掉 Forge 機制的核心邏輯)"
167
+ - "用 /api/task/complete(舊 API,已移除)"
168
+
169
+ - id: modify-existing-endpoint-update-existing-tests
170
+ name: "修改既有 endpoint 回應格式:應更新現有測試而非新建(邊界:augment vs new file)"
171
+ context: |
172
+ Forge 任務 r55:修改 POST /api/quest/delete 回應格式。
173
+ 原本:{ ok: true }
174
+ 新的:{ ok: true, deleted_task: { id, title, forge_cost } }
175
+ quest-api.test.js 中已有一個測試:
176
+ it('POST /api/quest/delete returns 200', ...) → assert status 200 + data.ok
177
+ 需要把「deleted_task 欄位存在且有正確結構」這個 AC 轉成測試。
178
+ expected_behavior: |
179
+ 正確做法:修改 quest-api.test.js 中現有的 delete 測試,新增 assert:
180
+ assert.ok(data.deleted_task, 'should return deleted task')
181
+ assert.ok(data.deleted_task.id, 'deleted_task should have id')
182
+ assert.ok(data.deleted_task.title !== undefined, 'deleted_task should have title')
183
+ 不應建立新的 test file 只為測這一個 AC 的新欄位。
184
+ 不應修改既有 assert 讓它更寬鬆,反而應加新的 assert。
185
+ 也可考慮新增一個獨立的 it() 區塊在同一檔案中,只測 deleted_task 的結構。
186
+ anti_patterns:
187
+ - "建立 quest-delete-v2-api.test.js 新檔,重複已有的 status/ok 驗證"
188
+ - "修改現有 assert 成 typeof data === 'object' 讓它過關(寬化現有測試而非加新斷言)"
189
+ - "完全略過 deleted_task 結構驗證,只確認 status 200 和 ok: true"
190
+ - "把整個 quest-api.test.js 重寫,而非只在既有 delete 測試後加新 assert"
191
+
@@ -0,0 +1,148 @@
1
+ skill: workflows
2
+ version: "1.2"
3
+ last_eval: "2026-03-22"
4
+ pass_rate: null
5
+ scenarios_passed: null
6
+ total_scenarios: 10
7
+
8
+ scenarios:
9
+ - id: url-research-trigger
10
+ name: "URL 研究觸發"
11
+ context: |
12
+ 用戶貼了一個技術文章 URL
13
+ expected_behavior: |
14
+ 依循 Workflow 1:WebFetch 抓取 → 摘要(主題+關鍵要點)→ 評估與系統關聯性 → 必要時更新 memory
15
+ anti_patterns:
16
+ - "只貼連結內容,沒有摘要"
17
+ - "沒有評估與系統的關聯性"
18
+ - "無謂建立 Forge 任務"
19
+ result: PASS
20
+
21
+ - id: project-init-request
22
+ name: "開項目請求"
23
+ context: |
24
+ 用戶說:「幫我開個項目追蹤 Rust 學習」
25
+ expected_behavior: |
26
+ 合併 Workflow 3+4:建 projects/{slug}/README.md → 建 Forge 任務 + 里程碑 → 建議第一步(具體可執行)
27
+ anti_patterns:
28
+ - "只回覆「好的」沒有實際建立"
29
+ - "有目錄但沒有里程碑"
30
+ - "沒有具體下一步"
31
+ result: PASS
32
+
33
+ - id: tech-evaluation
34
+ name: "技術評估"
35
+ context: |
36
+ 用戶問:「Bun 值得用來替換 Node 嗎?」
37
+ expected_behavior: |
38
+ 依循 Workflow 5:研究 Bun → 與現有系統比較(功能、成本、複雜度)→ 明確結論(採用/不採用/觀望)→ 行動建議 → 記入 research-notes
39
+ anti_patterns:
40
+ - "給出模糊回覆,沒有明確結論"
41
+ - "有結論但缺少比較依據"
42
+ - "沒有記入 memory"
43
+ result: PASS
44
+
45
+ - id: no-workflow-needed
46
+ name: "不該套用 workflow 的場景"
47
+ context: |
48
+ 用戶問:「今天晚餐吃什麼好?」
49
+ expected_behavior: |
50
+ 直接輕鬆回答,不套用任何 workflow 結構,自然回覆
51
+ anti_patterns:
52
+ - "出現「步驟 1、步驟 2」等結構化回覆"
53
+ - "硬套 workflow 模板回答日常問題"
54
+ result: PASS
55
+
56
+ - id: debug-workflow
57
+ name: "Debug 流程"
58
+ context: |
59
+ 用戶說:「heartbeat 好像沒有跑,幫我看看」
60
+ expected_behavior: |
61
+ 依循 Workflow 6:先查 log(不急著猜)→ 定位根因 → 修復 → 驗證修復有效 → 如果系統性問題加防護
62
+ anti_patterns:
63
+ - "不查 log,直接猜測原因"
64
+ - "修完沒有驗證"
65
+ - "沒有說明根因"
66
+ result: PASS
67
+
68
+ - id: feature-dev-workflow
69
+ name: "功能開發流程"
70
+ context: |
71
+ 用戶說:「在 Quest Board 加一個 /api/stats endpoint」
72
+ expected_behavior: |
73
+ 依循 Workflow 2:讀現有架構 → 實作 → 語法預檢(node -c)→ 服務重啟 → 端點驗證(curl)→ 回報結果
74
+ anti_patterns:
75
+ - "跳過語法預檢直接執行"
76
+ - "沒有重啟服務就測試"
77
+ - "實作完沒有驗證端點"
78
+ result: PASS
79
+
80
+ - id: ambiguous-workflow-trigger
81
+ name: "模糊觸發條件:URL + 功能需求混合"
82
+ context: |
83
+ 用戶貼了一個 GitHub repo URL 並說:「我覺得這個 token compressor 可以整合進我們系統,幫我看看」
84
+ expected_behavior: |
85
+ 正確判斷:同時觸發 Workflow 1(URL 研究)+ Workflow 5(技術評估),不是 Workflow 2(功能開發)。
86
+ 執行順序:先用 WebFetch/gh 研究該 repo → 評估技術可行性和整合成本 → 明確結論(整合/不整合/觀望)→ 若整合建立 Forge 任務,若不整合記錄原因到 research-notes。
87
+ 不應立即開始寫程式碼整合,因為還沒評估。
88
+ anti_patterns:
89
+ - "直接開始寫整合程式碼而不先研究"
90
+ - "只研究不給整合/不整合的結論"
91
+ - "只套用一個 workflow 而忽略另一個維度"
92
+ - "沒有記錄評估結論(memory / research-notes)"
93
+
94
+ # Boundary scenarios(有辨別力)
95
+ - id: boundary-testable-to-experiments-not-forge
96
+ name: "Boundary: testable 發現應進 experiments queue,非 Forge"
97
+ context: |
98
+ 研究時發現 Context-Gateway proxy(Go 工具,75% context 時背景壓縮)
99
+ 有助於降低 compact 頻率。評估後認為這是 [testable] 發現,需要驗證效果。
100
+ 你準備為這個發現建立一個 Forge 任務。
101
+ expected_behavior: |
102
+ [testable] 發現不建 Forge 任務,而是寫入 experiments/queue.jsonl:
103
+ {"id":"exp-YYYY-MM-DD-NNN","source":{"type":"research","ref":"主題名稱"},
104
+ "hypothesis":"假設","priority":"normal"}
105
+ 同時建立對應的 YAML 檔案 homunculus/experiments/<id>.yaml。
106
+ Forge 任務是用來追蹤開發工作,不是實驗假設。
107
+ anti_patterns:
108
+ - "建立 Forge 任務追蹤這個實驗"
109
+ - "直接採用(不先實驗就用 adoptable 處理)"
110
+ - "既不建 Forge 也不加 experiments queue,只記錄在 research-notes"
111
+
112
+ - id: boundary-debug-systematic-protection
113
+ name: "Boundary: debug 後是否加防護"
114
+ context: |
115
+ 調試發現 heartbeat.sh 中 jq 讀取 state.json 時,若該檔案為空(初次部署
116
+ 或意外清空),會造成 jq: error null iterator 且 heartbeat 靜默失敗。
117
+ 已修復當下的空檔問題。是否需要加防護?
118
+ expected_behavior: |
119
+ 是系統性問題(state.json 可能在多種情況下出現空/損毀),需要加防護:
120
+ 在讀取前先用 jq empty state.json 驗證,或提供預設值 jq '.x // []' 。
121
+ Workflow 6 步驟 5:「如果系統性問題加防護」— 空 state.json 是可重現的
122
+ 邊界情況,不是一次性 bug。
123
+ anti_patterns:
124
+ - "修完眼前問題就結束,不加防護"
125
+ - "不評估是否系統性,直接全加防護"
126
+ - "加防護但不測試空 state.json 情境"
127
+
128
+ # v1.2 新增:Use when 路由辨別力 scenario
129
+ - id: boundary-skill-routing-debug-vs-api-diagnosis
130
+ name: "Boundary: 系統性 debug 應路由到 workflows 而非 api-system-diagnosis"
131
+ context: |
132
+ 你有多個 skill 可選:workflows、api-system-diagnosis、tdd-workflow。
133
+ 用戶說:「heartbeat 今天跑了但沒推 Discord,幫我查一下」
134
+ 這個問題可能是 heartbeat 腳本問題、Discord webhook 問題、或 bridge 服務問題。
135
+ 你準備直接載入 api-system-diagnosis skill 來處理,因為涉及 API 呼叫。
136
+ expected_behavior: |
137
+ 正確路由是 workflows skill(Use when 明確包含「系統性 debug vs 孤立 bug」)。
138
+ 選擇 Workflow 6(Debug):先查 heartbeat log → 定位根因(是 heartbeat.sh?bridge?webhook?)
139
+ → 修復 → 驗證。
140
+ api-system-diagnosis 是針對 Quest Board / server.js 的 API 層 bug,
141
+ 不是 heartbeat 端到端排查的首選。正確判斷:
142
+ - 「heartbeat 今天有跑但沒推」= 行為異常但服務存活 → 查 log → Workflow 6
143
+ - 若發現是 Discord webhook API 回傳 4xx → 那時才需要 api-system-diagnosis
144
+ anti_patterns:
145
+ - "直接載入 api-system-diagnosis 處理 heartbeat 整體異常"
146
+ - "不查 log 就猜是 webhook 問題"
147
+ - "沒有依循 debug workflow(先查 log → 定位 → 修 → 驗證)"
148
+ - "將整個問題委派給 shell-debugger subagent 而不先自行查 log"