commitgate 0.1.1 → 0.2.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.
Files changed (4) hide show
  1. package/README.en.md +120 -244
  2. package/README.md +121 -245
  3. package/bin/init.ts +115 -5
  4. package/package.json +66 -63
package/README.en.md CHANGED
@@ -1,341 +1,217 @@
1
- # CommitGate 🚦
1
+ # CommitGate
2
2
 
3
3
  🌐 [한국어](./README.md) · **English**
4
4
 
5
- **A "commit gate" that lets AI-written code be committed only after a *different* AI reviews and approves it.**
5
+ **A commit gate that blocks AI-generated code from being committed until Codex has reviewed and approved it.**
6
6
 
7
- > In one line: pair a **Builder AI** with a **Reviewer AI** so that **nothing gets committed without review, approval, and evidence.**
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
9
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
10
10
 
11
11
  ---
12
12
 
13
- ## 🤔 What is this? (an analogy)
13
+ ## Quick Start
14
14
 
15
- Think of an airport security checkpoint. No matter how much of a hurry you're in, you **can't reach the gate without passing through security.**
15
+ Run this from your project root. The project must be a **git repository with a `package.json`**.
16
16
 
17
- CommitGate works the same way. No matter how much code you produce, **`git commit` is blocked until it passes the "review → approval" gate.**
18
-
19
- - 🛠️ **Builder (the maker)** — you, or your AI coding tool (e.g. Claude Code). Designs the requirement and writes the code.
20
- - 🔎 **Reviewer (the checker)** — the **Codex CLI**. **Independently re-reviews** what the Builder made and rules pass / needs-fix.
21
- - 🚦 **CommitGate** — stands between them and lets **only Reviewer-approved code** be committed.
22
-
23
- In short, instead of "build alone, commit alone," it enforces **cross-verification between the AI that built it and the AI that checked it.**
24
-
25
- ## 🎯 What problem does it solve?
26
-
27
- AI produces code **fast**, but committing it without verification is risky. CommitGate:
28
-
29
- - ✅ Forces **every change through review.**
30
- - ✅ Binds approval to **"the exact code that was reviewed."** (You can't swap in changes after approval — it's compared like a fingerprint.)
31
- - ✅ **Blocks by default (fail-closed)** whenever something is ambiguous or missing. "Pass only when certain" is the default, so it's safe.
32
- - ✅ Leaves **evidence on disk** of who approved what and when.
33
-
34
- ## 🔄 The flow at a glance
35
-
36
- ```
37
- ① create ticket → ② write design → ③ design review(Codex) → ④ implement code
38
- req:new req:review-codex
39
-
40
- → ⑤ gate check → ⑥ code review(Codex) → ⑦ commit once approved
41
- req:doctor req:review-codex req:commit
17
+ ```sh
18
+ npx commitgate
19
+ npm install
20
+ codex --version
21
+ codex login status
42
22
  ```
43
23
 
44
- At each step, **if it doesn't pass, you can't move to the next.**
45
-
46
- ---
47
-
48
- ## 📦 Prerequisites
24
+ Then paste this prompt into your AI coding agent.
49
25
 
50
- You need these 4 things before starting. Check each in your terminal.
26
+ ```text
27
+ Do not handle this as a normal implementation. Use the CommitGate workflow installed in this project.
51
28
 
52
- | What | Check command | If missing |
53
- |---|---|---|
54
- | **Git** (required) | `git --version` | install from [git-scm.com](https://git-scm.com) |
55
- | **Node.js 18.17+** (required) | `node --version` | install from [nodejs.org](https://nodejs.org) |
56
- | **Codex CLI** (for review) | `codex --version` | install OpenAI Codex CLI (without it only review is unavailable; the rest works) |
57
- | **Package manager** | `npm --version` | `npm` ships with Node (or use `pnpm`/`yarn`) |
58
-
59
- > 💡 **Reviewer = Codex CLI.** To actually run reviews, the Codex CLI must be installed. Without it, review commands **fail safely (fail-closed)** — they never silently pass.
60
-
61
- ### 🔧 Install & log in to the Codex CLI (Reviewer setup)
29
+ Create a new REQ ticket and run this flow end to end:
30
+ req:new → write design docs → Codex design review → implement and test → req:doctor → Codex phase review → req:commit
62
31
 
63
- Reviews in CommitGate are handled by the **OpenAI Codex CLI**. Three steps:
32
+ Proceed automatically:
33
+ - If Codex returns NEEDS_FIX, fix the findings and rerun review until approved.
34
+ - The review target is only what has been staged with git add.
35
+ - Do not manually git add state.json or responses/.
64
36
 
65
- **① Install**
37
+ Stop for human confirmation only:
38
+ - Right before req:commit --run
39
+ - Before merging to main or pushing
40
+ - Before destructive actions such as reset, clean, or force push
41
+ - When the requested scope must change
42
+ - When Codex review is still not approved after 3 rounds
66
43
 
67
- ```sh
68
- # npm (all OSes)
69
- npm install -g @openai/codex
70
-
71
- # or macOS Homebrew
72
- brew install codex
44
+ Requirement:
45
+ - What:
46
+ - Why:
47
+ - Constraints:
48
+ - Done when:
73
49
  ```
74
50
 
75
- Verify:
51
+ The agent's first reply should look roughly like this.
76
52
 
77
- ```sh
78
- codex --version # e.g. codex-cli 0.4x.x
53
+ ```text
54
+ REQ-2026-002 created
55
+ Branch: feat/req-2026-002-profile-edit-api
56
+ Phases:
57
+ - phase-1: implement PATCH /profile
58
+ - phase-2: tests and regression checks
59
+ Control points: before req:commit --run, before push
79
60
  ```
80
61
 
81
- **② Log in** pick whichever is easier
82
-
83
- - **Option A. With a ChatGPT account (recommended, browser)**
84
- ```sh
85
- codex login
86
- ```
87
- A browser opens → sign in with your ChatGPT account → return to the terminal when done.
62
+ After that, the agent runs design, implementation, tests, and Codex review. You only confirm at control points such as commit or push.
88
63
 
89
- - **Option B. With an OpenAI API key**
90
- ```sh
91
- # via environment variable (simplest)
92
- export OPENAI_API_KEY=sk-... # Windows PowerShell: $env:OPENAI_API_KEY="sk-..."
64
+ ---
93
65
 
94
- # or store the key in Codex
95
- printenv OPENAI_API_KEY | codex login --with-api-key
96
- ```
97
- Create an API key at [platform.openai.com](https://platform.openai.com/api-keys).
66
+ ## What Does It Enforce?
98
67
 
99
- **③ Verify login**
68
+ CommitGate is designed to block **unreviewed changes from being committed**, not just to wrap commands.
100
69
 
101
- ```sh
102
- codex login status # shows login status
103
- codex doctor # full diagnosis of install, auth, and environment (explains any issue)
104
- ```
70
+ - No Codex approval means no commit.
71
+ - If the approved staged tree differs from the current staged tree, the commit is blocked.
72
+ - Workflow files such as `state.json` and `responses/` cannot be mixed into the source commit.
73
+ - If Codex CLI is missing or fails, the workflow fails instead of silently passing.
74
+ - Approval responses and evidence are kept under `workflow/REQ-.../responses/`.
105
75
 
106
- > If `codex --version` and `codex login status` look good, the Reviewer is ready. Move on to `npx commitgate`.
107
- > ⚠️ If Windows can't find the `codex` command, open a **new terminal** so PATH is reloaded (a common issue right after a global install).
76
+ In short: **approved changes pass, ambiguous changes stop.**
108
77
 
109
78
  ---
110
79
 
111
- ## 🚀 Install (one line)
112
-
113
- **In your project folder** (= a git repo that has a `package.json`):
80
+ ## What Installation Adds
114
81
 
115
- ```sh
116
- npx commitgate
117
- ```
82
+ `npx commitgate` adds the following to the target project. Existing files are not overwritten by default.
118
83
 
119
- What this does automatically (it **never overwrites** existing files):
120
-
121
- 1. Copies the workflow scripts (`scripts/req/`) and schemas.
122
- 2. Creates a `req.config.json` (settings file).
123
- 3. Adds the `req:*` commands and required devDependencies (`tsx`, `ajv`, `cross-spawn`) to your `package.json`.
124
- 4. Creates an `AGENTS.md` template (the rules file the Reviewer reads) if you don't have one.
84
+ | Added item | Purpose |
85
+ |---|---|
86
+ | `scripts/req/` | `req:new`, `req:review-codex`, `req:doctor`, `req:commit` scripts |
87
+ | `workflow/*.schema.json` | Schemas for Codex responses and config |
88
+ | `req.config.json` | Project-level configuration |
89
+ | `AGENTS.md` | Template rules for the agent and reviewer |
90
+ | `package.json` scripts | `req:*` commands and required devDependencies |
125
91
 
126
- After installing, fetch the newly added dependencies:
92
+ Preview without writing files:
127
93
 
128
94
  ```sh
129
- npm install
95
+ npx commitgate --dry-run
130
96
  ```
131
97
 
132
- > Add `--dry-run` to preview what it would do **without changing anything**: `npx commitgate --dry-run`
133
-
134
98
  ---
135
99
 
136
- ## 🤖 How to use it — hand it to an AI agent via a prompt (recommended)
137
-
138
- Honestly, **nobody types `req:new → review → implement → review → commit` by hand, one at a time.** It's tedious.
139
-
140
- The real way to use CommitGate is this: **give your AI coding agent a prompt with your "requirements" plus "use this workflow," and the agent drives the whole thing.** You only approve at **control points (commit, merge, push, etc.).**
141
-
142
- ### What this mode assumes
143
- - **An AI coding agent that can run shell commands** — Claude Code, Cursor (agent), Codex CLI, etc. (it must be able to run terminal commands in your repo)
144
- - **Codex CLI installed** — the Reviewer role. Without it, the review step stops (fail-closed).
145
- - **A filled-in `AGENTS.md`** — write your project's rules (coding conventions, test commands, etc.) into the template that `npx commitgate` created; it improves review quality.
146
-
147
- ### Three steps and you're done
148
- 1. Copy the **prompt template** below and fill the `[Requirements]` block at the bottom with your request.
149
- 2. Paste the whole thing **into your AI agent's chat.**
150
- 3. The agent's **first reply reports only the REQ number, branch, phase plan, and control points.** After that it asks you **only at control points** — everything else (implementation, tests, Codex review, applying NEEDS_FIX, re-review) is automatic.
151
-
152
- ### 📋 Copy-paste prompt template
100
+ ## Prerequisites
153
101
 
154
- ````text
155
- Do NOT handle this as a normal implementation task. You MUST use the CommitGate (AI REQ workflow) installed in this project.
156
-
157
- Issue a new REQ ticket for the [Requirements] below and drive it all the way through:
158
- req:new write design docs (00/01/02) req:review-codex (design review)
159
- implement phase + tests req:doctor (gate) req:review-codex (phase review) → req:commit
160
-
161
- [Do automatically]
162
- - Within the approved phase scope, do implementation, tests, keeping codex-request consistent, applying NEEDS_FIX, and re-review (resume) automatically. Do not ask me every time.
163
- - If Codex returns NEEDS_FIX, apply the feedback and re-run the review until approved (max 3 rounds per phase).
164
- - Only what is `git add`ed is reviewed. NEVER `git add` state.json or responses/ (the tool manages those).
165
-
166
- [Control points — stop and ask me ONLY here]
167
- - Right before `req:commit --run` (the actual commit / HIGH impact)
168
- - Right before merging to main or `git push`
169
- - Destructive operations such as reset, clean, force push
170
- - When a design-scope change or a feature not in [Requirements] is needed
171
- - When Codex review exceeds 3 rounds without approval, or the judgment is unclear
172
- - When a prerequisite is missing (not a git repo, no Codex CLI / Node / package manager) and you must fail-closed
173
-
174
- [First reply] Report only the REQ number, branch, phase plan, and control points. After that, stop only at control points.
175
-
176
- [Requirements]
177
- - What: (e.g.) Add a user-profile edit API
178
- - Why: (e.g.) Only the name is editable today — email and bio should be editable too
179
- - Constraints: (e.g.) Reuse the existing auth middleware, validate email format, no new external libraries
180
- - Done when: (e.g.) PATCH /profile works + unit tests pass + existing tests unbroken
181
- ````
182
-
183
- > The `[Requirements]` example above is **just a sample.** Just replace the 4 lines (What / Why / Constraints / Done when) with your own. If the request is large, it's split into multiple phases, each going through its own review and gate.
102
+ | Requirement | Check | Notes |
103
+ |---|---|---|
104
+ | Git | `git --version` | Required |
105
+ | Node.js 18.17+ | `node --version` | Required |
106
+ | npm, pnpm, or yarn | `npm --version` | Examples use npm |
107
+ | Codex CLI | `codex --version` | Required for review runs |
184
108
 
185
- ### Example of the agent's first reply
109
+ If Codex CLI is not installed:
186
110
 
187
- ```
188
- Issued REQ-2026-002 · branch feat/req-2026-002-profile-edit-api
189
- Phase plan:
190
- - phase-1: PATCH /profile handler + validation
191
- - phase-2: unit tests + regression
192
- Control points: proceed per phase after design approval / confirm before req:commit --run / push needs separate approval
193
- → Starting with the design docs. Once the design review passes, I'll move to implementation.
111
+ ```sh
112
+ npm install -g @openai/codex
113
+ codex login
114
+ codex login status
194
115
  ```
195
116
 
196
- Now you just **wait** until a control-point notification arrives. When it asks "commit as-is?" right before committing, you confirm.
117
+ On Windows, if `codex` is not found right after installation, open a new terminal so PATH is reloaded.
197
118
 
198
119
  ---
199
120
 
200
- ## 🔧 Appendix: what the workflow actually runs under the hood (manual steps)
121
+ ## Manual Commands
201
122
 
202
- > With the prompt approach above, you **don't need to type the commands below** — the agent runs them for you.
203
- > These are the actual commands the workflow runs internally. Refer to them only when you need to **understand the behavior, debug, or run steps manually.**
204
-
205
- Let's walk the whole flow with one small feature as an example. (Commands use `npm`; arguments after `npm run` go after `--`. With `pnpm` you can drop the `--`, e.g. `pnpm req:new my-feature --run`.)
206
-
207
- ### Step 1 — create a work ticket
123
+ Most users should use the prompt flow above. This section is for understanding what the workflow runs internally or for debugging.
208
124
 
209
125
  ```sh
126
+ # 1. Create a ticket and branch
210
127
  npm run req:new -- my-feature --run
211
- ```
212
-
213
- - A new branch (`feat/req-...`) is created, and three design docs appear under `workflow/REQ-2026-001/`.
214
- - The output shows a **ticket number** (e.g. `REQ-2026-001`). Later commands use just the number → `2026-001`
215
-
216
- ### Step 2 — write the design docs
217
-
218
- Fill in the three files under `workflow/REQ-2026-001/`:
219
-
220
- - `00-requirement.md` — **what** to build and why
221
- - `01-design.md` — **how** to build it
222
- - `02-plan.md` — in what **order/phases** to proceed
223
-
224
- ### Step 3 — get a design review (Codex)
225
-
226
- Stage your design (i.e. `git add`):
227
128
 
228
- ```sh
129
+ # 2. Write design docs, then stage them
229
130
  git add workflow/REQ-2026-001/00-requirement.md workflow/REQ-2026-001/01-design.md workflow/REQ-2026-001/02-plan.md
230
- npm run req:review-codex -- 2026-001 --kind design --run
231
- ```
232
-
233
- - Codex reads the design and returns **approval** or **NEEDS_FIX**.
234
- - If NEEDS_FIX, apply the feedback, then **`git add` again → re-run the command.** Repeat until approved.
235
-
236
- ### Step 4 — implement code + tests
237
131
 
238
- Once the design is approved, write the actual code and tests.
239
-
240
- ### Step 5 — gate check
132
+ # 3. Design review
133
+ npm run req:review-codex -- 2026-001 --kind design --run
241
134
 
242
- Stage your changes and preview the gate status:
135
+ # 4. Implement code, then stage source files
136
+ git add <changed-source-files>
243
137
 
244
- ```sh
245
- git add <files-you-changed>
138
+ # 5. Gate check
246
139
  npm run req:doctor -- 2026-001
247
- ```
248
-
249
- - It checks several things (is the design approval valid, does the staged code match the approved code, is the working tree clean, etc.) and shows **PASS/FAIL.**
250
140
 
251
- > ⚠️ **Important:** `git add` **only your own code/docs.** Do **not** stage workflow-internal files like `state.json` or `responses/` (the tool manages them; staging them by mistake gets blocked at the commit step).
252
-
253
- ### Step 6 — get a code review (Codex)
254
-
255
- ```sh
141
+ # 6. Implementation review
256
142
  npm run req:review-codex -- 2026-001 --kind phase --run
143
+
144
+ # 7. Commit approved code
145
+ npm run req:commit -- 2026-001 --run -m "feat: my feature"
257
146
  ```
258
147
 
259
- - Codex reviews the **implementation code.** Again, apply feedback re-run until approved.
260
- - Once approved, `commit_allowed=true` and the commit opens.
148
+ Important: only stage code and documents you authored for the source commit. `state.json` and `responses/` are managed by the tool.
261
149
 
262
- ### Step 7 commit
150
+ For multi-line commit messages, use a file instead of `-m`.
263
151
 
264
152
  ```sh
265
- npm run req:commit -- 2026-001 --run -m "feat: implement my-feature"
153
+ npm run req:commit -- 2026-001 --run --message-file commit-message.txt
266
154
  ```
267
155
 
268
- - After passing the gate (doctor) one final time, it makes a **code commit + an evidence commit.**
269
- - If it isn't approved, or the code changed after approval, it **stops here.** (That's the heart of CommitGate.)
270
-
271
- 🎉 Done! Your code is now committed safely with review, approval, and evidence all recorded.
272
-
273
156
  ---
274
157
 
275
- ## 📋 Command cheat sheet
158
+ ## Command Cheat Sheet
276
159
 
277
- | Command | What it does |
160
+ | Command | Purpose |
278
161
  |---|---|
279
- | `npx commitgate` | Install (scaffold) CommitGate into your project |
280
- | `req:new <name> --run` | Create a new ticket + branch + design docs |
281
- | `req:review-codex <num> --kind design --run` | **Design** review (Codex) |
282
- | `req:review-codex <num> --kind phase --run` | **Implementation** review (Codex) |
283
- | `req:doctor <num>` | Gate check (shows pass/fail) |
284
- | `req:commit <num> --run -m "message"` | Commit approved code (+ evidence) |
285
-
286
- > Instead of `-m "message"`, multi-line messages can be read from a file with `--message-file message.txt`.
162
+ | `npx commitgate` | Install CommitGate into a project |
163
+ | `req:new <slug> --run` | Create a REQ ticket, branch, and design docs |
164
+ | `req:review-codex <id> --kind design --run` | Review the design |
165
+ | `req:review-codex <id> --kind phase --run` | Review the implementation |
166
+ | `req:doctor <id>` | Check gate status |
167
+ | `req:commit <id> --run -m "message"` | Commit approved changes |
287
168
 
288
169
  ---
289
170
 
290
- ## ⚙️ Configuration (`req.config.json`, optional)
171
+ ## Configuration
291
172
 
292
- You can tweak behavior via `req.config.json` at the project root. **Without the file it works on sensible defaults**, so you can ignore it at first.
173
+ Defaults are enough for most projects. If needed, edit `req.config.json` in the project root.
293
174
 
294
175
  | Key | Default | Meaning |
295
176
  |---|---|---|
296
- | `branchPrefix` | `"feat/req-"` | Prefix for newly created branch names |
297
- | `ticketRoot` | `"workflow"` | Where ticket folders live |
298
- | `packageManager` | auto-detected | `npm` / `pnpm` / `yarn` |
299
- | `designDocs` | `00-/01-/02-*.md` | Filenames of the three design docs |
177
+ | `branchPrefix` | `"feat/req-"` | Prefix for new branches |
178
+ | `ticketRoot` | `"workflow"` | REQ ticket directory |
179
+ | `packageManager` | auto-detected | `npm`, `pnpm`, or `yarn` |
180
+ | `designDocs` | `00/01/02` docs | Design document filenames |
300
181
 
301
- Invalid values (e.g. an empty `branchPrefix`, a path that escapes the folder) are **rejected safely.**
182
+ Empty `branchPrefix` values and paths that escape the project root are rejected.
302
183
 
303
184
  ---
304
185
 
305
- ## FAQ / troubleshooting
186
+ ## FAQ
306
187
 
307
- **Q. It says the `codex` command is not found.**
308
- A. The Reviewer (Codex CLI) must be installed for reviews to run. Before it's installed, review commands don't "silently pass" — they **fail clearly** (that's the intended fail-closed behavior).
188
+ **What happens if Codex CLI is missing?**
189
+ The review command fails. It is not treated as approval.
309
190
 
310
- **Q. I get an error like "staged tree != approved" at the commit step.**
311
- A. It means **the approved code and the code you currently staged (`git add`) differ.** If you changed code after approval, redo Step 6 (implementation review) to re-approve. (This safeguard prevents approval swapping.)
191
+ **Can I edit code after approval and still commit?**
192
+ No. If the staged tree changes after approval, CommitGate treats the approval as stale and requires review again.
312
193
 
313
- **Q. I get a "non-code staged not allowed (state/responses)" error.**
314
- A. You `git add`ed `state.json` or `responses/`. **Don't stage those** (the tool manages them); stage only your own code/docs.
194
+ **Why should I not stage `state.json` or `responses/`?**
195
+ They are workflow state and evidence files. Mixing them into the source commit weakens the approval binding, so `req:commit` blocks it.
315
196
 
316
- **Q. Does running `npx commitgate` twice overwrite things?**
317
- A. No. **Existing files are skipped** (idempotent). To force overwrite, add `--force`.
318
-
319
- **Q. On Windows my commit message newlines look wrong.**
320
- A. For multi-line messages, use `--message-file file.txt` instead of `-m`.
197
+ **Does running install twice overwrite files?**
198
+ No. Existing files are skipped. Use `--force` if you intentionally want to refresh them.
321
199
 
322
200
  ---
323
201
 
324
- ## 🔒 How is "safety" guaranteed? (fail-closed)
202
+ ## Current Scope
325
203
 
326
- CommitGate's principle is **"pass only when definitely approved; block on the slightest doubt."**
204
+ The current release is **Stage A: vendored scaffold model**. `npx commitgate` copies workflow files into the target project.
327
205
 
328
- - Design docs missing or malformed → treated as not approved
329
- - Codex not installed / review failed → not a pass, fails clearly
330
- - The approved code fingerprint differs from the current code → commit rejected
331
- - The working tree is dirty (unreviewed changes mixed in) → review/commit rejected
206
+ Future scope:
332
207
 
333
- In other words, **blocking is the default and passing is the exception**, minimizing the chance of unverified code slipping through.
208
+ - Running directly from `node_modules` as a library-style model
209
+ - Non-git VCS support
210
+ - More design document templates
211
+ - Broader Linux/macOS CI smoke coverage
334
212
 
335
213
  ---
336
214
 
337
- ## 📄 License
215
+ ## License
338
216
 
339
217
  [MIT](./LICENSE) © 2026 sol5288
340
-
341
- > This workflow was extracted as a standalone package from the REQ-2026-017 portability kit of `palm-kiosk-app`, and was validated by **reviewing and approving itself through this very workflow (dogfood).**
package/README.md CHANGED
@@ -1,341 +1,217 @@
1
- # CommitGate 🚦
1
+ # CommitGate
2
2
 
3
3
  🌐 **한국어** · [English](./README.en.md)
4
4
 
5
- **AI 코드를, 다른 AI가 리뷰하고 승인해야만 커밋되게 하는 "커밋 관문(gate)".**
5
+ **AI 코딩 변경을 Codex 리뷰 승인 없이는 커밋하지 못하게 막는 커밋 게이트입니다.**
6
6
 
7
- > 요약: **만드는 AI(Builder)** **검사하는 AI(Reviewer)** 짝지어, **리뷰·승인·증거 없이는 커밋이 통과하지 못하게** 막아줍니다.
7
+ AI 에이전트가 코드를 빠르게 만들더라도, 리뷰 없이 바로 커밋되면 위험합니다. CommitGate는 변경을 티켓 단위로 묶고, Codex가 승인한 staged tree만 커밋되게 합니다. 승인 후 코드가 바뀌거나 증거가 부족하면 기본적으로 막습니다.
8
8
 
9
9
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
10
10
 
11
11
  ---
12
12
 
13
- ## 🤔 이게 뭔가요? (비유로)
13
+ ## Quick Start
14
14
 
15
- 공항 보안 검색대를 떠올려 보세요. 아무리 급해도 **검색대를 통과하지 않으면** 탑승구로 수 없죠.
15
+ 아래는 가장 짧은 사용 경로입니다. 프로젝트 루트는 **git 저장소이고 `package.json`이 있는 폴더**여야 합니다.
16
16
 
17
- CommitGate도 똑같습니다. 코드를 아무리 많이 만들어도 **"검사 → 승인"이라는 관문을 통과하지 않으면 `git commit`이 막힙니다.**
18
-
19
- - 🛠️ **Builder(만드는 쪽)** — 당신, 또는 당신의 AI 코딩 도구(예: Claude Code). 요구사항을 설계하고 코드를 짭니다.
20
- - 🔎 **Reviewer(검사하는 쪽)** — **Codex CLI**. Builder가 만든 걸 **독립적으로 다시 검토**해서 통과/보완을 판정합니다.
21
- - 🚦 **CommitGate** — 그 사이에 서서, **Reviewer가 승인한 코드만** 커밋되게 하는 규칙(관문).
22
-
23
- 즉, "혼자 만들고 혼자 커밋"이 아니라 **"만든 AI ↔ 검사한 AI"의 교차 검증**을 강제합니다.
24
-
25
- ## 🎯 어떤 문제를 푸나요?
26
-
27
- AI는 코드를 **빠르게** 만들지만, 검증 없이 그대로 커밋되면 위험합니다. CommitGate는:
28
-
29
- - ✅ 모든 변경이 **리뷰를 반드시 거치게** 합니다.
30
- - ✅ 승인은 **"리뷰한 바로 그 코드"에 묶입니다.** (승인 후 몰래 코드를 바꿔치기 못 함 — 지문처럼 대조)
31
- - ✅ 무언가 애매하거나 빠지면 **일단 막습니다(fail-closed).** "확실할 때만 통과"가 기본값이라 안전합니다.
32
- - ✅ 누가 언제 무엇을 승인했는지 **증거가 파일로 남습니다.**
33
-
34
- ## 🔄 동작 흐름 한눈에
35
-
36
- ```
37
- ① 티켓 만들기 → ② 설계 작성 → ③ 설계 리뷰(Codex) → ④ 코드 구현
38
- req:new req:review-codex
39
-
40
- → ⑤ 관문 점검 → ⑥ 구현 리뷰(Codex) → ⑦ 승인되면 커밋
41
- req:doctor req:review-codex req:commit
17
+ ```sh
18
+ npx commitgate
19
+ npm install
20
+ codex --version
21
+ codex login status
42
22
  ```
43
23
 
44
- 단계에서 **통과하지 못하면 다음으로 넘어갑니다.**
45
-
46
- ---
47
-
48
- ## 📦 준비물 (Prerequisites)
24
+ 그다음 AI 코딩 에이전트에게 아래 프롬프트를 붙여넣습니다.
49
25
 
50
- 시작 전에 아래 4가지가 필요합니다. 터미널에서 하나씩 확인해 보세요.
26
+ ```text
27
+ 이 요청은 일반 구현으로 처리하지 말고, 이 프로젝트에 설치된 CommitGate를 사용해라.
51
28
 
52
- | 필요한 | 확인 명령 | 없으면 |
53
- |---|---|---|
54
- | **Git** (필수) | `git --version` | [git-scm.com](https://git-scm.com) 에서 설치 |
55
- | **Node.js 18.17+** (필수) | `node --version` | [nodejs.org](https://nodejs.org) 에서 설치 |
56
- | **Codex CLI** (리뷰용) | `codex --version` | OpenAI Codex CLI 설치 (없으면 리뷰만 안 되고 나머지는 됨) |
57
- | **패키지 매니저** | `npm --version` | Node 설치 시 `npm`은 기본 포함 (또는 `pnpm`/`yarn`) |
58
-
59
- > 💡 **Reviewer = Codex CLI** 입니다. 리뷰를 실제로 돌리려면 Codex CLI가 설치되어 있어야 해요. 없으면 리뷰 명령이 "안전하게 실패(fail-closed)"합니다 — 조용히 통과되는 일은 없습니다.
60
-
61
- ### 🔧 Codex CLI 설치 & 로그인 (Reviewer 준비)
29
+ REQ 티켓을 만들고 다음 흐름을 끝까지 진행해라:
30
+ req:new → 설계문서 작성 → Codex design 리뷰 → 구현·테스트 → req:doctor → Codex phase 리뷰 → req:commit
62
31
 
63
- CommitGate의 리뷰는 **OpenAI Codex CLI**가 담당합니다. 아래 3단계면 끝납니다.
32
+ 자동으로 진행할 것:
33
+ - NEEDS_FIX가 나오면 수정하고 재리뷰해 승인까지 반복한다.
34
+ - 리뷰 대상은 git add 한 파일만이다.
35
+ - `state.json`과 `responses/`는 직접 `git add`하지 않는다.
64
36
 
65
- **① 설치**
37
+ 멈춰서 확인받을 때:
38
+ - req:commit --run 직전
39
+ - main 병합 또는 push 직전
40
+ - reset, clean, force push 같은 destructive 작업 전
41
+ - 요구사항 범위를 바꿔야 할 때
42
+ - Codex 리뷰가 3라운드를 넘어도 승인되지 않을 때
66
43
 
67
- ```sh
68
- # npm (모든 OS)
69
- npm install -g @openai/codex
70
-
71
- # 또는 macOS Homebrew
72
- brew install codex
44
+ 요구사항:
45
+ - 무엇을:
46
+ - 왜:
47
+ - 제약:
48
+ - 완료 기준:
73
49
  ```
74
50
 
75
- 설치 확인:
51
+ 응답은 보통 이렇게 나와야 합니다.
76
52
 
77
- ```sh
78
- codex --version # 예: codex-cli 0.4x.x
53
+ ```text
54
+ REQ-2026-002 발행
55
+ 브랜치: feat/req-2026-002-profile-edit-api
56
+ phase:
57
+ - phase-1: PATCH /profile 구현
58
+ - phase-2: 테스트와 회귀 확인
59
+ 통제점: req:commit --run 직전, push 직전
79
60
  ```
80
61
 
81
- **② 로그인** 편한 방법 하나
82
-
83
- - **방법 A. ChatGPT 계정으로 (권장, 브라우저)**
84
- ```sh
85
- codex login
86
- ```
87
- 브라우저가 열리면 ChatGPT 계정으로 로그인 → 터미널로 돌아오면 완료.
62
+ 이후에는 에이전트가 설계, 구현, 테스트, Codex 리뷰를 진행합니다. 사용자는 커밋이나 push 같은 통제점에서만 확인하면 됩니다.
88
63
 
89
- - **방법 B. OpenAI API 키로**
90
- ```sh
91
- # 환경변수로 (가장 간단)
92
- export OPENAI_API_KEY=sk-... # Windows PowerShell: $env:OPENAI_API_KEY="sk-..."
64
+ ---
93
65
 
94
- # 또는 키를 Codex에 저장
95
- printenv OPENAI_API_KEY | codex login --with-api-key
96
- ```
97
- API 키는 [platform.openai.com](https://platform.openai.com/api-keys) 에서 발급합니다.
66
+ ## 무엇을 보장하나요?
98
67
 
99
- **③ 로그인 확인**
68
+ CommitGate가 막는 것은 단순한 명령 실수가 아니라 **리뷰받지 않은 변경이 커밋되는 상황**입니다.
100
69
 
101
- ```sh
102
- codex login status # 로그인 상태 표시
103
- codex doctor # 설치·인증·환경 종합 진단(문제 있으면 원인 안내)
104
- ```
70
+ - Codex 리뷰가 실패하거나 없으면 커밋할 수 없습니다.
71
+ - 승인된 staged tree와 지금 커밋하려는 staged tree가 다르면 막습니다.
72
+ - `state.json`, `responses/` 같은 워크플로 내부 파일을 source 커밋에 섞으면 막습니다.
73
+ - Codex CLI가 없거나 실행에 실패하면 조용히 통과하지 않고 실패합니다.
74
+ - 승인 응답과 증거 파일은 `workflow/REQ-.../responses/`에 남습니다.
105
75
 
106
- > `codex --version` `codex login status` 정상이면 리뷰 준비 끝. 이제 `npx commitgate` 로 넘어가세요.
107
- > ⚠️ Windows에서 `codex` 명령을 못 찾으면 **새 터미널**을 열어 PATH를 새로 읽게 하세요(전역 설치 직후 흔한 문제).
76
+ 줄로 말하면, **확실히 승인된 변경만 통과하고 애매하면 멈추는 방식**입니다.
108
77
 
109
78
  ---
110
79
 
111
- ## 🚀 설치 (딱 한 줄)
112
-
113
- **당신의 프로젝트 폴더**(= git 저장소, `package.json` 있는 곳)에서:
80
+ ## 설치가 하는
114
81
 
115
- ```sh
116
- npx commitgate
117
- ```
82
+ `npx commitgate`는 대상 프로젝트에 아래 파일과 설정을 추가합니다. 기존 파일은 기본적으로 덮어쓰지 않습니다.
118
83
 
119
- 명령이 자동으로 해주는 (기존 파일은 **덮어쓰지 않아요**):
120
-
121
- 1. 워크플로 스크립트(`scripts/req/`)와 스키마를 복사합니다.
122
- 2. `req.config.json`(설정 파일)을 만들어 둡니다.
123
- 3. `package.json`에 `req:*` 명령들과 필요한 devDependencies(`tsx`, `ajv`, `cross-spawn`)를 추가합니다.
124
- 4. `AGENTS.md`(Reviewer가 읽는 규칙 파일)가 없으면 템플릿을 만들어 줍니다.
84
+ | 추가 항목 | 설명 |
85
+ |---|---|
86
+ | `scripts/req/` | `req:new`, `req:review-codex`, `req:doctor`, `req:commit` 스크립트 |
87
+ | `workflow/*.schema.json` | Codex 응답과 설정 검증 스키마 |
88
+ | `req.config.json` | 프로젝트별 설정 |
89
+ | `AGENTS.md` | 에이전트와 Reviewer가 읽는 규칙 템플릿 |
90
+ | `package.json` 스크립트 | `req:*` 명령과 필요한 devDependencies |
125
91
 
126
- 설치 후, 방금 추가된 의존성을 받습니다:
92
+ 미리보기만 하려면:
127
93
 
128
94
  ```sh
129
- npm install
95
+ npx commitgate --dry-run
130
96
  ```
131
97
 
132
- > `--dry-run` 을 붙이면 **실제로 바꾸지 않고** 무엇을 할지 미리 볼 수 있어요: `npx commitgate --dry-run`
133
-
134
98
  ---
135
99
 
136
- ## 🤖 사용법 — AI 에이전트에게 프롬프트로 맡기기 (권장)
137
-
138
- 솔직히, `req:new → 리뷰 → 구현 → 리뷰 → 커밋`을 **손으로 하나씩 치는 사람은 없습니다.** 피곤하니까요.
139
-
140
- CommitGate의 진짜 사용법은 이겁니다: **당신의 AI 코딩 에이전트에게 "요구사항"과 "이 워크플로를 쓰라"는 프롬프트를 던지면, 에이전트가 알아서 전 과정을 굴립니다.** 당신은 **통제점(커밋·머지·푸시 등)에서만** 승인하면 됩니다.
141
-
142
- ### 이 방식의 전제
143
- - **셸 명령을 실행할 수 있는 AI 코딩 에이전트** — Claude Code, Cursor(agent), Codex CLI 등. (당신의 저장소에서 터미널 명령을 직접 돌릴 수 있어야 함)
144
- - **Codex CLI 설치** — 리뷰어(Reviewer) 역할. 없으면 리뷰 단계가 fail-closed로 멈춥니다.
145
- - **`AGENTS.md` 채우기** — `npx commitgate`가 만든 템플릿에 당신 프로젝트의 규칙(코딩 컨벤션·테스트 명령 등)을 적어두면 리뷰 품질이 올라갑니다.
146
-
147
- ### 3단계면 끝
148
- 1. 아래 **프롬프트 템플릿**을 복사하고, 맨 아래 `[요구사항]` 칸을 당신 요구로 채웁니다.
149
- 2. 전체를 **AI 에이전트 대화창에 그대로 붙여넣습니다.**
150
- 3. 에이전트가 **첫 응답으로 REQ 번호·브랜치·phase 계획·통제점**만 보고합니다. 이후엔 **통제점에서만** 당신에게 확인을 받습니다 — 나머지(구현·테스트·Codex 리뷰·NEEDS_FIX 반영·재리뷰)는 자동입니다.
151
-
152
- ### 📋 복사해서 쓰는 프롬프트 템플릿
100
+ ## 준비물
153
101
 
154
- ````text
155
- 이 요청은 일반 구현으로 처리하지 말고, 반드시 이 프로젝트에 설치된 CommitGate(AI REQ workflow)를 사용해라.
156
-
157
- 아래 [요구사항]으로 REQ 티켓을 발행하고 다음 흐름을 끝까지 태워라:
158
- req:new 설계문서(00/01/02) 작성 req:review-codex(design 리뷰)
159
- phase 구현·테스트 req:doctor(게이트) req:review-codex(phase 리뷰) req:commit
160
-
161
- [자동으로 진행할 것]
162
- - 승인된 phase 범위 안에서 구현·테스트·codex-request 정합·NEEDS_FIX 반영·재리뷰(resume)는 자동으로 진행해라. 매번 확인받지 마라.
163
- - Codex가 NEEDS_FIX를 주면 지적을 반영하고 재리뷰를 돌려 승인까지 반복해라(phase당 최대 3라운드).
164
- - 리뷰 대상은 git add 한 것만이다. state.json·responses/ 는 절대 git add 하지 마라(도구가 관리한다).
165
-
166
- [멈춰서 사람 확인을 받을 통제점 — 여기서만 멈춰라]
167
- - req:commit --run 직전 (실제 커밋 / HIGH 영향)
168
- - main 병합 또는 git push 직전
169
- - reset·clean·force push 등 destructive 작업
170
- - 설계 범위 변경 또는 [요구사항]에 없는 기능 추가가 필요할 때
171
- - Codex 리뷰가 3라운드를 넘겨도 승인 안 되거나 판단이 불명확할 때
172
- - git 저장소가 아니거나 Codex CLI·Node·패키지매니저 전제가 없어 fail-closed 해야 할 때
173
-
174
- [첫 응답] REQ 번호, 브랜치, phase 계획, 통제점만 간단히 보고해라. 그 뒤부터는 통제점에서만 멈춰라.
175
-
176
- [요구사항]
177
- - 무엇을: (예) 사용자 프로필 편집 API 추가
178
- - 왜: (예) 지금은 이름만 수정 가능 — 이메일·소개도 편집 필요
179
- - 제약: (예) 기존 인증 미들웨어 재사용, 이메일 형식 검증, 외부 라이브러리 추가 금지
180
- - 완료 기준: (예) PATCH /profile 동작 + 단위 테스트 통과 + 기존 테스트 무손상
181
- ````
182
-
183
- > 위 `[요구사항]` 예시는 **샘플일 뿐**입니다. 4줄(무엇을/왜/제약/완료 기준)을 당신 요구로 바꾸기만 하면 됩니다. 요구가 크면 phase가 여러 개로 쪼개지고, 각 phase마다 리뷰·게이트를 거칩니다.
102
+ | 필요 | 확인 명령 | 비고 |
103
+ |---|---|---|
104
+ | Git | `git --version` | 필수 |
105
+ | Node.js 18.17+ | `node --version` | 필수 |
106
+ | npm, pnpm, yarn 하나 | `npm --version` | npm 기준으로 안내 |
107
+ | Codex CLI | `codex --version` | 리뷰 실행에 필요 |
184
108
 
185
- ### 에이전트가 보고하는 첫 응답 예시
109
+ Codex CLI가 없다면:
186
110
 
187
- ```
188
- REQ-2026-002 발행 · 브랜치 feat/req-2026-002-profile-edit-api
189
- phase 계획:
190
- - phase-1: PATCH /profile 핸들러 + 유효성 검증
191
- - phase-2: 단위 테스트 + 회귀
192
- 통제점: design 승인 후 phase별 진행 / req:commit --run 직전 확인 / push는 별도 승인
193
- → 설계문서 작성부터 진행합니다. design 리뷰 통과하면 구현으로 넘어갑니다.
111
+ ```sh
112
+ npm install -g @openai/codex
113
+ codex login
114
+ codex login status
194
115
  ```
195
116
 
196
- 이제 당신은 통제점 알림이 때까지 **기다리기만** 하면 됩니다. 커밋 직전에 "이대로 커밋할까요?" 물으면 확인해 주면 되고요.
117
+ Windows에서 설치 직후 `codex` 명령을 찾으면 터미널을 열어 PATH를 다시 읽게 하세요.
197
118
 
198
119
  ---
199
120
 
200
- ## 🔧 부록: 워크플로가 내부에서 실제로 하는 일 (수동 단계)
121
+ ## 수동 명령
201
122
 
202
- > 위 프롬프트 방식이면 아래 명령을 **직접 필요가 없습니다** 에이전트가 알아서 실행합니다.
203
- > 아래는 워크플로가 내부에서 돌리는 실제 명령들입니다. **동작 이해·디버깅·수동 실행**이 필요할 때만 참고하세요.
204
-
205
- 작은 기능 하나를 예로, 전체 흐름을 그대로 밟아 봅니다. (명령은 `npm` 기준이며, `npm run` 뒤 인자는 `--` 다음에 씁니다. `pnpm`을 쓰면 `pnpm req:new my-feature --run` 처럼 `--` 없이 됩니다.)
206
-
207
- ### 1단계 — 작업 티켓 만들기
123
+ 대부분의 사용자는 위 프롬프트 방식으로 충분합니다. 아래는 내부에서 어떤 명령이 실행되는지 이해하거나 직접 디버깅할 때만 보면 됩니다.
208
124
 
209
125
  ```sh
126
+ # 1. 티켓과 브랜치 생성
210
127
  npm run req:new -- my-feature --run
211
- ```
212
-
213
- - 새 브랜치(`feat/req-...`)가 생기고, `workflow/REQ-2026-001/` 폴더에 설계 문서 3종이 만들어집니다.
214
- - 출력에 **티켓 번호**(예: `REQ-2026-001`)가 나옵니다. 이후 명령에선 번호만 씁니다 → `2026-001`
215
-
216
- ### 2단계 — 설계 문서 작성
217
-
218
- `workflow/REQ-2026-001/` 안의 세 파일을 채웁니다:
219
-
220
- - `00-requirement.md` — **무엇을** 왜 만드는가
221
- - `01-design.md` — **어떻게** 만들 것인가
222
- - `02-plan.md` — 어떤 **순서/단계**로 진행할 것인가
223
-
224
- ### 3단계 — 설계 리뷰 받기 (Codex)
225
-
226
- 작성한 설계를 검사대에 올립니다(= `git add`):
227
128
 
228
- ```sh
129
+ # 2. 설계 문서 작성 후 stage
229
130
  git add workflow/REQ-2026-001/00-requirement.md workflow/REQ-2026-001/01-design.md workflow/REQ-2026-001/02-plan.md
230
- npm run req:review-codex -- 2026-001 --kind design --run
231
- ```
232
-
233
- - Codex가 설계를 읽고 **승인** 또는 **보완 요청(NEEDS_FIX)** 을 돌려줍니다.
234
- - 보완 요청이면 지적사항을 반영하고 **다시 `git add` → 위 명령을 재실행**하세요. 승인될 때까지 반복합니다.
235
-
236
- ### 4단계 — 코드 구현 + 테스트
237
131
 
238
- 설계가 승인되면 실제 코드를 짜고 테스트를 작성합니다.
239
-
240
- ### 5단계 — 관문 점검
132
+ # 3. 설계 리뷰
133
+ npm run req:review-codex -- 2026-001 --kind design --run
241
134
 
242
- 변경을 검사대에 올리고, 게이트 상태를 미리 확인합니다:
135
+ # 4. 코드 구현 stage
136
+ git add <changed-source-files>
243
137
 
244
- ```sh
245
- git add <내가-바꾼-코드-파일들>
138
+ # 5. 게이트 점검
246
139
  npm run req:doctor -- 2026-001
247
- ```
248
-
249
- - 여러 항목(설계 승인 유효한지, 검사대에 올린 코드와 승인된 코드가 같은지, 워킹트리가 깨끗한지 등)을 점검해 **PASS/FAIL** 을 보여줍니다.
250
140
 
251
- > ⚠️ **중요:** `git add` 는 **당신이 만든 코드/문서만** 올리세요. `state.json` 이나 `responses/` 같은 워크플로 내부 파일은 **올리지 마세요.** (도구가 알아서 관리합니다. 실수로 올리면 커밋 단계에서 막힙니다.)
252
-
253
- ### 6단계 — 구현 리뷰 받기 (Codex)
254
-
255
- ```sh
141
+ # 6. 구현 리뷰
256
142
  npm run req:review-codex -- 2026-001 --kind phase --run
143
+
144
+ # 7. 승인된 코드 커밋
145
+ npm run req:commit -- 2026-001 --run -m "feat: my feature"
257
146
  ```
258
147
 
259
- - Codex가 **구현 코드**를 리뷰합니다. 역시 승인될 때까지 반영 재실행 반복.
260
- - 승인되면 `commit_allowed=true` 가 되어 커밋이 열립니다.
148
+ 중요: source 커밋에는 내가 만든 코드와 문서만 stage하세요. `state.json`과 `responses/`는 도구가 관리합니다.
261
149
 
262
- ### 7단계 커밋
150
+ 여러 커밋 메시지는 `-m` 대신 파일을 사용하세요.
263
151
 
264
152
  ```sh
265
- npm run req:commit -- 2026-001 --run -m "feat: my-feature 구현"
153
+ npm run req:commit -- 2026-001 --run --message-file commit-message.txt
266
154
  ```
267
155
 
268
- - 관문(doctor 게이트)을 마지막으로 통과한 뒤 **코드 커밋 + 증거 커밋** 을 남깁니다.
269
- - 승인되지 않았거나, 승인 후 코드가 바뀌었으면 **여기서 막힙니다.** (그게 CommitGate의 핵심)
270
-
271
- 🎉 끝! 이제 리뷰·승인·증거가 모두 남은 상태로 안전하게 커밋되었습니다.
272
-
273
156
  ---
274
157
 
275
- ## 📋 명령어 치트시트
158
+ ## 명령어 요약
276
159
 
277
- | 명령 | 하는 |
160
+ | 명령 | 용도 |
278
161
  |---|---|
279
- | `npx commitgate` | 프로젝트에 CommitGate 설치(스캐폴딩) |
280
- | `req:new <이름> --run` | 작업 티켓 + 브랜치 + 설계문서 생성 |
281
- | `req:review-codex <번호> --kind design --run` | **설계** 리뷰(Codex) |
282
- | `req:review-codex <번호> --kind phase --run` | **구현** 리뷰(Codex) |
283
- | `req:doctor <번호>` | 관문 점검(통과/실패 표시) |
284
- | `req:commit <번호> --run -m "메시지"` | 승인된 코드 커밋(+증거) |
285
-
286
- > `-m "메시지"` 대신 여러 줄 메시지는 `--message-file 메시지.txt` 로 파일에서 읽을 수 있습니다.
162
+ | `npx commitgate` | 프로젝트에 CommitGate 설치 |
163
+ | `req:new <slug> --run` | REQ 티켓, 브랜치, 설계문서 생성 |
164
+ | `req:review-codex <id> --kind design --run` | 설계 리뷰 |
165
+ | `req:review-codex <id> --kind phase --run` | 구현 리뷰 |
166
+ | `req:doctor <id>` | 게이트 상태 확인 |
167
+ | `req:commit <id> --run -m "message"` | 승인된 변경 커밋 |
287
168
 
288
169
  ---
289
170
 
290
- ## ⚙️ 설정 (`req.config.json`, 선택)
171
+ ## 설정
291
172
 
292
- 프로젝트 루트의 `req.config.json` 으로 동작을 바꿀 수 있습니다. **파일이 없으면 기본값**으로 잘 동작하니, 처음엔 신경 쓰지 않아도 됩니다.
173
+ 대부분은 기본값으로 충분합니다. 필요하면 프로젝트 루트의 `req.config.json`을 수정하세요.
293
174
 
294
- | 항목 | 기본값 | |
175
+ | 항목 | 기본값 | 설명 |
295
176
  |---|---|---|
296
- | `branchPrefix` | `"feat/req-"` | 새로 만드는 브랜치 이름 앞부분 |
297
- | `ticketRoot` | `"workflow"` | 티켓 폴더 위치 |
298
- | `packageManager` | 자동 감지 | `npm` / `pnpm` / `yarn` |
299
- | `designDocs` | `00-/01-/02-*.md` | 설계문서 3종 파일명 |
177
+ | `branchPrefix` | `"feat/req-"` | 브랜치 prefix |
178
+ | `ticketRoot` | `"workflow"` | REQ 티켓 폴더 |
179
+ | `packageManager` | 자동 감지 | `npm`, `pnpm`, `yarn` |
180
+ | `designDocs` | `00/01/02` 문서 | 설계 문서 파일명 |
300
181
 
301
- 잘못된 값(예: 빈 `branchPrefix`, 폴더 밖으로 벗어나는 경로)은 **안전하게 거부**됩니다.
182
+ 빈 `branchPrefix`나 프로젝트 밖으로 나가는 경로는 거부됩니다.
302
183
 
303
184
  ---
304
185
 
305
- ## ❓ 자주 묻는 질문 / 문제 해결
186
+ ## FAQ
306
187
 
307
- **Q. `codex` 명령이 없다고 나와요.**
308
- A. Reviewer(Codex CLI)가 설치되어 있어야 리뷰가 돌아갑니다. 설치 전에는 리뷰 명령이 "조용히 통과"하지 않고 **명확히 실패**합니다 — 이게 정상 동작(fail-closed)입니다.
188
+ **Codex CLI가 없으면 어떻게 되나요?**
189
+ 리뷰 명령이 실패합니다. 조용히 승인 처리하지 않습니다.
309
190
 
310
- **Q. 커밋 단계에서 "staged tree != approved" 같은 오류가 나요.**
311
- A. **승인받은 코드와, 지금 검사대(git add)에 올린 코드가 다르다**는 뜻입니다. 승인 후에 코드를 바꿨다면 6단계(구현 리뷰)를 다시 받아 재승인하세요. (승인 바꿔치기를 막는 안전장치입니다.)
191
+ **승인 코드를 조금 고치면 커밋되나요?**
192
+ 됩니다. 승인된 staged tree와 달라지면 stale 승인으로 보고 다시 리뷰를 요구합니다.
312
193
 
313
- **Q. "비-코드 staged 금지(state/responses)" 오류가 나요.**
314
- A. `git add` `state.json` 이나 `responses/` 올렸기 때문입니다. 파일들은 **올리지 말고**(도구가 관리), 내가 만든 코드/문서만 올리세요.
194
+ **`state.json`이나 `responses/`는 stage하면 되나요?**
195
+ 워크플로 증거와 상태 파일입니다. source 커밋에 섞이면 승인 바인딩이 흐려지므로 `req:commit`이 막습니다.
315
196
 
316
- **Q. `npx commitgate` 를 두 실행하면 덮어써지나요?**
317
- A. 아니요. **이미 있는 파일은 건너뜁니다**(멱등). 강제로 덮어쓰려면 `--force` 를 붙이세요.
318
-
319
- **Q. Windows인데 커밋 메시지 줄바꿈이 이상해요.**
320
- A. 여러 줄 메시지는 `-m` 대신 `--message-file 파일.txt` 를 쓰면 깔끔합니다.
197
+ **두설치하면 덮어쓰나요?**
198
+ 아니요. 기존 파일은 건너뜁니다. 강제로 갱신하려면 `--force`를 사용하세요.
321
199
 
322
200
  ---
323
201
 
324
- ## 🔒 어떻게 "안전"을 보장하나요? (fail-closed)
202
+ ## 현재 범위
325
203
 
326
- CommitGate의 원칙은 **"확실히 승인됐을 때만 통과, 조금이라도 애매하면 막는다"** 입니다.
204
+ 현재 버전은 **Stage A: vendored scaffold 모델**입니다. `npx commitgate`가 대상 프로젝트에 워크플로 파일을 복사합니다.
327
205
 
328
- - 설계문서가 없거나 형식이 안 맞으면 → 미승인 취급
329
- - Codex가 설치 안 됨 / 리뷰 실패 → 통과 아님, 명확히 실패
330
- - 승인된 코드 지문과 지금 코드가 다르면 → 커밋 거부
331
- - 워킹트리가 지저분하면(리뷰 안 한 변경 섞임) → 리뷰/커밋 거부
206
+ 아래는 후속 범위입니다.
332
207
 
333
- 즉, **"막히는 기본, 통과가 예외"** 라 실수로 미검증 코드가 새어 나갈 틈을 줄입니다.
208
+ - `node_modules`에서 직접 실행하는 라이브러리 모델
209
+ - 비-git VCS 지원
210
+ - 더 다양한 설계문서 템플릿
211
+ - Linux/macOS CI smoke 확대
334
212
 
335
213
  ---
336
214
 
337
- ## 📄 라이선스
215
+ ## License
338
216
 
339
217
  [MIT](./LICENSE) © 2026 sol5288
340
-
341
- > 이 워크플로는 `palm-kiosk-app`의 REQ-2026-017 portability kit에서 독립 패키지로 추출되었고, **자기 자신을 이 워크플로로 리뷰·승인(dogfood)** 하여 검증되었습니다.
package/bin/init.ts CHANGED
@@ -25,6 +25,7 @@ import { resolve, join, dirname, relative } from 'node:path'
25
25
  import { fileURLToPath, pathToFileURL } from 'node:url'
26
26
  import { loadConfig, stripBom, type PackageManager } from '../scripts/req/lib/config'
27
27
  import { createGitAdapter } from '../scripts/req/lib/adapters'
28
+ import * as semver from 'semver'
28
29
 
29
30
  /** 이 패키지 루트(bin/ 기준 1단계 위). 복사 원본. */
30
31
  const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
@@ -37,10 +38,13 @@ const REQ_SCRIPTS: Record<string, string> = {
37
38
  'req:commit': 'tsx scripts/req/req-commit.ts',
38
39
  }
39
40
 
41
+ /** cross-spawn 주입 spec(= 보안 하한 SSOT). 진단(#1)과 주입이 이 값을 공유. */
42
+ const CROSS_SPAWN_SPEC = '^7.0.6'
43
+
40
44
  /** 대상 package.json에 주입할 devDeps(워크플로 실행 전제). cross-spawn = 복사된 adapters.ts의 안전 spawn(P1) 런타임 의존. */
41
45
  const REQ_DEV_DEPS: Record<string, string> = {
42
46
  ajv: '^8.20.0',
43
- 'cross-spawn': '^7.0.6',
47
+ 'cross-spawn': CROSS_SPAWN_SPEC,
44
48
  tsx: '^4.19.1',
45
49
  }
46
50
 
@@ -48,6 +52,7 @@ export interface InitOptions {
48
52
  dir: string
49
53
  force: boolean
50
54
  dryRun: boolean
55
+ strict: boolean // cross-spawn 하한 미만이면 WARN 대신 throw(#1)
51
56
  }
52
57
 
53
58
  export interface InitResult {
@@ -59,6 +64,7 @@ export interface InitResult {
59
64
  packageJsonAdded: string[] // 추가된 script/devDep 키
60
65
  agentsCreated: boolean
61
66
  packageManager: PackageManager
67
+ crossSpawnFloorWarned: boolean // 기존 cross-spawn이 보안 하한 미만이라 경고(#1)
62
68
  dryRun: boolean
63
69
  }
64
70
 
@@ -142,6 +148,92 @@ function parseJsonObject(path: string, label: string): Record<string, unknown> {
142
148
  return parsed as Record<string, unknown>
143
149
  }
144
150
 
151
+ // ─────────────────────────────── cross-spawn 버전 하한 진단 (#1) ──
152
+
153
+ /** 보안 하한 = 주입 spec의 최소버전(SSOT — 하드코딩 이중화 금지). '^7.0.6' → 7.0.6. */
154
+ const CROSS_SPAWN_FLOOR = semver.minVersion(CROSS_SPAWN_SPEC)
155
+
156
+ /** obj가 plain object일 때 obj[key](문자열). 아니면 undefined. */
157
+ function stringField(obj: unknown, key: string): string | undefined {
158
+ if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
159
+ const v = (obj as Record<string, unknown>)[key]
160
+ if (typeof v === 'string') return v
161
+ }
162
+ return undefined
163
+ }
164
+
165
+ /** 대상의 기존 cross-spawn spec(devDeps 우선, 없으면 deps). 없으면 null. */
166
+ function existingCrossSpawnSpec(pkg: Record<string, unknown>): string | null {
167
+ return stringField(pkg.devDependencies, 'cross-spawn') ?? stringField(pkg.dependencies, 'cross-spawn') ?? null
168
+ }
169
+
170
+ /** node_modules에 실제 설치된 cross-spawn 버전(valid semver). 없으면 null. */
171
+ function installedCrossSpawnVersion(targetRoot: string): string | null {
172
+ const p = join(targetRoot, 'node_modules', 'cross-spawn', 'package.json')
173
+ if (!existsSync(p)) return null
174
+ try {
175
+ const v = (JSON.parse(stripBom(readFileSync(p, 'utf8'))) as { version?: unknown }).version
176
+ return typeof v === 'string' && semver.valid(v) ? v : null
177
+ } catch {
178
+ return null
179
+ }
180
+ }
181
+
182
+ /** lockfile 해소 cross-spawn 버전(package-lock v2/v3 JSON 우선, pnpm/yarn best-effort). 없으면 null. */
183
+ function lockedCrossSpawnVersion(targetRoot: string): string | null {
184
+ const pl = join(targetRoot, 'package-lock.json')
185
+ if (existsSync(pl)) {
186
+ try {
187
+ const j = JSON.parse(stripBom(readFileSync(pl, 'utf8'))) as {
188
+ packages?: Record<string, { version?: unknown }>
189
+ dependencies?: Record<string, { version?: unknown }>
190
+ }
191
+ const v = j.packages?.['node_modules/cross-spawn']?.version ?? j.dependencies?.['cross-spawn']?.version
192
+ if (typeof v === 'string' && semver.valid(v)) return v
193
+ } catch {
194
+ /* best-effort */
195
+ }
196
+ }
197
+ for (const [file, re] of [
198
+ ['pnpm-lock.yaml', /cross-spawn@(\d+\.\d+\.\d+)/],
199
+ ['yarn.lock', /(?:^|\n)"?cross-spawn@[^\n]*:[\s\S]*?\n\s+version:?\s+"?(\d+\.\d+\.\d+)"?/],
200
+ ] as const) {
201
+ const fp = join(targetRoot, file)
202
+ if (!existsSync(fp)) continue
203
+ try {
204
+ const m = readFileSync(fp, 'utf8').match(re)
205
+ if (m?.[1] && semver.valid(m[1])) return m[1]
206
+ } catch {
207
+ /* best-effort */
208
+ }
209
+ }
210
+ return null
211
+ }
212
+
213
+ /**
214
+ * 기존 cross-spawn이 보안 하한 미만인지 판정(#1). 우선순위: **설치버전 → lockfile 해소버전 → range**.
215
+ * range fallback은 `>=floor`로 절대 해소 불가한 spec만 below로 본다(‘^7.0.0’·‘~7.0.1’ 오탐 방지 — R1 P2).
216
+ * 기존 cross-spawn 없으면 null(우리가 `^7.0.6` 주입 → 진단 불필요).
217
+ */
218
+ export function crossSpawnBelowFloor(
219
+ targetRoot: string,
220
+ pkg: Record<string, unknown>,
221
+ ): { below: boolean; detail: string } | null {
222
+ if (!CROSS_SPAWN_FLOOR) return null // 이론상 도달 불가(REQ_DEV_DEPS 고정값)
223
+ const floor = CROSS_SPAWN_FLOOR.version
224
+ const spec = existingCrossSpawnSpec(pkg)
225
+ if (!spec) return null
226
+
227
+ const installed = installedCrossSpawnVersion(targetRoot)
228
+ if (installed) return { below: semver.lt(installed, floor), detail: `설치버전 ${installed}` }
229
+
230
+ const locked = lockedCrossSpawnVersion(targetRoot)
231
+ if (locked) return { below: semver.lt(locked, floor), detail: `lockfile ${locked}` }
232
+
233
+ if (semver.validRange(spec)) return { below: !semver.intersects(spec, `>=${floor}`), detail: `범위 ${spec}` }
234
+ return { below: false, detail: `범위 ${spec}(파싱 불가 — 무경고)` }
235
+ }
236
+
145
237
  /**
146
238
  * 설치 코어. IO는 여기서만(테스트가 임시 repo로 직접 호출).
147
239
  * **Preflight(전 검증·파싱) → Apply(쓰기) 2단계** — malformed 입력에 대해 어떤 파일도 복사·수정하기 전에 실패한다(부분 설치 방지, design R2 P2).
@@ -161,11 +253,23 @@ export function runInit(opts: InitOptions): InitResult {
161
253
  scripts?: Record<string, string>
162
254
  devDependencies?: Record<string, string>
163
255
  }
164
- // scripts·devDependencies가 존재하면 반드시 plain object — 배열/원시면 patch 조용히 유실되어(성공 보고인데 req:* 미주입) fail-closed 위반(phase R1 P2).
165
- for (const field of ['scripts', 'devDependencies'] as const) {
256
+ // scripts·devDependencies·dependencies가 존재하면 반드시 plain object — 배열/원시면 patch 유실(scripts/devDeps, phase R1 P2)
257
+ // 또는 cross-spawn 진단(dependencies, design R1 P3) 오동작. 읽기 전에 shape 검증(fail-closed).
258
+ for (const field of ['scripts', 'devDependencies', 'dependencies'] as const) {
166
259
  const v = (pkg as Record<string, unknown>)[field]
167
260
  if (v !== undefined && (typeof v !== 'object' || v === null || Array.isArray(v)))
168
- throw new Error(`package.json의 ${field} 필드가 객체가 아님(${pkgPath}) — req:* 주입 불가(배열/원시 미지원).`)
261
+ throw new Error(`package.json의 ${field} 필드가 객체가 아님(${pkgPath}) — 배열/원시 미지원.`)
262
+ }
263
+
264
+ // cross-spawn 보안 하한 진단(#1): 기존 cross-spawn이 하한 미만이면 WARN(기본)/throw(--strict). preflight라 strict throw 시 부분 설치 없음.
265
+ let crossSpawnFloorWarned = false
266
+ const floorCheck = crossSpawnBelowFloor(targetRoot, pkg as Record<string, unknown>)
267
+ if (floorCheck?.below) {
268
+ const spec = CROSS_SPAWN_SPEC
269
+ const msg = `기존 cross-spawn(${floorCheck.detail})이 보안 하한 >=${CROSS_SPAWN_FLOOR?.version} 미만 — CommitGate 안전 경계(safeSpawnSync)는 ${spec} 검증분입니다. 'npm i -D cross-spawn@${spec}' 권장.`
270
+ if (opts.strict) throw new Error(`[--strict] ${msg}`)
271
+ console.warn(`⚠️ ${msg} (설치는 계속 — 강제 중단하려면 --strict)`)
272
+ crossSpawnFloorWarned = true
169
273
  }
170
274
 
171
275
  const cfgPath = join(targetRoot, 'req.config.json')
@@ -247,6 +351,7 @@ export function runInit(opts: InitOptions): InitResult {
247
351
  packageJsonAdded,
248
352
  agentsCreated,
249
353
  packageManager,
354
+ crossSpawnFloorWarned,
250
355
  dryRun: opts.dryRun,
251
356
  }
252
357
  }
@@ -255,6 +360,7 @@ export function parseArgs(argv: string[]): InitOptions {
255
360
  let dir = process.cwd()
256
361
  let force = false
257
362
  let dryRun = false
363
+ let strict = false
258
364
  for (let i = 0; i < argv.length; i++) {
259
365
  const a = argv[i]
260
366
  if (a === '--dir') {
@@ -266,6 +372,8 @@ export function parseArgs(argv: string[]): InitOptions {
266
372
  force = true
267
373
  } else if (a === '--dry-run') {
268
374
  dryRun = true
375
+ } else if (a === '--strict') {
376
+ strict = true
269
377
  } else if (a === '-h' || a === '--help') {
270
378
  printHelp()
271
379
  process.exit(0)
@@ -273,7 +381,7 @@ export function parseArgs(argv: string[]): InitOptions {
273
381
  throw new Error(`알 수 없는 인자: ${a}`)
274
382
  }
275
383
  }
276
- return { dir: resolve(dir), force, dryRun }
384
+ return { dir: resolve(dir), force, dryRun, strict }
277
385
  }
278
386
 
279
387
  function printHelp(): void {
@@ -286,6 +394,7 @@ function printHelp(): void {
286
394
  --dir <path> 대상 repo 루트(기본: 현재 디렉터리)
287
395
  --force 기존 kit 파일 덮어쓰기(기본: 스킵)
288
396
  --dry-run 변경 없이 수행 예정 목록만 출력
397
+ --strict 기존 cross-spawn이 보안 하한(>=7.0.6) 미만이면 경고 대신 중단(fail-closed)
289
398
  -h, --help 도움말
290
399
 
291
400
  설치 후:
@@ -315,6 +424,7 @@ export function main(argv: string[]): void {
315
424
  `${tag} package.json: ${r.packageJsonAdded.length > 0 ? '추가 ' + r.packageJsonAdded.join(', ') : '변경 없음'}`,
316
425
  )
317
426
  console.log(`${tag} AGENTS.md: ${r.agentsCreated ? '템플릿 생성' : '이미 존재(유지)'}`)
427
+ if (r.crossSpawnFloorWarned) console.log(`${tag} ⚠️ cross-spawn 버전 하한 경고(위 참조) — 강제 중단은 --strict`)
318
428
  if (!r.dryRun) {
319
429
  console.log(`\n다음:`)
320
430
  console.log(` 1. cd ${r.targetRoot} && ${r.packageManager} install`)
package/package.json CHANGED
@@ -1,63 +1,66 @@
1
- {
2
- "name": "commitgate",
3
- "version": "0.1.1",
4
- "description": "CommitGate — Builder↔Reviewer(Claude↔Codex) fail-closed 커밋 게이트: 리뷰·승인·증거 없인 커밋을 통과시키지 않는 AI REQ 워크플로 kit (req:new/review-codex/doctor/commit)",
5
- "type": "module",
6
- "license": "MIT",
7
- "author": "sol5288",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/sol5288/commitgate.git"
11
- },
12
- "homepage": "https://github.com/sol5288/commitgate#readme",
13
- "bugs": {
14
- "url": "https://github.com/sol5288/commitgate/issues"
15
- },
16
- "keywords": [
17
- "ai",
18
- "code-review",
19
- "workflow",
20
- "codex",
21
- "claude",
22
- "git",
23
- "commit-gate",
24
- "fail-closed",
25
- "review-gate",
26
- "cli"
27
- ],
28
- "bin": {
29
- "commitgate": "bin/commitgate.mjs"
30
- },
31
- "scripts": {
32
- "req:new": "tsx scripts/req/req-new.ts",
33
- "req:review-codex": "tsx scripts/req/review-codex.ts",
34
- "req:doctor": "tsx scripts/req/req-doctor.ts",
35
- "req:commit": "tsx scripts/req/req-commit.ts",
36
- "test": "vitest run",
37
- "typecheck": "tsc --noEmit"
38
- },
39
- "files": [
40
- "scripts",
41
- "workflow/machine.schema.json",
42
- "workflow/req.config.schema.json",
43
- "bin",
44
- "AGENTS.template.md",
45
- "req.config.json.sample",
46
- "README.md",
47
- "README.en.md"
48
- ],
49
- "engines": {
50
- "node": ">=18.17"
51
- },
52
- "dependencies": {
53
- "ajv": "^8.20.0",
54
- "cross-spawn": "^7.0.6",
55
- "tsx": "^4.19.1"
56
- },
57
- "devDependencies": {
58
- "@types/cross-spawn": "^6.0.6",
59
- "@types/node": "^22.7.4",
60
- "typescript": "^5.6.2",
61
- "vitest": "^2.1.2"
62
- }
63
- }
1
+ {
2
+ "name": "commitgate",
3
+ "version": "0.2.0",
4
+ "description": "CommitGate — Builder↔Reviewer(Claude↔Codex) fail-closed 커밋 게이트: 리뷰·승인·증거 없인 커밋을 통과시키지 않는 AI REQ 워크플로 kit (req:new/review-codex/doctor/commit)",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "sol5288",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sol5288/commitgate.git"
11
+ },
12
+ "homepage": "https://github.com/sol5288/commitgate#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/sol5288/commitgate/issues"
15
+ },
16
+ "keywords": [
17
+ "ai",
18
+ "code-review",
19
+ "workflow",
20
+ "codex",
21
+ "claude",
22
+ "git",
23
+ "commit-gate",
24
+ "fail-closed",
25
+ "review-gate",
26
+ "cli"
27
+ ],
28
+ "bin": {
29
+ "commitgate": "bin/commitgate.mjs"
30
+ },
31
+ "scripts": {
32
+ "req:new": "tsx scripts/req/req-new.ts",
33
+ "req:review-codex": "tsx scripts/req/review-codex.ts",
34
+ "req:doctor": "tsx scripts/req/req-doctor.ts",
35
+ "req:commit": "tsx scripts/req/req-commit.ts",
36
+ "test": "vitest run",
37
+ "typecheck": "tsc --noEmit",
38
+ "smoke": "node scripts/smoke.mjs"
39
+ },
40
+ "files": [
41
+ "scripts/req",
42
+ "workflow/machine.schema.json",
43
+ "workflow/req.config.schema.json",
44
+ "bin",
45
+ "AGENTS.template.md",
46
+ "req.config.json.sample",
47
+ "README.md",
48
+ "README.en.md"
49
+ ],
50
+ "engines": {
51
+ "node": ">=18.17"
52
+ },
53
+ "dependencies": {
54
+ "ajv": "^8.20.0",
55
+ "cross-spawn": "^7.0.6",
56
+ "semver": "^7.6.3",
57
+ "tsx": "^4.19.1"
58
+ },
59
+ "devDependencies": {
60
+ "@types/cross-spawn": "^6.0.6",
61
+ "@types/node": "^22.7.4",
62
+ "@types/semver": "^7.5.8",
63
+ "typescript": "^5.6.2",
64
+ "vitest": "^2.1.2"
65
+ }
66
+ }