Ship with skills, not vibes 25개의 skill을 하나의 개발 흐름으로 엮다
이것은 도구 상자 목록이 아닙니다. 본류 하나에 진입로 몇 개를 더한 흐름입니다. 흐릿한 생각에서 commit에 이르기까지, 각 단계에서 무엇을 입력할지, 어디서 멈춰야 할지, 그리고 어디가 조용히 망가지는지를 다룹니다.
01
먼저 잡아야 할 세 가지 기본 개념
이 페이지가 다루는 것은 mattpocock/skills(MIT 라이선스) 1.2.3 버전, 이미 공개된 25개의 skill입니다. 이 skill 묶음은 TauX가 만든 것이 아닙니다. 이 글이 TauX의 것입니다. 아래의 모든 판단 기준과 함정, 시나리오는 공식 문서와 issue를 모두 읽은 뒤에 새로 쓴 한국어 교재이며, 번역도 전재도 아닙니다.
이 세 가지를 먼저 이해하지 않으면 뒤에 나오는 skill을 모두 잘못 쓰게 됩니다.
첫째, 누가 부를 수 있는가
이것은 이 pack 전체에서 유일한 분류 축입니다.
| User-invoked | Model-invoked | |
|---|---|---|
| 누가 부를 수 있나 | 사람이 이름을 직접 입력할 때만. 다른 skill도 부를 수 없음 | 직접 입력해도 되고, agent가 스스로 판단해 가져다 쓰기도 함 |
| 설정 | disable-model-invocation: true |
둘 다 설정하지 않음 |
| description은 누구를 위한 것인가 | 사람 (slash command 목록) | 모델 (트리거 문구를 다수 포함) |
| 자리매김 | 오케스트레이터: 흐름이 어떻게 흘러갈지 정함 | 규율 라이브러리: 재사용 가능한 방법론 |
실무에서 생기는 세 가지 결과
- 문서에 "이어서
/implement를 실행"이라고 적혀 있다면, 그것을 입력하는 주체는 사람입니다. agent가 알아서 이어서 진행하지는 않습니다. - harness는 user-invoked skill을 모델에 넘기는 목록에 넣지 않기 때문에, agent는 이 skill들이 설치되지 않았다고 '착각'하는 일이 잦습니다. 설치되어 있습니다. 그냥 입력하면 됩니다.
- 무엇이 설치되어 있는지 확인하려면
.claude-plugin/plugin.json을 보십시오. 그 파일이 기준입니다.
규칙 자체는 이렇습니다: user-invoked는 model-invoked를 부를 수 있지만, 다른 user-invoked는 결코 부를 수 없습니다.
둘째, 네 가지 역할
본류
아이디어에서 ship까지의 고정 경로: grill-with-docs → to-spec → to-tickets → implement → code-review.
진입로
일감을 만들어 낸 뒤 본류에 합류시킵니다: triage(다른 사람이 던져 넣은 것), wayfinder(하나의 session에 담기지 않는 것), improve-codebase-architecture(정기 점검에서 과제가 나오는 것).
단독
필요할 때 가져다 쓰고 끝나면 떠납니다: prototype, research, diagnosing-bugs, resolving-merge-conflicts, wizard, handoff, teach, to-questionnaire, wait-what, grill-me.
어휘층
흐름이 없고 정확한 용어만 제공하며, 다른 skill이 빌려다 씁니다: codebase-design(모듈의 형태), domain-modeling(도메인 언어), writing-for-agents(agent가 읽는 문서), grilling(인터뷰 프리미티브).
가장 오용되기 쉬운 어휘층
이들에게는 흐름이 없습니다. 예를 들어 codebase-design에 "시작하자"라고 말하면, agent는 스스로 흐름을 하나 만들어 내고, 묻지도 않은 것을 리팩터링하며 100k token을 태웁니다 (등록된 issue 449). 어휘층은 'driver skill이 위, 어휘층이 아래'의 방식으로 돌려야 합니다.
셋째, Phase boundary
하나의 session 안에서 한 덩어리의 작업을 phase라고 부릅니다 (인터뷰, 구현, QA…). '내 context를 어떻게 할까'라는 물음은 두 phase 사이에서만 성립합니다. phase 한가운데에서는 고를 것이 없고, 계속하거나 남은 일을 subagent에 넘기는 것뿐입니다.
| 순위 | 선택지 | 언제 고르나 |
|---|---|---|
| 1 | 계속 | 다음 phase가 이 phase의 원래 발언을 필요로 하거나, smart zone에 아직 여유가 있을 때. 1차 자료를 지키는 유일한 선택지이므로, 이것부터 배제한 다음에 다른 선택지를 고려 |
| 2 | clear | 뒤에 오는 것을 전부 버려도 될 때. 가장 싸지만, 판단이 틀리면 되돌릴 수 없음 |
| 3 | handoff | 무언가를 이사해야 할 때: harness 교체, 디렉터리 이동, 동료에게 전달, 도중에 발견한 곁가지 분리 |
| 4 | subagent | 작업 범위가 충분히 좁아서, 자리를 비워도 끝까지 돌아갈 수 있을 때 |
| 5 | compact | 위의 어느 것도 아닐 때. 첫 선택이 아니라 최후의 보루이지만, 실무에서는 여기로 떨어지는 경우가 가장 많음 |
가장 자주 헷갈리는 두 가지: handoff 자체는 '창을 넘나드는 범용 다리'가 아닙니다. 이것이 사 주는 것은 이식성뿐입니다. compact 역시 첫 반응이 아니라 트리의 맨 아래입니다. 셋이 지키는 것은 서로 다릅니다 — compact가 지키는 것은 의도이고, clear는 아무것도 지키지 않으며, handoff가 지키는 것은 일을 옮길 수 있는 힘입니다. 그리고 이 셋은 모두 대화(1차 자료)를 요약(2차 자료)으로 바꿔 버립니다.
02
설치: 두 갈래 길에서 하나를 고르기
설치 방식 두 가지는 두 가지 철학을 뜻합니다. 두 번 설치하면 모든 skill이 두 벌씩 생깁니다.
경로 A — 구독
claude plugins install mattpocock-skills
또는 session 안에서 /plugin install mattpocock-skills를 입력합니다. 이미 공식 marketplace에 있으므로 소스를 따로 추가할 필요가 없고, 업데이트도 자동으로 옵니다. 대가: 읽기 전용이라 고칠 수 없습니다.
경로 B — 고칠 수 있는 방식
npx skills@latest add mattpocock/skills
어떤 skill을 설치할지, 어떤 agent에 설치할지 물어봅니다. 반드시 체크할 것은 setup-matt-pocock-skills. 파일은 '내가 소유한 평범한 파일'로 repo에 기록되어 마음대로 고칠 수 있습니다. 업데이트할 때는 직접 npx skills update.
경로 B의 함정
직접 고친 SKILL.md 파일은 npx skills update 실행 시 덮어써집니다. 오래 유지되기를 바라는 동작은 각자의 CLAUDE.md / AGENTS.md(자세한 내용은 09절)에 적거나, 호출할 때마다 말로 전달하십시오 — skill 파일은 고치지 마십시오.
beta를 써 보고 싶다면
npx skills@latest add mattpocock/skills --skill=<name>
plugin으로는 이것들을 받을 수 없습니다. 글을 쓰는 시점의 in-progress bucket에는 loop-me, writing-beats, writing-fragments, writing-shape, claude-handoff, setup-ts-deep-modules가 있습니다 — 문서 페이지가 없고, 언제든 바뀌거나 사라질 수 있습니다. plugin에 들어 있지 않은 misc bucket도 있습니다: git-guardrails-claude-code(hook으로 위험한 git 명령을 막는 skill), setup-pre-commit, migrate-to-shoehorn, scaffold-exercises.
03
사전 준비, repo마다 한 번
/setup-matt-pocock-skills 명령은 모든 engineering skill의 전제 조건이지 흐름의 한 단계가 아닙니다.
| 결정 항목 | 먼저 제안하는 것 | 실제로 물어보는 때 |
|---|---|---|
| Issue tracker | git remote를 보고 추측 | 매번 물어봄 — 유일하게 진짜 선택하는 항목 |
| Triage label | 표준 이름 다섯 개를 그대로 사용 | triage를 설치했을 때만 물어봄 |
| Domain 문서 배치 | 단일 context: root에 CONTEXT.md 및 docs/adr/ |
monorepo 신호를 감지했을 때만 물어봄 |
Tracker 선택지 네 가지: GitHub(필요: gh), GitLab(필요: glab), Local markdown (.scratch/<feature>/, remote도 필요 없음), Other(작업 흐름을 설명하는 글을 직접 씀).
Local markdown은 대비책이 아니라 일등 시민입니다: 1인 프로젝트, remote가 없어도 완전히 지원됩니다. 다만 GitHub을 쓰는 프로젝트에서 local markdown을 함께 쓰지는 마십시오. 둘은 대체재이지 겹쳐 쓰는 것이 아닙니다.
'Other'도 자리 표시자가 아닙니다 — Jira, Linear, Azure DevOps가 돌아가는 것은 바로 이것 덕분입니다: 작업 흐름을 설명하면 그 말을 그대로 docs/agents/issue-tracker.md에 적어 넣고, 하위 skill이 그 문장대로 움직입니다. 그래서 이렇게 됩니다. 이 한 벌 전체는 GitHub에 묶여 있지 않습니다. 그리고 tracker를 바꾸려고 skill 파일을 고칠 일도 영영 없습니다.
반드시 알아야 할 세 가지 함정
첫째, label은 대신 만들어 주지 않습니다
triage-labels.md 파일은 '대조표'일 뿐입니다. 새로 만든 GitHub repo에는 그 label들이 아예 없어서, 붙이려 하면 실패합니다. 먼저 한 번 직접 만들어 두십시오:
gh label create needs-triage
gh label create needs-info
gh label create ready-for-agent
gh label create ready-for-human
gh label create wontfix
gh label create bug
gh label create enhancement
여기에 wayfinder 기능을 쓴다면 다섯 개를 더 먼저 만들어야 합니다 (gh 명령은 존재하지 않는 label을 만나면 곧바로 실패합니다): wayfinder:map, wayfinder:grilling, wayfinder:prototype, wayfinder:research, wayfinder:task.
둘째, 파일이 있는지를 볼 뿐 어떤 harness를 쓰는지는 보지 않습니다
Codex를 쓰고 있는데 repo에 CLAUDE.md가 남아 있으면, ## Agent skills 단락이 Codex는 영영 읽을 수 없는 곳에 쓰입니다. 해법은 수동으로 AGENTS.md로 옮기거나, AGENTS.md 쪽을 본체로 삼고, CLAUDE.md 파일에는 그곳을 가리키는 한 줄만 두는 것입니다.
셋째, skills를 갱신한 뒤에 다시 한 번 돌려도 됩니다
시드 템플릿은 판이 바뀌므로, 오래된 issue-tracker.md가 새 skill과 맞지 않을 수 있습니다. 하위 동작이 이상해지면 다시 돌리는 것이 가장 싼 수리법입니다.
성공했는지 판단하기
docs/agents/issue-tracker.md및domain.md파일이 존재합니다 (triage를 설치했다면triage-labels.md)- 내 harness가 진짜로 읽는 그 지시 파일 안에 다음 제목이 있습니다:
## Agent skills - 이후
/to-tickets명령이 issue를 어디에 둘지 더는 묻지 않고,/triage명령은 label을 '붙이는' 것이지 '발명'하는 것이 아닙니다 - skill 파일 자체는 한 글자도 바뀌지 않았습니다. setup이 어떤
SKILL.md를 고쳤다면 그건 사고입니다
04
25개의 skill, 전체 지도
'하드 의존' 열이 실전의 핵심입니다 — 의존이 설치되어 있지 않으면 skill은 조용히 즉흥 연기로 퇴화합니다.
| Skill | 호출 주체 | 역할 | 한마디로 |
|---|---|---|---|
| setup-matt-pocock-skills | User | 사전 준비 | repo마다 한 번 실행. tracker, label, 문서 배치를 설정 |
| ask-matt | User | 라우터 | 상황을 설명하면 어떤 순서로 입력할지 알려 줌 |
| grilling | Model | 프리미티브 | 라운드마다 진행하는 인터뷰 엔진. 다른 grilling은 모두 이 위에 세워짐 |
| grill-me | User | 단독 | 상태를 두지 않는 인터뷰. repo 불필요, 주제가 코드가 아니어도 됨 |
| grill-with-docs | User | 본류 선두 | 같은 인터뷰에 더해 codebase를 읽고 CONTEXT.md 및 ADR을 작성 |
| wayfinder | User | 진입로 | 하나의 session에 담기지 않는 큰 작업을 decision 티켓 지도로 그림 |
| to-spec | User | 본류 | 대화를 하나의 spec으로 수렴시켜 tracker에 등록. 더 이상 인터뷰하지 않음 |
| to-tickets | User | 본류 | spec 또는 대화를 tracer-bullet 티켓으로 잘라 블로킹 엣지를 선언 |
| implement | User | 본류 | 티켓대로 작업하고 내부에서 tdd를 구동, 마무리로 code-review를 돌린 뒤 commit |
| tdd | Model | 엔진 | red-green, 사전에 합의한 seam 위에서만 테스트를 작성 |
| code-review | Model | 본류 말미 | 어떤 고정점에 대한 diff를 Standards와 Spec 두 축으로 심사 |
| triage | User | 진입로 | 다른 사람이 던져 넣은 issue를 상태 기계에 통과시킴 |
| improve-codebase-architecture | User | 진입로 | codebase를 훑어 '모듈을 심화할' 기회를 찾고 HTML 보고서를 냄 |
| prototype | Model | 단독 | 일회용 코드로, 하나의 설계 질문에 답함 |
| diagnosing-bugs | Model | 단독 | 어려운 bug와 성능 회귀의 6단계 진단. red loop가 생기기 전에는 추측하지 않음 |
| research | Model | 단독 | 백그라운드 agent가 1차 자료를 읽고 인용이 붙은 markdown을 남김 |
| resolving-merge-conflicts | Model | 단독 | hunk마다 '의도'에 따라 충돌을 해결하고 검사를 돌려 merge를 완료. 결코 포기하지 않음 |
| wizard | Model | 단독 | 대화형 bash script를 생성해 사람만 할 수 있는 단계를 안내 |
| codebase-design | Model | 어휘층 | 모듈, 인터페이스, depth, seam의 정확한 용어와 네 가지 원칙 |
| domain-modeling | Model | 어휘층 | 도메인 언어를 능동적으로 세우고 벼리며 즉시 기록 CONTEXT.md 및 ADR을 작성 |
| handoff | User | 단독 | 현재 대화를 들고 다닐 수 있는 인수인계 문서로 압축 |
| teach | User | 단독 | 현재 디렉터리를 session을 넘나드는 학습 워크스페이스로 바꿈 |
| to-questionnaire | User | 단독 | '다른 사람만 아는' 결정을 한 장의 설문지로 만듦 |
| wait-what | User | 단독 | 방금 그 설명이 이해되지 않을 때 입력하면 agent가 다시 설명 |
| writing-for-agents | Model | 어휘층 | agent가 읽는 문서(skill, 지시 파일, spec, prompt)의 지침 |
기억해 둘 두 갈래
- prototype 갈림길: 인터뷰 도중 '말로는 못 하고 봐야 아는' 질문을 만나면 멈추고 prototype을 만든 뒤, 보고 나서 한 줄로 답합니다.
- spec과 tickets는 session을 넘어갈 때만 값을 합니다. 하나의 context window로 끝나는 변경이라면 곧바로
grill-with-docs다음에implement로 이어 가고, 가운데 두 단계는 건너뜁니다.
05
본류 일곱 단계, 차례대로
관통 사례
사내 도구 repo(Next.js와 Postgres)에 '계약 만료 알림'을 넣으려 합니다 — 30일 안에 만료되는 계약을 나열하고, 담당자에게 메일을 보내고, 관리 화면에 빨간 점을 표시합니다. schema, API, UI, 메일 발송에 걸쳐 있어 충분히 넓고, 전체 흐름을 밟을 값어치가 있습니다.
Step 1 — 막연한 생각을 캐물어 결정으로 만들기
/grill-with-docs 계약 만료 알림 기능을 추가하고 싶습니다
깨끗한 대화를 새로 열고, plan mode를 끕니다. plan mode는 agent가 계획을 빨리 내놓도록 재촉하는데, 그것은 '질문 상태에 머문다'와 정반대입니다.
무슨 일이 일어나는가
codebase를 읽은 다음, 라운드마다 질문합니다. 각 라운드는 그 시점의 frontier — 전제 조건이 모두 풀린 질문을 한 번에 묻기 때문에, 아직 공중에 뜬 질문을 받는 일은 없습니다. 형식은 고정입니다. 번호 붙은 제목, 본문, 그리고 한 줄의 권장 답변. 13문항이면 보통 3라운드, 46문항을 4라운드로 나누는 것도 아주 흔한 한 판입니다.
어떻게 답할 것인가
1 예
2 두 번째
3 아니요, 우리 계약에는 부분 해지가 없습니다
4 모르겠습니다
가장 큰 실패 방식은 수동성입니다. "동의"를 마흔 번 이어 답하면 agent가 쓰고 당신이 고개만 끄덕인 계획이 나옵니다 — 길기 때문에 생산적으로 느껴집니다. 하지만 실제로 정해진 것은 없고, 결과는 스스로 벌지 않은 확실성을 두르고 있습니다. 능동적이라는 말은 이런 뜻입니다. 필요한 정밀도보다 얕게 물어 오면, 되밀고, 범위가 떠내려가고 있으면, 말하고, 정말 모를 때는 "모르겠습니다"라고 답하십시오. 그것이 진짜 답입니다.
grillable vs ungrillable
'한 장짜리 긴 폼인가, 세 페이지인가' '이 인터랙션은 어떤 느낌이어야 하는가' — 이런 질문은, 말로는 풀리지 않습니다. 반응할 무언가가 필요합니다. 마주치면 멈추고 prototype을 만든 뒤, 보고 나서 한 줄로 답하십시오. ungrillable한 질문을 밀어붙여 계속 이야기하는 것이 session이 터지는 가장 큰 원인입니다. agent는 말을 바꿔 계속 묻고, 당신은 계속 추측하고, 범위는 불확실성을 메우려고 부풀어 오릅니다.
| 무엇이 해결되었나 | 어디에 남는가 |
|---|---|
| 하나 용어 — 이 프로젝트 고유의 표현 | CONTEXT.md, 그 자리에서 기록, 마지막에 몰아서 내놓는 것이 아님 |
| 하나 되돌리기 어렵고, context가 없으면 뜻밖으로 보이며, 실제로 트레이드오프가 있는 결정 | docs/adr/ 아래에 두는 ADR 한 건 |
| 그 밖에 결정한 모든 것 | 대화 안에만. 다른 어디에도 없음 |
셋째 줄의 뜻
당신이 캐물어 얻어낸 것 가운데, 대부분은 이 context window 안에만 존재합니다. 그러니 clear 하지 말고 compact 하지 말고, 같은 대화에서 그대로 /to-spec.
CONTEXT.md는 용어집이며, 용어집일 뿐입니다 — 구현 세부도, spec도, 초안도 넣지 않습니다. ADR은 세 조건이 동시에 성립해야 하므로, 대부분의 session은 ADR을 0건 냅니다. 그것이 설계대로입니다.
이 단계에서는, 가장 좋은 모델을 씁니다. grilling이 먹는 것은 '시스템이 어떻게 망가지는가'에 대한 모델 자신의 직관입니다. 구현 단계는 오히려 context를 많이 먹으므로 더 싼 모델이라도 괜찮습니다.
Step 2 — 정해진 것을 살아남는 문서로 만들기
/to-spec, 같은 대화 안에서. 새로 열지 마십시오.
이것은 당신을 인터뷰하지 않습니다. 여기까지 왔다면 정해야 할 것은 다 정해졌으므로, 이것은 '종합'입니다 — 대화, codebase, CONTEXT.md 및 ADR에서 정리합니다.
spec은 결정의 기록이지 결정이 이루어지는 자리가 아니다
이것이 존재하는 이유는 context window가 끝나기 때문입니다. 방금 캐물어 얻은 모든 것은 곧 지워질 대화 안에 있습니다. spec은 그 대화의 생존자입니다. 그래서 아무것도 검증하지 않고 아무것도 결정하지 않습니다. spec 안에 당신이 말하지 않은 문장이 하나라도 있다면 그것은 결함입니다.
먼저 seam을 당신과 확인한다
한 글자도 쓰기 전에, 이 기능을 어떤 seam(테스트가 동작을 관찰하는 공개 경계) 위에서 테스트할지 먼저 초안을 잡아 당신에게 묻습니다. 새로 여는 것보다 이미 있는 seam을 선호하며, 취할 수 있는 한, 가장 높은 seam을 취합니다. 이상적인 수는 변경 전체에 하나뿐입니다. 이 '사전에 합의한 seam'은 그대로 아래로 전달됩니다: tdd는 사전에 합의한 seam 위에서만 테스트를 쓰고, code-review는 합의하지 않은 seam이 쓰이지 않았는지 검사합니다. 그러므로 이 대화에는 성실히 답하고, 구현 단계로 미루지 마십시오.
| 지금 어디에 있는가 | 무엇을 실행하는가 |
|---|---|
| 아직 아무것도 정해지지 않음 | 먼저 grill-with-docs |
| 정해졌고, 하나의 context window로 끝남 | 곧바로 implement, spec 건너뛰기 |
| 정해졌고, 작업이 여러 session에 걸침 | /to-spec, 그다음 /to-tickets |
| wayfinder 지도를 막 비운 참 | /to-spec #<map_issue> |
흔한 함정
ready-for-agent라벨에 대한 오해: spec에 이것이 붙고, 뜻은 '더 triage 할 필요 없음'입니다. 곧, 입장 자격이지 티켓이 아닙니다. 하지만 이 라벨을 폴링하는, 지켜보는 사람 없는 agent가 있다면 그 차이를 구분하지 못하고 spec 전체를 한 번에 끝내려 듭니다. 해법은 그 agent의 prompt에서 parent spec을 명시적으로 제외하거나,/to-tickets실행이 끝나면 라벨을 떼어냅니다.- 리팩터링 성격의 작업은 템플릿에 맞지 않음: 템플릿이 user story에 너무 기울어 있어서, 아키텍처 작업을 끼워 넣으면 '아무도 요구한 적 없는 이야기'가 됩니다. 대신 implementation-decisions와 testing-decisions 두 절에 기대고, 오래가는 아키텍처 결정은 ADR 형태로
grill-with-docs쪽에서 확정합니다. - 중복을 확인하지 않습니다: 같은 issue가 이미 올라와 있는지 tracker를 검색하지 않고, 따르고 있는 ADR을 걸어 주지도 않습니다. 자주 손대는 영역은 먼저 직접 검색해 두십시오.
- spec이 너무 크면 잘려 나갑니다: 거대한 spec은 tracker issue가 깔끔하게 돌려줄 수 있는 분량을 넘고, 게다가 되돌아갈 로컬 사본도 없습니다.
/to-spec과/to-tickets사이에서는 clear도 compact도 하지 마십시오.
Step 3 — tracer bullet으로 자르기
/to-tickets, 같은 창에서. 또는 /to-tickets #<spec_issue>. 계획이 대화 안에만 있고 spec으로 쓰이지 않았어도 됩니다. 대화를 그대로 읽습니다.
| 수평 슬라이스 (틀림) | 수직 슬라이스 (맞음) | |
|---|---|---|
| 티켓 한 장이 내놓는 것 | 변경의 한 계층(schema 전부 한 장, API 전부 한 장) | 가느다란 길 하나가 모든 계층을 꿰뚫음 |
| 착지한 뒤 | 모든 계층이 갖춰지기 전까지는 아무것도 움직이지 못함 | 그것만으로 demo 가능 |
| 인수 조건 | 다른 티켓이 가진 작업까지 손을 뻗어야 함 | 자기가 가진 것만 평가함 |
이것은 가장 자주 어겨지는 규칙이고, 대가는 실측되어 있습니다: 어떤 팀은 계층별로 자른 티켓 26장을 썼습니다 (corpus, producer, aggregator, selector). 평균적으로 티켓 한 장을 닫는 데 agent를 20번 돌렸습니다. 그중 약 4분의 3은 재작업이었습니다. 그들 자신의 회고는 모든 종류의 실패를 구현 품질이 아니라 수평 슬라이스로 되짚어 갔습니다.
해야 할 확인
티켓 한 장마다 한마디 물어보십시오 — "이 티켓이 끝나면 무엇을 demo 할 수 있는가?" 답으로 행동을 대지 못한다면 그것은 수평 슬라이스입니다. 티켓마다 demo path를 한 줄 덧붙이는 사람도 있는데, 모델을 수직 분해 쪽으로 밀 수 있다고 보고됩니다.
발행 전
Prefactoring: 먼저 '변경을 쉽게 만들고, 그다음 그 쉬워진 변경을 한다'에 해당하는 작업을 찾아 맨 앞에 놓습니다. 그런 다음 번호 매긴 목록을 건네고 추궁합니다: 알갱이 크기가 맞는지, 블로킹 엣지가 진짜인지, 합치거나 쪼개야 할 것은 없는지. 승인하기 전까지는 tracker에 아무것도 들어가지 않습니다 — 이 추궁 단계가 바로 되미는 자리입니다.
광역 리팩터링만이 유일한 예외
tracer-bullet 규칙을 깨는 형태가 하나 있습니다 — 기계적인 변경 하나인데 영향 범위가 codebase 전체에 미치는 경우(필드 이름 하나를 바꾸거나, 공용 타입 하나를 갈아 끼우는 일)입니다. 한 번의 편집으로 수천 개의 호출 지점이 깨지고, 초록으로 착지할 수 있는 수직 슬라이스는 없습니다. expand–migrate–contract로 갑니다: Expand — 새 형태를 옛 형태 옆에 덧붙일 뿐, 아무것도 망가뜨리지 않습니다. Migrate — 영향 범위에 따라 호출 지점을 묶음으로 나누어 옮깁니다. 한 묶음이 티켓 한 장이고, 모두 expand에 막혀 있으며, 옛 형태가 남아 있어 CI는 초록을 유지합니다. Contract — 호출자가 없어진 뒤에야 옛 형태를 지웁니다. 모든 migrate 묶음에 막혀 있습니다.
흔한 함정
- 세 줄짜리 변경이 티켓 12장으로 쪼개짐: 과도한 분해가 가장 흔한 마찰입니다. 추궁 단계에서 합치라고 하십시오. 더 근본적인 답은 이렇습니다 — 변경 전체가 context window 하나에 들어간다면, 이 skill 자체가 필요 없습니다.
- GitHub에서 sub-issue로 만들어지지 않음: 알려져 있지만 고쳐지지 않았고 (issue 554), Codex에서는 더 심합니다.
gh는 v2.94부터 네이티브로 지원합니다 —gh issue create --parent및gh issue edit --add-sub-issue. - 'Blocked by'가 본문에만 적힘: 같은 종류의 문제입니다 (issue 513). GitHub에는 네이티브
gh issue create --blocked-by가 있습니다. 블로커가 먼저 발행되므로 번호는 만들 때 반드시 얻을 수 있습니다. - 인수 조건이 아무것도 평가하지 못함: 하나하나에 대해 '어떤 관찰이 그것을 거짓으로 만드는가'를 짚고, 시작 commit에서 레드인지 확인하십시오.
- 티켓을 다 냈습니다, 그다음은? 자동 배정은 없습니다. 보드를 보고, 끝나지 않은 블로커가 없는 티켓이 몇 장인지 세어, 그 수만큼 agent session을 엽니다. 티켓 한 장에 완전히 새로운 context 하나, 사이에 clear.
Step 4 — 티켓 한 장에 session 하나
/implement https://github.com/you/repo/issues/12
왜 완전한 reference를 써야 하는가
/implement #2의 #2는 'agent에게 보이는 모든 번호 매긴 목록'을 기준으로 해석됩니다 — 새 session에서는 그것이 todo 파일이나 checklist일 수 있고, 직접 설정한 tracker가 아닐 수 있습니다. 게다가 아주 자신 있게 해석하면서 fail-closed 되지 않습니다. 그래서 틀려도 곧바로 알아채지 못합니다. 완전한 URL이나 owner/repo#2를 넘기고, 제목을 읽어 확인시킨 뒤에 시작하게 하십시오.
run 한 번의 다섯 박자
- ticket이나 spec을 읽고 seam을 도출
- 사전에 합의한 seam 위에서
tdd를 돌리고, 한 번에 red-green 슬라이스 하나 - 자주 typecheck 하고, 중간에는 테스트 파일 하나만 실행
- 끝으로 전체 테스트 스위트를 한 번 실행
- 마지막으로
code-review를 돌리고, 그다음 commit 하는 곳은 현재 branch
절대 하지 않는 일
계획을 다시 여는 일은 결코 없습니다. 인터뷰도 없고, 확인 라운드도 없고, 다른 방식을 제안하지도 않습니다. 상류에서 정해진 것이 입력이고, 그 일은 그것을 commit 하나로 바꾸는 것뿐입니다. 이것이 바로 '새 agent에게 『이걸 해줘』라고 치는 것'과의 차이입니다 — 후자는 만들면서 설계를 다시 합니다.
| 증상 | 설명 |
|---|---|
| 다 돌았는데 티켓은 열린 채이고 인수 조건에 체크가 되어 있지 않음 | 정확하고 예상대로입니다. implement에는 마무리 단계가 없고, commit에서 멈춥니다. 티켓은 직접 닫아야 합니다 — 이것은 의존 사슬에서 가장 세게 뭅니다. frontier의 정의가 '블로커가 모두 닫힘'이라서, 아무도 닫지 않으면 할 수 있게 되는 티켓은 영영 생기지 않습니다 |
| 모든 티켓을 한 번에, 병렬로 돌릴 수 있습니까? | 안 됩니다. 같은 checkout에서 여러 implement를 병렬로 돌리는 것은 '지원하지 않음'보다 나쁩니다. 어느 하루 오후 사이에 다른 session의 commit에 amend가 박히고, stash가 사라지고, commit이 엉뚱한 branch에 떨어졌다는 현장 보고가 있습니다. 커뮤니티 workaround는 worktree지만, stash는 여전히 공유입니다 |
| PR을 열 수 있습니까? | 내장되어 있지 않습니다. 현재 branch에 commit 하고, branch를 대신 열어 주지도 않습니다. 호출할 때 덮어쓰는 사람도 있습니다 |
| code-review가 내 변경이 보이지 않는다고 함 | 검토 대상은 diff <fixed-point>...HEAD, staged와 working tree는 제외합니다. implement는 commit 전에 review를 돌리므로, 중간 commit이 이미 있지 않은 한 그 diff에는 아무것도 없습니다. 먼저 commit 하고 나서 review |
| 티켓 한 장이 150k token을 태움 | 대개는 잘못 쓴 것이 아니라 티켓이 너무 큰 탓입니다. 한 번의 run에는 codebase 탐색, seam마다의 red-green, 전체 스위트, review가 들어가므로 100k token을 넘는 것은 정상입니다. 지렛대는 상류에 있습니다: 새 창 하나에 들어갈 만큼 티켓을 조정하십시오. 한 장이 계속 넘치면 쪼갤 일이지, effort를 올릴 일이 아닙니다 |
내장된 그 review를 일부러 쓰지 않는 사람도 있습니다 — 코드를 쓴 agent가 자기 코드를 심사하면 자기 해법을 편듭니다. 깨끗한 session에서 고정점을 상대로 따로 code-review를 돌리는 것은 합리적인 대안입니다.
Step 5 — red-green 엔진
tdd는 참고 자료이지 드라이버가 아닙니다: 루프의 규칙을 쥐고 있을 뿐, session을 돌리는 것은 다른 쪽입니다 (본인, 또는 implement).
Red-green
실패하는 테스트를 쓰고, 그것을 딱 통과시킬 만큼의 코드만 씁니다. 다음 테스트를 미리 쓰지 않습니다. refactor 단계는 없습니다 — 2026년 6월에 제거되었습니다. agent가 그것을 거의 실행하지 않는 데다, review와 implementation을 session을 나눠서 하는 편이 결과가 좋기 때문입니다. 리팩터링은 code-review의 몫입니다.
Vertical slice
seam 하나, 테스트 하나, 최소 구현 하나, 그리고 반복. 첫 cycle이 tracer bullet이고, 한 갈래 길이 끝에서 끝까지 통한다는 것을 증명합니다. 반대는 테스트를 전부 쓰고 나서 코드를 전부 쓰는 방식입니다 — 그것이 검증하는 것은, 상상 속의 행동이고, 사용자가 하는 일이 아니라 사물의 모양을 확인하는 것이며, 구현을 이해하기도 전에 하나의 테스트 구조 안에 당신을 묶어 버립니다.
Pre-agreed seam
규칙은 절대적입니다: 확인되지 않은 seam에는 테스트를 쓰지 않는다. 전체 체인에서는 seam을 to-spec 단계에서 미리 합의합니다. 단독으로 호출하면 그 자리에서 바로 물어봅니다.
| 안티패턴 | 나타나는 모습 |
|---|---|
| Implementation-coupled | 내부 함수 이름만 바꾸고 동작은 그대로인데 테스트가 깨진다. 자기 내부 협력자를 mock 하기, 호출 횟수를 단언하기, 인터페이스가 아니라 데이터베이스 질의로 검증하기 |
| Tautological | 기댓값이 코드와 같은 방식으로 계산되므로 테스트는 반드시 통과한다. 기댓값은 다른 곳에서 와야 한다: 이미 옳다고 알려진 리터럴, 손으로 계산한 예, spec |
| Horizontal slicing | 구현보다 먼저 테스트가 한 무더기로 들어와 있다 |
Mock을 쓰는 곳은 시스템 경계뿐: 외부 API, 시간, 무작위성. 파일 시스템이나 데이터베이스일 때도 있습니다. 자기 모듈을 mock 하지 마십시오.
흔한 함정
- "어느 test seam을 고를지 묻는데, 저는 뭘 골라야 할지 전혀 모르겠습니다": 가장 흔한 마찰입니다(issue 607). 프롬프트는 후보 seam의 이름만 늘어놓을 뿐, 각각이 무엇을 잡고 무엇을 놓치는지는 말해 주지 않습니다. agent에게 트레이드오프를 되물으십시오: component 층의 seam이 놓치는 것 중에서 integration seam이 잡아내는 것은 무엇이고 얼마나 느려지는지. 전체 체인이
to-spec단계에서 seam을 합의하는 이유가 바로 이것입니다. - 구현을 먼저 쓰고 테스트를 나중에 쓴다: 일어납니다. skill은 '그것과 함께 살아간다'는 방식으로 쓰였고, agent가 100% 지키게 만드는 지시는 없습니다. 어떤 슬라이스에서 정말 엄격함이 필요하다면 돌아가는 것을 지켜보십시오.
- 브라우저 테스트를 먼저 쓰고 제자리를 맴돈다: agent가 Playwright를 먼저 쓰고, 아직 없는 기능을 상대로 반복해서 돌리다가, 끝내 "테스트가 깨졌다"고 결론 내렸다는 보고가 있습니다. repo의 지시 파일에 선언하십시오: browser 테스트는 동작이 굴러가고 난 뒤에 쓴다.
- 당신의 다른 티켓들을 모른다: 티켓 하나를 놓고 돌리면 형제 티켓에 속한 작업을 신나게 제안합니다(issue 129). spec을 ticket과 함께 주면 도움이 되고, 처음부터 티켓을 제대로 잘라 두면 더 도움이 됩니다.
Step 6 — 두 축 리뷰
/code-review main
고정점은 당신이 주어야 합니다. 주지 않으면 넘겨짚지 않고 물어보며, ref가 풀리는지와 diff가 비어 있지 않은지를 먼저 확인한 뒤에야 sub-agent를 만듭니다.
| Standards | Spec | |
|---|---|---|
| 물음 | 제대로 했는가? | 한 것이 옳은 것인가? |
| 무엇을 읽는가 | repo가 스스로 적어 둔 규범, 그리고 내장 smell 기준 | 출처가 되는 issue 또는 spec |
| 무엇을 보고하는가 | 명문 위반(하드한 실패가 될 수 있음)과 smell(언제나 판단의 문제) | 빠졌거나 일부만 구현된 요구사항, 범위 확산, 잘못 구현된 요구사항 |
| 발견마다 인용해야 할 것 | 규범 파일과 조항, 또는 smell 이름과 hunk | spec의 그 줄 |
두 축은, 각자 자기 sub-agent 안에서 돌아가며, 서로의 추론을 보지 못합니다. 보고서 끝에는 '축별로 가장 나쁜 발견'을 적고, 축을 가로질러 종합 우승을 뽑는 일은 거부합니다 — 하나의 변경이 한 축은 통과하고 한 축은 떨어질 수 있기 때문입니다: 모든 관례를 지키면서 엉뚱한 것을 만든 코드는 Standards를 통과하고 Spec에서 떨어지며, 티켓대로 만들었어도 repo의 관례를 깨뜨린 코드는 그 반대입니다. 섞인 판정은 통과한 축이 떨어진 축을 가려 주게 만듭니다.
Smell 기준은 Standards 아래에 깔린 바닥입니다: Fowler 『Refactoring』 3장에 나오는 12개 code smell. 하나하나가 '…일 수 있다'는 휴리스틱 딱지일 뿐 결코 하드한 위반이 아니고, 모두 '그것이 무엇이고 어떻게 고치는가'로 서술되어 있어서, 발견이 당신 앞에 올 때는, 행동 하나를 이미 달고 옵니다. 당신의 linter가 이미 처리하고 있는 것은 두 축 모두 건너뜁니다.
흔한 함정
- 같은 이름의 내장 명령과 부딪힌다: 가장 많이 보고되었고 아직 고쳐지지 않았습니다. 내장된 쪽은 'diff에서 bug 찾기'이고, 이쪽은 규범과 spec 준수입니다. 둘 다 깔면 하나가 이기는데, 어느 쪽이 이길지는 설치 방식에 달려 있습니다.
- sub-agent가 다시 자기를 불러 agent가 더 늘어난다: 여러 사람이 여러 harness에서 재현했고, 한 번은 50개 이상까지 갔습니다. fork에서의 수정은 두 sub-agent brief에 각각 한 줄을 넣는 것입니다: "code-review를 부르거나 추가 agent를 만들지 말고, 이번 리뷰를 직접 수행할 것". 무인으로 돌릴 때는 agent 수를 지켜보십시오.
- 코드를 쓴 것과 같은 session에서 돌려야 할까? 새 session을 권합니다. 누군가 잘 표현했습니다: 같은 context에서 자기를 리뷰하는 것은 slash command를 단 확증 편향입니다.
- 발견을 믿어도 될까? 확인 없이는 믿을 수 없습니다. sub-agent의 출력은, 증거가 아니라 가설입니다. 두 보고서를 모아 주기는 하지만 한 건씩 파일로 돌아가 검증하지는 않으므로, 인용이 엉뚱한 곳을 가리키거나 영향을 부풀릴 수 있습니다. 발견마다 인용을 보고 나서 움직이십시오.
- 왜 돌릴 때마다 새 문제가 나올까? 수정은 새로운 표면을 만들고, 판단에 속하는 절반은 결정적이지 않습니다. 수렴은 보장되지 않습니다. 한 번의 pass를 단서 목록으로 삼아 명문 규칙이 뒷받침하는 것만 처리하고 손을 떼십시오 — "깨끗하다"고 할 때까지 돌리지 마십시오. 그럴 일은 없습니다.
Step 7 — 마무리와 루프
티켓 하나의 루프:
- clear context
/implement <ticket>(tdd실행은 그 안에서 돌아간다)- commit
/code-review <fixed-point>, 깨끗한 session에서- 티켓을 손으로 닫고 인수 조건을 맞춰 본다 — implement는 이 일을 해 주지 않는다
- frontier에서 다음 티켓을 집고 1단계로 돌아간다
리듬
- 매일: 본류. 티켓 하나에 session 하나, 사이에 clear.
- 며칠에 한 번:
/improve-codebase-architecture, 구조 부채를 새 과제로 바꿔 본류로 되돌린다. - inbound 작업이 있을 때:
/triage. 외부 제보가 없는 프로젝트라면 열 일이 거의 없다. - 기술을 보충해야 할 때:
/teach, 전용 디렉터리를 하나 연다.
잊지 말 것
체인 전체에서 유일하게, 아무도 대신해 주지 않는 일은, 티켓을 닫고 인수 조건을 맞춰 보는 일입니다. implement는 commit에서 멈춥니다. 의존 사슬을 앞으로 굴리려면 당신이 티켓을 닫아 주어야 합니다 — 그러지 않으면 frontier에 새로 할 수 있는 항목이 영영 나타나지 않습니다.
06
상황 색인, 언제 어느 것을 집을까
본류 밖의 skill은 모두 '특정 상황에서만 갈라져 나가는' 것입니다. 여기서는, 당신이 처한 상황에 따라 늘어놓습니다.
단독 — prototype
이 문제는 논의로는 결론이 나지 않는다
이것이 쓰는 것은, 물음 하나에 답하기 위한 일회용 코드입니다. 물음이 먼저 오고, 뒤에 오는 모든 것의 모양을 정합니다. 틀린 물음에 답하는 prototype은 아무리 보기 좋아도 순전한 낭비입니다. '일회용'은, 어떻게 쓰는가에 대한 제약이지 '반드시 없앤다'는 약속이 아닙니다: 테스트 없음, 굴러가는 것 이상의 오류 처리 없음, 추상화 없음, 영속화 없음.
두 갈래에서 나오는 산출물은 크게 다릅니다. '이 로직이나 상태 모델이 맞다고 느껴지는가?'에는, 공유 가능한 단일 HTML 파일이 돌아옵니다 — state panel, free-play 버튼, 탭식 내비게이션을 갖추고 전부 도메인 언어로 이름 붙어 있어서, 디자이너나 도메인 전문가에게 그대로 건네 직접 느껴 보게 할 수 있습니다. 뒤의 로직은 DOM을 건드리지 않는 깨끗한 순수 모듈이라, 검증되면 그대로 정식 코드로 끌어올릴 수 있습니다. '이건 어떻게 보여야 하는가?'에는 같은 route 위에 놓인, 크게 다른 여러 UI 변형입니다. 플로팅 하단 바로 전환합니다. 변형끼리 어긋나야 하는 곳은 색이 아닙니다. 구조입니다. 살짝 손본 card grid 세 개는 벽지이지 prototype이 아닙니다.
그것을 '단단하게 만들고' 있다고 깨닫는 순간, 이미 prototype을 만드는 것이 아닙니다. 테스트를 붙이고, 진짜 데이터베이스에 연결하고, '나중에 필요할지도'를 위해 일반화하는 일이 그것입니다.
산출물을 어떻게 처리할 것인가: 답(판정과 그것이 해결한 물음)은 오래 남는 곳에 둡니다. commit message, ADR, 구현 issue. prototype 자체는 지우지 않지만 main에도 넣지 않습니다. commit 하는 곳은 prototype/<name> branch, 절대 merge 하지 않습니다. 구현 issue에 포인터를 하나 남겨 둡니다.
함정: 정작 구현해야 할 때 agent가 prototype을 하라고 권합니다. 이름의 문제입니다. 흐름에 익숙하지 않은 agent에게는 '티켓이 생긴 뒤의 당연한 다음 단계'처럼 읽힙니다. 그리고 하나 더. app 전체를 prototype 하지 마십시오. 자연스러운 정지점이 없어서 관성으로 그대로 제품이 되고, '테스트도 오류 처리도 없는' 코드가 그대로 사용자 앞에 나갑니다.
단독 — research
외부 사실 하나가 결정을 막고 있다
이것이 재료로 삼는 것은 하나뿐입니다. 1차 자료입니다. 공식 문서, 소스 코드, 명세, 퍼스트파티 API. 모든 주장을 답을 가진 그 출처까지 거슬러 추적합니다. 대화 안에서는 답해 주지 않습니다. 출력은 파일 하나이고, 모든 주장에 링크가 붙습니다. 결정적인 수는 읽는 부분을 어디서 돌리느냐입니다. 백그라운드 agent.
research는 위임한 발품이지, 외주로 넘긴 생각이 아닙니다.
함정: 자기 자신의 두 번째를 만들어 냅니다(issue 530). skill은 호출한 쪽에 백그라운드 agent를 띄우라고만 하고 agent 종류를 묶지 않기 때문에, 실제로 뜨는 것은 같은 도구와 지시를 쥔 범용 agent이고, 그것이 또 하나를 띄웁니다. 누군가 측정한 값이 이렇습니다. research 작업 하나가 세 번 겹친 실행으로 약 450k token을 태웠습니다. 중복된 쪽은 삼십 분 뒤, 완전히 시야 밖에서 끝났습니다. 호출한 뒤에는 백그라운드 작업 목록을 보고 중복을 멈추십시오.
또 세 가지. 반대 방향의 실패가 있습니다. 전역 지시가 추가 위임을 금지하고 있으면 백그라운드 agent는 정중히 거절하고 skill은 조용히 아무것도 하지 않습니다. '신뢰도 높은 출처'는 모델 스스로의 판단이고 allowlist는 없습니다. 실제로 듣는 완화책은 이것입니다. 인용 두세 개를 무작위로 따라가 보는 것. 그것 자체가 아니라 '그것의 요약'에 도착했다면 그 실행은 실패입니다. 정지 기준이 없습니다. 범위는 스스로 책임져야 합니다. 하나의 API, 하나의 동작, 하나의 버전 주장이 'research X'보다 훨씬 나은 결과를 가지고 돌아옵니다.
research 파일은 ADR이 아닙니다: ADR은 남기고, research 파일은 다 쓰면 보관하거나 지웁니다. 오래된 research 파일은 없느니만 못하고, 이후의 모든 repo 읽기를 오염시킵니다.
단독 — diagnosing-bugs
뭔가 망가졌는데 이유를 모르겠다
여섯 단계: repro 만들기, 최소화하기, 가설에 순위 매기기, 프로브 심기, 회귀 테스트와 함께 고치기, 깨끗이 치우기.
'타이트'한 피드백 루프가 생기기 전에는 agent가 이론을 세우지 못하게 합니다. 이름이 붙은 명령 하나, 이미 한 번 돌려 본 것, 이 bug에서는 레드이고 고치면 그린이 되는 것. bug 보고를 받은 coding agent의 기본 행동은 코드를 읽고 추측하는 것인데, 이 skill이 그것을 막습니다. 레드로 만들 수 있는 명령이 없으면 Phase 2도 없습니다. 그 gate가 이 skill의 가치 전부입니다.
루프가 '있다'는 것이 목표가 아니라 '타이트'한 것이 목표입니다: 빠르고(초 단위), 결정적이고(매번 같은 판정), 날카롭고('crash 나지 않았다'가 아니라 정확한 증상을 단언), agent가 사람 없이 돌릴 수 있어야 합니다. 30초씩 걸리면서 flaky한 루프는 없는 것보다 나을 게 별로 없습니다. 간헐적으로 나는 bug에서 목표는 깨끗한 repro가 아닙니다. 재현율을 높이는 것입니다. 트리거를 루프로 돌리고, 병렬화하고, 부하를 걸고, sleep을 주입합니다.
루프를 만드는 사다리, 선호 순서
- bug에 닿을 수 있는 seam 위의 실패하는 테스트
- dev server를 향한 curl 또는 HTTP script
- fixture 입력을 준 CLI 호출, 그리고 알려진 정상 스냅샷과의 diff
- DOM, console, network를 단언하는 headless browser script
- 캡처 재생(저장해 둔 request, payload, event log)
- 일회용 harness(시스템의 최소 부분집합, 함수 호출 한 번)
- property 또는 fuzz 루프, '가끔 출력이 틀린다'를 다루는 것
- 그대로
git bisect run명령에 넘길 수 있는 bisect harness - differential loop(같은 입력, 구버전 대 신버전)
- human-in-the-loop 방식의 bash script, 최후의 수단
| Gate | 참이어야 하는 것 |
|---|---|
| Phase 2 진입 | 이름이 붙은 명령 하나, 이미 돌려 봤고, 출력도 붙여 놓았으며(민감한 값은 가림), 이 bug에서 레드가 되는 것 |
| Phase 3 진입 | repro가 재현될 것. 그리고, 최소화까지 되어 있을 것 — 남은 요소는 하나하나가 핵심적일 것 |
| Phase 4 진입 | 순위를 매긴 반증 가능한 가설 3개에서 5개, 각각 예측을 밝히고, 어느 하나를 시험하기 전에 먼저 보여 줄 것 |
| Phase 5 진입 | 프로브가 특정 예측에 대응하고, 변수는 한 번에 하나, 모든 debug log에 grep 가능한 태그가 붙어 있을 것 |
| 완료 | 원래 repro가 더 이상 재현되지 않고, 계측 장치는 모두 제거되었으며, 맞았던 가설이 commit message에 적혀 있을 것 |
함정: 직접적인 답 하나만 원하는 가벼운 질문에서도 발동합니다. 가장 많이 보고된 문제입니다(issue 578, 네 사람이 같은 모양을 보고). "진단하지 말고 바로 답하라"고 분명히 말하거나, 이 skill의 model invocation을 끄십시오. '성능 문제가 어디에 있는지'를 훑는 데에는 쓸 수 없습니다. 진단하는 대상은 이미 이름을 댈 수 있는 실패입니다. 또 하나. 수정을 쓰기 전에 멈춰서 묻지 않습니다. 사람이 확인하는 지점은 Phase 3 하나뿐입니다.
단독 — resolving-merge-conflicts
merge나 rebase 충돌에 갇혀 있다
이것은 충돌을 텍스트 문제로 다루기를 거부합니다. hunk 하나에 손대기 전에, 양쪽을 먼저 여기까지 되짚습니다. 1차 자료입니다. commit message, PR, 원래 issue. 그래서 이 skill이 고르는 것은 이것입니다. 두 의도. 두 덩이의 텍스트 사이에서 고르는 것이 아니며, 양립하는 곳에서는 양쪽을 모두 남깁니다. 정말로 양립하지 않을 때는 이번 merge가 밝힌 목표에 맞는 쪽을 고르고 그 맞바꿈을 말로 밝힙니다. 충돌을 덮으려고 새 동작을 지어내지 않으며, 도중에 포기하지 않습니다: merge는 반드시 완료된 commit까지 옮겨집니다.
repo 자신의 자동화된 검사를 찾아내어 commit 전에 돌리기도 합니다. merge는 git 안에서 '두 branch를 동시에 만족시키면서 양쪽 테스트는 모두 통과하지 못하는' 것이 가장 쉽게 나오는 자리이기 때문입니다.
덧붙이는 실무 지식: 충돌을 피하려고 병렬 작업 사이에서 '파일을 나눠 갖는' 일은 하지 마십시오. 얻는 것보다 드는 비용이 큽니다. 지킬 가치가 있는 유일한 규율은 이것입니다. 큰 리팩터링을 먼저 하기. worktree로 병렬 개발할 때, merge 해서 되돌리는 일은 그 변경을 쓴 session이 하는 것이 가장 좋습니다. 의도를 아는 것은 그 session뿐이기 때문입니다. 모두의 충돌을 마지막 agent 하나에 batch로 몰아주는 것은, 이 skill이 힘들게 다시 세우려는 것을 그대로 버리는 일입니다.
진입로 — improve-codebase-architecture
codebase가 썩어가고 있다
codebase를 훑어 심화 기회를 찾습니다 — 얕은 모듈(인터페이스가 그것이 감추고 있는 것과 거의 같은 정도로 복잡한 모듈)을 깊은 모듈로 바꿀 수 있는 지점입니다. 그 결과를 HTML 리포트로 정리하고, 고른 후보를 놓고 그릴링을 합니다.
코드는 절대 고치지 않습니다. run 전체가 내놓는 것은 'HTML 파일 하나와 대화 한 번'입니다. 리팩터링 자체는 나중에 다른 session에서 정상적인 구축 흐름을 타고 진행합니다. 이것이 이 skill을 리팩터링 도구가 아니라 점검이라고 부르는 이유이고, '아직 손댈 준비가 되지 않은' codebase에 돌려 볼 가치가 있는 이유이기도 합니다.
필터는 두 개: deletion test — 이 모듈을 지운다고 상상해 보십시오. 복잡도가 더 작은 인터페이스 뒤로 모이는지, 아니면 각 호출자 쪽으로 흩어지는지? '모인다'가 되는 사례만 카드로 올라갑니다. 또한 영역을 지정하지 않는 한, 최근 commit 이력을 먼저 읽어 스캔을 지금 변하고 있는 경로 쪽으로 기울입니다 — 아무도 건드리지 않는 코드에서의 심화는, 결코 실현하지 않을 리팩터링입니다.
강도 표시는 세 단계입니다. 'Strong'(deletion test를 명확히 통과하고 마찰도 실재함. 진지하게 볼 것), 'Worth exploring'(말은 되지만 보상은 코드가 앞으로 어디로 가느냐에 달림), 'Speculative'(완전성을 위해 나열했을 뿐, 대부분은 안심하고 무시해도 됨).
| 상황 | 어떻게 쓰는가 |
|---|---|
| 정기 유지보수 | 며칠에 한 번, 또는 짬이 날 때 돌려 기능과 기능 사이에서 구조가 썩는 것을 막음 |
| 큰 작업 전 | spec을 가리키며 "이 변경을 쉽게 하려면 어떻게 해야 하는가?"라고 물음. 이것이 가장 효과적인 prompt |
| Brownfield 감사 | 크고 구조가 없는 vibe-coded repo에 돌려, 실제로 어떤 모양인지 파악 |
| Legacy 테스트 작업 | 먼저 이것으로 빠진 seam을 찾아낸 다음, 테스트하기 어려운 코드에 테스트를 작성 |
함정: "아이디어 하나 때문에 한 시간이나 캐물었다"가 가장 목소리 큰 불만입니다 — 호출할 때 아예 "캐묻지 말고 바로 리포트를 달라"고 말하십시오. 리포트를 열었을 때 스타일도 그림도 없는 것은, 외부 리소스를 CDN에서 불러오는데 차단되어도 조용히 실패해 agent가 알아채지 못하기 때문입니다 (그 페이지를 렌더링하는 일은 없습니다). inline CSS와 손으로 쓴 SVG를 쓰라고 지시하십시오. 한 session에 후보 하나입니다. 이 skill이 "당신의 codebase는 문제없다"고 말하는 일은 거의 없습니다 — 전부 Speculative인 리포트는, 아무것도 찾지 못했다는 사실을 이 skill이 할 줄 아는 유일한 방식으로 알리는 것입니다.
진입로 — triage
남들이 issue를 잔뜩 던져 넣는다
자신이 만들지 않은 issue에만 씁니다. 가공되지 않은 bug 보고, 외부에서 온 feature request, 갑자기 나타난 외부 PR입니다. to-tickets skill이 만들어 내는 티켓은 구조상 이미 agent-ready이므로, 거기에 triage를 돌려 봐야 잘해야 헛수고입니다. 이 skill은 제안하고 기다립니다: 분류와 상태에 대한 판단을 이유와 함께 알려 주고, 지시하기 전에는 아무것도 적용하지 않습니다.
triage된 항목은 모두 마지막에 정확히 분류 역할 하나와 상태 역할 하나를 답니다. 분류는 두 가지, bug와 enhancement입니다. 상태는 다섯 가지입니다. needs-triage(당신이 평가해야 하는 것), needs-info(보고자를 기다리는 중. 답이 오면 needs-triage로 복귀), ready-for-agent(완전히 규격화되고 agent brief가 붙은 것), ready-for-human(같은 brief에 '왜 위임할 수 없는지'를 더한 것), wontfix(닫음, 이유는 기록되어 있음).
wontfix 라벨은 세 종류가 있고 그 차이가 중요합니다. 이유는 그중 하나만 지식 베이스에 기록되기 때문입니다: 이미 구현된 것은 그것이 이미 존재하는 위치를 가리키는 댓글을 남기고, out-of-scope에는 쓰지 않습니다 (그것은 이미 만들어진 기능이지 거절된 기능이 아니고, 써 넣으면 중복 검사를 오염시킵니다). 거절한 bug는 정중히 설명한 뒤 닫습니다. 거절한 enhancement는 out-of-scope 디렉터리에 파일을 하나 쓰고, 닫는 댓글에서 링크를 겁니다. 그 디렉터리는 거절된 개념 하나당 markdown 파일 하나입니다 (issue 하나당 하나가 아닙니다). 그리고 triage는 무엇이든 평가하기 전에 디렉터리 전체를 먼저 읽어, 키워드가 아니라 개념으로 대조합니다.
brief를 쓰기 전에 먼저 검증합니다: bug는 보고자의 절차대로 재현하고, PR은 checkout 해서 관련 테스트를 돌린 다음, 세 가지 결과 중 하나를 보고합니다 — 확인됨 (코드 경로 첨부), 재현 불가, 시도하기에는 세부가 부족함 (이 자체가 가장 강한 needs-info 신호입니다). 이 모든 것은 agent brief 품질을 높이기 위한 것이고, 그 brief는 정확하기보다 오래가도록 쓰였습니다: 타입, 시그니처, 동작 계약을 쓰고, 파일 경로와 줄 번호는 절대 쓰지 않습니다. issue는 몇 주씩 방치될 수 있고 그 밑에서 코드는 계속 움직이기 때문입니다.
함정: label은 자동으로 만들어지지 않습니다. 상태 다섯 개로는 부족하다는 것이 가장 자주 언급되는 빈틈입니다 (blocked, deferred, implemented 모두 요청이 있었지만 어느 것도 ship되지 않았습니다). backlog 전체를 한 번에 풀어놓고 돌리지 마십시오 — "주의가 필요한 것을 보여 달라"는 그 pass는 골라내기 위한 값싼 목록입니다. 한 번에 스무 개의 issue를 돌리면 agent는 그것을 조용히 증거의 바탕으로 삼아 버립니다. 게다가 이 skill은 issue 본문만 돌려주고 댓글은 돌려주지 않습니다.
진입로 — wayfinder
이 작업은 session 하나에 담기지 않는다
이 skill이 맡는 것은 agent session 하나에 담기에는 너무 큰 작업입니다. 말할 수 있는 것은 목적지이지만 경로는 아직 보이지 않습니다. 그것을 tracker 위의 공유된 한 장의 지도로 그리고, decision 티켓으로 구성한 다음, 한 번에 한 장씩 풀어 경로가 뚜렷해질 때까지 진행합니다.
계획은 하되 실행은 하지 않습니다. 티켓 한 장은 '풀리면 결정이 나오는' 질문 하나를 쥐고 있는 것이지, 실행해야 할 구축 조각이 아닙니다. 지도가 끝났다는 정의는 이렇습니다: 누군가 이것을 만들러 가기 전에 아직 결정해야 할 것이 아무것도 남아 있지 않습니다. 이 규칙은 agent가 가장 자주 어기는 규칙입니다.
이것과 grill-with-docs 사이의 경계는 session 개수이지 프로젝트 크기가 아닙니다: 대화 하나에 담기면 grilling을 씁니다 (더 싸고 더 좋습니다). 담기지 않을 때만 wayfinder입니다. 범위가 잘 잡힌 기능에 wayfinder를 꺼내 드는 것은 흔한 실수입니다.
지도에 실리는 네 가지: Destination — 끝까지 갔을 때 어떤 모습인가입니다. 그것을 어떤 티켓이 존재하기 전에 먼저 이름 붙입니다. Decisions so far — 닫힌 티켓 한 장에 한 줄씩, 각각 세부가 실제로 사는 곳으로 링크합니다. Not yet specified, 즉 전쟁의 안개입니다 — 다가오는 것은 보이지만 아직 정확히 표현할 수 없는 결정들입니다. 판단 기준은 그 질문을 지금 정확히 말할 수 있는가이지, 답할 수 있는가가 아닙니다. Out of scope — 목적지 바깥이라고 판정한 작업입니다. 닫고, 결코 졸업시키지 않습니다. 지도는 저장소가 아니라 색인이고, 결정은 자기 티켓 안에만 삽니다.
Frontier — '열려 있고, 막혀 있지 않고, 아직 아무도 맡지 않은' 티켓을 말합니다. session은 어떤 작업이든 시작하기 전에 티켓을 자신에게 assign 해서 맡습니다. 그래서 assignee가 곧 맡았다는 표시입니다. 티켓은 처음부터 끝까지 이름으로 부르고, 맨 번호는 쓰지 않습니다 — issue 번호가 늘어선 벽은 서술 속에서는 읽히지 않습니다.
| 유형 | 모드 | 언제 쓰는가 |
|---|---|---|
| grilling | HITL | 기본값. 이야기로 문제를 분명히 할 수 있을 때 |
| prototype | HITL | '이건 어떤 모습이어야 하는가' — 이야기로는 결론이 나지 않는 문제. 산출물은 티켓에서 asset으로 링크 |
| research | AFK | 작업 디렉터리 바깥의 사실이 결정을 막고 있을 때. 지도를 그릴 때 바로 쏘아 올려 병렬로 태워 없앰 |
| task | 둘 다 가능 | 결정할 것은 없지만 수작업이 하나의 결정을 막고 있을 때 — 권한 열기, 서비스 등록, 모양이 보이도록 데이터 옮기기 |
task — '결정하는' 것이 아니라 '하는' 유일한 유형입니다. 존재 이유는 어떤 결정의 블로킹을 푸는 것, 목적지를 전달하는 한 조각인 적은 결코 없습니다. 실무에서 가장 자주 어긋나는 유형입니다: agent가 이것을 구현 단계로 여기고 지도 안에서 제품 코드를 쓰기 시작합니다. research 티켓만은 '한 session에 한 장' 규칙의 유일한 예외입니다.
치명적인 함정이 세 가지 있습니다. 첫째, wayfinder session 도중에 agent가 프로덕션 코드를 쓰기 시작하는 것 — 가장 많이 보고되는 실패입니다. '계획만 하고 실행하지는 않는다'라는 기본값은 지도의 Notes에서 덮어쓸 수 있지만, 그 Notes를 쓰는 것은 agent입니다. 따라서 제약과 그 면제가 '제약받는 쪽'이 소유한 같은 파일 안에 함께 놓이게 됩니다. 어떤 사용자는 agent가 "이 지도는 실행을 포함한다"를 자기 Notes에 써넣고, 이후 session에서 그것을 자기 허가로 읽어들여 프로덕션 서버에서 작업을 시작하는 것을 지켜봤습니다. 둘째, 지도가 비워진 뒤에도 필요한 것은 /to-spec과 /to-tickets — decision 티켓은 지도가 닫힐 때 모두 함께 닫히고, 남는 것은 '링크된 결정으로 가득 찬 지도'이며 그것은 구축 계획이 아닙니다. 셋째, grilling 티켓을 병렬로 돌리지 마십시오. 두 session은 context를 공유하지 않으므로, 한쪽에서 방금 답한 질문을 다른 쪽에서 다시 받게 됩니다.
실측된 사례가 하나 더 있습니다: "티켓을 27장 그렸는데, 13장째에 이르자 나머지가 전부 말이 되지 않았다". 대응책은 두 가지입니다. 지도의 범위를 경계가 분명한 목적지 하나로 좁히는 것(잘 정의된 epic이 막연한 'V1 구현'보다 훨씬 낫습니다), 그리고 적극적으로 prototype 하는 것. 저자의 표현으로는 wayfinder는 'prototypemaxxing'이지 'planmaxxing'이 아닙니다.
단독 — handoff
무언가를 옮겨야 할 때
현재 대화를 한 편의 인수인계 문서로 압축합니다 — 워크스페이스가 아니라 OS 임시 디렉터리에 쓰이는 markdown 파일이며, 완전히 새로운 agent가 이것을 읽으면 곧바로 이어받을 수 있습니다.
이것이 사는 것은 이식성이지 압축이 아닙니다. 그래서 들리는 것보다 훨씬 좁은 용도입니다: 파일이 필요한 것은 작업이 이동해야 할 때뿐입니다. 트리거는 네 가지 — harness 교체, 다른 디렉터리나 repo로 이동, 동료에게 작업 넘기기, phase 도중에 발견한 곁가지를 분기해 내보내기.
가장 자주 건너뛰는 사용법은 분기입니다. 자신은 자기 session에 남은 채, 쌓아 둔 context의 복사본을 병렬로 일하는 두 번째 agent에게 넘깁니다. prototype 갈림길이 바로 이렇게 쓰입니다: 깊은 설계 대화 한복판에서 실행해 봐야만 풀리는 문제에 부딪혔는데, 힘들게 쌓아 올린 thread를 그 조사에 쓰고 싶지는 않습니다 — prototype session으로 handoff 하고, 답을 받고, 그 답을 가지고 돌아와, 원래 thread에서 인용합니다. 두 번의 건넘, 살아 있는 대화 하나, 다시 설명할 것은 없습니다.
무엇이 여행하는가: 문서는 살아 있는 thread(지금 무엇이 진행 중인지, 왜인지, 다음은 무엇인지)와 권장 skill 한 묶음을 가지고 갑니다. 비밀은 쓰기 전에 가려집니다. 이미 적혀 있는 것은 의도적으로 일절 가져가지 않습니다 — spec, 계획, ADR, issue, commit, diff는 모두 경로나 URL로 참조할 뿐 절대 복사하지 않습니다.
함정: 파일은 임시 디렉터리에 있고 경로가 길며 OS마다 다르므로, 경로를 물어보고 적어 둔 다음에 진행하십시오. session 사이에 temp를 지우는 환경도 있으니, 다음 session이 곧바로 시작되지 않는다면 직접 오래 남는 곳으로 복사해 두십시오. 다음 agent에게 넘기는 방법은 경로를 가리키는 것입니다. 요약을 shell 명령에 붙여 넣지 마십시오 — 특수 문자가 든 요약은 망가지고, 전형적인 실패는 조용한 잘림입니다. "what은 잡지만 why는 잡지 못한다"는 정당한 비판이므로, '다음 session은 무엇을 위한 것인가'를 파라미터로 넘기십시오. 그리고 검증되지 않은 믿음을 사실처럼 적어 두지는 않는지 살피십시오.
단독 — to-questionnaire
답은 다른 사람 머릿속에 있다
혼자서는 결정할 수 없는 사안을 한 부의 설문지로 바꾸어, 부족한 조각을 쥐고 있는 사람에게 넘깁니다.
캐묻는 대상은 '이번 발송'이지 주제가 아닙니다. 주제에 대해 당신을 인터뷰하는 것은 여기서 아무 의미가 없습니다 — 주제를 모른다는 것이야말로 다른 사람에게 써서 보내는 이유입니다. 그래서 언제나 답할 수 있는 두 가지만 묻습니다: 누구에게 보내는가(상대의 역할, 전문성, 나와의 관계 — 이것이 어투와, 문서가 스스로 얼마나 많은 context를 담아야 하는지를 정합니다), 그리고 무엇을 돌려받아야 하는가(혼자서는 해결할 수 없는 구체적인 결정이나 사실 — 이것이 결과물을 재는 체크리스트가 됩니다). 그다음은 전부 초안 작성입니다.
문서의 모양: 한 줄짜리 purpose, 그리고 '당신 머릿속에 한 번도 들어와 본 적 없는 사람'을 위한 짧은 context. 질문은 가장 중요한 것을 먼저, 주제별로 묶습니다. 한 질문에 하나의 생각, 복합 질문은 절대 만들지 않기. "모르겠습니다"라고 답해도 된다고 명시하기 — 표시된 불확실성은 쓸모가 있지만, 사실처럼 읽히는 자신만만한 추측은 쓸모가 없습니다. 마지막에는 catch-all 하나.
이것은 의도적으로 일절 분기하지 않고, 일절 여러 수신자를 받지 않습니다. 세 사람이 세 조각의 답을 쥐고 있다면 세 번 돌립니다. 가장 흔한 사용법은 막혀 버린 grilling입니다: 같은 대화 안에서 돌리십시오 — 이 skill에는 ingest 단계가 없고, grilling 뒤에 동작하는 것은 순전히 그 session이 이미 context에 들어 있기 때문입니다.
단독 — wait-what
방금 그 설명이 이해되지 않는다
agent가 방금 말한 것을 다시 한 번 팔아 봅니다: 빠져 있던 context를 채우고, 쉬운 말로 쓰고, 프로젝트의 CONTEXT.md에 있는 어휘를 사용합니다.
이 skill은 단 세 줄이며, 그것은 미완성 초고가 아니라 설계입니다. 장황함과 싸우는 skill은 길어지면서 실패합니다: 사백 줄짜리 '간결하게 쓰라'를 읽어도 모델은 여전히 장황해집니다. 모델이 읽는 것은 호소가 아니라 분량이기 때문입니다.
이름이 곧 메커니즘입니다. 맨 앞에 오는 단어는 wait입니다. "좀 더 간결하게"는 agent의 출력에 대한 지시라서, 모델은 '단어를 깎는' 방식으로 따르고, 그 결과 당신은 더 길을 잃습니다. wait가 가리키는 것은 당신의 상태입니다: "이해가 여기서 무너졌다"라고 말하는 것입니다. "짧게 하라"는 말을 들은 agent는 전보를 씁니다. "잠깐, 나를 놓쳤어요"라는 말을 들은 agent는 되돌아가 다시 설명합니다. 유행하는 해법은 하나같이 출력을 이름 붙이고, 그래서 모델은 더 짧지만 더 명확하지는 않은 어투로 과잉 교정합니다. 듣는 사람을 이름 붙이면 두 조각을 한꺼번에 얻습니다: 더 적은 말, 그리고 당신에게 없던 그 전제.
의도적으로 "다시 설명할 것은 그것"이라고 말하지 "직전 메시지"라고 말하지 않습니다 — 당신을 놓친 것은 대개 한 문단보다 크고, 얼마나 뒤로 돌아갈지는 agent가 정합니다. 진짜 해독제는 미리 공유 언어를 만들어 두는 것이고, wait-what이 고치는 것은 이미 어긋나 버린 그 한 건입니다.
단독 — teach
여러 날에 걸쳐 무언가를 배우고 싶다
이것을 실행한 디렉터리를 상설 학습 워크스페이스로 바꾸고, 일련의 자체 스타일을 갖춘 짧은 HTML 레슨으로 여러 session에 걸쳐 한 가지 주제를 가르칩니다.
모델이 이미 알고 있는 것에서 가르치지 않습니다. parametric knowledge는 믿을 수 없는 것으로 취급됩니다: 가르치기 전에 먼저 신뢰도 높은 자료를 찾아 자료 파일에 기록하고, 모든 레슨에서 그것을 인용합니다. 그리고 이것은 상태를 가집니다 — mission, 자료, 레슨, 학습 기록이 모두 파일 형태로 디렉터리 안에 살고 있습니다:
| 경로 | 무엇이 들어가는가 |
|---|---|
| MISSION.md | 왜 이것을 배우는가. 다른 모든 것이 여기에 매달립니다. 이것이 없으면 가장 먼저 이것이 생길 때까지 당신에게 묻습니다 |
| RESOURCES.md | 선별된 출처. Knowledge와 Wisdom(커뮤니티)으로 나뉩니다 |
| lessons/ | 번호가 붙은 레슨 — 가르침의 주된 단위 |
| reference/ | 압축된 치트시트, 알고리즘, 용어집 — 정말로 다시 찾아보게 되는 문서 |
| learning-records/ | ADR 형식의 '무엇을 확실히 배웠는가' 기록. 다음에 무엇을 가르칠지 정하는 데 씁니다 |
| assets/ | 재사용 가능한 구성 요소 — 첫 번째는 공용 stylesheet — 레슨들이 하나의 강좌처럼 보이게 합니다 |
| NOTES.md | 당신이 밝힌 교육 방식 선호 |
핵심 개념은 storage strength(장기 보존)이지 fluency(그 순간의 회상감 — 읽을 때는 통달한 것처럼 느껴지지만 일주일 뒤에는 사라집니다)가 아닙니다. 이것은 바람직한 어려움을 사용해 전자를 만듭니다. 지식이 먼저입니다 (이 단계에서 어려움은 적이며, 이해에 필요한 작업 기억을 잡아먹습니다). 기량은 그다음에 타이트한 피드백 루프로 단련합니다 (이 단계에서 어려움은 도구입니다). 레슨은 좀처럼 다시 읽히지 않지만 레퍼런스 문서는 다시 읽힙니다 — 그래서 한 레슨의 압축된 핵심은 레퍼런스 디렉터리에 속하며, 그것을 도입한 레슨 안에 묻히는 것이 아닙니다.
함정: 파일이 엉뚱한 곳에 쓰일 수 있으니 (issue 377, 어떤 사람의 레슨이 전역 skill 디렉터리에 쓰였습니다), 시작할 때 디렉터리 이름을 분명히 말하십시오. 쪽지 시험의 정답이 늘 첫 번째 선택지입니다(여러 모델에서 확인됨, 미수정. 어떤 기여자는 9개 레슨 33회가 모두 A에 몰렸다고 보고했습니다). 능력 평가 단계가 없습니다. 첫 메시지에서 자신의 기존 지식과 공백을 말해 두십시오. 간격 반복 일정도 없습니다. 복습하고 싶으면 직접 요청하십시오.
코드에만 쓰는 것이 아닙니다 — 기록을 보면 코드가 아닌 용도가 더 큰 비중을 차지합니다. 코드에서 가장 강한 용도는 언어를 처음부터 배우는 것이 아니라, 낯선 codebase나 새 팀의 기술 스택에서 방향을 잡는 것입니다. 저자는 멋진 조합을 하나 언급했습니다. 캐물리는 도중에 모르는 것에 부딪히면, grilling을 멈추고 배우러 가지 마십시오 — 학습 워크스페이스로 handoff 해서 거기서 배운 뒤, 돌아와 이어 가십시오.
단독 — wizard
사람만 할 수 있는 수동 절차가 있다
이것은 대화형 bash script를 생성해 사람을 한 단계씩 수동 절차에 따라 안내합니다 — 서드파티 서비스 연결, 일회성 마이그레이션 실행, 프로젝트를 상태 A에서 상태 B로 옮기기.
agent가 script를 쓰지만, 그것을 실행하는 일은 결코 없습니다. 실행은 각자의 기계에서 직접 합니다. 그래서 wizard는 그대로 따라 하기만 하는 설명서가 아니라, 프로세스를 구동하고 상태를 쥐고 있는 프로그램이며, 사람이 맡는 몫은 클릭과 붙여넣기, 그리고 Enter 누르기입니다. Stage는 '한 화면에 하나의 집중된 작업'이고, script는 stage 사이에서 터미널을 비웁니다.
script를 쓰기 전에 먼저 scoping: 아무것도 모른 채 묻는 대신 repo를 읽습니다 — 환경 파일, compose 파일, framework config, 그리고 CI 설정 안의 모든 secret과 변수 참조. 그 하나하나가 wizard가 만들어 내야 하는 값입니다. 그런 다음 순서를 매긴 stage 목록을 보여 주고 확인을 받은 뒤에야, 각 stage를 사람이 지나갈 정확한 경로에 대응시킵니다. 지금 UI가 어떻게 생겼는지 모를 때는 묻거나 문서를 찾아보며, 클릭을 지어내지 않습니다.
template이 이미 UX를 해결해 두었습니다: 진행 표시, 확인 게이트, 크로스 플랫폼 URL 열기, secret 가림 입력, 환경 파일 멱등 기록, CI secret 기록, 그리고 '무엇을 건너뛰어야 했는지'의 마무리 요약. 고정 라이브러리 쪽 절반은 어느 wizard에서나 같고, 손으로 고치는 일이 결코 없습니다. 일관성이 바로 핵심입니다. wizard를 쓰는 agent는 그것을 엔드투엔드로 실행하지 않고 정적 검증으로 대신합니다. 첫 실행은 직접 하는 것이고, 그 한 번이 그대로 테스트입니다.
함정: 도중에 이전 단계로 돌아갈 수 없습니다. 3번째 스테이지에서 잘못 입력하면 중단하고 다시 돌립니다 (다시 돌리는 비용은 싸고, 환경 파일에 이미 기록된 값은 기본값으로 되돌아옵니다). 프롬프트에서는 방향키에 bug가 있고(issue 741), backspace는 동작합니다. 서드파티 서비스의 상태를 조회하러 가지는 않습니다. API key는 모델 context에 들어가지 않습니다 — 다만 scoping 때 key를 채팅에 붙여 넣었다면, 그것은 붙여 넣은 다른 어떤 텍스트와도 마찬가지로 context 안에 있습니다.
어휘층 — codebase-design
모듈은 어떤 모양이어야 하는가
모듈을 설계할 때 쓰는 말을 고정하고, 하나하나를 정확히 정의하며, 느슨한 대체어를 금지합니다. 그리고 그로부터 도출되는 몇 가지 원칙을 밝힙니다.
| 용어 | 뜻 |
|---|---|
| Module | 인터페이스와 구현을 가진 모든 것. 의도적으로 규모와 무관 — 하나의 함수, 하나의 class, 하나의 package, 계층을 가로지르는 하나의 슬라이스 |
| Interface | 호출자가 올바르게 쓰기 위해 알아야 하는 모든 것: 타입 시그니처에 더해 불변식, 순서 제약, 오류 모드, 필수 설정, 성능 특성 |
| Depth | 인터페이스에 걸리는 지렛대. 깊음: 작은 인터페이스 뒤에 많은 동작. 얕음: 인터페이스가 구현과 거의 같은 정도로 복잡 |
| Seam | 거기를 편집하지 않고도 동작을 바꿀 수 있는 자리. 인터페이스의 위치 |
| Adapter | 어떤 seam 위에서 어떤 인터페이스를 만족시키는 구체적인 것. 이름이 가리키는 것은 재질이 아니라 역할 |
| Leverage | 호출자가 depth에서 얻는 것: 인터페이스를 한 단위 배울 때마다 더 많은 능력을 얻음 |
| Locality | 유지보수하는 쪽이 depth에서 얻는 것: 변경, bug, 검증이 한곳에 모임 |
Depth는 의도적으로 '구현 줄 수를 인터페이스 줄 수로 나눈 값'으로 정의하지 않습니다 — 그 지표는 구현을 더 비대하게 쓰도록 보상하기 때문입니다. 여기서 쓰는 것은 depth-as-leverage입니다.
네 가지 원칙: depth는 인터페이스의 성질이지 구현의 성질이 아닙니다. deletion test — 이 모듈을 지워서 복잡도가 사라지면 그것은 pass-through이고, 복잡도가 N 개의 호출자에게 다시 나타나면 그것은 제 몫을 하고 있다는 뜻입니다. 인터페이스가 곧 테스트 면이며, 그 바깥까지 테스트하고 싶어졌다면 모듈의 모양이 잘못된 것입니다. adapter가 하나면 가설상의 seam이고, adapter가 둘이어야 비로소 진짜 seam.
함정: 이것을 driver로 쓰지 마십시오(issue 449). "계속해서 미결 사항을 진행해"라는 지시를 받으면, agent는 찾을 수 있는 것 중 가장 동작처럼 보이는 것을 붙잡고, 이전 session에서 이미 훑은 코드를 다시 탐색하며, 한참을 돌린 뒤에야 무언가를 묻습니다. driver가 될 skill을 지목하고, 이 skill은 그 아래에 두십시오.
어휘층 — domain-modeling
말이 서로 부딪친다
이것은 설계를 진행하는 동시에 프로젝트의 ubiquitous language를 만들고 벼려 나갑니다 — 용어집과 충돌하는 표현에 이의를 제기하고, 모호한 말을 썼을 때 정확한 말을 끌어내며, 구체적인 시나리오로 하나의 관계를 경계가 또렷해질 때까지 압박 테스트합니다.
이것은 능동적인 규율이지 수동적인 것이 아닙니다. 그냥 CONTEXT.md를 읽어 어휘를 빌리는 것은 어떤 skill이든 할 수 있는 한 줄짜리 습관입니다. 이것은 모델을 바꾸고 있을 때 쓰는 것입니다. 이것이 바로 끼어드는 이유입니다: 용어가 정리되는 바로 그 순간, 대화 도중에 CONTEXT.md에 씁니다 — 배치 버전은 한 session의 요약이고, 실시간 버전은 그 session의 실제 산출물.
산출물 둘, 기준 둘. CONTEXT.md에 담기는 것은 용어(어떤 것이 무엇인지, 한두 문장)입니다. 기록 문턱은 '모호한 말이 정식 용어가 되는 순간'이고, 시점은 실시간입니다. 절대 담기지 않는 것은 구현 세부, spec, 메모장, 일반적인 프로그래밍 개념입니다. ADR에 담기는 것은 하나의 결정(한 문장에서 세 문장: context, 선택, 이유)입니다. 기록 문턱은 세 가지 모두 해당될 것 — 되돌리기 어려울 것, context가 없으면 뜻밖으로 느껴질 것, 실제 트레이드오프의 결과일 것 — 이며, 게다가 제안이지 기본값이 아닙니다.
정말로 기억해야 할 것은 CONTEXT.md의 그 규칙입니다. 실전에서 깨지는 것이 바로 그 규칙이기 때문입니다: 그것은 용어집이고, 용어집일 뿐입니다. 내버려 두면 모델은 'CONTEXT.md에 쓴다'를 '받은 답을 모두 영속화해도 된다'는 허가로 받아들이고, 파일은 굴러가는 spec이 되어 버립니다 — 이것은 이 skill에서 가장 많이 보고된 문제이며, 여러 모델에 걸쳐 나타납니다.
이 skill의 진가를 느끼게 하는 동작: 어떤 것이 어떻게 동작하는지 말하면, 코드를 뒤져 모순을 펼쳐 놓습니다 — "코드는 Order 전체를 취소하는데, 방금 부분 취소가 가능하다고 했습니다. 어느 쪽이 맞습니까?" 이렇게 해서, 어느 한쪽이 고쳐지기 전에 언어와 코드는 소리 내어 정렬되도록 강제됩니다. 제한: 코드와 이미 commit된 문서만 교차 참조하고, issue tracker는 뒤지지 않습니다. 그래서 몇 달 전에 이미 닫힌 issue 안에서 다 다투고 일부러 확정한 이름 충돌이 새것처럼 다시 올라옵니다.
함정: CONTEXT.md가 500줄 이상으로 커집니다 — 크기는 증상이지 병이 아닙니다. 곧바로 간결하게 줄이고 구현 세부를 없애라고 지시하십시오. 파일이 정말로 군더더기 없이 얇은데도, 독자가 동시에 머리에 담고 싶지 않은 두 영역을 여전히 다루고 있을 때에만 분할을 고려하십시오 — 비대해진 파일을 쪼개도 비대해진 파일이 여러 개 생길 뿐입니다. 자동 트리거는 이 skill의 가장 약한 부분입니다: 그릴링을 한 차례 끝까지 돌렸는데도 CONTEXT.md 파일이 전혀 바뀌지 않았다면 바로 그 일이 일어난 것입니다. 지목해서 지시하십시오. 사람의 검토를 거치지 않은, agent가 쓴 용어집은 없는 것보다 나쁩니다: 자신 있게 들리는 전설이 되어, 이후 session이 그것을 진실로 받아들입니다.
어휘층 — writing-for-agents
agent가 읽을 문서를 쓰려고 한다
skill, 지시 파일, spec, runtime prompt, README — agent가 읽는 문서라면 무엇이든 해당합니다. 포장은 달라도 쓰는 법은 같습니다.
이 skill의 기본 동작은 설명이 아니라 삭제입니다. agent에게 다른 agent용 지시를 쓰게 하면 분량의 대부분은 모델이 이미 아는 것을 설명하는 데 들어갑니다. 그 줄들은 하나같이 no-op입니다. context 값은 치르면서 행동은 하나도 바꾸지 않습니다. 이 참고 자료는 바로 그런 줄을 찾아내는 렌즈입니다. 그래서 값을 하는 곳은 빈 파일만이 아닙니다. 이미 가지고 있는 문서에서도 최소한 그만큼의 값을 합니다.
부담은 두 가지입니다. Context load 쪽은 항상 로드되는 재료가 agent의 창에서 치르는 비용입니다. 지시 파일의 한 줄, skill description, 트리거되든 아니든 매 turn context에 들어 있는 모든 것이 여기에 들어갑니다. Cognitive load 쪽은 비용을 무는 주체가 다릅니다. 사람에게 드는 비용입니다. 어떤 문서가 있는지, 언제 어느 것을 꺼내야 하는지 — 그 색인이 바로 당신입니다. 이것은 최소화할 비용이 아니라, 사람이 주도권을 쥐기 위해 치르는 값입니다. 이 둘이 머릿속에서 정리되면, 글을 쓸 때의 판단은 대부분 같은 맞바꿈을 자리만 바꿔 가며 하는 일이 됩니다.
다섯 개의 지렛대: Context pointer(context 안에 있으면서 context 밖의 재료를 지목하고 '언제 가지러 갈지'까지 부호화한 참조. agent가 그것을 통해 얼마나 확실하게 손을 뻗는지를 정하는 것은 가리키는 대상이 아니라, pointer에 쓰인 말입니다), Information hierarchy('파일 안의 절차'에서 '파일 안의 참고'로, 다시 'pointer 뒤에 둔 참고'로 올라가는 사다리), Completion criteria(조기 완료를 막는 방어선), Leading words(모델의 사전 학습에 이미 들어 있는 압축된 개념. 닻은 두 번 내립니다 — body에서는 실행을 위해, pointer에서는 트리거를 위해), Pruning(단일 진실 원천, 관련성, 그리고 한 문장씩 적용하는 no-op test).
no-op test는 미학이 아니라 행동으로 판정합니다: 그 줄을 지우고 agent의 행동이 달라지는지 물으십시오. 통과하지 못한 문장은, 문장째로 삭제합니다. 표현만 손보는 것이 아닙니다. 의견이 갈릴 때는, 그 문서를 돌려 보는 것으로 해결하십시오. 논쟁하지 마십시오. 판단 기준은 문서가 좋아지는 동시에 짧아지는 것, 그리고 남은 분량이 이렇게 적은가 하고 놀라게 되는 것입니다. 하나 더, 같은 말이 두 번 나오지 않는다는 것 (반복은 '이 문서는 한 번도 시험된 적이 없다'는 가장 확실한 징후입니다).
단독 — grill-me
아이디어는 있는데 아직 형태가 없다
이 skill이 다루는 것은 하나뿐입니다. 설익은 아이디어입니다. 그것을 놓고, 거기에 몸을 실을 수 있을 때까지 인터뷰합니다. 다 짜인 계획이 있어야 시작할 수 있는 것은 아닙니다. 그 계획을 만들어 내는 것이 바로 이 session의 용도입니다. 그리고 이 skill의 성격은 한마디로, 무상태입니다. 파일도 쓰지 않고 작업 공간도 남기지 않으며, 남는 것은 머릿속에서 더 날카로워진 판본뿐입니다. 주제가 코드일 필요도 없고 repo도 필요 없습니다.
plan mode는 꺼 두십시오. 이것은 agent에게 계획을 빨리 내놓으라고 재촉하는데, '질문 안에 머무른다'와 정확히 반대입니다.
제대로 돌아갈 때의 모습: 무언가에 이의를 제기하게 됩니다. 한 번도 되밀지 않은 session은 애초에 필요 없던 session입니다. 질문은 길게 이어지는 물방울이 아니라 '몇 번의 라운드'로 도착하고, 뒤쪽 라운드는 앞에서 한 말 위에 눈에 띄게 쌓입니다. 어떤 질문이 그동안 암묵적으로 내리고 있던 결정을 뒤집어 내기 때문에, 예상하지 못한 곳에 다다릅니다. 끝날 무렵에는 모든 선택을 그 자리에 없었던 사람 앞에서 변호할 수 있습니다.
라운드를 세십시오. 질문 수를 세지 마십시오. 46문항을 4라운드로 나누는 것이 평범한 한 판입니다. 200문항은 범위가 너무 넓다는 뜻이고, 지나치게 긴 session은 dumb zone, 곧 context window가 가득 차서 질문의 품질이 떨어지는 구간으로 떠내려갑니다. 캐묻기가 끝나고 하기로 마음을 굳혔다면, 새 session을 열지 마십시오. 그 대화의 context가 바로 가치입니다.
라우터 — ask-matt
어느 것을 써야 할지 모르겠다
이것은 추천하고, 거기서 멈춥니다. grill도 하지 않고, spec도 쓰지 않고, 파일도 열지 않고, 방금 지목한 skill을 대신 띄워 주지도 않습니다 — 손에 들어오는 것은 '다음에 무엇을 칠지'뿐이고, 치는 쪽은 사람입니다. 건네주는 사고의 단위는 flow: 하나의 skill이 아니라, 여러 skill을 가느다란 길 하나가 한 줄기 길입니다.
알아 두어야 할 정직한 한계. 이것은 지도입니다. 손으로 쓴 것이라 repo보다 뒤처지고, 이 pack의 skill만 압니다. 게다가 이런 일까지 벌어집니다. "skill의 절반이 설치되어 있지 않다"고 말합니다. 알려져 있지만 아직 고쳐지지 않았습니다. 라우팅되는 skill 대부분은 user-invoked이고, harness는 그것들을 agent에 주입하는 목록에 넣지 않으며, agent는 그 목록을 완전한 것으로 여겨 존재하지 않는다고 보고합니다. 그 skill들은 설치되어 있습니다.
그리고 이런 일도 있습니다. 다른 skill의 동작을 잘못 설명할 수도 있습니다: skill 본체가 아니라 자기가 가진 한 줄 요약에서 답하기 때문입니다. 어떤 상세 보고는 한 session 안에서 그런 사례를 세 번 추적했는데, 'thread를 spec으로 바꾸는 것'이라는 거친 인상만으로 to-spec를 건너뛰라고 권한 경우도 들어 있었습니다. 그 SKILL.md 파일은 한 번도 열리지 않았고, 그 대가로 진짜 seam 점검이 한 번 빠졌으며 잘라 낸 티켓은 작업량을 과소평가했습니다. 다른 skill에 대해 핵심적인 단언을 할 때는 먼저 열어 보게 하십시오 — 바로 그 SKILL.md.
자리매김: ask-matt은 이 묶음 전체 위에 있는 secondary source입니다. router와 SKILL.md 파일이 서로 어긋날 때, SKILL.md 파일 쪽이 옳습니다.
07
완전한 시나리오 네 편
본류 사례는 05절에 있습니다. 여기서는 그 밖에 가장 흔한 네 가지 상황을 다룹니다.
사례 A — 운영 환경에서 간헐적으로 나는 500
상황: 고객이 "가끔 전송을 누르면 500이 난다"고 알려 왔는데, 스스로는 재현하지 못합니다.
- 다른 사람이 알려 온 건이니 먼저 진입로를 탑니다:
/triage. 알려 준 절차대로 재현이 됩니까. 재현되지 않으면needs-info, 아니면 지금 쫓기로 결정합니다. - 지금 쫓기로 했다면, 새 session을 엽니다:
/diagnosing-bugs. 그리고 "먼저 빨개지는 루프부터 만들어 달라"고 분명히 말합니다.
Phase 1만이 진짜 관문이고, 지켜봐야 할 곳도 그곳뿐
이 skill이 먼저 건네야 하는 것은, 이미 실행했고 출력을 붙여 두었으며 이 bug에서 빨간 명령입니다. 간헐적인 bug에서 목표는 깨끗한 재현이 아니라, 재현율을 높이는 것. 빨간 명령이 없으면 Phase 2로 들여보내지 마십시오. 추측을 시작하려 하면 끌어당겨 되돌리십시오.
이다음은 기계적입니다. 최소화(남은 요소는 하나하나 왜 핵심적인지 말할 수 있어야 합니다), 3개에서 5개의 순위를 매긴 반증 가능한 가설(사람이 확인하는 유일한 지점), 꼬리표를 단 프로브 심기, 고치기 전에 회귀 테스트부터 쓰기, 뒷정리, 그리고 맞아떨어진 가설을 commit message에 적기.
알아 둘 갈림길이 하나 있습니다: 그 회귀 테스트를 놓을 올바른 seam이 없을 때는, 헛된 안심을 주는 얕은 테스트를 쓰지 말고 그렇다고 말해야 합니다. 'seam이 없다'는 사실 자체가 발견입니다. 넘길 곳은 improve-codebase-architecture.
사례 B — 아무도 정리하지 않은 legacy repo를 넘겨받다
상황: 8년 된 프로젝트에 막 합류했거나, vibe-coded된 repo를 넘겨받았습니다. ADR도 없고 도메인 언어도 없고 설계 원칙도 없습니다.
- 첫날:
/setup-matt-pocock-skills명령으로 tracker와 문서 배치를 잡습니다. - 첫날:
/grill-with-docs로, 이 기존 repo를CONTEXT.md파일로 세워 달라고 요청하십시오. 인터뷰 길이를 미리 각오하십시오. 아주 깁니다. 파일이 형태를 갖추기까지 50문항 이상 걸렸다는 보고도 있습니다. 그리고 능동적으로 방향을 잡아 주십시오 — 이 skill은 코드를 읽고 자기가 찾은 것을 물어보지만, '코드에 이미 있는 말 가운데 어느 것이 옳은 말인가'는 사람이 정합니다. - 둘째 날:
/improve-codebase-architecture를 부르고, 첫마디로 "캐묻지 말고 먼저 보고서를 주십시오"라고 말합니다. 전부 Speculative라면 사실은 아무것도 찾아내지 못했다는 뜻입니다. Strong 후보를 하나 고르십시오. - 둘째 날: 후보는 한 번에 하나씩. 그 후보를 대상으로 grilling 하게 하고, 산출물은 diff가 아니라 '결정'입니다. 그다음에
to-spec,to-tickets,implement. - 그 이후: 며칠에 한 번씩 아키텍처 점검을 다시 돌려 유지 보수로 삼습니다.
왜 이 순서인가
공용 어휘를 먼저 만들어 두면 아키텍처 점검의 출력이 훨씬 좋아집니다 — 후보가 'Order intake 모듈' 같은 여러분의 명사로 불리고, 'FooBarHandler'가 아니게 됩니다.
솔직한 기대치: 정말로 손을 쓸 수 없게 된 프로젝트에서는 "조금은 도움이 됐지만 그래도 부족하다"는 보고가 있었습니다. 8년 된 legacy codebase에서는 모델이 제자리를 맴도는 것을 본 사람도 있고, 같은 skill이 잘 정돈된 repo에서는 깔끔한 그림을 내놓습니다. 현재 이 사례를 전담하는 skill은 없습니다.
사례 C — 대규모 그린필드 프로젝트
상황: 새 제품 모듈을 처음부터 만들어야 하는데 경로가 전혀 보이지 않고, 한 번의 대화로 끝낼 수 있는 일이 아닌 것이 분명합니다.
- 먼저 다섯 개의
wayfinder:label이 존재하는지 확인하십시오 (없는 label을 쓰면gh명령이 그대로 실패합니다). /wayfinder. 가장 먼저 할 일은 destination에 이름을 붙이는 것입니다. 여기서 묻는 것은 '지도 전체의 목적지'이지 이번 session의 목적지가 아닙니다. 범위를 경계가 분명한 하나의 epic으로 좁히십시오. 'V1 구현'은 안 됩니다.- 너비 우선으로 grilling을 한 번 수행해 Destination, Decisions so far, 안개, Out of scope를 그려 냅니다. 안개와 티켓을 가르는 판단 기준은 그 질문을 '지금' 정확히 말할 수 있는지 여부입니다. 첫 grill에서 안개가 하나도 나오지 않으면 "이건 지도가 필요 없을 만큼 작은 일입니다"라고 말하며 멈춰야 합니다.
- research 티켓은 지도를 그리는 동안 곧바로 발사해 병렬로 태웁니다. 나머지 티켓은 한 번에 한 장씩. 자신에게 assign 해서 맡습니다.
- 한 장을 풀 때마다 resolution 코멘트를 붙이고, 티켓을 닫고, 지도에 한 줄을 남긴 다음 멈추십시오. 앞쪽의 안개를 걷어 내고, 지금 말로 표현할 수 있게 된 것을 새 티켓으로 졸업시킵니다.
- 지도가 비면:
/to-spec #<map_issue>(전달하는 것은 메인 지도이고, 개별 decision 티켓이 아닙니다). 그다음에/to-tickets,/implement.
치명적인 함정 세 가지는 06절 wayfinder 항목에 이미 나와 있습니다: agent가 정식 코드를 쓰기 시작한다는 것, 그리고 to-spec을 건너뛰지 말 것, grilling 티켓을 병렬로 돌리지 말 것.
사례 D — 코드와 전혀 관계없는 의사 결정
상황: 비즈니스 판단을 고민하는 중입니다 — 새 제품 라인을 낼지 말지, 제안서 가격을 어떻게 정할지, 글 하나의 논증 뼈대를 어떻게 세울지.
- 깨끗한 대화를 하나 엽니다 (어떤 repo 안에 있을 필요도 없습니다). plan mode를 끄고,
/grill-me. - 한 라운드씩 답하고, 번호를 붙여 한꺼번에 돌려줍니다. 너무 얕은 질문은 되밀고, 범위가 흔들리면 말합니다. "모르겠습니다"도 진짜 답입니다.
- '직접 보지 않으면 답할 수 없는' 질문을 만나면 그것은 ungrillable입니다. 코드가 아닌 상황에서는 대개 한 장짜리 초안을 먼저 만들거나, 표를 하나 먼저 계산하거나, 고객 한 명에게 먼저 물어보는 일입니다.
- '답이 다른 사람의 머릿속에 있는' 질문을 만나면, 같은 대화 안에서 마지막으로
/to-questionnaire. 그것을 그 사람에게 보내고, 답이 오면 다음 라운드를 엽니다. - 이것은 상태를 남기지 않습니다. 파일을 쓰지도, 워크스페이스를 남기지도 않습니다. 남는 것은 머릿속에 있는 더 날카로워진 판뿐입니다.
08
알려진 함정 목록
'먼저 보게 되는 증상' 순으로 정렬했습니다. 심각은 돈이나 시간을 낭비하게 된다는 뜻입니다.
| 증상 | 심각 | 해법 |
|---|---|---|
| agent가 일부 skill이 설치되어 있지 않다고 말함 | — | user-invoked skill은 모델의 목록에 들어가지 않습니다. 설치되어 있으니 그대로 입력하면 됩니다. 기준은 .claude-plugin/plugin.json |
gh 명령이 label이 없다고 함 | — | setup 명령은 label을 만들지 않습니다. 직접 gh label create 명령을 한 번 실행하십시오 |
| 인터뷰가 질문을 한꺼번에 다 내놓고 추천 답안도 없음 | — | grilling 또는 domain-modeling이 로드되지 않았습니다. agent에게 "어떤 skill을 로드했는지" 물어보십시오 |
인터뷰는 좋은데 CONTEXT.md 파일이 바뀌지 않음 | — | domain-modeling이 로드되지 않았습니다. 이름을 직접 지목해 부르십시오 |
CONTEXT.md 파일이 500줄 이상으로 불어남 | — | 구현 세부 사항을 흡수했습니다. 간결하게 줄이고 구현 세부 사항을 제거하라고 직접 지시하십시오 |
| spec 읽기가 계속 잘림 | 심각 | 두 단계 사이에서는 clear나 compact를 하지 마십시오. 같은 창에서 끝까지 돌리십시오 |
| 세 줄짜리 변경이 티켓 12장으로 쪼개짐 | — | 추궁 단계에서 합치라고 지시하십시오. 정말 작으면 그냥 implement 하고 이 skill은 쓰지 마십시오 |
| 레이어마다 티켓 한 장씩으로 잘림 | — | 티켓마다 "끝나면 무엇을 demo 할 수 있는가"를 묻고, 행동을 답하지 못하면 수평 슬라이스입니다 |
| sub-issue로 만들어지지 않고 blocked-by가 본문에만 적힘 | — | 알려진 미수정 사항입니다. 나중에 직접 gh issue create --parent, --add-sub-issue, --blocked-by |
| 인수 조건이 작업 전에 이미 통과됨 | — | 각 항목마다 "어떤 관찰이 이것을 거짓으로 만드는가"를 묻고, 시작 commit에서 레드인지 확인하십시오 |
/implement #2 명령이 전혀 상관없는 일을 함 | 심각 | #2라는 표기는 '눈에 보이는 번호 목록이면 무엇이든'에 대해 해석됩니다. 전체 URL을 전달하고 제목을 읽어 보게 하십시오 |
| 다 돌았는데 티켓이 열린 채이고 인수 조건에 체크가 안 됨 | — | 예상된 동작이며, 마무리 단계가 없습니다. 티켓을 직접 닫으십시오. 그래야 의존 사슬이 앞으로 나아갑니다 |
| code-review가 내 변경이 보이지 않는다고 함 | — | HEAD와 diff를 뜨기 때문에 commit 하지 않은 것은 빠집니다. 먼저 commit 하고 나서 review |
| implement를 여러 개 병렬로 돌리면 git 상태가 이상해짐 | 심각 | 같은 checkout에서는 지원하지 않습니다. worktree를 쓰되 stash는 여전히 공유됩니다 |
| 내장 code-review와 이름이 겹침 | — | 내장된 쪽을 제거하거나 fork 해서 새 이름으로 바꾸십시오 |
| review의 sub-agent가 agent를 더 만들어 냄 | 심각 | 알려진 미수정 사항이며, 한 번은 50개 이상까지 늘었습니다. 무인으로 돌릴 때는 agent 수를 지켜보십시오. fork에는 재생성 금지 한 줄을 추가하십시오 |
| review를 돌릴 때마다 새 문제를 찾아냄 | — | 수렴한다는 보장이 없습니다. 단서 목록으로 삼아 명문화된 규칙이 뒷받침하는 것만 처리한 다음 손을 떼십시오 |
| research가 450k token을 태움 | 심각 | nesting bug (issue 530)로, 자기 자신을 하나 더 만듭니다. 호출한 뒤 백그라운드 작업 목록을 확인하십시오 |
| 한마디 답만 원하는데 재현 환경을 만들러 감 | — | "진단하지 말고 바로 답하십시오"라고 말하거나, 그 skill의 model invocation을 끄십시오 |
| 구현을 먼저 쓰고 테스트를 나중에 쓴다 | — | 일어납니다. skill은 이 점을 안고 살아갑니다. 어떤 슬라이스에서 엄격하게 가려면 지켜보며 돌리십시오 |
| 브라우저 테스트를 먼저 쓰고 제자리를 맴돈다 | — | repo의 지시 파일에 선언하십시오: browser 테스트는 동작이 작동한 다음에 씁니다 |
| 아키텍처 보고서를 열면 스타일도 그림도 없음 | — | 외부 CDN이 차단됩니다. inline CSS와 손으로 쓴 SVG를 쓰게 하십시오 |
| 한 시간 동안 캐묻기만 하고 선택지를 주지 않음 | — | 호출할 때 "캐묻지 말고 바로 보고서를 주십시오"라고 말하십시오 |
| 어휘층에 "시작"이라고 말했다가 100k token을 태움 | 심각 | 여기에는 흐름이 없습니다. driver skill을 하나 지목해 그 아래에 두십시오 |
| wayfinder의 agent가 정식 코드를 쓰기 시작함 | 심각 | Notes는 '계획만 하고 실행하지 않는다'를 덮어쓸 수 있는데, 그 Notes는 agent가 씁니다. Notes를 먼저 읽으십시오 |
| 27장의 티켓 중 13장째에 이르니 전부 말이 안 됨 | — | 범위를 경계가 있는 하나의 epic으로 좁히고, 적극적으로 prototype 하십시오 |
| grilling이 질문마다 세 단락이라 지침 | — | reasoning effort를 낮추고 전역 지시 파일에 쉬운 문장 하나를 추가합니다. 미해결 |
| handoff 파일이 사라짐 | — | 임시 디렉터리는 지워집니다. 경로를 물어보고, 필요하면 직접 오래 남는 위치로 복사하십시오 |
| 강의가 전역 skill 디렉터리에 기록됨 | 심각 | issue 377. 디렉터리 이름을 분명히 말하고, 첫 강의가 어디에 놓이는지 먼저 확인하십시오 |
| 쪽지 시험 정답이 항상 A | — | 알려진 미수정 사항입니다 (33번 모두 적중). 위치는 의미 없다고 여기거나, render 할 때 섞어 주는 컴포넌트를 요구하십시오 |
| wizard에서 오타를 내고 이전 단계로 돌아가고 싶음 | — | 이전 단계로 돌아갈 방법이 없습니다. 중단하고 다시 돌리십시오 (저장된 값이 기본값이 됩니다). 방향키에는 bug가 있으니 backspace를 쓰십시오 |
직접 고친 SKILL.md가 업데이트 후 사라졌습니다 | 심각 | npx skills update 명령이 덮어쓰고, plugin은 읽기 전용. 장기적 동작은 자신의 지시 파일에 기록 |
09
자신의 지시 파일에 넣으면 좋은 것
이것은 '공식 경로로 커스터마이즈하는' 방식입니다 — skill 파일을 고치면 덮어써지지만 여기는 덮어써지지 않습니다. 전체를 그대로 복사하면 됩니다. 붙여 넣을 곳은 자신의 CLAUDE.md 또는 AGENTS.md.
## Agent behaviour
- When grilling, ask one question at a time.
- Do not start implementing without my explicit permission.
- Browser and end-to-end tests are written after the behaviour works,
never as the first red test.
- Keep questions and recommendations short. One paragraph maximum
per question.
- When a skill asserts something about another skill's behaviour,
open that skill's SKILL.md before acting on it.
- code-review sub-agents must not invoke /code-review or spawn
additional agents; perform the review directly.
각 줄이 막는 것
- 한 번에 한 질문: 한 번에 한 문제씩 가는 리듬으로 되돌립니다. 천천히 읽는 사람, 제2 언어로 읽는 사람, 집중을 위한 발판이 필요한 사람에게 권합니다.
- 허락 없이 구현을 시작하지 않기: grilling이 frontier를 비운 뒤 스스로 만들기 시작하는 것을 막습니다. 약한 모델이나 낮은 effort일 때 일어납니다.
- 브라우저 테스트는 마지막에 쓰기: tdd가 Playwright를 먼저 써 놓고 제자리를 맴도는 것을 막습니다.
- 질문과 제안은 짧게: wayfinder와 grilling의 장황함을 덜어 줍니다.
- 먼저 열 것은 주장의 대상이 된
SKILL.md: ask-matt가 자기 요약으로 다른 skill을 잘못 설명하는 것을 막습니다. - review의 sub-agent는 또 agent를 만들지 않기: 통제를 벗어난 fan-out을 막습니다. fork 한 사용자가 실제로 효과를 확인한 줄입니다.
10
핵심 용어
이 단어들은 skill 전체가 함께 쓰는 언어입니다. 뜻을 모르면 skill의 출력도 읽어 낼 수 없습니다.
| 용어 | 정의 |
|---|---|
| Seam | 그곳을 고치지 않고도 동작을 바꿀 수 있는 자리. 테스트는 seam 위에 산다. seam은 인터페이스의 위치 |
| Pre-agreed seam | 코드를 쓰기 전에 미리 합의해 둔 seam. 테스트가 오래가는 이유 — 아래의 구현을 다시 써도 테스트는 그대로 |
| Tracer bullet | 모든 층을 관통하는 가늘지만 완전한 한 갈래 길. 안착하는 순간 단독으로 demo 가능 |
| Vertical / horizontal slice | 수직은 한 갈래 길이 모든 층을 관통하는 것 (맞음). 수평은 한 번에 한 층 (틀림, 가장 흔한 실패) |
| Deep / shallow module | 깊은 쪽은 작은 인터페이스 뒤에 많은 동작. 얕은 쪽은 인터페이스가 구현과 거의 같은 복잡도 |
| Deletion test | 이 모듈을 지웠다고 상상해 보기: 복잡도가 더 작은 인터페이스 뒤로 모이는지, 남길 값어치가 있는 쪽. 아니면 호출하는 쪽으로 흩어지는지, 그렇다면 pass-through |
| Locality / Leverage | Locality는 유지보수하는 쪽이 얻는 것 (변경이 한곳에 모임). Leverage는 호출하는 쪽이 얻는 것 (인터페이스를 한 단위 배울수록 더 많은 능력) |
| Design tree / Frontier / Round | 설계 트리는 결정에 결정이 매달린 것. frontier는 전제 조건이 모두 풀린 결정의 집합. 1 round는 frontier 전체를 한 번에 다 묻는 것 |
| Grillable / ungrillable | 말로 풀어낼 수 있는 질문. 그에 비해 반응할 대상이 있어야 하는 질문 (후자는 prototype으로) |
| Fog of war | wayfinder 지도 위에서 '올 것이 보이지만 아직 정확히 말로 옮기지 못하는' 결정 |
| Decision ticket | wayfinder의 단위: 질문 하나를 쥐고 있는 것 (풀리면 결정이 나옴). 이것은 결코 실행할 구축 슬라이스가 아님 |
| Destination | wayfinder 지도 한 장 전체의 종착점 모습. 지도를 그리는 첫 동작이 그것에 이름을 붙이는 일 |
| Spec / Ticket | spec은 목적지와 그것을 고정하는 결정 (남김). ticket은 거기에 이르는 실행 단계 (쓰고 나면 버림) |
| Primary / secondary source | 1차 자료는 대화 그 자체, commit, 공식 문서, 소스 코드. 2차 자료는 모든 요약. 충돌하면 1차 자료가 기준 |
| Context pointer | context 안에 있으면서 context 밖의 자료를 지목하고 '언제 가지러 갈지'까지 새겨 넣은 참조 |
| Progressive disclosure | 특정 분기에서만 필요한 참고 자료를 pointer 뒤로 옮겨 주 파일을 읽을 수 있게 유지하는 것 |
| Context load / Cognitive load | 앞의 것은 늘 적재되는 자료가 모델 윈도우에서 치르는 비용. 뒤의 것은 '어떤 문서가 있고 언제 써야 하는지'를 사람이 지는 비용 |
| No-op | 지워도 agent의 동작이 달라지지 않는 한 줄. context를 치르고도 아무 동작도 바꾸지 않음 |
| Leading word | 모델의 사전 학습에 이미 들어 있는 압축된 개념 (tight, red, tracer bullet). agent가 그것으로 생각함 |
| Storage strength / fluency | 장기 보존. 그에 비해 그 순간의 회상감 (후자는 읽는 동안에는 통달한 느낌, 일주일 뒤에는 사라짐) |
| Smart zone / dumb zone | context window에 아직 여유가 있음. 그에 비해 품질이 떨어질 만큼 이미 찬 상태 |
| HITL / AFK | 사람이 루프 안에 있음 (살아 있는 주고받기로만 풀림). 그에 비해 자리에 없어도 끝까지 도는 일 |
| Phase boundary | 두 덩어리의 작업 사이. "내 context를 어떻게 할까"를 물어야 할 유일한 지점 |
| Expand–migrate–contract | 광역 리팩터링의 3단계: 새 형태를 옛 형태 옆에 더하기, 호출 지점을 나눠서 옮기기, 부르는 쪽이 없어진 뒤에 옛것 지우기 |
11
일곱 가지 안티패턴
이 도구 모음이 가장 자주 잘못 쓰이는 방식입니다.
- 수동적인 grilling. "동의"를 마흔 번 답하고 나면 agent가 쓰고 당신은 고개만 끄덕인 계획이 나옵니다. 한 번도 되밀지 않은 session은 애초에 필요 없던 session입니다.
- to-spec과 to-tickets 사이에서 clear나 compact를 하기. 캐물어 끌어낸 것의 대부분은 그 context window 안에만 있습니다. 여기서 한 번 자르면 spec은 당신이 실제로 결정한 것을 조용히 빠뜨립니다.
- 자기가 만든 티켓에 triage를 돌리기.
to-tickets쪽에서 나오는 티켓은 구조상 이미 agent-ready입니다. triage는 다른 사람이 던져 넣은 일을 받는 진입로입니다. - 범위가 잘 잡힌 기능에 wayfinder를 꺼내 들기. 판단 기준은 session 수입니다. 한 번의 대화에 담기면
grill-with-docs를 쓰십시오. 더 싸고 더 좋습니다. - 어휘층을 드라이버로 쓰기. 예를 들어
codebase-design또는domain-modeling쪽에 "시작하자"라고 하면 agent는 스스로 절차를 지어내고 token을 잔뜩 태웁니다. driver를 지목하십시오. - review를 코드를 쓴 것과 같은 session에서 돌리기. 같은 context에서 자기를 심사하는 것은 review가 아니라 slash command를 붙인 확증 편향입니다.
- 커스터마이즈하려고
SKILL.md파일을 고치기. 업데이트에 덮어써지고 plugin 설치본은 애초에 읽기 전용입니다. 장기적 동작은 자신의 지시 파일에 적으십시오.
메타 안티패턴이 하나 더
이것을 '절차가 있으니 생각할 필요가 없다'로 받아들이는 것. 저자가 README에서 취하는 입장은 그 반대입니다. 그렇게 절차를 넘겨받는 식의 방법은 도와주는 대가로 당신의 통제권을 가져가고 절차 자체의 bug를 고치기 어렵게 만듭니다. 이 skill 묶음은 일부러 작고 고치기 쉽고 조합할 수 있게 만들어졌습니다. 산출물의 품질은 질문의 수가 아니라 당신이 내놓은 답의 품질을 따라갑니다.
12
14일 학습 계획
하루 30분에서 60분 정도, 대상은 자신의 진짜 프로젝트.
| 일 | 할 일 | 통과 기준 |
|---|---|---|
| 01 | 그냥 세 가지 밑바탕 개념을 훑기. plugin 또는 skills.sh 설치 (둘 중 하나). repo 하나에서 setup 실행. label 만들기 | docs/agents/ 아래에 파일 세 개가 있음. 지시 파일에 ## Agent skills |
| 02 | /grill-me 명령으로 코드가 아닌 결정을 캐묻기. '되밀기'를 의식하며 연습 | 되밀기 3회 이상. 그 자리에 없던 사람에게 모든 선택을 변호할 수 있음 |
| 03 | /grill-with-docs 명령으로 기존 repo에 작은 기능 하나를 인터뷰 | CONTEXT.md 파일이 진행 중에 한 줄씩 자람. ADR은 0에서 1건 |
| 04 | 같은 대화에서 이어서 /to-spec. seam과 out-of-scope 두 절을 제대로 읽기 | spec 안의 모든 결정을 자신이 내린 기억이 있음 |
| 05 | 같은 창에서 이어서 /to-tickets. 추궁 단계에서 티켓마다 "무엇을 demo 할 수 있는지"를 묻기 | 모든 티켓이 동작을 demo 할 수 있음. 맨 위 티켓에는 막는 것이 없음 |
| 06 | /implement 명령으로 첫 티켓을 처리 (전체 URL). 처음부터 끝까지 trace 보기 | trace 안에서 tdd 호출이 보임. commit까지 감 |
| 07 | 새 session에서 /code-review main을 실행. 인용을 하나씩 추적 | 따로 나뉜 보고서 두 개. 발견 하나 이상을 반박함 |
| 08 | 그냥 codebase-design 용어집을 절차가 아니라 사전으로 다루기 | 설계 대화에서 component, service, boundary가 더는 나오지 않음 |
| 09 | '말로 풀리지 않는' 질문을 만나면 돌릴 것은 /prototype | 공유할 수 있는 HTML 파일 하나 또는 구조적으로 다른 몇 가지 변형. 답은 한 줄 |
| 10 | 진짜 bug 하나에 /diagnosing-bugs를 돌리기. Phase 1의 gate를 주시 | 첫 이론보다 먼저 레드 상태의 명령 출력을 봄 |
| 11 | /improve-codebase-architecture, "보고서 먼저"라고 말하는 것을 잊지 말 것. Strong 후보 하나 고르기 | HTML 보고서. 후보 하나가 캐묻기를 거쳐 결정이 됨 |
| 12 | /handoff 명령으로 '분기'를 한 번 연습. 주 대화는 남겨 두고 병렬 session 하나 열기 | 원래 session은 그 자리에 그대로. 새 agent는 다시 설명하지 않아도 바로 착수 |
| 13 | 연습할 것은 /wait-what 및 /to-questionnaire. 그리고 09절 내용을 지시 파일에 써 넣기 | 다시 설명한 것이 '더 짧고 더 명확'해짐. 설문지는 그대로 보낼 수 있음 |
| 14 | 정말 너무 큰 일 하나를 골라 돌릴 것은 /wayfinder. 범위를 경계가 있는 epic 하나로 좁히기 | destination이 어떤 티켓보다 먼저 적혀 있음. 열려 있는 티켓은 모두 하나의 질문으로 읽힘 |
이후의 리듬은 이렇습니다. 본류는 매일, 아키텍처 점검은 며칠에 한 번, /teach는 역량을 보충해야 할 때 전용 디렉터리를 엽니다.
13
한 페이지 치트시트
repo마다 한 번
/setup-matt-pocock-skills— tracker, label, 문서 배치
본류(아이디어에서 ship까지)
/grill-with-docs— repo 있음, 단일 session으로 끝낼 수 있음/to-spec— session을 넘길 때만 필요. 같은 창에서, clear 하지 말 것/to-tickets— tracer bullet으로 자르고 블로킹 엣지 선언. 같은 창/implement <전체 ticket URL>— 티켓 하나에 session 하나, 사이에 clear/code-review <fixed-point>— 깨끗한 session에서 실행, 먼저 commit
진입로
/triage— 남이 던져 넣은 issue/wayfinder— session 하나에 담기지 않음. 비운 뒤 돌아갈 곳은/to-spec/improve-codebase-architecture— 며칠에 한 번 하는 구조 점검
언제든지
/grill-me— repo 없음, 파일 없음, 주제가 코드가 아니어도 됨/prototype— 말로는 결론이 안 나는 설계 문제, 한 번에 하나씩/research— 외부 사실. 백그라운드로 실행, 두 개가 생기지 않았는지 확인/diagnosing-bugs— 어려운 bug. 레드 루프가 생긴 뒤에야 추측/resolving-merge-conflicts— 이미 충돌에 빠져 있을 때/wizard— 사람만 할 수 있는 수동 절차/handoff— 옮길 것이 있거나 곁가지로 분기할 때/to-questionnaire— 답이 다른 사람 머릿속에 있을 때/wait-what— 방금 그 대목을 못 알아들었을 때/teach— 여러 날에 걸쳐 한 주제를 배울 때/ask-matt— 어느 것을 쓸지 모를 때. 추천하고 멈춤
어휘층, 드라이버로 쓰지 말 것
codebase-design, domain-modeling, grilling, writing-for-agents
Phase boundary 다섯 중 하나, 위에서부터 순서대로 판단
계속 → clear → handoff → subagent → compact
출처
이 튜토리얼은 무엇을 근거로 썼는가
근거로 삼은 것은 mattpocock/skills plugin 1.2.3 버전(공개된 25개의 skill)입니다. 그 repo의 README.md, CONTEXT.md, 25편의 공식 skill 문서, .claude-plugin/plugin.json 및 CHANGELOG.md를 읽고 정리해 다시 썼습니다. 이 repo는 MIT 라이선스로 공개되어 있습니다.
이 페이지는 TauX가 독자적으로 집필한 한국어 튜토리얼이며, 공식 문서의 번역이나 전재가 아닙니다. skill 자체와 그 이름, 그 동작은 원저자에게 속합니다. 이 페이지의 구성, 판단 기준, 용어 선택, 그리고 모든 논평은 TauX가 쓴 것이며, 원저자의 입장을 대변하지 않습니다.
본문의 issue 번호는 모두 그 repo의 issue이며, 집필 시점에는 대부분 아직 열려 있습니다. 이것은 두 가지를 뜻합니다. 이 함정들은 실재하고, 이미 고쳐졌을 수도 있습니다. 돌려 보다가 이상한 일이 생기면 먼저 그 repo에서 증상을 검색하십시오. 못박아 둔 함정 목록이 맞을 수 있는 가장 좋은 결말은, 언젠가 전부 낡아 버리는 것입니다.
버전 표기는 여기서 장식이 아닙니다. 이 skill 묶음은 아주 빠르게 바뀌고(to-prd는 v1.1에서 이름이 바뀌어 지금은 to-spec, tdd의 refactor 단계는 2026년 6월에 제거되었습니다), 버전 번호가 없는 튜토리얼은 어느 대목이 아직 유효한지 독자가 판단할 수 없습니다.
이 워크플로를 우리 팀에 넣고 싶다면
도구는 공개되어 있습니다. 어려운 부분은 이미 쓰고 있는 tracker, 규범, 납품 리듬에 이어 붙이는 일입니다. 그 일은 저희가 해 봤습니다.