From my-harness
코드 리뷰 결과의 finding을 하나씩 유저와 같이 점검하고 해결하는 대화형 스킬. 각 항목에 대해 발생 원인/이슈인 이유/해결 방안 예시를 설명하고, 작업 진행/패스/보류 상태를 저장하여 다음 실행 시 중복 작업을 방지한다.
npx claudepluginhub pokuding/my-harness --plugin my-harnessThis skill uses the workspace's default tool permissions.
`/code-review` 결과 JSON의 각 finding을 **한 번에 하나씩** 유저와 같이 점검한다. 각 항목에 대해 자세히 설명하고, 유저의 판단에 따라 작업/패스/보류를 기록한다. 다음 실행 시 이미 처리된 항목은 건너뛴다.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
/code-review 결과 JSON의 각 finding을 한 번에 하나씩 유저와 같이 점검한다. 각 항목에 대해 자세히 설명하고, 유저의 판단에 따라 작업/패스/보류를 기록한다. 다음 실행 시 이미 처리된 항목은 건너뛴다.
이 스킬의 결정 지점은 모두 AskUserQuestion 도구로 받는다 — 텍스트 파싱([w]/[p]/...)이 아닌 구조화된 선택지 UI. 각 지점의 구체 옵션은 아래 Step별 명세 참조.
규칙:
(Recommended) 추가description으로 각 옵션의 구체 결과·트레이드오프 설명header는 12자 이내 짧은 라벨preview 필드에 fenced code block으로 넣음 (side-by-side 렌더)Opus 메인 세션 = 리뷰·설명·승인 / Sonnet 워커(cr-walk-worker) = 실행·검증·커밋
[w] 작업 선택 후 수정안 승인되면 즉시 cr-walk-worker 에이전트를 run_in_background: true로 spawn하고 메인은 다음 finding으로 바로 이동한다. 유저는 워커의 Edit·typecheck·commit 완료를 기다리지 않는다.
파일 겹침 처리: 실행 중 워커들의 files_changed를 추적. 새 finding의 수정 파일이 겹치면 직렬화 (겹친 워커 완료 대기 후 spawn).
세션 종료 시: pending 워커 완료 대기 → 결과 집계 → state 최종 반영 → 백로그 resolve 처리.
실패 처리: 워커가 edit/typecheck/commit 중 실패해도 다음 finding 워커에 영향 없음. 각 워커는 독립적으로 결과 JSON 반환. 세션 종료 요약에서 실패 건 수동 처리 안내.
/code-review-walk # 최근 리뷰부터 시작 (처리된 항목 제외)
/code-review-walk .harness/reviews/20260410_... # 특정 리뷰 지정
/code-review-walk --include-deferred # 보류 항목도 다시 포함
/code-review-walk --filter critical,major # 특정 severity만
/code-review-walk --category security # 특정 category만
/code-review-walk --status # 진행 현황만 표시하고 종료
/code-review-walk --reset # state 파일 삭제 후 처음부터
*-review.json 파일 Read.harness/reviews/*/ 하위에서 가장 최근 *-review.json 자동 탐지
ls -t .harness/reviews/*/*-review.json | head -1
리뷰 결과를 찾을 수 없습니다. 먼저 /code-review를 실행하세요.
리뷰 파일 경로에서 폴더와 prefix를 추출:
review_dir = dirname(review_json_path) # .harness/reviews/{TS}-{SUM}/
prefix = basename(review_json_path, "-review.json") # {TS}-{SUM}
State 파일 경로: {review_dir}/{prefix}-walk.json
예: .harness/reviews/20260420_143022-payment-integration/20260420_143022-payment-integration-walk.json
--reset 플래그 → 기존 state 삭제 후 신규 생성
--status 플래그 → 현재 state 요약만 표시하고 종료 (Step 6)
다음 조건으로 대상 findings 선정:
status가 done, passed, deferred인 항목--include-deferred → deferred 포함--filter severity → 지정 severity만 (critical/major/minor/nit)--category → 지정 category만진행 중 항목이 있으면 먼저 처리:
in_progress — Opus 리뷰 중 중단. 대화 재개 필요.in_progress_bg — 워커 spawn까지 완료, 결과 미반영. 워커가 여전히 실행 중일 수 있으므로 먼저 결과 수집 시도:
worker_name으로 해당 워커 완료 여부 확인 (가능하면 반환 JSON Read)done / bg_failed)로 갱신bg_failed — 워커가 typecheck/commit에서 실패. Step 4 메인 루프에서 자동 포함되며 "재시도 / 수동 해결 / 패스" 선택 제시.AskUserQuestion으로 재개 여부 확인:
AskUserQuestion({
questions: [{
question: "이전 세션의 중단 항목이 있습니다. 어떻게 처리할까요?",
header: "Resume",
options: [
{ label: "재개 (Recommended)",
description: "중단된 지점부터 계속 진행" },
{ label: "이번 세션은 skip",
description: "미완료 항목은 건너뛰고 새 finding부터 시작" },
{ label: "state 리셋",
description: "--reset 효과, 처음부터 다시" }
],
multiSelect: false
}]
})
처리할 findings 수를 보여준다:
## Code Review Walk
### 대상 리뷰
- 리뷰 파일: 20260410_143022-review.json
- 전체 findings: 15건
- 이미 처리됨: 5건 (done: 3, passed: 1, deferred: 1)
- 이번 세션 대상: 10건
### 대상 분포
| Severity | 건수 |
|----------|------|
| Critical | 1 |
| Major | 4 |
| Minor | 4 |
| Nit | 1 |
위 요약을 보여준 후 AskUserQuestion으로 시작 여부를 묻는다:
AskUserQuestion({
questions: [{
question: "N건의 finding을 순차 점검합니다. 시작할까요?",
header: "Walk 시작",
options: [
{ label: "시작 (Recommended)",
description: "첫 finding부터 순서대로 점검 시작" },
{ label: "취소",
description: "세션을 종료합니다. state 변경 없음." }
],
multiSelect: false
}]
})
사용자가 "취소" 선택 시 스킬 종료.
severity 순(Critical → Major → Minor → Nit)으로 하나씩 표시한다.
각 finding에 대해:
설명 출력 직전에 다음을 수집하여 더 풍부한 설명을 만든다:
file, lines, symbol에 해당하는 코드와 주변 맥락 5-10줄복잡하거나 맥락 파악이 어려운 Critical/Major finding에는 필요 시 my-harness:researcher 에이전트로 1-2분 심층 분석 위탁.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[3/10] CR-005 · 🔴 Critical · reliability
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
**제목:** 외부 API 호출에 timeout 미설정
**파일:** src/integrations/payment.ts:45-52 (symbol: charge)
**Detected by:** my-harness:cr-reliability (consensus: 양쪽 supervisor 일치)
## 📌 배경
이 코드는 결제 게이트웨이(Stripe 추정)와 통신하는 외부 HTTP 호출부다.
Node.js 기본 fetch는 timeout 기본값이 없어 네트워크 지연이나 상대 서비스
장애 시 응답을 무한 대기한다. Node 18+부터 `AbortController`로 제어하거나
`undici`의 `bodyTimeout`/`headersTimeout`을 사용하는 것이 권장된다.
같은 레포 내 `src/integrations/slack.ts`에서는 이미 AbortController로
7초 timeout을 적용하고 있음. 패턴 불일치 상태.
## 🔍 발생 원인
fetch 호출에 timeout이나 AbortController가 설정되지 않아 응답이 오지 않을 때
무한 대기 상태가 됨.
```typescript
// 문제 코드 (src/integrations/payment.ts:45-52)
const res = await fetch(url, { method: 'POST', body });
결제 게이트웨이 장애 시 요청 워커가 모두 이 호출에 묶임. 시간이 지날수록 사용 가능한 워커가 고갈되어 서비스 전체가 응답 불가 상태로 전파됨.
미해결 시 영향
// After
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), 5000);
try {
const res = await fetch(url, { method: 'POST', body, signal: ctrl.signal });
// ...
} finally {
clearTimeout(timer);
}
또는 기존 src/integrations/slack.ts와 동일한 유틸 함수로 추출해서
재사용 가능.
src/integrations/slack.ts:28 — 동일 패턴 이미 적용됨 (참고)src/integrations/payment.ts:78 — 같은 파일의 다른 호출도 동일 이슈 가능성Scope: fix_now (이 PR에서 수정 권장)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
### 필드 매핑 및 보강 기준
| 섹션 | 출처 |
|------|------|
| **📌 배경** | 관련 파일 Read + 연관 패턴 Grep + 일반적 도메인 지식으로 합성 |
| **🔍 발생 원인** | `problem` + 실제 코드 스니펫 (가능한 경우) |
| **⚠️ 이슈인 이유** | `why` + 발생 가능성/심각도/복구 비용 분해 |
| **💥 미해결 시 영향** | `impact`를 가능성·심각도·관측성 관점으로 분해 |
| **💡 해결 방안** | `recommendation` + before/after 코드 블록 |
| **✅ 수정 시 장점** | 카테고리 기반 템플릿 + finding 맥락으로 합성 |
| **⚠️ 수정 시 고려사항** | 아래 카테고리별 트레이드오프 템플릿 + 실제 코드 맥락 |
| **🔗 연관 코드** | Grep 결과 중 관련성 높은 3-5개 |
### 카테고리별 트레이드오프 템플릿
| Category | 일반 장점 | 일반 고려사항 |
|----------|----------|---------------|
| **correctness** | 의도한 동작 보장, 회귀 방지 | 기존 동작에 의존하던 호출부 확인 |
| **reliability** | 장애 격리, 관측 가능성 ↑ | 타임아웃 값 선정, 재시도 조합, 멱등성 |
| **security** | 공격 벡터 차단 | 합법 사용자 플로우 영향 여부, 성능 trade-off |
| **performance** | 응답 시간 단축, 리소스 절약 | 읽기 난이도 상승 가능, 캐시 무효화 로직 필요 |
| **maintainability** | 변경 용이성, 테스트 가능성 ↑ | 단기 리팩토링 비용, 리뷰 범위 확대 |
**주의:** 템플릿은 시작점일 뿐. 반드시 해당 finding의 **구체적 맥락**(어느 파일, 어느 호출부, 어떤 레포 패턴)을 녹여 합성한다. 일반론만 나열하면 유용성이 떨어진다.
#### 4-3. 유저 액션 선택
**AskUserQuestion**으로 4개 옵션 제시:
AskUserQuestion({ questions: [{ question: "<FINDING_ID>: <finding.title> — 어떻게 처리할까요?", header: "Walk action", options: [ { label: "작업 진행 (Recommended)", description: "함께 코드 수정. 에이전트가 초안을 제시하고 같이 다듬음. 수정 후 자동 커밋 옵션 제공" }, { label: "패스", description: "실제 문제 아니라고 판단. 다음 실행 시 제외 (사유는 다음 단계에서 입력)" }, { label: "보류", description: "당장은 넘기고 나중에 재검토. 중앙 백로그에도 push되어 추적됨. --include-deferred 없이는 다음 walk 실행 제외" }, { label: "건너뛰기", description: "이번 세션만 넘김. state 저장 안 되므로 다음 실행 시 다시 등장" } ], multiSelect: false }] })
**종료 `[q]` 처리:** AskUserQuestion 옵션에서 제외. 유저가 답변 대신 "그만", "종료", "나중에 이어서" 같은 자연어로 응답하면 Claude가 포착 → Step 6 요약 후 종료. Ctrl+C도 동일.
사용자가 AskUserQuestion의 자동 "Other" 옵션으로 자유 텍스트 입력 시: Claude가 의도 해석 (예: "이건 보류"→보류 처리, "같이 고쳐"→작업 진행). 모호하면 재질문.
#### 4-4. 액션별 처리
**[w] 작업 진행 (v0.18+ 비동기 패턴):**
Opus 메인 세션은 **리뷰·맥락 설명·승인**까지만 담당한다. 승인 후 실제 수정·구문체크·커밋은 **Sonnet 워커(`cr-walk-worker`)를 background로 spawn**하여 전담시키고, 메인은 즉시 다음 finding으로 이동한다. 유저가 기다리지 않음.
##### 1. 사전 체크 (작업 트리)
첫 번째 [w] 호출 시 한 번만 확인 (이후 finding들은 이미 결정된 모드 재사용):
```bash
git status --porcelain
AskUserQuestion({
questions: [{
question: "작업 트리에 다른 변경이 있습니다. 어떻게 진행할까요?",
header: "Dirty tree",
options: [
{ label: "기존 변경 먼저 커밋 (Recommended)",
description: "기존 작업을 별도 커밋으로 정리한 뒤 finding 수정 진행",
preview: "```\n<git status --porcelain 출력>\n```" },
{ label: "stash 후 진행",
description: "git stash push로 보관. 세션 종료 시 stash pop 안내" },
{ label: "무시하고 진행",
description: "기존 변경 유지. 워커가 finding의 files_changed만 git add하므로 섞이지 않음" },
{ label: "중단",
description: "이 finding 작업 취소 → 다음으로 이동" }
],
multiSelect: false
}]
})
my-harness:researcher 에이전트로 영향 범위 파악 (동기 — Opus가 참고해야 할 맥락)AskUserQuestion({
questions: [{
question: "다음 수정을 백그라운드 워커에게 맡길까요?",
header: "Dispatch fix",
options: [
{ label: "백그라운드로 진행 (Recommended)",
description: "Sonnet 워커가 Edit·typecheck·commit을 자동 수행. 메인은 즉시 다음 finding으로 이동. 실패 시 walk 종료 시 요약에서 확인.",
preview: "```diff\n<수정 diff (before/after)>\n```" },
{ label: "다른 접근 제안 요청",
description: "이 방향 대신 대안을 제시받기. 이전 제안 폐기, 재승인 후 spawn." },
{ label: "수동 조정 후 재제시",
description: "사용자가 세부 조정 사항을 지시 → 수정안 재작성 후 재승인." },
{ label: "수정 중단",
description: "이 finding 작업 취소. state는 in_progress로 유지 → 다음 실행 시 재개." }
],
multiSelect: false
}]
})
파일 겹침 검사 — 이미 실행 중인 bg 워커들의 files_changed와 이번 finding의 수정 대상 파일을 비교:
Agent(
name: "cr-walk-worker-{FINDING_ID}",
subagent_type: "my-harness:cr-walk-worker",
model: "claude-sonnet-4-6",
run_in_background: true,
prompt: """
## Finding
{finding JSON 전체}
## Approved Fix
{승인된 diff 또는 before/after spec — Opus 메인이 Step 3에서 유저와 합의한 정확한 수정안}
## Commit Template
subject: {category_prefix}(review): {finding.id} {finding.title}
body: |
{action 요약 1-3줄}
Review: {review.json 절대 경로}
Finding: {finding.id} ({category}/{severity})
Files: {files_changed 쉼표 구분}
## Review Path
{review.json 절대 경로}
## Files Changed
{수정 대상 파일 목록}
## Typecheck Command
{프로젝트별 자동 감지, 명시 원하면 여기에}
"""
)
// state.findings["CR-005"] 업데이트 (bg 진행 중)
{
"status": "in_progress_bg",
"worker_name": "cr-walk-worker-CR-005",
"action": "AbortController + 5s timeout 추가",
"approved_fix_summary": "...",
"files_changed": ["src/integrations/payment.ts"],
"spawned_at": "<ISO8601>"
}
사용자에게 짧게 알림:
[bg] CR-005 수정 백그라운드 시작 (worker: cr-walk-worker-CR-005). 다음 finding으로 이동합니다.
Step 4 메인 루프로 복귀 → 다음 finding 표시.
중요: 메인 세션은 이 시점에 워커 완료를 기다리지 않음. 커밋 여부·typecheck 결과 모두 Step 6 요약에서 집계.
done → status: "done", commit 기록typecheck_failed / commit_failed / edit_failed → status: "bg_failed", error 기록# 성공한 finding들에 대해 backlog에서 대응 항목 자동 resolve
for finding_id in <done_findings>; do
python3 scripts/backlog_tool.py list --file "<file>" --json > /tmp/bl_search.json
BL_ID=$(python3 -c "import json; e=[x for x in json.load(open('/tmp/bl_search.json')) if x.get('symbol')=='<symbol>' and x.get('category')=='<category>']; print(e[0]['id'] if e else '')")
[[ -n "$BL_ID" ]] && python3 scripts/backlog_tool.py resolve "$BL_ID" --commit "<commit_sha>" --approach "<action_summary>"
done
fix(review): {FINDING_ID} {title}
{action 요약 1-3줄 — 무엇을 어떻게 바꿨는지}
Review: .harness/reviews/{review-ts}-review.json
Finding: {finding.id} ({category}/{severity})
Files: {file1}, {file2}, ...
subject prefix 매핑 (카테고리 → Conventional Commit 타입):
| Category | Prefix |
|---|---|
| correctness | fix |
| reliability | fix |
| security | fix (또는 security) |
| performance | perf |
| maintainability | refactor |
수정이 신규 기능을 동반하지 않고 리뷰 지적 해결에 국한되므로 대부분 fix 또는 refactor 계열.
[p] 패스:
{
"status": "passed",
"reason": "이 서비스는 내부 전용이며 외부 장애 영향 없음",
"timestamp": "..."
}
[d] 보류:
{
"status": "deferred",
"note": "Q2 리팩토링 플랜에 포함 예정",
"timestamp": "..."
}
.harness/review-backlog/backlog.json으로 흘러들어 여러 리뷰에 걸쳐 추적되도록:
python3 scripts/backlog_tool.py add-manual \
--file "<finding.file>" \
--title "<finding.title>" \
--severity "<finding.severity>" \
--category "<finding.category>" \
--problem "<finding.problem>" \
--recommendation "<finding.recommendation>" \
--symbol "<finding.symbol>" \
--lines "<finding.lines>" \
--note "<user_note>" \
--source-review "<review.json 절대 경로>"
dedup key가 이미 존재하면 occurrence_count만 증가 → 여러 번 보류된 이슈는 더 눈에 띄게 됨.
스크립트 실패 시 경고만 표시하고 walk는 계속 진행 (state는 저장됨).[s] 건너뛰기:
[q] 종료:
모든 대상 finding 순회가 끝났거나 유저가 종료를 요청하면:
Pending BG 확인: state에서 status == "in_progress_bg"인 모든 항목의 워커 완료 대기
사용자 안내: "[bg] N개 워커 완료 대기 중... (예상 1-2분)"
각 워커 결과 수집 + state 업데이트:
done → status: "done", commit 기록edit_failed / typecheck_failed / commit_failed → status: "bg_failed", error_detail 기록중앙 백로그 resolve (done만):
for finding in <done_findings>; do
python3 scripts/backlog_tool.py list --file "<file>" --json > /tmp/bl.json
BL_ID=$(python3 -c "import json; e=[x for x in json.load(open('/tmp/bl.json')) if x.get('symbol')=='<symbol>' and x.get('category')=='<category>']; print(e[0]['id'] if e else '')")
[[ -n "$BL_ID" ]] && python3 scripts/backlog_tool.py resolve "$BL_ID" --commit "<sha>" --approach "<summary>"
done
Step 6로 진행.
## Code Review Walk 세션 요약
### 이번 세션
- 점검: 8건
- 작업 완료 (bg): 4건 (모두 Sonnet 워커가 자동 커밋)
- 워커 실패: 1건 (→ 수동 개입 필요, 아래 참조)
- 패스: 2건
- 보류: 1건 (→ 중앙 백로그에도 push됨)
### 이번에 수정한 항목 (bg 워커 결과)
| ID | Severity | 제목 | 파일 | Commit | 상태 |
|----|----------|------|------|--------|------|
| CR-001 | Critical | SQL Injection | src/api/users.ts | abc1234 | ✅ done |
| CR-005 | Major | timeout 미설정 | src/integrations/payment.ts | def5678 | ✅ done |
| CR-007 | Minor | 네이밍 개선 | src/utils/fmt.ts | - | ⚠️ typecheck_failed |
### 워커 실패 상세
- **CR-007** typecheck_failed: `TS2322: Type 'string' is not assignable to type 'number'` — Edit 적용됨, 커밋 안 됨. 수동 수정 후 `git add src/utils/fmt.ts && git commit` 또는 `git checkout -- src/utils/fmt.ts`로 되돌림.
### 전체 진행 현황 (review 전체 기준)
- 전체: 15건
- 완료/패스: 8건 (53%)
- 보류: 3건 (20%)
- 미처리: 4건 (27%)
### 저장된 파일
- State: .harness/reviews/{review-ts}/{prefix}-walk.json
- 워커 로그: 각 bg 워커의 반환 JSON이 state.findings[id].worker_result에 저장됨
### 다음 단계
- `git log -5` 로 새 커밋 확인
- 워커 실패 항목 수동 처리
- 남은 finding 계속: `/code-review-walk`
- 보류 항목 재검토: `/code-review-walk --include-deferred`
- 백로그 현황: `/review-backlog`
.harness/reviews/{review-ts}-walk.json:
{
"metadata": {
"source_review": "20260410_143022-review.json",
"source_review_total": 15,
"first_walked_at": "2026-04-17T10:00:00",
"last_walked_at": "2026-04-17T14:30:00",
"walk_session_count": 2
},
"summary": {
"done": 4,
"passed": 2,
"deferred": 2,
"in_progress": 0,
"in_progress_bg": 0,
"bg_failed": 0,
"untouched": 7
},
"findings": {
"CR-001": {
"status": "done",
"action": "파라미터화 쿼리로 변경",
"files_changed": ["src/api/users.ts"],
"commit": "abc1234",
"worker_result": {
"worker_name": "cr-walk-worker-CR-001",
"typecheck_output": "ok",
"worker_start": "2026-04-17T10:15:00",
"worker_end": "2026-04-17T10:15:42"
},
"timestamp": "2026-04-17T10:15:00"
},
"CR-002": {
"status": "passed",
"reason": "스타일 선호 차이로 판단",
"timestamp": "2026-04-17T10:20:00"
},
"CR-003": {
"status": "deferred",
"note": "대규모 리팩토링 필요, 별도 이슈 등록 예정",
"timestamp": "2026-04-17T10:25:00"
},
"CR-007": {
"status": "bg_failed",
"action": "네이밍 개선",
"files_changed": ["src/utils/fmt.ts"],
"commit": null,
"worker_result": {
"worker_name": "cr-walk-worker-CR-007",
"failure_stage": "typecheck",
"error": "TS2322: Type 'string' is not assignable to type 'number'",
"worker_start": "...",
"worker_end": "..."
},
"timestamp": "..."
}
}
}
| status | 다음 실행 시 | 의미 |
|---|---|---|
done | 제외 | 워커가 Edit + typecheck + commit 모두 성공, SHA 기록 |
passed | 제외 | 문제 아니라고 판단, 수정 없이 종결 |
deferred | 제외 (기본) / 포함 (--include-deferred) | 당장은 넘기고 나중에 다시 볼 것. 중앙 백로그에도 push |
in_progress | 우선 재개 제안 | Opus 메인 리뷰 도중 유저가 [q] 종료로 승인 전 중단 |
in_progress_bg | 우선 재개 (pending worker 결과 수집) | 승인 완료되어 워커 spawn되었으나 결과 미확인 상태 |
bg_failed | 포함 (재시도 기본) | 워커가 edit/typecheck/commit 중 실패 — 유저가 수동 처리 필요 |
| (없음) | 포함 | 아직 점검하지 않음 |
[q], Ctrl-C, 에러 발생 모두 최신 state 저장 시도git add -- {files_changed}만, 절대 git add -A 금지 (다른 파일이 섞이지 않도록)done 마크 안 함, 다음 실행 시 재시도 가능.harness/code-review-walk.json (선택):
{
"default_severity_filter": ["critical", "major"],
"auto_typecheck_after_edit": true,
"show_code_snippet_context_lines": 5,
"auto_commit": true,
"commit_prefix_override": null,
"commit_require_approval": true
}
auto_commit: 수정 후 자동 커밋 활성화 (기본: true)commit_prefix_override: 카테고리 매핑 대신 고정 prefix 사용 (예: "fix")commit_require_approval: 커밋 전 유저 승인 요청 (기본: true, false면 바로 커밋)