코드를 고치거나 새로 짜는 작업을 단계별 워크플로우로 진행한다. 버그 수정, 기능 구현, 리팩터링, 설정·의존성 변경, "이거 고쳐줘" / "이 기능 추가해줘" / "왜 안 되는지 보고 고쳐봐" 같은 요청에 파일을 건드리기 전 반드시 먼저 호출할 것. 계획 승인·검증 통과·커밋을 엔진이 강제하는데, 이 스킬로 작업을 시작해야만 그 강제가 걸린다 — 스킬 없이 바로 Edit/Write하면 아무 규칙도 적용되지 않은 채 진행된다. 질문·설명·코드 읽기만 하는 요청에는 쓰지 않는다.
Installs into .claude/skills of the current project.
Are you the author of Dev Bounce?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/kangraemin-dev-bounce-ai-bouncer)
---
name: dev-bounce
description: 코드를 고치거나 새로 짜는 작업을 단계별 워크플로우로 진행한다. 버그 수정, 기능 구현, 리팩터링, 설정·의존성 변경, "이거 고쳐줘" / "이 기능 추가해줘" / "왜 안 되는지 보고 고쳐봐" 같은 요청에 파일을 건드리기 전 반드시 먼저 호출할 것. 계획 승인·검증 통과·커밋을 엔진이 강제하는데, 이 스킬로 작업을 시작해야만 그 강제가 걸린다 — 스킬 없이 바로 Edit/Write하면 아무 규칙도 적용되지 않은 채 진행된다. 질문·설명·코드 읽기만 하는 요청에는 쓰지 않는다.
---
# dev-bounce
작업을 **스테이지 체인**으로 진행한다. 각 단계에서 무엇을 하고 무엇이 금지되는지는
프로젝트의 `workflow.yaml`에 정의돼 있고, 엔진이 단계마다 지시를 주입한다.
이 문서에 워크플로우 내용은 없다. **시작 절차만 있다.**
시작한 뒤에는 주입되는 지시를 따르면 된다.
## 물어야 하는데 물을 수단이 없을 때
이 문서는 몇 군데에서 AskUserQuestion으로 사용자에게 물으라고 한다.
그 도구가 없는 컨텍스트도 있다(서브에이전트, 위임 실행 등).
그럴 때는 **추측해서 진행하지 말고 멈춘다.** 선택지를 텍스트로 그대로 제시하고
사용자 답을 기다린다. 도구가 없다는 건 "알아서 하라"는 뜻이 아니다.
물어야 하는 것들은 전부 **사용자만 답할 수 있는 것**이기 때문이다 —
어느 모드로 갈지, 남의 작업과 병렬로 갈지, 이 규칙을 앞으로도 적용할지.
문구가 명확해 보여도(예: "앞으로 항상") 추측으로 진행하면
사용자가 원한 적 없는 영구 변경이 남는다. 되돌리는 비용이 묻는 비용보다 훨씬 크다.
### plan mode를 쓸 수 없는 세션
`blocking: plan_approved`는 **ExitPlanMode가 실제로 승인된 것**만 인정한다.
그런데 비대화 세션(`Codex -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 <task-id> <워크플로우> <단계> 잠금이 풀린 미완 작업 (이어받을 수 있다)
ERROR <메시지> 설정을 읽을 수 없다 — 사용자에게 그대로 알린다
WORKFLOW <이름> <설명> 모드 선택지
OPTION <워크플로우> <단계> <id> <이름> 시작할 때 물어볼 선택 항목
```
| 결과 | 다음 |
|---|---|
| `MINE` | 이미 진행 중이다. 요청이 그 작업의 연장이면 `bouncer status`로 남은 조건을 보고 이어서 한다. Step 2~4는 건너뛴다 |
| `OTHER`만 있음 | 다른 세션이 작업 중이다. Step 2로 가되 Step 4에서 병렬 여부를 묻는다. 그 세션이 죽은 것 같으면 `bouncer release`로 누가 잡고 있는지 보여주고 회수 여부를 **사용자에게 묻는다** |
| `ORPHAN` 줄이 있음 | 잠금이 풀린 미완 작업이다 (세션이 죽었거나 회수됨). 요청이 그 작업의 연장인지 **사용자에게 확인하고**, 맞으면 `bouncer resume <task-id>` 로 이어받는다 |
| `NONE` | Step 2 |
**`bouncer: command not found`가 나오면** 두 가지 경우다. 먼저 구분해라:
- `.Codex/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`<br>별도 브랜치와 레포 밖 worktree가 만들어지고 base 브랜치가 이 시점에 기록된다.<br>**출력에 나온 worktree 경로로 먼저 `cd` 하고, 이후 편집·검증·커밋을 전부 거기서 한다.** 메인 레포를 고치면 엔진이 막는다 — 검증이 손대지 않은 트리를 보게 되기 때문이다.<br>끝나면 `bouncer worktree finalize`로 base에 FF 머지된다 |
| 기존 작업 이어하기 | 그 세션의 작업이므로 건드리지 않는다. 해당 세션에서 계속하라고 안내한다 |
## Step 5 — 이후
엔진이 단계마다 지시를 주입한다. 그 지시를 따른다.
- 응답을 끝내려 할 때 조건이 안 맞으면 엔진이 사유를 알려주고 계속 진행시킨다
- 조건이 다 맞으면 자동으로 다음 단계로 넘어간다
- 단계는 스스로 넘길 수 없다. `state.json` 수정은 차단된다
---
## 막혔을 때
**hook이 차단했을 때** — 차단 사유에 무엇이 필요한지 적혀 있다. 그 조건을 충족시킨다.
우회로를 찾지 마라. 차단은 지금 그 행동이 이 단계에서 안전하지 않다는 뜻이고,
우회하면 사용자가 원한 검증이 빠진 채로 결과가 나간다.
**`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 도구로 `.Codex/ai-bouncer/workflow.yaml`을 수정한다
6. `bouncer check`로 검증한다. 실패하면 되돌린다
7. 다음 세션부터 적용된다고 알린다
`forbid`를 약화시키는 방향(차단 해제)은 사용자가 명시적으로 요구할 때만 한다.
게이트가 귀찮다는 이유로 규칙을 무르면 그 규칙을 만든 이유가 사라진다.
---
## 명령
| 명령 | 용도 |
|---|---|
| `bouncer scan` | 상태·모드·선택항목 (시작 전 1회) |
| `bouncer start <모드> "<슬러그>"` | 작업 시작 |
| `bouncer status` | 현재 단계와 남은 조건 (각 step의 `id:` 도 함께 나온다) |
| `bouncer run <step-id>` | 검증 명령 실행 후 결과 기록. 명령 문자열은 엔진이 소유한다 |
| `bouncer done <step-id>` | 사람 확인이 필요한 step 완료 처리 |
| `bouncer cancel` | 작업 취소 |
| `bouncer skip <step-id>` | 엔진이 포기한 조건을 이번 작업에서만 건너뛴다 (사용자가 요청할 때만) |
| `bouncer release [--force]` | 죽은 세션이 남긴 잠금 확인 / 회수 |
| `bouncer resume <task-id>` | 잠금이 풀린 미완 작업을 이어받는다 (`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`으로 해야 결과가 증거로 남는다. 직접 실행한 것은 기록되지 않아
엔진이 계속 미충족으로 판정한다
- 실패한 것을 통과로 보고하기
- 완료 후 사용자 지시 없이 새 작업 시작하기