@walwal-harness/cli 6.1.1 → 6.1.2
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/CHANGELOG.md +8 -0
- package/README.md +305 -368
- package/assets/templates/config.json +7 -0
- package/assets/templates/progress.json.template +13 -0
- package/package.json +1 -1
- package/scripts/harness-session-start.sh +54 -0
- package/scripts/harness-token-limit.sh +99 -0
- package/scripts/harness-user-prompt-submit.sh +23 -0
package/CHANGELOG.md
CHANGED
|
@@ -29,6 +29,14 @@ docmeta:
|
|
|
29
29
|
|
|
30
30
|
# Changelog
|
|
31
31
|
|
|
32
|
+
## 6.1.2 — TokenLimit hold/resume checker (2026-05-08)
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- `TaskStopReason: TokenLimit` 기반의 저비용 작업 재개 플로우 추가
|
|
36
|
+
- `scripts/harness-token-limit.sh mark|resume-probe` 도입
|
|
37
|
+
- SessionStart / UserPromptSubmit 가 TokenLimit hold 를 감지해 전체 작업 중지 및 재개 타이밍을 안내
|
|
38
|
+
- `progress.json.task_stop` 과 `config.token_limit` 필드 추가
|
|
39
|
+
|
|
32
40
|
## 6.1.1 — COO hypothesis routing activation (2026-05-08)
|
|
33
41
|
|
|
34
42
|
### Why
|
package/README.md
CHANGED
|
@@ -1,499 +1,436 @@
|
|
|
1
1
|
# @walwal-harness/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AI 에이전트 개발을 위한 회사형 하네스 프레임워크.
|
|
4
|
+
|
|
5
|
+
walwal-harness 는 단일 에이전트를 오래 붙잡는 대신, 문서와 상태 파일을 기준으로 여러 역할을 이어 붙입니다.
|
|
6
|
+
핵심 개념은 "하나의 프로젝트 = 하나의 회사" 입니다.
|
|
7
|
+
|
|
8
|
+
- Owner: 사용자
|
|
9
|
+
- Dispatcher: CEO, 유일한 대화 창구
|
|
10
|
+
- Planner: COO, 기획·가설·HR
|
|
11
|
+
- CTO: 구현 총괄
|
|
12
|
+
- CQO: 품질 총괄
|
|
13
|
+
- Service-Ops: 운영·모니터링·회고
|
|
14
|
+
- Conductor: 자율 라우터
|
|
15
|
+
- Meeting-Manager: 회의 소집기
|
|
16
|
+
|
|
17
|
+
이 프레임워크는 Anthropic 의 harness engineering 방향과 NEXUS-style company loop 를 walwal-harness 구조에 맞게 재해석한 것입니다.
|
|
18
|
+
|
|
19
|
+
## 핵심 원칙
|
|
20
|
+
|
|
21
|
+
- 에이전트는 대화 기억보다 문서 팩트를 우선합니다.
|
|
22
|
+
- 작업 전환은 항상 `progress.json`, `handoff.json`, `task session` 을 기준으로 이뤄집니다.
|
|
23
|
+
- 회의는 동기화와 의사결정에 쓰고, 단순 런타임 복구는 값싼 상태 기반 로직으로 처리합니다.
|
|
24
|
+
- TokenLimit, retry, drift, handoff 같은 운영 문제를 코드가 아니라 하네스 레벨에서 다룹니다.
|
|
25
|
+
|
|
26
|
+
## 회사 구조
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
Owner
|
|
30
|
+
↕
|
|
31
|
+
Dispatcher (CEO)
|
|
32
|
+
├─ Conductor
|
|
33
|
+
└─ Meeting-Manager
|
|
34
|
+
↓
|
|
35
|
+
Planner (COO + HR)
|
|
36
|
+
├─ COO Hypothesis Cell
|
|
37
|
+
│ ├─ coo-developer
|
|
38
|
+
│ └─ documentationer
|
|
39
|
+
├─ CTO
|
|
40
|
+
│ ├─ generator-backend
|
|
41
|
+
│ ├─ generator-frontend
|
|
42
|
+
│ ├─ generator-designer
|
|
43
|
+
│ └─ generator-devops
|
|
44
|
+
├─ CQO
|
|
45
|
+
│ ├─ evaluator-code-quality
|
|
46
|
+
│ ├─ evaluator-functional
|
|
47
|
+
│ ├─ evaluator-visual
|
|
48
|
+
│ ├─ evaluator-architecture
|
|
49
|
+
│ └─ evaluator-security
|
|
50
|
+
└─ Service-Ops
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 각 부서가 하는 일
|
|
54
|
+
|
|
55
|
+
- `Dispatcher`: 사용자 요청을 회사가 처리할 목표와 루프로 변환
|
|
56
|
+
- `Meeting-Manager`: Standup, Sprint Review, Spec Review, Incident War Room, All-Hands 소집
|
|
57
|
+
- `Conductor`: 다음 owner 와 next agent 를 재결정
|
|
58
|
+
- `Planner`: 스펙, feature-list, api-contract, 가설 검증 셀 운영
|
|
59
|
+
- `CTO`: 구현 라인 총괄, hotfix/기술 판단
|
|
60
|
+
- `CQO`: 적대적 평가와 회귀 차단
|
|
61
|
+
- `Service-Ops`: cadence, 운영 drift, auto-retro
|
|
62
|
+
- `coo-developer`: 빠른 spike, backdata 검증
|
|
63
|
+
- `documentationer`: 웹 리서치, 실험 보고서, 가설 유효/무효 판정
|
|
4
64
|
|
|
5
|
-
|
|
6
|
-
> — [Anthropic Engineering Blog](https://www.anthropic.com/engineering/harness-design-long-running-apps)
|
|
7
|
-
|
|
8
|
-
같은 AI 모델이라도 **하네스 설계에 따라 결과물 품질이 극적으로 달라집니다.** walwal-harness는 Anthropic이 제안한 하네스 엔지니어링 패턴을 설치 한 번으로 즉시 사용할 수 있게 패키징한 프레임워크입니다.
|
|
9
|
-
|
|
10
|
-
---
|
|
65
|
+
## 설치
|
|
11
66
|
|
|
12
|
-
|
|
67
|
+
프로젝트 루트에서:
|
|
13
68
|
|
|
14
|
-
|
|
69
|
+
```bash
|
|
70
|
+
npm i @walwal-harness/cli
|
|
71
|
+
```
|
|
15
72
|
|
|
16
|
-
|
|
73
|
+
설치 후 Claude Code 를 재시작합니다.
|
|
17
74
|
|
|
18
|
-
|
|
75
|
+
초기화가 필요하면:
|
|
19
76
|
|
|
20
|
-
```
|
|
21
|
-
|
|
77
|
+
```bash
|
|
78
|
+
npx walwal-harness
|
|
22
79
|
```
|
|
23
80
|
|
|
24
|
-
|
|
25
|
-
- 요청을 분류 (기능 요청 / 실수 지적 / 메타 질문)
|
|
26
|
-
- `FULLSTACK` / `FE-ONLY` / `BE-ONLY` 파이프라인 결정 → `actions/pipeline.json`
|
|
27
|
-
- 신규/재플래닝이면 "Brainstormer 를 거칠지" 한 번 묻고 `next_agent` 설정 후 STOP
|
|
81
|
+
기존 설치를 현재 패키지 버전에 맞게 다시 정리하려면:
|
|
28
82
|
|
|
29
|
-
|
|
83
|
+
```bash
|
|
84
|
+
npx walwal-harness --force
|
|
85
|
+
```
|
|
30
86
|
|
|
31
|
-
|
|
87
|
+
## 시작 방법
|
|
32
88
|
|
|
33
|
-
새
|
|
89
|
+
새 Claude Code 세션의 첫 메시지:
|
|
34
90
|
|
|
35
|
-
```
|
|
36
|
-
|
|
91
|
+
```text
|
|
92
|
+
하네스 엔지니어링 시작
|
|
37
93
|
```
|
|
38
94
|
|
|
39
|
-
|
|
95
|
+
기본 흐름:
|
|
40
96
|
|
|
41
|
-
|
|
97
|
+
1. `dispatcher` 가 요청을 분류하고 pipeline/runbook 을 정합니다.
|
|
98
|
+
2. 필요하면 `meeting-manager` 가 CEO intake 회의를 엽니다.
|
|
99
|
+
3. `planner` 가 `plan.md`, `feature-list.json`, `api-contract.json` 을 만듭니다.
|
|
100
|
+
4. `conductor` 가 회사 루프에 따라 CTO/CQO/Service-Ops/Meeting 으로 라우팅합니다.
|
|
101
|
+
5. generator / evaluator / cqo / ops 가 문서 기반으로 이어집니다.
|
|
42
102
|
|
|
43
|
-
|
|
103
|
+
## 상태 파일
|
|
44
104
|
|
|
45
|
-
|
|
46
|
-
|------|------|------|
|
|
47
|
-
| **Solo** | 프롬프트로 `/harness-generator-backend` → `/harness-generator-frontend` → `/harness-evaluator-*` 순차 호출 | 학습 목적 · feature 3개 이하 · 레이아웃이 좁음 |
|
|
48
|
-
| **Team** | `/harness-team` | feature 4개 이상 · 병렬로 확 밀고 싶을 때 |
|
|
105
|
+
하네스의 기준 상태는 `.harness/` 아래에 있습니다.
|
|
49
106
|
|
|
50
|
-
|
|
107
|
+
| 파일 | 역할 |
|
|
108
|
+
|---|---|
|
|
109
|
+
| `.harness/progress.json` | 현재 회사 상태의 단일 기준 |
|
|
110
|
+
| `.harness/handoff.json` | 다음 agent 실행 문서 |
|
|
111
|
+
| `.harness/progress.log` | 사람 읽기용 활동 로그 |
|
|
112
|
+
| `.harness/actions/` | 활성 sprint 문서 |
|
|
113
|
+
| `.harness/archive/` | 완료 sprint 보관 |
|
|
51
114
|
|
|
52
|
-
|
|
115
|
+
### 중요한 progress 필드
|
|
53
116
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
117
|
+
- `current_agent`, `agent_status`, `next_agent`
|
|
118
|
+
- `workflow.stage`
|
|
119
|
+
- `meetings.*`
|
|
120
|
+
- `task_sessions.current`
|
|
121
|
+
- `task_stop.*`
|
|
122
|
+
- `goals.*`
|
|
123
|
+
- `conductor.*`, `planner.*`, `cto.*`, `cqo.*`, `service_ops.*`
|
|
57
124
|
|
|
58
|
-
|
|
59
|
-
npx walwal-harness team
|
|
60
|
-
```
|
|
125
|
+
## Task Session
|
|
61
126
|
|
|
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회 초과 실패하면 사용자 개입 요청
|
|
127
|
+
각 agent 전환 시 `.harness/actions/task-sessions/<agent>/...md` 가 생성됩니다.
|
|
68
128
|
|
|
69
|
-
|
|
129
|
+
목적:
|
|
70
130
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
│ - feature 진행도 ├───────────────┤ │
|
|
76
|
-
│ - queue 상태 │ Conventions ├───────────┤
|
|
77
|
-
│ │ (하우스 스타일)│ TEAM 2 │
|
|
78
|
-
├────────────────────┤ │ Gen|Eval │
|
|
79
|
-
│ Archive Prompt ├───────────────┤ │
|
|
80
|
-
│ (완료 feature 요약)│ Memory ├───────────┤
|
|
81
|
-
│ │ (공유 교훈) │ TEAM 3 │
|
|
82
|
-
│ │ │ Gen|Eval │
|
|
83
|
-
└────────────────────┴───────────────┴───────────┘
|
|
84
|
-
```
|
|
131
|
+
- 이전 채팅 문맥을 들고 가지 않기
|
|
132
|
+
- 자기편향적 사고를 줄이기
|
|
133
|
+
- 사실과 추론을 분리하기
|
|
134
|
+
- 재개 시에도 문서 기준으로만 이어가기
|
|
85
135
|
|
|
86
|
-
|
|
87
|
-
|------|------|------|
|
|
88
|
-
| **Dashboard** | Pipeline · Sprint · Feature passes · Queue R:B:P · Retry | `harness-dashboard.sh` |
|
|
89
|
-
| **Gotchas** | 활성 에이전트의 누적 실수 (`[G-NNN]`) — v5.9.1 부터 독립 패널 | `harness-gotcha-memory.sh --mode gotcha` |
|
|
90
|
-
| **Conventions** | 하우스 스타일 (`[C-NNN]`) — v5.9.1 부터 독립 패널, 독립 스크롤 | `harness-gotcha-memory.sh --mode conventions` |
|
|
91
|
-
| **Memory** | 공유 교훈 (`memory.md`) — v5.9.1 부터 독립 패널 | `harness-gotcha-memory.sh --mode memory` |
|
|
92
|
-
| **TEAM 1–3** | 각 워커의 현재 feature · phase(Gen/Eval) · 실시간 stdout | `harness-queue-manager.sh` worker loop |
|
|
93
|
-
| **Archive Prompt** | 직전 완료 feature 요약 (다음 팀 컨텍스트 주입용) | archive 디렉토리 |
|
|
136
|
+
에이전트는 task session, handoff, progress 를 단일 사실원으로 사용해야 합니다.
|
|
94
137
|
|
|
95
|
-
|
|
138
|
+
## 회의 시스템
|
|
96
139
|
|
|
97
|
-
|
|
140
|
+
회의는 계속 유지됩니다. 토큰 제한 복구 로직이 회의를 대체하지 않습니다.
|
|
98
141
|
|
|
99
|
-
|
|
100
|
-
|--------|------|------|
|
|
101
|
-
| `●` (녹색) | PASS | Evaluator 통과 · merge 완료 |
|
|
102
|
-
| `◐` (청색) | IN PROGRESS | 현재 team 배정됨 (phase 표기: T1:gen / T2:eval) |
|
|
103
|
-
| `○` (노랑) | READY | 의존성 해소됨 · idle team 배정 대기 |
|
|
104
|
-
| `◍` (자색) | **BLOCKED** | 선행 feature 대기 · deps 개수 함께 표시 |
|
|
105
|
-
| `◌` (어두움) | PENDING | 아직 큐 미등록 (sprint 미진입 or 사전 분석 단계) |
|
|
106
|
-
| `✗` (빨강) | FAILED | 재시도 한도 도달 · 사용자 개입 필요 |
|
|
142
|
+
지원 회의:
|
|
107
143
|
|
|
108
|
-
|
|
144
|
+
- `Standup`
|
|
145
|
+
- `Sprint Review`
|
|
146
|
+
- `Spec Review`
|
|
147
|
+
- `Incident War Room`
|
|
148
|
+
- `All-Hands`
|
|
109
149
|
|
|
110
|
-
|
|
150
|
+
역할:
|
|
111
151
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
152
|
+
- 회의: owner 결정, drift 분류, evidence 집계, action item 생성
|
|
153
|
+
- Conductor: 회의 결과를 읽고 next agent 갱신
|
|
154
|
+
- Service-Ops: cadence 계산
|
|
115
155
|
|
|
116
|
-
|
|
117
|
-
# → {"idle_teams":["3"], "ready_features":["F-003","F-004"], "dispatchable":1}
|
|
118
|
-
```
|
|
156
|
+
기본 cadence:
|
|
119
157
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
158
|
+
- `light`: 30m
|
|
159
|
+
- `normal`: 1h
|
|
160
|
+
- `heavy`: 4h
|
|
123
161
|
|
|
124
|
-
|
|
162
|
+
## TokenLimit Hold / Resume
|
|
125
163
|
|
|
126
|
-
|
|
164
|
+
`TokenLimit` 은 회의가 아니라 런타임 중단 복구 문제로 취급합니다.
|
|
127
165
|
|
|
128
|
-
|
|
129
|
-
|------|------|--------|----------|-----|
|
|
130
|
-
| **Gotcha** | 에이전트 실수(부정) | "~하지 마", "잘못됐어" | `.harness/gotchas/<agent>.md` | `G-NNN` |
|
|
131
|
-
| **Convention** | 하우스 스타일(긍정) | "~해야 해", "이렇게 해줘" | `.harness/conventions/<scope>.md` | `C-NNN` |
|
|
132
|
-
| **Memory** | 전체 공통 교훈 | "모든 에이전트가~" | `.harness/memory.md` | `M-NNN` |
|
|
166
|
+
즉:
|
|
133
167
|
|
|
134
|
-
|
|
168
|
+
- 회의 시스템은 그대로 유지
|
|
169
|
+
- TokenLimit 은 별도 저비용 복구 레이어로 처리
|
|
135
170
|
|
|
136
|
-
|
|
171
|
+
### 동작 방식
|
|
137
172
|
|
|
138
|
-
|
|
173
|
+
토큰 한도로 작업이 중단되면:
|
|
139
174
|
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
실제 DB 에 붙으려고 하는데, npm run dev 에서 MockServer 가 concurrent 로
|
|
143
|
-
기동되어 있으니 그걸 먼저 확인하고 써.
|
|
175
|
+
```bash
|
|
176
|
+
bash scripts/harness-token-limit.sh . mark
|
|
144
177
|
```
|
|
145
178
|
|
|
146
|
-
|
|
147
|
-
- **대상 에이전트**: `generator-backend`
|
|
148
|
-
- **저장 위치**: `.harness/gotchas/generator-backend.md`
|
|
149
|
-
- **ID 할당**: `[G-002]` (기존 항목 다음 번호)
|
|
150
|
-
|
|
151
|
-
#### 기록 포맷 (Dispatcher 가 자동 작성)
|
|
152
|
-
|
|
153
|
-
```markdown
|
|
154
|
-
### [G-002] MockServer + npm run dev 자동 기동 + OpenAPI 동기화
|
|
155
|
-
- **Date**: 2026-04-22
|
|
156
|
-
- **Severity**: HIGH
|
|
157
|
-
- **Occurrences**: 1
|
|
158
|
-
- **Symptom**: 실제 DB 연결 시도 → 연결 실패로 스프린트 중단
|
|
159
|
-
- **Rule**: `npm run dev` 는 MockServer 를 concurrent 로 기동한다.
|
|
160
|
-
API 호출 전 `http://localhost:3001/health` 를 확인할 것.
|
|
161
|
-
- **Applies to**: generator-backend
|
|
162
|
-
```
|
|
179
|
+
기본 정책:
|
|
163
180
|
|
|
164
|
-
|
|
181
|
+
- `TaskStopReason = TokenLimit`
|
|
182
|
+
- 현재 작업은 `paused`
|
|
183
|
+
- `progress.json.task_stop` 에 아래가 기록됨
|
|
184
|
+
- `wake_target`
|
|
185
|
+
- `resume_after`
|
|
186
|
+
- `stopped_agent`
|
|
187
|
+
- `stopped_next_agent`
|
|
188
|
+
- `task_session_path`
|
|
165
189
|
|
|
166
|
-
|
|
190
|
+
그 다음:
|
|
167
191
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
192
|
+
- `SessionStart` 는 별도 모델 probe 없이 시간만 확인
|
|
193
|
+
- 아직 hold 중이면 `retry_after` 와 `wake target` 만 출력
|
|
194
|
+
- 시간이 지나면 `# Harness resume ready` 를 출력하고 원래 CXX/agent 로 복귀
|
|
195
|
+
|
|
196
|
+
테스트용:
|
|
172
197
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
- **저장 위치**: `.harness/conventions/generator-backend.md`
|
|
176
|
-
- **ID 할당**: `[C-001]` (해당 파일의 기존 최댓값 + 1)
|
|
177
|
-
|
|
178
|
-
기록 포맷 (자동 작성):
|
|
179
|
-
|
|
180
|
-
```markdown
|
|
181
|
-
### [C-001] API 응답 필드는 snake_case
|
|
182
|
-
- **Date**: 2026-04-22
|
|
183
|
-
- **Scope**: generator-backend
|
|
184
|
-
- **Rule**: 모든 API 응답 JSON 필드는 snake_case (created_at, user_id 등).
|
|
185
|
-
- **Rationale**: FE TS 모델이 snake_case 로 정의돼 있어 변환 레이어 불필요.
|
|
186
|
-
- **Applies to**: generator-backend, libs/shared-dto
|
|
187
|
-
- **Added from**: user prompt (2026-04-22 16:12)
|
|
198
|
+
```bash
|
|
199
|
+
bash scripts/harness-token-limit.sh . mark 300
|
|
188
200
|
```
|
|
189
201
|
|
|
190
|
-
|
|
202
|
+
중요:
|
|
191
203
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
| frontend, React, Next.js, UI, component, hook | `generator-frontend.md` |
|
|
196
|
-
| plan, sprint, feature-list | `planner.md` |
|
|
197
|
-
| Playwright, E2E, browser | `evaluator-functional.md` |
|
|
198
|
-
| layout, screenshot, a11y, responsive | `evaluator-visual.md` |
|
|
199
|
-
| code quality, lint, architecture | `evaluator-code-quality.md` |
|
|
200
|
-
| 매칭 실패 + 에이전트 국한 | `shared.md` |
|
|
201
|
-
| 프로젝트 철학 (예: "우리는 TDD") | 루트 `CONVENTIONS.md` 권고 |
|
|
204
|
+
- 회의는 유지됩니다.
|
|
205
|
+
- TokenLimit checker 는 회의를 대체하지 않습니다.
|
|
206
|
+
- 에이전트는 복귀 시 이전 대화가 아니라 `task_session_path` 와 문서를 보고 이어갑니다.
|
|
202
207
|
|
|
203
|
-
|
|
208
|
+
## COO Hypothesis Cell
|
|
204
209
|
|
|
205
|
-
|
|
210
|
+
정규 CTO/CQO 라인에 넣기 전, COO 직속으로 빠른 가설 검증 셀을 돌릴 수 있습니다.
|
|
206
211
|
|
|
207
|
-
|
|
208
|
-
1. CONVENTIONS.md (루트, 최상위 원칙)
|
|
209
|
-
2. .harness/conventions/shared.md (공통)
|
|
210
|
-
3. .harness/conventions/<self>.md (자기 스코프)
|
|
211
|
-
4. .harness/gotchas/<self>.md (과거 실수)
|
|
212
|
-
5. .harness/memory.md (공유 교훈)
|
|
213
|
-
```
|
|
212
|
+
구성:
|
|
214
213
|
|
|
215
|
-
|
|
214
|
+
- `coo-developer`
|
|
215
|
+
- `documentationer`
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
흐름:
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
1. `planner.requested_mode = "hypothesis"`
|
|
220
|
+
2. `documentationer` 가 리서치/질문 정리
|
|
221
|
+
3. `coo-developer` 가 spike / backdata 실험
|
|
222
|
+
4. `documentationer` 가 보고서와 verdict 작성
|
|
223
|
+
5. `planner` 가 결과를 정규 sprint artifact 로 승격하거나 폐기
|
|
220
224
|
|
|
221
|
-
|
|
222
|
-
이건 특정 Generator 실수가 아니라 이 프로젝트 공통 규칙이야 —
|
|
223
|
-
모든 테스트는 MockServer seed data 기반이어야 한다는 걸
|
|
224
|
-
메모리에 올려줘.
|
|
225
|
-
```
|
|
225
|
+
핵심은 운영 품질이 아니라 빠른 사실 확인입니다.
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
## 모드
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
### Company / Team
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
기본 경로입니다. Conductor 가 `mode=auto` 에서 선택합니다.
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
특징:
|
|
234
|
+
|
|
235
|
+
- 회사형 루프 유지
|
|
236
|
+
- control-plane 과 worker-plane 분리
|
|
237
|
+
- feature queue 기반 병렬 처리
|
|
238
|
+
- tmux studio 사용 가능
|
|
236
239
|
|
|
237
|
-
|
|
240
|
+
강제 전환:
|
|
238
241
|
|
|
239
|
-
|
|
242
|
+
```text
|
|
243
|
+
/harness-team
|
|
244
|
+
```
|
|
240
245
|
|
|
241
|
-
|
|
246
|
+
### Solo
|
|
242
247
|
|
|
243
|
-
|
|
248
|
+
비상용 fallback 입니다.
|
|
244
249
|
|
|
245
|
-
|
|
250
|
+
사용 시점:
|
|
246
251
|
|
|
247
|
-
-
|
|
248
|
-
-
|
|
249
|
-
-
|
|
250
|
-
- **리포트** → `.harness/MIGRATION_REPORT.md` 에 이관 내역 + 수동 확인 요청 사항 기록
|
|
252
|
+
- 디버깅
|
|
253
|
+
- 스크립트 장애
|
|
254
|
+
- 짧은 수동 복구
|
|
251
255
|
|
|
252
|
-
|
|
256
|
+
강제 전환:
|
|
253
257
|
|
|
254
|
-
|
|
258
|
+
```text
|
|
259
|
+
/harness-solo
|
|
260
|
+
```
|
|
255
261
|
|
|
256
|
-
|
|
262
|
+
### Stop
|
|
257
263
|
|
|
258
|
-
|
|
264
|
+
Team 모드를 안전하게 멈추고 진행 중이던 feature 를 ready 로 복구합니다.
|
|
259
265
|
|
|
260
|
-
|
|
266
|
+
```text
|
|
267
|
+
/harness-stop
|
|
268
|
+
```
|
|
261
269
|
|
|
262
|
-
|
|
263
|
-
|------|------|----------|
|
|
264
|
-
| **Solo** | 순차 실행 — 프롬프트 기반으로 Planner → Generator → Evaluator 순서대로 진행 | `/harness-solo` 또는 프롬프트로 진행 |
|
|
265
|
-
| **Team** | 병렬 실행 — 3 Team이 Feature 단위 Gen→Eval 루프를 자동 핸즈오프로 동시 실행 | `/harness-team` 또는 `npx walwal-harness team` |
|
|
270
|
+
## Team Studio
|
|
266
271
|
|
|
267
|
-
|
|
272
|
+
Team 모드에서는 tmux 기반 Studio 레이아웃을 사용합니다.
|
|
268
273
|
|
|
269
|
-
|
|
274
|
+
시작:
|
|
270
275
|
|
|
271
|
-
|
|
276
|
+
```text
|
|
277
|
+
/harness-team
|
|
278
|
+
```
|
|
272
279
|
|
|
273
|
-
|
|
280
|
+
또는:
|
|
274
281
|
|
|
275
282
|
```bash
|
|
276
|
-
|
|
277
|
-
npm install @walwal-harness/cli
|
|
283
|
+
npx walwal-harness team
|
|
278
284
|
```
|
|
279
285
|
|
|
280
|
-
|
|
281
|
-
1. `.harness/` 디렉토리 스캐폴딩
|
|
282
|
-
2. `.claude/skills/` 에 에이전트 스킬 설치 (8개)
|
|
283
|
-
3. `.claude/commands/` 에 모드 제어 커맨드 설치 (3개)
|
|
284
|
-
4. `scripts/` 에 오케스트레이션 스크립트 설치
|
|
285
|
-
5. SessionStart / UserPromptSubmit 훅 등록
|
|
286
|
-
6. `AGENTS.md` + `CLAUDE.md` 심볼릭 링크 생성
|
|
286
|
+
Team Studio 는 보통 다음을 보여줍니다.
|
|
287
287
|
|
|
288
|
-
|
|
288
|
+
- Dashboard
|
|
289
|
+
- Gotchas
|
|
290
|
+
- Conventions
|
|
291
|
+
- Memory
|
|
292
|
+
- Team 1~3 worker pane
|
|
293
|
+
- Archive prompt
|
|
289
294
|
|
|
290
|
-
|
|
295
|
+
Queue 관련 유용한 명령:
|
|
291
296
|
|
|
292
297
|
```bash
|
|
293
|
-
|
|
298
|
+
bash scripts/harness-queue-manager.sh status .
|
|
299
|
+
bash scripts/harness-queue-manager.sh auto-dispatch .
|
|
300
|
+
bash scripts/harness-queue-manager.sh idle-slots .
|
|
294
301
|
```
|
|
295
302
|
|
|
296
|
-
|
|
303
|
+
## Generator / Evaluator Chain
|
|
297
304
|
|
|
298
|
-
|
|
305
|
+
구현과 평가는 분리됩니다.
|
|
299
306
|
|
|
300
|
-
|
|
301
|
-
npx walwal-harness # 초기화 / 스크립트 업데이트
|
|
302
|
-
npx walwal-harness --force # 강제 재초기화
|
|
303
|
-
npx walwal-harness team # Team Mode tmux 레이아웃 실행
|
|
304
|
-
npx walwal-harness team --kill # Team Mode tmux 세션 종료
|
|
305
|
-
npx walwal-harness --help # 도움말
|
|
306
|
-
```
|
|
307
|
+
일반적인 흐름:
|
|
307
308
|
|
|
308
|
-
|
|
309
|
+
1. `generator-backend`
|
|
310
|
+
2. `generator-frontend`
|
|
311
|
+
3. `evaluator-code-quality`
|
|
312
|
+
4. `evaluator-functional`
|
|
313
|
+
5. `evaluator-visual`
|
|
314
|
+
6. `cqo`
|
|
315
|
+
7. `service-ops`
|
|
309
316
|
|
|
310
|
-
|
|
317
|
+
평가자 체인 원칙:
|
|
311
318
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
| **Planner** | 제품 사양 + API 계약서 + 서비스 분할 | opus |
|
|
317
|
-
| **Generator-Backend** | NestJS MSA 서비스 구현 | sonnet |
|
|
318
|
-
| **Generator-Frontend** | React/Next.js UI 구현 | sonnet |
|
|
319
|
-
| **Evaluator-Code-Quality** | 코드 유지보수성/아키텍처/Best Practice (BE/FE/libs 공통, 브라우저 없음) | opus |
|
|
320
|
-
| **Evaluator-Functional** | Playwright E2E 기능 검증 · API 계약 준수 | opus |
|
|
321
|
-
| **Evaluator-Visual** | 레이아웃/접근성/AI슬롭 검증 | opus |
|
|
319
|
+
- 앞단 FAIL 시 뒤 평가는 생략 가능
|
|
320
|
+
- Evidence 없는 점수는 0
|
|
321
|
+
- regression 1건 이상이면 전체 FAIL
|
|
322
|
+
- evaluator 는 읽기 전용
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
## Gotchas / Conventions / Memory
|
|
324
325
|
|
|
325
|
-
|
|
326
|
+
하네스는 피드백을 세 저장소로 나눠 누적합니다.
|
|
326
327
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
→ Archive
|
|
333
|
-
```
|
|
328
|
+
| 종류 | 용도 |
|
|
329
|
+
|---|---|
|
|
330
|
+
| `gotchas/` | 에이전트가 반복한 실수 |
|
|
331
|
+
| `.harness/conventions/` | 하우스 스타일 |
|
|
332
|
+
| `.harness/memory.md` | 프로젝트 전역 교훈 |
|
|
334
333
|
|
|
335
|
-
|
|
334
|
+
각 agent 는 세션 시작 시 다음 순서로 읽습니다.
|
|
336
335
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
1. `CONVENTIONS.md`
|
|
337
|
+
2. `.harness/conventions/shared.md`
|
|
338
|
+
3. `.harness/conventions/<self>.md`
|
|
339
|
+
4. `.harness/gotchas/<self>.md`
|
|
340
|
+
5. `.harness/memory.md`
|
|
342
341
|
|
|
343
|
-
|
|
344
|
-
- PASS: Weighted Score ≥ 2.80 / 3.00
|
|
345
|
-
- AC 100% 충족 필수 (부분 통과 = FAIL)
|
|
346
|
-
- Regression 실패 1건+ = FAIL (이전 Sprint PASS 기능 재검증)
|
|
347
|
-
- Evidence 없는 Score = 0점 강제 재계산
|
|
348
|
-
- Cross-Validation 불일치 1건+ = CONDITIONAL FAIL
|
|
349
|
-
- Team Mode: 최대 5회 재시도 후 사용자 개입 요청
|
|
342
|
+
## 주요 스크립트
|
|
350
343
|
|
|
351
|
-
|
|
344
|
+
| 스크립트 | 역할 |
|
|
345
|
+
|---|---|
|
|
346
|
+
| `scripts/harness-next.sh` | handoff 생성과 다음 agent 결정 |
|
|
347
|
+
| `scripts/conductor-tick.sh` | company loop 라우팅 |
|
|
348
|
+
| `scripts/harness-session-start.sh` | 새 세션 시작 시 자동 안내 |
|
|
349
|
+
| `scripts/harness-user-prompt-submit.sh` | prompt 훅 주입/차단 |
|
|
350
|
+
| `scripts/harness-task-session.sh` | agent 별 task session 생성 |
|
|
351
|
+
| `scripts/harness-token-limit.sh` | TokenLimit hold/resume 마킹 |
|
|
352
|
+
| `scripts/harness-queue-manager.sh` | team queue 관리 |
|
|
353
|
+
| `scripts/harness-dashboard.sh` | dashboard 렌더 |
|
|
354
|
+
| `scripts/harness-meeting-doc.sh` | 회의 문서 skeleton / decision 처리 |
|
|
352
355
|
|
|
353
|
-
##
|
|
356
|
+
## 디렉토리 구조
|
|
354
357
|
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
358
|
+
```text
|
|
359
|
+
.harness/
|
|
360
|
+
├── actions/
|
|
361
|
+
│ ├── plan.md
|
|
362
|
+
│ ├── feature-list.json
|
|
363
|
+
│ ├── api-contract.json
|
|
364
|
+
│ ├── sprint-contract.md
|
|
365
|
+
│ ├── meetings/
|
|
366
|
+
│ ├── incidents/
|
|
367
|
+
│ └── task-sessions/
|
|
368
|
+
├── archive/
|
|
369
|
+
├── progress.json
|
|
370
|
+
├── handoff.json
|
|
371
|
+
├── progress.log
|
|
372
|
+
├── config.json
|
|
373
|
+
└── doctrine/
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
상세 조직 규칙은 다음 문서를 봅니다.
|
|
377
|
+
|
|
378
|
+
- `AGENTS.md`
|
|
379
|
+
- `.harness/doctrine/nexus.md`
|
|
380
|
+
- `.harness/agency-mapping.md`
|
|
381
|
+
- `.harness/HARNESS.md`
|
|
361
382
|
|
|
362
|
-
|
|
383
|
+
## Troubleshooting
|
|
363
384
|
|
|
364
|
-
|
|
385
|
+
### 다음 agent 가 안 뜸
|
|
365
386
|
|
|
366
387
|
```bash
|
|
367
|
-
|
|
368
|
-
> /harness-team
|
|
369
|
-
|
|
370
|
-
# 자동 실행 흐름:
|
|
371
|
-
# 1. feature-queue.json 초기화 (의존성 topological sort)
|
|
372
|
-
# 2. tmux Studio 레이아웃 구축
|
|
373
|
-
# 3. 3개 팀이 병렬로 Gen→Eval 루프 자동 실행
|
|
374
|
-
# 4. 팀 완료 시 자동으로 다음 feature dequeue
|
|
375
|
-
# 5. 5회 초과 실패 시 사용자 개입 요청
|
|
388
|
+
cat .harness/progress.json | jq '{current_agent, agent_status, next_agent, workflow, task_stop}'
|
|
376
389
|
```
|
|
377
390
|
|
|
378
|
-
###
|
|
379
|
-
|
|
380
|
-
| 명령 | 설명 |
|
|
381
|
-
|------|------|
|
|
382
|
-
| `/harness-team` | Team 모드 시작/재개 |
|
|
383
|
-
| `/harness-solo` | Solo 모드로 전환 (진행 상태 보존) |
|
|
384
|
-
| `/harness-stop` | Team 모드 중단 (queue 보존, 나중에 재개 가능) |
|
|
391
|
+
### handoff 재생성
|
|
385
392
|
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
↓
|
|
389
|
-
/harness-team → 나머지 feature 팀 재개
|
|
393
|
+
```bash
|
|
394
|
+
bash scripts/harness-next.sh .
|
|
390
395
|
```
|
|
391
396
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
## 디렉토리 구조
|
|
397
|
+
### SessionStart 안내 확인
|
|
395
398
|
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
├── .harness/
|
|
399
|
-
│ ├── config.json # 하네스 설정
|
|
400
|
-
│ ├── progress.json # 런타임 상태 (mode, sprint, agent)
|
|
401
|
-
│ ├── progress.log # 실시간 이벤트 로그
|
|
402
|
-
│ ├── memory.md # 공유 학습 기록 (모든 에이전트 공통)
|
|
403
|
-
│ ├── HARNESS.md # 하네스 상세 가이드
|
|
404
|
-
│ ├── actions/ # 활성 스프린트 문서
|
|
405
|
-
│ │ ├── pipeline.json # Dispatcher 결정 (evaluator_chain 포함)
|
|
406
|
-
│ │ ├── plan.md
|
|
407
|
-
│ │ ├── feature-list.json # Feature 목록 + Executable AC
|
|
408
|
-
│ │ ├── api-contract.json
|
|
409
|
-
│ │ ├── feature-queue.json # Feature Queue 상태 (Team Mode)
|
|
410
|
-
│ │ ├── sprint-contract.md
|
|
411
|
-
│ │ ├── evaluation-code-quality.md
|
|
412
|
-
│ │ ├── evaluation-functional.md
|
|
413
|
-
│ │ └── evaluation-visual.md
|
|
414
|
-
│ ├── archive/ # 완료 스프린트 보관 (불변, 마이그레이션 백업도 여기)
|
|
415
|
-
│ ├── gotchas/ # 에이전트 실수 기록 [G-NNN] (누적 보존)
|
|
416
|
-
│ │ ├── planner.md
|
|
417
|
-
│ │ ├── generator-backend.md
|
|
418
|
-
│ │ ├── generator-frontend.md
|
|
419
|
-
│ │ ├── evaluator-code-quality.md
|
|
420
|
-
│ │ ├── evaluator-functional.md
|
|
421
|
-
│ │ └── evaluator-visual.md
|
|
422
|
-
│ ├── conventions/ # 하우스 스타일 [C-NNN] (v5.6+, 누적 보존)
|
|
423
|
-
│ │ ├── shared.md
|
|
424
|
-
│ │ ├── planner.md
|
|
425
|
-
│ │ ├── generator-backend.md
|
|
426
|
-
│ │ ├── generator-frontend.md
|
|
427
|
-
│ │ ├── evaluator-code-quality.md
|
|
428
|
-
│ │ ├── evaluator-functional.md
|
|
429
|
-
│ │ └── evaluator-visual.md
|
|
430
|
-
│ └── MIGRATION_REPORT.md # 첫 설치 시 기존 문서 이관 내역 (있을 때만)
|
|
431
|
-
├── .claude/
|
|
432
|
-
│ ├── skills/harness-*/ # 에이전트 스킬 (8개)
|
|
433
|
-
│ ├── commands/harness-*.md # 모드 제어 커맨드 (3개)
|
|
434
|
-
│ └── settings.json # 훅, statusline
|
|
435
|
-
├── scripts/
|
|
436
|
-
│ ├── harness-tmux.sh # 통합 tmux 레이아웃 (Solo/Team)
|
|
437
|
-
│ ├── harness-dashboard.sh # 통합 대시보드
|
|
438
|
-
│ ├── harness-gotcha-memory.sh # Gotcha & Memory 패널
|
|
439
|
-
│ ├── harness-monitor.sh # 에이전트 모니터
|
|
440
|
-
│ ├── harness-queue-manager.sh # Feature Queue 관리
|
|
441
|
-
│ ├── harness-next.sh # 에이전트 전환 라우터
|
|
442
|
-
│ ├── harness-session-start.sh # SessionStart 훅
|
|
443
|
-
│ ├── harness-user-prompt-submit.sh # UserPromptSubmit 훅
|
|
444
|
-
│ ├── harness-statusline.sh # 상태바
|
|
445
|
-
│ ├── harness-prompt-history.sh # 프롬프트 히스토리
|
|
446
|
-
│ └── lib/ # 공유 라이브러리
|
|
447
|
-
├── AGENTS.md # 프로젝트 컨텍스트 (IA-MAP)
|
|
448
|
-
├── CLAUDE.md → AGENTS.md # 심볼릭 링크
|
|
449
|
-
└── CONVENTIONS.md # 최상위 원칙 (사용자 자유 기술, 하위는 .harness/conventions/)
|
|
399
|
+
```bash
|
|
400
|
+
bash scripts/harness-session-start.sh
|
|
450
401
|
```
|
|
451
402
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
## Troubleshooting
|
|
403
|
+
### TokenLimit hold 상태 확인
|
|
455
404
|
|
|
456
|
-
### Skills/Commands가 인식되지 않음
|
|
457
405
|
```bash
|
|
458
|
-
|
|
459
|
-
/exit
|
|
460
|
-
claude
|
|
406
|
+
cat .harness/progress.json | jq '.task_stop'
|
|
461
407
|
```
|
|
462
408
|
|
|
463
|
-
###
|
|
409
|
+
### queue 상태 확인
|
|
410
|
+
|
|
464
411
|
```bash
|
|
465
|
-
# Queue 상태 확인
|
|
466
412
|
bash scripts/harness-queue-manager.sh status .
|
|
467
|
-
|
|
468
|
-
# 실패한 feature requeue
|
|
469
|
-
bash scripts/harness-queue-manager.sh requeue F-001 .
|
|
470
413
|
```
|
|
471
414
|
|
|
472
|
-
###
|
|
473
|
-
```bash
|
|
474
|
-
# progress.json 직접 확인
|
|
475
|
-
cat .harness/progress.json | jq '{mode, sprint, current_agent, next_agent}'
|
|
415
|
+
### mode 강제 전환
|
|
476
416
|
|
|
477
|
-
|
|
478
|
-
|
|
417
|
+
```text
|
|
418
|
+
/harness-team
|
|
419
|
+
/harness-solo
|
|
420
|
+
/harness-stop
|
|
479
421
|
```
|
|
480
422
|
|
|
481
|
-
|
|
482
|
-
- v5.5.1 에서 해결 (feature 의 `name`/`title`/`description` 순으로 fallback).
|
|
483
|
-
- 그 이전 버전이면 `npm i @walwal-harness/cli@latest` 로 업데이트.
|
|
484
|
-
|
|
485
|
-
### Gotcha 가 누적되지 않고 사라짐
|
|
486
|
-
- v5.5.2 에서 해결 (postinstall 이 누적 엔트리를 절대 덮어쓰지 않도록 수정).
|
|
487
|
-
- 반드시 `5.5.2+` 사용.
|
|
423
|
+
## 버전 호환성
|
|
488
424
|
|
|
489
|
-
|
|
490
|
-
- v5.9.5 에서 해결. `feature-queue.json.queue.in_progress > 0` 이면 dashboard refresh / tmux 재기동 시 자동으로 `mode=team` 으로 self-heal 합니다.
|
|
491
|
-
- 그 이전 버전: `progress.json` 의 `mode` 만 직접 수정하거나 새 세션을 열어 SessionStart 훅의 heal 을 트리거.
|
|
425
|
+
README 는 v6.1 계열 회사형 하네스를 기준으로 작성되었습니다.
|
|
492
426
|
|
|
493
|
-
|
|
494
|
-
- v5.9.4 에서 해결. invalid JSON 인 경우 안내 메시지로 graceful degrade. 복구 가이드는 dashboard 본문에 inline 표시됩니다.
|
|
427
|
+
이 문서에서 전제하는 기능:
|
|
495
428
|
|
|
496
|
-
|
|
429
|
+
- company loop
|
|
430
|
+
- conductor / meeting-manager / cto / cqo / service-ops
|
|
431
|
+
- task-session isolation
|
|
432
|
+
- COO hypothesis cell
|
|
433
|
+
- TokenLimit hold/resume
|
|
497
434
|
|
|
498
435
|
## License
|
|
499
436
|
|
|
@@ -342,6 +342,13 @@
|
|
|
342
342
|
"auto_route_dispatcher": true,
|
|
343
343
|
"auto_route_dispatcher_description": "true 이면 사용자의 모든 프롬프트가 harness-dispatcher 경유로 분류/라우팅 된다. 사용자가 'harness skip' 등을 말하면 단일 메시지 한정으로 건너뛴다."
|
|
344
344
|
},
|
|
345
|
+
"token_limit": {
|
|
346
|
+
"comment": "모델 토큰 제한으로 작업이 중단됐을 때의 저비용 재개 정책. 별도 probe 호출 없이 시간 기반으로만 재개 알림을 계산한다.",
|
|
347
|
+
"stop_reason_flag": "TokenLimit",
|
|
348
|
+
"retry_after_seconds": 3600,
|
|
349
|
+
"re_notify_every_seconds": 3600,
|
|
350
|
+
"owner": "session-start"
|
|
351
|
+
},
|
|
345
352
|
"mode_selection": {
|
|
346
353
|
"comment": "v6.0 — Solo/Team 모드를 사용자가 아닌 Conductor 가 결정. progress.json.mode='auto' 일 때 Conductor 가 feature-list 의 ready_count + 의존성 깊이 + sprint feature 수를 보고 룰을 적용. 사용자는 /harness-solo 또는 /harness-team 으로 override 가능하며 그 결정은 progress.json.mode_decision.user_override 에 기록된다.",
|
|
347
354
|
"default_mode": "auto",
|
|
@@ -28,6 +28,19 @@
|
|
|
28
28
|
"message": null,
|
|
29
29
|
"retry_target": null
|
|
30
30
|
},
|
|
31
|
+
"task_stop": {
|
|
32
|
+
"active": false,
|
|
33
|
+
"reason": null,
|
|
34
|
+
"stopped_at": null,
|
|
35
|
+
"resume_after": null,
|
|
36
|
+
"resume_ready": false,
|
|
37
|
+
"resume_notified_at": null,
|
|
38
|
+
"wake_target": null,
|
|
39
|
+
"stopped_agent": null,
|
|
40
|
+
"stopped_next_agent": null,
|
|
41
|
+
"task_session_path": null,
|
|
42
|
+
"hold_count": 0
|
|
43
|
+
},
|
|
31
44
|
"artifacts": {
|
|
32
45
|
"plan.md": { "status": "pending", "updated_by": null, "updated_at": null },
|
|
33
46
|
"feature-list.json": { "status": "pending", "updated_by": null, "updated_at": null },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@walwal-harness/cli",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.2",
|
|
4
4
|
"description": "Production harness for AI agent engineering — NEXUS-adapted company metaphor (Dispatcher/CEO + Conductor + Meeting-Manager + COO/Planner + CTO + CQO + Service-Ops). Solo/Team mode, Brainstormer, Planner, Generator(BE/FE/Designer/DevOps), Evaluator chain (Code-Quality → Functional → Visual + Architecture/Security). Supports React, Next.js, and Flutter FE stacks.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"walwal-harness": "bin/init.js"
|
|
@@ -27,6 +27,23 @@ next_agent=$(jq -r '.next_agent // "none"' "$PROGRESS" 2>/dev/null)
|
|
|
27
27
|
agent_status=$(jq -r '.agent_status // "pending"' "$PROGRESS" 2>/dev/null)
|
|
28
28
|
mode=$(jq -r '.mode // "team"' "$PROGRESS" 2>/dev/null)
|
|
29
29
|
conductor_state=$(jq -r '.conductor.state // "idle"' "$PROGRESS" 2>/dev/null)
|
|
30
|
+
task_stop_active=$(jq -r '.task_stop.active // false' "$PROGRESS" 2>/dev/null)
|
|
31
|
+
task_stop_reason=$(jq -r '.task_stop.reason // "null"' "$PROGRESS" 2>/dev/null)
|
|
32
|
+
task_stop_resume_after=$(jq -r '.task_stop.resume_after // "null"' "$PROGRESS" 2>/dev/null)
|
|
33
|
+
task_stop_notified_at=$(jq -r '.task_stop.resume_notified_at // "null"' "$PROGRESS" 2>/dev/null)
|
|
34
|
+
task_stop_wake_target=$(jq -r '.task_stop.wake_target // .next_agent // "none"' "$PROGRESS" 2>/dev/null)
|
|
35
|
+
task_stop_task_session=$(jq -r '.task_stop.task_session_path // "null"' "$PROGRESS" 2>/dev/null)
|
|
36
|
+
|
|
37
|
+
parse_iso_epoch() {
|
|
38
|
+
local iso="${1:-}"
|
|
39
|
+
[ -n "$iso" ] && [ "$iso" != "null" ] || return 1
|
|
40
|
+
date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$iso" "+%s" 2>/dev/null \
|
|
41
|
+
|| date -u -d "$iso" "+%s" 2>/dev/null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
now_epoch() {
|
|
45
|
+
date -u "+%s"
|
|
46
|
+
}
|
|
30
47
|
|
|
31
48
|
# ─────────────────────────────────────────
|
|
32
49
|
# Auto-heal mode drift — Team 상태 유실 복구
|
|
@@ -79,6 +96,43 @@ if [ "$mode" = "paused" ]; then
|
|
|
79
96
|
exit 0
|
|
80
97
|
fi
|
|
81
98
|
|
|
99
|
+
# ─────────────────────────────────────────
|
|
100
|
+
# TokenLimit hold — zero-token resume reminder
|
|
101
|
+
# ─────────────────────────────────────────
|
|
102
|
+
if [ "$task_stop_active" = "true" ] && [ "$task_stop_reason" = "TokenLimit" ]; then
|
|
103
|
+
retry_interval=$(jq -r '.token_limit.re_notify_every_seconds // 3600' "$CONFIG" 2>/dev/null || echo 3600)
|
|
104
|
+
resume_after_epoch=$(parse_iso_epoch "$task_stop_resume_after" || echo 0)
|
|
105
|
+
now_ts=$(now_epoch)
|
|
106
|
+
notified_epoch=$(parse_iso_epoch "$task_stop_notified_at" || echo 0)
|
|
107
|
+
|
|
108
|
+
if [ "$now_ts" -lt "$resume_after_epoch" ]; then
|
|
109
|
+
echo "# Harness paused — TokenLimit hold"
|
|
110
|
+
echo "# Wake target: /harness-${task_stop_wake_target}"
|
|
111
|
+
echo "# Retry after: ${task_stop_resume_after}"
|
|
112
|
+
if [ "$task_stop_task_session" != "null" ] && [ -n "$task_stop_task_session" ]; then
|
|
113
|
+
echo "# Task session: ${task_stop_task_session}"
|
|
114
|
+
fi
|
|
115
|
+
exit 0
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [ "$notified_epoch" -eq 0 ] || [ $((now_ts - notified_epoch)) -ge "$retry_interval" ]; then
|
|
119
|
+
bash "$SCRIPT_DIR/harness-progress-set.sh" "$PROJECT_ROOT" \
|
|
120
|
+
".agent_status = \"pending\" |
|
|
121
|
+
.current_agent = null |
|
|
122
|
+
.next_agent = \"${task_stop_wake_target}\" |
|
|
123
|
+
.task_stop.active = false |
|
|
124
|
+
.task_stop.resume_ready = true |
|
|
125
|
+
.task_stop.resume_notified_at = (now | todate)" \
|
|
126
|
+
>/dev/null 2>&1 || true
|
|
127
|
+
echo "# Harness resume ready — TokenLimit hold expired"
|
|
128
|
+
echo "# Resume target: /harness-${task_stop_wake_target}"
|
|
129
|
+
if [ "$task_stop_task_session" != "null" ] && [ -n "$task_stop_task_session" ]; then
|
|
130
|
+
echo "# Resume with task session: ${task_stop_task_session}"
|
|
131
|
+
fi
|
|
132
|
+
exit 0
|
|
133
|
+
fi
|
|
134
|
+
fi
|
|
135
|
+
|
|
82
136
|
# ─────────────────────────────────────────
|
|
83
137
|
# init 상태: 첫 안내
|
|
84
138
|
# ─────────────────────────────────────────
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# harness-token-limit.sh — mark/resume token-limit interruptions
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
source "$SCRIPT_DIR/lib/harness-render-progress.sh"
|
|
7
|
+
|
|
8
|
+
PROJECT_ROOT="$(resolve_harness_root "${1:-.}")" || exit 1
|
|
9
|
+
CMD="${2:-mark}"
|
|
10
|
+
|
|
11
|
+
PROGRESS="$PROJECT_ROOT/.harness/progress.json"
|
|
12
|
+
CONFIG="$PROJECT_ROOT/.harness/config.json"
|
|
13
|
+
|
|
14
|
+
[ -f "$PROGRESS" ] || exit 1
|
|
15
|
+
command -v jq >/dev/null 2>&1 || exit 1
|
|
16
|
+
|
|
17
|
+
parse_iso_epoch() {
|
|
18
|
+
local iso="${1:-}"
|
|
19
|
+
[ -n "$iso" ] && [ "$iso" != "null" ] || return 1
|
|
20
|
+
date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$iso" "+%s" 2>/dev/null \
|
|
21
|
+
|| date -u -d "$iso" "+%s" 2>/dev/null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
mark_token_limit() {
|
|
25
|
+
local retry_secs current next task_path target stop_reason
|
|
26
|
+
retry_secs="${3:-$(jq -r '.token_limit.retry_after_seconds // 3600' "$CONFIG" 2>/dev/null || echo 3600)}"
|
|
27
|
+
stop_reason=$(jq -r '.token_limit.stop_reason_flag // "TokenLimit"' "$CONFIG" 2>/dev/null || echo "TokenLimit")
|
|
28
|
+
current=$(jq -r '.current_agent // "null"' "$PROGRESS")
|
|
29
|
+
next=$(jq -r '.next_agent // "null"' "$PROGRESS")
|
|
30
|
+
task_path=$(jq -r '.task_sessions.current.path // "null"' "$PROGRESS")
|
|
31
|
+
target="$current"
|
|
32
|
+
if [ "$target" = "null" ] || [ -z "$target" ]; then
|
|
33
|
+
target="$next"
|
|
34
|
+
fi
|
|
35
|
+
[ "$target" != "null" ] || target="dispatcher"
|
|
36
|
+
|
|
37
|
+
local stopped_at resume_after
|
|
38
|
+
stopped_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
39
|
+
resume_after="$(date -u -v+"${retry_secs}"S +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|
|
40
|
+
|| date -u -d "+${retry_secs} seconds" +%Y-%m-%dT%H:%M:%SZ)"
|
|
41
|
+
|
|
42
|
+
bash "$SCRIPT_DIR/harness-progress-set.sh" "$PROJECT_ROOT" "
|
|
43
|
+
.agent_status = \"paused\" |
|
|
44
|
+
.next_agent = \"$target\" |
|
|
45
|
+
.task_stop.active = true |
|
|
46
|
+
.task_stop.reason = \"$stop_reason\" |
|
|
47
|
+
.task_stop.stopped_at = \"$stopped_at\" |
|
|
48
|
+
.task_stop.resume_after = \"$resume_after\" |
|
|
49
|
+
.task_stop.resume_ready = false |
|
|
50
|
+
.task_stop.resume_notified_at = null |
|
|
51
|
+
.task_stop.wake_target = \"$target\" |
|
|
52
|
+
.task_stop.stopped_agent = $(jq -Rn --arg v "$current" '$v') |
|
|
53
|
+
.task_stop.stopped_next_agent = $(jq -Rn --arg v "$next" '$v') |
|
|
54
|
+
.task_stop.task_session_path = $(jq -Rn --arg v "$task_path" '$v') |
|
|
55
|
+
.task_stop.hold_count = ((.task_stop.hold_count // 0) + 1)
|
|
56
|
+
" >/dev/null
|
|
57
|
+
|
|
58
|
+
echo "[token-limit] marked: target=$target resume_after=$resume_after"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
resume_probe() {
|
|
62
|
+
local active reason resume_after wake_target
|
|
63
|
+
active=$(jq -r '.task_stop.active // false' "$PROGRESS")
|
|
64
|
+
reason=$(jq -r '.task_stop.reason // "null"' "$PROGRESS")
|
|
65
|
+
resume_after=$(jq -r '.task_stop.resume_after // "null"' "$PROGRESS")
|
|
66
|
+
wake_target=$(jq -r '.task_stop.wake_target // .next_agent // "null"' "$PROGRESS")
|
|
67
|
+
|
|
68
|
+
if [ "$active" != "true" ] || [ "$reason" != "TokenLimit" ]; then
|
|
69
|
+
echo "[token-limit] no active TokenLimit hold"
|
|
70
|
+
exit 0
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
local resume_epoch now_ts
|
|
74
|
+
resume_epoch=$(parse_iso_epoch "$resume_after" || echo 0)
|
|
75
|
+
now_ts=$(date -u "+%s")
|
|
76
|
+
if [ "$now_ts" -lt "$resume_epoch" ]; then
|
|
77
|
+
echo "[token-limit] still held until $resume_after"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
bash "$SCRIPT_DIR/harness-progress-set.sh" "$PROJECT_ROOT" "
|
|
82
|
+
.agent_status = \"pending\" |
|
|
83
|
+
.current_agent = null |
|
|
84
|
+
.next_agent = \"$wake_target\" |
|
|
85
|
+
.task_stop.active = false |
|
|
86
|
+
.task_stop.resume_ready = true |
|
|
87
|
+
.task_stop.resume_notified_at = (now | todate)
|
|
88
|
+
" >/dev/null
|
|
89
|
+
echo "[token-limit] resume ready: wake_target=$wake_target"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
case "$CMD" in
|
|
93
|
+
mark) mark_token_limit "$@" ;;
|
|
94
|
+
resume-probe) resume_probe ;;
|
|
95
|
+
*)
|
|
96
|
+
echo "usage: $0 <project-root> <mark|resume-probe> [retry_seconds]" >&2
|
|
97
|
+
exit 2
|
|
98
|
+
;;
|
|
99
|
+
esac
|
|
@@ -42,6 +42,17 @@ if [ -f "$CWD/.harness/progress.json" ] && command -v jq >/dev/null 2>&1; then
|
|
|
42
42
|
AGENT_STATUS=$(jq -r '.agent_status // "pending"' "$CWD/.harness/progress.json" 2>/dev/null || echo "pending")
|
|
43
43
|
fi
|
|
44
44
|
|
|
45
|
+
TASK_STOP_ACTIVE="false"
|
|
46
|
+
TASK_STOP_REASON="null"
|
|
47
|
+
TASK_STOP_RESUME_AFTER="null"
|
|
48
|
+
TASK_STOP_WAKE_TARGET="none"
|
|
49
|
+
if [ -f "$CWD/.harness/progress.json" ] && command -v jq >/dev/null 2>&1; then
|
|
50
|
+
TASK_STOP_ACTIVE=$(jq -r '.task_stop.active // false' "$CWD/.harness/progress.json" 2>/dev/null || echo "false")
|
|
51
|
+
TASK_STOP_REASON=$(jq -r '.task_stop.reason // "null"' "$CWD/.harness/progress.json" 2>/dev/null || echo "null")
|
|
52
|
+
TASK_STOP_RESUME_AFTER=$(jq -r '.task_stop.resume_after // "null"' "$CWD/.harness/progress.json" 2>/dev/null || echo "null")
|
|
53
|
+
TASK_STOP_WAKE_TARGET=$(jq -r '.task_stop.wake_target // .next_agent // "none"' "$CWD/.harness/progress.json" 2>/dev/null || echo "none")
|
|
54
|
+
fi
|
|
55
|
+
|
|
45
56
|
# ── 명령 히스토리 기록 (모든 모드 공통) ──
|
|
46
57
|
PROGRESS_LOG="$CWD/.harness/progress.log"
|
|
47
58
|
if [ -n "$PROMPT" ] && [ -d "$CWD/.harness" ]; then
|
|
@@ -79,6 +90,18 @@ EOF
|
|
|
79
90
|
exit 0
|
|
80
91
|
fi
|
|
81
92
|
|
|
93
|
+
if [ "$TASK_STOP_ACTIVE" = "true" ] && [ "$TASK_STOP_REASON" = "TokenLimit" ]; then
|
|
94
|
+
cat <<EOF
|
|
95
|
+
[harness] token-limit hold | wake_target=${TASK_STOP_WAKE_TARGET}
|
|
96
|
+
## TokenLimit Hold
|
|
97
|
+
- 모든 작업은 일시중지 상태입니다.
|
|
98
|
+
- 재개 대상: /harness-${TASK_STOP_WAKE_TARGET}
|
|
99
|
+
- retry_after: ${TASK_STOP_RESUME_AFTER}
|
|
100
|
+
- 이 상태는 문서 기반으로만 복구되며, 별도 모델 probe는 수행하지 않습니다.
|
|
101
|
+
EOF
|
|
102
|
+
exit 0
|
|
103
|
+
fi
|
|
104
|
+
|
|
82
105
|
# ── Mode 기반 분기 ──
|
|
83
106
|
MODE="team"
|
|
84
107
|
if [ -f "$CWD/.harness/progress.json" ] && command -v jq >/dev/null 2>&1; then
|