--- name: dev-bounce description: 코드를 고치거나 새로 짜는 작업을 단계별 워크플로우로 진행한다. 버그 수정, 기능 구현, 리팩터링, 설정·의존성 변경, "이거 고쳐줘" / "이 기능 추가해줘" / "왜 안 되는지 보고 고쳐봐" 같은 요청에 파일을 건드리기 전 반드시 먼저 호출할 것. 계획 승인·검증 통과·커밋을 엔진이 강제하는데, 이 스킬로 작업을 시작해야만 그 강제가 걸린다 — 스킬 없이 바로 Edit/Write하면 아무 규칙도 적용되지 않은 채 진행된다. 질문·설명·코드 읽기만 하는 요청에는 쓰지 않는다. --- # dev-bounce 작업을 **스테이지 체인**으로 진행한다. 각 단계에서 무엇을 하고 무엇이 금지되는지는 프로젝트의 `workflow.yaml`에 정의돼 있고, 엔진이 단계마다 지시를 주입한다. 이 문서에 워크플로우 내용은 없다. **시작 절차만 있다.** 시작한 뒤에는 주입되는 지시를 따르면 된다. ## 물어야 하는데 물을 수단이 없을 때 이 문서는 몇 군데에서 AskUserQuestion으로 사용자에게 물으라고 한다. 그 도구가 없는 컨텍스트도 있다(서브에이전트, 위임 실행 등). 그럴 때는 **추측해서 진행하지 말고 멈춘다.** 선택지를 텍스트로 그대로 제시하고 사용자 답을 기다린다. 도구가 없다는 건 "알아서 하라"는 뜻이 아니다. 물어야 하는 것들은 전부 **사용자만 답할 수 있는 것**이기 때문이다 — 어느 모드로 갈지, 남의 작업과 병렬로 갈지, 이 규칙을 앞으로도 적용할지. 문구가 명확해 보여도(예: "앞으로 항상") 추측으로 진행하면 사용자가 원한 적 없는 영구 변경이 남는다. 되돌리는 비용이 묻는 비용보다 훨씬 크다. ### plan mode를 쓸 수 없는 세션 `blocking: plan_approved`는 **ExitPlanMode가 실제로 승인된 것**만 인정한다. 그런데 비대화 세션(`claude -p` 등)에는 `EnterPlanMode` / `ExitPlanMode`가 아예 없다. 그 세션에서 `plan` 워크플로우를 시작하면 **충족할 방법이 없는 조건에 갇힌다.** 도구가 없다는 걸 확인했으면 조용히 멈춰 있지 말고 **막힌 이유와 빠져나갈 길을 알려라**: - `plan` 대신 `simple` 워크플로우로 시작한다 (계획 단계가 없다), 또는 - 대화형 세션에서 다시 실행한다 승인을 위조하거나 `bouncer done`으로 우회하지 않는다 — 그러면 게이트가 있으나 마나다. 아직 시작하지 않았다면 `bouncer start`를 하지 말고, 이미 시작했다면 `bouncer cancel`로 정리한 뒤 안내한다. 갇힌 작업을 그대로 두면 다음 세션까지 잠금이 남는다. --- ## Step 1 — 상태 확인 ```bash bouncer scan ``` 항상 부른다. 0.01초짜리고, 세션 시작 때 주입된 정보는 그 사이 다른 세션이 작업을 시작했으면 이미 낡았을 수 있다. ``` STATE MINE <경로> <워크플로우> <단계> 이 세션이 이어서 할 작업 STATE OTHER <경로> <단계> <나이> 다른 세션이 잡고 있는 작업 STATE NONE 아무것도 없음 ORPHAN <워크플로우> <단계> 잠금이 풀린 미완 작업 (이어받을 수 있다) ERROR <메시지> 설정을 읽을 수 없다 — 사용자에게 그대로 알린다 WORKFLOW <이름> <설명> 모드 선택지 OPTION <워크플로우> <단계> <이름> 시작할 때 물어볼 선택 항목 ``` | 결과 | 다음 | |---|---| | `MINE` | 이미 진행 중이다. 요청이 그 작업의 연장이면 `bouncer status`로 남은 조건을 보고 이어서 한다. Step 2~4는 건너뛴다 | | `OTHER`만 있음 | 다른 세션이 작업 중이다. Step 2로 가되 Step 4에서 병렬 여부를 묻는다. 그 세션이 죽은 것 같으면 `bouncer release`로 누가 잡고 있는지 보여주고 회수 여부를 **사용자에게 묻는다** | | `ORPHAN` 줄이 있음 | 잠금이 풀린 미완 작업이다 (세션이 죽었거나 회수됨). 요청이 그 작업의 연장인지 **사용자에게 확인하고**, 맞으면 `bouncer resume ` 로 이어받는다 | | `NONE` | Step 2 | **`bouncer: command not found`가 나오면** 두 가지 경우다. 먼저 구분해라: - `.claude/ai-bouncer/engine/bouncer.sh` 가 **있다** → 설치는 됐고 `~/.local/bin` 이 PATH에 없는 것뿐이다. 그 경로로 직접 부르고, 사용자에게 PATH 추가를 알린다. - **없다** → 이 프로젝트에 설치되지 않았다. 스킬을 쓰지 말고 사용자에게 알린 뒤 평소대로 작업한다. 설치를 임의로 진행하지 않는다. 설치돼 있는데 "설치 안 됨"으로 오진하면 워크플로우 없이 작업하게 된다. ## Step 2 — 요청이 개발 작업인지 판별 | 요청 성격 | 처리 | |---|---| | 질문·설명·코드 읽기 | 스킬을 쓰지 않고 그냥 답한다 | | 계획을 세우려면 탐색이 먼저 필요 | 읽기 전용으로 탐색한다(수정 금지). 끝나면 **Step 1부터 다시 시작**한다 | | 개발 의도는 있으나 무엇을 고칠지 불명확 | AskUserQuestion으로 구체화한다. "개발 작업으로 처리할까요?" 같은 확인 질문은 답이 뻔해서 사용자 시간만 쓴다 | | 개발 요청 | Step 3 | ## Step 3 — 모드와 옵션을 사용자에게 묻는다 Step 1의 `WORKFLOW` 줄을 그대로 AskUserQuestion 선택지로 만든다. 모드가 정해지면 그 모드의 `OPTION` 줄들을 스테이지별로 묶어 다시 묻는다 (multiSelect, 기본 전체 켜짐). 선택지가 4개를 넘으면 질문을 나눠서 여러 번 호출한다. `OPTION`이 없으면 이 질문은 건너뛴다. 모드는 사용자가 고른다. 계획 단계가 번거롭다는 이유로 가벼운 모드를 대신 고르면 사용자는 자기가 원한 검증이 빠진 줄 모른 채 결과를 받는다. 그건 워크플로우 회피다. AskUserQuestion을 쓸 수 없으면 위 "물어야 하는데 물을 수단이 없을 때"를 따른다. ## Step 4 — 시작 ```bash bouncer start <모드> "<슬러그>" [--off <끈-항목-id>] ... ``` 슬러그는 **영문 소문자와 하이픈**으로 짧게 쓴다 (`payment-bug`, `add-oauth`). 디렉토리 이름이 되므로 한글이나 공백을 쓰면 도구에 따라 정렬·경로 처리가 어긋난다. Step 1에 `OTHER`가 있었으면 그냥 `start`하면 거부된다. 사용자에게 먼저 묻는다: | 선택 | 처리 | |---|---| | 병렬로 진행 | `bouncer start <모드> "<슬러그>" --parallel`
별도 브랜치와 레포 밖 worktree가 만들어지고 base 브랜치가 이 시점에 기록된다.
**출력에 나온 worktree 경로로 먼저 `cd` 하고, 이후 편집·검증·커밋을 전부 거기서 한다.** 메인 레포를 고치면 엔진이 막는다 — 검증이 손대지 않은 트리를 보게 되기 때문이다.
끝나면 `bouncer worktree finalize`로 base에 FF 머지된다 | | 기존 작업 이어하기 | 그 세션의 작업이므로 건드리지 않는다. 해당 세션에서 계속하라고 안내한다 | ## Step 5 — 이후 엔진이 단계마다 지시를 주입한다. 그 지시를 따른다. - 응답을 끝내려 할 때 조건이 안 맞으면 엔진이 사유를 알려주고 계속 진행시킨다 - 조건이 다 맞으면 자동으로 다음 단계로 넘어간다 - 단계는 스스로 넘길 수 없다. `state.json` 수정은 차단된다 --- ## 막혔을 때 **hook이 차단했을 때** — 차단 사유에 무엇이 필요한지 적혀 있다. 그 조건을 충족시킨다. 우회로를 찾지 마라. 차단은 지금 그 행동이 이 단계에서 안전하지 않다는 뜻이고, 우회하면 사용자가 원한 검증이 빠진 채로 결과가 나간다. 단, **plan 단계에서 계획 작성 자체가 막혔다면** 묻지 말고 스스로 복구한다: `bouncer cancel` → 막혔던 준비 작업 → `bouncer start <같은 모드> "<같은 슬러그>"` → ExitPlanMode. **`bouncer run`이 계속 실패할 때** — 출력을 읽고 원인을 고친 뒤 다시 실행한다. 같은 실패가 반복되면 접근이 틀린 것이다. 같은 수정을 반복하지 말고 다른 원인을 찾거나, 사용자에게 상황과 막힌 지점을 보고한다. 설정된 횟수를 넘기면 엔진이 알아서 사용자에게 판단을 넘긴다. **작업을 접어야 할 때** — `bouncer cancel`로 정리한다. `.active`를 직접 지우면 상태가 어긋난 채로 남는다. --- ## 사용자가 "앞으로 항상 ~해라"라고 할 때 이번 작업 한정인지 앞으로 계속인지 먼저 구분한다. 잘못 판단하면 한 번짜리 요청이 영구 규칙이 되거나, 반복될 규칙이 매번 잊힌다. | 사용자 말 | 해석 | 처리 | |---|---|---| | "이번엔 e2e까지 돌려" | 이번만 | 그냥 한다. yaml은 건드리지 않는다 | | "작업 끝나면 CHANGELOG도 갱신해" | 애매 | 물어본다 | | "앞으로 커밋 전엔 항상 린트 돌려" | 계속 | 물어본다 | 애매하거나 반복될 성격이면 AskUserQuestion으로 확인한다. 도구가 없으면 아래 선택지를 텍스트로 제시하고 답을 기다린다 — 문구가 명확해 보여도 확인 없이 `workflow.yaml`을 고치지 않는다. 그건 사용자가 요청한 적 없는 영구 변경이다. ``` ❓ 이걸 워크플로우에 넣을까요? ○ 이번 작업만 — 지금 한 번만 수행 ○ 워크플로우에 추가 — 앞으로 모든 작업에 적용 (workflow.yaml 수정) ``` "워크플로우에 추가"를 고르면: 1. 어느 단계에 넣을지 정한다: - "작업 끝나면 ~" → `finalize` 앞 (커밋 전에 끝내야 할 정리) - "커밋 전에 ~" → `finalize`의 첫 step - "구현하면서 ~" → `implement` / "검증할 때 ~" → `verify` - 성격이 뚜렷이 다른 묶음이면 새 스테이지로 만들고 체인 배열에 끼워넣는다 2. 자동 검증이 가능하면 `run`, 사람 판단이 필요하면 `inject`로 쓴다. 강제할 것이면 `blocking: true`, 매번 물어볼 성격이면 `optional: true` 3. 추가할 yaml을 사용자에게 그대로 보여주고 **승인을 받는다** 4. **지금 고치지 않는다.** 진행 중에는 엔진이 설정 파일 수정을 막는다 — 이번 작업의 규칙은 시작 시점에 고정돼 있고, 고쳐도 다음 세션부터 적용되므로 중간에 바꾸면 "무슨 규칙으로 검증했는지"가 흐려진다. 승인받은 yaml을 기억해뒀다가, 이번 작업이 `done`으로 끝난 뒤에 적용한다. 5. 작업 종료 후 Edit 도구로 `.claude/ai-bouncer/workflow.yaml`을 수정한다 6. `bouncer check`로 검증한다. 실패하면 되돌린다 7. 다음 세션부터 적용된다고 알린다 `forbid`를 약화시키는 방향(차단 해제)은 사용자가 명시적으로 요구할 때만 한다. 게이트가 귀찮다는 이유로 규칙을 무르면 그 규칙을 만든 이유가 사라진다. --- ## 명령 | 명령 | 용도 | |---|---| | `bouncer scan` | 상태·모드·선택항목 (시작 전 1회) | | `bouncer start <모드> "<슬러그>"` | 작업 시작 | | `bouncer todo` | 할 일 목록 보기 (plan 모드면 승인된 계획에서 자동으로 채워진다) | | `bouncer todo add '<항목>' …` | 요청 범위를 목록으로 세운다 (checklist 게이트가 이걸 센다) | | `bouncer todo done ` | 그 항목을 **실제로 구현한 뒤** 체크 | | `bouncer todo drop ` | 범위에서 뺀다 (기록에 남으니 사유를 사용자에게 알린다) | | `bouncer status` | 현재 단계와 남은 조건 (각 step의 `id:` 도 함께 나온다) | | `bouncer run ` | 검증 명령 실행 후 결과 기록. 명령 문자열은 엔진이 소유한다 | | `bouncer done ` | 할 일을 마친 step 완료 표시 (사람 확인은 없다) | | `bouncer cancel` | 작업 취소 | | `bouncer skip ` | 엔진이 포기한 조건을 이번 작업에서만 건너뛴다 (사용자가 요청할 때만) | | `bouncer release [--force]` | 죽은 세션이 남긴 잠금 확인 / 회수 | | `bouncer resume` | 이어받을 수 있는 미완 작업 목록 (인자 없으면 조회) | | `bouncer resume ` | 그 작업을 이어받는다 (`scan`의 `ORPHAN` 줄) | | `bouncer workflows` | 정의된 모드 목록 | | `bouncer worktree finalize` | 병렬 작업을 base로 FF 머지하고 정리 | | `bouncer check` | `workflow.yaml`을 고친 뒤 유효한지 검사 | ## 하지 말 것 - 모드를 사용자 대신 고르기 - 물을 수단이 없다는 이유로 사용자 몫의 결정을 대신 내리기 - `state.json` / `.active` / `workflow.compiled.json` 직접 수정 - 작업 진행 중에 `workflow.yaml` 고치기 (엔진이 막는다 — 끝난 뒤에 한다) - 사용자가 요청하지 않았는데 `bouncer skip` / `bouncer release --force` 쓰기 - 검증 명령을 직접 타이핑해 실행하고 "통과했다"고 보고하기 → `bouncer run`으로 해야 결과가 증거로 남는다. 직접 실행한 것은 기록되지 않아 엔진이 계속 미충족으로 판정한다 - 실패한 것을 통과로 보고하기 - 완료 후 사용자 지시 없이 새 작업 시작하기