@uzysjung/agent-harness 26.83.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 (212) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +279 -0
  3. package/README.md +306 -0
  4. package/dist/chunk-SDVAM5JZ.js +775 -0
  5. package/dist/chunk-SDVAM5JZ.js.map +1 -0
  6. package/dist/index.js +5412 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/trust-tier-drift.js +67 -0
  9. package/dist/trust-tier-drift.js.map +1 -0
  10. package/package.json +53 -0
  11. package/scripts/prune-ecc.sh +310 -0
  12. package/templates/CLAUDE.md +86 -0
  13. package/templates/agents/build-error-resolver.md +114 -0
  14. package/templates/agents/code-reviewer.md +237 -0
  15. package/templates/agents/data-analyst.md +69 -0
  16. package/templates/agents/plan-checker.md +118 -0
  17. package/templates/agents/reviewer.md +128 -0
  18. package/templates/agents/security-reviewer.md +108 -0
  19. package/templates/agents/silent-failure-hunter.md +50 -0
  20. package/templates/agents/strategist.md +86 -0
  21. package/templates/antigravity/AGENTS.md.template +58 -0
  22. package/templates/codex/AGENTS.md.template +94 -0
  23. package/templates/codex/README.md +69 -0
  24. package/templates/codex/config.toml.template +108 -0
  25. package/templates/codex/hooks/README.md +40 -0
  26. package/templates/codex/hooks/gate-check.sh +7 -0
  27. package/templates/codex/hooks/hito-counter.sh +7 -0
  28. package/templates/codex/hooks/session-start.sh +7 -0
  29. package/templates/codex/hooks/uncommitted-check.sh +7 -0
  30. package/templates/codex/skills/uzys-build/SKILL.md +24 -0
  31. package/templates/codex/skills/uzys-plan/SKILL.md +24 -0
  32. package/templates/codex/skills/uzys-review/SKILL.md +24 -0
  33. package/templates/codex/skills/uzys-ship/SKILL.md +24 -0
  34. package/templates/codex/skills/uzys-spec/SKILL.md +28 -0
  35. package/templates/codex/skills/uzys-test/SKILL.md +24 -0
  36. package/templates/commands/ecc/checkpoint.md +32 -0
  37. package/templates/commands/ecc/e2e.md +105 -0
  38. package/templates/commands/ecc/eval.md +88 -0
  39. package/templates/commands/ecc/evolve.md +7 -0
  40. package/templates/commands/ecc/harness-audit.md +73 -0
  41. package/templates/commands/ecc/instinct-status.md +8 -0
  42. package/templates/commands/ecc/promote.md +10 -0
  43. package/templates/commands/ecc/security-scan.md +10 -0
  44. package/templates/commands/uzys/auto.md +190 -0
  45. package/templates/commands/uzys/build.md +42 -0
  46. package/templates/commands/uzys/plan.md +55 -0
  47. package/templates/commands/uzys/review.md +44 -0
  48. package/templates/commands/uzys/ship.md +49 -0
  49. package/templates/commands/uzys/spec.md +93 -0
  50. package/templates/commands/uzys/test.md +58 -0
  51. package/templates/docs/PLAN.template.md +102 -0
  52. package/templates/hooks/agentshield-gate.sh +101 -0
  53. package/templates/hooks/checkpoint-snapshot.sh +115 -0
  54. package/templates/hooks/gate-check.sh +138 -0
  55. package/templates/hooks/hito-counter.sh +26 -0
  56. package/templates/hooks/karpathy-gate.sh +59 -0
  57. package/templates/hooks/mcp-pre-exec.sh +104 -0
  58. package/templates/hooks/protect-files.sh +41 -0
  59. package/templates/hooks/session-start.sh +40 -0
  60. package/templates/hooks/spec-drift-check.sh +86 -0
  61. package/templates/mcp-allowlist.example +24 -0
  62. package/templates/mcp.json +20 -0
  63. package/templates/opencode/.opencode/commands/uzys-build.md +22 -0
  64. package/templates/opencode/.opencode/commands/uzys-plan.md +22 -0
  65. package/templates/opencode/.opencode/commands/uzys-review.md +22 -0
  66. package/templates/opencode/.opencode/commands/uzys-ship.md +22 -0
  67. package/templates/opencode/.opencode/commands/uzys-spec.md +28 -0
  68. package/templates/opencode/.opencode/commands/uzys-test.md +22 -0
  69. package/templates/opencode/.opencode/plugins/uzys-harness.ts +146 -0
  70. package/templates/opencode/AGENTS.md.template +98 -0
  71. package/templates/opencode/README.md +34 -0
  72. package/templates/opencode/opencode.json.template +42 -0
  73. package/templates/project-claude/_base.md +23 -0
  74. package/templates/project-claude/fragments/csr-fastapi/active-rules.md +13 -0
  75. package/templates/project-claude/fragments/csr-fastapi/agents.md +5 -0
  76. package/templates/project-claude/fragments/csr-fastapi/boundaries.md +18 -0
  77. package/templates/project-claude/fragments/csr-fastapi/commands.md +6 -0
  78. package/templates/project-claude/fragments/csr-fastapi/plugins.md +2 -0
  79. package/templates/project-claude/fragments/csr-fastapi/skills.md +5 -0
  80. package/templates/project-claude/fragments/csr-fastapi/stack.md +6 -0
  81. package/templates/project-claude/fragments/csr-fastapi/tagline.md +1 -0
  82. package/templates/project-claude/fragments/csr-fastapi/workflow.md +8 -0
  83. package/templates/project-claude/fragments/csr-fastify/active-rules.md +13 -0
  84. package/templates/project-claude/fragments/csr-fastify/agents.md +5 -0
  85. package/templates/project-claude/fragments/csr-fastify/boundaries.md +18 -0
  86. package/templates/project-claude/fragments/csr-fastify/commands.md +6 -0
  87. package/templates/project-claude/fragments/csr-fastify/plugins.md +2 -0
  88. package/templates/project-claude/fragments/csr-fastify/skills.md +5 -0
  89. package/templates/project-claude/fragments/csr-fastify/stack.md +6 -0
  90. package/templates/project-claude/fragments/csr-fastify/tagline.md +1 -0
  91. package/templates/project-claude/fragments/csr-fastify/workflow.md +8 -0
  92. package/templates/project-claude/fragments/csr-supabase/active-rules.md +12 -0
  93. package/templates/project-claude/fragments/csr-supabase/agents.md +5 -0
  94. package/templates/project-claude/fragments/csr-supabase/boundaries.md +19 -0
  95. package/templates/project-claude/fragments/csr-supabase/commands.md +6 -0
  96. package/templates/project-claude/fragments/csr-supabase/plugins.md +4 -0
  97. package/templates/project-claude/fragments/csr-supabase/skills.md +7 -0
  98. package/templates/project-claude/fragments/csr-supabase/stack.md +6 -0
  99. package/templates/project-claude/fragments/csr-supabase/supabase-auth.md +21 -0
  100. package/templates/project-claude/fragments/csr-supabase/tagline.md +1 -0
  101. package/templates/project-claude/fragments/csr-supabase/workflow.md +8 -0
  102. package/templates/project-claude/fragments/data/active-rules.md +10 -0
  103. package/templates/project-claude/fragments/data/agents.md +6 -0
  104. package/templates/project-claude/fragments/data/boundaries.md +20 -0
  105. package/templates/project-claude/fragments/data/commands.md +6 -0
  106. package/templates/project-claude/fragments/data/plugins.md +2 -0
  107. package/templates/project-claude/fragments/data/skills.md +3 -0
  108. package/templates/project-claude/fragments/data/stack.md +7 -0
  109. package/templates/project-claude/fragments/data/tagline.md +1 -0
  110. package/templates/project-claude/fragments/data/workflow.md +9 -0
  111. package/templates/project-claude/fragments/executive/active-rules.md +6 -0
  112. package/templates/project-claude/fragments/executive/agents.md +6 -0
  113. package/templates/project-claude/fragments/executive/boundaries.md +17 -0
  114. package/templates/project-claude/fragments/executive/commands.md +11 -0
  115. package/templates/project-claude/fragments/executive/plugins.md +1 -0
  116. package/templates/project-claude/fragments/executive/skills.md +7 -0
  117. package/templates/project-claude/fragments/executive/stack.md +4 -0
  118. package/templates/project-claude/fragments/executive/tagline.md +1 -0
  119. package/templates/project-claude/fragments/executive/workflow.md +10 -0
  120. package/templates/project-claude/fragments/growth-marketing/active-rules.md +7 -0
  121. package/templates/project-claude/fragments/growth-marketing/agents.md +6 -0
  122. package/templates/project-claude/fragments/growth-marketing/boundaries.md +17 -0
  123. package/templates/project-claude/fragments/growth-marketing/commands.md +11 -0
  124. package/templates/project-claude/fragments/growth-marketing/plugins.md +9 -0
  125. package/templates/project-claude/fragments/growth-marketing/skills.md +8 -0
  126. package/templates/project-claude/fragments/growth-marketing/stack.md +7 -0
  127. package/templates/project-claude/fragments/growth-marketing/tagline.md +1 -0
  128. package/templates/project-claude/fragments/growth-marketing/workflow.md +11 -0
  129. package/templates/project-claude/fragments/project-management/active-rules.md +7 -0
  130. package/templates/project-claude/fragments/project-management/agents.md +6 -0
  131. package/templates/project-claude/fragments/project-management/boundaries.md +16 -0
  132. package/templates/project-claude/fragments/project-management/commands.md +10 -0
  133. package/templates/project-claude/fragments/project-management/plugins.md +6 -0
  134. package/templates/project-claude/fragments/project-management/skills.md +5 -0
  135. package/templates/project-claude/fragments/project-management/stack.md +4 -0
  136. package/templates/project-claude/fragments/project-management/tagline.md +1 -0
  137. package/templates/project-claude/fragments/project-management/workflow.md +12 -0
  138. package/templates/project-claude/fragments/ssr-htmx/active-rules.md +11 -0
  139. package/templates/project-claude/fragments/ssr-htmx/agents.md +5 -0
  140. package/templates/project-claude/fragments/ssr-htmx/boundaries.md +20 -0
  141. package/templates/project-claude/fragments/ssr-htmx/commands.md +6 -0
  142. package/templates/project-claude/fragments/ssr-htmx/plugins.md +2 -0
  143. package/templates/project-claude/fragments/ssr-htmx/skills.md +3 -0
  144. package/templates/project-claude/fragments/ssr-htmx/stack.md +6 -0
  145. package/templates/project-claude/fragments/ssr-htmx/tagline.md +1 -0
  146. package/templates/project-claude/fragments/ssr-htmx/workflow.md +8 -0
  147. package/templates/project-claude/fragments/ssr-nextjs/active-rules.md +12 -0
  148. package/templates/project-claude/fragments/ssr-nextjs/agents.md +5 -0
  149. package/templates/project-claude/fragments/ssr-nextjs/boundaries.md +20 -0
  150. package/templates/project-claude/fragments/ssr-nextjs/commands.md +6 -0
  151. package/templates/project-claude/fragments/ssr-nextjs/plugins.md +2 -0
  152. package/templates/project-claude/fragments/ssr-nextjs/skills.md +5 -0
  153. package/templates/project-claude/fragments/ssr-nextjs/stack.md +5 -0
  154. package/templates/project-claude/fragments/ssr-nextjs/tagline.md +1 -0
  155. package/templates/project-claude/fragments/ssr-nextjs/workflow.md +8 -0
  156. package/templates/project-claude/fragments/tooling/active-rules.md +11 -0
  157. package/templates/project-claude/fragments/tooling/agents.md +5 -0
  158. package/templates/project-claude/fragments/tooling/boundaries.md +17 -0
  159. package/templates/project-claude/fragments/tooling/commands.md +4 -0
  160. package/templates/project-claude/fragments/tooling/skills.md +4 -0
  161. package/templates/project-claude/fragments/tooling/stack.md +5 -0
  162. package/templates/project-claude/fragments/tooling/tagline.md +1 -0
  163. package/templates/project-claude/fragments/tooling/workflow.md +5 -0
  164. package/templates/rules/api-contract.md +33 -0
  165. package/templates/rules/change-management.md +80 -0
  166. package/templates/rules/cli-development.md +39 -0
  167. package/templates/rules/code-style.md +23 -0
  168. package/templates/rules/data-analysis.md +61 -0
  169. package/templates/rules/database.md +29 -0
  170. package/templates/rules/design-workflow.md +17 -0
  171. package/templates/rules/error-handling.md +23 -0
  172. package/templates/rules/gates-taxonomy.md +21 -0
  173. package/templates/rules/git-policy.md +102 -0
  174. package/templates/rules/htmx.md +42 -0
  175. package/templates/rules/nextjs.md +35 -0
  176. package/templates/rules/playwright-launch.md +66 -0
  177. package/templates/rules/pyside6.md +59 -0
  178. package/templates/rules/shadcn.md +33 -0
  179. package/templates/rules/ship-checklist.md +24 -0
  180. package/templates/rules/tauri.md +40 -0
  181. package/templates/rules/test-policy.md +62 -0
  182. package/templates/settings.json +71 -0
  183. package/templates/skills/agent-introspection-debugging/SKILL.md +153 -0
  184. package/templates/skills/continuous-learning-v2/SKILL.md +365 -0
  185. package/templates/skills/continuous-learning-v2/config.json +8 -0
  186. package/templates/skills/continuous-learning-v2/hooks/observe.sh +428 -0
  187. package/templates/skills/continuous-learning-v2/scripts/detect-project.sh +228 -0
  188. package/templates/skills/continuous-learning-v2/scripts/instinct-cli.py +1426 -0
  189. package/templates/skills/deep-research/SKILL.md +155 -0
  190. package/templates/skills/deep-research/agents/openai.yaml +7 -0
  191. package/templates/skills/e2e-testing/SKILL.md +326 -0
  192. package/templates/skills/e2e-testing/agents/openai.yaml +7 -0
  193. package/templates/skills/eval-harness/SKILL.md +279 -0
  194. package/templates/skills/eval-harness/agents/openai.yaml +7 -0
  195. package/templates/skills/gh-issue-workflow/ISSUE.template.md +58 -0
  196. package/templates/skills/gh-issue-workflow/SKILL.md +184 -0
  197. package/templates/skills/investor-materials/SKILL.md +96 -0
  198. package/templates/skills/investor-outreach/SKILL.md +91 -0
  199. package/templates/skills/market-research/SKILL.md +75 -0
  200. package/templates/skills/market-research/agents/openai.yaml +7 -0
  201. package/templates/skills/nextjs-turbopack/SKILL.md +44 -0
  202. package/templates/skills/north-star/NORTH_STAR.template.md +114 -0
  203. package/templates/skills/north-star/SKILL.md +103 -0
  204. package/templates/skills/python-patterns/SKILL.md +750 -0
  205. package/templates/skills/python-testing/SKILL.md +816 -0
  206. package/templates/skills/spec-scaling/SKILL.md +89 -0
  207. package/templates/skills/strategic-compact/SKILL.md +131 -0
  208. package/templates/skills/strategic-compact/suggest-compact.sh +54 -0
  209. package/templates/skills/ui-visual-review/SKILL.md +154 -0
  210. package/templates/skills/verification-loop/SKILL.md +126 -0
  211. package/templates/skills/verification-loop/agents/openai.yaml +7 -0
  212. package/templates/track-mcp-map.tsv +15 -0
@@ -0,0 +1,138 @@
1
+ #!/bin/bash
2
+ # PreToolUse Hook: 워크플로우 게이트 강제
3
+ # Skill 도구 호출 시 이전 게이트 완료 여부 확인
4
+ # 미완료 시 exit code 2로 차단
5
+ set -e
6
+
7
+ GATE_FILE=".claude/gate-status.json"
8
+ INPUT_JSON=$(cat)
9
+
10
+ # tool_input에서 skill 이름 추출 (jq 우선, bash 폴백)
11
+ if command -v jq &> /dev/null; then
12
+ SKILL_NAME=$(echo "$INPUT_JSON" | jq -r '.tool_input.skill // .tool_input.args // ""' 2>/dev/null || echo "")
13
+ else
14
+ # jq 없을 때 bash 폴백
15
+ SKILL_NAME=$(echo "$INPUT_JSON" | grep -o '"skill"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
16
+ if [ -z "$SKILL_NAME" ]; then
17
+ SKILL_NAME=$(echo "$INPUT_JSON" | grep -o '"args"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
18
+ fi
19
+ fi
20
+
21
+ # uzys: 커맨드가 아니면 통과
22
+ # uzys:auto는 게이트 체크 제외 (auto 커맨드가 내부에서 gate-status 직접 관리)
23
+ case "$SKILL_NAME" in
24
+ uzys:spec|uzys:plan|uzys:build|uzys:test|uzys:review|uzys:ship) ;;
25
+ uzys:auto) exit 0 ;;
26
+ *) exit 0 ;;
27
+ esac
28
+
29
+ # gate-status.json 없으면 초기 상태 생성 (모두 미완료)
30
+ if [ ! -f "$GATE_FILE" ]; then
31
+ mkdir -p "$(dirname "$GATE_FILE")"
32
+ cat > "$GATE_FILE" << 'INIT'
33
+ {
34
+ "define": { "completed": false },
35
+ "plan": { "completed": false },
36
+ "build": { "completed": false },
37
+ "verify": { "completed": false },
38
+ "review": { "completed": false },
39
+ "ship": { "completed": false },
40
+ "hotfix": false
41
+ }
42
+ INIT
43
+ fi
44
+
45
+ # v26.11.2 — 게이트 상태 읽기. jq 실패/손상된 JSON 시 안전한 default "false"로 fail-secure.
46
+ # (이전: jq 실패 시 빈 출력 가능 → 호출자에서 일관성 없는 처리. C2 수정)
47
+ is_completed() {
48
+ local result=""
49
+ if command -v jq &> /dev/null; then
50
+ result=$(jq -r ".$1.completed // false" "$GATE_FILE" 2>/dev/null) || result="false"
51
+ else
52
+ grep -A1 "\"$1\"" "$GATE_FILE" 2>/dev/null | grep -o '"completed"[[:space:]]*:[[:space:]]*true' | head -1 | grep -q 'true' && result="true" || result="false"
53
+ fi
54
+ case "$result" in
55
+ true|false) echo "$result" ;;
56
+ *) echo "false" ;;
57
+ esac
58
+ }
59
+
60
+ is_hotfix() {
61
+ local result=""
62
+ if command -v jq &> /dev/null; then
63
+ result=$(jq -r ".hotfix // false" "$GATE_FILE" 2>/dev/null) || result="false"
64
+ else
65
+ grep -o '"hotfix"[[:space:]]*:[[:space:]]*true' "$GATE_FILE" 2>/dev/null | head -1 | grep -q 'true' && result="true" || result="false"
66
+ fi
67
+ case "$result" in
68
+ true|false) echo "$result" ;;
69
+ *) echo "false" ;;
70
+ esac
71
+ }
72
+
73
+ HOTFIX=$(is_hotfix)
74
+
75
+ # 게이트 순서 검증
76
+ case "$SKILL_NAME" in
77
+ uzys:spec)
78
+ # Define은 항상 허용 (첫 단계). 새 사이클 시작이므로 모든 게이트 리셋
79
+ cat > "$GATE_FILE" << 'RESET'
80
+ {
81
+ "define": { "completed": false },
82
+ "plan": { "completed": false },
83
+ "build": { "completed": false },
84
+ "verify": { "completed": false },
85
+ "review": { "completed": false },
86
+ "ship": { "completed": false },
87
+ "hotfix": false
88
+ }
89
+ RESET
90
+ exit 0
91
+ ;;
92
+ uzys:plan)
93
+ if [ "$(is_completed define)" != "true" ]; then
94
+ echo "BLOCKED: Define 단계가 완료되지 않았습니다. /uzys:spec을 먼저 실행하세요. (docs/SPEC.md 필요)" >&2
95
+ exit 2
96
+ fi
97
+ ;;
98
+ uzys:build)
99
+ if [ "$HOTFIX" = "true" ]; then
100
+ exit 0 # hotfix 모드: plan 건너뛰기 허용
101
+ fi
102
+ if [ "$(is_completed plan)" != "true" ]; then
103
+ echo "BLOCKED: Plan 단계가 완료되지 않았습니다. /uzys:plan을 먼저 실행하세요. (docs/todo.md 필요)" >&2
104
+ exit 2
105
+ fi
106
+ ;;
107
+ uzys:test)
108
+ if [ "$(is_completed build)" != "true" ]; then
109
+ echo "BLOCKED: Build 단계가 완료되지 않았습니다. /uzys:build를 먼저 실행하세요." >&2
110
+ exit 2
111
+ fi
112
+ ;;
113
+ uzys:review)
114
+ if [ "$HOTFIX" = "true" ]; then
115
+ exit 0 # hotfix 모드: review 건너뛰기 허용
116
+ fi
117
+ if [ "$(is_completed verify)" != "true" ]; then
118
+ echo "BLOCKED: Verify 단계가 완료되지 않았습니다. /uzys:test를 먼저 실행하세요." >&2
119
+ exit 2
120
+ fi
121
+ ;;
122
+ uzys:ship)
123
+ if [ "$HOTFIX" = "true" ]; then
124
+ # hotfix: verify만 필수
125
+ if [ "$(is_completed verify)" != "true" ]; then
126
+ echo "BLOCKED: Hotfix 모드에서도 Verify는 필수입니다. /uzys:test를 먼저 실행하세요." >&2
127
+ exit 2
128
+ fi
129
+ exit 0
130
+ fi
131
+ if [ "$(is_completed review)" != "true" ]; then
132
+ echo "BLOCKED: Review 단계가 완료되지 않았습니다. /uzys:review를 먼저 실행하세요." >&2
133
+ exit 2
134
+ fi
135
+ ;;
136
+ esac
137
+
138
+ exit 0
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+ # ============================================================
3
+ # hito-counter.sh (v26.32.0)
4
+ # UserPromptSubmit hook — HITO (Human-In-The-Loop Occurrences) 측정용.
5
+ #
6
+ # NORTH_STAR.md NSM 추적을 위한 Phase 2 baseline 수집 인프라.
7
+ # 사용자 prompt submit 시마다 타임스탬프 1줄 추가.
8
+ # 프롬프트 내용은 기록하지 않음 (프라이버시).
9
+ #
10
+ # 로그 위치: .claude/evals/hito-YYYY-MM-DD.log
11
+ # 집계: `wc -l .claude/evals/hito-*.log` 로 일일 카운트
12
+ # 더 정밀한 분류(명시적 지시 vs 승인 vs 확인)는 수동 eval에서.
13
+ #
14
+ # Exit: 항상 0 (hook 차단 금지)
15
+ # ============================================================
16
+
17
+ DATE=$(date +%Y-%m-%d 2>/dev/null || echo "unknown")
18
+ LOG_DIR="${CLAUDE_PROJECT_DIR:-.}/.claude/evals"
19
+ LOG_FILE="$LOG_DIR/hito-$DATE.log"
20
+
21
+ mkdir -p "$LOG_DIR" 2>/dev/null || exit 0
22
+
23
+ TS=$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo "?")
24
+ echo "$TS prompt_submit" >> "$LOG_FILE" 2>/dev/null
25
+
26
+ exit 0
@@ -0,0 +1,59 @@
1
+ #!/bin/bash
2
+ # karpathy Gate — Claude Code PreToolUse hook (Write|Edit matcher, non-blocking warn).
3
+ #
4
+ # v0.6.0 cherry-pick from alirezarezvani/claude-skills@f567c61
5
+ # src: engineering/karpathy-coder/hooks/karpathy-gate.sh
6
+ # License: MIT (alirezarezvani/claude-skills)
7
+ #
8
+ # Adapt for Claude Code PreToolUse context:
9
+ # - upstream은 git pre-commit (staged files) context 가정
10
+ # - 본 스크립트는 PreToolUse Write|Edit — Claude가 코드 작성 직전 발동
11
+ # - stdin으로 tool_input JSON 받음 (Claude Code hook spec)
12
+ # - file_path 추출 → Python 도구로 complexity 검사 (best-effort)
13
+ # - 비차단 (exit 0 항상) — upstream "warn, doesn't reject" 정신 유지
14
+ #
15
+ # Python 3 + plugin scripts 부재 시 graceful exit (commit/edit 차단 X).
16
+
17
+ # 어떤 실패도 차단 안 함
18
+ set +e
19
+
20
+ # stdin tool_input JSON 읽기 (Claude Code hook spec: PreToolUse 시 자동 주입)
21
+ INPUT=$(cat 2>/dev/null || echo "")
22
+
23
+ # file_path 추출 — jq 우선, grep 폴백 (cli-development.md hook 컨벤션)
24
+ # jq 가용 시: escape 처리 정확. 미설치 시: grep+sed (단순 케이스만)
25
+ if command -v jq >/dev/null 2>&1; then
26
+ FILE_PATH=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || echo "")
27
+ else
28
+ FILE_PATH=$(printf '%s' "$INPUT" | grep -o '"file_path":"[^"]*"' | head -1 | sed 's/"file_path":"//; s/"$//')
29
+ fi
30
+
31
+ # 짧은 reminder — 모든 Write|Edit 시점에 출력 (4 원칙 환기)
32
+ printf '[karpathy] Think Before / Simplicity / Surgical / Goal-Driven\n' >&2
33
+
34
+ # Python 3 + plugin scripts 가용 시만 complexity 검사
35
+ SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-}/scripts"
36
+ if ! command -v python3 >/dev/null 2>&1; then
37
+ # Python 3 부재 — reminder만 출력하고 종료
38
+ exit 0
39
+ fi
40
+ if [ ! -d "$SCRIPT_DIR" ]; then
41
+ # plugin 미설치 또는 ${CLAUDE_PLUGIN_ROOT} 미세팅
42
+ exit 0
43
+ fi
44
+ if [ -z "$FILE_PATH" ]; then
45
+ # tool_input 파싱 실패 또는 file_path 없음
46
+ exit 0
47
+ fi
48
+
49
+ # 코드 파일 한정
50
+ case "$FILE_PATH" in
51
+ *.py|*.ts|*.tsx|*.js|*.jsx)
52
+ # complexity_checker 실행, WARN만 stderr로
53
+ python3 "$SCRIPT_DIR/complexity_checker.py" "$FILE_PATH" --threshold medium 2>/dev/null \
54
+ | grep -E "^[[:space:]]+\[WARN\]" >&2 \
55
+ || true
56
+ ;;
57
+ esac
58
+
59
+ exit 0
@@ -0,0 +1,104 @@
1
+ #!/bin/bash
2
+ # ============================================================
3
+ # mcp-pre-exec.sh — PreToolUse hook (mcp__.* matcher)
4
+ #
5
+ # 목적: MCP tool 호출을 화이트리스트 + 위험 패턴으로 차단.
6
+ # CVE-2025-59536, CVE-2026-21852 (hooks/MCP RCE) 대응.
7
+ #
8
+ # 호출: templates/settings.json의 PreToolUse 매처 "mcp__.*" 에서 실행.
9
+ # 입력: stdin JSON (tool_name, tool_input, cwd, session_id, ...)
10
+ # 출력: stderr 경고 + exit 2 차단 또는 exit 0 통과
11
+ #
12
+ # 화이트리스트: $CLAUDE_PROJECT_DIR/.mcp-allowlist
13
+ # - 한 줄에 하나의 서버 이름 (예: context7, github, chrome-devtools)
14
+ # - '#' 주석, 빈 줄 허용
15
+ # - 파일 없으면 모든 MCP 호출 통과 (opt-in 구조 — 사용자가 의도적으로 활성)
16
+ #
17
+ # 위험 파라미터 패턴: stdin의 tool_input에 다음 패턴 감지 시 차단
18
+ # - rm -rf, curl | sh, wget | bash, eval, base64 decode + exec
19
+ #
20
+ # Exit codes:
21
+ # 0: 통과 (MCP 아님, 화이트리스트 매칭, 또는 allowlist 없음)
22
+ # 2: 차단 (서버 비매칭 또는 위험 패턴 감지)
23
+ # ============================================================
24
+ set -u
25
+
26
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
27
+ ALLOWLIST="$PROJECT_DIR/.mcp-allowlist"
28
+
29
+ # stdin JSON 파싱
30
+ INPUT=$(cat 2>/dev/null || echo "{}")
31
+
32
+ TOOL_NAME=""
33
+ if command -v jq &>/dev/null; then
34
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null || echo "")
35
+ else
36
+ # jq 없을 때 bash 폴백
37
+ TOOL_NAME=$(echo "$INPUT" | grep -oE '"tool_name"[[:space:]]*:[[:space:]]*"[^"]*"' | sed -E 's/.*"([^"]*)"$/\1/')
38
+ fi
39
+
40
+ # MCP tool 이 아니면 즉시 통과
41
+ case "$TOOL_NAME" in
42
+ mcp__*__*) ;;
43
+ *) exit 0 ;;
44
+ esac
45
+
46
+ # 서버 이름 추출: mcp__<server>__<tool> → <server>
47
+ SERVER_NAME=$(echo "$TOOL_NAME" | awk -F'__' '{print $2}')
48
+
49
+ if [ -z "$SERVER_NAME" ]; then
50
+ echo "[mcp-pre-exec] WARN: cannot extract server name from '$TOOL_NAME'" >&2
51
+ exit 0
52
+ fi
53
+
54
+ # 화이트리스트 대조 (파일 없으면 opt-in 미활성 — 통과)
55
+ if [ ! -f "$ALLOWLIST" ]; then
56
+ exit 0
57
+ fi
58
+
59
+ # 화이트리스트에 서버 있는지 확인 (주석/빈 줄 제외)
60
+ MATCHED=false
61
+ while IFS= read -r line; do
62
+ # 주석과 빈 줄 skip
63
+ case "$line" in
64
+ ""|"#"*) continue ;;
65
+ esac
66
+ # trim whitespace
67
+ clean=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
68
+ if [ "$clean" = "$SERVER_NAME" ]; then
69
+ MATCHED=true
70
+ break
71
+ fi
72
+ done < "$ALLOWLIST"
73
+
74
+ if [ "$MATCHED" = false ]; then
75
+ echo "[mcp-pre-exec] BLOCKED: MCP server '$SERVER_NAME' not in allowlist" >&2
76
+ echo "" >&2
77
+ echo "Tool: $TOOL_NAME" >&2
78
+ echo "Allowlist: $ALLOWLIST" >&2
79
+ echo "" >&2
80
+ echo "이 서버를 허용하려면 '$SERVER_NAME'을 $ALLOWLIST 에 한 줄로 추가." >&2
81
+ exit 2
82
+ fi
83
+
84
+ # 위험 파라미터 패턴 검사 (tool_input 전체를 문자열로)
85
+ TOOL_INPUT_JSON=""
86
+ if command -v jq &>/dev/null; then
87
+ TOOL_INPUT_JSON=$(echo "$INPUT" | jq -r '.tool_input // empty' 2>/dev/null || echo "")
88
+ else
89
+ TOOL_INPUT_JSON=$(echo "$INPUT" | grep -oE '"tool_input"[[:space:]]*:[[:space:]]*\{[^}]*\}')
90
+ fi
91
+
92
+ if [ -n "$TOOL_INPUT_JSON" ]; then
93
+ if echo "$TOOL_INPUT_JSON" | grep -qE "rm -rf|curl[^|]*\| *sh|wget[^|]*\| *bash|\beval\b.*\\\$|base64[[:space:]]+-d.*\| *sh"; then
94
+ echo "[mcp-pre-exec] BLOCKED: suspicious parameter pattern in tool_input" >&2
95
+ echo "" >&2
96
+ echo "Tool: $TOOL_NAME" >&2
97
+ echo "위험 패턴 감지: rm -rf / curl|sh / wget|bash / eval \$... / base64-d|sh" >&2
98
+ echo "" >&2
99
+ echo "의도된 사용이면 .mcp-allowlist 대신 이 서버의 다른 호출 경로 검토 필요." >&2
100
+ exit 2
101
+ fi
102
+ fi
103
+
104
+ exit 0
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # PreToolUse Hook: Write/Edit 대상이 보호 파일이면 차단
3
+ # Python 의존 없음 — jq 또는 순수 bash로 동작
4
+ set -e
5
+
6
+ INPUT_JSON=$(cat)
7
+
8
+ # jq가 있으면 사용, 없으면 grep 폴백
9
+ if command -v jq &> /dev/null; then
10
+ FILE_PATH=$(echo "$INPUT_JSON" | jq -r '.tool_input.file_path // .tool_input.path // ""' 2>/dev/null)
11
+ else
12
+ # 순수 bash 폴백: file_path 추출
13
+ FILE_PATH=$(echo "$INPUT_JSON" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
14
+ if [ -z "$FILE_PATH" ]; then
15
+ FILE_PATH=$(echo "$INPUT_JSON" | grep -o '"path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
16
+ fi
17
+ fi
18
+
19
+ if [ -z "$FILE_PATH" ]; then
20
+ exit 0
21
+ fi
22
+
23
+ BASENAME=$(basename "$FILE_PATH")
24
+
25
+ # 보호 패턴 확인
26
+ case "$BASENAME" in
27
+ .env|.env.*)
28
+ echo "BLOCKED: Protected file: $BASENAME. Environment files must be edited manually." >&2
29
+ exit 2
30
+ ;;
31
+ package-lock.json|yarn.lock|pnpm-lock.yaml|Cargo.lock|poetry.lock|uv.lock)
32
+ echo "BLOCKED: Protected file: $BASENAME. Lock files should not be edited directly." >&2
33
+ exit 2
34
+ ;;
35
+ *.pem|*.key|*.p12|*.pfx)
36
+ echo "BLOCKED: Protected file: $BASENAME. Certificate/key files must not be modified by agents." >&2
37
+ exit 2
38
+ ;;
39
+ esac
40
+
41
+ exit 0
@@ -0,0 +1,40 @@
1
+ #!/bin/bash
2
+ # Session Start Hook
3
+ # git pull + 세션 컨텍스트 출력 + compact-warning.flag 감지
4
+ set -e
5
+
6
+ BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
7
+
8
+ # 1. git pull (branch가 있고 detached HEAD가 아닐 때)
9
+ if [ -n "$BRANCH" ] && [ "$BRANCH" != "HEAD" ]; then
10
+ git pull --rebase 2>/dev/null || true
11
+ fi
12
+
13
+ # 2. SPEC 존재 여부 확인
14
+ SPEC_EXISTS="false"
15
+ if [ -f "docs/SPEC.md" ] || [ -f "SPEC.md" ]; then
16
+ SPEC_EXISTS="true"
17
+ fi
18
+
19
+ # 3. compact-warning.flag 감지 (이전 세션에서 checkpoint-snapshot이 생성)
20
+ COMPACT_WARNING=""
21
+ WARNING_FLAG=".claude/compact-warning.flag"
22
+ if [ -f "$WARNING_FLAG" ]; then
23
+ LAST_CHECKPOINT=$(cat "$WARNING_FLAG" 2>/dev/null || echo "unknown")
24
+ COMPACT_WARNING=" Checkpoint saved at $LAST_CHECKPOINT — run /compact soon to reclaim context."
25
+ rm -f "$WARNING_FLAG"
26
+ fi
27
+
28
+ # 4. 세션 컨텍스트 출력
29
+ if [ "$SPEC_EXISTS" = "true" ]; then
30
+ MSG="Session started. Branch: ${BRANCH:-detached}. SPEC exists — read docs/SPEC.md first (Persistent Anchor). Check Change Log and current Phase before starting work.${COMPACT_WARNING}"
31
+ else
32
+ MSG="Session started. Branch: ${BRANCH:-detached}. No SPEC found. Use /uzys:spec to begin workflow.${COMPACT_WARNING}"
33
+ fi
34
+
35
+ cat <<EOF
36
+ {
37
+ "priority": "INFO",
38
+ "message": "$MSG"
39
+ }
40
+ EOF
@@ -0,0 +1,86 @@
1
+ #!/bin/bash
2
+ # spec-drift-check.sh
3
+ # SPEC.md/todo.md/PRD.md의 drift를 검출한다.
4
+ # Verify 또는 Ship 단계에서 호출 가능.
5
+ #
6
+ # 검출 항목:
7
+ # 1. SPEC.md의 Verification Checklist에 unchecked 항목 존재
8
+ # 2. todo.md의 unchecked 항목 존재
9
+ # 3. SPEC.md Status가 "Define"인데 build/verify gate가 완료된 경우
10
+ # 4. PRD.md Status가 In Progress인데 모든 Phase가 Complete인 경우
11
+ #
12
+ # Exit codes:
13
+ # 0: drift 없음
14
+ # 1: drift 발견 (경고 출력)
15
+ # 2: 차단 수준 drift (Ship 게이트에서 차단)
16
+ set -e
17
+
18
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
19
+ DOCS_DIR="$PROJECT_DIR/docs"
20
+ [ ! -d "$DOCS_DIR" ] && DOCS_DIR="$PROJECT_DIR/Docs"
21
+
22
+ DRIFT=0
23
+ BLOCK=0
24
+
25
+ count_unchecked() {
26
+ local file="$1"
27
+ grep -c "^- \[ \]\|^ - \[ \]" "$file" 2>/dev/null | tail -1 | tr -d ' \n'
28
+ }
29
+
30
+ # 1. SPEC.md unchecked 검사
31
+ if [ -f "$DOCS_DIR/SPEC.md" ]; then
32
+ UNCHECKED=$(count_unchecked "$DOCS_DIR/SPEC.md")
33
+ UNCHECKED=${UNCHECKED:-0}
34
+ if [ "$UNCHECKED" -gt 0 ] 2>/dev/null; then
35
+ echo "DRIFT: SPEC.md에 unchecked 항목 ${UNCHECKED}건" >&2
36
+ DRIFT=$((DRIFT + 1))
37
+ fi
38
+ fi
39
+
40
+ # 2. todo.md unchecked 검사
41
+ if [ -f "$DOCS_DIR/todo.md" ]; then
42
+ UNCHECKED=$(count_unchecked "$DOCS_DIR/todo.md")
43
+ UNCHECKED=${UNCHECKED:-0}
44
+ if [ "$UNCHECKED" -gt 0 ] 2>/dev/null; then
45
+ echo "DRIFT: todo.md에 unchecked 항목 ${UNCHECKED}건" >&2
46
+ DRIFT=$((DRIFT + 1))
47
+ fi
48
+ fi
49
+
50
+ # 3. SPEC.md Status 일관성 — gate-status.json과 대조
51
+ GATE_FILE="$PROJECT_DIR/.claude/gate-status.json"
52
+ if [ -f "$GATE_FILE" ] && [ -f "$DOCS_DIR/SPEC.md" ] && command -v jq &> /dev/null; then
53
+ BUILD_DONE=$(jq -r '.build.completed // false' "$GATE_FILE")
54
+ VERIFY_DONE=$(jq -r '.verify.completed // false' "$GATE_FILE")
55
+
56
+ # SPEC Status가 "Define"인지 확인 (frontmatter 형식만, 본문 파이프라인 설명 제외)
57
+ if grep -qE "^> \*\*Status\*\*:.*Define" "$DOCS_DIR/SPEC.md"; then
58
+ if [ "$BUILD_DONE" = "true" ] || [ "$VERIFY_DONE" = "true" ]; then
59
+ echo "DRIFT: SPEC.md Status='Define'인데 Build/Verify gate가 완료됨" >&2
60
+ DRIFT=$((DRIFT + 1))
61
+ # Ship 게이트에서는 차단 (Build 이후에도 SPEC이 Define이면 안 됨)
62
+ [ "$1" = "ship" ] && BLOCK=1
63
+ fi
64
+ fi
65
+ fi
66
+
67
+ # 4. Ship 단계에서는 모든 unchecked가 차단
68
+ if [ "$1" = "ship" ] && [ "$DRIFT" -gt 0 ]; then
69
+ BLOCK=1
70
+ fi
71
+
72
+ # Summary
73
+ if [ "$DRIFT" -eq 0 ]; then
74
+ echo "OK: SPEC/todo/PRD 동기화 상태 정상"
75
+ exit 0
76
+ fi
77
+
78
+ if [ "$BLOCK" -eq 1 ]; then
79
+ echo "" >&2
80
+ echo "BLOCKED (ship gate): SPEC drift 발견 — SPEC.md, todo.md, PRD.md 동기화 후 재시도" >&2
81
+ exit 2
82
+ fi
83
+
84
+ echo "" >&2
85
+ echo "WARNING: SPEC drift ${DRIFT}건. 동기화 권장." >&2
86
+ exit 1
@@ -0,0 +1,24 @@
1
+ # MCP Server Allowlist — opt-in security gate
2
+ #
3
+ # mcp-pre-exec.sh hook이 이 파일을 참조해 MCP 서버 호출을 화이트리스트
4
+ # 방식으로 차단한다. 파일이 없으면 opt-in 미활성 (모든 MCP 호출 통과).
5
+ #
6
+ # 사용법:
7
+ # 1. 이 파일을 프로젝트 루트에 `.mcp-allowlist` 이름으로 복사
8
+ # 2. 허용할 MCP 서버 이름을 한 줄에 하나씩 작성
9
+ # 3. '#' 주석과 빈 줄 허용
10
+ #
11
+ # 서버 이름 확인 방법:
12
+ # - .mcp.json의 `mcpServers` 필드 키 이름
13
+ # - 또는 PreToolUse에서 tool_name `mcp__<server>__<tool>` 의 <server>
14
+ #
15
+ # 기본 프로젝트 서버 (templates/mcp.json):
16
+ context7
17
+ github
18
+ chrome-devtools
19
+
20
+ # Track별 추가 서버 예시 (주석 해제 후 사용):
21
+ # supabase # csr-supabase Track
22
+ # railway # 배포 Track
23
+ # notion # executive Track
24
+ # playwright # UI Track
@@ -0,0 +1,20 @@
1
+ {
2
+ "_comment": "프로젝트 .mcp.json 템플릿. setup-harness.sh가 Track별로 조건부 항목을 동적 추가한다. 글로벌 ~/.claude/는 절대 건드리지 않음.",
3
+ "mcpServers": {
4
+ "context7": {
5
+ "type": "stdio",
6
+ "command": "npx",
7
+ "args": ["-y", "@upstash/context7-mcp@latest"]
8
+ },
9
+ "github": {
10
+ "type": "stdio",
11
+ "command": "npx",
12
+ "args": ["-y", "@modelcontextprotocol/server-github"]
13
+ },
14
+ "chrome-devtools": {
15
+ "type": "stdio",
16
+ "command": "npx",
17
+ "args": ["-y", "chrome-devtools-mcp@latest"]
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: "Build phase — TDD로 점진적 구현한다."
3
+ agent: build
4
+ ---
5
+
6
+ # /uzys-build — OpenCode
7
+
8
+ > **Generated from**: `.claude/commands/uzys/build.md` via TS CLI `src/opencode/skills.ts` (Phase C)
9
+ > **Slash**: `/uzys-build` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
10
+
11
+ ## Goal
12
+
13
+ {COMMAND_BODY_PLACEHOLDER}
14
+
15
+ ## OpenCode 제약 참고
16
+
17
+ - Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-build.md` → `/uzys-build`)
18
+ - Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
19
+
20
+ ---
21
+
22
+ *Phase C에서 본 command 본문이 `.claude/commands/uzys/build.md`로부터 포팅됨.*
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: "Plan phase — 작업을 검증 가능한 작은 단위로 분해한다."
3
+ agent: plan
4
+ ---
5
+
6
+ # /uzys-plan — OpenCode
7
+
8
+ > **Generated from**: `.claude/commands/uzys/plan.md` via TS CLI `src/opencode/skills.ts` (Phase C)
9
+ > **Slash**: `/uzys-plan` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
10
+
11
+ ## Goal
12
+
13
+ {COMMAND_BODY_PLACEHOLDER}
14
+
15
+ ## OpenCode 제약 참고
16
+
17
+ - Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-plan.md` → `/uzys-plan`)
18
+ - Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
19
+
20
+ ---
21
+
22
+ *Phase C에서 본 command 본문이 `.claude/commands/uzys/plan.md`로부터 포팅됨.*
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: "Review phase — 다중 관점 리뷰로 품질을 검증한다."
3
+ agent: plan
4
+ ---
5
+
6
+ # /uzys-review — OpenCode
7
+
8
+ > **Generated from**: `.claude/commands/uzys/review.md` via TS CLI `src/opencode/skills.ts` (Phase C)
9
+ > **Slash**: `/uzys-review` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
10
+
11
+ ## Goal
12
+
13
+ {COMMAND_BODY_PLACEHOLDER}
14
+
15
+ ## OpenCode 제약 참고
16
+
17
+ - Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-review.md` → `/uzys-review`)
18
+ - Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
19
+
20
+ ---
21
+
22
+ *Phase C에서 본 command 본문이 `.claude/commands/uzys/review.md`로부터 포팅됨.*
@@ -0,0 +1,22 @@
1
+ ---
2
+ description: "Ship phase — 프리런치 체크리스트 실행 후 배포한다."
3
+ agent: build
4
+ ---
5
+
6
+ # /uzys-ship — OpenCode
7
+
8
+ > **Generated from**: `.claude/commands/uzys/ship.md` via TS CLI `src/opencode/skills.ts` (Phase C)
9
+ > **Slash**: `/uzys-ship` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
10
+
11
+ ## Goal
12
+
13
+ {COMMAND_BODY_PLACEHOLDER}
14
+
15
+ ## OpenCode 제약 참고
16
+
17
+ - Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-ship.md` → `/uzys-ship`)
18
+ - Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
19
+
20
+ ---
21
+
22
+ *Phase C에서 본 command 본문이 `.claude/commands/uzys/ship.md`로부터 포팅됨.*
@@ -0,0 +1,28 @@
1
+ ---
2
+ description: "Define phase — 구조화된 스펙을 코드 작성 전에 작성한다."
3
+ agent: plan
4
+ ---
5
+
6
+ # /uzys-spec — Define Phase (OpenCode)
7
+
8
+ > **Generated from**: `.claude/commands/uzys/spec.md` via TS CLI `src/opencode/skills.ts` (Phase C)
9
+ > **Slash**: `/uzys-spec` (OpenCode namespace 미사용 — Phase B2 결정, hyphen 채택)
10
+
11
+ ## Pre-flight
12
+
13
+ 이 command 호출 전 확인:
14
+ - 직전 단계 없음 (최초 진입점)
15
+ - `docs/SPEC.md` 또는 `docs/specs/<feature>.md`가 아직 없거나 갱신 필요한 상황
16
+
17
+ ## Goal
18
+
19
+ {COMMAND_BODY_PLACEHOLDER}
20
+
21
+ ## OpenCode 제약 참고
22
+
23
+ - Slash 콜론 namespace 미사용 — 파일명 = 커맨드명 (`uzys-spec.md` → `/uzys-spec`)
24
+ - Plugin lifecycle (`.opencode/plugins/uzys-harness.ts`)이 gate-check / spec-drift / HITO 처리
25
+
26
+ ---
27
+
28
+ *Phase C에서 본 command 본문이 `.claude/commands/uzys/spec.md`로부터 포팅됨.*