@walwal-harness/cli 6.0.5 → 6.1.1

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 (49) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/commands/harness-solo.md +20 -20
  3. package/commands/harness-team.md +1 -1
  4. package/gotchas/coo-developer.md +13 -0
  5. package/gotchas/documentationer.md +13 -0
  6. package/package.json +1 -1
  7. package/scripts/conductor-tick.sh +416 -0
  8. package/scripts/harness-archive.sh +123 -0
  9. package/scripts/harness-dashboard-up.sh +72 -0
  10. package/scripts/harness-dashboard.sh +509 -0
  11. package/scripts/harness-goal-init.sh +72 -0
  12. package/scripts/harness-goal-show.sh +37 -0
  13. package/scripts/harness-gotcha-memory.sh +348 -0
  14. package/scripts/harness-gotcha-register.sh +393 -0
  15. package/scripts/harness-meeting-doc.sh +153 -0
  16. package/scripts/harness-monitor.sh +398 -0
  17. package/scripts/harness-next.sh +577 -0
  18. package/scripts/harness-progress-set.sh +41 -0
  19. package/scripts/harness-prompt-history.sh +164 -0
  20. package/scripts/harness-queue-manager.sh +694 -0
  21. package/scripts/harness-session-start.sh +140 -0
  22. package/scripts/harness-statusline.sh +139 -0
  23. package/scripts/harness-task-session.sh +48 -0
  24. package/scripts/harness-tmux.sh +372 -0
  25. package/scripts/harness-user-prompt-submit.sh +123 -0
  26. package/scripts/init-agents-md.sh +337 -0
  27. package/scripts/init-ref-docs.sh +262 -0
  28. package/scripts/lib/harness-audit.sh +113 -0
  29. package/scripts/lib/harness-guardrail.sh +148 -0
  30. package/scripts/lib/harness-keywait.sh +57 -0
  31. package/scripts/lib/harness-render-progress.sh +346 -0
  32. package/scripts/scan-project.sh +367 -0
  33. package/skills/brainstorming/SKILL.md +4 -4
  34. package/skills/conductor/SKILL.md +19 -16
  35. package/skills/coo-developer/SKILL.md +42 -0
  36. package/skills/cqo/SKILL.md +7 -0
  37. package/skills/cto/SKILL.md +7 -0
  38. package/skills/dispatcher/SKILL.md +17 -28
  39. package/skills/dispatcher/persona-ceo.md +2 -1
  40. package/skills/documentationer/SKILL.md +46 -0
  41. package/skills/evaluator-code-quality/SKILL.md +1 -1
  42. package/skills/evaluator-functional/SKILL.md +1 -1
  43. package/skills/evaluator-visual/SKILL.md +1 -1
  44. package/skills/generator-backend/SKILL.md +1 -1
  45. package/skills/generator-frontend/SKILL.md +1 -1
  46. package/skills/meeting-manager/SKILL.md +34 -1
  47. package/skills/planner/SKILL.md +23 -9
  48. package/skills/planner/persona-coo-hr.md +17 -0
  49. package/skills/service-ops/SKILL.md +19 -4
@@ -0,0 +1,367 @@
1
+ #!/bin/bash
2
+ # scan-project.sh — 기존 프로젝트 구조를 분석하여 하네스 초기화 정보를 생성
3
+ # 출력: .harness/actions/scan-result.json
4
+ set -e
5
+
6
+ PROJECT_ROOT="${1:-.}"
7
+ OUTPUT="${PROJECT_ROOT}/.harness/actions/scan-result.json"
8
+
9
+ mkdir -p "$(dirname "$OUTPUT")"
10
+
11
+ echo "=== Scanning project: ${PROJECT_ROOT} ==="
12
+
13
+ # ─────────────────────────────────────────
14
+ # 1. 기존 AGENTS.md / CLAUDE.md 감지
15
+ # ─────────────────────────────────────────
16
+ AGENTS_MD="none"
17
+ CLAUDE_MD="none"
18
+ CLAUDE_MD_IS_SYMLINK=false
19
+ EXISTING_RULES=""
20
+
21
+ if [ -f "${PROJECT_ROOT}/AGENTS.md" ]; then
22
+ AGENTS_MD="exists"
23
+ fi
24
+
25
+ if [ -L "${PROJECT_ROOT}/CLAUDE.md" ]; then
26
+ CLAUDE_MD="symlink"
27
+ CLAUDE_MD_IS_SYMLINK=true
28
+ elif [ -f "${PROJECT_ROOT}/CLAUDE.md" ]; then
29
+ CLAUDE_MD="exists"
30
+ # 기존 CLAUDE.md 내용 보존용 추출
31
+ EXISTING_RULES=$(cat "${PROJECT_ROOT}/CLAUDE.md")
32
+ fi
33
+
34
+ # ─────────────────────────────────────────
35
+ # 2. Tech Stack 감지
36
+ # ─────────────────────────────────────────
37
+ TECH_BACKEND="unknown"
38
+ TECH_FRONTEND="unknown"
39
+ TECH_DB="unknown"
40
+ TECH_MONOREPO="none"
41
+ TECH_LANG="unknown"
42
+ IS_NATIVE_APP=false
43
+
44
+ # Backend
45
+ if [ -f "${PROJECT_ROOT}/nest-cli.json" ]; then
46
+ TECH_BACKEND="nestjs"
47
+ TECH_LANG="typescript"
48
+ elif [ -f "${PROJECT_ROOT}/requirements.txt" ] || [ -f "${PROJECT_ROOT}/pyproject.toml" ]; then
49
+ TECH_BACKEND="python"
50
+ TECH_LANG="python"
51
+ if grep -q "fastapi" "${PROJECT_ROOT}/requirements.txt" 2>/dev/null || grep -q "fastapi" "${PROJECT_ROOT}/pyproject.toml" 2>/dev/null; then
52
+ TECH_BACKEND="fastapi"
53
+ elif grep -q "django" "${PROJECT_ROOT}/requirements.txt" 2>/dev/null || grep -q "django" "${PROJECT_ROOT}/pyproject.toml" 2>/dev/null; then
54
+ TECH_BACKEND="django"
55
+ fi
56
+ elif [ -f "${PROJECT_ROOT}/go.mod" ]; then
57
+ TECH_BACKEND="go"
58
+ TECH_LANG="go"
59
+ elif [ -f "${PROJECT_ROOT}/pom.xml" ] || [ -f "${PROJECT_ROOT}/build.gradle" ]; then
60
+ TECH_BACKEND="java"
61
+ TECH_LANG="java"
62
+ fi
63
+
64
+ # Frontend
65
+ # Flutter 우선 감지 — pubspec.yaml 존재하면 Flutter 프로젝트로 판정 (TECH_LANG도 보정)
66
+ FE_STACK="react" # react | flutter (기본값은 react 계열)
67
+ FE_TARGET="web" # web | mobile | desktop (Flutter 의 컴파일 타겟; React 는 항상 web)
68
+ FLUTTER_ROOT="" # Flutter 프로젝트 루트 경로 (web/mobile/desktop 감지용)
69
+
70
+ if [ -f "${PROJECT_ROOT}/pubspec.yaml" ] && grep -q "flutter:" "${PROJECT_ROOT}/pubspec.yaml" 2>/dev/null; then
71
+ TECH_FRONTEND="flutter"
72
+ TECH_LANG="dart"
73
+ FE_STACK="flutter"
74
+ FLUTTER_ROOT="${PROJECT_ROOT}"
75
+ elif [ -f "${PROJECT_ROOT}/next.config.js" ] || [ -f "${PROJECT_ROOT}/next.config.ts" ] || [ -f "${PROJECT_ROOT}/next.config.mjs" ]; then
76
+ TECH_FRONTEND="nextjs"
77
+ elif [ -f "${PROJECT_ROOT}/vite.config.ts" ] || [ -f "${PROJECT_ROOT}/vite.config.js" ]; then
78
+ TECH_FRONTEND="vite-react"
79
+ elif [ -f "${PROJECT_ROOT}/angular.json" ]; then
80
+ TECH_FRONTEND="angular"
81
+ elif [ -f "${PROJECT_ROOT}/nuxt.config.ts" ]; then
82
+ TECH_FRONTEND="nuxt"
83
+ fi
84
+
85
+ # Monorepo 내 Frontend 감지
86
+ if [ -d "${PROJECT_ROOT}/apps/web" ]; then
87
+ if [ -f "${PROJECT_ROOT}/apps/web/next.config.js" ] || [ -f "${PROJECT_ROOT}/apps/web/next.config.ts" ]; then
88
+ TECH_FRONTEND="nextjs"
89
+ FE_STACK="react"
90
+ elif [ -f "${PROJECT_ROOT}/apps/web/vite.config.ts" ]; then
91
+ TECH_FRONTEND="vite-react"
92
+ FE_STACK="react"
93
+ fi
94
+ fi
95
+
96
+ # Flutter 서브디렉토리 감지 (monorepo 또는 서브 프로젝트 케이스)
97
+ if [ "$TECH_FRONTEND" = "unknown" ]; then
98
+ # 대표적인 Flutter 서브폴더 이름을 얕게 탐색
99
+ for d in apps/mobile apps/web mobile clue_mobile_app flutter_app; do
100
+ if [ -f "${PROJECT_ROOT}/${d}/pubspec.yaml" ] && grep -q "flutter:" "${PROJECT_ROOT}/${d}/pubspec.yaml" 2>/dev/null; then
101
+ TECH_FRONTEND="flutter"
102
+ TECH_LANG="dart"
103
+ FE_STACK="flutter"
104
+ FLUTTER_ROOT="${PROJECT_ROOT}/${d}"
105
+ break
106
+ fi
107
+ done
108
+ fi
109
+
110
+ # Flutter fe_target 감지 (web / mobile / desktop)
111
+ # - web/index.html 존재 → web
112
+ # - android/ 또는 ios/ 존재 + web/ 없음 → mobile
113
+ # - macos/ 또는 windows/ 또는 linux/ 존재 + 위 둘 없음 → desktop
114
+ # - 동시 존재 (멀티 타겟) → web 우선 (사용자가 Planner에서 변경 가능)
115
+ if [ "$FE_STACK" = "flutter" ] && [ -n "$FLUTTER_ROOT" ]; then
116
+ HAS_WEB=false
117
+ HAS_MOBILE=false
118
+ HAS_DESKTOP=false
119
+ [ -f "${FLUTTER_ROOT}/web/index.html" ] && HAS_WEB=true
120
+ { [ -d "${FLUTTER_ROOT}/android" ] || [ -d "${FLUTTER_ROOT}/ios" ]; } && HAS_MOBILE=true
121
+ { [ -d "${FLUTTER_ROOT}/macos" ] || [ -d "${FLUTTER_ROOT}/windows" ] || [ -d "${FLUTTER_ROOT}/linux" ]; } && HAS_DESKTOP=true
122
+
123
+ if [ "$HAS_WEB" = "true" ]; then
124
+ FE_TARGET="web"
125
+ elif [ "$HAS_MOBILE" = "true" ]; then
126
+ FE_TARGET="mobile"
127
+ elif [ "$HAS_DESKTOP" = "true" ]; then
128
+ FE_TARGET="desktop"
129
+ else
130
+ FE_TARGET="unknown"
131
+ fi
132
+ fi
133
+
134
+ # Swift (macOS / iOS 네이티브 앱) 감지 — Flutter 감지 이후
135
+ if [ "$TECH_FRONTEND" = "unknown" ]; then
136
+ SWIFT_DETECTED=false
137
+ if [ -f "${PROJECT_ROOT}/Package.swift" ]; then
138
+ SWIFT_DETECTED=true
139
+ fi
140
+ if ! $SWIFT_DETECTED; then
141
+ for f in "${PROJECT_ROOT}"/*.xcodeproj "${PROJECT_ROOT}"/*.xcworkspace; do
142
+ if [ -e "$f" ]; then
143
+ SWIFT_DETECTED=true
144
+ break
145
+ fi
146
+ done
147
+ fi
148
+ if ! $SWIFT_DETECTED && [ -f "${PROJECT_ROOT}/Podfile" ]; then
149
+ SWIFT_DETECTED=true
150
+ fi
151
+
152
+ if $SWIFT_DETECTED; then
153
+ TECH_LANG="swift"
154
+ IS_NATIVE_APP=true
155
+ FE_STACK="swift" # FE_STACK 기본값(react) 을 Swift 로 치환
156
+ FE_TARGET="native" # web/mobile/desktop 대신 native
157
+ # 서브타입 판별 — NSStatusBar 가 가장 특화적이므로 우선
158
+ if grep -rq "NSStatusBar.system" "${PROJECT_ROOT}" --include="*.swift" 2>/dev/null; then
159
+ TECH_FRONTEND="swift-macos-statusbar"
160
+ elif grep -rq "import SwiftUI" "${PROJECT_ROOT}" --include="*.swift" 2>/dev/null; then
161
+ TECH_FRONTEND="swift-swiftui"
162
+ elif grep -rq "import UIKit" "${PROJECT_ROOT}" --include="*.swift" 2>/dev/null; then
163
+ TECH_FRONTEND="swift-uikit"
164
+ else
165
+ TECH_FRONTEND="swift"
166
+ fi
167
+ fi
168
+ fi
169
+
170
+ # Database
171
+ if grep -rq "typeorm\|prisma\|sequelize\|knex" "${PROJECT_ROOT}/package.json" 2>/dev/null; then
172
+ if grep -q "pg\|postgres" "${PROJECT_ROOT}/package.json" 2>/dev/null; then
173
+ TECH_DB="postgresql"
174
+ elif grep -q "mysql" "${PROJECT_ROOT}/package.json" 2>/dev/null; then
175
+ TECH_DB="mysql"
176
+ elif grep -q "sqlite" "${PROJECT_ROOT}/package.json" 2>/dev/null; then
177
+ TECH_DB="sqlite"
178
+ else
179
+ TECH_DB="orm-detected"
180
+ fi
181
+ elif grep -rq "mongoose\|mongodb" "${PROJECT_ROOT}/package.json" 2>/dev/null; then
182
+ TECH_DB="mongodb"
183
+ fi
184
+
185
+ # Monorepo
186
+ if [ -f "${PROJECT_ROOT}/turbo.json" ]; then
187
+ TECH_MONOREPO="turborepo"
188
+ elif [ -f "${PROJECT_ROOT}/nx.json" ]; then
189
+ TECH_MONOREPO="nx"
190
+ elif [ -f "${PROJECT_ROOT}/lerna.json" ]; then
191
+ TECH_MONOREPO="lerna"
192
+ elif [ -f "${PROJECT_ROOT}/pnpm-workspace.yaml" ]; then
193
+ TECH_MONOREPO="pnpm-workspace"
194
+ elif [ -f "${PROJECT_ROOT}/nest-cli.json" ] && grep -q '"monorepo": true' "${PROJECT_ROOT}/nest-cli.json" 2>/dev/null; then
195
+ TECH_MONOREPO="nestjs-monorepo"
196
+ fi
197
+
198
+ # ─────────────────────────────────────────
199
+ # 3. 디렉토리 트리 스캔 (2 depth)
200
+ # ─────────────────────────────────────────
201
+ TREE=$(find "${PROJECT_ROOT}" -maxdepth 3 -type d \
202
+ ! -path "*/node_modules/*" \
203
+ ! -path "*/.git/*" \
204
+ ! -path "*/.next/*" \
205
+ ! -path "*/dist/*" \
206
+ ! -path "*/__pycache__/*" \
207
+ ! -path "*/.harness/archive/*" \
208
+ ! -name "node_modules" \
209
+ ! -name ".git" \
210
+ ! -name ".next" \
211
+ ! -name "dist" \
212
+ 2>/dev/null | sort | sed "s|${PROJECT_ROOT}/||g" | sed '/^$/d')
213
+
214
+ # ─────────────────────────────────────────
215
+ # 4. 주요 설정 파일 목록
216
+ # ─────────────────────────────────────────
217
+ CONFIG_FILES=""
218
+ for f in package.json tsconfig.json nest-cli.json next.config.js next.config.ts \
219
+ vite.config.ts docker-compose.yml docker-compose.yaml Dockerfile \
220
+ .env .env.example turbo.json nx.json pyproject.toml requirements.txt \
221
+ go.mod pom.xml build.gradle Makefile; do
222
+ if [ -f "${PROJECT_ROOT}/${f}" ]; then
223
+ CONFIG_FILES="${CONFIG_FILES}\"${f}\","
224
+ fi
225
+ done
226
+ CONFIG_FILES="[${CONFIG_FILES%,}]"
227
+
228
+ # ─────────────────────────────────────────
229
+ # 5. OpenAPI / Swagger 감지
230
+ # ─────────────────────────────────────────
231
+ OPENAPI="none"
232
+ for f in openapi.json openapi.yaml swagger.json swagger.yaml api-spec.json api-spec.yaml; do
233
+ if [ -f "${PROJECT_ROOT}/${f}" ] || [ -f "${PROJECT_ROOT}/docs/${f}" ]; then
234
+ OPENAPI="${f}"
235
+ break
236
+ fi
237
+ done
238
+
239
+ # NestJS Swagger 모듈 감지
240
+ if grep -rq "@nestjs/swagger" "${PROJECT_ROOT}/package.json" 2>/dev/null; then
241
+ if [ "$OPENAPI" = "none" ]; then
242
+ OPENAPI="nestjs-swagger-module (runtime-generated)"
243
+ fi
244
+ fi
245
+
246
+ # ─────────────────────────────────────────
247
+ # 6. Git 정보
248
+ # ─────────────────────────────────────────
249
+ GIT_INIT=false
250
+ GIT_COMMITS=0
251
+ GIT_BRANCH="none"
252
+ if [ -d "${PROJECT_ROOT}/.git" ]; then
253
+ GIT_INIT=true
254
+ GIT_COMMITS=$(git -C "${PROJECT_ROOT}" rev-list --count HEAD 2>/dev/null || echo 0)
255
+ GIT_BRANCH=$(git -C "${PROJECT_ROOT}" branch --show-current 2>/dev/null || echo "unknown")
256
+ fi
257
+
258
+ # ─────────────────────────────────────────
259
+ # 7. 하네스 기존 상태
260
+ # ─────────────────────────────────────────
261
+ HARNESS_EXISTS=false
262
+ HARNESS_VERSION="none"
263
+ if [ -f "${PROJECT_ROOT}/.harness/config.json" ]; then
264
+ HARNESS_EXISTS=true
265
+ HARNESS_VERSION=$(grep '"version"' "${PROJECT_ROOT}/.harness/config.json" 2>/dev/null | head -1 | sed 's/.*: *"\(.*\)".*/\1/')
266
+ fi
267
+
268
+ # ─────────────────────────────────────────
269
+ # 8. JSON 출력
270
+ # ─────────────────────────────────────────
271
+
272
+ # 디렉토리 트리를 JSON 배열로 변환
273
+ TREE_JSON=$(echo "$TREE" | awk 'BEGIN{printf "["} NR>1{printf ","} {printf "\"%s\"", $0} END{printf "]"}')
274
+
275
+ # 기존 CLAUDE.md 내용 (JSON escape)
276
+ EXISTING_RULES_JSON=$(echo "$EXISTING_RULES" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || echo '""')
277
+
278
+ cat > "$OUTPUT" << JSONEOF
279
+ {
280
+ "scanned_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
281
+ "project_root": "${PROJECT_ROOT}",
282
+
283
+ "existing_docs": {
284
+ "agents_md": "${AGENTS_MD}",
285
+ "claude_md": "${CLAUDE_MD}",
286
+ "claude_md_is_symlink": ${CLAUDE_MD_IS_SYMLINK},
287
+ "existing_claude_md_content": ${EXISTING_RULES_JSON}
288
+ },
289
+
290
+ "tech_stack": {
291
+ "backend": "${TECH_BACKEND}",
292
+ "frontend": "${TECH_FRONTEND}",
293
+ "fe_stack": "${FE_STACK}",
294
+ "fe_target": "${FE_TARGET}",
295
+ "database": "${TECH_DB}",
296
+ "monorepo": "${TECH_MONOREPO}",
297
+ "language": "${TECH_LANG}",
298
+ "is_native_app": ${IS_NATIVE_APP}
299
+ },
300
+
301
+ "tech_stack_confidence": "$(
302
+ if [ "$TECH_BACKEND" = "unknown" ] && [ "$TECH_FRONTEND" = "unknown" ]; then
303
+ echo "unknown"
304
+ else
305
+ echo "detected"
306
+ fi
307
+ )",
308
+
309
+ "structure": {
310
+ "directories": ${TREE_JSON},
311
+ "config_files": ${CONFIG_FILES}
312
+ },
313
+
314
+ "api": {
315
+ "openapi_spec": "${OPENAPI}"
316
+ },
317
+
318
+ "git": {
319
+ "initialized": ${GIT_INIT},
320
+ "commits": ${GIT_COMMITS},
321
+ "branch": "${GIT_BRANCH}"
322
+ },
323
+
324
+ "harness": {
325
+ "exists": ${HARNESS_EXISTS},
326
+ "version": "${HARNESS_VERSION}"
327
+ },
328
+
329
+ "recommendation": {
330
+ "project_type": "$(
331
+ if [ "$TECH_BACKEND" != "unknown" ] && [ "$TECH_FRONTEND" != "unknown" ]; then
332
+ echo "fullstack"
333
+ elif [ "$TECH_BACKEND" != "unknown" ]; then
334
+ echo "backend-only"
335
+ elif [ "$TECH_FRONTEND" != "unknown" ]; then
336
+ echo "frontend-only"
337
+ else
338
+ echo "empty"
339
+ fi
340
+ )",
341
+ "agents_md_action": "$(
342
+ if [ "$AGENTS_MD" = "none" ] && [ "$CLAUDE_MD" = "none" ]; then
343
+ echo "create-new"
344
+ elif [ "$AGENTS_MD" = "none" ] && [ "$CLAUDE_MD" = "exists" ]; then
345
+ echo "migrate-claude-to-agents"
346
+ elif [ "$AGENTS_MD" = "exists" ]; then
347
+ echo "rebuild-with-harness"
348
+ else
349
+ echo "create-new"
350
+ fi
351
+ )"
352
+ }
353
+ }
354
+ JSONEOF
355
+
356
+ echo ""
357
+ echo "=== Scan Complete ==="
358
+ echo "Output: ${OUTPUT}"
359
+ echo ""
360
+ echo "--- Summary ---"
361
+ echo "Tech Stack: ${TECH_BACKEND} / ${TECH_FRONTEND} (fe_stack=${FE_STACK}, fe_target=${FE_TARGET}, native=${IS_NATIVE_APP}) / ${TECH_DB}"
362
+ echo "Monorepo: ${TECH_MONOREPO}"
363
+ echo "OpenAPI: ${OPENAPI}"
364
+ echo "Git: ${GIT_INIT} (${GIT_COMMITS} commits, branch: ${GIT_BRANCH})"
365
+ echo "Existing Docs: AGENTS.md=${AGENTS_MD}, CLAUDE.md=${CLAUDE_MD}"
366
+ echo "Harness: ${HARNESS_EXISTS} (v${HARNESS_VERSION})"
367
+ echo "Recommendation: $(cat "$OUTPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f\"type={d['recommendation']['project_type']}, agents_md={d['recommendation']['agents_md_action']}\")" 2>/dev/null)"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: harness-brainstorming
3
3
  description: "사용자의 러프한(바이브코딩) 요구사항을 대화형으로 구체화하여 Planner가 바로 쓸 수 있는 디자인/스펙 문서(.harness/actions/brainstorm-spec.md)로 만든다. Dispatcher가 사용자에게 '브레인스토밍 필요?' 라고 확인한 뒤에만 호출된다. 원본: obra/superpowers MIT."
4
- disable-model-invocation: true
4
+ disable-model-invocation: false
5
5
  ---
6
6
 
7
7
  # Brainstormer — 요구사항 구체화 (obra/superpowers 파생)
@@ -52,9 +52,9 @@ jq '.agent_status = "completed" | .completed_agents += ["planner"]' .harness/p
52
52
  ## Session Boundary Protocol
53
53
 
54
54
  ### On Start
55
- 1. `.harness/progress.json` 읽기 — `next_agent == "brainstormer"` 인지 확인
55
+ 1. `.harness/progress.json` 읽기 — `next_agent == "brainstorming"` 인지 확인
56
56
  - 아니면 즉시 STOP + "Dispatcher 를 먼저 실행하세요" 안내
57
- 2. progress.json 업데이트: `current_agent` → `"brainstormer"`, `agent_status` → `"running"`, `updated_at` 갱신
57
+ 2. progress.json 업데이트: `current_agent` → `"brainstorming"`, `agent_status` → `"running"`, `updated_at` 갱신
58
58
  3. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
59
59
  4. **Skip 조건 검사**: `.harness/actions/brainstorm-spec.md` 가 이미 존재하고
60
60
  사용자가 "새로 브레인스토밍" 을 명시하지 않았다면:
@@ -66,7 +66,7 @@ jq '.agent_status = "completed" | .completed_agents += ["planner"]' .harness/p
66
66
  1. `.harness/actions/brainstorm-spec.md` 가 존재하고 "User Review Gate" 를 통과했는지 확인
67
67
  2. progress.json 업데이트:
68
68
  - `agent_status` → `"completed"`
69
- - `completed_agents` 에 `"brainstormer"` 추가
69
+ - `completed_agents` 에 `"brainstorming"` 추가
70
70
  - `next_agent` → `"planner"`
71
71
  3. `.harness/progress.log` 에 요약 추가: `Brainstormer → Planner (spec: <경로>)`
72
72
  4. 출력: `"✓ Brainstormer 완료. brainstorm-spec.md 검토 후 승인 신호를 주세요. 승인 시 자동 핸드오프 (Conductor 자율 시동) (Planner)."`
@@ -136,16 +136,23 @@ idle ─► running ─► (waiting_meeting | waiting_owner | running) ─► co
136
136
 
137
137
  ```
138
138
  [Planner missing or sprint=0] → spawn planner
139
- [generator pending in feature row] → spawn generator-{be|fe|designer|devops}
140
- [generator done, eval pending] → spawn evaluator-{func|visual|cq|arch|sec}
139
+ [generator pending in feature row] → spawn generator-backend | generator-frontend | generator-designer | generator-devops
140
+ [generator done, eval pending] → spawn evaluator-code-quality | evaluator-functional | evaluator-visual | evaluator-architecture | evaluator-security
141
141
  [all eval PASS for feature] → next feature
142
142
  [all features PASS] → Phase Gate Meeting
143
- [Service-Ops cron due] → spawn service-ops monitor
144
- [ops-report ready] → handoff to CTO (spawn cto-review)
145
- [generator-* / eval-functional spawn 직전] → 동시 spawn service-ops/monitor (stream-mode, G-006)
143
+ [Service-Ops cron due] → spawn service-ops (requested_mode=monitor)
144
+ [ops-report ready] → handoff to CTO (spawn cto)
145
+ [planner requested_mode=hypothesis]→ spawn coo-developer and/or documentationer
146
+ [generator-* / eval-functional spawn 직전] → 동시 spawn service-ops (requested_mode=monitor, stream-mode, G-006)
146
147
  [mode=team & ready ≥ 2] → 동시 spawn min(ready,3) generator/evaluator (G-005)
147
148
  ```
148
149
 
150
+ `planner.requested_mode == "hypothesis"` 인 경우 Conductor 는 정규 Generator/Evaluator 체인보다 COO 직속 셀을 우선한다:
151
+
152
+ - 리서치·정리 중심 → `documentationer`
153
+ - 빠른 실험·백데이터 코드 중심 → `coo-developer`
154
+ - 둘 다 필요 → 같은 tick 에 2명 병렬 spawn 가능
155
+
149
156
  ### 5.1 Team mode 병렬 spawn (G-005)
150
157
 
151
158
  `progress.json.mode == "team"` 이면 매 tick 시작 시 ready 목록을 계산하여 **동시 다발 spawn**:
@@ -161,11 +168,12 @@ slots=$(( ready_count < 3 ? ready_count : 3 ))
161
168
 
162
169
  ### 5.2 Service-Ops monitor 동반 spawn (G-006)
163
170
 
164
- generator-{backend,frontend,frontend-flutter,devops} 또는 evaluator-functional* 을 spawn 하기 직전, **동일 tick 에서** service-ops/monitor 를 stream-mode 로 함께 spawn:
171
+ generator-backend / generator-frontend / generator-devops 또는 evaluator-functional 을 spawn 하기 직전, **동일 tick 에서** `service-ops` 를 `requested_mode=monitor` 로 함께 spawn:
165
172
 
166
173
  ```bash
167
174
  bash scripts/harness-progress-set.sh . \
168
- '.service_ops.monitor.stream_active = true |
175
+ '.service_ops.requested_mode = "monitor" |
176
+ .service_ops.monitor.stream_active = true |
169
177
  .service_ops.monitor.stream_target = "generator-frontend" |
170
178
  .agents += [{"id":"service-ops","room":"service-ops","minifigState":"watching"}]'
171
179
  ```
@@ -200,7 +208,7 @@ bash scripts/harness-progress-set.sh . \
200
208
 
201
209
  ## 7.5 모드 결정 (v6.0+, 사용자에서 이양)
202
210
 
203
- 이전에는 사용자가 `/harness-solo` 또는 `/harness-team` 으로 직접 선택했다. v6.0 부터 **Conductor 가 sprint 시작 시점에 자동 결정**한다. 사용자 override 는 가능하지만 디폴트는 자동.
211
+ 이전에는 사용자가 `/harness-solo` 또는 `/harness-team` 으로 직접 선택했다. v6.0 부터 **Conductor 가 sprint 시작 시점에 자동 결정**하며, 정상 경로는 회사형 team/company 루프다. `solo` 는 사용자 명시 시에만 들어가는 비상용 fallback 이다.
204
212
 
205
213
  ### 7.5.1 결정 시점
206
214
 
@@ -216,12 +224,7 @@ ready_at_start ≥ 3
216
224
  feature_count ≥ 6
217
225
  critical_path_depth ≤ 2
218
226
 
219
- # Solo 강제 조건 (어느 하나라도)
220
- ready_at_start ≤ 2
221
- 또는 feature_count ≤ 3
222
- 또는 critical_path_depth ≥ 4
223
-
224
- # 동률 → solo (비용 안전)
227
+ # Solo 관련 threshold 는 문서상 fallback 참고치일 뿐, auto 기본 경로는 team 유지
225
228
  ```
226
229
 
227
230
  `critical_path_depth` = feature 의존성 그래프에서 가장 긴 체인의 길이. `feature-list.json` 의 `depends_on` 으로 계산.
@@ -230,7 +233,7 @@ ready_at_start ≤ 2
230
233
 
231
234
  1. 결정 후 `progress.json` partial update:
232
235
  ```json
233
- "mode": "solo" 또는 "team",
236
+ "mode": "team" 기본, 필요 시 "solo",
234
237
  "mode_decision": {
235
238
  "owner": "conductor",
236
239
  "decided_at": "<iso>",
@@ -247,7 +250,7 @@ ready_at_start ≤ 2
247
250
 
248
251
  | 발화/명령 | 효과 |
249
252
  |---|---|
250
- | `/harness-solo` 또는 "solo 로" | mode=solo 강제, mode_decision.user_override="solo" |
253
+ | `/harness-solo` 또는 "solo 로" | mode=solo 강제, mode_decision.user_override="solo" (비상용 fallback) |
251
254
  | `/harness-team` 또는 "team 으로" | mode=team 강제, user_override="team" |
252
255
  | "auto 다시" / "Conductor 결정으로" | user_override=null, 다음 sprint 시작 시 재자동결정 |
253
256
 
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: harness-coo-developer
3
+ description: "COO 직속 가설검증 개발자. 빠른 spike, 백데이터 활용 실험, throwaway prototype 을 통해 가설을 사실로 검증한다. 아키텍처·코드퀄리티·테스트 완결성보다 속도와 의사결정용 evidence를 우선한다. 트리거: '가설 검증 개발', 'spike', 'backdata experiment'."
4
+ disable-model-invocation: false
5
+ ---
6
+
7
+ # COO Developer
8
+
9
+ > 목적은 운영용 코드를 만드는 것이 아니라, COO가 다음 결정을 내릴 수 있게 충분한 사실을 빠르게 확보하는 것이다.
10
+
11
+ ## 1. 책임
12
+
13
+ - 가설을 검증하기 위한 최소 코드 작성
14
+ - 백데이터/로그/덤프를 활용한 검증 스크립트 작성
15
+ - 프로덕션 품질보다 속도 우선의 throwaway prototype 제작
16
+ - 결과와 한계를 `documentationer` 또는 Planner에 넘길 수 있는 형태로 정리
17
+
18
+ ## 2. 입력
19
+
20
+ - CEO 또는 Service-Ops에서 전달된 가설/질문
21
+ - Planner의 `requested_mode = "hypothesis"`
22
+ - 기존 코드베이스, 로컬 데이터, 백데이터, 샘플 CSV/JSON/DB dump
23
+
24
+ ## 3. 출력
25
+
26
+ - 실험 코드 또는 스크립트
27
+ - 재현 절차
28
+ - 관찰 결과와 한계
29
+ - "가설 지지 / 반박 / 추가 데이터 필요" 3분류 결론
30
+
31
+ ## 4. 작업 원칙
32
+
33
+ - 빠르게 버릴 수 있는 코드를 두려워하지 말 것
34
+ - 운영 아키텍처에 맞추려다 속도를 잃지 말 것
35
+ - 단, 데이터 훼손이나 destructive action은 금지
36
+ - 결과가 정규화 가치가 있으면 Planner에게 Sprint artifact 승격을 요청
37
+
38
+ ## 5. 금지
39
+
40
+ - 실험 결과만으로 운영 가능 판정
41
+ - 정규 팀 평가 없이 배포 코드로 승격
42
+ - 근거 없는 직감성 결론
@@ -90,6 +90,13 @@ CQO는 다음 짝의 평가가 일치하는지 확인:
90
90
  docmeta: { ... }
91
91
  cqo_audit:
92
92
  sprint: <n>
93
+ decision:
94
+ owner: cqo
95
+ action_type: re-evaluate | reject
96
+ rationale: <why CQO passed or rejected the build>
97
+ evidence:
98
+ - source: <artifact path>
99
+ kind: evaluation | regression | security | architecture
93
100
  per_axis_scores:
94
101
  functional: 2.85
95
102
  visual: 2.92
@@ -93,6 +93,13 @@ CTO 판단 옵션:
93
93
  docmeta: { ... }
94
94
  cto_review:
95
95
  sprint: <n>
96
+ decision:
97
+ owner: cto
98
+ action_type: implement | replan
99
+ rationale: <fact-based conclusion>
100
+ evidence:
101
+ - source: <artifact path>
102
+ kind: ops-report | meeting-record | cqo-audit
96
103
  goal_feasibility: feasible | feasible-with-recruit | infeasible
97
104
  recommended_recruits: [generator-designer, eval-security]
98
105
  arch_risks: [...]
@@ -53,9 +53,8 @@ jq '.agent_status = "completed" | .completed_agents += ["planner"]' .harness/p
53
53
  1. progress.json 업데이트:
54
54
  - `agent_status` → `"completed"`
55
55
  - `completed_agents`에 `"dispatcher"` 추가
56
- - `next_agent` → **브레인스토밍 결정 트리에 따라 결정** ([섹션 6](#6-brainstormer-routing-decision) 참조)
57
- - 신규/재플래닝 + 사용자가 브레인스토밍 선택 → `"brainstorming"`
58
- - 신규/재플래닝 + 사용자가 건너뛰기 선택 → `"planner"`
56
+ - `next_agent` → **기본은 `"meeting-manager"`**. CEO가 먼저 Cxx 회의를 소집하고, Conductor가 그 결과로 `planner(COO)` / `cto` / `cqo` / `service-ops` 를 분배한다.
57
+ - 신규/재플래닝/Goal 재정렬 → `"meeting-manager"`
59
58
  - 특정 에이전트 직접 명령 → 해당 에이전트 (예: `"evaluator-functional"`)
60
59
  - Gotcha 교정 후 재작업 → `failure.retry_target` (해당 에이전트)
61
60
  - `pipeline` → 선택된 파이프라인 (FULLSTACK/FE-ONLY/BE-ONLY)
@@ -74,7 +73,7 @@ jq '.agent_status = "completed" | .completed_agents += ["planner"]' .harness/p
74
73
  아카이빙 후 `dispatch.id` 는 `null` 로 리셋되므로, 다음 dispatcher 실행 시 새 D-NNN 이 할당된다.
75
74
  2. `.harness/progress.log`에 요약 한 줄 추가
76
75
  3. 출력: `"✓ Dispatcher 완료. 자동 핸드오프 (Conductor 자율 시동)."`
77
- 4. **즉시 내부 핸드오프 (scripts/harness-next.sh) 를 호출하여 다음 에이전트로 자동 핸드오프** (Solo 모드. Team 모드는 Lead가 별도 오케스트레이션). Brainstorming/Planner 단계가 아니면 사용자 승인 게이트 없음.
76
+ 4. **즉시 내부 핸드오프 (scripts/harness-next.sh) 를 호출하여 다음 에이전트로 자동 핸드오프**. 기본 경로는 `meeting-manager -> planner(COO) -> cto -> gen/eval -> cqo -> service-ops -> meeting-manager`.
78
77
 
79
78
  ## Auto-Routing (UserPromptSubmit Hook)
80
79
 
@@ -223,40 +222,30 @@ Dispatcher 는 사용자 요청을 분류한 뒤 아래 순서로 판단:
223
222
  ```
224
223
  1. Gotcha / 실수 지적인가?
225
224
  → YES: gotcha 기록 → next_agent = failure.retry_target (해당 에이전트)
226
- (브레인스토밍 없음)
225
+ (회의 소집 없이 재작업)
227
226
 
228
227
  2. 특정 에이전트 직접 명령인가?
229
228
  ("evaluator 다시 돌려", "generator-frontend 재작업", "planner plan.md 고쳐" 등)
230
- → YES: next_agent = <대상 에이전트> (브레인스토밍 없음)
229
+ → YES: next_agent = <대상 에이전트> (CEO 회의 우회)
231
230
 
232
- 3. Planner 가 동작해야 하는 케이스인가?
233
- (신규 파이프라인 / 신규 PRD / 기존 plan.md 대폭 수정 / 신규 feature 대규모 추가)
234
- → YES: 사용자에게 확인 질문 → 6.2 "브레인스토밍 확인 플로우"
235
- → NO: 다른 에이전트로 라우팅 (generator 이어서 등)
231
+ 3. 신규 GOAL / 재플래닝 / Goal drift / 운영 이슈인가?
232
+ → YES: next_agent = meeting-manager
233
+ (CEO가 COO/CTO/CQO/Service-Ops 회의를 먼저 소집)
236
234
 
237
- 4. 그 외 (메타/인사/Claude 자체 질문) → Dispatcher skip
238
- ```
239
-
240
- ### 6.2 브레인스토밍 확인 플로우
241
-
242
- Planner 를 호출해야 한다고 판단되면, **사용자에게 단 하나의 질문을 출력한 뒤 대기한다:**
235
+ 4. Brainstorming 이 필요한가?
236
+ → YES: Brainstorming 은 기본 진입점이 아니라 COO/Planner 내부 판단 또는
237
+ 명시적 요청일 때만 사용
243
238
 
239
+ 5. 그 외 (메타/인사/Claude 자체 질문) → Dispatcher skip
244
240
  ```
245
- 이 요청은 Planner 가 처리할 신규/재플래닝 건으로 보입니다.
246
- 러프한 요구사항을 먼저 구체화하는 Brainstormer 과정을 거칠까요?
247
241
 
248
- (Y) 예 — Brainstormer 와 대화하며 요구사항을 fit 하게 만든 뒤 Planner
249
- (N) 아니오 — 이미 PRD/OpenAPI 가 명확하므로 바로 Planner
242
+ ### 6.2 브레인스토밍 확인 플로우
250
243
 
251
- 답변: Y / N
252
- ```
244
+ 브레인스토밍은 더 이상 Dispatcher의 기본 확인 질문이 아니다.
253
245
 
254
- 사용자 응답 처리:
255
- - **Y (긍정)** — "네", "y", "yes", "필요해", "해줘" 등
256
- → `next_agent = "brainstorming"`
257
- - **N (부정)** — "아니오", "n", "no", "필요없어", "바로", "skip" 등
258
- → `next_agent = "planner"`
259
- - **불명확 / 무응답** — 한 번 더 "Y 또는 N 으로 답해주세요" 요청
246
+ - 기본값: `meeting-manager` 로 넘겨 CEO 회의 후 `planner(COO)` 가 브레인스토밍/웹리서치 필요 여부를 판단
247
+ - 예외: Owner가 명시적으로 "`/harness-brainstorming`", "브레인스토밍부터"를 요청한 경우에만 직접 `brainstorming`
248
+ - 금지: Planner 진입 전에 Brainstorming 여부를 사용자 승인 게이트로 되돌리는 것
260
249
 
261
250
  ### 6.3 Skip 케이스 정리
262
251
 
@@ -83,6 +83,7 @@ Source: https://github.com/msitarzewski/agency-agents (MIT)
83
83
  | Enterprise Feature | "기존 시스템", "엔터프라이즈", "통합" | + Eval-Arch·Eval-Security·Service-Ops |
84
84
  | Marketing/Content | "랜딩", "캠페인", "콘텐츠" | Designer·Marketing(옵트인)·Eval-Visual |
85
85
  | Incident Response | "장애", "다운", "긴급", "롤백" | Incident-Responder·Service-Ops·관련 Gen |
86
+ | Hypothesis Validation | "가설", "리서치", "실험", "백데이터", "빠르게 검증" | Planner·coo-developer·documentationer·Service-Ops(옵트인) |
86
87
 
87
88
  매칭 실패 시 → "추가 정보가 필요합니다" 1회 질문 → 그래도 모호하면 **Startup MVP** 기본값.
88
89
 
@@ -96,7 +97,7 @@ Source: https://github.com/msitarzewski/agency-agents (MIT)
96
97
  "runbook": "startup-mvp",
97
98
  "departments": {
98
99
  "must": ["planner","cto","cqo","conductor","meeting-manager","generator-backend","generator-frontend","generator-designer","evaluator-functional","evaluator-visual","evaluator-code-quality","generator-devops"],
99
- "should":["evaluator-architecture","service-ops"],
100
+ "should":["evaluator-architecture","service-ops","coo-developer","documentationer"],
100
101
  "may": ["evaluator-security","marketing","sales"],
101
102
  "off": ["finance","legal-compliance","spatial-computing"]
102
103
  },