LogoSkills

/cc-dev:unstuck — 막혔을 때 시각을 바꿔주는 "관점 전환 회의"

5가지 측면 사고 페르소나로 막힌 루프를 벗어납니다 — 단독 재구성 또는 병렬 토론(정답이 아닌 옵션을 반환합니다)

/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).
  • 어느 모드든 막힌 상황 정보(무엇을 하려 했나 / 무엇을 반복했나 / 무엇을 시도했고 어떻게 실패했나)를 함께 주면 더 정확합니다.

안에서 무슨 일이 벌어지나요#

  1. 상황 정리 — "무엇을 하려는지(problem_context) / 어떤 방법을 반복했는지(current_approach) / 무엇을 시도했고 어떻게 실패했는지(failed_attempts)"를 모읍니다.
  2. 관점 전환
    • 솔로 모드: 지정한 페르소나 정의를 읽고, 그 한 명의 시각으로 막힌 지점을 다시 진술합니다.
    • 토론 모드: 5명을 동시에(병렬) 불러 각자 reframing을 받아옵니다.
  3. 종합 — 토론 모드는 5명의 의견을 선택지(Options) / 서로 엇갈린 지점(Disagreements) / 추천(Recommended) 으로 묶어 보여줍니다. "엇갈린 지점"은 5명을 서로 맞대어 봐야 나오는 항목이라, 다섯 명이 다 돌아온 뒤에 한 번에 정리합니다 — 한 명씩 오는 대로 흘려보낼 수 없는 이유입니다.
  4. 빠진 사람은 밝힙니다 — 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#

ParameterRequiredDescription
modesolo 또는 생략(=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:standardlateral-thinkermodel: 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 기록 → STOP

dropped 가 비어 있지 않아도 남은 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
- {상황상 가장 설득력 있는 선택지 12+ 이유}

 >   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#

  1. No verdict: 선택지·추천까지만. 결정은 사용자.
  2. Reframe, not retry: 모든 next move 는 failed_attempts 와 종류가 달라야 한다.
  3. Semantic matching: stuck/affinity 판정은 의미 기반, 어휘 겹침 금지 (Korean-first).
  4. Shared definitions: 페르소나 정의는 references/LATERAL_PERSONAS.md 단일 출처.
  5. Pinned subagent + explicit tier: 팬아웃은 lateral-thinker 하나만 쓴다(model: sonnet = Standard). general-purpose 는 티어를 실을 자리가 없어 5× silent inherit 이므로 쓰지 않는다. 다른 에이전트로 갈아탈 때는 스폰 지점에 tier: 를 명시한다(../rules/orchestration-graph.md §5).
  6. No silent drop: 5개 호출은 allSettled 의미로 모은다. 한 명의 실패가 완료된 나머지를 버리지 않고, 탈락 페르소나는 Synthesis 의 Dropped 절에 이름·사유로 남긴다. 전원 실패만 호출자에게 실패로 돌려준다.
  7. Barrier is required, not an optimisation target: Disagreements 가 5건 교차 비교이므로 종합은 mode:barrier 다(../rules/orchestration-graph.md §4.2). 기질은 Task 서브에이전트에서 올리지 않고 폭도 5에서 늘리지 않는다.
  • /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. 여기서 재정의하지 않는다.