/cc-dev:unstuck — 막혔을 때 시각을 바꿔주는 "관점 전환 회의"#
| 항목 | 내용 |
|---|---|
| 실행 명령 | /cc-dev:unstuck |
| 분류 | 개발 사이클 |
| 난이도 | ●●○ 보통 |
같은 수정을 반복하다 막힌 작업을, 서로 다른 5명의 관점으로 다시 바라보게 해 주는 워크플로
한마디로#
작업이 같은 자리에서 계속 막혔을 때 — 같은 수정을 몇 번이나 시도했는데 똑같이 실패할 때 — 서로 다른 사고방식을 가진 5명의 "관점 전환가"를 불러 "다르게 보는 법" 을 받아오는 명령입니다. 막힌 문제 앞에서 친구 5명에게 "이거 어떻게 봐?"라고 물어보는 회의라고 생각하면 됩니다. 단, 답을 대신 정해주지는 않습니다 — 선택은 당신 몫입니다.
누가·언제 쓰나요#
- 같은 에러를 같은 방법으로 N번 고쳤는데도 계속 똑같이 실패할 때
- 두 수정 사이를 왔다 갔다(A 고치면 B 깨지고, B 고치면 A 깨지고) 하며 진동할 때
- "뭔가 사실 하나가 비어 있는데 그게 뭔지 모르겠다" 싶을 때
-
자동화 배치(
/cc-dev:batch)가 한 Story에서 같은 실패를 반복해 스스로 관점 전환을 호출할 때 (이때는 사람이 부르지 않아도 자동으로 호출됩니다)
👉 "더 열심히 다시 시도"가 아니라 "다른 각도로 다시 보기" 가 필요할 때 쓰는 도구입니다.
무엇을 해주나요#
5명의 관점(페르소나)으로 막힌 상황을 다시 바라봅니다. 각 페르소나는 한 가지 사고방식만 가집니다.
- HACKER — 같은 수리 그만하고, 막힌 지점을 떼어내 우회하라
- RESEARCHER — 노력이 아니라 사실 하나가 비어 있다, 가서 찾아와라
- SIMPLIFIER — 과하게 지어졌다, 더하지 말고 덜어내라
- ARCHITECT — 계속 왔다 갔다 한다, 구조가 틀렸으니 다시 짜라
- CONTRARIAN — (기본 폴백) 전제 자체를 의심하라
이 5명의 정의·질문은 한 곳(references/LATERAL_PERSONAS.md)에 모여 있어, 어디서 부르든 같은 페르소나가 같은 방식으로 동작합니다.
어떻게 쓰나요#
# 토론 모드 (기본) — 5명 전원이 각자 관점을 내고, 종합 정리
/cc-dev:unstuck
# 솔로 모드 — 특정 페르소나 한 명만 불러 빠르게 관점 전환
/cc-dev:unstuck solo hacker
/cc-dev:unstuck solo architect
- 인자 없이 부르면 토론(debate) 모드 입니다 — 5명이 동시에 의견을 내고 마지막에 종합해 줍니다.
-
solo <페르소나>로 부르면 해당 페르소나 한 명만 빠르게 관점을 전환해 줍니다 (페르소나:hacker/researcher/simplifier/architect/contrarian). - 어느 모드든 막힌 상황 정보(무엇을 하려 했나 / 무엇을 반복했나 / 무엇을 시도했고 어떻게 실패했나)를 함께 주면 더 정확합니다.
안에서 무슨 일이 벌어지나요#
- 상황 정리 — "무엇을 하려는지(problem_context) / 어떤 방법을 반복했는지(current_approach) / 무엇을 시도했고 어떻게 실패했는지(failed_attempts)"를 모읍니다.
-
관점 전환
- 솔로 모드: 지정한 페르소나 정의를 읽고, 그 한 명의 시각으로 막힌 지점을 다시 진술합니다.
- 토론 모드: 5명을 동시에(병렬) 불러 각자 reframing을 받아옵니다.
- 종합 — 토론 모드는 5명의 의견을 선택지(Options) / 서로 엇갈린 지점(Disagreements) / 추천(Recommended) 으로 묶어 보여줍니다. "엇갈린 지점"은 5명을 서로 맞대어 봐야 나오는 항목이라, 다섯 명이 다 돌아온 뒤에 한 번에 정리합니다 — 한 명씩 오는 대로 흘려보낼 수 없는 이유입니다.
- 빠진 사람은 밝힙니다 — 5명 중 누가 실패해도 돌아온 나머지 의견은 버리지 않고, 누가 왜 빠졌는지를 결과에 함께 적습니다(전원 성공이면 "빠진 사람 없음"이라고 적습니다).
- 멈춤 — 여기서 멈춥니다. 결론(verdict)은 자동으로 내지 않습니다 — 어떤 선택지를 택할지는 사람이 정합니다.
핵심: 이 명령은 선택지를 주는 것이지 결정을 내리는 것이 아닙니다.
끝나면 다음은?#
- 마음에 드는 선택지가 있으면 그 방향으로 직접 작업을 이어가면 됩니다.
-
그래도 안 풀리면 다른 페르소나로 한 번 더(
solo) 돌리거나, 전제 자체가 의심되면 사고 복기(/cc-dev:debrief)로 넘어갑니다. -
배치 자동화가 호출한 경우, 관점 전환을 다 써도 안 풀리면 해당 Story는
BLOCKED('unstuck_exhausted')로 표시되고 나머지 배치는 계속 진행됩니다 (Epic 전체가 멈추지 않습니다).
⚙️ 상세 옵션·실행 명세 (개발자 / AI 에이전트용)
Triggers#
- 동일 전략을 반복했는데 동일하게 실패하는 stuck loop
/cc-dev:batch/sequential-workflow의 stall budget 2단계에서 자동 호출- 사람이 명시적으로 관점 전환을 요청
Usage#
/cc-dev:unstuck # debate 모드 (기본): 5 페르소나 병렬
/cc-dev:unstuck solo < persona > # solo 모드: 단일 페르소나Parameters#
| Parameter | Required | Description |
|---|---|---|
mode | — | solo 또는 생략(=debate). 기본 debate |
<persona> | solo일 때 ✅ | hacker / researcher / simplifier / architect / contrarian |
Stuck Context (양 모드 공통 입력)#
| 필드 | 의미 |
|---|---|
problem_context | 달성하려는 목표 |
current_approach | 반복하고 있는 전략 |
failed_attempts | 이미 시도한 것 + 각각 어떻게 실패했는지 |
Persona Source of Truth#
5 페르소나(HACKER / RESEARCHER / SIMPLIFIER / ARCHITECT / CONTRARIAN)의 mindset·affinity·probing questions는 단일 정의 파일을 따른다:
plugins/cc-spec/references/LATERAL_PERSONAS.md
이 명령과 lateral-thinker 에이전트는 그 파일을 READ해서 쓴다 — 페르소나 문장을 여기서 다시 쓰지 않는다.
LLM-SEMANTIC, never lexical#
"같은 실패가 반복되는가?" 와 "어떤 증상 → 어떤 페르소나" 판정은 상황의 의미에 대한 LLM 판단으로 한다. 에러 텍스트의 문자열/토큰 겹침으로 비교하지 않는다. 한국어는 띄어쓰기 경계가 없고 조사가 붙어, 같은 블로커를 가리키는 두 로그가 토큰을 거의 공유하지 않을 수 있다("빌드가 실패" vs "빌드는 또 실패"). 의미로 판단하라.
Solo Mode#
1. < persona > 검증 (5개 중 하나). 미지정/오타 → affinity 라우팅으로 추정(기본 CONTRARIAN)하고 무엇을 골랐는지 명시.
2. LATERAL_PERSONAS.md 에서 해당 페르소나 행 로드.
3. stuck context 에 페르소나 3 probing questions 적용.
4. reframing 1건 출력 (재시도 아님 — 종류가 다른 next move).
5. STOP. verdict 없음.단일 호출은 lateral-thinker 에이전트로 위임할 수도, 인라인으로 처리할 수도 있다:
await Task({
subagent_type: " lateral-thinker " ,
prompt: `
persona: ${persona} // e.g. HACKER
problem_context: ${problem_context}
current_approach: ${current_approach}
failed_attempts: ${failed_attempts}
`
});Debate Mode (default)#
5 페르소나를 병렬 fan-out한다. 각 호출은 subagent_type: "lateral-thinker" 하나만 쓴다 (정의된 에이전트, 페르소나 인자 전달 — plugins/cc-dev/agents/lateral-thinker.md 로 resolve된다). 빌트인 general-purpose 로 대체하지 않는다: 그 타입은 에이전트 파일이 없어 모델 티어를 실을 자리가 없고, 부모 세션 모델을 조용히 물려받는다(unset = silent inherit) — degree 5 팬아웃에서 미선언은 기본값이 아니라 5배 승수이고, lateral-thinker frontmatter 가 model: sonnet(Standard) 을 못박아 둔 이유가 정확히 이것이다. 커스텀 미정의 타입은 쓰지 않는다. 외부 lateral-thinking MCP 도구는 참조하지 않는다 — Task 만 사용한다.
부득이 다른 에이전트로 갈아탈 때는 스폰 지점에
tier:를 명시한다. 에이전트/세션을 스폰하는 노드의tier:의무와 승수 논리는../rules/orchestration-graph.md§5 · §7 규칙 9 가 SoT다(티어 이름 정의는../skills/agent-teams/SKILL.md→ "Effort Routing Convention").
Fan-out 계약 — 표기·의무는 ../rules/orchestration-graph.md §5 를 따르고, 값은 이 자리가 정본이다:
width:5— 페르소나 수로 고정. 데이터 주도 폭이 아니므로 cap 도 deferred 로그도 필요 없다(잘릴 항목이 없다).tier:standard—lateral-thinker의model: sonnet이 강제한다. unset 로 두지 않는다.own:없음 — 5개 워커 전부 읽기 전용(tools: Read, Glob, Grep)이라 쓰기 소유권을 나눌 대상이 없다.mode:barrier because:Disagreements 는 5건 reframing 의 교차 비교—../rules/orchestration-graph.md§4.2 "barrier 가 정당한 자리" 목록에 이 자리가 이름으로 올라 있다. 스트림/파이프라인으로 "최적화" 하면 Disagreements 자체가 계산 불가가 된다.log:— 반환한 페르소나 수와 탈락시킨 페르소나를 Synthesis 출력의Dropped절에 남긴다(콘솔은 내구 기록이 아니다 — 같은 문서 §7 규칙 6).
기질은 그대로 Task 서브에이전트다 — ../rules/orchestration-graph.md §4 6행 매트릭스에서 한 칸도 올리지 않는다. 워크트리·터미널·브랜치를 늘리지 않고, 폭도 5에서 늘리지 않는다.
const PERSONAS = [ " HACKER " , " RESEARCHER " , " SIMPLIFIER " , " ARCHITECT " , " CONTRARIAN " ];
// 5개 동시 실행 (한 메시지에서 병렬 Task)
// allSettled: 한 명의 실패가 완료된 나머지를 버리지 않는다 (all 은 첫 reject 에서 4건을 무음 폐기했다)
const settled = await Promise.allSettled(
PERSONAS.map((persona) = >
Task({
subagent_type: " lateral-thinker " , // 고정 — general-purpose 로 바꾸지 않는다 (tier 없음 = 5× silent inherit)
prompt: `
persona: ${persona}
problem_context: ${problem_context}
current_approach: ${current_approach}
failed_attempts: ${failed_attempts}
references/LATERAL_PERSONAS.md 의 ${persona} 정의를 읽고,
이 stuck context 를 그 시각으로 reframing 하라. verdict 금지.
`,
})
)
);
// 반환분과 탈락분을 이름으로 분리 — 조용한 절단 금지
const reframings = settled.flatMap((r, i) = >
r.status === " fulfilled " ? [{ persona: PERSONAS[i], reframing: r.value }] : []
);
const dropped = settled.flatMap((r, i) = >
r.status === " rejected " ? [{ persona: PERSONAS[i], reason: String(r.reason) }] : []
);
// 전원 실패는 종합을 꾸며내지 않고 호출자(stall ladder Rung 2)에게 실패로 돌려준다
if (reframings.length === 0) throw new Error( " unstuck: 5 페르소나 전원 실패 — 종합할 reframing 이 없다 " );
// barrier: 5건이 settle 된 뒤에만 종합한다 → Dropped 기록 → STOPdropped 가 비어 있지 않아도 남은 reframing 으로 종합을 진행한다 — 단, 교차 비교의 모집단이 5보다 작아졌다는 사실을 Dropped 절에 적어 독자가 Disagreements 의 범위를 오해하지 않게 한다.
Synthesis Output#
돌아온 reframing(최대 5건)을 받아 아래로 묶고 멈춘다:
## /cc-dev:unstuck — Debate Synthesis
### Options
- [HACKER] {next move}
- [RESEARCHER] {next move}
- [SIMPLIFIER] {next move}
- [ARCHITECT] {next move}
- [CONTRARIAN] {next move}
### Dropped
- {반환 3/5} · {탈락 페르소나 + 사유} ← 전원 성공이면 `- none (5/5 반환)` 로 명시. 절을 지우지 않는다
### Disagreements
- {페르소나 간 충돌하는 진단/제안 — 어디서 엇갈리는가}
### Recommended
- {상황상 가장 설득력 있는 선택지 1–2개 + 이유}
> Do not auto-emit a verdict; the verdict is the user ' s.Synthesis는 추천까지만. 결론(어떤 옵션을 실행할지)은 자동으로 내지 않는다 — 사용자가 정한다.
Disagreements 는 5건 reframing 전부를 맞대어야 나오는 항목이므로, 이 종합은 진짜 barrier 다 — 도착 순 스트림으로 바꿀 수 있는 자리가 아니다(../rules/orchestration-graph.md §4.2). Dropped 는 그 barrier 가 몇 건 위에서 판정됐는지를 남기는 내구 기록이며, 빈 경우도 none (5/5 반환) 으로 적는다 — 없음 과 확인함 은 다르다.
Affinity Routing (solo 페르소나 미지정 시)#
references/LATERAL_PERSONAS.md 의 affinity/symptom 표를 의미 기반으로 적용 (기본 CONTRARIAN):
| 증상 (semantic) | Persona |
|---|---|
| 같은 에러·같은 수정 N회 반복 | HACKER |
| 확인 안 된 사실·가정 때문에 막힘 | RESEARCHER |
| 과설계·복잡성에 묻힌 블로커 | SIMPLIFIER |
| 수정 사이 진동(flip-flop) | ARCHITECT |
| 분류 불가·전제 자체 의심 (기본) | CONTRARIAN |
Key Rules#
- No verdict: 선택지·추천까지만. 결정은 사용자.
- Reframe, not retry: 모든 next move 는
failed_attempts와 종류가 달라야 한다. - Semantic matching: stuck/affinity 판정은 의미 기반, 어휘 겹침 금지 (Korean-first).
- Shared definitions: 페르소나 정의는
references/LATERAL_PERSONAS.md단일 출처. - Pinned subagent + explicit tier: 팬아웃은
lateral-thinker하나만 쓴다(model: sonnet= Standard).general-purpose는 티어를 실을 자리가 없어 5× silent inherit 이므로 쓰지 않는다. 다른 에이전트로 갈아탈 때는 스폰 지점에tier:를 명시한다(../rules/orchestration-graph.md§5). - No silent drop: 5개 호출은
allSettled의미로 모은다. 한 명의 실패가 완료된 나머지를 버리지 않고, 탈락 페르소나는 Synthesis 의Dropped절에 이름·사유로 남긴다. 전원 실패만 호출자에게 실패로 돌려준다. - Barrier is required, not an optimisation target: Disagreements 가 5건 교차 비교이므로 종합은
mode:barrier다(../rules/orchestration-graph.md§4.2). 기질은 Task 서브에이전트에서 올리지 않고 폭도 5에서 늘리지 않는다.
Related Commands#
/cc-dev:batch— stall budget 2단계에서 이 명령을 자동 호출/cc-dev:debrief— 관점 전환으로도 안 풀린 사고의 사후 복기references/LATERAL_PERSONAS.md— 5 페르소나 공유 정의../rules/orchestration-graph.md— 팬아웃 의무(tier:·width:·log:, §5) · barrier 정당화 목록(§4.2) · 기질 매트릭스(§4) SoT. 여기서 재정의하지 않는다.