@walwal-harness/cli 7.1.1 → 7.1.3

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.
@@ -0,0 +1,160 @@
1
+ # AGENTS.md — {{PROJECT_NAME}}
2
+ # walwal-harness v7.1 | Company Mode
3
+ # 설치일: {{DATE}} | CLAUDE.md는 이 파일의 심볼릭 링크입니다.
4
+
5
+ ---
6
+
7
+ ## 1. 코딩 전 생각하기
8
+
9
+ **가정하지 않는다. 혼란을 숨기지 않는다. 트레이드오프를 드러낸다.**
10
+
11
+ 구현 전:
12
+ - 가정을 명시적으로 밝힌다. 불확실하면 질문한다.
13
+ - 여러 해석이 가능하면 모두 제시한다 — 조용히 선택하지 않는다.
14
+ - 더 단순한 접근이 있으면 말한다. 필요할 때 반론을 제기한다.
15
+ - 불명확한 것이 있으면 멈춘다. 무엇이 혼란스러운지 명시하고 질문한다.
16
+
17
+ ## 2. 단순함 우선
18
+
19
+ **문제를 해결하는 최소한의 코드. 추측성 구현은 없다.**
20
+
21
+ - 요청받은 것 이상의 기능을 추가하지 않는다.
22
+ - 단일 용도 코드에 추상화를 도입하지 않는다.
23
+ - 요청하지 않은 "유연성"이나 "설정 가능성"을 추가하지 않는다.
24
+ - 불가능한 시나리오에 대한 에러 처리를 추가하지 않는다.
25
+ - 200줄로 작성했는데 50줄로 될 수 있다면, 다시 작성한다.
26
+
27
+ 스스로에게 물어본다: "시니어 엔지니어가 이것을 과도하게 복잡하다고 할까?" 그렇다면 단순화한다.
28
+
29
+ ## 3. 외과적 변경
30
+
31
+ **반드시 필요한 것만 건드린다. 자신이 만든 혼란만 정리한다.**
32
+
33
+ 기존 코드를 편집할 때:
34
+ - 인접한 코드, 주석, 포맷을 "개선"하지 않는다.
35
+ - 망가지지 않은 것을 리팩터링하지 않는다.
36
+ - 자신이 다르게 작성할 것이라도 기존 스타일을 따른다.
37
+ - 관련 없는 죽은 코드를 발견하면 언급한다 — 삭제하지 않는다.
38
+
39
+ 변경으로 인해 고아가 생길 때:
40
+ - 자신의 변경이 만든 미사용 import/변수/함수를 제거한다.
41
+ - 기존에 있던 죽은 코드는 요청받지 않는 한 제거하지 않는다.
42
+
43
+ 판단 기준: 변경된 모든 줄이 사용자의 요청으로 직접 추적 가능해야 한다.
44
+
45
+ ## 4. 목표 주도 실행
46
+
47
+ **성공 기준을 정의한다. 검증될 때까지 반복한다.**
48
+
49
+ 작업을 검증 가능한 목표로 변환한다:
50
+ - "유효성 검사 추가" → "잘못된 입력에 대한 테스트 작성 후 통과시키기"
51
+ - "버그 수정" → "버그를 재현하는 테스트 작성 후 통과시키기"
52
+ - "X 리팩터링" → "리팩터링 전후로 테스트가 통과함을 확인"
53
+
54
+ 다단계 작업의 경우 간략한 계획을 제시한다:
55
+ ```
56
+ 1. [단계] → 검증: [확인 방법]
57
+ 2. [단계] → 검증: [확인 방법]
58
+ 3. [단계] → 검증: [확인 방법]
59
+ ```
60
+
61
+ 명확한 성공 기준은 독립적인 반복을 가능하게 한다. 모호한 기준("잘 동작하게 해줘")은 지속적인 확인을 요구한다.
62
+
63
+ ---
64
+
65
+ **이 가이드라인이 작동하고 있다면:** diff에서 불필요한 변경이 줄고, 과도한 복잡성으로 인한 재작성이 줄고, 실수 후가 아닌 구현 전에 명확화 질문이 나온다.
66
+
67
+ ---
68
+ ---
69
+
70
+ # walwal-harness v7.1 — Company Mode
71
+
72
+ 이 프로젝트는 walwal-harness company mode로 운영된다.
73
+ 위 행동 가이드라인에 더해 아래 규칙이 추가로 적용된다.
74
+
75
+ ## 5. 진입점
76
+
77
+ Owner가 회사에 접근하는 명령은 두 개뿐이다. 그 외의 경로는 없다.
78
+
79
+ | 명령 | 사용 시점 |
80
+ |---|---|
81
+ | `/goal` | 미션 설정, 수정, 추가 |
82
+ | `/hot-fix` | 활성 goal과 독립된 긴급 수정 |
83
+
84
+ `/ceo`, `/cto`, `/cqo`, `/coo`, `/cdo`, `/ops`, `/hiring`은 slash command가 아니다.
85
+ 내부 라우팅은 agent/skill wiring으로만 처리한다.
86
+
87
+ ## 6. Company 구조
88
+
89
+ ```
90
+ Owner
91
+ └─ /goal 또는 /hot-fix
92
+ └─ harness-ceo 오케스트레이터 — Owner의 유일한 접점
93
+ ├─ harness-coo 리서치, 가설, 서비스 방향
94
+ ├─ harness-cdo 브랜딩, UI/UX, 디자인 리뷰
95
+ ├─ harness-cto 아키텍처, API, 플랫폼, 구현 총괄
96
+ ├─ harness-cqo 품질 게이트, 회귀, archive, gotcha/convention 관리
97
+ └─ harness-ops 빌드 모니터링, 로그 분석, 서비스 이벤트
98
+ ```
99
+
100
+ 각 CXX는:
101
+ - **독립된 fresh session 컨텍스트**에서 실행된다 — CEO 세션과 메모리를 공유하지 않는다
102
+ - 결정을 `.harness/documents/{mission_name}/{cxx}.md`에 기록한다
103
+ - 모든 전문 작업을 hired worker에게 위임한다 — 직접 실행하지 않는다
104
+ - 필요한 worker가 없으면 `harness-hiring`을 먼저 호출한다
105
+
106
+ CEO는 worker 기록 없이 완료된 산출물을 포함한 CXX 보고서를 거부한다.
107
+
108
+ ## 7. 미션 플로우
109
+
110
+ ### Goal
111
+
112
+ 1. CEO가 Owner 요청을 읽고 판단한다: 브레인스토밍 먼저, 또는 즉시 실행.
113
+ 2. CEO가 관련 CXX에게만 범위를 한정한 질문을 전달한다.
114
+ 3. 각 CXX가 worker를 고용하고, 위임하고, 결과를 수집하여 `{cxx}.md`에 기록한다.
115
+ 4. CEO가 CXX 산출물을 종합하여 다음 CXX에 라우팅하거나 Owner에게 보고한다.
116
+
117
+ **완료 기준:** `.harness/documents/{mission_name}/ceo.md`에 최종 Owner 보고가 존재한다.
118
+
119
+ ### Hot Fix
120
+
121
+ 1. CEO가 긴급 요청을 받고 즉시 CTO와 CQO를 소집한다.
122
+ 2. CTO가 최소 패치 경로를 설계하고 구현 worker를 고용한다.
123
+ 3. Worker가 구현한다. CTO가 worker 증거를 검증하고 `cto.md`를 작성한다.
124
+ 4. CQO가 회귀 게이트를 실행한다. `.harness/gotchas/` 또는 `.harness/conventions/`에 교훈을 등록하고 `cqo.md`를 작성한다.
125
+ 5. CQO 판정 **PASS** 이후에만 archive한다.
126
+
127
+ **완료 기준:** `cto.md`, `cqo.md`, 그리고 최소 하나의 신규 gotcha 또는 convention 항목이 존재한다.
128
+
129
+ 주의: harness 문서(ceo.md, cto.md, cqo.md, worker 보고서)에 대한 docmeta skip 판단은 미션 프로토콜 단계를 건너뛸 권한을 부여하지 않는다. 이 파일들은 분석 산출물이 아니라 미션 기록이다.
130
+
131
+ ## 8. 하네스 런타임
132
+
133
+ | 경로 | 역할 |
134
+ |---|---|
135
+ | `.harness/documents/{mission}/` | 미션별 CXX 결정 기록 및 worker 보고서 |
136
+ | `.harness/conventions/` | 지속 규칙 (CQO가 작성, 미션을 넘어 유지) |
137
+ | `.harness/gotchas/` | 재발 방지 기록 (CQO가 hot-fix마다 작성) |
138
+ | `.harness/memories/` | 장기 공유 컨텍스트 |
139
+ | `.harness/shared/HR-Resource/` | 채용 가능한 worker skill pool |
140
+ | `.harness/archive/` | CQO 승인 완료 미션 (불변) |
141
+ | `.harness/logs/YYYY-MM-DD/` | OPS 예외 로그 (비정상 케이스만) |
142
+
143
+ `.harness/`는 미션 상태 저장소다. 빌드 산출물이 아니다. 삭제하지 않는다.
144
+
145
+ ## 9. 금지 규칙
146
+
147
+ 1. **`{mission}/cto.md` 없이 소스 코드 편집 금지** — CTO의 범위 승인이 있어야 소스 파일을 수정할 수 있다.
148
+ 2. **CXX 사칭 금지** — 현재 모델이 CEO/CTO/CQO를 인라인으로 대행하지 않는다. 설치된 harness skill을 fresh session에서 사용한다.
149
+ 3. **이름 없는 worker 금지** — 모든 전문 작업은 `harness-hiring` → `harness-resource-manager`를 거친다.
150
+ 4. **CQO 판정 없이 archive 금지** — 명시적 PASS가 담긴 `{mission}/cqo.md`가 존재해야 한다.
151
+ 5. **gotcha 등록 생략 금지** — 모든 hot-fix는 `.harness/gotchas/` 또는 `.harness/conventions/`에 최소 하나의 항목을 만든다.
152
+ 6. **미션 중 이 파일 편집 금지** — AGENTS.md를 수정하려면 별도 `/goal`을 제출한다.
153
+
154
+ ---
155
+
156
+ ## 10. 프로젝트 컨텍스트
157
+
158
+ - **기술 스택**: {{TECH_STACK}}
159
+ - **프로젝트 구조**: {{PROJECT_STRUCTURE}}
160
+ - **하네스 설치일**: {{DATE}}
@@ -1,83 +1,114 @@
1
- # AGENTS.md — Project Context for AI Agents
1
+ # AGENTS.md — {{PROJECT_NAME}}
2
+ # walwal-harness v7.1 | Company Mode
3
+ # Installed: {{DATE}} | CLAUDE.md is a symlink to this file.
2
4
 
3
- > 이 파일은 모든 AI 에이전트(Claude, Cursor, Copilot, Windsurf 등)의 공통 진입점입니다.
4
- > CLAUDE.md는 이 파일의 심볼릭 링크입니다.
5
- > Generated by walwal-harness ({{DATE}})
5
+ ---
6
6
 
7
- ## Project
7
+ ## 1. Entry Points
8
8
 
9
- - **Name**: (Planner가 설정)
10
- - **Description**: (Planner가 설정)
11
- - **Phase**: INIT
12
- - **Harness**: `.harness/HARNESS.md` 참조
9
+ Two Owner-facing commands. Nothing else reaches the company.
13
10
 
14
- ## Tech Stack
11
+ | Command | When |
12
+ |---|---|
13
+ | `/goal` | Set, update, or extend a mission |
14
+ | `/hot-fix` | Emergency fix independent of the active goal |
15
15
 
16
- - Backend: (scan-project.sh가 감지)
17
- - Frontend: (scan-project.sh가 감지)
18
- - Database: (scan-project.sh가 감지)
16
+ `/ceo`, `/cto`, `/cqo`, `/coo`, `/cdo`, `/ops`, `/hiring` are not slash commands.
17
+ Internal routing uses agent/skill wiring only.
19
18
 
20
- ## IA-MAP (Information Architecture)
19
+ ---
21
20
 
22
- > Planner가 프로젝트 시작 시 확정합니다.
23
- > `[?]` 태그는 Planner가 분류해야 하는 미확인 경로입니다.
21
+ ## 2. Think Before Acting
22
+
23
+ Don't assume. Don't hide confusion.
24
+
25
+ - State assumptions before implementing. If uncertain, ask.
26
+ - If multiple approaches exist, name them — don't pick silently.
27
+ - Minimum change that solves the problem. No speculative scope.
28
+ - If something is unclear, stop. Name what is unclear. Ask.
29
+
30
+ For hot-fix: smallest correct patch only. Do not "improve" adjacent code.
31
+ For goal: define verifiable success criteria before CEO routes to CXX.
32
+
33
+ ---
34
+
35
+ ## 3. Company Structure
24
36
 
25
37
  ```
26
- /
27
- ├── AGENTS.md # [META] 프로젝트 컨텍스트 → Planner
28
- ├── CLAUDE.md # [META] → AGENTS.md 심볼릭 링크
29
- └── .harness/ # [HARNESS] 하네스 시스템 → Planner
38
+ Owner
39
+ └─ /goal or /hot-fix
40
+ └─ harness-ceo orchestrator — Owner's only contact
41
+ ├─ harness-coo research, hypothesis, service direction
42
+ ├─ harness-cdo branding, UI/UX, design review
43
+ ├─ harness-cto architecture, API, platform, implementation
44
+ ├─ harness-cqo quality gates, regression, archive, gotcha/convention
45
+ └─ harness-ops build monitoring, log analysis, service events
30
46
  ```
31
47
 
32
- ## Rules (모든 에이전트 공통)
33
-
34
- ### 읽기/쓰기 권한
35
-
36
- | 파일 | 읽기 | 쓰기 |
37
- |------|------|------|
38
- | AGENTS.md | 전체 | Planner만 |
39
- | .harness/actions/api-contract.json | 전체 | Planner만 |
40
- | .harness/actions/feature-list.json | 전체 | passes: Generator, 나머지: Planner |
41
- | .harness/progress.json | 전체 | 전체 (Session Boundary Protocol에 따라 업데이트) |
42
- | `[BE]` 소유 경로 | 전체 | Generator-Backend만 |
43
- | `[FE]` 소유 경로 | 전체 | Generator-Frontend만 |
44
- | .harness/archive/ | 전체 | 쓰기 금지 (불변) |
45
- | .harness/gotchas/ | 전체 | Dispatcher만 |
46
-
47
- ### 금지 사항
48
-
49
- - AGENTS.md를 Planner 외 에이전트가 수정
50
- - 서비스 간 직접 DB 접근
51
- - 테스트 삭제/약화
52
- - archive/ 내 파일 수정
53
- - 아티팩트 상태가 `draft` 미만인 선행 아티팩트에 의존하여 작업 시작
54
-
55
- ### 품질 게이트 (v3.1)
56
-
57
- | 게이트 | 시점 | 내용 |
58
- |--------|------|------|
59
- | **Pre-Eval Gate** | Generator → Evaluator 전환 | tsc, eslint, jest/vitest 자동 실행. 실패 시 Generator 리라우팅 |
60
- | **파일 소유권 검증** | 에이전트 전환 시 | git diff로 권한 밖 파일 수정 감지 |
61
- | **아티팩트 선행조건** | 에이전트 시작 전 | progress.json.artifacts 상태 확인 |
62
- | **에스컬레이션** | 3회 연속 실패 | Planner에게 scope 축소/접근 변경 요청 |
63
-
64
- ### Evaluation System (v3.2)
65
-
66
- | 설정 | 값 |
67
- |------|------|
68
- | PASS 기준 | **2.80 / 3.00 이상** |
69
- | FAIL 기준 | 2.79 이하 (예외 없음) |
70
- | Evidence 없는 Score | 0점 강제 |
71
- | AC 부분 통과 | FAIL (100% 필수) |
72
- | Regression 실패 1건+ | FAIL (신규 점수 무관) |
73
-
74
- - Planner는 feature-list.json에 **Executable AC** (type: api/visual/e2e + verify 조건) 필수 작성
75
- - Evaluator는 Adversarial Rules에 따라 적대적으로 검증 (rubber-stamping 금지)
76
- - 이전 Sprint PASS 기능은 Regression Checkpoint로 재검증
77
- - Eval-Functional ↔ Eval-Visual 간 Cross-Validation으로 불일치 감지
78
-
79
- ### 메모리 오염 방어
80
-
81
- - gotcha/memory 항목은 `unverified` 상태로 시작, Planner 리뷰 후 `verified` 승격
82
- - TTL 만료 항목은 Planner 스프린트 전환 시 리뷰 (갱신 또는 삭제)
83
- - 코드/git으로 검증 불가한 항목은 즉시 삭제
48
+ Each CXX:
49
+ - Runs in a **fresh session context** — no shared memory with CEO's session
50
+ - Records decisions in `.harness/documents/{mission_name}/{cxx}.md`
51
+ - Delegates all specialist work to hired workers — never executes directly
52
+ - If a required worker is absent, invokes `harness-hiring` before assigning
53
+
54
+ CEO rejects any CXX report that contains completed deliverables without matching worker records.
55
+
56
+ ---
57
+
58
+ ## 4. Mission Flow
59
+
60
+ ### Goal
61
+
62
+ 1. CEO reads the Owner request. Decides: brainstorm first, or assign immediately.
63
+ 2. CEO sends scoped questions to relevant CXX only.
64
+ 3. Each CXX hires workers, collects reports, records decisions in `{cxx}.md`.
65
+ 4. CEO aggregates CXX outputs, routes to next CXX or reports to Owner.
66
+
67
+ **Complete when:** `.harness/documents/{mission_name}/ceo.md` contains a final Owner report.
68
+
69
+ ### Hot Fix
70
+
71
+ 1. CEO receives emergency request. Immediately summons CTO and CQO.
72
+ 2. CTO designs the minimum patch path. Hires implementation workers.
73
+ 3. Workers implement. CTO verifies evidence, writes `cto.md`.
74
+ 4. CQO runs regression gate. Registers a lesson in `.harness/gotchas/` or `.harness/conventions/`. Writes `cqo.md`.
75
+ 5. Archive only after CQO verdict: **PASS**.
76
+
77
+ **Complete when:** `cto.md`, `cqo.md`, and at least one new gotcha or convention entry exist.
78
+
79
+ Note: A docmeta skip decision on harness documents (ceo.md, cto.md, cqo.md, worker reports) does not authorize skipping any mission protocol step. These are mission records, not derived output documents.
80
+
81
+ ---
82
+
83
+ ## 5. Harness Runtime
84
+
85
+ | Path | Role |
86
+ |---|---|
87
+ | `.harness/documents/{mission}/` | CXX decisions and worker reports per mission |
88
+ | `.harness/conventions/` | Durable rules (CQO writes, survives missions) |
89
+ | `.harness/gotchas/` | Recurrence-prevention records (CQO writes per hot-fix) |
90
+ | `.harness/memories/` | Long-term shared context |
91
+ | `.harness/shared/HR-Resource/` | Hireable worker skill pool |
92
+ | `.harness/archive/` | CQO-approved completed missions (immutable) |
93
+ | `.harness/logs/YYYY-MM-DD/` | OPS exception logs (non-happy-path only) |
94
+
95
+ `.harness/` is the mission state store. Not a build artifact. Do not delete.
96
+
97
+ ---
98
+
99
+ ## 6. Hard Rules
100
+
101
+ 1. **No source edit without `{mission}/cto.md`** — CTO scope sign-off is required before any source file is modified.
102
+ 2. **No CXX impersonation** — The active model must not act as CEO/CTO/CQO inline. Use installed harness skills in fresh sessions.
103
+ 3. **No unnamed workers** — All specialist work routes through `harness-hiring` → `harness-resource-manager`.
104
+ 4. **No archive without CQO verdict** — `{mission}/cqo.md` with explicit PASS must exist.
105
+ 5. **No gotcha skip** — Every hot-fix produces at least one `.harness/gotchas/` or `.harness/conventions/` entry.
106
+ 6. **This file is read-only during missions** — Raise a separate `/goal` to update AGENTS.md.
107
+
108
+ ---
109
+
110
+ ## 7. Project Context
111
+
112
+ - **Tech Stack**: {{TECH_STACK}}
113
+ - **Structure**: {{PROJECT_STRUCTURE}}
114
+ - **Harness installed**: {{DATE}}
@@ -1,200 +1,28 @@
1
1
  {
2
2
  "harness": {
3
3
  "name": "walwal-harness — NEXUS company harness",
4
- "version": "6.1.4",
5
- "description": "NEXUS-adapted company metaphor for AI-agent engineering. Owner ↔ Dispatcher(CEO) ↔ Conductor + Meeting-Manager ↔ Planner(COO/HR) + CTO + CQO + Service-Ops. Generators (BE/FE/Designer/DevOps) + Evaluators (Functional/Visual/Code-Quality/Architecture/Security) + COO Hypothesis Cell. Always-on company mode, parallel worker pool, parallel-tracks fork-join meetings, hierarchical Conventions/Gotchas. React/Next.js/Flutter FE, NestJS/Laravel BE.",
4
+ "version": "7.1.1",
5
+ "description": "v7 company harness. Owner uses /goal or /hot-fix, CEO coordinates CXX agents, CXX agents use resource-manager/hiring, and hired workers produce mission evidence under .harness/documents/{mission}/workers/.",
6
6
  "source": "https://www.anthropic.com/engineering/harness-design-long-running-apps"
7
7
  },
8
8
  "agents": {
9
- "dispatcher": {
10
- "role": "사용자 요청 분석 → 파이프라인 결정 (FE-ONLY / BE-ONLY / FULLSTACK)",
11
- "skill": "harness-dispatcher",
12
- "outputs": ["actions/pipeline.json"],
13
- "always_first": true,
14
- "model": "opus",
15
- "thinking_mode": null
16
- },
17
- "brainstorming": {
18
- "role": "사용자의 러프한 요구사항을 대화형으로 구체화하여 Planner가 바로 쓸 수 있는 brainstorm-spec.md로 변환.",
19
- "skill": "harness-brainstorming",
20
- "inputs": ["(user conversation)"],
21
- "outputs": ["actions/brainstorm-spec.md"],
22
- "conditional": true,
23
- "trigger_conditions": {
24
- "comment": "Dispatcher가 아래 조건 중 하나 이상 충족 시 사용자에게 브레인스토밍 제안",
25
- "rules": [
26
- "사용자 요청에 구체적 기능명/엔드포인트/화면명이 없고 추상적 목표만 있을 때",
27
- "PRD/OpenAPI 등 구조화된 입력 문서가 없을 때",
28
- "'뭔가 만들고 싶은데', '아이디어가 있는데' 등 탐색적 표현이 포함될 때"
29
- ],
30
- "skip_when": [
31
- "사용자가 PRD, OpenAPI spec, 또는 구체적 feature list를 제공한 경우",
32
- "사용자가 '브레인스토밍 없이', 'skip brainstorming'을 명시한 경우",
33
- "이미 brainstorm-spec.md가 actions/에 존재하는 경우"
34
- ]
35
- },
36
- "invoked_by": "dispatcher (user opt-in after suggestion)",
37
- "next_on_complete": "planner",
38
- "model": "opus",
39
- "thinking_mode": "plan",
40
- "thinking_mode_description": "Claude Code plan 모드로 실행. 구조화된 계획 수립 후 실행.",
41
- "attribution": "Derived from obra/superpowers skills/brainstorming (MIT License)"
42
- },
43
- "planner": {
44
- "role": "제품 사양 + API 계약서 + 서비스 분할 설계",
45
- "skill": "harness-planner",
46
- "inputs": ["actions/brainstorm-spec.md (optional)"],
47
- "outputs": [
48
- "actions/plan.md",
49
- "actions/feature-list.json",
50
- "actions/api-contract.json"
51
- ],
52
- "model": "opus",
53
- "thinking_mode": null,
54
- "thinking_mode_description": null
55
- },
56
- "generator-backend": {
57
- "role": "NestJS MSA 서비스 구현, API 엔드포인트, DB 스키마",
58
- "skill": "harness-generator-backend",
59
- "inputs": ["actions/plan.md", "actions/feature-list.json", "actions/api-contract.json", "actions/sprint-contract.md"],
60
- "outputs": ["code:backend", "actions/sprint-contract.md"],
61
- "order": 1,
62
- "model": "sonnet",
63
- "thinking_mode": null,
64
- "model_rationale": "코드 생성은 Sonnet이 비용 대비 효율적. 계획은 Planner가 이미 완료."
65
- },
66
- "generator-frontend": {
67
- "role": "React/Next.js UI 컴포넌트, 상태관리, API 연동",
68
- "skill": "harness-generator-frontend",
69
- "inputs": ["actions/plan.md", "actions/feature-list.json", "actions/api-contract.json", "actions/sprint-contract.md"],
70
- "outputs": ["code:frontend", "actions/sprint-contract.md"],
71
- "order": 2,
72
- "model": "sonnet",
73
- "thinking_mode": null,
74
- "model_rationale": "코드 생성은 Sonnet이 비용 대비 효율적. 계획은 Planner가 이미 완료."
75
- },
76
- "evaluator-code-quality": {
77
- "role": "코드 자체의 유지보수성/아키텍처/Best Practice 검사 (BE/FE/libs 공통, 브라우저 없음)",
78
- "skill": "harness-evaluator-code-quality",
79
- "tools": ["Read", "Grep", "Glob", "Bash(tsc,eslint,biome,lint 스크립트 한정)"],
80
- "inputs": ["actions/sprint-contract.md", "actions/feature-list.json", "actions/api-contract.json"],
81
- "outputs": ["actions/evaluation-code-quality.md"],
82
- "model": "opus",
83
- "thinking_mode": "ultrathink",
84
- "thinking_mode_description": "시니어 리뷰어 관점. 변경 파일 전수 정적 분석 + C1-C5 축 적대적 채점.",
85
- "adversarial_rules": {
86
- "comment": "Code-Quality Evaluator 적대적 행동 규칙 — rubber-stamping 금지",
87
- "rules": [
88
- "브라우저 없이 코드만으로 판정. '동작하니 PASS' 금지.",
89
- "변경 파일(git diff)은 전수 검사. '시간 제약' 핑계 금지.",
90
- "모든 Score 주장은 파일:라인 evidence 동반. Evidence 없는 Score = 0.",
91
- "toolchain(tsc/eslint) 에러 1건 이상이면 나머지 축 채점 전 즉시 FAIL.",
92
- "api-contract.json ↔ 실제 DTO/시그니처 불일치 1건 이상 = FAIL.",
93
- "레이어 역방향 의존 / MSA 직접 DB 접근 / FE view→fetch 직결 1건 이상 = C1 Score 0.",
94
- "unhandled promise 1건 이상 또는 비타당한 any 3건 이상 = C4 Score 0.",
95
- "PASS를 주기 전에 자문하라: '내가 이 코드를 머지 승인할 수 있는가?' NO이면 FAIL.",
96
- "반복 페널티: 같은 축에서 이전 스프린트 대비 악화 시 Score 최대 1."
97
- ],
98
- "forbidden": [
99
- "'동작은 Functional 에서 확인됐으니 OK' 식의 책임 전가",
100
- "'관용적 any', '사소한 중복' 같은 자기설득",
101
- "'제안사항만 남기고 Pass' — 필수 개선은 FAIL",
102
- "파일 수정/커밋 (이 평가자는 읽기 전용)"
103
- ]
104
- }
105
- },
106
- "evaluator-functional": {
107
- "role": "Playwright로 E2E 기능 검증, API 응답/DB 상태 확인",
108
- "skill": "harness-evaluator-functional",
109
- "tools": ["playwright:browser_*"],
110
- "inputs": ["actions/sprint-contract.md", "actions/feature-list.json", "actions/api-contract.json"],
111
- "outputs": ["actions/evaluation-functional.md"],
112
- "model": "opus",
113
- "thinking_mode": "ultrathink",
114
- "thinking_mode_description": "최고 수준의 사고 모드. 적대적 검증에 깊은 추론이 필요. 각 항목을 비판적으로 분석.",
115
- "evaluation_template": "assets/templates/evaluation-functional.md.template",
116
- "adversarial_rules": {
117
- "comment": "Evaluator 적대적 행동 규칙 — 통과 편향 제거를 위한 강제 규칙",
118
- "rules": [
119
- "Generator의 '구현 완료' 주장을 절대 신뢰하지 마라. 모든 엔드포인트에 직접 요청을 보내고 응답을 확인하라.",
120
- "정상 경로(happy path) 1개당 비정상 경로(unhappy path) 최소 2개를 반드시 테스트하라.",
121
- "api-contract.json과 실제 응답을 필드 단위로 비교하라. 누락 필드, 타입 불일치, 추가 필드 모두 FAIL 사유.",
122
- "PASS를 주기 전에 자문하라: '내가 이 코드를 직접 작성했다면 이 수준으로 PR을 올리겠는가?' NO이면 FAIL.",
123
- "AC 항목 하나라도 미통과이면 전체 FAIL. 부분 통과는 인정하지 않는다.",
124
- "Evidence(증거)가 없는 Score는 0점이다. '확인했다'는 주장은 증거가 아니다.",
125
- "이전 Sprint에서 PASS된 기능이 하나라도 깨졌으면 신규 기능 점수와 무관하게 FAIL.",
126
- "Score 3을 주려면 엣지케이스(빈 값, 초과값, 동시 요청, 특수문자)까지 테스트한 증거가 있어야 한다."
127
- ],
128
- "forbidden": [
129
- "'전반적으로 잘 구현되었습니다' 류의 모호한 긍정 평가",
130
- "'사소한 이슈이므로 PASS' — 사소함은 Evaluator가 판단할 사항이 아니다",
131
- "'시간 제약상 일부만 테스트' — 전수 테스트가 불가하면 FAIL 처리",
132
- "Generator에게 유리한 방향으로 기준을 해석하는 행위"
133
- ]
134
- }
135
- },
136
- "evaluator-visual": {
137
- "role": "디자인 일관성, 반응형, 접근성, AI슬롭 감지",
138
- "skill": "harness-evaluator-visual",
139
- "tools": ["playwright:browser_take_screenshot", "playwright:browser_resize", "playwright:browser_snapshot"],
140
- "inputs": ["actions/sprint-contract.md", "actions/evaluation-functional.md", "actions/feature-list.json"],
141
- "outputs": ["actions/evaluation-visual.md"],
142
- "model": "opus",
143
- "thinking_mode": "ultrathink",
144
- "thinking_mode_description": "최고 수준의 사고 모드. 시각적 결함, 접근성, AI슬롭을 비판적으로 탐지.",
145
- "evaluation_template": "assets/templates/evaluation-visual.md.template",
146
- "adversarial_rules": {
147
- "comment": "Visual Evaluator 적대적 행동 규칙",
148
- "rules": [
149
- "모든 페이지를 반드시 3개 뷰포트(375px, 768px, 1280px)에서 스크린샷 촬영하라. 1개라도 누락이면 해당 페이지 Score 산정 불가.",
150
- "axe-core 접근성 검사를 실제로 실행하라. Critical 또는 Serious 위반이 1건이라도 있으면 V3 = 0.",
151
- "AI슬롭 패턴(무의미한 그라데이션, 과도한 그림자, 장식 아이콘 남발)을 적극 탐지하라. 2건 이상이면 V4 최대 1점.",
152
- "evaluation-functional.md의 Cross-Validation Data와 교차 검증하라. API 성공인데 UI에 에러 표시 = 불일치 = FAIL 사유.",
153
- "이전 Sprint 스크린샷 대비 의도치 않은 시각 변경이 있으면 점수 무관 FAIL.",
154
- "PASS를 주기 전에 자문하라: '이 UI를 실사용자에게 보여줄 수 있는가?' NO이면 FAIL.",
155
- "로딩/에러/빈 상태가 하나라도 미구현이면 V5 최대 1점.",
156
- "Evidence(스크린샷 경로 또는 DOM 스냅샷)가 없는 Score는 0점이다."
157
- ],
158
- "forbidden": [
159
- "'디자인이 깔끔합니다' 류의 주관적 긍정 평가",
160
- "'접근성은 추후 개선' — 접근성은 기본 요건이지 부가 기능이 아니다",
161
- "'모바일 뷰포트는 생략' — 3개 뷰포트 전수 검사는 필수",
162
- "스크린샷 없이 '확인했다'고 주장하는 행위"
163
- ]
164
- }
165
- }
9
+ "ceo": { "role": "Owner-facing mission intake, CXX orchestration, and final reports", "skill": "harness-ceo", "model": "sonnet" },
10
+ "coo": { "role": "Planning, research, hypothesis, mission fit", "skill": "harness-coo", "model": "sonnet" },
11
+ "cdo": { "role": "Branding, UI/UX, design review", "skill": "harness-cdo", "model": "sonnet" },
12
+ "cto": { "role": "Architecture, platform, API, implementation coordination", "skill": "harness-cto", "model": "opus" },
13
+ "cqo": { "role": "Quality gates, regression, archive criteria", "skill": "harness-cqo", "model": "opus" },
14
+ "ops": { "role": "Build/service environment monitoring and exception logging", "skill": "harness-ops", "model": "sonnet" },
15
+ "hiring": { "role": "Hire missing workers from HR-Resource", "skill": "harness-hiring", "model": "sonnet" },
16
+ "resource-manager": { "role": "Resolve hired-worker availability and invocation wording", "skill": "harness-resource-manager", "model": "haiku" },
17
+ "brick-office": { "role": "Company status and dashboard support", "skill": "harness-brick-office", "model": "haiku" }
166
18
  },
167
19
  "flow": {
168
- "sequence": ["dispatcher", "planner", "generator-backend", "generator-frontend", "evaluator-code-quality", "evaluator-functional", "evaluator-visual"],
169
- "evaluator_chain": {
170
- "comment": "Generator 완료 후 실행되는 평가자 체인. 직렬 실행 + 조기 종료 — 앞단 FAIL 시 이후 평가자는 생략하고 Generator 로 리라우팅. 모두 PASS 여야 다음 스프린트로 이동.",
171
- "execution": "serial_with_early_exit",
172
- "order_rationale": "code-quality(정적, 저비용) → functional(동작, 중비용) → visual(렌더, 고비용). 구조가 깨진 코드에 동작 테스트를 낭비하지 않기 위함.",
173
- "on_any_fail": "reroute_to_generator",
174
- "on_all_pass": "advance_sprint"
175
- },
176
- "pipeline_selection": {
177
- "comment": "Dispatcher가 pipeline.json으로 활성 에이전트를 결정.",
178
- "pipelines": {
179
- "FULLSTACK": ["planner", "generator-backend", "generator-frontend", "evaluator-code-quality", "evaluator-functional", "evaluator-visual"],
180
- "FE-ONLY": ["planner:light", "generator-frontend", "evaluator-code-quality", "evaluator-functional", "evaluator-visual"],
181
- "BE-ONLY": ["planner", "generator-backend", "evaluator-code-quality", "evaluator-functional:api-only"]
182
- },
183
- "evaluator_chains": {
184
- "comment": "파이프라인별 평가자 체인. Dispatcher가 pipeline.json.evaluator_chain 으로 기록.",
185
- "FULLSTACK": ["evaluator-code-quality", "evaluator-functional", "evaluator-visual"],
186
- "FE-ONLY": ["evaluator-code-quality", "evaluator-functional", "evaluator-visual"],
187
- "BE-ONLY": ["evaluator-code-quality", "evaluator-functional"]
188
- }
189
- },
190
- "sprint_execution": {
191
- "comment": "Backend 먼저 → API 안정 후 Frontend 연동 → 기능 QA → 비주얼 QA (FULLSTACK 기준)",
192
- "backend_first": true,
193
- "reason": "프론트가 존재하지 않는 API를 호출하는 실패 방지"
194
- },
20
+ "sequence": ["ceo", "coo", "cdo", "cto", "cqo", "ops"],
21
+ "worker_gate": "CXX agents must use harness-resource-manager and harness-hiring before specialist deliverables.",
22
+ "worker_reports_required": ".harness/documents/{mission}/workers/{worker-name}.md",
195
23
  "retry_on_fail": true,
196
24
  "max_retries_per_sprint": 5,
197
- "escalate_to_planner_after": 3,
25
+ "escalate_to_ceo_after": 3,
198
26
  "archive_on_sprint_complete": true,
199
27
  "pre_eval_gate": {
200
28
  "comment": "Generator → Evaluator 전환 전 결정론적 검증. 실패 시 Evaluator 세션을 열지 않고 Generator로 자동 리라우팅.",
@@ -338,9 +166,9 @@
338
166
  }
339
167
  },
340
168
  "behavior": {
341
- "comment": "하네스 동작 플래그. UserPromptSubmit 훅이 이 값을 읽어 자동 라우팅을 결정한다.",
342
- "auto_route_dispatcher": true,
343
- "auto_route_dispatcher_description": "true 이면 사용자의 모든 프롬프트가 harness-dispatcher 경유로 분류/라우팅 된다. 사용자가 'harness skip' 등을 말하면 단일 메시지 한정으로 건너뛴다."
169
+ "comment": "하네스 동작 플래그. UserPromptSubmit 훅이 이 값을 읽어 v7 CEO/CXX 라우팅 안내를 결정한다.",
170
+ "auto_route_ceo": true,
171
+ "auto_route_ceo_description": "true 이면 /goal 또는 /hot-fix 이후 Owner 입력을 v7 CEO/CXX mission flow 기준으로 안내한다. 사용자가 'harness skip' 등을 말하면 단일 메시지 한정으로 건너뛴다."
344
172
  },
345
173
  "token_limit": {
346
174
  "comment": "모델 토큰 제한으로 작업이 중단됐을 때의 저비용 재개 정책. 별도 probe 호출 없이 시간 기반으로만 재개 알림을 계산한다.",
@@ -350,9 +178,9 @@
350
178
  "owner": "session-start"
351
179
  },
352
180
  "company_mode": {
353
- "comment": "v6.3 — 회사모드는 항시 활성이다. 사용자 모드 선택과 tie-breaker 는 제거됐다. Conductor 는 feature-list/queue 를 기반으로 매 tick 가능한 병렬 작업을 자동 배정한다.",
181
+ "comment": "v7 — 회사모드는 항시 활성이다. Owner entrypoint는 /goal, /hot-fix이며 CEO가 CXX와 hired worker 흐름을 조정한다.",
354
182
  "default_mode": "company",
355
- "owner": "conductor",
183
+ "owner": "ceo",
356
184
  "worker_concurrency": 3,
357
185
  "worker_spawn": "claude",
358
186
  "worker_spawn_description": "claude 이면 idle worker 배정 시 `claude -p` 백그라운드 프로세스를 띄운다. record 로 두면 prompt/log만 생성한다.",
@@ -2,10 +2,10 @@
2
2
  "version": 4,
3
3
  "mode": "company",
4
4
  "mode_decision": {
5
- "owner": "conductor",
5
+ "owner": "ceo",
6
6
  "decided_at": null,
7
- "rationale": "company mode is always-on",
8
- "policy": "always_company_parallel"
7
+ "rationale": "v7 company mode is CEO-led",
8
+ "policy": "owner_goal_to_ceo_cxx_workers"
9
9
  },
10
10
  "project_name": "",
11
11
  "pipeline": null,
@@ -21,7 +21,7 @@
21
21
  "current_agent": null,
22
22
  "agent_status": "pending",
23
23
  "completed_agents": [],
24
- "next_agent": "dispatcher",
24
+ "next_agent": "ceo",
25
25
  "failure": {
26
26
  "agent": null,
27
27
  "location": null,
package/bin/init.js CHANGED
@@ -859,10 +859,10 @@ function installStatusline() {
859
859
  }
860
860
 
861
861
  // ─────────────────────────────────────────
862
- // 3d. UserPromptSubmit hook (auto dispatcher routing)
862
+ // 3d. UserPromptSubmit hook (v7 CEO routing guidance)
863
863
  // ─────────────────────────────────────────
864
864
  function installUserPromptSubmitHook() {
865
- log('Installing UserPromptSubmit hook (auto dispatcher routing)...');
865
+ log('Installing UserPromptSubmit hook (v7 CEO routing guidance)...');
866
866
 
867
867
  const settingsDir = path.join(PROJECT_ROOT, '.claude');
868
868
 
@@ -896,9 +896,9 @@ function installUserPromptSubmitHook() {
896
896
  });
897
897
  writeClaudeSettings(settings);
898
898
  log('UserPromptSubmit hook installed in .claude/settings.json');
899
- log(' → All prompts will be routed through harness-dispatcher');
899
+ log(' → /goal and /hot-fix are guided through harness-ceo and CXX workflow');
900
900
  log(' → Opt-out per message: say "harness skip" or "without harness"');
901
- log(' → Disable globally: set .harness/config.json behavior.auto_route_dispatcher = false');
901
+ log(' → Disable globally: set .harness/config.json behavior.auto_route_ceo = false');
902
902
  } else {
903
903
  log('UserPromptSubmit hook already installed');
904
904
  }
@@ -1185,7 +1185,9 @@ function detectMigrationNeeded() {
1185
1185
  const memoryTplPath = path.join(PKG_ROOT, 'assets', 'templates', 'memory.md');
1186
1186
  const flags = {
1187
1187
  progressV3toV4: false,
1188
+ progressLegacyRouting: false,
1188
1189
  configMissingCompanyMode: false,
1190
+ configLegacyRouting: false,
1189
1191
  memoryMissingSystemEntries: [],
1190
1192
  gotchaMissingEntries: {}, // { "<filename>": [G-IDs...] }
1191
1193
  conventionMissingEntries: {}, // { "<filename>": [C-IDs...] }
@@ -1246,12 +1248,22 @@ function detectMigrationNeeded() {
1246
1248
  try {
1247
1249
  const p = JSON.parse(fs.readFileSync(progressPath, 'utf8'));
1248
1250
  if ((p.version ?? 0) < TARGET_PROGRESS_VERSION) flags.progressV3toV4 = true;
1251
+ if (
1252
+ ['dispatcher', 'planner', 'generator-backend', 'generator-frontend', 'evaluator-functional', 'evaluator-visual', 'service-ops'].includes(p.next_agent) ||
1253
+ p.mode_decision?.owner === 'conductor'
1254
+ ) flags.progressLegacyRouting = true;
1249
1255
  } catch {}
1250
1256
  }
1251
1257
  if (fs.existsSync(configPath)) {
1252
1258
  try {
1253
1259
  const c = JSON.parse(fs.readFileSync(configPath, 'utf8'));
1254
1260
  if (!c.company_mode || c.mode_selection) flags.configMissingCompanyMode = true;
1261
+ if (
1262
+ c.behavior?.auto_route_dispatcher !== undefined ||
1263
+ c.behavior?.auto_route_dispatcher_description ||
1264
+ c.company_mode?.owner === 'conductor' ||
1265
+ c.agents?.dispatcher?.skill === 'harness-dispatcher'
1266
+ ) flags.configLegacyRouting = true;
1255
1267
  } catch {}
1256
1268
  }
1257
1269
  if (fs.existsSync(memoryPath) && fs.existsSync(memoryTplPath)) {
@@ -1327,15 +1339,21 @@ function extractConventionEntryBlock(md, id) {
1327
1339
  function showMigrationProposal(flags) {
1328
1340
  console.log('');
1329
1341
  console.log('╔══════════════════════════════════════════════════════════╗');
1330
- console.log('║ walwal-harness v6 — 자동 마이그레이션 사용 가능 ║');
1342
+ console.log('║ walwal-harness v7 — 자동 마이그레이션 사용 가능 ║');
1331
1343
  console.log('╚══════════════════════════════════════════════════════════╝');
1332
1344
  if (flags.progressV3toV4) {
1333
1345
  console.log(' • progress.json: legacy mode → "company"');
1334
1346
  console.log(' legacy mode 값은 보존하지 않고 회사모드로 정규화됩니다.');
1335
1347
  }
1348
+ if (flags.progressLegacyRouting) {
1349
+ console.log(' • progress.json: legacy dispatcher/conductor routing → v7 CEO routing');
1350
+ }
1336
1351
  if (flags.configMissingCompanyMode) {
1337
1352
  console.log(' • config.json: company_mode 섹션 동기화 가능');
1338
- console.log(' 사용자 모드 선택 없이 회사모드 병렬 실행으로 고정합니다.');
1353
+ console.log(' Owner /goal, /hot-fix → CEO/CXX/worker 흐름으로 고정합니다.');
1354
+ }
1355
+ if (flags.configLegacyRouting) {
1356
+ console.log(' • config.json: legacy dispatcher/conductor wording → v7 CEO/CXX wording');
1339
1357
  }
1340
1358
  if (flags.memoryMissingSystemEntries && flags.memoryMissingSystemEntries.length) {
1341
1359
  console.log(' • memory.md: 시스템 entry 누락 — append 가능');
@@ -1376,7 +1394,9 @@ function runMigrate(opts = {}) {
1376
1394
  const conventionMissingTotal = Object.values(flags.conventionMissingEntries || {}).reduce((n, a) => n + a.length, 0);
1377
1395
  if (
1378
1396
  !flags.progressV3toV4 &&
1397
+ !flags.progressLegacyRouting &&
1379
1398
  !flags.configMissingCompanyMode &&
1399
+ !flags.configLegacyRouting &&
1380
1400
  (!flags.memoryMissingSystemEntries || flags.memoryMissingSystemEntries.length === 0) &&
1381
1401
  gotchaMissingTotal === 0 &&
1382
1402
  conventionMissingTotal === 0 &&
@@ -1385,7 +1405,7 @@ function runMigrate(opts = {}) {
1385
1405
  console.log('');
1386
1406
  let pkgVer = 'unknown';
1387
1407
  try { pkgVer = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf8')).version; } catch {}
1388
- log(`이미 최신 — bundle v${pkgVer} 일치, progress v${TARGET_PROGRESS_VERSION}, config.company_mode, memory 시스템 entry, gotcha entry 모두 sync.`);
1408
+ log(`이미 최신 — bundle v${pkgVer} 일치, progress v${TARGET_PROGRESS_VERSION} v7 routing, config.company_mode, memory 시스템 entry, gotcha entry 모두 sync.`);
1389
1409
  return;
1390
1410
  }
1391
1411
 
@@ -1398,7 +1418,7 @@ function runMigrate(opts = {}) {
1398
1418
 
1399
1419
  // 1. progress.json
1400
1420
  const progressPath = path.join(HARNESS_DIR, 'progress.json');
1401
- if (flags.progressV3toV4 && fs.existsSync(progressPath)) {
1421
+ if ((flags.progressV3toV4 || flags.progressLegacyRouting) && fs.existsSync(progressPath)) {
1402
1422
  const original = fs.readFileSync(progressPath, 'utf8');
1403
1423
  const p = JSON.parse(original);
1404
1424
  const oldMode = p.mode ?? 'company';
@@ -1407,14 +1427,17 @@ function runMigrate(opts = {}) {
1407
1427
  version: TARGET_PROGRESS_VERSION,
1408
1428
  mode: 'company',
1409
1429
  mode_decision: {
1410
- owner: 'conductor',
1430
+ owner: 'ceo',
1411
1431
  decided_at: null,
1412
- rationale: `migration — legacy mode="${oldMode}" normalized to company`,
1413
- policy: 'always_company_parallel',
1432
+ rationale: `migration — legacy mode="${oldMode}" normalized to v7 CEO-led company`,
1433
+ policy: 'owner_goal_to_ceo_cxx_workers',
1414
1434
  user_override: null,
1415
1435
  },
1436
+ next_agent: ['dispatcher', 'planner', 'generator-backend', 'generator-frontend', 'evaluator-functional', 'evaluator-visual', 'service-ops'].includes(p.next_agent)
1437
+ ? 'ceo'
1438
+ : (p.next_agent ?? 'ceo'),
1416
1439
  };
1417
- log(` progress.json: version 3 → ${TARGET_PROGRESS_VERSION}, mode "${oldMode}" → "company"`);
1440
+ log(` progress.json: v7 routing normalized, mode "${oldMode}" → "company", next_agent="${p.next_agent ?? 'null'}" → "${newP.next_agent}"`);
1418
1441
  if (!dryRun) {
1419
1442
  fs.writeFileSync(path.join(backupDir, 'progress.json'), original);
1420
1443
  fs.writeFileSync(progressPath, JSON.stringify(newP, null, 2) + '\n');
@@ -1424,14 +1447,26 @@ function runMigrate(opts = {}) {
1424
1447
  // 2. config.json — inject company_mode from template if missing
1425
1448
  const configPath = path.join(HARNESS_DIR, 'config.json');
1426
1449
  const tplPath = path.join(PKG_ROOT, 'assets', 'templates', 'config.json');
1427
- if (flags.configMissingCompanyMode && fs.existsSync(configPath) && fs.existsSync(tplPath)) {
1450
+ if ((flags.configMissingCompanyMode || flags.configLegacyRouting) && fs.existsSync(configPath) && fs.existsSync(tplPath)) {
1428
1451
  const original = fs.readFileSync(configPath, 'utf8');
1429
1452
  const c = JSON.parse(original);
1430
1453
  const tpl = JSON.parse(fs.readFileSync(tplPath, 'utf8'));
1431
1454
  if (tpl.company_mode) {
1432
- c.company_mode = tpl.company_mode;
1455
+ c.company_mode = {
1456
+ ...tpl.company_mode,
1457
+ comment: 'v7 — 회사모드는 CEO/CXX/worker 문서 흐름으로 운영된다.',
1458
+ owner: 'ceo',
1459
+ };
1460
+ c.harness = tpl.harness || c.harness;
1461
+ c.agents = tpl.agents || c.agents;
1462
+ c.flow = tpl.flow || c.flow;
1463
+ c.behavior = c.behavior || {};
1464
+ c.behavior.auto_route_ceo = c.behavior.auto_route_ceo ?? c.behavior.auto_route_dispatcher ?? true;
1465
+ c.behavior.auto_route_ceo_description = 'true 이면 /goal 또는 /hot-fix 이후 Owner 입력을 v7 CEO/CXX mission flow 기준으로 안내한다.';
1466
+ delete c.behavior.auto_route_dispatcher;
1467
+ delete c.behavior.auto_route_dispatcher_description;
1433
1468
  delete c.mode_selection;
1434
- log(' config.json: company_mode 섹션 주입 (always-on company parallel)');
1469
+ log(' config.json: v7 CEO/CXX routing 섹션 동기화');
1435
1470
  if (!dryRun) {
1436
1471
  fs.writeFileSync(path.join(backupDir, 'config.json'), original);
1437
1472
  fs.writeFileSync(configPath, JSON.stringify(c, null, 2) + '\n');
@@ -1524,60 +1559,90 @@ function runMigrate(opts = {}) {
1524
1559
  log('Dry-run 완료 — 실제 변경 적용하려면 `npx walwal-harness migrate` 실행');
1525
1560
  } else {
1526
1561
  log(`Migration 완료. 백업: ${backupDir}`);
1527
- log('Conductor 가 다음 sprint 시작 시 자동으로 모드 결정합니다.');
1562
+ log('v7 routing 기준으로 /goal 또는 /hot-fix 가 CEO/CXX/worker 흐름을 시작합니다.');
1528
1563
  log('회사모드는 기본값이며 사용자 override 는 사용하지 않습니다.');
1529
1564
  }
1530
1565
  console.log('');
1531
1566
  }
1532
1567
 
1533
1568
  // ─────────────────────────────────────────
1534
- // Verify — 14 SKILL invariants + spawn whitelist + progress schema
1569
+ // Verify — v7 CXX/core skill invariants + progress schema
1535
1570
  // ─────────────────────────────────────────
1536
1571
  function runVerify() {
1537
1572
  const expectedSkills = [
1538
- 'dispatcher', 'conductor', 'meeting-manager', 'planner',
1539
- 'cto', 'cqo', 'service-ops',
1540
- 'generator-backend', 'generator-frontend', 'generator-designer', 'generator-devops',
1541
- 'evaluator-code-quality', 'evaluator-functional', 'evaluator-visual',
1542
- 'evaluator-architecture', 'evaluator-security',
1543
- 'coo-developer', 'documentationer',
1544
- 'brainstorming',
1573
+ 'ceo', 'coo', 'cdo', 'cto', 'cqo', 'ops',
1574
+ 'hiring', 'resource-manager', 'brick-office',
1545
1575
  ];
1546
1576
  const requiredFrontmatter = ['name', 'description'];
1547
1577
 
1548
1578
  console.log('');
1549
- log('=== Verify: skill invariants + spawn whitelist + progress schema ===');
1579
+ log('=== Verify: v7 command/skill invariants + progress schema ===');
1550
1580
  let pass = 0;
1551
1581
  let fail = 0;
1552
1582
  const issues = [];
1553
1583
 
1554
1584
  // 1) skill files
1585
+ const skillRoots = [
1586
+ ['.claude', CLAUDE_SKILLS_DIR],
1587
+ ['.codex', CODEX_SKILLS_DIR],
1588
+ ];
1555
1589
  for (const s of expectedSkills) {
1556
- const local = path.join(CLAUDE_SKILLS_DIR, `harness-${s}`, 'SKILL.md');
1557
- const exists = fs.existsSync(local);
1558
- if (!exists) {
1559
- issues.push(` ✗ skills/harness-${s}/SKILL.md MISSING`);
1560
- fail++;
1561
- continue;
1590
+ for (const [toolName, root] of skillRoots) {
1591
+ const local = path.join(root, `harness-${s}`, 'SKILL.md');
1592
+ const exists = fs.existsSync(local);
1593
+ if (!exists) {
1594
+ issues.push(` ✗ ${toolName}/skills/harness-${s}/SKILL.md MISSING`);
1595
+ fail++;
1596
+ continue;
1597
+ }
1598
+ const body = fs.readFileSync(local, 'utf8');
1599
+ const fmMatch = body.match(/^---\n([\s\S]*?)\n---/);
1600
+ if (!fmMatch) {
1601
+ issues.push(` ✗ ${toolName}/skills/harness-${s}: frontmatter 누락`);
1602
+ fail++;
1603
+ continue;
1604
+ }
1605
+ const missing = requiredFrontmatter.filter((k) => !new RegExp(`^${k}:`, 'm').test(fmMatch[1]));
1606
+ if (missing.length) {
1607
+ issues.push(` ✗ ${toolName}/skills/harness-${s}: frontmatter [${missing.join(',')}] 누락`);
1608
+ fail++;
1609
+ continue;
1610
+ }
1611
+ pass++;
1562
1612
  }
1563
- const body = fs.readFileSync(local, 'utf8');
1564
- const fmMatch = body.match(/^---\n([\s\S]*?)\n---/);
1565
- if (!fmMatch) {
1566
- issues.push(` ✗ harness-${s}: frontmatter 누락`);
1567
- fail++;
1568
- continue;
1613
+ }
1614
+ log(` skills: ${pass}/${expectedSkills.length * skillRoots.length} OK`);
1615
+
1616
+ // 2) owner-facing commands
1617
+ const allowedCommands = new Set(['goal.md', 'hot-fix.md']);
1618
+ const forbiddenCommands = new Set(['ceo.md', 'coo.md', 'cdo.md', 'cto.md', 'cqo.md', 'ops.md', 'hiring.md', 'resource-manager.md', 'brick-office.md']);
1619
+ const commandRoots = [
1620
+ ['.claude', CLAUDE_COMMANDS_DIR],
1621
+ ['.codex', CODEX_COMMANDS_DIR],
1622
+ ];
1623
+ for (const [toolName, root] of commandRoots) {
1624
+ for (const cmd of allowedCommands) {
1625
+ if (!fs.existsSync(path.join(root, cmd))) {
1626
+ issues.push(` ✗ ${toolName}/commands/${cmd} MISSING`);
1627
+ fail++;
1628
+ } else {
1629
+ pass++;
1630
+ }
1569
1631
  }
1570
- const missing = requiredFrontmatter.filter((k) => !new RegExp(`^${k}:`, 'm').test(fmMatch[1]));
1571
- if (missing.length) {
1572
- issues.push(` ✗ harness-${s}: frontmatter [${missing.join(',')}] 누락`);
1573
- fail++;
1574
- continue;
1632
+ if (fs.existsSync(root)) {
1633
+ for (const cmd of fs.readdirSync(root).filter(f => f.endsWith('.md'))) {
1634
+ if (forbiddenCommands.has(cmd)) {
1635
+ issues.push(` ✗ ${toolName}/commands/${cmd} forbidden in v7`);
1636
+ fail++;
1637
+ } else if (!allowedCommands.has(cmd)) {
1638
+ issues.push(` ⚠ ${toolName}/commands/${cmd} is outside walwal v7 owner-facing command set`);
1639
+ }
1640
+ }
1575
1641
  }
1576
- pass++;
1577
1642
  }
1578
- log(` skills: ${pass}/${expectedSkills.length} OK`);
1643
+ log(` commands: /goal + /hot-fix checked`);
1579
1644
 
1580
- // 2) progress.json schema (v6 = version 4 + mode_decision)
1645
+ // 3) progress.json schema (v6+ = version 4 + mode_decision)
1581
1646
  const progressPath = path.join(HARNESS_DIR, 'progress.json');
1582
1647
  if (fs.existsSync(progressPath)) {
1583
1648
  try {
@@ -1586,6 +1651,10 @@ function runVerify() {
1586
1651
  if ((p.version ?? 0) < 4) schemaIssues.push(`version=${p.version} (<4)`);
1587
1652
  if (!p.mode_decision) schemaIssues.push('mode_decision 누락');
1588
1653
  if (!p.dispatch) schemaIssues.push('dispatch 누락');
1654
+ if (p.mode_decision?.owner === 'conductor') schemaIssues.push('mode_decision.owner=conductor legacy');
1655
+ if (['dispatcher', 'planner', 'generator-backend', 'generator-frontend', 'evaluator-functional', 'evaluator-visual', 'service-ops'].includes(p.next_agent)) {
1656
+ schemaIssues.push(`next_agent=${p.next_agent} legacy`);
1657
+ }
1589
1658
  if (schemaIssues.length) {
1590
1659
  issues.push(` ✗ progress.json schema: ${schemaIssues.join(', ')} → npx walwal-harness migrate`);
1591
1660
  fail++;
@@ -1607,6 +1676,13 @@ function runVerify() {
1607
1676
  if (!c.company_mode) {
1608
1677
  issues.push(' ✗ config.json: company_mode 누락 → npx walwal-harness migrate');
1609
1678
  fail++;
1679
+ } else if (
1680
+ c.company_mode.owner === 'conductor' ||
1681
+ c.behavior?.auto_route_dispatcher !== undefined ||
1682
+ c.agents?.dispatcher?.skill === 'harness-dispatcher'
1683
+ ) {
1684
+ issues.push(' ✗ config.json: legacy dispatcher/conductor routing → npx walwal-harness migrate');
1685
+ fail++;
1610
1686
  } else {
1611
1687
  pass++;
1612
1688
  log(` config.json: company_mode.owner=${c.company_mode.owner} OK`);
@@ -1636,6 +1712,20 @@ function runVerify() {
1636
1712
  issues.push(' ⚠ .claude/commands/harness-next.md 존재 — v6.0.3 부터 회사 내부 도구로 전환됨. `npx walwal-harness --force` 또는 직접 삭제 권장');
1637
1713
  }
1638
1714
 
1715
+ // 6) installed script guidance must not claim removed dispatcher/planner flow.
1716
+ const routeScript = path.join(PROJECT_ROOT, 'scripts', 'harness-user-prompt-submit.sh');
1717
+ const sessionScript = path.join(PROJECT_ROOT, 'scripts', 'harness-session-start.sh');
1718
+ for (const scriptPath of [routeScript, sessionScript]) {
1719
+ if (!fs.existsSync(scriptPath)) continue;
1720
+ const body = fs.readFileSync(scriptPath, 'utf8');
1721
+ if (/harness-dispatcher|pipeline=none\/dispatcher|dispatch -> CEO meeting|planner\(COO\)|gen\/eval/.test(body)) {
1722
+ issues.push(` ✗ ${path.relative(PROJECT_ROOT, scriptPath)}: legacy dispatcher/planner guidance → npx walwal-harness init migrate --force`);
1723
+ fail++;
1724
+ } else {
1725
+ pass++;
1726
+ }
1727
+ }
1728
+
1639
1729
  console.log('');
1640
1730
  if (fail === 0) {
1641
1731
  log(`✓ Verify PASS — ${pass} 개 invariant 통과.`);
@@ -1702,7 +1792,9 @@ function main() {
1702
1792
  const gotchaMissing = Object.keys(migFlags.gotchaMissingEntries || {}).length > 0;
1703
1793
  const hasContentDrift =
1704
1794
  migFlags.progressV3toV4 ||
1795
+ migFlags.progressLegacyRouting ||
1705
1796
  migFlags.configMissingCompanyMode ||
1797
+ migFlags.configLegacyRouting ||
1706
1798
  (migFlags.memoryMissingSystemEntries && migFlags.memoryMissingSystemEntries.length) ||
1707
1799
  gotchaMissing;
1708
1800
  if (hasContentDrift) {
@@ -1715,7 +1807,7 @@ function main() {
1715
1807
  } catch {}
1716
1808
  }
1717
1809
 
1718
- // v6.0 — Brick Office dashboard one-liner
1810
+ // Brick Office dashboard one-liner
1719
1811
  console.log('');
1720
1812
  console.log('╔══════════════════════════════════════════════════════════╗');
1721
1813
  console.log('║ Brick Office — 라이브 운영 대시보드 (선택) ║');
@@ -1732,8 +1824,7 @@ function main() {
1732
1824
  log('╔═══════════════════════════════════════════════════════════╗');
1733
1825
  log('║ Restart Claude Code for skills & commands to activate! ║');
1734
1826
  log('║ ║');
1735
- log('║ Then say: "하네스 엔지니어링 시작" ║');
1736
- log('║ Or invoke: /harness-dispatcher ║');
1827
+ log('║ Then invoke /goal or /hot-fix ║');
1737
1828
  log('║ ║');
1738
1829
  log('║ 기본은 회사모드: 병렬 · 자율 진행. 추가 입력 불필요. ║');
1739
1830
  log('╚═══════════════════════════════════════════════════════════╝');
@@ -1744,6 +1835,10 @@ function main() {
1744
1835
  log(' 3. Internal agents call hired agents/skills, not slash commands.');
1745
1836
  }
1746
1837
  console.log('');
1838
+
1839
+ if (subcommand === 'init' && subcommandArgs.includes('migrate')) {
1840
+ runMigrate({ dryRun: args.includes('--dry-run') });
1841
+ }
1747
1842
  }
1748
1843
 
1749
1844
  main();
package/commands/goal.md CHANGED
@@ -18,6 +18,8 @@ Required flow:
18
18
  8. CEO must require worker report paths under `.harness/documents/{mission_name}/workers/` before accepting CXX completion.
19
19
  9. Do not invoke internal roles through slash commands; commands are Owner entrypoints only.
20
20
 
21
+ Note: Harness documents (ceo.md, cto.md, cqo.md, worker reports) are mission records, not derived output documents. A docmeta skip decision on these files does not authorize skipping any harness protocol step.
22
+
21
23
  Owner request:
22
24
 
23
25
  ```
@@ -9,14 +9,17 @@ Route the Owner request to the installed `harness-ceo` agent/skill as an emergen
9
9
 
10
10
  Required flow:
11
11
  1. Create `.harness/documents/{hotfix_name}/ceo.md`.
12
- 2. CEO summons CTO and CQO; summon COO/CDO only when planning or UX decisions are involved.
12
+ 2. CEO summons CTO and CQO first; summon COO/CDO only when planning or UX decisions are involved.
13
13
  3. CTO applies the smallest correct patch path through hired implementation skills.
14
- 4. CXX roles must not directly execute specialist deliverables. They must use hired workers for implementation, QA, ops checks, and documentation even when the fix is small.
15
- 5. If a required worker is missing, CEO or the responsible CXX must invoke the installed `harness-hiring` skill before assigning the work.
16
- 6. CQO records regression coverage and recurrence prevention with worker report paths under `.harness/documents/{hotfix_name}/workers/`.
17
- 7. Register durable lessons in `.harness/gotchas/`, `.harness/conventions/`, or `.harness/memories/` as appropriate.
18
- 8. Archive only after CQO has accepted the fix.
19
- 9. Do not invoke internal roles through slash commands; commands are Owner entrypoints only.
14
+ 4. CXX roles must start in a fresh session context. Do not let the default model impersonate a missing CXX or worker.
15
+ 5. CXX roles must not directly execute specialist deliverables. They must use hired workers for implementation, QA, ops checks, and documentation even when the fix is small.
16
+ 6. If a required worker is missing, CEO or the responsible CXX must invoke the installed `harness-hiring` skill before assigning the work.
17
+ 7. CEO must require worker report paths under `.harness/documents/{hotfix_name}/workers/` before accepting CXX completion.
18
+ 8. CQO must register durable lessons in `.harness/gotchas/`, `.harness/conventions/`, or `.harness/memories/`. This step is mandatory, not optional, even for small fixes.
19
+ 9. Archive only after CQO has accepted the fix.
20
+ 10. Do not invoke internal roles through slash commands; commands are Owner entrypoints only.
21
+
22
+ Note: Harness documents (ceo.md, cto.md, cqo.md, worker reports) are mission records, not derived output documents. A docmeta skip decision on these files does not authorize skipping any harness protocol step.
20
23
 
21
24
  Hot-fix request:
22
25
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@walwal-harness/cli",
3
- "version": "7.1.1",
3
+ "version": "7.1.3",
4
4
  "description": "Company-style AI agent harness for Claude and Codex. Installs commands, CXX agents, skills, HR-Resource hiring pool, and project-local .harness runtime state.",
5
5
  "bin": {
6
6
  "walwal-harness": "bin/init.js"
@@ -168,24 +168,24 @@ fi
168
168
  # init 상태: 첫 안내
169
169
  # ─────────────────────────────────────────
170
170
  if [ "$sprint_status" = "init" ]; then
171
- if [ "$next_agent" != "null" ] && [ "$next_agent" != "none" ] && [ "$next_agent" != "dispatcher" ]; then
171
+ if [ "$next_agent" != "null" ] && [ "$next_agent" != "none" ] && [ "$next_agent" != "ceo" ]; then
172
172
  echo "# Harness Company Mode active"
173
173
  echo "# Sprint is init, but next_agent=${next_agent}; continue the autonomous loop instead of waiting for Owner."
174
174
  else
175
- echo "# Harness ready — say \"하네스 엔지니어링 시작\" or /harness-dispatcher"
176
- echo "# 기본 경로는 회사 루프입니다: dispatch -> CEO meeting -> COO/CTO 분배 -> gen/eval -> CQO -> service-ops -> batch meeting."
175
+ echo "# Harness ready — use /goal or /hot-fix"
176
+ echo "# 기본 경로는 v7 회사 루프입니다: CEO -> 필요한 CXX -> resource-manager/hiring -> worker reports -> CXX review -> CEO report."
177
177
  exit 0
178
178
  fi
179
179
  fi
180
180
 
181
181
  # ─────────────────────────────────────────
182
- # Audit lifecycle: Planner/Dispatcher 시작 시 리셋
182
+ # Audit lifecycle: CEO 시작 시 리셋
183
183
  # ─────────────────────────────────────────
184
184
  init_audit "$PROJECT_ROOT"
185
- if [ "$next_agent" = "planner" ] || [ "$next_agent" = "dispatcher" ]; then
185
+ if [ "$next_agent" = "ceo" ]; then
186
186
  # 새 사이클 — 이전 audit을 archive로 이동하고 새로 시작
187
187
  reset_audit "$PROJECT_ROOT" "$sprint_num"
188
- audit_log "system" "cycle" "start" "sprint-${sprint_num}" "new plan/dispatch cycle"
188
+ audit_log "system" "cycle" "start" "sprint-${sprint_num}" "new CEO mission cycle"
189
189
  fi
190
190
 
191
191
  # ─────────────────────────────────────────
@@ -14,7 +14,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
14
14
  # 조건 2: opt-out 플래그 확인
15
15
  AUTO_ROUTE="true"
16
16
  if command -v jq >/dev/null 2>&1; then
17
- AUTO_ROUTE=$(jq -r '.behavior.auto_route_dispatcher // true' "$CWD/.harness/config.json" 2>/dev/null || echo "true")
17
+ AUTO_ROUTE=$(jq -r '.behavior.auto_route_ceo // .behavior.auto_route_dispatcher // true' "$CWD/.harness/config.json" 2>/dev/null || echo "true")
18
18
  fi
19
19
  if [ "$AUTO_ROUTE" != "true" ]; then exit 0; fi
20
20
 
@@ -114,13 +114,13 @@ cat <<EOF
114
114
  [harness] company | S${SPRINT_NUM} | ${PIPELINE} | agent=${CURRENT_AGENT} (${AGENT_STATUS}) | next=${NEXT_AGENT} | queue=${T_PASSED}/${T_TOTAL} passed | failed=${T_FAILED}
115
115
  ${CONTEXT_WARNING}
116
116
  ## Route
117
- - pipeline=none/dispatcher 미실행 → harness-dispatcher 스킬 호출
118
- - 기본 경로는 conductor 중심 회사 루프다: dispatch -> CEO meeting -> planner(COO) -> cto -> gen/eval -> cqo -> service-ops -> batch meeting
119
- - worker pool(기본 3)이 자율적으로 Gen→Eval 루프 실행 중이며 control-plane은 이 상한에 포함되지 않는다
117
+ - pipeline=none/init → harness-ceo 스킬로 Owner goal/hot-fix를 접수하고 mission 문서를 생성
118
+ - 기본 경로는 v7 CXX 회사 루프다: CEO -> COO/CDO/CTO/CQO/OPS -> harness-resource-manager -> harness-hiring -> hired workers -> CXX review -> CEO report
119
+ - CXX는 직접 전문 산출물을 만들지 않고 worker report를 `.harness/documents/{mission}/workers/`에 남겨야 한다
120
120
  - Owner에게 "계속 진행", "진행할까요?", "다음 명령을 입력하세요"를 요구하지 않는다. GOAL이 있고 escalation이 아니면 즉시 next_agent/current_agent 업무를 수행한다
121
121
  - Owner 입력은 목표 변경·사고·결과 확인용이지 회사 진행을 펌프하는 신호가 아니다
122
- - conductor 는 Planner 직행 대신 meeting-manager / cto / cqo / service-ops 로 next_agent를 재작성할 수 있다
123
- - 기능 요청 → pipeline flow | 실수 지적 → gotcha flow | 메타 질문 → 짧게 응답 (skip)
122
+ - CEO는 필요한 CXX만 호출하고, CXX는 resource-manager/hiring 없이 worker 업무를 수행하지 않는다
123
+ - 기능 요청 → CEO mission flow | 긴급 수정 → hot-fix flow | 메타 질문 → 짧게 응답 (skip)
124
124
  - 활성 pipeline → next_agent/current_agent 컨텍스트로 계속
125
125
  - skip: "harness skip", "just answer" 등 명시 시 단일 메시지 건너뜀
126
126
  EOF
@@ -1,22 +0,0 @@
1
- ---
2
- description: Run the harness play build and notify OPS monitoring.
3
- argument-hint: "[additional play args]"
4
- ---
5
-
6
- # /play-harness
7
-
8
- Run the target project's harness play mode.
9
-
10
- Required flow:
11
- 1. Confirm `.harness/` exists in the current project.
12
- 2. Run `bash scripts/play.sh $ARGUMENTS`.
13
- 3. Treat play mode and release mode as mutually exclusive. If release mode is active, stop it first with `/stop-harness` or report the conflict to the Owner.
14
- 4. After the script returns, read the emitted OPS report path and notify the installed `harness-ops` skill/agent that play monitoring has started.
15
- 5. Record the build result in `.harness/documents/{mission_name}/ops.md` when a mission is active.
16
- 6. Do not route this through `/goal`; this command is an Owner-facing runtime control entrypoint.
17
-
18
- Play arguments:
19
-
20
- ```
21
- $ARGUMENTS
22
- ```
@@ -1,22 +0,0 @@
1
- ---
2
- description: Run the harness release build, start service operation, and notify OPS monitoring.
3
- argument-hint: "[additional release args]"
4
- ---
5
-
6
- # /release-harness
7
-
8
- Run the target project's harness release mode and begin service operation.
9
-
10
- Required flow:
11
- 1. Confirm `.harness/` exists in the current project.
12
- 2. Run `bash scripts/release.sh release $ARGUMENTS`.
13
- 3. Treat play mode and release mode as mutually exclusive. If play mode is active, stop it first with `/stop-harness` or report the conflict to the Owner.
14
- 4. After the script returns, read the emitted OPS report path and notify the installed `harness-ops` skill/agent that release monitoring has started.
15
- 5. Record the release result in `.harness/documents/{mission_name}/ops.md` when a mission is active.
16
- 6. Do not route this through `/goal`; this command is an Owner-facing runtime control entrypoint.
17
-
18
- Release arguments:
19
-
20
- ```
21
- $ARGUMENTS
22
- ```
@@ -1,21 +0,0 @@
1
- ---
2
- description: Stop any harness play or release process/session.
3
- argument-hint: "[optional stop reason]"
4
- ---
5
-
6
- # /stop-harness
7
-
8
- Stop any active harness play or release runtime.
9
-
10
- Required flow:
11
- 1. Confirm `.harness/` exists in the current project.
12
- 2. Run `bash scripts/harness-runtime-stop.sh $ARGUMENTS`.
13
- 3. Verify both play and release runtime state files are cleared or marked stopped.
14
- 4. Notify the installed `harness-ops` skill/agent that monitoring should stop for the terminated runtime mode.
15
- 5. Record the stop result in `.harness/documents/{mission_name}/ops.md` when a mission is active.
16
-
17
- Stop reason:
18
-
19
- ```
20
- $ARGUMENTS
21
- ```