@walwal-harness/cli 5.5.2 → 5.6.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.
package/README.md CHANGED
@@ -9,6 +9,215 @@
9
9
 
10
10
  ---
11
11
 
12
+ ## Run Book — 0 → 첫 스프린트 완주
13
+
14
+ > 프로젝트 루트에서 `npm i @walwal-harness/cli` 를 마치고 Claude Code 를 재시작한 뒤 아래 순서 그대로 진행합니다.
15
+
16
+ ### Step 1. Dispatcher — 들어오자마자
17
+
18
+ Claude Code 세션을 연 뒤 첫 메시지로:
19
+
20
+ ```
21
+ 하네스 엔지니어링 시작
22
+ ```
23
+
24
+ Dispatcher 가:
25
+ - 요청을 분류 (기능 요청 / 실수 지적 / 메타 질문)
26
+ - `FULLSTACK` / `FE-ONLY` / `BE-ONLY` 파이프라인 결정 → `actions/pipeline.json`
27
+ - 신규/재플래닝이면 "Brainstormer 를 거칠지" 한 번 묻고 `next_agent` 설정 후 STOP
28
+
29
+ 완료되면 **새 세션을 열기만 하면** SessionStart 훅이 다음 에이전트(`planner` 또는 `brainstorming`)를 안내합니다.
30
+
31
+ ### Step 2. Planner
32
+
33
+ 새 세션에서:
34
+
35
+ ```
36
+ /harness-planner
37
+ ```
38
+
39
+ Planner 가 `plan.md` + `feature-list.json` + `api-contract.json` 을 생성합니다. AC(Acceptance Criteria)는 반드시 **Executable** 포맷으로 기술됩니다.
40
+
41
+ ### Step 3. Solo / Team 모드 선택
42
+
43
+ Planner 완료 후 두 갈래 중 하나.
44
+
45
+ | 선택 | 명령 | 언제 |
46
+ |------|------|------|
47
+ | **Solo** | 프롬프트로 `/harness-generator-backend` → `/harness-generator-frontend` → `/harness-evaluator-*` 순차 호출 | 학습 목적 · feature 3개 이하 · 레이아웃이 좁음 |
48
+ | **Team** | `/harness-team` | feature 4개 이상 · 병렬로 확 밀고 싶을 때 |
49
+
50
+ ### Step 4. Team 모드 — Dashboard 띄우기
51
+
52
+ Team 모드는 tmux 통합 Studio 레이아웃을 제공합니다:
53
+
54
+ ```bash
55
+ # Claude Code 내에서
56
+ > /harness-team
57
+
58
+ # 또는 외부 터미널에서
59
+ npx walwal-harness team
60
+ ```
61
+
62
+ 첫 실행 시 자동으로:
63
+ 1. `feature-queue.json` 초기화 (의존성 topological sort)
64
+ 2. tmux (또는 iTerm2 native split) 레이아웃 구축
65
+ 3. 3개 팀 worker 가 Gen → Eval 루프를 병렬 실행
66
+ 4. 팀이 feature 완료 시 자동 dequeue
67
+ 5. 5회 초과 실패하면 사용자 개입 요청
68
+
69
+ #### 대시보드 구성
70
+
71
+ ```
72
+ ┌────────────────────┬──────────────────────────┬───────────┐
73
+ │ Dashboard │ Gotcha & Memory │ TEAM 1 │
74
+ │ - pipeline/sprint │ - 활성 에이전트 gotcha │ Gen|Eval │
75
+ │ - feature 진행도 │ - 나머지 에이전트 요약 ├───────────┤
76
+ │ - queue 상태 │ - SHARED MEMORY │ TEAM 2 │
77
+ │ │ (memory.md 최근 N) │ Gen|Eval │
78
+ ├────────────────────┤ ├───────────┤
79
+ │ Archive Prompt │ │ TEAM 3 │
80
+ │ (완료 feature 요약)│ │ Gen|Eval │
81
+ └────────────────────┴──────────────────────────┴───────────┘
82
+ ```
83
+
84
+ | 패널 | 내용 | 소스 |
85
+ |------|------|------|
86
+ | **Dashboard** | Pipeline · Sprint · Feature passes (●/◐/○/◌/✗) · Queue R:B:P · Retry | `harness-dashboard.sh` |
87
+ | **Gotcha & Memory** | 활성 에이전트의 누적 실수 + 나머지 요약 + 공유 메모리 | `harness-gotcha-memory.sh` |
88
+ | **TEAM 1–3** | 각 워커의 현재 feature · phase(Gen/Eval) · 실시간 stdout | `harness-queue-manager.sh` worker loop |
89
+ | **Archive Prompt** | 직전 완료 feature 요약 (다음 팀 컨텍스트 주입용) | archive 디렉토리 |
90
+
91
+ - 새로고침 주기: `HARNESS_REFRESH=5` (초). 환경변수로 조정.
92
+ - 단축키: `tmux prefix + 방향키` 로 패널 이동, `prefix + z` 로 확대/축소.
93
+ - 종료: `npx walwal-harness team --kill`.
94
+
95
+ ### Step 5. Feedback 등록 — 학습 누적
96
+
97
+ 대화 중 사용자 피드백은 **성격에 따라 3개 저장소** 중 하나로 자동 분류됩니다.
98
+
99
+ | 유형 | 성격 | 시그널 | 저장 위치 | ID |
100
+ |------|------|--------|----------|-----|
101
+ | **Gotcha** | 에이전트 실수(부정) | "~하지 마", "잘못됐어" | `.harness/gotchas/<agent>.md` | `G-NNN` |
102
+ | **Convention** | 하우스 스타일(긍정) | "~해야 해", "이렇게 해줘" | `.harness/conventions/<scope>.md` | `C-NNN` |
103
+ | **Memory** | 전체 공통 교훈 | "모든 에이전트가~" | `.harness/memory.md` | `M-NNN` |
104
+
105
+ #### 5a. Gotcha — "이러면 안 돼"
106
+
107
+ 사용자가 에이전트의 실수를 지적하면 Dispatcher 가 해당 에이전트의 `.harness/gotchas/<agent>.md` 에 자동 append. 다음 세션부터 그 에이전트는 세션 시작 시 자기 gotcha 파일을 읽고 같은 실수를 피합니다.
108
+
109
+ #### 예제 — 실수 지적
110
+
111
+ ```
112
+ 아니 그렇게 하면 안 되지. Generator-Backend 가 MockServer 를 무시하고
113
+ 실제 DB 에 붙으려고 하는데, npm run dev 에서 MockServer 가 concurrent 로
114
+ 기동되어 있으니 그걸 먼저 확인하고 써.
115
+ ```
116
+
117
+ Dispatcher 는 자동으로 분류:
118
+ - **대상 에이전트**: `generator-backend`
119
+ - **저장 위치**: `.harness/gotchas/generator-backend.md`
120
+ - **ID 할당**: `[G-002]` (기존 항목 다음 번호)
121
+
122
+ #### 기록 포맷 (Dispatcher 가 자동 작성)
123
+
124
+ ```markdown
125
+ ### [G-002] MockServer + npm run dev 자동 기동 + OpenAPI 동기화
126
+ - **Date**: 2026-04-22
127
+ - **Severity**: HIGH
128
+ - **Occurrences**: 1
129
+ - **Symptom**: 실제 DB 연결 시도 → 연결 실패로 스프린트 중단
130
+ - **Rule**: `npm run dev` 는 MockServer 를 concurrent 로 기동한다.
131
+ API 호출 전 `http://localhost:3001/health` 를 확인할 것.
132
+ - **Applies to**: generator-backend
133
+ ```
134
+
135
+ #### 5b. Convention — "이렇게 해줘"
136
+
137
+ 긍정 가이드는 하우스 스타일로 등록됩니다:
138
+
139
+ ```
140
+ API 응답 필드는 전부 snake_case 로 해야 해. FE TS 모델이
141
+ snake_case 로 정의돼 있어서 변환 레이어를 두기 싫어.
142
+ ```
143
+
144
+ Dispatcher 자동 분류:
145
+ - **스코프**: `generator-backend` (API 응답 → BE 스코프)
146
+ - **저장 위치**: `.harness/conventions/generator-backend.md`
147
+ - **ID 할당**: `[C-001]` (해당 파일의 기존 최댓값 + 1)
148
+
149
+ 기록 포맷 (자동 작성):
150
+
151
+ ```markdown
152
+ ### [C-001] API 응답 필드는 snake_case
153
+ - **Date**: 2026-04-22
154
+ - **Scope**: generator-backend
155
+ - **Rule**: 모든 API 응답 JSON 필드는 snake_case (created_at, user_id 등).
156
+ - **Rationale**: FE TS 모델이 snake_case 로 정의돼 있어 변환 레이어 불필요.
157
+ - **Applies to**: generator-backend, libs/shared-dto
158
+ - **Added from**: user prompt (2026-04-22 16:12)
159
+ ```
160
+
161
+ #### 스코프 판별 (Convention)
162
+
163
+ | 키워드 | 스코프 (파일) |
164
+ |--------|-------------|
165
+ | backend, API, controller, service, DTO, NestJS | `generator-backend.md` |
166
+ | frontend, React, Next.js, UI, component, hook | `generator-frontend.md` |
167
+ | plan, sprint, feature-list | `planner.md` |
168
+ | Playwright, E2E, browser | `evaluator-functional.md` |
169
+ | layout, screenshot, a11y, responsive | `evaluator-visual.md` |
170
+ | code quality, lint, architecture | `evaluator-code-quality.md` |
171
+ | 매칭 실패 + 에이전트 국한 | `shared.md` |
172
+ | 프로젝트 철학 (예: "우리는 TDD") | 루트 `CONVENTIONS.md` 권고 |
173
+
174
+ #### 에이전트 와이어링
175
+
176
+ 각 에이전트는 세션 시작 시 다음 순서로 읽고 적용:
177
+
178
+ ```
179
+ 1. CONVENTIONS.md (루트, 최상위 원칙)
180
+ 2. .harness/conventions/shared.md (공통)
181
+ 3. .harness/conventions/<self>.md (자기 스코프)
182
+ 4. .harness/gotchas/<self>.md (과거 실수)
183
+ 5. .harness/memory.md (공유 교훈)
184
+ ```
185
+
186
+ 충돌 시 우선순위: `<self>` > `shared` > 루트.
187
+
188
+ #### 5c. Memory — 프로젝트 전체 규칙
189
+
190
+ 한 에이전트 실수가 아니라 **모든 에이전트에 적용할 구조적 교훈** 이면 `.harness/memory.md` 로 승격:
191
+
192
+ ```
193
+ 이건 특정 Generator 실수가 아니라 이 프로젝트 공통 규칙이야 —
194
+ 모든 테스트는 MockServer seed data 기반이어야 한다는 걸
195
+ 메모리에 올려줘.
196
+ ```
197
+
198
+ → Dispatcher 가 `memory.md` 에 `### [M-NNN] ...` 로 기록. Planner 리뷰 후 `unverified → verified` 로 승격.
199
+
200
+ #### 주의 — 데이터 보존
201
+
202
+ `npm install` postinstall 은 **누적 엔트리(`[G-NNN]` 또는 `[C-NNN]`)가 있는 파일을 절대 덮어쓰지 않습니다**. 스캐폴드 템플릿인 경우에만 갱신됩니다. v5.5.2 이전 버전은 gotchas 에 이 버그가 있었으므로 `5.6.0+` 사용을 권장합니다.
203
+
204
+ #### 기존 프로젝트 마이그레이션 (첫 설치 시 자동)
205
+
206
+ 기존 `CLAUDE.md` / `AGENTS.md` 에 Convention/Gotcha 성격의 섹션(`Conventions`, `Coding Standards`, `Best Practices`, `Gotchas`, `Don't`, `주의사항`, `금지사항` 등)이 있다면 첫 설치 시 자동으로 추출되어:
207
+
208
+ - **Convention 성격** → `.harness/conventions/<scope>.md` 에 `[C-NNN]` 으로 이관
209
+ - **Gotcha 성격** → `.harness/gotchas/<agent>.md` 에 `[G-NNN]` 으로 이관
210
+ - **원본** → `.harness/archive/pre-harness-*.md.bak` 에 백업
211
+ - **리포트** → `.harness/MIGRATION_REPORT.md` 에 이관 내역 + 수동 확인 요청 사항 기록
212
+
213
+ 마이그레이션은 heuristic(키워드 기반)이므로 리포트를 확인해 스코프 재배정이 필요한지 검토하세요. 이미 하네스 서명(`[BE]`/`[FE]`/`[HARNESS]`)이 있는 문서는 skip 됩니다.
214
+
215
+ ---
216
+
217
+ ## Detail Architecture
218
+
219
+ 여기부터는 어떻게 구성되어 있는지, 왜 그렇게 설계했는지에 대한 상세 문서입니다.
220
+
12
221
  ## 두 가지 모드
13
222
 
14
223
  | 모드 | 설명 | 실행 방법 |
@@ -31,7 +240,7 @@ npm install @walwal-harness/cli
31
240
 
32
241
  `postinstall`이 자동으로:
33
242
  1. `.harness/` 디렉토리 스캐폴딩
34
- 2. `.claude/skills/` 에 에이전트 스킬 설치 (7개)
243
+ 2. `.claude/skills/` 에 에이전트 스킬 설치 (8개)
35
244
  3. `.claude/commands/` 에 모드 제어 커맨드 설치 (3개)
36
245
  4. `scripts/` 에 오케스트레이션 스크립트 설치
37
246
  5. SessionStart / UserPromptSubmit 훅 등록
@@ -45,8 +254,7 @@ npm install @walwal-harness/cli
45
254
  npm update @walwal-harness/cli
46
255
  ```
47
256
 
48
- npm update 시 모든 시스템 파일(scripts, skills, commands)이 **자동으로 교체**됩니다.
49
- 사용자 데이터(progress.json, progress.log, gotchas 커스텀 항목, archive)는 보존됩니다.
257
+ npm update 시 모든 시스템 파일(scripts, skills, commands, config 템플릿)이 **자동으로 교체**됩니다. 사용자 데이터(progress.json, progress.log, **gotchas 누적 엔트리**, memory.md, archive)는 보존됩니다.
50
258
 
51
259
  ### CLI 명령어
52
260
 
@@ -60,40 +268,67 @@ npx walwal-harness --help # 도움말
60
268
 
61
269
  ---
62
270
 
63
- ## Quick Start — Solo Mode
271
+ ## 에이전트 구성
64
272
 
65
- ```bash
66
- # 1. 설치
67
- npm install @walwal-harness/cli
273
+ | 에이전트 | 역할 | 모델 |
274
+ |----------|------|------|
275
+ | **Dispatcher** | 요청 분석 → 파이프라인 결정 · gotcha 관리 | opus |
276
+ | **Brainstormer** | 러프한 요구사항 → 구조화된 spec | opus |
277
+ | **Planner** | 제품 사양 + API 계약서 + 서비스 분할 | opus |
278
+ | **Generator-Backend** | NestJS MSA 서비스 구현 | sonnet |
279
+ | **Generator-Frontend** | React/Next.js UI 구현 | sonnet |
280
+ | **Evaluator-Code-Quality** | 코드 유지보수성/아키텍처/Best Practice (BE/FE/libs 공통, 브라우저 없음) | opus |
281
+ | **Evaluator-Functional** | Playwright E2E 기능 검증 · API 계약 준수 | opus |
282
+ | **Evaluator-Visual** | 레이아웃/접근성/AI슬롭 검증 | opus |
68
283
 
69
- # 2. Claude Code 재시작
70
- claude # (또는 codex)
284
+ ### Evaluator Chain (v5.5+)
71
285
 
72
- # 3. 하네스 시작
73
- > 하네스 엔지니어링 시작
286
+ Generator 이후는 **3-Evaluator 직렬 체인 + 조기 종료** 로 동작:
74
287
 
75
- # 4. Dispatcher → Planner 순서로 자동 진행
76
- # 5. Generator, Evaluator를 프롬프트로 순차 호출
77
288
  ```
289
+ Generator
290
+ → Evaluator-Code-Quality (정적 · 저비용 · 브라우저 없음)
291
+ → Evaluator-Functional (동작 · 중비용 · Playwright/curl)
292
+ → Evaluator-Visual (렌더 · 고비용 · 스크린샷)
293
+ → Archive
294
+ ```
295
+
296
+ 앞단 FAIL 시 뒤 평가자는 실행하지 않고 바로 Generator 재작업으로 리라우팅. BE-ONLY 파이프라인에서는 Visual 이 체인에서 제외됩니다.
297
+
298
+ | 단계 | 채점 축 | Weight | 도구 |
299
+ |------|---------|--------|------|
300
+ | Code-Quality | C1 Layer · C2 Readability · C3 DRY · C4 Type/Error · C5 Test | 25/15/20/25/15 | Read/Grep + tsc/eslint |
301
+ | Functional | R1 Contract · R2 AC · R3 Negative · R4 E2E · R5 Error | 25/25/20/15/15 | Playwright 또는 curl |
302
+ | Visual | V1 Layout · V2 Responsive · V3 A11y · V4 Consistency · V5 Interaction | 20×5 | Playwright 스크린샷 |
303
+
304
+ ### Evaluation 기준
305
+ - PASS: Weighted Score ≥ 2.80 / 3.00
306
+ - AC 100% 충족 필수 (부분 통과 = FAIL)
307
+ - Regression 실패 1건+ = FAIL (이전 Sprint PASS 기능 재검증)
308
+ - Evidence 없는 Score = 0점 강제 재계산
309
+ - Cross-Validation 불일치 1건+ = CONDITIONAL FAIL
310
+ - Team Mode: 최대 5회 재시도 후 사용자 개입 요청
311
+
312
+ ---
78
313
 
79
- ### Solo 파이프라인
314
+ ## 솔로 파이프라인 상세
80
315
 
81
316
  ```
82
317
  사용자 요청 → Dispatcher → (Brainstormer) → Planner
83
318
  → Generator-Backend → Generator-Frontend
84
- → Evaluator-Functional → Evaluator-Visual
319
+ → Evaluator-Code-Quality → Evaluator-Functional → Evaluator-Visual
85
320
  → PASS: 다음 Sprint | FAIL: Generator로 재시도 (최대 5회)
86
321
  ```
87
322
 
88
- ---
323
+ 각 에이전트는 **독립 Claude Code 세션** 에서 실행됩니다. Session Boundary Protocol 이 On Start / On Complete / On Fail 훅으로 progress.json 을 갱신하고 STOP. 다음 세션을 열면 SessionStart 훅이 자동으로 다음 에이전트를 안내합니다.
89
324
 
90
- ## Quick Start — Team Mode
325
+ ## 팀 파이프라인 상세
91
326
 
92
327
  ```bash
93
- # Planner 완료 후:
328
+ # Planner 완료 후
94
329
  > /harness-team
95
330
 
96
- # 자동으로:
331
+ # 자동 실행 흐름:
97
332
  # 1. feature-queue.json 초기화 (의존성 topological sort)
98
333
  # 2. tmux Studio 레이아웃 구축
99
334
  # 3. 3개 팀이 병렬로 Gen→Eval 루프 자동 실행
@@ -101,23 +336,7 @@ claude # (또는 codex)
101
336
  # 5. 5회 초과 실패 시 사용자 개입 요청
102
337
  ```
103
338
 
104
- ### Team 모드 레이아웃
105
-
106
- ```
107
- ┌──────────────┬──────────────┬──────────────┐
108
- │ Prompt │ Dashboard │ TEAM 1 │
109
- │ History │ (queue + │ Gen | Eval │
110
- │ │ status) ├──────────────┤
111
- ├──────────────┤ │ TEAM 2 │
112
- │ Controller │ │ Gen | Eval │
113
- │ (Claude / │ ├──────────────┤
114
- │ Codex) │ │ TEAM 3 │
115
- └──────────────┴──────────────┴──────────────┘
116
- ```
117
-
118
- ---
119
-
120
- ## 모드 전환
339
+ ### 모드 전환
121
340
 
122
341
  | 명령 | 설명 |
123
342
  |------|------|
@@ -133,27 +352,6 @@ Team 실행 중 → /harness-stop → /harness-solo → 프롬프트로 계속
133
352
 
134
353
  ---
135
354
 
136
- ## 에이전트 구성
137
-
138
- | 에이전트 | 역할 | 모델 |
139
- |----------|------|------|
140
- | **Dispatcher** | 요청 분석 → 파이프라인 결정 | opus |
141
- | **Brainstormer** | 러프한 요구사항 → 구조화된 spec | opus |
142
- | **Planner** | 제품 사양 + API 계약서 + 서비스 분할 | opus |
143
- | **Generator-Backend** | NestJS MSA 서비스 구현 | sonnet |
144
- | **Generator-Frontend** | React/Next.js UI 구현 | sonnet |
145
- | **Evaluator-Functional** | Playwright E2E 기능 검증 | opus |
146
- | **Evaluator-Visual** | 디자인/접근성/AI슬롭 검증 | opus |
147
-
148
- ### Evaluation 기준
149
- - PASS: Weighted Score ≥ 2.80/3.00
150
- - AC 100% 충족 필수 (부분 통과 = FAIL)
151
- - Regression 실패 1건+ = FAIL
152
- - Evidence 없는 Score = 0점
153
- - Team Mode: 최대 5회 재시도 후 사용자 개입 요청
154
-
155
- ---
156
-
157
355
  ## 디렉토리 구조
158
356
 
159
357
  ```
@@ -162,21 +360,43 @@ your-project/
162
360
  │ ├── config.json # 하네스 설정
163
361
  │ ├── progress.json # 런타임 상태 (mode, sprint, agent)
164
362
  │ ├── progress.log # 실시간 이벤트 로그
363
+ │ ├── memory.md # 공유 학습 기록 (모든 에이전트 공통)
165
364
  │ ├── HARNESS.md # 하네스 상세 가이드
166
365
  │ ├── actions/ # 활성 스프린트 문서
167
- │ │ ├── feature-list.json # Feature 목록 + AC
168
- │ │ ├── api-contract.json # API 계약서
366
+ │ │ ├── pipeline.json # Dispatcher 결정 (evaluator_chain 포함)
367
+ │ │ ├── plan.md
368
+ │ │ ├── feature-list.json # Feature 목록 + Executable AC
369
+ │ │ ├── api-contract.json
169
370
  │ │ ├── feature-queue.json # Feature Queue 상태 (Team Mode)
170
- │ │ └── ...
171
- │ ├── archive/ # 완료 스프린트 보관 (불변)
172
- │ └── gotchas/ # 에이전트 실수 기록
371
+ │ │ ├── sprint-contract.md
372
+ │ │ ├── evaluation-code-quality.md
373
+ │ │ ├── evaluation-functional.md
374
+ │ │ └── evaluation-visual.md
375
+ │ ├── archive/ # 완료 스프린트 보관 (불변, 마이그레이션 백업도 여기)
376
+ │ ├── gotchas/ # 에이전트 실수 기록 [G-NNN] (누적 보존)
377
+ │ │ ├── planner.md
378
+ │ │ ├── generator-backend.md
379
+ │ │ ├── generator-frontend.md
380
+ │ │ ├── evaluator-code-quality.md
381
+ │ │ ├── evaluator-functional.md
382
+ │ │ └── evaluator-visual.md
383
+ │ ├── conventions/ # 하우스 스타일 [C-NNN] (v5.6+, 누적 보존)
384
+ │ │ ├── shared.md
385
+ │ │ ├── planner.md
386
+ │ │ ├── generator-backend.md
387
+ │ │ ├── generator-frontend.md
388
+ │ │ ├── evaluator-code-quality.md
389
+ │ │ ├── evaluator-functional.md
390
+ │ │ └── evaluator-visual.md
391
+ │ └── MIGRATION_REPORT.md # 첫 설치 시 기존 문서 이관 내역 (있을 때만)
173
392
  ├── .claude/
174
- │ ├── skills/harness-*/ # 에이전트 스킬 (7개)
393
+ │ ├── skills/harness-*/ # 에이전트 스킬 (8개)
175
394
  │ ├── commands/harness-*.md # 모드 제어 커맨드 (3개)
176
395
  │ └── settings.json # 훅, statusline
177
396
  ├── scripts/
178
397
  │ ├── harness-tmux.sh # 통합 tmux 레이아웃 (Solo/Team)
179
398
  │ ├── harness-dashboard.sh # 통합 대시보드
399
+ │ ├── harness-gotcha-memory.sh # Gotcha & Memory 패널
180
400
  │ ├── harness-monitor.sh # 에이전트 모니터
181
401
  │ ├── harness-queue-manager.sh # Feature Queue 관리
182
402
  │ ├── harness-next.sh # 에이전트 전환 라우터
@@ -186,7 +406,8 @@ your-project/
186
406
  │ ├── harness-prompt-history.sh # 프롬프트 히스토리
187
407
  │ └── lib/ # 공유 라이브러리
188
408
  ├── AGENTS.md # 프로젝트 컨텍스트 (IA-MAP)
189
- └── CLAUDE.md → AGENTS.md # 심볼릭 링크
409
+ ├── CLAUDE.md → AGENTS.md # 심볼릭 링크
410
+ └── CONVENTIONS.md # 최상위 원칙 (사용자 자유 기술, 하위는 .harness/conventions/)
190
411
  ```
191
412
 
192
413
  ---
@@ -218,6 +439,14 @@ cat .harness/progress.json | jq '{mode, sprint, current_agent, next_agent}'
218
439
  jq '.mode = "solo"' .harness/progress.json > /tmp/p.json && mv /tmp/p.json .harness/progress.json
219
440
  ```
220
441
 
442
+ ### 대시보드에 feature title 이 "?" 로 표시
443
+ - v5.5.1 에서 해결 (feature 의 `name`/`title`/`description` 순으로 fallback).
444
+ - 그 이전 버전이면 `npm i @walwal-harness/cli@latest` 로 업데이트.
445
+
446
+ ### Gotcha 가 누적되지 않고 사라짐
447
+ - v5.5.2 에서 해결 (postinstall 이 누적 엔트리를 절대 덮어쓰지 않도록 수정).
448
+ - 반드시 `5.5.2+` 사용.
449
+
221
450
  ---
222
451
 
223
452
  ## License
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "harness": {
3
3
  "name": "7-Agent Production Harness",
4
- "version": "5.5.0",
5
- "description": "Solo/Team 통합 하네스 — Dispatcher + 3-Evaluator Chain (Code-Quality → Functional → Visual) + NestJS MSA + React/Next.js + Playwright",
4
+ "version": "5.6.0",
5
+ "description": "Solo/Team 통합 하네스 — Dispatcher + 3-Evaluator Chain (Code-Quality → Functional → Visual) + Hierarchical Conventions/Gotchas + NestJS MSA + React/Next.js + Playwright",
6
6
  "source": "https://www.anthropic.com/engineering/harness-design-long-running-apps"
7
7
  },
8
8
  "agents": {
@@ -368,11 +368,17 @@
368
368
  "statuses": ["start", "complete", "fail", "pass", "skip", "warn"]
369
369
  },
370
370
  "conventions": {
371
- "comment": "CONVENTIONS.md — 사용자가 자유 형식으로 작성하는 프로젝트 컨벤션. 모든 에이전트가 세션 시작 시 직접 읽음. Gotcha/AGENTS.md에 복사하지 않음.",
372
- "file": "CONVENTIONS.md",
371
+ "comment": "House-style registry. 루트 CONVENTIONS.md(사용자 자유 기술) + .harness/conventions/<scope>.md(Dispatcher 자동 누적). 모든 에이전트가 세션 시작 시 읽고 적용한다. Gotcha 의 긍정 대칭판.",
372
+ "root_file": "CONVENTIONS.md",
373
+ "scoped_dir": ".harness/conventions/",
374
+ "scopes": ["shared", "planner", "generator-backend", "generator-frontend", "evaluator-code-quality", "evaluator-functional", "evaluator-visual"],
375
+ "entry_id_prefix": "C",
373
376
  "read_by": "all_agents",
374
- "write_by": "user_only",
375
- "read_timing": "session_start"
377
+ "read_order": ["CONVENTIONS.md", ".harness/conventions/shared.md", ".harness/conventions/<self>.md", ".harness/gotchas/<self>.md", ".harness/memory.md"],
378
+ "conflict_priority": "self > shared > root",
379
+ "write_by": "dispatcher (auto-append C-NNN) or user_only (manual edit)",
380
+ "read_timing": "session_start",
381
+ "preserve_on_postinstall": true
376
382
  },
377
383
  "recommended_skills": {
378
384
  "comment": "Claude Code에 설치하면 하네스 품질이 향상되는 외부 스킬 목록",
package/bin/init.js CHANGED
@@ -90,16 +90,162 @@ function log(msg) {
90
90
  console.log(`[walwal-harness] ${msg}`);
91
91
  }
92
92
 
93
+ // ─────────────────────────────────────────
94
+ // First-install migration — extract Convention/Gotcha-shaped sections from
95
+ // existing CLAUDE.md / AGENTS.md into .harness/conventions and .harness/gotchas.
96
+ // Conservative: only triggers when these docs are NOT already harness-scaffolded
97
+ // (detected by IA-MAP tags like "[BE]" or "[HARNESS]").
98
+ // ─────────────────────────────────────────
99
+ function migrateExistingDocs() {
100
+ // Match heading titles. Use (?=\s|$) instead of \b — Korean chars are
101
+ // not "word" in JS regex, so \b produces inconsistent matches.
102
+ const CONVENTION_HEADINGS = /^#{1,4}\s+(Conventions?|Coding Standards?|Style Guide|Rules|Guidelines|Best Practices|Do's and Don'ts|규칙|하우스 스타일|명명 규칙|코딩 규칙|코드 스타일)(?=[\s:]|$)/im;
103
+ const GOTCHA_HEADINGS = /^#{1,4}\s+(Gotchas?|Anti[- ]?patterns?|Don'?ts?|Avoid|Pitfalls?|주의사항|금지사항|실수|함정|안티[- ]?패턴)(?=[\s:]|$)/im;
104
+ const HARNESS_SIGNATURE = /\[(BE|FE|HARNESS|META|INFRA|ROOT)\]|walwal-harness|harness-dispatcher/;
105
+
106
+ const candidates = [
107
+ path.join(PROJECT_ROOT, 'CLAUDE.md'),
108
+ path.join(PROJECT_ROOT, 'AGENTS.md')
109
+ ];
110
+
111
+ const report = [];
112
+ const extractedConv = { counter: 0, byScope: {} };
113
+ const extractedGotcha = { counter: 0, byAgent: {} };
114
+
115
+ const scopeFor = (body) => {
116
+ const b = body.toLowerCase();
117
+ if (/\b(backend|api|nestjs|controller|dto|service|msa|repository)\b/.test(b)) return 'generator-backend';
118
+ if (/\b(frontend|react|next\.?js|ui|component|tsx|tailwind|hook)\b/.test(b)) return 'generator-frontend';
119
+ if (/\b(planner|plan\.md|sprint|feature-list|api-contract)\b/.test(b)) return 'planner';
120
+ if (/\b(playwright|e2e|functional test)\b/.test(b)) return 'evaluator-functional';
121
+ if (/\b(visual|layout|screenshot|a11y|accessibility|responsive)\b/.test(b)) return 'evaluator-visual';
122
+ if (/\b(code quality|lint|tsc|architecture|typescript strict)\b/.test(b)) return 'evaluator-code-quality';
123
+ return 'shared';
124
+ };
125
+
126
+ const appendEntry = (filePath, id, kind, title, body, source) => {
127
+ const existing = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : '';
128
+ const entry = [
129
+ ``,
130
+ `### [${id}] ${title}`,
131
+ `- **Date**: ${new Date().toISOString().split('T')[0]}`,
132
+ `- **Source**: ${source} (migrated)`,
133
+ ``,
134
+ body.trim(),
135
+ ``
136
+ ].join('\n');
137
+ fs.writeFileSync(filePath, existing.replace(/\s*$/, '') + '\n' + entry + '\n');
138
+ };
139
+
140
+ for (const docPath of candidates) {
141
+ if (!fileExists(docPath)) continue;
142
+ const content = fs.readFileSync(docPath, 'utf8');
143
+ if (HARNESS_SIGNATURE.test(content)) {
144
+ // Already a harness-managed doc — skip
145
+ continue;
146
+ }
147
+
148
+ // Backup
149
+ const backupPath = path.join(HARNESS_DIR, 'archive', `pre-harness-${path.basename(docPath)}.bak`);
150
+ fs.writeFileSync(backupPath, content);
151
+ report.push(`Backed up: ${docPath} → ${backupPath}`);
152
+
153
+ // Split by top-level and H2 headings to get sections
154
+ // Simple approach: find heading lines, slice until next heading of same-or-higher level
155
+ const lines = content.split('\n');
156
+ const sections = [];
157
+ let current = null;
158
+ lines.forEach((line, idx) => {
159
+ const m = /^(#{1,4})\s+(.+?)\s*$/.exec(line);
160
+ if (m) {
161
+ if (current) sections.push(current);
162
+ current = { level: m[1].length, title: m[2], startLine: idx + 1, endLine: idx + 1, body: [] };
163
+ } else if (current) {
164
+ current.body.push(line);
165
+ current.endLine = idx + 1;
166
+ }
167
+ });
168
+ if (current) sections.push(current);
169
+
170
+ for (const sec of sections) {
171
+ const header = `${'#'.repeat(sec.level)} ${sec.title}`;
172
+ const isConv = CONVENTION_HEADINGS.test(header);
173
+ const isGotcha = GOTCHA_HEADINGS.test(header);
174
+ if (!isConv && !isGotcha) continue;
175
+ const body = sec.body.join('\n').trim();
176
+ if (!body) continue;
177
+
178
+ const sourceRef = `${path.basename(docPath)}:${sec.startLine}-${sec.endLine}`;
179
+
180
+ if (isConv) {
181
+ const scope = scopeFor(sec.title + '\n' + body);
182
+ extractedConv.counter += 1;
183
+ const id = `C-${String(extractedConv.counter).padStart(3, '0')}`;
184
+ const target = path.join(HARNESS_DIR, 'conventions', `${scope}.md`);
185
+ appendEntry(target, id, 'convention', sec.title, body, sourceRef);
186
+ extractedConv.byScope[scope] = (extractedConv.byScope[scope] || 0) + 1;
187
+ report.push(`[${id}] "${sec.title}" → conventions/${scope}.md (from ${sourceRef})`);
188
+ } else {
189
+ const scope = scopeFor(sec.title + '\n' + body);
190
+ const agent = scope === 'shared' ? 'planner' : scope; // default shared-gotchas to planner
191
+ extractedGotcha.counter += 1;
192
+ const id = `G-${String(extractedGotcha.counter).padStart(3, '0')}`;
193
+ const target = path.join(HARNESS_DIR, 'gotchas', `${agent}.md`);
194
+ appendEntry(target, id, 'gotcha', sec.title, body, sourceRef);
195
+ extractedGotcha.byAgent[agent] = (extractedGotcha.byAgent[agent] || 0) + 1;
196
+ report.push(`[${id}] "${sec.title}" → gotchas/${agent}.md (from ${sourceRef})`);
197
+ }
198
+ }
199
+ }
200
+
201
+ if (report.length === 0) return;
202
+
203
+ const reportPath = path.join(HARNESS_DIR, 'MIGRATION_REPORT.md');
204
+ const reportContent = [
205
+ `# Walwal-Harness Migration Report`,
206
+ ``,
207
+ `Generated on first install at ${new Date().toISOString()}.`,
208
+ ``,
209
+ `## Summary`,
210
+ ``,
211
+ `- Conventions extracted: ${extractedConv.counter}`,
212
+ `- Gotchas extracted: ${extractedGotcha.counter}`,
213
+ ``,
214
+ `## Manual Review Required`,
215
+ ``,
216
+ `Migration is heuristic (keyword-based). Please review each extracted entry:`,
217
+ `- Verify scope assignment is correct`,
218
+ `- Split entries into smaller atomic rules if appropriate`,
219
+ `- Adjust wording to positive-rule form for conventions, negative/anti-pattern form for gotchas`,
220
+ ``,
221
+ `## Entries`,
222
+ ``,
223
+ ...report.map(r => `- ${r}`),
224
+ ``,
225
+ `## Backups`,
226
+ ``,
227
+ `Original documents were preserved in \`.harness/archive/pre-harness-*.md.bak\`.`,
228
+ ``
229
+ ].join('\n');
230
+ fs.writeFileSync(reportPath, reportContent);
231
+ log(`Migration: ${extractedConv.counter} convention(s), ${extractedGotcha.counter} gotcha(s) extracted.`);
232
+ log(`Migration report: ${reportPath}`);
233
+ }
234
+
93
235
  // ─────────────────────────────────────────
94
236
  // 1. .harness/ scaffolding
95
237
  // ─────────────────────────────────────────
96
238
  function scaffoldHarness() {
97
239
  log('Scaffolding .harness/ directory...');
98
240
 
241
+ // Detect first install BEFORE ensureDir creates the root
242
+ const isFirstInstall = !fs.existsSync(HARNESS_DIR);
243
+
99
244
  // Core directories
100
245
  ensureDir(path.join(HARNESS_DIR, 'actions'));
101
246
  ensureDir(path.join(HARNESS_DIR, 'archive'));
102
247
  ensureDir(path.join(HARNESS_DIR, 'gotchas'));
248
+ ensureDir(path.join(HARNESS_DIR, 'conventions'));
103
249
 
104
250
  // Copy gotchas — preserve any existing file that has accumulated entries.
105
251
  // Dispatcher appends `### [G-NNN] ...` entries directly; we must NEVER overwrite
@@ -136,6 +282,39 @@ function scaffoldHarness() {
136
282
  }
137
283
  }
138
284
 
285
+ // Copy conventions — mirror gotchas preservation: never overwrite files with
286
+ // accumulated `### [C-NNN]` entries.
287
+ const conventionsSrc = path.join(PKG_ROOT, 'conventions');
288
+ if (fs.existsSync(conventionsSrc)) {
289
+ const CONV_ENTRY = /^### \[C-\d+\]/m;
290
+ const files = fs.readdirSync(conventionsSrc);
291
+ for (const file of files) {
292
+ const destPath = path.join(HARNESS_DIR, 'conventions', file);
293
+ const srcPath = path.join(conventionsSrc, file);
294
+ if (!fileExists(destPath)) {
295
+ copyFile(srcPath, destPath);
296
+ continue;
297
+ }
298
+ if (!file.endsWith('.md')) continue;
299
+ const existing = fs.readFileSync(destPath, 'utf8');
300
+ if (CONV_ENTRY.test(existing)) {
301
+ if (file === 'README.md') copyFile(srcPath, destPath);
302
+ continue;
303
+ }
304
+ copyFile(srcPath, destPath);
305
+ }
306
+ }
307
+
308
+ // First-install migration: extract Convention/Gotcha-shaped sections from
309
+ // existing CLAUDE.md / AGENTS.md and copy into the hierarchical stores.
310
+ if (isFirstInstall) {
311
+ try {
312
+ migrateExistingDocs();
313
+ } catch (e) {
314
+ log('WARNING: migration failed — ' + e.message);
315
+ }
316
+ }
317
+
139
318
  // Copy templates as initial files
140
319
  const templateMap = {
141
320
  'progress.json.template': path.join(HARNESS_DIR, 'progress.json'),
@@ -232,12 +411,12 @@ function scaffoldHarness() {
232
411
  copyFile(memorySrc, memoryDest);
233
412
  }
234
413
 
235
- // Copy CONVENTIONS.md to project root
236
- const conventionsSrc = path.join(PKG_ROOT, 'assets', 'templates', 'CONVENTIONS.md');
237
- const conventionsDest = path.join(PROJECT_ROOT, 'CONVENTIONS.md');
238
- if (fs.existsSync(conventionsSrc) && (!fileExists(conventionsDest) || isForce)) {
239
- copyFile(conventionsSrc, conventionsDest);
240
- log('CONVENTIONS.md created — edit to define your project conventions');
414
+ // Copy CONVENTIONS.md to project root (legacy — root still supported)
415
+ const rootConvSrc = path.join(PKG_ROOT, 'assets', 'templates', 'CONVENTIONS.md');
416
+ const rootConvDest = path.join(PROJECT_ROOT, 'CONVENTIONS.md');
417
+ if (fs.existsSync(rootConvSrc) && (!fileExists(rootConvDest) || isForce)) {
418
+ copyFile(rootConvSrc, rootConvDest);
419
+ log('CONVENTIONS.md created — edit to define top-level project conventions');
241
420
  }
242
421
 
243
422
  // Create progress.log
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "5.5.2",
3
+ "version": "5.6.0",
4
4
  "description": "Production harness for AI agent engineering — Solo/Team mode, Planner, Generator(BE/FE), Evaluator chain (Code-Quality → Functional → Visual), optional Brainstormer. Supports React, Next.js, and Flutter FE stacks.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"
@@ -46,19 +46,25 @@ Claude 는 기본적으로 Dispatcher 경유로 분류/라우팅해야 한다.
46
46
 
47
47
  사용자 입력을 먼저 분류합니다:
48
48
 
49
- - **실수 지적** ("아니", "잘못", "그렇게 하면 안 돼", "X로 해야지") → **Gotcha Flow**
49
+ - **실수 지적 (부정)** ("아니", "잘못", "그렇게 하면 안 돼", "~하지 마") → **Gotcha Flow**
50
+ - **긍정 규범** ("~해야 해", "~이렇게 해줘", "항상 ~", "우리는 ~ 방식") → **Convention Flow**
50
51
  - **기능 요청** ("만들어", "추가", "시작", PRD, OpenAPI) → **Pipeline Flow**
51
- - **혼합** → Gotcha 먼저 기록 → Pipeline 이어서
52
+ - **혼합** → Gotcha/Convention 먼저 기록 → Pipeline 이어서
52
53
  - **메타/인사/Claude 자체 질문** → Dispatcher skip, 짧은 일반 응답 허용
53
54
 
54
- ## 2. Gotcha Flow vs Memory Flow
55
+ **부정 vs 긍정 구분법**: "X 하지 마 / X 가 틀렸어 / 그렇게 하면 안 돼" 는 **Gotcha**. "X 를 해야 해 / X 로 해줘 / 항상 X" 는 **Convention**. 동일 주제도 시그널에 따라 저장 위치가 달라집니다.
55
56
 
56
- 사용자의 교정/피드백을 받으면 **먼저 분류**:
57
+ ## 2. Feedback Taxonomy — Gotcha / Convention / Memory
57
58
 
58
- | 유형 | 저장 위치 | 예시 |
59
- |------|----------|------|
60
- | **에이전트별 실수** (일회성 교정) | `.harness/gotchas/[agent].md` | "API 응답에 created_at은 ISO 8601로" |
61
- | **프로젝트 공유 규칙** (구조적/반복적) | `.harness/memory.md` | "Playwright 스크린샷은 단계 완료 후 항상 삭제" |
59
+ 사용자의 교정/가이드를 받으면 **먼저 분류**:
60
+
61
+ | 유형 | 성격 | 저장 위치 | ID | 예시 |
62
+ |------|------|----------|-----|------|
63
+ | **Gotcha** | 특정 에이전트의 **일회성 실수(사고)** 기록 (negative) | `.harness/gotchas/<agent>.md` | `[G-NNN]` | "Generator-BE 가 MockServer 무시하고 실 DB 붙지 마" |
64
+ | **Convention** | 에이전트/스코프의 **하우스 스타일(norm)** (positive) | `.harness/conventions/<scope>.md` | `[C-NNN]` | "API 응답 필드는 snake_case" |
65
+ | **Memory** | **모든 에이전트** 공통 구조적 교훈 | `.harness/memory.md` | `[M-NNN]` | "Playwright 스크린샷은 단계 완료 후 항상 삭제" |
66
+
67
+ Scope 가 특정 에이전트를 넘어서면 Memory. 특정 에이전트에 해당하면 Gotcha(부정) 혹은 Convention(긍정).
62
68
 
63
69
  ### Gotcha Flow (에이전트별 실수)
64
70
 
@@ -67,7 +73,17 @@ Claude 는 기본적으로 Dispatcher 경유로 분류/라우팅해야 한다.
67
73
  핵심:
68
74
  1. 교정 시그널 감지 (HIGH/MEDIUM만 기록)
69
75
  2. 도메인 분석 → 대상 에이전트 판별
70
- 3. `.harness/gotchas/[agent].md`에 항목 추가 (중복 시 Occurrences 증가)
76
+ 3. `.harness/gotchas/[agent].md`에 `[G-NNN]` 추가 (중복 시 Occurrences 증가)
77
+ 4. 사용자에게 기록 확인
78
+
79
+ ### Convention Flow (에이전트별 하우스 스타일)
80
+
81
+ 긍정 가이드 감지 시 → [Convention 상세 가이드](references/convention-flow.md)
82
+
83
+ 핵심:
84
+ 1. 긍정 시그널 감지 ("해야 해", "이렇게 해줘", "항상" 등)
85
+ 2. 스코프 판별: 특정 에이전트(`generator-backend` 등) / `shared` / 프로젝트 전체(루트 `CONVENTIONS.md`)
86
+ 3. `.harness/conventions/<scope>.md` 에 `[C-NNN]` 추가
71
87
  4. 사용자에게 기록 확인
72
88
 
73
89
  ### Memory Flow (프로젝트 공유 규칙)
@@ -0,0 +1,111 @@
1
+ ---
2
+ docmeta:
3
+ id: convention-flow
4
+ title: Convention Flow — Positive Guide Classifier
5
+ type: output
6
+ createdAt: 2026-04-22T00:00:00Z
7
+ updatedAt: 2026-04-22T00:00:00Z
8
+ source:
9
+ producer: agent
10
+ skillId: harness-dispatcher
11
+ inputs:
12
+ - documentId: harness-dispatcher-skill
13
+ uri: ../SKILL.md
14
+ relation: output-from
15
+ sections:
16
+ - sourceRange:
17
+ startLine: 45
18
+ endLine: 100
19
+ targetRange:
20
+ startLine: 30
21
+ endLine: 140
22
+ tags:
23
+ - dispatcher
24
+ - convention
25
+ - positive-guidance
26
+ ---
27
+
28
+ # Convention Flow — Positive Guide Classifier
29
+
30
+ 긍정 가이드("~해야 해", "항상 ~", "이렇게 해줘")를 감지하면
31
+ 해당 스코프의 `.harness/conventions/<scope>.md` 에 `[C-NNN]` 엔트리로 append.
32
+
33
+ ## 1. 긍정 시그널 감지
34
+
35
+ 다음 패턴 중 하나라도 포함되면 Convention 후보:
36
+
37
+ - 명령형: "해야 해", "~로 해줘", "이렇게 만들어", "~를 사용해"
38
+ - 원칙 선언: "항상 ~", "모든 ~ 는", "우리는 ~ 방식", "표준은 ~"
39
+ - 하우스 스타일: "이 프로젝트에서는 ~", "컨벤션상 ~", "규칙은 ~"
40
+ - 영어: "always", "must", "should", "we use", "prefer", "standard is"
41
+
42
+ **부정 시그널과 충돌 시 부정 우선** (Gotcha 로 라우팅). 예: "~ 하지 말고 ~ 해줘" 는 Gotcha.
43
+
44
+ ## 2. Scope 판별
45
+
46
+ 엔트리의 적용 범위를 다음 순서로 판별:
47
+
48
+ 1. **특정 에이전트 명시** → 해당 에이전트 파일
49
+ - 사용자가 명시적으로 이름 언급 ("Generator-BE 는 ~") 또는 문맥상 확실한 키워드
50
+ 2. **도메인 키워드 매칭** → 대응 에이전트
51
+ | 키워드 | 스코프 |
52
+ |--------|-------|
53
+ | backend, API, controller, service, DTO, NestJS, MSA | `generator-backend` |
54
+ | frontend, React, Next.js, UI, component, hook, Tailwind | `generator-frontend` |
55
+ | plan, sprint, feature-list, api-contract, roadmap | `planner` |
56
+ | Playwright, E2E, browser, functional test | `evaluator-functional` |
57
+ | layout, screenshot, a11y, responsive, viewport, AI slop | `evaluator-visual` |
58
+ | code quality, lint, tsc, architecture, type safety | `evaluator-code-quality` |
59
+ 3. **매칭 실패 + 여전히 에이전트 국한** → `shared.md`
60
+ 4. **프로젝트 전체 철학/원칙** (예: "우리는 TDD 한다", "보안 우선") → 루트 `CONVENTIONS.md` 에 사용자 권고 (Dispatcher 직접 수정 금지)
61
+
62
+ ## 3. 중복 감지
63
+
64
+ 대상 파일에서 기존 `[C-NNN]` 엔트리를 읽어:
65
+ - **완전 중복** (같은 rule) → append 하지 않고 기존 엔트리의 Date 를 갱신
66
+ - **부분 중복** (관련 주제) → 새 엔트리로 추가하되 기존 엔트리 ID 를 `Related:` 필드로 참조
67
+
68
+ ## 4. 엔트리 포맷
69
+
70
+ ```markdown
71
+ ### [C-NNN] 간결한 제목 (긍정형, 70자 이내)
72
+ - **Date**: YYYY-MM-DD
73
+ - **Scope**: <agent> | shared
74
+ - **Rule**: 사용자가 말한 내용을 긍정 규칙으로 정제. 명령형 문장.
75
+ - **Rationale**: 사용자가 설명한 이유 (없으면 "미지정" 표기, 추정 금지)
76
+ - **Applies to**: 적용 대상 상세 (특정 파일 경로, 특정 상황, 엔드포인트 등)
77
+ - **Added from**: 사용자 프롬프트 (YYYY-MM-DD HH:MM) | migration | manual
78
+ - **Related**: C-XXX, C-YYY (선택)
79
+ ```
80
+
81
+ ### ID 할당
82
+
83
+ 대상 파일의 기존 `[C-NNN]` 최댓값 + 1 을 3자리 zero-pad. 예: 기존에 C-001, C-003 이 있으면 다음은 C-004 (비어있는 번호는 재사용하지 않음).
84
+
85
+ ## 5. 루트 CONVENTIONS.md 처리
86
+
87
+ 루트 `CONVENTIONS.md` 는 **사용자가 자유 기술하는 최상위 원칙 파일**. Dispatcher 가 직접 수정하지 않고, 사용자에게 안내:
88
+
89
+ ```
90
+ 이 규칙은 프로젝트 전체 철학에 가까워 보여서 CONVENTIONS.md(루트) 에
91
+ 직접 추가하시는 게 좋겠습니다. 추가 후 모든 에이전트가 세션 시작 시 읽습니다.
92
+ ```
93
+
94
+ ## 6. 사용자 확인 메시지 포맷
95
+
96
+ ```
97
+ Convention 등록 완료:
98
+ - ID: [C-004]
99
+ - Scope: generator-backend
100
+ - Rule: API 응답 필드는 snake_case
101
+ - 저장 위치: .harness/conventions/generator-backend.md
102
+
103
+ Generator-Backend 는 다음 세션 시작 시 이 규칙을 읽고 적용합니다.
104
+ ```
105
+
106
+ ## 7. 금지 사항
107
+
108
+ - Convention 파일의 기존 엔트리 삭제/수정 (사용자만 가능)
109
+ - `CONVENTIONS.md` (루트) 직접 수정
110
+ - 추정성 rationale 작성 (근거 없으면 "미지정")
111
+ - 에이전트 SKILL.md 자체 수정 (구조적 변경은 사용자 권고)
@@ -63,13 +63,14 @@ disable-model-invocation: true
63
63
  ## Startup
64
64
 
65
65
  1. `AGENTS.md` 읽기 — IA-MAP (레이어 경계)
66
- 2. `CONVENTIONS.md` 읽기 — 프로젝트 컨벤션 (있을 때만)
67
- 3. `.harness/gotchas/evaluator-code-quality.md` 읽기 — **과거 실수 반복 금지**
68
- 4. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
69
- 5. `actions/sprint-contract.md` — 이번 스프린트 변경 범위
70
- 6. `actions/feature-list.json` — 기능 정의
71
- 7. `actions/api-contract.json` — DTO 형태 (계약 vs 구현 일치 확인용)
72
- 8. `.harness/progress.json`
66
+ 2. `CONVENTIONS.md` (루트) 읽기 — 프로젝트 최상위 원칙 (있을 때만)
67
+ 3. `.harness/conventions/shared.md` + `.harness/conventions/evaluator-code-quality.md` — **긍정 하우스 스타일 (C-NNN) — PASS 판정의 기준이 된다**
68
+ 4. `.harness/gotchas/evaluator-code-quality.md` 읽기 — **과거 실수 반복 금지**
69
+ 5. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
70
+ 6. `actions/sprint-contract.md` — 이번 스프린트 변경 범위
71
+ 7. `actions/feature-list.json` — 기능 정의
72
+ 8. `actions/api-contract.json` — DTO 형태 (계약 vs 구현 일치 확인용)
73
+ 9. `.harness/progress.json`
73
74
 
74
75
  ## Evaluation Steps
75
76
 
@@ -63,12 +63,14 @@ disable-model-invocation: true
63
63
  ## Startup
64
64
 
65
65
  1. `AGENTS.md` 읽기 — IA-MAP
66
- 2. `.harness/gotchas/evaluator-functional.md` 읽기 — **과거 실수 반복 금지**
67
- 3. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
68
- 4. `actions/sprint-contract.md` — BE + FE 성공 기준 전체
69
- 4. `actions/feature-list.json` — 이번 스프린트 범위
70
- 5. `actions/api-contract.json` — 기대 API 동작
71
- 6. `.harness/progress.json`
66
+ 2. `CONVENTIONS.md` (루트) 읽기 — 프로젝트 최상위 원칙 (있을 때만)
67
+ 3. `.harness/conventions/shared.md` + `.harness/conventions/evaluator-functional.md` — **긍정 하우스 스타일 적용**
68
+ 4. `.harness/gotchas/evaluator-functional.md` 읽기 — **과거 실수 반복 금지**
69
+ 5. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
70
+ 6. `actions/sprint-contract.md` — BE + FE 성공 기준 전체
71
+ 7. `actions/feature-list.json` — 이번 스프린트 범위
72
+ 8. `actions/api-contract.json` — 기대 API 동작
73
+ 9. `.harness/progress.json`
72
74
 
73
75
  ## Feature-Level Mode (Team Mode)
74
76
 
@@ -56,10 +56,12 @@ disable-model-invocation: true
56
56
  ## Startup
57
57
 
58
58
  1. `AGENTS.md` 읽기
59
- 2. `.harness/gotchas/evaluator-visual.md` 읽기 — **과거 실수 반복 금지**
60
- 3. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
61
- 4. `actions/evaluation-functional.md` — Verdict: PASS 확인
62
- 5. **Stack-Adaptive Gate** (v5.2) — `scan-result.json.tech_stack` 으로 스택 확인 후 `.harness/ref/fe-<stack>.md` 의 `validation.visual` 파싱:
59
+ 2. `CONVENTIONS.md` (루트) 읽기 — 프로젝트 최상위 원칙 (있을 때만)
60
+ 3. `.harness/conventions/shared.md` + `.harness/conventions/evaluator-visual.md` — **긍정 하우스 스타일 적용**
61
+ 4. `.harness/gotchas/evaluator-visual.md` 읽기 — **과거 실수 반복 금지**
62
+ 5. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
63
+ 6. `actions/evaluation-functional.md` — Verdict: PASS 확인
64
+ 7. **Stack-Adaptive Gate** (v5.2) — `scan-result.json.tech_stack` 으로 스택 확인 후 `.harness/ref/fe-<stack>.md` 의 `validation.visual` 파싱:
63
65
  - `visual.enabled == false`: 즉시 **MANUAL_REQUIRED 모드** 로 전환 — 아래 "Visual Skip Flow" 수행 후 종료
64
66
  - `visual.enabled == true` (또는 ref-docs 없이 웹 전통 스택): 계속 진행, ref 에 `visual.base_url` 이 있으면 그 URL 로, 없으면 `ref.runner.dev_command` 로 서버 기동 후 Playwright 접속
65
67
 
@@ -27,18 +27,23 @@ disable-model-invocation: true
27
27
  ## Startup (Adaptive Loading)
28
28
 
29
29
  1. `AGENTS.md` 읽기 — IA-MAP, 권한 확인
30
- 2. `.harness/actions/scan-result.json` 읽기 → `tech_stack.backend` 또는 `tech_stack.language` 로 현재 스택 확정 (이하 `<stack>`)
31
- 3. **Ref-docs 로드** — `.harness/ref/be-<stack>.md`
30
+ 2. `CONVENTIONS.md` (루트) 읽기 — 프로젝트 최상위 원칙 (있을 때만)
31
+ 3. **Conventions 로드** — 세 파일 모두 (있는 것만):
32
+ - `.harness/conventions/shared.md` (모든 에이전트 공통)
33
+ - `.harness/conventions/generator-backend.md` (BE 스코프)
34
+ - `.harness/conventions/generator-backend-<stack>.md` (스택별, 선택)
35
+ 4. `.harness/actions/scan-result.json` 읽기 → `tech_stack.backend` 또는 `tech_stack.language` 로 현재 스택 확정 (이하 `<stack>`)
36
+ 5. **Ref-docs 로드** — `.harness/ref/be-<stack>.md`
32
37
  - 파일 없음 → STOP + 안내: `"ref-docs 가 없습니다. bash init.sh init 실행 또는 bash scripts/init-ref-docs.sh --claude-prompt --stack <stack> --role be . 실행하세요."`
33
38
  - frontmatter 파싱 실패 → 경고 출력 + 기본값으로 degrade
34
- 4. **Gotchas 로드** — 두 파일 모두 (있는 것만):
39
+ 6. **Gotchas 로드** — 두 파일 모두 (있는 것만):
35
40
  - `.harness/gotchas/generator-backend.md` (공통)
36
41
  - `.harness/gotchas/generator-backend-<stack>.md` (스택별)
37
- 5. `.harness/memory.md` 읽기 — 프로젝트 공유 학습 규칙
38
- 6. `pwd` + `.harness/progress.json` + `git log --oneline -20`
39
- 7. `.harness/actions/api-contract.json` 읽기 — **이 계약이 유일한 BE 외부 인터페이스**
40
- 8. `.harness/actions/feature-list.json` — 지정된 `FEATURE_ID` 또는 `layer: "backend"` 필터
41
- 9. **DB / 외부 의존성 부트스트랩**:
42
+ 7. `.harness/memory.md` 읽기 — 프로젝트 공유 학습 규칙
43
+ 8. `pwd` + `.harness/progress.json` + `git log --oneline -20`
44
+ 9. `.harness/actions/api-contract.json` 읽기 — **이 계약이 유일한 BE 외부 인터페이스**
45
+ 10. `.harness/actions/feature-list.json` — 지정된 `FEATURE_ID` 또는 `layer: "backend"` 필터
46
+ 11. **DB / 외부 의존성 부트스트랩**:
42
47
  - `ref.runner.install_command` 가 있으면 1회 실행
43
48
  - `ref.runner.dev_command` 를 백그라운드 실행 (있는 경우)
44
49
 
@@ -27,21 +27,26 @@ disable-model-invocation: true
27
27
  ## Startup (Adaptive Loading)
28
28
 
29
29
  1. `AGENTS.md` 읽기 — IA-MAP, 권한 확인
30
- 2. `.harness/actions/scan-result.json` 읽기 → `tech_stack.fe_stack` 또는 `tech_stack.frontend` 로 현재 스택 확정 (이하 `<stack>`)
31
- 3. **Ref-docs 로드** — `.harness/ref/fe-<stack>.md`
30
+ 2. `CONVENTIONS.md` (루트) 읽기 — 프로젝트 최상위 원칙 (있을 때만)
31
+ 3. **Conventions 로드** — 세 파일 모두 (있는 것만):
32
+ - `.harness/conventions/shared.md` (모든 에이전트 공통)
33
+ - `.harness/conventions/generator-frontend.md` (FE 스코프)
34
+ - `.harness/conventions/generator-frontend-<stack>.md` (스택별, 선택)
35
+ 4. `.harness/actions/scan-result.json` 읽기 → `tech_stack.fe_stack` 또는 `tech_stack.frontend` 로 현재 스택 확정 (이하 `<stack>`)
36
+ 5. **Ref-docs 로드** — `.harness/ref/fe-<stack>.md`
32
37
  - 파일 없음 → STOP + 안내: `"ref-docs 가 없습니다. bash init.sh init 실행 또는 bash scripts/init-ref-docs.sh --claude-prompt --stack <stack> --role fe . 실행하세요."`
33
38
  - frontmatter 파싱 실패 → 경고 출력 + 기본값(runner/paths/api 모두 null)으로 degrade
34
- 4. **Gotchas 로드** — 두 파일 모두 (있는 것만):
39
+ 6. **Gotchas 로드** — 두 파일 모두 (있는 것만):
35
40
  - `.harness/gotchas/generator-frontend.md` (공통)
36
41
  - `.harness/gotchas/generator-frontend-<stack>.md` (스택별)
37
- 5. `.harness/memory.md` 읽기 — 프로젝트 공유 학습 규칙
38
- 6. `pwd` + `.harness/progress.json` + `git log --oneline -20`
39
- 7. `.harness/actions/api-contract.json` 읽기
40
- 8. `.harness/actions/feature-list.json` — 지정된 `FEATURE_ID` 또는 `layer: "frontend"` 필터
41
- 9. **개발 서버 기동**:
42
- - `ref.runner.dev_command` 가 `null` 이 아니면 해당 명령 백그라운드 실행
43
- - `null` 이면 "개발 서버 기동은 스택 특성상 생략" 로그만 남김
44
- 10. **API Gateway 체크**:
42
+ 7. `.harness/memory.md` 읽기 — 프로젝트 공유 학습 규칙
43
+ 8. `pwd` + `.harness/progress.json` + `git log --oneline -20`
44
+ 9. `.harness/actions/api-contract.json` 읽기
45
+ 10. `.harness/actions/feature-list.json` — 지정된 `FEATURE_ID` 또는 `layer: "frontend"` 필터
46
+ 11. **개발 서버 기동**:
47
+ - `ref.runner.dev_command` 가 `null` 이 아니면 해당 명령 백그라운드 실행
48
+ - `null` 이면 "개발 서버 기동은 스택 특성상 생략" 로그만 남김
49
+ 12. **API Gateway 체크**:
45
50
  - `ref.api.base_url` 이 `null` 이 아니면 `curl -s <base_url>/health` 로 헬스체크
46
51
  - `null` (네이티브 앱 등) 이면 체크 스킵
47
52
 
@@ -24,18 +24,20 @@ disable-model-invocation: true
24
24
  ## Startup
25
25
 
26
26
  1. `AGENTS.md` 읽기
27
- 2. `.harness/gotchas/planner.md` 읽기 — **과거 실수 반복 금지**
28
- 3. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
29
- 4. `.harness/progress.json` 읽기
30
- 5. `.harness/actions/pipeline.json` 읽기 — `planner_mode`, `fe_stack` 확인
31
- 6. `.harness/actions/scan-result.json` 읽기 — `tech_stack.fe_stack` 확인 (없으면 `react` 기본)
32
- 7. **Brainstorm Spec 우선 로드** — `.harness/actions/brainstorm-spec.md` 가 존재하면
27
+ 2. `CONVENTIONS.md` (루트) 읽기 — 프로젝트 최상위 원칙 (있을 때만)
28
+ 3. `.harness/conventions/shared.md` + `.harness/conventions/planner.md` — **긍정 하우스 스타일 적용 (feature 분할/AC 작성 시)**
29
+ 4. `.harness/gotchas/planner.md` 읽기 — **과거 실수 반복 금지**
30
+ 5. `.harness/memory.md` 읽기 — **프로젝트 공유 학습 규칙 적용**
31
+ 6. `.harness/progress.json` 읽기
32
+ 7. `.harness/actions/pipeline.json` 읽기 — `planner_mode`, `fe_stack` 확인
33
+ 8. `.harness/actions/scan-result.json` 읽기 — `tech_stack.fe_stack` 확인 (없으면 `react` 기본)
34
+ 9. **Brainstorm Spec 우선 로드** — `.harness/actions/brainstorm-spec.md` 가 존재하면
33
35
  **이 파일이 PRD 대체 입력**. Brainstormer 가 이미 사용자와 대화하여 확정한
34
36
  결과이므로 **승인된 결정을 뒤엎지 않는다**. 없으면 사용자의 원본 요청 텍스트를 입력으로 사용.
35
37
  - brainstorm-spec.md 에 `## Open Questions` 섹션이 있으면 Planner 가 해소 (API 계약으로 확정)
36
38
  - brainstorm-spec.md 의 `## 7. 주요 컴포넌트 / 엔티티` → `feature-list.json` 초기 feature 목록 시드
37
39
  - brainstorm-spec.md 의 `## 5. 선택된 접근법` / `## 6. 아키텍처 스케치` → MSA 서비스 분할 베이스
38
- 8. **FE Stack 확정** → [FE Stack 결정 가이드](references/fe-stack-detection.md)
40
+ 10. **FE Stack 확정** → [FE Stack 결정 가이드](references/fe-stack-detection.md)
39
41
  - `pubspec.yaml` + `flutter:` 키 → `fe_stack = "flutter"`
40
42
  - 혼재/불명확 → 사용자에게 단 한 번 질문
41
43
  - 확정 후 `pipeline.json.fe_stack` 갱신 (없으면 생성)