npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tuzi-ince/hi-loop

v0.6.1

Published

CLI와 MCP 모드를 지원하는 초경량 자율형 자가 치유 엔진

Readme

hi-loop

CLI와 MCP 모드를 지원하는 초경량 자율형 자가 치유 엔진.

날것의 아이디어(goal)를 던지면, AI 에이전트를 PDCA 루프로 반복 구동해 테스트가 실제로 통과할 때까지 스스로 고쳐 나간다.

루프 엔지니어링 — 우리의 개발 철학

이 엔진은 "AI가 코드를 잘 짜준다"에 기대지 않는다. AI는 자주 틀리고, 더 자주 틀린 것을 다 됐다고 말한다. 그래서 우리는 모델의 자기보고를 판정에서 배제하고, 기계가 검증할 수 있는 종료 조건 위에 루프를 세운다. 세 문장이 전부다.

  1. 산문은 요청이고, 메커니즘은 사실이다. 보고서에 "이건 검증 안 됨"이라고 적는 것은 요청일 뿐이다. 한 번 더 돌려서 측정하면 그 문장이 사실이 된다. 그래서 이 엔진은 문장을 늘리기보다 검사를 하나 더 돌린다.
  2. 에이전트의 "다 됐어요"는 판정이 아니다. 성패는 언제나 testCommand의 exit code다. 엔진이 직접 실행해서 확인한다.
  3. 종료 조건 없는 단계는 엔진의 단계가 아니라 문서 생성기다. 모든 단계는 기계가 판정할 통과 기준을 가진다. 없으면 그 단계는 만들지 않는다.

이 세 원칙에서 뒤의 안전장치들이 전부 파생된다.

설치

# 1) 전역 설치 — hi-loop / hi-loop-setup 명령 등록
npm install -g @tuzi-ince/hi-loop

# 2) 프로젝트에 주입 (멱등 — 여러 번 돌려도 안전)
cd /path/to/my-project
hi-loop-setup            # .mcp.json / .gitignore / docs·tests / CLAUDE.md / docs/DESIGN.md 자동 주입
hi-loop-setup --host cursor     # Cursor 용 .cursor/mcp.json 에 등록
hi-loop-setup --host opencode   # opencode 용 opencode.json 에 등록

MCP 서버는 표준 stdio 라 Cursor·opencode 등 다른 호스트에도 --host 로 등록된다. 단 스킬·CLAUDE.md 자동 라우팅은 Claude Code 전용이고, 다른 호스트에선 루프의 일꾼도 claude 가 아니라면 HILOOP_AGENT_PROVIDER=generic 이 필요하다(claude 외 CLI 이식 — 세션·비용 미지원). 자세히는 가이드 §4-2/§4-3.

hi-loop-setup 은 표준 설계 문서 docs/DESIGN.md 를 함께 만든다(있으면 보존). 이 문서를 채우면 문서↔소스 정합 장치(--reconcile-spec / --spec)의 오라클이 된다 — 아래 문서↔소스 정합 참조.

소스에서 개발용으로 설치하려면:

git clone <이 저장소> hi-loop && cd hi-loop
npm install && npm test   # node:test, devDependency 0개
npm link                  # hi-loop / hi-loop-setup 명령 등록

자세한 절차·문제해결·배포는 docs/guide.md.

두 가지 실행 모드

# 1) CLI 직접 실행 — 터미널, 백그라운드 데몬, 텔레그램 봇에서 구동
hi-loop run --goal "JWT 인증 미들웨어를 만들어라" --test "npm test" --max-loops 10 --budget-usd 5

# 2) MCP 서버 — 클로드코드/커서가 도구로 로드 (인자 없으면 기본 동작)
hi-loop mcp

hi-loop status           # 현재 루프 상태 요약

MCP 도구: hiloop_run, hiloop_answer, hiloop_status, hiloop_reset, hiloop_rollback, hiloop_setup, hiloop_docsync.

동작 원리

PLAN  ──► SPEC.md + tests/app.test.js 를 먼저 강제 (구현 코드 금지)
DO    ──► 테스트를 통과시킬 최소 구현
CHECK ──► 엔진이 testCommand 를 직접 실행 (에이전트의 "다 됐어요"는 안 믿는다)
ACT   ──► stderr 를 그대로 에이전트에 들이밀고 "이 에러를 고쳐라" (최대 10회)

기본은 이 자가 치유 루프 하나다. --full 을 붙이면 앞뒤 단계까지 돈다.

DISCOVER → PLAN → DESIGN_REVIEW → BUILD(DO ⇄ CHECK ⇄ HEAL) → CODE_REVIEW → SHIP → WATCH → DONE
             ▲          │                                          │                │
             └── reject ┘                                 reject ──┘       fail ────┘

추가되는 모든 단계는 기계가 판정할 종료 조건을 가진다.

| 단계 | 무엇을 하는가 | 종료 조건 | |---|---|---| | DISCOVER | goal 의 모호함을 가정으로 확정하고 문서화 | 가정 목록 확정 | | PLAN | 스펙 + 테스트를 먼저 쓴다 (구현 금지) | 산출물 작성 | | DESIGN_REVIEW | 구현 착수 전 스펙을 심판 | 독립 검증자 pass | | BUILD | DO ⇄ CHECK ⇄ HEAL 자가 치유 루프 | testCommand exit 0 | | CODE_REVIEW | diff 를 정확성·보안·YAGNI 축으로 심판 | 독립 검증자 pass | | SHIP | 배포 명령 실행 | exit code 0 | | WATCH | 헬스체크 반복 | 지정 시간 동안 버팀 |

배포·감시는 에이전트를 부르지 않는다. "배포했다고 모델이 말했다"가 아니라 "헬스체크 exit code 가 0이다"가 통과 조건이다. 그래서 이 두 단계의 비용은 0이다.


실전 활용 가이드 (프로젝트 관리 관점)

무엇을 하려는지에 따라 어떻게 goal을 쓰고 어떤 플래그를 켜는지가 달라진다. 아래는 실제 프로젝트를 굴리며 자주 만나는 상황별 레시피다.

1. 프로젝트 생성 — 아이디어 한 줄 → 동작하는 코드

모호한 요구를 발굴부터 구현·리뷰까지 한 번에 돌린다. --full 이 앞뒤 단계를 켠다.

hi-loop run --goal "JWT 인증 미들웨어를 만들어라" --full --budget-usd 5
  • DISCOVER 가 goal의 빈칸(토큰 저장 위치, 만료 정책 등)을 가정으로 확정하고 문서화한다.
  • PLAN 이 스펙과 테스트를 먼저 쓴다 — 구현보다 판정 기준이 앞선다.
  • DESIGN_REVIEW → BUILD → CODE_REVIEW 순으로 만들고, 만든 것을 스스로 심판한다.
  • 상호배타 분기(예: "users 확장 vs auth_tokens 신설")를 만나면 거기서만 사람에게 묻는다.

기존 파일을 덮어쓰지 않는다. docs/SPEC.md / tests/app.test.js 가 비어 있으면 그대로 쓰고, 이미 뭔가 있으면 goal 해시로 비켜간다(docs/spec-5d88cc7f.md). 같은 프로젝트에서 goal만 바꿔 여러 번 돌려도 앞의 산출물이 살아남는다.

발굴 단계만 먼저 돌려 요구사항을 확정하고 싶다면:

hi-loop discover --goal "..."   # 가정 확정 + 문서만, 구현은 안 함

2. 프로젝트 개선 — 기존 코드베이스 손질

리팩터링·성능 개선·기술부채 정리처럼 이미 테스트가 있는 코드를 고칠 때. 기존 테스트를 가드레일로 두고, 스펙 대비 검증을 더 얹는다.

hi-loop run --goal "결제 모듈의 중복 검증 로직을 하나로 합쳐라" \
  --test "npm test" \
  --spec docs/SPEC.md \
  --verify-spec
  • 기존 npm test 가 회귀 방지선이다 — 개선하다 무언가 깨면 Tier 1에서 걸린다.
  • --verify-spec 은 테스트 통과 후 별도 검증자가 스펙 대비 구현을 심판한다. 구조가 아니라 의도를 본다("리팩터링했다"는데 동작이 달라졌으면 기각).
  • --spec docs/SPEC.md 는 사람이 관리하는 표준 문서를 오라클로 고정한다 — 단말적 개선 요청이 문서와 어긋나는 것을 잡는다(→ 문서↔소스 정합).
  • 개선 중 락파일·설정·마이그레이션을 건드리면 보고서 Gaps에 ⚠️로 공개된다 (→ 영향도 분석).

3. 장애 분석 — 버그·회귀 재현 → 수정

버그를 "고쳤다"가 아니라 "재현 테스트로 못박고 고쳤다"로 끝낸다. 회귀 방지가 공짜로 남는다.

hi-loop run --goal "재현 테스트를 먼저 작성하고, 동시 요청 시 잔액이 음수가 되는 버그를 고쳐라" \
  --test "npm test" \
  --stagnation 3
  • PLAN이 실패하는 재현 테스트를 먼저 강제한다 → 버그가 테스트로 고정된다.
  • HEAL이 실제 stderr를 연료로 삼아 고친다. 모델의 추측이 아니라 진짜 에러를 본다.
  • 같은 벽에 열 번 부딪히지 않는다: 같은 실패가 3회 연속이면 stagnated 로 조기 종료한다 — "이 접근으론 안 된다"를 --max-loops 소진 전에 잡는다. --no-stagnation 으로 끈다.
  • 에이전트가 멀쩡한 코드를 오히려 망가뜨렸으면 되돌린다:
    hi-loop rollback            # 최신 체크포인트로 파일 복원
    hi-loop rollback --to 3     # 3회차 직전 상태로

4. 영향도 분석 — 변경 위험 파악

이 변경이 어디까지 번지는가를 두 층위로 잡는다.

(a) 블라스트 반경 — 자동, 비용 0. 실행이 위험 분류 파일을 건드리면 판정과 무관하게 보고서 Gaps에 ⚠️로 공개한다. 분류: 의존성(lock/package.json), 스키마 마이그레이션, CI·배포 설정, 빌드·러너 설정, 환경 변수. "테스트는 통과했는데 왜 락파일이 바뀌었지"를 사람이 놓치지 않게 한다.

(b) 조건부 검사 — 바뀐 파일에 따라 게이트를 켠다. 무거운 검사(e2e 등)를 매 회차 돌리는 대신, 특정 경로에 변경이 있을 때만 돌린다. --when 은 git status(HEAD 대비 워킹트리 변경)로 매칭한다 — 즉 "그 경로를 건드린 그 회차만"이 아니라 커밋 전 변경분에 그 경로가 있는 한 이후 회차마다 검사가 돈다(2회차에 e2e 가 사라지지 않게 하려는 의도).

hi-loop run --goal "..." \
  --check "npm test" \
  --check "npm run typecheck" \
  --check "npx playwright test" --when "src/ui/**"
  • 검사는 short-circuit 하지 않는다. 유닛이 깨져도 typecheck·e2e 결과를 같은 회차에 다 본다 (&& 로 이으면 첫 실패에서 멈춰 나머지를 영영 모른다).
  • --when 글롭에 안 맞은 검사는 건너뜀으로 기록된다 — 안 돌린 것이 통과처럼 보이지 않게 Gaps에 남는다.

MCP 에서도 같은 걸 쓴다 — "UI 변경 회차에만 e2e"를 엔진이 강제한다. hiloop_run 이 checks 인자를 받는다(CLI --check/--when 의 MCP 노출):

"checks": [
  { "cmd": "npm test" },
  { "cmd": "npx playwright test", "when": "src/**/*.tsx" }
]
  • e2e 를 "스킬이 사람에게 기억해서 실행"(제안)이 아니라 엔진이 결정론적으로 강제(메커니즘)하는 길이다. UI 파일이 바뀐 회차마다 엔진이 e2e 를 돌리고 통과해야 pass 로 인정한다 — 조용히 빠지지 않는다.
  • e2e 는 셸 명령이어야 한다. 엔진은 Playwright MCP 도구를 부를 수 없으므로, MCP 만 있는 프로젝트는 flow 스킬이 루프 통과 후 MCP 로 돌린다(폴백). 셸 e2e 명령도 없으면 스킵.
  • flow 스킬이 UI 작업을 감지하면 사용자에게 물은 뒤 이 checks 를 자동 구성해 hiloop_run 에 넘긴다.

diff만 리뷰하고 싶다면 — 지금 워킹트리 변경분을 정확성·보안·YAGNI 축으로 심판:

hi-loop review              # 현재 변경분만 코드 리뷰 (구현/배포는 안 함)

5. 테스트·품질 게이트

테스트 설계만 뽑고 싶을 때 (구현은 사람이 하거나 나중에):

hi-loop plan --goal "장바구니 할인 규칙"   # 스펙 + 테스트까지만, 구현 전

플레이키(불안정) 테스트를 걸러내고 싶을 때:

hi-loop run --goal "..." --flaky-probe
  • 통과한 회차에서만 같은 테스트를 한 번 더 돌린다. 두 번의 결과가 갈리면 통과로 인정하지 않는다("두 번 돌려 갈리는 초록불은 초록불이 아니다"). 에이전트 호출 0 — 비용은 테스트 한 번뿐.

여러 게이트를 한 판정에 묶고 싶을 때 — 위 조건부 검사의 --check 를 여러 번 준다. lint·typecheck·유닛·e2e를 각각 독립된 게이트로 세운다.

6. 배포 & 감시 — 사람 개입 최소

리뷰를 통과한 변경을 배포하고, 배포 후 일정 시간 헬스체크로 버티는지 지켜본다.

hi-loop run --goal "..." --full \
  --ship "npm publish --access public" \
  --watch "curl -f https://api.example.com/health" --watch-for 5m
  • --ship 을 주면 리뷰 단계들이 자동으로 켜진다 ("리뷰 없는 자동 배포는 위험하다"의 근거가 여기서만 성립).
  • SHIP/WATCH는 에이전트를 부르지 않는다 — 통과 조건은 오직 exit code다.
  • 실패 대응을 지정할 수 있다: --on-ship-fail stop|heal, --on-watch-fail stop|rollback|heal.
  • 비가역 배포 직전에는 사람에게 확인을 구한다. CI·봇에서는 --yes 로 생략.

7. 단계별로 따로 부르기

전체를 한 번에 돌리지 않고, 필요한 구간만 실행할 수 있다. 어느 경로로 들어와도 같은 상태 머신을 쓴다.

hi-loop discover --goal "..."     # 발굴만 (가정 확정 + 문서)
hi-loop plan     --goal "..."     # 스펙·테스트까지만 (구현 전)
hi-loop review                    # 현재 변경분만 코드 리뷰
hi-loop ship     --ship "npm publish"
hi-loop watch    --watch "curl -f ..."

또는 --start-from / --stop-after 로 한 실행의 구간을 자른다:

hi-loop run --goal "..." --start-from BUILD --stop-after CODE_REVIEW

후반 단계는 --goal 을 다시 받지 않는다 — 저장된 상태에서 읽는다(goal이 한 글자만 달라도 새 루프로 인식돼 진행 상황이 버려진다). PLAN은 BUILD 안쪽의 회차라 --start-from 대상이 아니다 — BUILD로 시작하면 자연히 PLAN부터 돈다.

8. MCP에서 팀으로 쓰기 (클로드코드/커서)

hi-loop mcp 로 띄우면 호스트 LLM이 위 시나리오를 도구로 호출한다. 차단형 입력을 쓰지 않고 상태를 저장하고 종료하므로(exit 3) 대화형 세션·백그라운드 데몬·봇에서 그대로 성립한다.

호스트 LLM ──hiloop_run──► 루프 구동
           ◄──분기 질문─── (상호배타 선택 필요)
           ──hiloop_answer──► 사람의 선택을 "가정"으로 기록하고 재개
           ──hiloop_status──► 진행/비용/Gaps 조회

9. 코드 어시스턴트가 요청을 처리하는 방식 — 직접 호출 vs 평문 요청

클로드코드·커서 같은 코드 어시스턴트(호스트 LLM) 안에서 hi-loop은 두 갈래로 불린다. 핵심은 "LLM이 요청을 읽는 순간, hi-loop을 떠올릴 근거가 눈앞에 있느냐" 다.

(a) 직접 호출 — 명시적으로 엔진을 지목

사용자가 hi-loop을 대놓고 부른다. LLM은 바로 hiloop_run을 구동한다(목표만 확정).

| 사용자가 이렇게 말하면 | LLM이 하는 일 | |---|---| | /flow 로그인 폼 만들어줘 (슬래시 스킬, /hi-loop:flow 도 동일) | flow 스킬 기동 → hiloop_run(full=true, step=true) 실행 — 대화형이라 스텝 모드로 매 스텝을 보이며 진행 | | /flow plan 로그인 폼 (단계어) | 첫 단어가 단계면 그 단계까지만: stopAfter:"PLAN" → 스펙·테스트만 만들고 멈춰 다음(구현) 제안. do/review/ship 등도 동일 | | "hiloop_run 도구로 결제 버그 고쳐줘" | 지목된 MCP 도구를 로드해 바로 호출 | | 터미널에서 hi-loop run --goal "..." --full | 엔진을 CLI로 직접 구동(LLM 개입 없음) |

(b) 평문 요청 — 그냥 하고 싶은 일을 말함

사용자는 hi-loop을 언급하지 않는다. 이때 자동으로 hi-loop에 걸리는 건 트리거가 박힌 스킬 description + CLAUDE.md 지침이 매 세션 떠 있기 때문이다(설치 + hi-loop-setup 전제). 그 표면이 없으면 LLM은 hi-loop을 모른 채 그냥 직접 구현한다.

| 사용자가 이렇게 말하면 | 어디에 걸리나 | LLM이 하는 일 | |---|---|---| | "워크스페이스 폴더 드래그앤드롭 개선해줘" | 트리거 개선 | flow 스킬 후보로 뜸 → 기획·설계 필요 판단 → flow 실행(대화형이라 step 으로 매 스텝 보이며 진행) | | "장바구니 기능 하나 만들어줘" | 트리거 기능/design | 발굴→스펙·테스트 우선(PLAN)→구현·리뷰 루프 | | "결제 모듈 리팩터해줘" | 트리거 리팩터 | 기존 테스트를 가드레일로 --verify-spec 성격의 개선 루프 | | "동시 요청 시 잔액 음수 버그 고쳐줘" | 트리거 구현/버그성 | 재현 테스트 먼저 → HEAL 루프로 수정 | | "이 오타 고쳐줘" / "변수명 바꿔줘" | 예외(사소) | 루프 없이 바로 처리 — README·CLAUDE.md가 사소한 작업은 제외하라고 명시 |

왜 이렇게 갈리나 (push vs pull)

  • 트리거 스킬 description·CLAUDE.md = push 표면. LLM이 찾지 않아도 매 세션 상주하며, 평문에 개선/설계/버그 같은 단어가 있으면 자동으로 hi-loop을 후보로 올린다.
  • MCP 도구 = pull 표면. 세션에선 이름만 있고(때로 deferred), LLM이 먼저 "hi-loop이 필요하다"고 떠올려 ToolSearch로 끌어와야 설명이 보인다.
  • 그래서 평문 요청이 자동 라우팅되려면 push 표면이 반드시 있어야 한다. hi-loop-setup이 CLAUDE.md 지침을 심고, 플러그인이 트리거 스킬을 등록하는 이유가 이것이다. 이게 없으면 "개선해줘"라고 해도 LLM은 hi-loop을 거치지 않고 곧장 코드부터 짠다.

확실히 hi-loop을 태우고 싶으면 (a) 직접 호출이 가장 안전하다. (b) 평문 자동 라우팅은 편하지만, 설치·주입이 안 됐거나 트리거에 안 걸리는 표현이면 우회될 수 있다.

브랜치 & 커밋 워크플로 (FR-16)

코드 변경 작업을 보호 브랜치에서 분기 → 구현·테스트 → 로컬 커밋으로 감싼다. push/PR 은 하지 않는다.

정책은 커밋되는 .hi-loop.json 한 파일에 산다(팀 공유, 스킬·엔진 공용). .hi-loop/STATE.json (임시·gitignore)과 다르다. 기본값:

{
  "protectedBranches": ["main", "master", "develop", "dev"],
  "branchPolicy": "ask",     // always=자동 분기 | ask=매번 확인 | never
  "commitPolicy": "confirm", // confirm=메시지+diff 확인 후 | auto | off
  "commitStyle": "match-log" // match-log=git log 관행 미러 | conventional | korean
}

두 실행 층 (같은 정책 파일):

  • 대화형(스킬/코드 어시스턴트): 코드변경 요청 시 .hi-loop.json 이 없으면 최초 1회 정책을 묻고 저장(지연 발동). 이후 보호 브랜치면 분기 게이트, 테스트 통과 후 커밋 게이트(diff 보여주고 승인)를 태운다. "이번만 커밋하지 마"(일회성)와 "앞으로 커밋하지 마"(정책 변경)를 구분한다.
  • 헤드리스(CLI/봇/CI): 물어볼 수 없으니 플래그 = 동의.
hi-loop run --goal "..." --branch --commit          # 보호 브랜치면 자동 분기 + 통과 후 자동 커밋
hi-loop run --goal "..." --branch feature/login     # 브랜치명 지정
hi-loop run --goal "..." --commit --commit-message "feat: 로그인"

.hi-loop.json 의 branchPolicy: always / commitPolicy: auto 는 CLI 에서 플래그 없이도 발동한다 (플래그가 우선). 커밋 스테이지는 상태 머신에서 CODE_REVIEW → COMMIT → SHIP 사이에 든다 — 리뷰된 코드를 커밋한 뒤 배포한다.

정책 관리:

hi-loop config                          # 현재 정책 출력
hi-loop config set commitPolicy auto    # 정책 변경 (branchPolicy|commitPolicy|commitStyle)
hi-loop config add-branch release       # 보호 브랜치 추가
hi-loop config remove-branch dev        # 보호 브랜치 제거

상태 초기화

새 goal로 깨끗이 다시 시작하려면 상태 파일을 지운다:

hi-loop reset               # .hi-loop/STATE.json 삭제 (CLI)
# MCP: hiloop_reset

안전장치 — 루프 엔지니어링 원칙

위 세 원칙에서 파생된, 이 엔진이 false green을 막는 구체적 장치들이다.

세션 핸드오프 & 컨텍스트 다이어트

에이전트는 같은 세션에서 오래 굴릴수록 토큰이 쌓여 멍청해진다. 그래서 4회마다 세션을 버리고, .hi-loop/STATE.json 에 압축된 상태(goal / 스펙 요약 / 마지막 에러 / 최근 이력 5건)만 새 세션에 넘겨 이어서 작업한다(auto-resume). 같은 goal로 다시 실행하면 중단 지점부터 재개한다.

TDD 자가 치유

성패 판정은 항상 testCommand 의 exit code다. 에이전트의 자기보고는 판정에 쓰지 않는다.

테스트를 지워서 통과하는 것을 막는다

CHECK는 2단이다 — check.ok && integrity.ok 여야 통과. 판정 기준인 테스트를 에이전트가 지우거나 skip/always-true로 무력화하면 exit 0이 나와도 통과로 인정하지 않는다. 탐지 패턴은 케이스 감소, .skip, .only, assert.ok(true) 등이다. 테스트 추가는 위반이 아니다.

통과가 무엇을 확인 안 했는지 공개한다

이 엔진의 passed 는 조용한 거짓말이 될 수 있다 — 테스트를 PLAN 단계에서 에이전트 자신이 썼기 때문이다. 그래서 통과할 때마다 Evidence와 Gaps를 함께 출력한다:

관측하지 않은 것(Gaps):
- 이 테스트는 에이전트 자신이 작성했다. 외부 오라클이 아니다.
- 스펙의 어떤 수용 기준이 커버 안 됐는지는 검증하지 않았다.
- 런타임·성능·보안은 관측 범위 밖이다.

false green을 disclosed green으로 바꾼다.

망가뜨려도 되돌린다

각 에이전트 호출 전에 git stash create 로 워킹트리를 스냅샷한다(비파괴 — 워킹트리를 안 건드리고 SHA만 남긴다). 에이전트가 멀쩡한 코드를 망가뜨리면 hi-loop rollback 으로 복원한다. 자동 롤백은 없다 — 전경 실행이 기본이라 사람이 본다. git 저장소가 아니면 조용히 생략한다.

스펙을 오라클로 — 2단 판정 (--verify-spec)

이 엔진의 exit 0은 "에이전트가 자기가 쓴 테스트를 통과시켰다"일 뿐이다. --verify-spec 을 켜면 통과 후 별도 검증자가 스펙 대비 구현을 심판한다.

  • Tier 1 (기계): exit code + 무결성. 최종 권한. 실패면 끝.
  • Tier 2 (모델): 스펙 대조. 오직 기각만 가능 — 통과를 되돌릴 순 있어도 Tier 1 실패를 통과로 못 올린다. 쓰기 권한 없이(--permission-mode plan) 새 세션으로 호출.

구조가 아니라 의도를 본다. 비용이 늘어 opt-in이다.

문서를 상시 오라클로 — 표준 문서 고정 (--spec)

구현하다 보면 단말적 요청들이 작성된 문서와 상이하게 들어와 문서↔소스 갭이 생기고, 그 갭이 환각의 빌미가 된다. 기본 동작은 goal마다 스펙을 새로 만들어(goal 해시 분기) 이 갭을 막지 못한다 — 스펙 파일만 여러 개로 늘 뿐이다. --spec <path> 가 이 구멍을 닫는다.

hi-loop run --goal "..." --spec docs/SPEC.md --verify-spec
  • 스펙 오라클을 이 경로로 고정한다. DESIGN_REVIEW·CODE_REVIEW·--verify-spec 이 모두 state.specPath 하나에서 읽으므로, 셋 다 이 표준 문서를 기준으로 심판한다.
  • goal이 달라도 같은 문서를 오라클로 공유한다 — 새 요청이 문서와 어긋나면 오라클이 잡는다.
  • 고정한 문서에 이미 내용이 있으면 PLAN이 덮어쓰지 않는다. 사람이 관리하는 표준 문서를 진실로 받아들이고, 그에 맞춰 테스트만 쓴다. 비어 있을 때만 스펙을 작성한다.

기본(자기서술 스펙)은 "에이전트가 자기가 쓴 테스트를 통과"일 뿐이다(Gaps가 이를 공개한다). --spec으로 외부 오라클을 주면 그 한계를 좁힌다.

문서와 어긋나는 요청을 조용히 넘기지 않는다 (--reconcile)

--spec이 "이 문서를 오라클로 써라"라면, --reconcile은 **"이 요청이 기존 문서와 모순되는지 먼저 확인하라"**다. 표준 문서를 고정하지 않아도, 요청이 문서를 배신하는 순간을 잡는다.

hi-loop run --goal "결제에서 음수 잔액도 허용하라" --reconcile   # --full 이면 자동 켜짐
  • 기존 표준 문서가 있고 이번 요청이 그것과 별개 스펙으로 포크될 참이면, 포크 직전에 별도 판정자(plan 모드, 새 세션)가 goal과 표준 문서를 대조한다.
  • 대조 대상 우선순위: --reconcile-spec <path>(명시) → docs/SPEC.md가 아니라 docs/DESIGN.md (setup이 만드는 사람 관리 표준 문서) → 없으면 docs/SPEC.md 폴백. 즉 hi-loop-setup을 했다면 --full/--reconcile만으로 별도 지정 없이 DESIGN.md가 자동으로 오라클이 된다. (SPEC.md는 PLAN이 쓴 에이전트 산출물이라 오라클로 약하다 — 사람 문서가 있으면 그쪽이 옳다.)
  • 모순이면 멈추고 사람에게 묻는다(상호배타 3지선다): (a) 표준 문서를 오라클로 고정하고 진행 / (b) 새 스펙으로 분기(요청이 문서를 갱신) / (c) 중단하고 문서를 먼저 정리.
  • 모순이 없으면(또는 표준 문서가 없으면) 판정자를 부르지도 않는다 — 비용 0. 판정 실패는 통과로 흘린다(애매한 것까지 막으면 정상 작업이 멈춘다). opt-in.

이것이 "단말적 요청이 문서와 상이하게 들어와 갭이 벌어지는" 상황을 엔진 차원에서 막는 장치다. --spec(고정)과 --reconcile(감지)은 짝으로 쓰면 문서↔소스 정합이 가장 단단하다.

소스를 바꿨으면 문서도 맞춘다 — hiloop_docsync / hi-loop docsync / /flow doc-sync

--spec/--reconcile이 drift를 예방하는 게이트라면, doc-sync는 이미 바뀐 소스에 맞춰 문서를 갱신하는 단발 패스다. git diff로 소스 변경을 읽어 일꾼 에이전트가 문서만(README·docs/*) 고친다.

hi-loop docsync            # 소스 변경 → 문서 반영 (한 번의 패스, 진행 표시)
# 또는 스킬: /flow doc-sync   ·   MCP: hiloop_docsync
  • docs/DESIGN.md(사람 오라클)와 소스·테스트는 건드리지 않는다. 문서 외 편집은 stray로 경고.
  • diff로 확인되는 것만 반영한다(없는 내용을 지어내지 않음). 커밋은 사람이 판단한다.
  • 자가 치유 루프가 아니라 짧은 단발이라 타임아웃/블랙박스가 없다. MCP/CLI라 소비 프로젝트에서도 동작.

에이전트를 못 부르면 스택이 아니라 지침을 준다 (preflight)

에이전트(claude) 미설치·인증 만료·API 키 부재는 이 엔진의 버그가 아니라 환경 문제다. 루프 한복판의 스택트레이스가 아니라 행동지침 한 줄로 바꾼다.

  • 에이전트를 부르는 명령은 루프 진입 전 claude --version(비용 0)으로 실행 가능성을 확인한다. 미설치(ENOENT)·권한(EACCES)이면 회차를 태우지 않고 멈추며 설치·HILOOP_AGENT_CMD 안내를 준다.
  • 인증/구독/키 문제는 --version으론 알 수 없다(비용을 안 들인다). 첫 호출 stderr를 패턴으로 읽어 힌트로 번역하고, 못 알아본 실패는 원문을 그대로 보여준다(감추지 않는다).
  • 환경 오류는 CLI에서 스택 없이 메시지만, MCP에선 접두 없이 그대로 전달한다. 진짜 버그만 스택을 노출한다.

MCP는 호스트가 정한 프로젝트를 앵커로 삼는다

MCP 도구의 cwd 기본값은 CLAUDE_PROJECT_DIR || process.cwd() 다 — 호스트(클로드코드/커서)가 "어느 프로젝트인가"로 주입하는 값을 따른다. 호출 시 cwd를 명시하면 그것이 최우선. (CLI는 반대로 순수 process.cwd() — 터미널에서 cd한 곳이 사용자의 명시 의도이고, 통합 터미널에 새어든 env가 그것을 덮으면 하위 프로젝트 겨냥이 깨지기 때문이다.)

🛑 실패를 어떻게 멈출까 — 카운트 대신 사람 판단 (--on-fail)

기본은 --max-loops(10)까지 자동 치유다(무인 환경 백스톱). 하지만 대화형·비싼 검사(e2e)에서는 카운트보다 사람 판단이 낫다 — --on-fail 로 정한다:

| 값 | 동작 | |---|---| | heal (기본) | --max-loops 안에서 자동 치유 (종전) | | stop | 첫 실패에서 즉시 종료 | | ask | 실패/불능에서 "재시도할까 / 종료할까"를 사람에게 물음 (pause/resume). MCP 에선 awaiting 반환 → hiloop_answer 로 답하고 재호출 |

ask 는 비싼 e2e 루프에 특히 유용하다 — 8.5분·수달러짜리 회차를 무인으로 반복하지 않고, **판정 불능(무결성·환경)**까지 사람에게 표면화한다. 무인(--ask never)에선 물을 수 없으니 안전하게 종료한다.

⏭ 스텝 모드 — LLM 이 루프를 몰고, 매 스텝이 보인다 (step)

기본은 한 콜에서 엔진이 루프 전체를 돈다(모델 A: 무인·결정론에 최적). 대화형에선 이게 불투명하고(진행이 콘솔에 안 보임) 길어서 타임아웃 위험이 있으며 에이전트를 두 번(바깥 LLM + 서브프로세스 claude) 쓴다. step 을 주면 매 단위 작업(BUILD 회차·각 stage) 후 제어를 LLM 에게 돌려준다(모델 B):

hiloop_run({ goal, step: true })
  └▶ ⏭ 스텝 완료 (PLAN) → LLM 이 진행을 알리고 같은 goal 로 재호출
  └▶ ⏭ 스텝 완료 (DO) …  └▶ ✅ 통과 / ❌ 실패 / ⏸ awaiting

매 스텝이 콘솔에 보이고, 콜당 에이전트 1콜이라 타임아웃이 없다. 상태가 STATE.json 에 저장돼 재개는 자동이며, 통과 판정은 그대로 엄격하다(continue 는 통과가 아니다). flow 스킬이 대화형에서 이 모드를 기본으로 쓴다. CLI 는 --step(스텝 후 exit 3, 재실행으로 이어감). 무인·완료까지 자동은 step 을 빼면 모델 A 그대로다.

💸 비용은 엔진이 센다 — 그리고 싸지 않다

--max-loops 는 비용 상한이 아니다. 실패 루프가 10회를 다 쓰면 비용이 크게 뛸 수 있다. 그래서 --budget-usd 를 쓴다 — 누적이 상한에 닿으면 다음 에이전트 호출 전에 멈춘다.

hi-loop run --goal "..." --max-loops 5 --budget-usd 1 --no-stagnation
# [hi-loop] 💸 예산 $1 소진 (누적 $1.61) — 2회차에서 중단합니다.

hi-loop status 와 완료 로그에 누적 비용이 찍힌다. 모델은 사용자 기본값을 상속하므로 HILOOP_AGENT_ARGS="--model sonnet" 으로 낮출 수 있다.

환경변수

| 변수 | 설명 | |---|---| | HILOOP_AGENT_CMD | 에이전트 실행 명령 (기본 claude) | | HILOOP_AGENT_PROVIDER | 에이전트 CLI 계약 (기본 claude). generic 은 프롬프트를 마지막 위치인자로, stdout 을 결과로 읽는 최소 계약 — opencode 등 claude 외 CLI 를 일꾼으로 쓸 때. 단 세션 재개·비용 집계는 없다 | | HILOOP_AGENT_ARGS | 에이전트에 덧붙일 인자 (공백 구분). 예: --model sonnet — 비용에 직결된다. generic 에선 프롬프트 앞 서브커맨드로 쓰임(예: run) | | HILOOP_PERMISSION_MODE | 권한 모드 (기본 acceptEdits). 편집 허용이 이 엔진의 전제다 | | HILOOP_VERIFY_CMD / HILOOP_VERIFY_MODEL | --verify-spec 검증자의 실행 명령·모델 (미설정 시 구현자와 동일). 검증에 더 센 모델을 쓸 수 있다 | | HILOOP_REVIEW_CMD / HILOOP_REVIEW_MODEL | 설계·코드 리뷰어의 실행 명령·모델 (미설정 시 HILOOP_VERIFY_* → 구현자 순으로 폴백) | | HILOOP_DISCOVER_CMD / HILOOP_DISCOVER_MODEL | 발굴 단계의 실행 명령·모델 | | HILOOP_RECONCILE_CMD / HILOOP_RECONCILE_MODEL | 문서 정합 판정자(--reconcile)의 실행 명령·모델 (미설정 시 HILOOP_VERIFY_* → 구현자 순 폴백) | | HILOOP_AGENT_TIMEOUT_MS / HILOOP_TEST_TIMEOUT_MS | 에이전트(30분)·테스트(10분) 타임아웃. 쓰레기값은 기본값으로 되돌림 | | TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID | 시작/핸드오프/성공/실패 알림. 미설정 시 조용히 생략 |

개발

npm test        # node:test, devDependency 0개

구조

bin/hi-loop.js     CLI 엔트리포인트 (CLI / MCP 분기 + rollback + answer + 단계별 실행)
bin/setup.js       프로젝트·클로드코드 설정 자동 주입
src/loop.js        라이프사이클 stage 머신 — 다음 stage 를 정하는 권한은 여기 한 곳뿐
src/build.js       안쪽 자가 치유 루프 — 예산·정체·무결성·2단 판정·핸드오프 집행
src/stages.js      DISCOVER / CODE_REVIEW / SHIP / WATCH 핸들러 (지시만 반환)
src/discover.js    DISCOVER — 요구사항 발굴, 가정 확정, 분기 감지
src/review.js      DESIGN_REVIEW / CODE_REVIEW — 격리된 Tier 2 심판
src/ship.js        SHIP / WATCH — 배포·헬스체크. 에이전트를 부르지 않는다
src/vcs.js         브랜치·커밋 메커니즘 — 프리스텝·COMMIT 스테이지·git log 스타일 감지
src/config.js      .hi-loop.json 정책 저장소 — 브랜치·커밋 정책의 단일 진실 원천
src/ask.js         ask 모드 — pause/resume 상태머신, 가정 기록
src/checks.js      다중 조건 검사 — --check/--when, short-circuit 없음
src/blast.js       블라스트 반경 — 변경의 위험 분류를 공개
src/report.js      완료 보고 — Gaps 공개 + 상태 요약
src/cli-options.js CLI 인자 → runLoop 옵션 번역 (잘못된 값은 조용히 흘리지 않는다)
src/state.js       .hi-loop/STATE.json (원자적 저장 + 다이어트 + 산출물 경로 + resume + Gaps)
src/runners.js     에이전트/테스트 실행 어댑터 (주입 가능) + 비용 파싱 + 타임아웃
src/preflight.js   에이전트 실행 preflight + 실패 진단 (미설치·인증·키 → 행동지침)
src/reconcile.js   문서 정합 게이트 — 요청↔표준 문서 모순 판정 + ask 표면화 (FR-21)
src/cli-commands.js CLI 보조 명령 — answer / rollback / config (bin 은 라우팅만)
src/stage-context.js stage 핸들러 실행 맥락 조립
src/prompts.js     PDCA 단계별 프롬프트 + 검증자 프롬프트
src/integrity.js   테스트 무결성 지문·비교 — 보상 해킹 방어
src/checkpoint.js  git stash 체크포인트·롤백 + 삭제 관측
src/verify.js      스펙 오라클 — Tier 2 검증자
src/lock.js        동시 실행 pid 락
src/mcp-server.js  MCP 프로토콜 통신
src/telegram.js    텔레그램 비동기 알림
src/args.js        의존성 없는 인자 파서
src/is-main.js     "직접 실행인가?" 판정 (심링크 안전)