@tuzi-ince/hi-loop 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,26 +4,44 @@
4
4
 
5
5
  날것의 아이디어(goal)를 던지면, AI 에이전트를 PDCA 루프로 반복 구동해
6
6
  **테스트가 실제로 통과할 때까지** 스스로 고쳐 나간다.
7
+
7
8
  - 요구사항(무엇을): [`docs/spec.md`](docs/spec.md)
8
9
  - 설계(어떻게·왜): [`docs/design.md`](docs/design.md)
9
10
  - 배포·설치·사용: [`docs/guide.md`](docs/guide.md)
10
11
 
11
- > 현재 상태: 실제 `claude`(2.1.212) 와의 통합 **검증 완료** 편집 권한, 세션 재개,
12
- > 전체 루프, 예산 상한을 실측했다([`docs/design.md`](docs/design.md) §10).
13
- > 아직 것도 표에 적어뒀다(핸드오프 실측, MCP 모드 실제 spawn, 10회 장시간 루프).
12
+ ## 루프 엔지니어링우리의 개발 철학
13
+
14
+ 엔진은 "AI가 코드를 짜준다"에 기대지 않는다. AI는 자주 틀리고, 자주
15
+ **틀린 것을 다 됐다고 말한다.** 그래서 우리는 모델의 자기보고를 판정에서 배제하고,
16
+ 기계가 검증할 수 있는 종료 조건 위에 루프를 세운다. 세 문장이 전부다.
17
+
18
+ 1. **산문은 요청이고, 메커니즘은 사실이다.**
19
+ 보고서에 "이건 검증 안 됨"이라고 적는 것은 요청일 뿐이다. 한 번 더 돌려서 측정하면
20
+ 그 문장이 사실이 된다. 그래서 이 엔진은 문장을 늘리기보다 검사를 하나 더 돌린다.
21
+ 2. **에이전트의 "다 됐어요"는 판정이 아니다.**
22
+ 성패는 언제나 `testCommand`의 exit code다. 엔진이 직접 실행해서 확인한다.
23
+ 3. **종료 조건 없는 단계는 엔진의 단계가 아니라 문서 생성기다.**
24
+ 모든 단계는 기계가 판정할 통과 기준을 가진다. 없으면 그 단계는 만들지 않는다.
25
+
26
+ 이 세 원칙에서 뒤의 [안전장치](#안전장치--루프-엔지니어링-원칙)들이 전부 파생된다.
14
27
 
15
28
  ## 설치
16
29
 
17
- > ⚠️ `npm install -g handoff` 를 하지 마라. npm 의 `handoff` 는 이 프로젝트와 무관한
18
- > **제3자의 redis 래퍼 패키지**다. 이름만 같다. 아직 미배포이므로 소스에서 설치한다.
30
+ ```bash
31
+ # 1) 전역 설치 hi-loop / hi-loop-setup 명령 등록
32
+ npm install -g @tuzi-ince/hi-loop
33
+
34
+ # 2) 프로젝트에 주입 (멱등 — 여러 번 돌려도 안전)
35
+ cd /path/to/my-project
36
+ hi-loop-setup # .mcp.json / .gitignore / docs / tests 자동 주입
37
+ ```
38
+
39
+ 소스에서 개발용으로 설치하려면:
19
40
 
20
41
  ```bash
21
42
  git clone <이 저장소> hi-loop && cd hi-loop
22
- npm install && npm test # 104 통과
43
+ npm install && npm test # node:test, devDependency 0
23
44
  npm link # hi-loop / hi-loop-setup 명령 등록
24
-
25
- cd /path/to/my-project
26
- hi-loop-setup # .mcp.json / .gitignore / docs / tests 자동 주입 (멱등)
27
45
  ```
28
46
 
29
47
  자세한 절차·문제해결·배포는 [`docs/guide.md`](docs/guide.md).
@@ -51,30 +69,22 @@ CHECK ──► 엔진이 testCommand 를 직접 실행 (에이전트의 "다
51
69
  ACT ──► stderr 를 그대로 에이전트에 들이밀고 "이 에러를 고쳐라" (최대 10회)
52
70
  ```
53
71
 
54
- ## 전과정 라이프사이클 (`--full`)
55
-
56
- 기본은 위의 자가 치유 루프 하나다. `--full` 을 붙이면 앞뒤 단계까지 돈다.
72
+ 기본은 자가 치유 루프 하나다. `--full` 을 붙이면 앞뒤 단계까지 돈다.
57
73
 
58
74
  ```
59
- DISCOVER → PLAN → DESIGN_REVIEW → DO ⇄ CHECK ⇄ HEAL → CODE_REVIEW → SHIP → WATCH → DONE
60
- ▲ │
61
- └── reject ┘ reject ──┘ fail ─────┘
62
- ```
63
-
64
- ```bash
65
- # 아이디어 한 줄 → 발굴 → 스펙 → 구현 → 리뷰 → 배포 → 감시. 사람 개입 최소.
66
- hi-loop run --goal "JWT 인증 미들웨어" --full \
67
- --ship "npm publish --access public" \
68
- --watch "curl -f https://api.example.com/health" --watch-for 5m
75
+ DISCOVER → PLAN → DESIGN_REVIEW → BUILD(DO ⇄ CHECK ⇄ HEAL) → CODE_REVIEW → SHIP → WATCH → DONE
76
+ ▲ │
77
+ └── reject ┘ reject ──┘ fail ────┘
69
78
  ```
70
79
 
71
- **추가되는 모든 단계는 기계가 판정할 종료 조건을 가진다.** 없으면 그건 엔진의 단계가
72
- 아니라 문서 생성기다.
80
+ **추가되는 모든 단계는 기계가 판정할 종료 조건을 가진다.**
73
81
 
74
82
  | 단계 | 무엇을 하는가 | 종료 조건 |
75
83
  |---|---|---|
76
84
  | DISCOVER | goal 의 모호함을 **가정으로 확정**하고 문서화 | 가정 목록 확정 |
85
+ | PLAN | 스펙 + 테스트를 먼저 쓴다 (구현 금지) | 산출물 작성 |
77
86
  | DESIGN_REVIEW | 구현 착수 **전** 스펙을 심판 | 독립 검증자 pass |
87
+ | BUILD | DO ⇄ CHECK ⇄ HEAL 자가 치유 루프 | testCommand exit 0 |
78
88
  | CODE_REVIEW | diff 를 정확성·보안·YAGNI 축으로 심판 | 독립 검증자 pass |
79
89
  | SHIP | 배포 명령 실행 | **exit code 0** |
80
90
  | WATCH | 헬스체크 반복 | 지정 시간 동안 버팀 |
@@ -82,106 +92,287 @@ hi-loop run --goal "JWT 인증 미들웨어" --full \
82
92
  배포·감시는 **에이전트를 부르지 않는다.** "배포했다고 모델이 말했다"가 아니라
83
93
  "헬스체크 exit code 가 0이다"가 통과 조건이다. 그래서 이 두 단계의 비용은 0이다.
84
94
 
85
- ### 기본은 무중단, 필연적 선택에서만 묻는다
95
+ ---
86
96
 
87
- 리뷰 단계들은 **모델이 심판하고 엔진이 되돌린다.** 사람을 안 부른다 —
88
- 설계 리뷰가 기각하면 PLAN 을 다시 쓰고, 코드 리뷰가 기각하면 그 지적이 HEAL 의 연료가 된다.
97
+ # 실전 활용 가이드 (프로젝트 관리 관점)
89
98
 
90
- 사람이 멈춰 서는 곳은 둘뿐이다:
91
- 1. DISCOVER **상호배타 분기**를 만났을 (가정으로 답할 수 없는 지점)
92
- 2. SHIP 직전 (비가역 외부 행위. `--yes` 로 생략)
99
+ 무엇을 하려는지에 따라 **어떻게 goal을 쓰고 어떤 플래그를 켜는지**가 달라진다.
100
+ 아래는 실제 프로젝트를 굴리며 자주 만나는 상황별 레시피다.
93
101
 
102
+ ## 1. 프로젝트 생성 — 아이디어 한 줄 → 동작하는 코드
103
+
104
+ 모호한 요구를 발굴부터 구현·리뷰까지 한 번에 돌린다. `--full` 이 앞뒤 단계를 켠다.
105
+
106
+ ```bash
107
+ hi-loop run --goal "JWT 인증 미들웨어를 만들어라" --full --budget-usd 5
94
108
  ```
95
- $ hi-loop run --goal "..." --full
96
- 선택이 필요합니다 [DISCOVER]
97
- 인증 저장소를 어디에 둘까?
98
- a) 기존 users 테이블 확장 — 마이그레이션 필요
99
- b) 별도 auth_tokens 테이블 신규 조인 비용
100
- → hi-loop answer <a|b> [--note "..."]
101
-
102
- $ hi-loop answer a # 고른 것도 "가정"으로 기록돼 이후 프롬프트에 실린다
109
+
110
+ - **DISCOVER** goal의 빈칸(토큰 저장 위치, 만료 정책 등)을 가정으로 확정하고 문서화한다.
111
+ - **PLAN** 스펙과 테스트를 먼저 쓴다 — 구현보다 판정 기준이 앞선다.
112
+ - **DESIGN_REVIEW BUILD CODE_REVIEW** 순으로 만들고, 만든 것을 스스로 심판한다.
113
+ - 상호배타 분기(예: "users 확장 vs auth_tokens 신설")를 만나면 거기서만 사람에게 묻는다.
114
+
115
+ **기존 파일을 덮어쓰지 않는다.** `docs/spec.md` / `tests/app.test.js` 가 비어 있으면 그대로
116
+ 쓰고, 이미 뭔가 있으면 goal 해시로 비켜간다(`docs/spec-5d88cc7f.md`). 같은 프로젝트에서
117
+ goal만 바꿔 여러 번 돌려도 앞의 산출물이 살아남는다.
118
+
119
+ > 발굴 단계만 먼저 돌려 요구사항을 확정하고 싶다면:
120
+ > ```bash
121
+ > hi-loop discover --goal "..." # 가정 확정 + 문서만, 구현은 안 함
122
+ > ```
123
+
124
+ ## 2. 프로젝트 개선 — 기존 코드베이스 손질
125
+
126
+ 리팩터링·성능 개선·기술부채 정리처럼 **이미 테스트가 있는 코드**를 고칠 때.
127
+ 기존 테스트를 가드레일로 두고, 스펙 대비 검증을 더 얹는다.
128
+
129
+ ```bash
130
+ hi-loop run --goal "결제 모듈의 중복 검증 로직을 하나로 합쳐라" \
131
+ --test "npm test" \
132
+ --verify-spec
103
133
  ```
104
134
 
105
- 차단형 입력을 쓰지 않고 **상태를 저장하고 종료**한다(exit 3). 그래서 MCP·백그라운드
106
- 데몬·텔레그램 봇에서도 그대로 성립한다. MCP 에서는 호스트 LLM 질문을 사용자에게
107
- 제시하고 `hiloop_answer` 답을 돌려준다.
135
+ - 기존 `npm test` 회귀 방지선이다 개선하다 무언가 깨면 Tier 1에서 걸린다.
136
+ - `--verify-spec` 테스트 통과 **후** 별도 검증자가 스펙 대비 구현을 심판한다.
137
+ 구조가 아니라 **의도**를 본다("리팩터링했다"는데 동작이 달라졌으면 기각).
138
+ - 개선 중 락파일·설정·마이그레이션을 건드리면 보고서 Gaps에 ⚠️로 공개된다
139
+ (→ [영향도 분석](#4-영향도-분석--변경-위험-파악)).
108
140
 
109
- `--ask never` 분기에서도 멈춘다(CI·봇용). 대신 **미해결이라는 사실이 Gaps 에 남는다.**
141
+ ## 3. 장애 분석 버그·회귀 재현 수정
110
142
 
111
- ### 단계별로 따로 부를 수도 있다
143
+ 버그를 "고쳤다"가 아니라 "재현 테스트로 못박고 고쳤다"로 끝낸다. 회귀 방지가 공짜로 남는다.
144
+
145
+ ```bash
146
+ hi-loop run --goal "재현 테스트를 먼저 작성하고, 동시 요청 시 잔액이 음수가 되는 버그를 고쳐라" \
147
+ --test "npm test" \
148
+ --stagnation 3
149
+ ```
150
+
151
+ - PLAN이 **실패하는 재현 테스트**를 먼저 강제한다 → 버그가 테스트로 고정된다.
152
+ - HEAL이 실제 stderr를 연료로 삼아 고친다. 모델의 추측이 아니라 진짜 에러를 본다.
153
+ - **같은 벽에 열 번 부딪히지 않는다**: 같은 실패가 3회 연속이면 `stagnated` 로 조기 종료한다
154
+ — "이 접근으론 안 된다"를 `--max-loops` 소진 전에 잡는다. `--no-stagnation` 으로 끈다.
155
+ - 에이전트가 멀쩡한 코드를 오히려 망가뜨렸으면 되돌린다:
156
+ ```bash
157
+ hi-loop rollback # 최신 체크포인트로 파일 복원
158
+ hi-loop rollback --to 3 # 3회차 직전 상태로
159
+ ```
160
+
161
+ ## 4. 영향도 분석 — 변경 위험 파악
162
+
163
+ 이 변경이 **어디까지 번지는가**를 두 층위로 잡는다.
164
+
165
+ **(a) 블라스트 반경 — 자동, 비용 0.** 실행이 위험 분류 파일을 건드리면 판정과 무관하게
166
+ 보고서 Gaps에 ⚠️로 공개한다. 분류: 의존성(lock/package.json), 스키마 마이그레이션,
167
+ CI·배포 설정, 빌드·러너 설정, 환경 변수. "테스트는 통과했는데 왜 락파일이 바뀌었지"를
168
+ 사람이 놓치지 않게 한다.
169
+
170
+ **(b) 조건부 검사 — 바뀐 파일에 따라 게이트를 켠다.** 무거운 검사(e2e 등)를 매 회차 돌리는
171
+ 대신, 특정 경로가 바뀐 회차에만 돌린다.
172
+
173
+ ```bash
174
+ hi-loop run --goal "..." \
175
+ --check "npm test" \
176
+ --check "npm run typecheck" \
177
+ --check "npx playwright test" --when "src/ui/**"
178
+ ```
179
+
180
+ - 검사는 **short-circuit 하지 않는다.** 유닛이 깨져도 typecheck·e2e 결과를 같은 회차에 다 본다
181
+ (`&&` 로 이으면 첫 실패에서 멈춰 나머지를 영영 모른다).
182
+ - `--when` 글롭에 안 맞은 검사는 **건너뜀으로 기록**된다 — 안 돌린 것이 통과처럼 보이지 않게
183
+ Gaps에 남는다.
184
+
185
+ **diff만 리뷰하고 싶다면** — 지금 워킹트리 변경분을 정확성·보안·YAGNI 축으로 심판:
186
+
187
+ ```bash
188
+ hi-loop review # 현재 변경분만 코드 리뷰 (구현/배포는 안 함)
189
+ ```
190
+
191
+ ## 5. 테스트·품질 게이트
192
+
193
+ **테스트 설계만** 뽑고 싶을 때 (구현은 사람이 하거나 나중에):
194
+
195
+ ```bash
196
+ hi-loop plan --goal "장바구니 할인 규칙" # 스펙 + 테스트까지만, 구현 전
197
+ ```
198
+
199
+ **플레이키(불안정) 테스트를 걸러내고 싶을 때:**
200
+
201
+ ```bash
202
+ hi-loop run --goal "..." --flaky-probe
203
+ ```
204
+
205
+ - 통과한 회차에서만 같은 테스트를 **한 번 더** 돌린다. 두 번의 결과가 갈리면 통과로 인정하지
206
+ 않는다("두 번 돌려 갈리는 초록불은 초록불이 아니다"). 에이전트 호출 0 — 비용은 테스트 한 번뿐.
207
+
208
+ **여러 게이트를 한 판정에 묶고 싶을 때** — 위 [조건부 검사](#4-영향도-분석--변경-위험-파악)의
209
+ `--check` 를 여러 번 준다. lint·typecheck·유닛·e2e를 각각 독립된 게이트로 세운다.
210
+
211
+ ## 6. 배포 & 감시 — 사람 개입 최소
212
+
213
+ 리뷰를 통과한 변경을 배포하고, 배포 후 일정 시간 헬스체크로 버티는지 지켜본다.
214
+
215
+ ```bash
216
+ hi-loop run --goal "..." --full \
217
+ --ship "npm publish --access public" \
218
+ --watch "curl -f https://api.example.com/health" --watch-for 5m
219
+ ```
220
+
221
+ - `--ship` 을 주면 리뷰 단계들이 **자동으로 켜진다** ("리뷰 없는 자동 배포는 위험하다"의
222
+ 근거가 여기서만 성립).
223
+ - SHIP/WATCH는 에이전트를 부르지 않는다 — 통과 조건은 오직 exit code다.
224
+ - 실패 대응을 지정할 수 있다: `--on-ship-fail stop|heal`, `--on-watch-fail stop|rollback|heal`.
225
+ - 비가역 배포 직전에는 사람에게 확인을 구한다. CI·봇에서는 `--yes` 로 생략.
226
+
227
+ ## 7. 단계별로 따로 부르기
228
+
229
+ 전체를 한 번에 돌리지 않고, 필요한 구간만 실행할 수 있다. 어느 경로로 들어와도 **같은 상태
230
+ 머신**을 쓴다.
112
231
 
113
232
  ```bash
114
233
  hi-loop discover --goal "..." # 발굴만 (가정 확정 + 문서)
115
- hi-loop plan --goal "..." # 스펙·테스트까지만 (구현 전)
234
+ hi-loop plan --goal "..." # 스펙·테스트까지만 (구현 전)
116
235
  hi-loop review # 현재 변경분만 코드 리뷰
117
- hi-loop ship --ship "npm publish" # 배포 단계만
118
- hi-loop watch --watch "curl -f ..."
236
+ hi-loop ship --ship "npm publish"
237
+ hi-loop watch --watch "curl -f ..."
119
238
  ```
120
239
 
121
- 어느 경로로 들어와도 **같은 상태 머신**을 쓴다. 후반 단계는 `--goal` 다시 받는다
122
- 저장된 상태에서 읽는다(한 글자만 달라도 새 루프로 인식돼 진행 상황이 버려지기 때문).
240
+ 또는 `--start-from` / `--stop-after` 실행의 구간을 자른다:
123
241
 
124
- ### 왜 기본값이 "꺼짐"인가
242
+ ```bash
243
+ hi-loop run --goal "..." --start-from BUILD --stop-after CODE_REVIEW
244
+ ```
245
+
246
+ > 후반 단계는 `--goal` 을 다시 받지 않는다 — 저장된 상태에서 읽는다(goal이 한 글자만 달라도
247
+ > 새 루프로 인식돼 진행 상황이 버려진다). PLAN은 BUILD 안쪽의 회차라 `--start-from` 대상이
248
+ > 아니다 — BUILD로 시작하면 자연히 PLAN부터 돈다.
125
249
 
126
- 단계는 각각 에이전트 호출을 1회씩 더한다. 전역 기본 ON 으로 하면 업데이트만 한
127
- 기존 사용자의 실행 비용이 조용히 는다. 그래서:
250
+ ## 8. MCP에서 팀으로 쓰기 (클로드코드/커서)
128
251
 
129
- - 플래그가 없으면 **종전 그대로** 자가 치유 루프 하나만 돈다.
130
- - `--full` 발굴·설계리뷰·코드리뷰 켜짐.
131
- - `--ship` → 리뷰들만 자동 켜짐 ("리뷰 없는 자동 배포가 위험하다"는 근거가 여기서만 성립).
132
- - `--review/--no-review`, `--design-review/--no-design-review`, `--discover/--no-discover`
133
- 가 위 자동을 양방향으로 덮는다.
252
+ `hi-loop mcp` 띄우면 호스트 LLM이 시나리오를 도구로 호출한다. 차단형 입력을 쓰지 않고
253
+ **상태를 저장하고 종료**하므로(exit 3) 대화형 세션·백그라운드 데몬·봇에서 그대로 성립한다.
134
254
 
135
- ### 세션 핸드오프 & 컨텍스트 다이어트 (bkit 철학)
255
+ ```
256
+ 호스트 LLM ──hiloop_run──► 루프 구동
257
+ ◄──분기 질문─── (상호배타 선택 필요)
258
+ ──hiloop_answer──► 사람의 선택을 "가정"으로 기록하고 재개
259
+ ──hiloop_status──► 진행/비용/Gaps 조회
260
+ ```
136
261
 
137
- 에이전트는 같은 세션에서 오래 굴릴수록 토큰이 쌓여 멍청해진다.
138
- 그래서 4회마다 세션을 **버리고**, `.agent-state.json`에 압축된 상태
139
- (goal / 스펙 요약 / 마지막 에러 / 최근 이력 5건)만 새 세션에 넘겨 이어서 작업한다(auto-resume).
140
- 같은 goal로 다시 실행하면 중단 지점부터 재개한다.
262
+ ## 9. 코드 어시스턴트가 요청을 처리하는 방식 — 직접 호출 vs 평문 요청
141
263
 
142
- ### TDD 자가 치유 (MoAI 철학)
264
+ 클로드코드·커서 같은 코드 어시스턴트(호스트 LLM) 안에서 hi-loop은 두 갈래로 불린다.
265
+ **핵심은 "LLM이 요청을 읽는 순간, hi-loop을 떠올릴 근거가 눈앞에 있느냐"** 다.
143
266
 
144
- 성패 판정은 항상 `testCommand`의 exit code다. 에이전트의 자기보고는 판정에 쓰지 않는다.
267
+ ### (a) 직접 호출 명시적으로 엔진을 지목
268
+ 사용자가 hi-loop을 대놓고 부른다. LLM은 **바로 `hiloop_run`을 구동**한다(목표만 확정).
145
269
 
146
- ### 💸 비용은 엔진이 센다 그리고 싸지 않다
270
+ | 사용자가 이렇게 말하면 | LLM이 하는 |
271
+ |---|---|
272
+ | `/hi-loop 로그인 폼 만들어줘` (슬래시 스킬) | hi-loop 스킬 기동 → `hiloop_run(full=true)` 실행 |
273
+ | "hiloop_run 도구로 결제 버그 고쳐줘" | 지목된 MCP 도구를 로드해 바로 호출 |
274
+ | 터미널에서 `hi-loop run --goal "..." --full` | 엔진을 CLI로 직접 구동(LLM 개입 없음) |
275
+
276
+ ### (b) 평문 요청 — 그냥 하고 싶은 일을 말함
277
+ 사용자는 hi-loop을 언급하지 않는다. 이때 자동으로 hi-loop에 걸리는 건 **트리거가 박힌
278
+ 스킬 description + `CLAUDE.md` 지침**이 매 세션 떠 있기 때문이다(설치 + `hi-loop-setup` 전제).
279
+ 그 표면이 없으면 LLM은 hi-loop을 모른 채 그냥 직접 구현한다.
147
280
 
148
- **실측**: "두 수를 더하는 add 함수를 만들어라"가 2회차에 통과하는 **$2.58~$4.67**
149
- (claude-opus-4-8). 같은 goal·같은 회차인데 컨텍스트 크기 때문에 1.8배 갈렸다.
150
- 세션은 일을 시켜도 바닥값이 ~$0.43이다(캐시 생성).
281
+ | 사용자가 이렇게 말하면 | 어디에 걸리나 | LLM이 하는 일 |
282
+ |---|---|---|
283
+ | "워크스페이스 폴더 드래그앤드롭 **개선**해줘" | 트리거 `개선` | hi-loop 스킬 후보로 뜸 → 기획·설계 필요 판단 → `hiloop_run(full=true)` 제안·실행 |
284
+ | "장바구니 **기능** 하나 **만들어**줘" | 트리거 `기능/design` | 발굴→스펙·테스트 우선(PLAN)→구현·리뷰 루프 |
285
+ | "결제 모듈 **리팩터**해줘" | 트리거 `리팩터` | 기존 테스트를 가드레일로 `--verify-spec` 성격의 개선 루프 |
286
+ | "동시 요청 시 잔액 음수 **버그** 고쳐줘" | 트리거 `구현/버그성` | **재현 테스트 먼저** → HEAL 루프로 수정 |
287
+ | "이 **오타** 고쳐줘" / "변수명 바꿔줘" | 예외(사소) | 루프 없이 **바로** 처리 — README·CLAUDE.md가 사소한 작업은 제외하라고 명시 |
288
+
289
+ ### 왜 이렇게 갈리나 (push vs pull)
290
+ - **트리거 스킬 description·CLAUDE.md = push 표면.** LLM이 찾지 않아도 매 세션 상주하며,
291
+ 평문에 `개선/설계/버그` 같은 단어가 있으면 **자동으로** hi-loop을 후보로 올린다.
292
+ - **MCP 도구 = pull 표면.** 세션에선 이름만 있고(때로 deferred), LLM이 먼저 "hi-loop이
293
+ 필요하다"고 떠올려 `ToolSearch`로 끌어와야 설명이 보인다.
294
+ - 그래서 **평문 요청이 자동 라우팅되려면 push 표면이 반드시 있어야 한다.** `hi-loop-setup`이
295
+ `CLAUDE.md` 지침을 심고, 플러그인이 트리거 스킬을 등록하는 이유가 이것이다. 이게 없으면
296
+ "개선해줘"라고 해도 LLM은 hi-loop을 거치지 않고 곧장 코드부터 짠다.
297
+
298
+ > 확실히 hi-loop을 태우고 싶으면 **(a) 직접 호출**이 가장 안전하다. **(b) 평문 자동 라우팅**은
299
+ > 편하지만, 설치·주입이 안 됐거나 트리거에 안 걸리는 표현이면 우회될 수 있다.
300
+
301
+ ## 브랜치 & 커밋 워크플로 (FR-16)
302
+
303
+ 코드 변경 작업을 **보호 브랜치에서 분기 → 구현·테스트 → 로컬 커밋**으로 감싼다. push/PR 은 하지 않는다.
304
+
305
+ **정책은 커밋되는 `.hi-loop.json` 한 파일**에 산다(팀 공유, 스킬·엔진 공용). `.agent-state.json`
306
+ (임시·gitignore)과 다르다. 기본값:
307
+
308
+ ```json
309
+ {
310
+ "protectedBranches": ["main", "master", "develop", "dev"],
311
+ "branchPolicy": "ask", // always=자동 분기 | ask=매번 확인 | never
312
+ "commitPolicy": "confirm", // confirm=메시지+diff 확인 후 | auto | off
313
+ "commitStyle": "match-log" // match-log=git log 관행 미러 | conventional | korean
314
+ }
315
+ ```
151
316
 
152
- **`--max-loops`는 비용 상한이 아니다.** 실패 루프가 10회를 다 쓰면 $20을 넘길 수 있다.
153
- 그래서 `--budget-usd`를 쓴다 누적이 상한에 닿으면 **다음 에이전트 호출 전에** 멈춘다
154
- (이미 돈은 돌리니 있는 쓰는 것뿐이다).
317
+ **두 실행 (같은 정책 파일):**
318
+ - **대화형(스킬/코드 어시스턴트)**: 코드변경 요청 `.hi-loop.json` 없으면 **최초 1회** 정책을
319
+ 묻고 저장(지연 발동). 이후 보호 브랜치면 분기 게이트, 테스트 통과 커밋 게이트(diff 보여주고
320
+ 승인)를 태운다. "이번만 커밋하지 마"(일회성)와 "앞으로 커밋하지 마"(정책 변경)를 구분한다.
321
+ - **헤드리스(CLI/봇/CI)**: 물어볼 수 없으니 **플래그 = 동의**.
155
322
 
156
323
  ```bash
157
- hi-loop run --goal "..." --max-loops 5 --budget-usd 1 --no-stagnation
158
- # [hi-loop] 💸 예산 $1 소진 (누적 $1.61) — 2회차에서 중단합니다.
324
+ hi-loop run --goal "..." --branch --commit # 보호 브랜치면 자동 분기 + 통과 후 자동 커밋
325
+ hi-loop run --goal "..." --branch feature/login # 브랜치명 지정
326
+ hi-loop run --goal "..." --commit --commit-message "feat: 로그인"
159
327
  ```
160
328
 
161
- `hi-loop status`와 완료 로그에 누적 비용이 찍힌다. 모델은 사용자 기본값을 상속하므로
162
- `HILOOP_AGENT_ARGS="--model sonnet"`으로 낮출 있다.
329
+ `.hi-loop.json` `branchPolicy: always` / `commitPolicy: auto` CLI 에서 플래그 없이도 발동한다
330
+ (플래그가 우선). 커밋 스테이지는 상태 머신에서 `CODE_REVIEW COMMIT SHIP` 사이에 든다 —
331
+ 리뷰된 코드를 커밋한 뒤 배포한다.
163
332
 
164
- ### 기존 파일을 덮어쓰지 않는다
333
+ **정책 관리:**
165
334
 
166
- PLAN 산출물 경로는 **엔진이 정한다.** `docs/spec.md`/`tests/app.test.js`가 비어 있으면
167
- 그대로 쓰고, 이미 뭔가 있으면 goal 해시로 비켜간다(`docs/spec-5d88cc7f.md`).
168
- 같은 프로젝트에서 goal만 바꿔 돌려도 앞의 산출물이 살아남는다.
335
+ ```bash
336
+ hi-loop config # 현재 정책 출력
337
+ hi-loop config set commitPolicy auto # 정책 변경 (branchPolicy|commitPolicy|commitStyle)
338
+ hi-loop config add-branch release # 보호 브랜치 추가
339
+ hi-loop config remove-branch dev # 보호 브랜치 제거
340
+ ```
169
341
 
170
- ### 테스트를 지워서 통과하는 것을 막는다 (bkit 철학)
342
+ ## 상태 초기화
171
343
 
172
- CHECK는 2단이다 `check.ok && integrity.ok`여야 통과. 판정 기준인 테스트를 에이전트가
173
- 지우거나 skip/always-true로 무력화하면 exit 0이 나와도 **통과로 인정하지 않는다.**
174
- 탐지 패턴(케이스 감소, `.skip`, `.only`, `assert.ok(true)`)은 bkit gap-detector의
175
- 가짜 완료 분류학에서 가져왔다. 테스트 **추가**는 위반이 아니다.
344
+ goal로 깨끗이 다시 시작하려면 상태 파일을 지운다:
345
+
346
+ ```bash
347
+ hi-loop reset # .agent-state.json 삭제 (CLI)
348
+ # MCP: hiloop_reset
349
+ ```
350
+
351
+ ---
176
352
 
177
- ### 같은 벽에 부딪히지 않는다
353
+ # 안전장치 루프 엔지니어링 원칙
178
354
 
179
- 같은 실패가 3회 연속이면 `stopReason: 'stagnated'`로 조기 종료한다 "이 접근으론 안 된다"를
180
- `--max-loops` 소진 전에 잡는다. `--stagnation N` 으로 조절, `--no-stagnation` 으로 끈다.
355
+ 원칙에서 파생된, 엔진이 **false green을 막는** 구체적 장치들이다.
181
356
 
182
- ### 통과가 무엇을 확인 했는지 공개한다 (MoAI 철학)
357
+ ### 세션 핸드오프 & 컨텍스트 다이어트
358
+
359
+ 에이전트는 같은 세션에서 오래 굴릴수록 토큰이 쌓여 멍청해진다. 그래서 4회마다 세션을
360
+ **버리고**, `.agent-state.json` 에 압축된 상태(goal / 스펙 요약 / 마지막 에러 / 최근 이력 5건)만
361
+ 새 세션에 넘겨 이어서 작업한다(auto-resume). 같은 goal로 다시 실행하면 중단 지점부터 재개한다.
362
+
363
+ ### TDD 자가 치유
364
+
365
+ 성패 판정은 항상 `testCommand` 의 exit code다. 에이전트의 자기보고는 판정에 쓰지 않는다.
366
+
367
+ ### 테스트를 지워서 통과하는 것을 막는다
368
+
369
+ CHECK는 2단이다 — `check.ok && integrity.ok` 여야 통과. 판정 기준인 테스트를 에이전트가
370
+ 지우거나 skip/always-true로 무력화하면 exit 0이 나와도 **통과로 인정하지 않는다.**
371
+ 탐지 패턴은 케이스 감소, `.skip`, `.only`, `assert.ok(true)` 등이다. 테스트 **추가**는 위반이 아니다.
183
372
 
184
- 엔진의 `passed`는 조용한 거짓말이 수 있다 — 테스트를 PLAN 단계에서 **에이전트 자신이**
373
+ ### 통과가 무엇을 확인 했는지 공개한다
374
+
375
+ 이 엔진의 `passed` 는 조용한 거짓말이 될 수 있다 — 테스트를 PLAN 단계에서 **에이전트 자신이**
185
376
  썼기 때문이다. 그래서 통과할 때마다 Evidence와 Gaps를 함께 출력한다:
186
377
 
187
378
  ```
@@ -191,33 +382,38 @@ CHECK는 2단이다 — `check.ok && integrity.ok`여야 통과. 판정 기준
191
382
  - 런타임·성능·보안은 관측 범위 밖이다.
192
383
  ```
193
384
 
194
- moai의 5-섹션 보고 규약에서 왔다. false green을 disclosed green으로 바꾼다.
385
+ false green을 disclosed green으로 바꾼다.
195
386
 
196
- ### 망가뜨려도 되돌린다 (bkit 철학)
387
+ ### 망가뜨려도 되돌린다
197
388
 
198
- 각 에이전트 호출 **전에** `git stash create`로 워킹트리를 스냅샷한다(비파괴 — 워킹트리를
199
- 안 건드리고 SHA만 남긴다). 에이전트가 멀쩡한 코드를 망가뜨리면:
389
+ 각 에이전트 호출 **전에** `git stash create` 워킹트리를 스냅샷한다(비파괴 — 워킹트리를
390
+ 안 건드리고 SHA만 남긴다). 에이전트가 멀쩡한 코드를 망가뜨리면 `hi-loop rollback` 으로
391
+ 복원한다. **자동 롤백은 없다** — 전경 실행이 기본이라 사람이 본다. git 저장소가 아니면
392
+ 조용히 생략한다.
200
393
 
201
- ```bash
202
- hi-loop rollback # 최신 체크포인트로 파일 복원
203
- hi-loop rollback --to 3 # 3회차 직전 상태로
204
- ```
394
+ ### 스펙을 오라클로 — 2단 판정 (`--verify-spec`)
205
395
 
206
- **자동 롤백은 없다** 전경 실행이 기본이라 사람이 본다(bkit도 자동 되돌리기를 무인 L4에만
207
- 건다). git 저장소가 아니면 조용히 생략한다.
396
+ 엔진의 exit 0은 "에이전트가 자기가 테스트를 통과시켰다"일 뿐이다. `--verify-spec`
397
+ 켜면 통과 **별도 검증자**가 스펙 대비 구현을 심판한다.
208
398
 
209
- ### 스펙을 오라클로 2단 판정 (bkit 중심 명제)
399
+ - **Tier 1 (기계)**: exit code + 무결성. 최종 권한. 실패면 끝.
400
+ - **Tier 2 (모델)**: 스펙 대조. **오직 기각만 가능** — 통과를 되돌릴 순 있어도 Tier 1 실패를
401
+ 통과로 못 올린다. 쓰기 권한 없이(`--permission-mode plan`) 새 세션으로 호출.
210
402
 
211
- `--verify-spec`을 켜면 테스트 통과 **별도 검증자**가 스펙 대비 구현을 심판한다.
212
- 이 엔진의 exit 0은 "에이전트가 자기가 쓴 테스트를 통과시켰다"일 뿐이므로:
403
+ 구조가 아니라 의도를 본다. 비용이 늘어 opt-in이다.
213
404
 
214
- - **Tier 1 (기계)**: exit code + 무결성. 최종 권한. 실패면 끝.
215
- - **Tier 2 (모델)**: 스펙 대조. **오직 기각만 가능** — 통과를 되돌릴 순 있어도
216
- Tier 1 실패를 통과로 올린다. 쓰기 권한 없이(`--permission-mode plan`) 세션으로 호출.
405
+ ### 💸 비용은 엔진이 센다 그리고 싸지 않다
406
+
407
+ **`--max-loops` 비용 상한이 아니다.** 실패 루프가 10회를 쓰면 비용이 크게 뛸 수 있다.
408
+ 그래서 `--budget-usd` 를 쓴다 — 누적이 상한에 닿으면 **다음 에이전트 호출 전에** 멈춘다.
409
+
410
+ ```bash
411
+ hi-loop run --goal "..." --max-loops 5 --budget-usd 1 --no-stagnation
412
+ # [hi-loop] 💸 예산 $1 소진 (누적 $1.61) — 2회차에서 중단합니다.
413
+ ```
217
414
 
218
- **실측**: 스펙이 "음수는 TypeError"를 요구하는데 테스트는 양수만 검사하고 구현이
219
- `(a,b)=>a+b`인 경우 테스트는 초록이었지만 검증자가 *"add(-1,2)는 예외 대신 1을
220
- 반환한다"*고 정확히 기각했다. 구조가 아니라 의도를 본다. opt-in(비용 증가).
415
+ `hi-loop status` 완료 로그에 누적 비용이 찍힌다. 모델은 사용자 기본값을 상속하므로
416
+ `HILOOP_AGENT_ARGS="--model sonnet"` 으로 낮출 있다.
221
417
 
222
418
  ## 환경변수
223
419
 
@@ -226,7 +422,7 @@ hi-loop rollback --to 3 # 3회차 직전 상태로
226
422
  | `HILOOP_AGENT_CMD` | 에이전트 실행 명령 (기본 `claude`) |
227
423
  | `HILOOP_AGENT_ARGS` | 에이전트에 덧붙일 인자 (공백 구분). 예: `--model sonnet` — 비용에 직결된다 |
228
424
  | `HILOOP_PERMISSION_MODE` | 권한 모드 (기본 `acceptEdits`). 편집 허용이 이 엔진의 전제다 |
229
- | `HILOOP_VERIFY_CMD` / `HILOOP_VERIFY_MODEL` | `--verify-spec` 검증자의 실행 명령·모델 (미설정 시 구현자와 동일). bkit처럼 검증에 더 센 모델을 쓸 수 있다 |
425
+ | `HILOOP_VERIFY_CMD` / `HILOOP_VERIFY_MODEL` | `--verify-spec` 검증자의 실행 명령·모델 (미설정 시 구현자와 동일). 검증에 더 센 모델을 쓸 수 있다 |
230
426
  | `HILOOP_REVIEW_CMD` / `HILOOP_REVIEW_MODEL` | 설계·코드 리뷰어의 실행 명령·모델 (미설정 시 `HILOOP_VERIFY_*` → 구현자 순으로 폴백) |
231
427
  | `HILOOP_DISCOVER_CMD` / `HILOOP_DISCOVER_MODEL` | 발굴 단계의 실행 명령·모델 |
232
428
  | `HILOOP_AGENT_TIMEOUT_MS` / `HILOOP_TEST_TIMEOUT_MS` | 에이전트(30분)·테스트(10분) 타임아웃. 쓰레기값은 기본값으로 되돌림 |
@@ -241,24 +437,28 @@ npm test # node:test, devDependency 0개
241
437
  ## 구조
242
438
 
243
439
  ```
244
- bin/hi-loop.js CLI 엔트리포인트 (CLI / MCP 분기 + rollback + answer + 단계별 실행)
440
+ bin/hi-loop.js CLI 엔트리포인트 (CLI / MCP 분기 + rollback + answer + 단계별 실행)
245
441
  bin/setup.js 프로젝트·클로드코드 설정 자동 주입
246
442
  src/loop.js 라이프사이클 stage 머신 — 다음 stage 를 정하는 권한은 여기 한 곳뿐
247
443
  src/build.js 안쪽 자가 치유 루프 — 예산·정체·무결성·2단 판정·핸드오프 집행
248
444
  src/stages.js DISCOVER / CODE_REVIEW / SHIP / WATCH 핸들러 (지시만 반환)
249
- src/discover.js DISCOVER — 요구사항 발굴, 가정 확정, 분기 감지 (FR-10)
250
- src/review.js DESIGN_REVIEW / CODE_REVIEW — 격리된 Tier 2 심판 (FR-11, FR-12)
251
- src/ship.js SHIP / WATCH — 배포·헬스체크. 에이전트를 부르지 않는다 (FR-13, FR-14)
252
- src/ask.js ask 모드pause/resume 상태머신, 가정 기록 (FR-16)
253
- src/report.js 완료 보고Gaps 공개(L10) + 상태 요약
445
+ src/discover.js DISCOVER — 요구사항 발굴, 가정 확정, 분기 감지
446
+ src/review.js DESIGN_REVIEW / CODE_REVIEW — 격리된 Tier 2 심판
447
+ src/ship.js SHIP / WATCH — 배포·헬스체크. 에이전트를 부르지 않는다
448
+ src/vcs.js 브랜치·커밋 메커니즘프리스텝·COMMIT 스테이지·git log 스타일 감지
449
+ src/config.js .hi-loop.json 정책 저장소 브랜치·커밋 정책의 단일 진실 원천
450
+ src/ask.js ask 모드 — pause/resume 상태머신, 가정 기록
451
+ src/checks.js 다중 조건 검사 — --check/--when, short-circuit 없음
452
+ src/blast.js 블라스트 반경 — 변경의 위험 분류를 공개
453
+ src/report.js 완료 보고 — Gaps 공개 + 상태 요약
254
454
  src/cli-options.js CLI 인자 → runLoop 옵션 번역 (잘못된 값은 조용히 흘리지 않는다)
255
455
  src/state.js .agent-state.json (원자적 저장 + 다이어트 + 산출물 경로 + resume + Gaps)
256
- src/runners.js 에이전트/테스트 실행 어댑터 (주입 가능) + 비용 파싱 + 타임아웃 (L6)
456
+ src/runners.js 에이전트/테스트 실행 어댑터 (주입 가능) + 비용 파싱 + 타임아웃
257
457
  src/prompts.js PDCA 단계별 프롬프트 + 검증자 프롬프트
258
- src/integrity.js 테스트 무결성 지문·비교 — 보상 해킹 방어 (L1)
259
- src/checkpoint.js git stash 체크포인트·롤백 (L3) + 삭제 관측 (L8)
260
- src/verify.js 스펙 오라클 — Tier 2 검증자 (L9)
261
- src/lock.js 동시 실행 pid 락 (L4)
458
+ src/integrity.js 테스트 무결성 지문·비교 — 보상 해킹 방어
459
+ src/checkpoint.js git stash 체크포인트·롤백 + 삭제 관측
460
+ src/verify.js 스펙 오라클 — Tier 2 검증자
461
+ src/lock.js 동시 실행 pid 락
262
462
  src/mcp-server.js MCP 프로토콜 통신
263
463
  src/telegram.js 텔레그램 비동기 알림
264
464
  src/args.js 의존성 없는 인자 파서