commitgate 0.3.1 → 0.7.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.
@@ -1,8 +1,12 @@
1
+ <!-- commitgate:contract -->
1
2
  # AGENTS.md (AI REQ workflow — Codex/Builder 계약)
2
3
 
3
4
  > 이 파일은 `commitgate`(init)가 대상 repo에 `AGENTS.md`가 없을 때 생성한 **템플릿**이다.
4
5
  > 프로젝트 고유 규칙(SSOT 경로·포트·참조 프로젝트·phase 문서 등)은 여기에 직접 채워 넣어라.
5
6
  > Codex CLI는 repo 루트의 `AGENTS.md`를 리뷰 컨텍스트로 읽는다.
7
+ >
8
+ > ⚠️ 첫 줄의 `<!-- commitgate:contract -->` 마커를 지우지 마라. `.claude/`·`.cursor/` 진입점 파일이
9
+ > "이 `AGENTS.md`가 CommitGate 계약인가"를 그 마커로 판별하고, `npx commitgate`도 부재 시 경고한다.
6
10
 
7
11
  ## 역할
8
12
 
@@ -42,6 +46,14 @@
42
46
 
43
47
  > PR을 생략할 수 있다는 것과, 우회를 보고하지 않아도 된다는 것은 다르다. 경로는 선택이지만 **투명성은 선택이 아니다.**
44
48
 
49
+ ### 6. 리뷰 전 staged 내용 확인 (외부 전송)
50
+
51
+ `req:review-codex`는 `git diff --cached` **전문**을 Codex(OpenAI)로 전송한다. codex는 `--sandbox read-only`로 저장소 루트를 읽으므로 diff에 없는 파일(`.env` 등)도 읽힐 수 있다. 마스킹·스크러빙·길이 상한은 **없다.**
52
+
53
+ - 리뷰를 실행하기 전에 staged 내용에 자격증명·토큰·개인정보가 없는지 확인한다.
54
+ - 민감 코드베이스(결제·인증·개인정보)라면 이 확인을 생략하지 않는다. 확인 없이 리뷰를 돌리지 않는다.
55
+ - 이 절은 도구가 강제하지 않는다. **Builder의 의무다.**
56
+
45
57
  ## 사람에게 보고해야 할 때
46
58
 
47
59
  각 통제점은 **고유한 승인 문장**을 가진다. 그 문장 그대로 승인받지 못했으면 실행하지 않는다.
@@ -78,8 +90,13 @@ protected branch에 변경을 넣는 경로는 **두 가지**이고 **둘 다
78
90
  | 명령 | 용도 |
79
91
  |---|---|
80
92
  | `req:new <slug> --run` | REQ 티켓 생성(채번·브랜치·`00/01/02` 스캐폴드) |
93
+ | `req:next <id> [--json]` | **다음 행동 계산**(읽기 전용). `RUN`/`AGENT`/`AWAIT_HUMAN`/`DONE`/`BLOCKED` |
81
94
  | `req:review-codex <id> --kind design\|phase [--phase <p>] --run` | Codex 리뷰 조립·호출·승인 반영 |
82
95
  | `req:doctor <id>` | 일관성 게이트(D-체크) |
83
96
  | `req:commit <id> [--run] [--message-file <f>]` | 승인된 phase 커밋 + evidence-finalize |
84
97
 
98
+ **다음 행동을 추측하지 마라.** `req:next`가 state와 git에서 계산해 준다. `RUN`이면 그 명령을 그대로 실행하고, `AGENT`면 그 작업을 한 뒤 `git add` 하고, `AWAIT_HUMAN`이면 멈춰서 출력된 승인 문장을 그대로 받는다. 이 루프를 끊지 말고 반복한다.
99
+
100
+ **리뷰어 페르소나는 도구가 주입한다.** `req:review-codex`가 `workflow/review-persona.md`를 프롬프트 첫 블록으로 넣는다(`req.config.json`의 `reviewPersonaPath`). 사람이 직접 실행하든 다른 에이전트가 실행하든 동일하다 — 프롬프트에 손으로 붙여넣지 마라. 파일이 없거나 비어 있으면 fail-closed로 멈춘다.
101
+
85
102
  설정은 repo 루트의 `req.config.json`(선택). 자세한 계약은 `README.md` 참조.
package/CHANGELOG.md ADDED
@@ -0,0 +1,115 @@
1
+ # Changelog
2
+
3
+ 이 프로젝트는 [Semantic Versioning](https://semver.org/lang/ko/)을 따릅니다.
4
+
5
+ ## 0.7.0
6
+
7
+ **설치 모델이 바뀝니다 — 기존 사용자는 조치가 필요합니다.** 실행 코드와 런타임 의존성을 대상 프로젝트에 복사·주입하지 않고, `commitgate` 패키지에서 실행합니다. 프로젝트에는 거버넌스·감사 데이터만 남습니다.
8
+
9
+ > **npm 배포 이력**: `0.5.0`·`0.6.0`은 npm에 배포되지 않았습니다. `0.4.0` 다음 릴리스가 `0.7.0`이며, 아래 `0.5.0`·`0.6.0` 항목의 변경도 **전부 `0.7.0`에 포함**됩니다.
10
+
11
+ ### ⚠️ Breaking
12
+
13
+ - **설치가 2단계가 됩니다.** `npx commitgate` 단독 실행으로는 더 이상 설치되지 않습니다.
14
+
15
+ ```sh
16
+ npm install -D commitgate # 1) 런타임이 node_modules/commitgate 에 들어옵니다
17
+ npx commitgate init # 2) 설정·계약·스키마와 req:* 스크립트를 깝니다
18
+ ```
19
+
20
+ `init`은 대상 `package.json`에 `devDependencies.commitgate` 선언이 없으면 **중단**합니다 — `req:*`가 가리킬 런타임이 없기 때문입니다. 선언의 **존재만** 확인하고 값 형태는 검증하지 않습니다(`file:`·`link:`·`workspace:`·git URL 전부 정당한 설치 형태입니다).
21
+
22
+ - **`scripts/req/**`를 복사하지 않습니다.** 실행 코드는 `node_modules/commitgate`에만 있습니다.
23
+ - **`tsx`·`ajv`·`cross-spawn`을 대상 `package.json`에 주입하지 않습니다.** 이들은 `commitgate` 패키지의 runtime dependency로 전이 설치됩니다.
24
+ - **`req:*` 스크립트 값이 `commitgate <verb>`가 됩니다**(예: `req:new` → `commitgate req:new`). `npm run req:new -- <slug>` UX와 인자 전달은 그대로입니다.
25
+
26
+ ### 기존 설치본(0.6.0 이하)에서 옮겨오기
27
+
28
+ 기존 프로젝트에는 `scripts/req/`가 복사돼 있고 `req:*`가 `tsx scripts/req/*.ts`를 가리킵니다. `init`은 이 상태를 감지하면 조용히 섞이지 않도록 **중단하고** `migrate`를 안내합니다.
29
+
30
+ ```sh
31
+ npm install -D commitgate
32
+ npx commitgate migrate # 계획만 출력 — 아무것도 쓰지 않습니다
33
+ npx commitgate migrate --apply # package.json 의 req:* 만 전환
34
+ ```
35
+
36
+ - **아무것도 삭제하지 않습니다.** `scripts/req/`·스키마·persona·설정·진입점·`workflow/REQ-*` 증거를 전부 그대로 둡니다. 남은 `scripts/req/`는 더 이상 실행되지 않으니, 정리하려면 `npx commitgate uninstall` 계획을 먼저 확인하세요.
37
+ - **직접 고친 스크립트는 덮어쓰지 않습니다.** 값이 **정확히** 기존 주입값일 때만 전환하고, 한 글자라도 다르면 사용자 값으로 보아 보존한 뒤 수동 조치를 안내합니다.
38
+ - **커밋하지 않습니다.** `package.json` 한 파일만 쓰고, 검토는 사용자 몫입니다.
39
+
40
+ ### 추가
41
+
42
+ - **`commitgate migrate`** — 위 비파괴 전환 명령. 기본 dry-run.
43
+ - **`req:doctor` D19 — 설치 모드 진단.** `req:*` 값의 **형태만**으로 예전(vendored)/현재(런타임 패키지)/혼합/없음/사용자정의를 분류합니다. 혼합일 때만 WARN하며 **FAIL하지 않습니다** — 예전 설치 형태는 결함이 아니라 지원되는 상태이고, `req:commit`이 doctor를 하드 게이트로 실행하므로 FAIL로 두면 정당한 프로젝트의 커밋이 막힙니다. manifest·lockfile·`node_modules`·버전은 검증하지 않습니다.
44
+ - **verb dispatch** — `commitgate <verb>`가 패키지 내부 모듈로 라우팅됩니다. `npx commitgate --dry-run` 같은 기존 옵션 형태는 그대로 `init`으로 갑니다(하위호환).
45
+ - **`uninstall`에 런타임 제거 안내 추가** — `npm uninstall -D commitgate`. 이 명령은 여전히 **읽기 전용**이며 안내를 문자열로 출력만 합니다(npm을 실행하지 않습니다).
46
+
47
+ ### 지원 범위
48
+
49
+ - **npm** — 완전 지원. 매 릴리스 packed tarball smoke로 검증합니다.
50
+ - **pnpm·yarn**(`node_modules` linker) — 지원. 표준 `node_modules/.bin/commitgate` 해소를 씁니다.
51
+ - **Yarn PnP** — **이번 릴리스 미지원**(검증하지 않았습니다). `nodeLinker: node-modules`를 쓰세요.
52
+ - **workspace/monorepo** — 워크스페이스 root 설치를 지원합니다. 하위 패키지 독립 설치는 미지원.
53
+ - 런타임 버전은 lockfile이 고정하므로 `package-lock.json`(pnpm/yarn은 각 lockfile)을 **커밋하세요**.
54
+
55
+ ### 알려진 한계
56
+
57
+ - **관리 자산(스키마·persona)과 런타임 패키지의 버전 skew를 자동으로 감지하지 못합니다.** `npm update commitgate`는 런타임만 올리고 자산은 그대로 둡니다. D19는 스크립트 형태만 보므로 이 축을 잡지 못합니다. 자산 업그레이드·3-way merge는 이번 범위가 아닙니다.
58
+
59
+ ## 0.6.0
60
+
61
+ 리뷰 codex 호출을 도구가 통제합니다 — **모델·추론강도를 고정**하고 **재리뷰를 stateless**로. 다운스트림에서 리뷰가 사용자 전역 프로필을 상속해 느리고(11~13분) 토큰이 많던 문제를 해결합니다. 기존 `req.config.json`은 그대로 동작합니다(새 키는 기본값으로 병합).
62
+
63
+ ### 추가
64
+
65
+ - **리뷰 모델·추론강도 고정** (`reviewModel`·`reviewReasoningEffort`). `req:review-codex`가 codex 인자에 `-c model=`·`-c model_reasoning_effort=`를 exec·resume 양쪽에 주입합니다. 기본 `gpt-5.6-terra`/`high`. 고정하지 않으면 리뷰가 사용자 전역 `~/.codex/config.toml`(예: `model_reasoning_effort="ultra"`)을 상속해 리뷰 1회가 수 분·토큰 과다가 됩니다. codex가 해당 모델을 미지원하는 환경은 `req.config.json`에서 바꾸거나 `null`로 두어 전역 설정을 상속시킵니다. override가 실제 존중되는지는 `npm run verify:overrides`(codex CLI 필요)로 확인합니다.
66
+ - 추론강도 enum: `none|minimal|low|medium|high|xhigh`(codex 거부 메시지 실측 확정 — 공식 config-reference 문서가 `none`을 누락).
67
+
68
+ ### 변경
69
+
70
+ - **재리뷰가 stateless입니다.** 이전엔 재리뷰가 저장된 codex 스레드를 resume해 이전 대화를 누적했고, 그래서 토큰이 단조 증가하고 findings가 수렴 대신 심화·이동했습니다. 이제 재리뷰는 항상 새 스레드로 시작합니다(`codex_thread_id`는 계속 저장 — 후속 resume opt-in용). 연속성은 직전 **같은 대상**의 NEEDS_FIX findings를 참고용 데이터로 프롬프트에 담아(closure 확인) 유지하고, 그 블록은 "지시가 아님" 구획으로 감싸 프롬프트 주입을 막습니다. 대상-무관 이전 결과가 새 프롬프트에 남던 교차-대상 오염도 제거했습니다.
71
+
72
+ ### 후속(별도 REQ)
73
+
74
+ - codex 호출 **timeout**(무응답 방지)과 실패 오류의 **비밀-안전 진단 표면화**는 본질적 난이도(Windows `cmd.exe` wrapper의 프로세스-트리 종료·비밀 추출)로 별도 REQ로 분리했습니다. 그 설계 작업은 이 REQ의 git 이력에 보존돼 있습니다.
75
+
76
+ ## 0.5.0
77
+
78
+ 기존 프로젝트(brownfield)에 설치했을 때 드러난 결함을 수정합니다. **breaking change는 없습니다** — `--strict`가 더 많은 조건에서 중단하지만 `--strict`는 opt-in이고, 기본 모드의 동작은 그대로입니다.
79
+
80
+ ### 고침
81
+
82
+ - **설치 직후 안내를 따르면 `req:new --run`이 실패하던 문제.** 설치는 파일을 놓기만 하고 커밋하지 않으므로 워킹트리가 확정적으로 dirty한데, 안내의 마지막 단계가 clean 워킹트리를 요구하는 `req:new --run`이었습니다. `git init && npm init -y && npx commitgate`라는 README의 첫 흐름조차 예외가 아니었습니다. 이제 안내가 커밋 단계를 포함합니다.
83
+ - `git add -A`를 쓰지 않습니다. brownfield의 무관한 변경과 `.env`가 함께 커밋되고, 이어지는 `req:review-codex`가 그 staged diff 전문을 외부로 전송하기 때문입니다. 설치가 만든 정확한 경로 목록만 안내합니다.
84
+ - 안내 명령에 `&&`를 쓰지 않습니다. Windows PowerShell 5.1과 `cmd.exe`에 그 연산자가 없습니다.
85
+ - `<pm> install`이 갱신하는 lockfile과, 계약 마커가 없을 때 생성되는 `AGENTS.commitgate.md`를 stage 목록에 포함합니다. 빠뜨리면 커밋 뒤에도 워킹트리가 dirty로 남습니다.
86
+ - 설치 전부터 있던 무관한 변경은 `git stash push -u -- <경로>`로 안내합니다. 경로 없는 `git stash -u`는 gitignore되지 않은 `node_modules/`까지 쓸어 갑니다.
87
+ - 설치 전에 **staged 변경**이 있거나 **산출물과 겹치는 tracked 수정**이 있으면 `git add` 목록을 내지 않습니다. 전자는 커밋이 삼키고 후자는 사후 분리가 불가능합니다. 잘못된 안내보다 안내 없음이 낫습니다.
88
+ - `node_modules`가 무시되지 않으면 `.gitignore` 추가를 안내하고 그 파일을 설치 커밋에 담습니다. 무시 규칙은 **tracked 저장소 `.gitignore`**에서 온 것만 인정합니다 — `.git/info/exclude`와 전역 ignore는 clone에 따라오지 않습니다.
89
+ - 경로에 공백이 있으면 큰따옴표로 묶습니다. 큰따옴표·백틱·`$`·`%`·`!`가 든 경로는 어떤 셸 인용으로도 안전하지 않으므로 복붙 명령을 아예 내지 않습니다 — `cmd.exe`는 큰따옴표 안에서도 `%VAR%`와 `!VAR!`를 치환합니다.
90
+ - `git status --porcelain`이 C-인용해 주는 경로(`"notes today.txt"`)를 되돌립니다. 되돌리지 않으면 산출물 매칭이 실패하고 안내가 이중 인용을 냅니다.
91
+
92
+ - **`.claude`를 통짜로 무시하는 repo에서 진입점이 조용히 추적 제외되던 문제.** 설치는 "성공"을 출력했지만 팀원의 fresh clone과 CI에는 계약 포인터가 없었습니다. 이제 `git check-ignore`로 감지해 경고하고, 동작하는 `.gitignore` 패턴을 제시합니다(부모 디렉터리가 제외되면 하위 부정 패턴이 무효라는 함정 포함). `--strict`에서는 파일을 하나도 쓰기 전에 중단합니다.
93
+
94
+ - **진입점 템플릿이 `npm run …`을 하드코딩하던 문제.** pnpm/yarn 프로젝트에 틀린 명령이 깔렸습니다. 이제 계약(`AGENTS.md`)과 같은 pm-중립 표기를 씁니다. 치환 렌더링은 쓰지 않습니다 — `uninstall`이 설치본과 패키지 원본의 sha256을 비교하므로, 렌더하면 자기가 깐 파일을 지우지 못합니다.
95
+
96
+ - **런타임 문구의 pm 리터럴.** `req:next`는 npm을, `req:new`·`req:doctor`·`req:review-codex`는 pnpm을 박아 두어 어느 프로젝트에서든 최소 하나는 틀렸습니다. config 로드 이후의 안내·에러는 이제 감지한 패키지매니저로 렌더합니다.
97
+
98
+ - **`--`를 "알 수 없는 옵션"으로 거부하던 문제.** npm은 `npm run x -- a`에서 `--`를 제거하지만 pnpm/yarn은 그대로 전달합니다. 이제 POSIX end-of-options 구분자로 흡수합니다. `--` 이후 인자도 계속 옵션으로 파싱하므로 `req:commit <id> -- --run`이 조용히 dry-run이 되지 않습니다.
99
+
100
+ - **`uninstall`이 skip한 사용자 파일을 소유물로 오인하던 경로.** stage 목록은 패키지 원본과 byte-identical한 파일만 CommitGate 소유로 봅니다.
101
+
102
+ ### 새로 알림
103
+
104
+ - `README`와 `AGENTS.template.md`에 **`req:review-codex`가 `git diff --cached` 전문을 Codex(OpenAI)로 전송한다**는 사실을 명시했습니다. codex는 `--sandbox read-only`로 저장소 루트를 읽으며, 마스킹·필터·길이 상한이 없습니다.
105
+ - **git hook을 설치하지 않으므로 `git commit`을 직접 치면 게이트가 우회된다**는 점도 README 상단에 명시했습니다. 이 도구의 강제력은 협조하는 에이전트를 계약 궤도에 유지하는 데 있습니다.
106
+
107
+ ### 아직 하지 않은 것
108
+
109
+ - 트렁크 브랜치가 `'main'`으로 하드코딩되어 있습니다(`trunkBranch` config 없음).
110
+ - `req:review-codex`에 타임아웃이 없습니다.
111
+ - 리뷰 전 시크릿 스캔 훅(`preReviewCommand`)이 없습니다.
112
+
113
+ ## 0.4.0 이전
114
+
115
+ `git log`를 참조하세요.
package/README.en.md CHANGED
@@ -6,6 +6,11 @@
6
6
 
7
7
  AI coding agents can move quickly, but unreviewed changes should not go straight into your history. CommitGate wraps each change in a REQ ticket and only allows the staged tree approved by Codex to be committed. If the code changes after approval, or if evidence is missing, it fails closed.
8
8
 
9
+ > **⚠️ Two things to know before you start.**
10
+ >
11
+ > 1. **Review sends your staged diff off-machine.** `req:review-codex` passes the **entire** `git diff --cached` to Codex (OpenAI). Codex reads your repository root under `--sandbox read-only`, so files outside the diff can be read too. There is **no** masking, filtering, or size cap. Check the staged content for credentials, tokens, and personal data before running a review.
12
+ > 2. **No git hook is installed.** Running `git commit` directly instead of `req:commit` bypasses the gate, the approval binding, and the evidence trail. CommitGate's enforcement keeps a **cooperating agent on the contract's rails** — it is not a barrier against a human going around it.
13
+
9
14
  [![CI](https://github.com/sol5288/commitgate/actions/workflows/ci.yml/badge.svg)](https://github.com/sol5288/commitgate/actions/workflows/ci.yml)
10
15
  [![npm version](https://img.shields.io/npm/v/commitgate.svg)](https://www.npmjs.com/package/commitgate)
11
16
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
@@ -21,43 +26,55 @@ Run this from your project root. The project must be a **git repository with a `
21
26
  git init
22
27
  npm init -y
23
28
 
24
- # Then install:
25
- npx commitgate
26
- npm install
29
+ # 1) Install CommitGate as a devDependency — this is where the runtime lives:
30
+ npm install -D commitgate
31
+
32
+ # 2) Add config, contract, schemas, and the req:* scripts to your project:
33
+ npx commitgate init
34
+
27
35
  codex --version
28
36
  codex login status
29
37
  ```
30
38
 
31
- Then paste this prompt into your AI coding agent.
39
+ > **Why two steps?** CommitGate does **not** copy its runtime code into your project. Step 1 puts the runtime in `node_modules/commitgate`; step 2 adds only **governance assets** (config, contract, schemas, persona) plus `req:* = commitgate <verb>` scripts.
40
+ > That means updating is a single `npm update commitgate`, and removing the runtime is `npm uninstall -D commitgate`.
41
+ > `init` **stops** if `devDependencies.commitgate` is not declared — there would be no runtime for `req:*` to point at.
42
+
43
+ Installation writes files but never commits them. `req:new` **requires a clean working tree**, so commit the scaffold first. The installer's `다음:` (next steps) output prints the exact paths to stage.
44
+
45
+ ```sh
46
+ git add -- <the paths the installer printed>
47
+ git status # confirm only what you intended is staged
48
+ git commit -m "chore: install commitgate"
49
+ ```
50
+
51
+ > **Do not stage everything (`-A` / `.`).** Unrelated changes and untracked files such as `.env` would be swept into the commit, and the next `req:review-codex` transmits that staged diff in full to an external service.
52
+ > Park any changes that predate the install **by pathspec** after the install commit: `git stash push -u -- <paths>`.
53
+ > Without `-u`, untracked files remain and `req:new` stays blocked; without the pathspec, a bare `git stash -u` also sweeps up directories that are not ignored, such as `node_modules/`. The installer prints that path list too.
54
+
55
+ **You do not paste a long prompt.** Installation lays down agent entrypoints for you.
56
+
57
+ | File | Read by |
58
+ |---|---|
59
+ | `AGENTS.md` | Codex CLI, Cursor — **the contract** |
60
+ | `.claude/skills/commitgate/SKILL.md` | Claude Code (auto-invoked when it matches) |
61
+ | `.claude/commands/req.md` | Claude Code (`/req` explicit call) |
62
+ | `.cursor/rules/commitgate.mdc` | Cursor (`alwaysApply`) |
63
+ | `CLAUDE.md` | Claude Code (always loaded) — created only if absent |
64
+
65
+ Just give the agent a requirement.
32
66
 
33
67
  ```text
34
- Do not handle this as a normal implementation. Use the CommitGate workflow installed in this project.
35
-
36
- Create a new REQ ticket and run this flow end to end:
37
- req:new write design docs Codex design review → implement and test → req:doctor → Codex phase review → req:commit
38
-
39
- Proceed automatically:
40
- - If `req:review-codex` returns NEEDS_FIX/exit 3, fix the findings and rerun review.
41
- - If it returns BLOCKED/exit 2, do not retry the same review; escalate or change the review target. If a stuck thread is suspected, you may retry once with `--fresh-thread`.
42
- - The review target is only what has been staged with git add.
43
- - Do not manually git add state.json or responses/.
44
-
45
- Stop for human confirmation only (each item must be approved by that exact sentence; one approval never carries over to the next step):
46
- - Right before req:commit --run
47
- - [Path A · optional] [I1] Before pushing the feature branch and opening a PR / [I2] Before merging the PR, after confirming the required status checks are green
48
- - [Path B] [B1] Before a direct push to a protected branch — get a separate "branch protection bypass를 사용한 direct push 승인". This push bypasses the required status checks, and CI runs after it
49
- - [R1/R2/R3] tag creation and push / npm publish / GitHub release — each approved separately, after CI is green
50
- - Before destructive actions such as reset, clean, or force push
51
- - When the requested scope must change
52
- - When Codex review returns BLOCKED or remains unclear after bounded retries
53
-
54
- Requirement:
55
- - What:
56
- - Why:
57
- - Constraints:
58
- - Done when:
68
+ /req Add a profile edit API
69
+
70
+ - What: PATCH /profile to change nickname and bio
71
+ - Why: users cannot change their profile after signup
72
+ - Constraints: reuse the existing auth middleware, no schema change
73
+ - Done when: unit tests pass, unauthorized users get 403
59
74
  ```
60
75
 
76
+ Outside Claude Code you can skip the slash command and state the requirement directly — `.cursor/rules` and `AGENTS.md` load the rules. If the four fields are missing, the agent asks first.
77
+
61
78
  The agent's first reply should look roughly like this.
62
79
 
63
80
  ```text
@@ -69,7 +86,38 @@ Phases:
69
86
  Control points: before req:commit --run / [B1] before a direct push to main (or [I1] open PR → [I2] merge)
70
87
  ```
71
88
 
72
- After that, the agent runs design, implementation, tests, and Codex review. You only confirm at control points.
89
+ ### The agent follows whatever `req:next` says
90
+
91
+ The agent never guesses the next action. The tool computes it from `state.json` and git state.
92
+
93
+ ```sh
94
+ npm run req:next -- 2026-002
95
+ ```
96
+
97
+ ```text
98
+ [req:next] RUN REQ-2026-002
99
+ phase `phase-1`의 staged 변경을 리뷰받는다.
100
+
101
+ $ npm run req:review-codex -- 2026-002 --kind phase --phase phase-1 --run
102
+ ```
103
+
104
+ | kind | Meaning | exit |
105
+ |---|---|---|
106
+ | `RUN` | Run the printed command verbatim, then `req:next` again | 0 |
107
+ | `AGENT` | Work the tool cannot do (implement, write docs, `git add`) | 0 |
108
+ | `AWAIT_HUMAN` | **Control point** — do not proceed without the exact approval sentence | 10 |
109
+ | `DONE` | Nothing left for the tool. Integration is a separate control point | 11 |
110
+ | `BLOCKED` | Escalate to a human. Do not retry the same review | 2 |
111
+
112
+ Use `--json` for machine-readable output. It is **read-only** and changes no state.
113
+
114
+ Repeat this loop without stopping and it drives design → Codex review → implementation → re-review → commit. You only confirm at `AWAIT_HUMAN`.
115
+
116
+ ### The reviewer persona is injected by the tool
117
+
118
+ `req:review-codex` puts `workflow/review-persona.md` in as the **first block** of the prompt. It is identical whether a human, Cursor, or Claude runs the command — it does not live where an agent can forget it. If the file is missing or empty, the review stops fail-closed.
119
+
120
+ Edit it for your project, or point `reviewPersonaPath` in `req.config.json` at a different file. Set it to `null` to disable.
73
121
 
74
122
  Both integration paths are valid: **through a PR (optional)** and **direct push**. A PR is not mandatory. But a direct push to a protected branch **bypasses the required status checks**, so it needs a separate "branch protection bypass를 사용한 direct push 승인" — holding bypass permission is not approval. In that case CI runs **after** the push, so its green is post-hoc verification, and the agent must not omit that from its report. tag, npm publish, and GitHub release are control points of their own, requested after CI is green and never bundled with the integration approval. See [AGENTS.template.md](AGENTS.template.md) and [docs/RELEASING.md](docs/RELEASING.md) for the full contract.
75
123
 
@@ -90,19 +138,52 @@ CommitGate is designed to block **unreviewed changes from being committed**, not
90
138
 
91
139
  In short: **approved changes pass, ambiguous changes stop.**
92
140
 
141
+ ### What It Does *Not* Enforce
142
+
143
+ So that you do not miscalculate where your real defenses are:
144
+
145
+ - **This is not hard enforcement.** No git hook is installed, so running `git commit` directly instead of `req:commit` bypasses doctor, the approval binding, and the evidence trail. Your real defense for production is still CI and the deployment pipeline.
146
+ - **It does not keep your staged content secret.** `req:review-codex` transmits the full `git diff --cached` to Codex (OpenAI), and codex reads the repository root under `--sandbox read-only`. There is no masking, scrubbing, or size cap. For payment or credential-bearing codebases, write a "inspect the staged diff before review" step into your contract (`AGENTS.md`).
147
+ - **It does not guarantee anything after the commit.** Approval binds the staged tree at commit time; merge, tag, and publish are each separate control points.
148
+
93
149
  ---
94
150
 
95
151
  ## What Installation Adds
96
152
 
97
- `npx commitgate` adds the following to the target project. Existing files are not overwritten by default.
153
+ `npx commitgate init` adds the following to the target project. Existing files are not overwritten by default.
98
154
 
99
155
  | Added item | Purpose |
100
156
  |---|---|
101
- | `scripts/req/` | `req:new`, `req:review-codex`, `req:doctor`, `req:commit` scripts |
102
157
  | `workflow/*.schema.json` | Schemas for Codex responses and config |
158
+ | `workflow/review-persona.md` | Reviewer persona injected into the Codex review prompt (created only if absent) |
103
159
  | `req.config.json` | Project-level configuration |
104
- | `AGENTS.md` | Template rules for the agent and reviewer |
105
- | `package.json` scripts | `req:*` commands and required devDependencies |
160
+ | `AGENTS.md` | The contract (created only if absent) |
161
+ | `CLAUDE.md` | Claude Code pointer (created only if absent) |
162
+ | `.claude/skills/commitgate/SKILL.md` | Claude Code skill (pointer) |
163
+ | `.claude/commands/req.md` | `/req` slash command (pointer) |
164
+ | `.cursor/rules/commitgate.mdc` | Cursor rule (pointer) |
165
+ | `package.json` scripts | `req:new`·`req:next`·`req:review-codex`·`req:doctor`·`req:commit` = `commitgate <verb>` (missing keys only) |
166
+
167
+ ### What it does **not** install
168
+
169
+ | Item | Where it lives instead |
170
+ |---|---|
171
+ | `scripts/req/**` runtime code | `node_modules/commitgate` — never copied into your project |
172
+ | `tsx` · `ajv` · `cross-spawn` | runtime dependencies of the `commitgate` package — never injected into your `package.json` |
173
+
174
+ What stays in your project is **governance and audit data** only: config, contract, schemas, persona, and `workflow/REQ-*` evidence. Because the runtime lives in the package, `npm update commitgate` updates it in one step and vendored copies cannot drift.
175
+
176
+ The `req:*` scripts call the installed package bin — `npm run req:new -- <slug>` → `commitgate req:new <slug>` → `node_modules/.bin/commitgate`.
177
+
178
+ The entrypoint files are **thin pointers**. The contract itself lives only in `AGENTS.md`.
179
+
180
+ If another tool already owns `.claude/` or `.cursor/`, skip that layer.
181
+
182
+ ```sh
183
+ npx commitgate --no-agent-entrypoints
184
+ ```
185
+
186
+ If an `AGENTS.md` already exists without the CommitGate contract marker (`<!-- commitgate:contract -->`), the contract template is installed alongside it as `AGENTS.commitgate.md` and you are told to merge it. Your existing file is never touched.
106
187
 
107
188
  Preview without writing files:
108
189
 
@@ -110,21 +191,64 @@ Preview without writing files:
110
191
  npx commitgate --dry-run
111
192
  ```
112
193
 
113
- Treat the security floor warning as an install failure:
194
+ Treat integrity warnings as an install failure:
114
195
 
115
196
  ```sh
116
197
  npx commitgate --strict
117
198
  ```
118
199
 
119
- If an existing `cross-spawn` is below the verified floor, CommitGate stops before copying files.
200
+ CommitGate stops **before writing any file** if a contract pointer would be swallowed by `.gitignore`, if the `workflow/.gitignore` policy file would not reach a fresh clone, if the working tree makes a safe install commit impossible, or if an existing `cross-spawn` is below the verified floor.
201
+
202
+ > `--strict` also treats the `package.json`/lockfile changes left by the required `npm install -D commitgate` as pre-existing dirt. Recommended order: `npm i -D commitgate` → **commit** → `npx commitgate init --strict` → commit the scaffold.
120
203
 
121
204
  > `workflow/machine.schema.json` and `workflow/req.config.schema.json` are always copied under `workflow/`, regardless of the `ticketRoot` setting in `req.config.json`.
122
205
 
123
206
  ---
124
207
 
208
+ ## Migrating from an older install (`migrate`)
209
+
210
+ If `scripts/req/` is copied into your project and `req:*` points at `tsx scripts/req/*.ts`, you have an **older (vendored) install**. `init` detects this and **stops** rather than creating a silent mix, pointing you here.
211
+
212
+ ```sh
213
+ npm install -D commitgate # first, if it is not a devDependency yet
214
+ npx commitgate migrate # plan only — writes nothing
215
+ npx commitgate migrate --apply # rewrites only the req:* scripts in package.json
216
+ ```
217
+
218
+ `migrate` does exactly **one** thing: it rewrites the `req:*` keys **whose current value is byte-for-byte the old injected value** to `commitgate <verb>`.
219
+
220
+ - **It deletes nothing.** `scripts/req/`, schemas, persona, config, entrypoints, and `workflow/REQ-*` evidence are all left in place. The leftover `scripts/req/` is no longer executed; run `npx commitgate uninstall` to see a cleanup plan first.
221
+ - **It never overwrites scripts you edited.** Any value that differs — even by one character — is treated as yours, preserved, and reported for manual action.
222
+ - **It does not commit.** It writes `package.json` only; reviewing is up to you.
223
+
224
+ `req:doctor` also reports the install mode (old / current / mixed).
225
+
226
+ ---
227
+
228
+ ## Support scope
229
+
230
+ | Environment | Status |
231
+ |---|---|
232
+ | **npm** | Fully supported — verified on every release by a packed-tarball smoke test |
233
+ | **pnpm · yarn** (`node_modules` linker) | Supported — uses the standard `node_modules/.bin/commitgate` resolution |
234
+ | **Yarn PnP** | **Not supported in this release** (untested). Use `nodeLinker: node-modules` |
235
+ | **workspaces / monorepo** | **Workspace-root installs** are supported (`req.config.json` and `workflow/` at the root). Installing independently in a sub-package is not supported |
236
+
237
+ **Reproducibility**: the review model/effort pins in `req.config.json`, plus the schemas and persona, stay in your project, so past review inputs are reproducible from git history. Runtime versions are pinned by your lockfile — **commit `package-lock.json`** (or the pnpm/yarn equivalent).
238
+
239
+ ---
240
+
125
241
  ## Removing CommitGate
126
242
 
127
- First, the important part: **`npx commitgate` is not a global install.** npx downloads the package into the npm cache (`_npx/<hash>/`) and runs it once; it leaves nothing in your global `node_modules` and nothing on your PATH. The real "installation" is the set of files added to your repo, plus the `package.json` changes listed above.
243
+ CommitGate lives in two places: the **runtime** (`node_modules/commitgate`) and the **governance files installed into your project**.
244
+
245
+ The package manager removes the runtime:
246
+
247
+ ```sh
248
+ npm uninstall -D commitgate # pnpm remove -D commitgate · yarn remove commitgate
249
+ ```
250
+
251
+ For the project files, review the plan below and clean up yourself. First, the important part: **`npx commitgate` is not a global install.** npx downloads the package into the npm cache (`_npx/<hash>/`) and runs it once; it leaves nothing in your global `node_modules` and nothing on your PATH.
128
252
 
129
253
  Start by previewing the removal plan. This command **deletes nothing**:
130
254
 
@@ -163,7 +287,7 @@ git checkout HEAD -- package.json
163
287
 
164
288
  Delete only the paths `npx commitgate uninstall` listed. Removing `scripts/req/` or `workflow/` as whole directories would also take your own files and your ticket evidence with them.
165
289
 
166
- > git does not track empty directories. After deleting the files, `git status` can report a clean tree while empty `scripts/` and `workflow/` directories remain on disk.
290
+ > git does not track empty directories. After deleting the files, `git status` can report a clean tree while empty `scripts/`, `workflow/`, `.claude/`, and `.cursor/` directories remain on disk.
167
291
 
168
292
  ### If you already committed the scaffold
169
293
 
@@ -263,15 +387,28 @@ npm run req:commit -- 2026-001 --run --message-file commit-message.txt
263
387
 
264
388
  | Command | Purpose |
265
389
  |---|---|
266
- | `npx commitgate` | Install CommitGate into a project |
267
- | `npx commitgate --dry-run` | Preview the install plan without writing files |
268
- | `npx commitgate --strict` | Treat low `cross-spawn` version warnings as install failures |
390
+ | `npm install -D commitgate` | **Install the runtime (required first)** — the executable code lives in `node_modules/commitgate` |
391
+ | `npx commitgate init` | Install config, contract, schemas, and the `req:*` scripts into a project |
392
+ | `npx commitgate init --dry-run` | Preview the install plan without writing files |
393
+ | `npx commitgate init --strict` | Treat integrity warnings as install failures — stops before writing any file |
394
+ | `npx commitgate init --no-agent-entrypoints` | Skip `.claude/`, `.cursor/`, and `CLAUDE.md` |
395
+ | `npx commitgate migrate [--apply]` | Move an older vendored install to the runtime package (plan-only by default, non-destructive) |
269
396
  | `npx commitgate uninstall` | Preview the removal plan (read-only — deletes nothing) |
270
- | `req:new <slug> --run` | Create a REQ ticket, branch, and design docs |
271
- | `req:review-codex <id> --kind design --run` | Review the design |
272
- | `req:review-codex <id> --kind phase --run` | Review the implementation |
273
- | `req:doctor <id>` | Check gate status |
274
- | `req:commit <id> --run -m "message"` | Commit approved changes |
397
+ | `npm uninstall -D commitgate` | Remove the runtime |
398
+ | `npm run req:new -- <slug> --run` | Create a REQ ticket, branch, and design docs |
399
+ | `npm run req:next -- <id> [--json]` | **Compute the next action** (read-only) |
400
+ | `npm run req:review-codex -- <id> --kind design --run` | Review the design |
401
+ | `npm run req:review-codex -- <id> --kind phase --phase <p> --run` | Review the implementation |
402
+ | `npm run req:doctor -- <id>` | Check gate status |
403
+ | `npm run req:commit -- <id> --run -m "message"` | Commit approved changes |
404
+
405
+ `req:*` are **`package.json` scripts**, not executables on your PATH. npm needs the `--` separator to pass arguments.
406
+
407
+ ```sh
408
+ npm run req:next -- 2026-002 # npm
409
+ pnpm req:next 2026-002 # pnpm
410
+ yarn req:next 2026-002 # yarn
411
+ ```
275
412
 
276
413
  ---
277
414
 
@@ -285,9 +422,16 @@ Defaults are enough for most projects. If needed, edit `req.config.json` in the
285
422
  | `ticketRoot` | `"workflow"` | REQ ticket directory |
286
423
  | `packageManager` | auto-detected | `npm`, `pnpm`, or `yarn` |
287
424
  | `designDocs` | `00/01/02` docs | Design document filenames |
425
+ | `reviewPersonaPath` | `"workflow/review-persona.md"` | First block of the review prompt. `null` disables it |
426
+ | `reviewModel` | `"gpt-5.6-terra"` | codex review model (pinned via `-c model=`). `null` inherits your global codex config |
427
+ | `reviewReasoningEffort` | `"high"` | codex review reasoning effort. One of `none`, `minimal`, `low`, `medium`, `high`, `xhigh`. `null` inherits the global setting |
288
428
 
289
429
  Empty `branchPrefix` values and paths that escape the project root are rejected.
290
430
 
431
+ **Pinned review model & effort**: `req:review-codex` injects `-c model=` and `-c model_reasoning_effort=` into the codex arguments to **pin the model and reasoning effort**. Without pinning, a review inherits your global `~/.codex/config.toml` (e.g. `model_reasoning_effort="ultra"`), making a single review take minutes and burn tokens. The defaults are `gpt-5.6-terra`/`high`; if your codex doesn't support that model, change it in `req.config.json` or set it to `null` to inherit the global config. Whether the overrides are actually honored can be checked with `npm run verify:overrides` (requires the codex CLI).
432
+
433
+ **Stateless re-reviews**: each re-review starts a **fresh codex thread** (it does not resume/accumulate the prior conversation — which drove token growth and goalpost drift). Only the previous same-target NEEDS_FIX findings are carried into the prompt as reference data, to confirm closure.
434
+
291
435
  ---
292
436
 
293
437
  ## FAQ
@@ -311,17 +455,18 @@ No. Existing files are skipped. Use `--force` if you intentionally want to refre
311
455
 
312
456
  ## Current Scope
313
457
 
314
- The current release is **Stage A: vendored scaffold model**. `npx commitgate` copies workflow files into the target project.
458
+ The current release is a **runtime package model**. Executable code and runtime dependencies live only in `node_modules/commitgate`; your project keeps governance/audit data and the `req:* = commitgate <verb>` scripts. (Older vendored installs move over with [`migrate`](#migrating-from-an-older-install-migrate).)
315
459
 
316
460
  Current verification:
317
461
 
318
462
  - GitHub Actions runs a `ubuntu-latest`, `macos-latest`, `windows-latest` × Node 18/20/22 matrix.
319
- - `npm run smoke` installs the packed tarball and runs the installed `commitgate` bin.
463
+ - `npm run smoke` installs the packed tarball into a throwaway project and asserts that the target has **no** `scripts/req/`, that `tsx`/`ajv`/`cross-spawn` are **not** injected, that all five `req:*` scripts point at the package bin, and that `npm run req:doctor` actually dispatches into the module inside the package. It verifies `migrate`'s non-destructiveness the same way.
320
464
  - A Windows `.cmd` wrapper injection regression test protects package-manager and Codex wrapper paths.
321
465
 
322
466
  Future scope:
323
467
 
324
- - Running directly from `node_modules` as a library-style model
468
+ - Yarn PnP support; independent installs in workspace sub-packages
469
+ - Asset↔runtime version drift detection
325
470
  - Non-git VCS support
326
471
  - More design document templates
327
472