Agents · REPO · 2026
Skills For Real Engineers (mattpocock/skills)
요약
mattpocock/skills는 TypeScript 교육자 Matt Pocock이 실무에서 매일 쓰는 코딩 에이전트용 스킬 25개를 묶은 MIT 라이선스 저장소다. 스킬은 특정 작업 절차를 담아 에이전트가 불러 쓰는 지침 패키지를 뜻한다. 이 저장소의 스킬은 인터뷰, 스펙 작성, 티켓 분해, 테스트 주도 개발, 디버깅, 코드 리뷰처럼 소프트웨어를 만드는 과정 전체를 덮는다.
저장소의 성격을 규정하는 것은 스킬의 개수가 아니라 배치 원리다. 스킬을 기능 목록으로 나열하지 않고, 코딩 에이전트가 실무에서 반복적으로 실패하는 네 지점에 하나씩 대응시켜 배치했다. 각 대응에는 The Pragmatic Programmer, Domain-Driven Design, Extreme Programming Explained, A Philosophy of Software Design 같은 소프트웨어 공학 고전의 인용이 근거로 붙는다.
설계 원칙은 작고 교체 가능한 단위다. 저자는 GSD, BMAD, Spec-Kit처럼 개발 프로세스를 통째로 소유하는 방법론이 사용자의 통제권을 가져가고, 그 결과 프로세스 자체에 생긴 문제를 해결하기 어렵게 만든다고 본다. 이 저장소의 스킬은 작게 쪼개져 있어 사용자가 직접 고쳐 자기 것으로 만들 수 있고, 특정 모델에 묶이지 않는다.
이 페이지는 저장소의 README와 함께 수집한 스킬 정의 25개, 설계 규약 문서, ADR 2건을 근거로 삼는다. star 약 25만 개를 기록했고 Claude Code 공식 마켓플레이스에 등재되어 있다.
배경
프로세스를 소유하는 방법론과의 차이
에이전트로 소프트웨어를 만드는 방법론은 대체로 프로세스를 대신 소유하는 방향으로 발전했다. 요구 수집부터 설계, 구현, 검증까지의 순서를 방법론이 정해 두고 사용자는 그 궤도를 따라간다. 이 방식은 시작이 쉽다는 장점이 있다.
문제는 궤도에서 벗어날 때 생긴다. 방법론이 정한 프로세스 안에서 무언가 어긋나면 사용자가 손댈 수 있는 지점이 없다. 프로세스가 블랙박스이기 때문에 어긋난 원인을 찾기도, 고치기도 어렵다.
이 저장소는 반대 방향을 택한다. 프로세스를 하나의 큰 절차로 묶지 않고 각각 독립적으로 호출할 수 있는 스킬로 쪼갠다. 사용자는 필요한 스킬만 골라 쓰고, 마음에 들지 않는 부분은 해당 스킬 파일을 직접 고친다. 저자가 README에서 "이걸 가지고 마음껏 만져 보고 당신 것으로 만들라"고 쓴 것은 이 설계를 그대로 반영한 문장이다.
네 가지 실패 모드
저장소의 구성은 네 가지 실패 모드에서 출발한다. 각 실패 모드는 진단과 대응 스킬이 짝을 이룬다.
| 실패 모드 | 진단 | 대응 스킬 |
|---|---|---|
| 에이전트가 원하는 것을 만들지 않음 | 사람과 에이전트 사이의 의사소통 격차 | grill-me, grill-with-docs |
| 에이전트가 지나치게 장황함 | 프로젝트 전문 용어를 모르는 상태로 투입되어 한 단어로 될 말에 스무 단어를 씀 | grill-with-docs가 만드는 CONTEXT.md 공용 언어 |
| 코드가 동작하지 않음 | 산출물이 실제로 어떻게 실행되는지에 대한 피드백 부재 | tdd, diagnosing-bugs |
| 설계가 무너진 코드베이스 | 에이전트가 코딩 속도를 높이면서 소프트웨어 엔트로피 증가도 함께 가속 | to-spec, improve-codebase-architecture |
첫 번째 실패 모드의 근거로 저자는 The Pragmatic Programmer의 "아무도 자기가 정확히 무엇을 원하는지 모른다"를 인용한다. 사람과 개발자 사이에서 늘 일어나던 오해가 에이전트를 상대로도 똑같이 반복된다는 진단이다. 처방은 인터뷰다. 만들기 시작하기 전에 에이전트가 사용자에게 상세한 질문을 던지게 만든다.
두 번째 실패 모드는 Domain-Driven Design의 ubiquitous language 개념에서 온다. 프로젝트 초기에 개발자와 도메인 전문가는 서로 다른 언어를 쓴다. 에이전트도 같은 처지다. 프로젝트에 갑자기 투입되어 전문 용어를 알아서 파악하라는 요구를 받기 때문에 한 단어면 될 자리에 스무 단어를 쓴다.
저자는 자신의 course-video-manager 저장소 사례로 효과를 보인다. 공용 언어가 없을 때 "코스의 섹션 안에 있는 레슨이 실체화될 때 문제가 생긴다"라고 쓰던 문장이 공용 언어를 갖춘 뒤에는 "materialization cascade에 문제가 있다"로 줄어든다. 부수 효과도 함께 든다. 변수와 함수와 파일 이름이 일관되게 지어지고 코드베이스 탐색이 쉬워지며, 언어가 간결해진 만큼 에이전트가 사고에 쓰는 토큰이 줄어든다.
세 번째 실패 모드는 피드백의 문제다. 사람과 에이전트가 무엇을 만들지 합의했는데도 결과물이 나쁘다면 피드백 loop를 봐야 한다. 정적 타입, 브라우저 접근, 자동화된 테스트가 없으면 에이전트는 눈을 가린 채 날아간다.
네 번째 실패 모드는 속도의 부작용이다. 에이전트가 코딩 속도를 크게 높이면 소프트웨어 엔트로피의 증가 속도도 함께 올라간다. 코드베이스가 전례 없는 속도로 복잡해진다. 저자는 Kent Beck의 "시스템 설계에 매일 투자하라"와 Ousterhout의 "가장 좋은 모듈은 깊다"를 근거로 삼아, 설계에 대한 관심 자체를 스킬의 모든 층에 심는 방식을 택했다.
핵심 개념
스킬과 버킷
스킬은 skills/ 아래 다섯 개 버킷으로 나뉜다. 버킷은 스킬의 완성도와 배포 여부를 나타내는 분류다.
| 버킷 | 성격 | 플러그인 배포 | 문서 페이지 |
|---|---|---|---|
engineering/ |
매일 쓰는 코드 작업 | 포함 | 있음 |
productivity/ |
코드 외 워크플로 도구 | 포함 | 있음 |
misc/ |
보관은 하되 권장하지 않음 | 제외 | 없음 |
in-progress/ |
베타, 의도적으로 공개, 피드백 수집용 | 제외 | 없음 |
deprecated/ |
사용 중단 | 제외 | 없음 |
engineering/과 productivity/가 승격 버킷이다. 승격 버킷의 스킬은 세 곳에 빠짐없이 등록되어야 한다. 최상위 README.md의 참조, .claude-plugin/plugin.json의 skills 배열 항목, 그리고 docs/{버킷}/{스킬명}.md 문서 페이지다. 비승격 버킷의 스킬은 셋 중 어디에도 나타나면 안 된다.
이 불변 조건은 AGENTS.md에 명문화되어 있어 에이전트가 저장소를 수정할 때 지켜야 하는 규칙으로 작동한다. 스킬을 추가하거나 이름을 바꾸거나 동작을 바꿀 때마다 문서 페이지와 라우터를 다시 맞추라는 지시도 함께 있다. 저자는 그 이유를 "새 스킬을 한 번도 언급하지 않거나 사라진 스킬로 여전히 안내하는 라우터는 거짓말을 하는 라우터"라고 적는다.
user-invoked와 model-invoked
모든 스킬은 호출 주체 하나만으로 나뉜다. user-invoked는 사람이 이름을 직접 입력해야만 도달하는 스킬이고, model-invoked는 사람과 모델 양쪽이 도달할 수 있는 스킬이다.
| 구분 | user-invoked | model-invoked |
|---|---|---|
| 도달 가능 주체 | 사람만 | 사람과 모델 |
| Claude Code 설정 | disable-model-invocation: true |
생략 |
| Codex 설정 | policy.allow_implicit_invocation: false |
생략 |
description 대상 |
사람이 읽는 한 줄 요약, 트리거 목록 제거 | 모델이 읽는 트리거 문구 유지 |
| 역할 | 오케스트레이션 | 재사용 가능한 규율 |
두 harness의 설정은 반드시 함께 움직인다. 한 스킬은 양쪽 모두에서 user-invoked이거나 양쪽 모두에서 아니어야 한다. harness는 모델을 감싸 도구와 verification과 상태를 제공하는 실행 환경을 말한다.
description 필드의 성격이 달라지는 점이 중요하다. user-invoked 스킬의 description은 슬래시 커맨드 목록을 훑어보는 사람이 읽는 한 줄이므로 "사용자가 ~라고 말할 때 사용"류의 트리거 목록을 걷어낸다. model-invoked 스킬의 description은 자동 호출이 발동하도록 트리거 문구를 풍부하게 유지한다.
두 종류 사이에는 단방향 규칙이 있다. user-invoked 스킬은 model-invoked 스킬을 호출할 수 있다. 반대로 어떤 스킬도 user-invoked 스킬을 호출할 수 없다. 그래서 선행 조건이 user-invoked 스킬인 경우에는 tool call로 적지 않고 "사용자에게 /setup-matt-pocock-skills를 실행하라고 알려라"라는 사람 대상 지시문으로 적는다.
model-invoked로 둘지 판단하는 기준도 명시되어 있다. 기준은 재사용 여부가 아니라 "모델이 자율적으로 이 스킬에 도달하는 것이 유용한가"다. 재사용은 스킬로 분리하는 이유일 뿐 invocation을 정하는 기준이 아니다.
스킬 사이의 의존 표현
스킬이 다른 스킬에 의존할 때의 표기 방식도 규약으로 고정되어 있다. 세 가지 방식 중 하나만 허용한다.
- 허용: "grilling에 대해 Skill tool을 호출하라"처럼 도구 이름을 명시한 지시문
- 금지:
../other-skill/FILE.md형태의 깊은 파일 경로 상호 참조 - 금지:
/skill형태로 이름만 남기고 모델의 해석에 맡기는 방식
도구 이름을 명시하는 쪽을 택한 근거는 두 가지다. 첫째, 대부분의 harness가 스킬 호출을 모델이 부르는 도구로 노출하므로 도구를 명시하는 편이 산문에 /name을 흘려 두고 명령으로 읽히기를 기대하는 것보다 적중률이 높다. 둘째, 앞의 슬래시를 떼면 특정 harness의 트리거 문법에 묶이지 않는다.
Skill tool은 한 번에 스킬 하나만 받는다. 두 스킬이 필요한 단계는 호출 두 번으로 적는다. "grilling과 domain-modeling에 대해 Skill tool을 두 번 호출하라"가 올바른 표현이고, 이름 두 개를 한 호출에 넘기는 것처럼 읽히는 문장은 쓰지 않는다.
이 규약은 실제로 동작하는 지시문에만 적용된다. ask-matt나 버킷 README처럼 사람이 고르라고 스킬 이름을 나열하는 안내문은 아무것도 호출하지 않으므로 /skill 형태의 이름을 그대로 쓴다.
방법
요구를 맞추는 인터뷰
grilling은 이 저장소에서 가장 많이 재사용되는 부품이다. 다섯 개 상위 스킬이 내부에서 이 스킬을 호출한다.
인터뷰의 구조는 design tree다. 설계 결정 하나가 그에 딸린 하위 결정으로 가지를 친다. frontier는 선행 조건이 이미 정해진 결정 전체, 즉 아직 듣지 못한 답을 추측하지 않고도 지금 물을 수 있는 질문들이다.
진행은 라운드 단위다. 한 라운드에서 frontier 전체를 한꺼번에 묻는다. 질문마다 번호를 붙이고 추천 답을 함께 제시한 뒤 사용자의 답을 기다린다. 답이 들어오면 트리가 재구성된다. 정해진 결정이 frontier를 바깥으로 밀어내면서 그에 의존하던 질문이 열린다. 같은 라운드에 아직 열려 있는 질문에 답이 걸린 질문은 이번 라운드가 아니라 다음 라운드에 속한다.
역할 분담이 명확하게 규정되어 있다. 사실을 찾는 일은 에이전트의 몫이다. frontier 질문이 파일 시스템이나 도구에서 얻을 수 있는 사실을 필요로 하면 서브에이전트를 보내 찾고 사용자에게 묻지 않는다. 서브에이전트는 상위 에이전트가 위임한 작업을 격리된 컨텍스트에서 수행한다.
다만 그 탐색을 기다리느라 인터뷰를 멈추지는 않는다. 진행 중인 탐색은 미해결 선행 조건이므로 그 아래에 걸린 질문만 기다리고 나머지 frontier는 지금 묻는다. 결정은 사용자의 몫이므로 각각을 사용자에게 제시하고 기다린다.
세션은 frontier가 비면 끝난다. 설계 트리의 모든 가지를 방문했고 조용히 가정된 것이 남지 않은 상태다. 사용자가 공통된 이해에 도달했다고 확인하기 전에는 실행에 들어가지 않는다.
이 primitive를 감싸는 진입점이 둘 있다. grill-me는 grilling만 호출하는 상태 없는 래퍼이고, grill-with-docs는 grilling과 domain-modeling을 함께 호출해 결과를 문서로 남기는 래퍼다. 작업 디렉터리가 있으면 후자가 항상 낫다. 같은 인터뷰를 진행하면서 기록까지 남기기 때문이다.
공용 언어와 도메인 문서
domain-modeling은 도메인 모델을 능동적으로 만들고 벼리는 규율이다. 저자는 이 스킬의 경계를 명확히 긋는다. CONTEXT.md를 읽어 어휘만 참고하는 것은 이 스킬이 아니라 어느 스킬이나 하는 한 줄짜리 습관이다. 용어를 도전하고 시나리오로 압박하고 문서를 그 자리에서 갱신하는 능동적 규율만 이 스킬에 해당한다.
세션 중 수행하는 동작은 다섯 가지다.
- 사용자가 쓴 용어가
CONTEXT.md의 기존 언어와 충돌하면 즉시 지적한다 - 모호하거나 과부하된 용어에는 정확한 canonical 용어를 제안한다
- 도메인 관계가 논의될 때 경계를 파고드는 구체적 시나리오로 압박한다
- 사용자가 진술한 동작을 코드와 대조해 모순이 있으면 드러낸다
- 용어가 정해지는 즉시
CONTEXT.md를 그 자리에서 갱신한다
마지막 항목에는 단서가 붙는다. 갱신을 모아 두었다가 일괄 처리하지 않는다. 결정이 일어나는 순간 붙잡아 기록한다.
CONTEXT.md의 성격도 좁게 규정된다. 구현 세부가 전혀 없어야 하고 스펙이나 메모장이나 구현 결정 저장소로 쓰지 않는다. 용어집이며 그 외의 것이 아니다.
저장소 자체의 CONTEXT.md가 이 형식의 예시가 된다. Issue tracker, Issue, Decision ticket, Triage role 네 용어를 정의하고 각각에 피해야 할 표현을 함께 적는다. 예를 들어 Issue tracker 항목에는 backlog manager, backlog backend, issue host를 쓰지 말라고 명시한다. 문서 끝에는 해소된 모호함도 기록한다. "backlog"가 이슈를 담는 도구와 그 안의 작업 덩어리 두 가지를 동시에 뜻하던 문제를 Issue tracker로 정리했다는 기록이다.
ADR은 아껴서 제안한다. 세 조건이 모두 참일 때만 만든다. 되돌리기 어렵고 맥락 없이는 놀랍고 실제 절충의 결과여야 한다. 하나라도 빠지면 ADR을 만들지 않는다.
테스트 주도 개발 규율
tdd는 red에서 green으로 가는 loop 자체를 새로 설명하지 않는다. 그 loop가 남길 가치가 있는 테스트를 만들도록 하는 참고 문서 역할을 한다. 좋은 테스트란 무엇인지, 테스트가 어디에 놓이는지, 무엇이 안티 패턴인지, loop의 규칙이 무엇인지를 담는다.
좋은 테스트의 기준은 공개 interface를 통해 동작을 검증하는 것이다. 구현 세부를 검증하지 않는다. 코드가 통째로 바뀌어도 테스트는 바뀌지 않아야 한다. "사용자가 유효한 장바구니로 결제할 수 있다"라는 테스트는 어떤 기능이 존재하는지를 정확히 알려 주고, 내부 구조에 무관심하기 때문에 리팩터링을 견딘다.
seam은 테스트가 놓이는 공개 경계를 말한다. 내부에 손을 뻗지 않고 동작을 관찰하는 자리다. 규칙은 사전에 합의된 seam에서만 테스트한다는 것이다. 테스트를 쓰기 전에 대상 seam을 적어 사용자에게 확인받고, 확인되지 않은 seam에는 테스트를 쓰지 않는다.
이 규칙의 근거는 자원 배분이다. 모든 것을 테스트할 수는 없으므로 seam을 먼저 합의하는 것이 테스트 노력을 임계 경로와 복잡한 로직에 집중시키는 방법이다. 모든 예외 상황에 테스트를 흩뿌리는 대신이다.
안티 패턴은 세 가지다.
| 안티 패턴 | 내용 | 판별 신호 |
|---|---|---|
| 구현 결합 | 내부 협력자를 mock하거나 private 메서드를 테스트하거나 interface 대신 데이터베이스를 직접 조회 | 동작이 안 바뀌었는데 리팩터링에서 테스트가 깨진다 |
| 동어반복 | 단언이 코드와 같은 방식으로 기대값을 다시 계산 (expect(add(a, b)).toBe(a + b)) |
구조상 항상 통과하므로 코드와 불일치할 수 없다 |
| 수평 분할 | 테스트를 전부 먼저 쓰고 구현을 전부 나중에 씀 | 상상한 동작을 검증하게 되고 실제 변경에 둔감해진다 |
동어반복을 피하는 방법은 기대값의 출처를 독립시키는 것이다. 알려진 리터럴, 손으로 푼 예제, 스펙 중 하나에서 값을 가져온다.
수평 분할의 대안은 수직 슬라이스다. 테스트 하나를 쓰고 구현 하나를 쓰는 사이클을 반복한다. 각 테스트는 직전 사이클에서 배운 것에 반응하는 tracer bullet이 된다.
loop의 규칙은 세 가지로 압축된다. 실패하는 테스트를 먼저 쓰고 통과에 필요한 만큼만 구현한다. 사이클마다 seam 하나와 테스트 하나와 최소 구현 하나만 다룬다. 리팩터링은 loop의 일부가 아니라 검토 단계에 속한다.
피드백 loop 중심 디버깅
diagnosing-bugs는 어려운 버그를 위한 6단계 규율이다. 단계를 건너뛰려면 명시적으로 정당화해야 한다.
1단계인 feedback loop 구축이 이 스킬의 본체이고 나머지는 기계적인 작업으로 규정된다. 전제는 단순하다. 이 버그에서 실패로 바뀌는 명확한 pass 또는 fail 신호를 확보하면 원인은 찾게 된다. 이분 탐색과 가설 검증과 계측은 모두 그 신호를 소비할 뿐이다. 신호가 없으면 코드를 아무리 들여다봐도 소용없다.
loop를 만드는 방법은 대략 다음 순서로 10가지가 제시된다.
- 버그에 닿는 seam에서의 실패하는 테스트
- 실행 중인 개발 서버를 향한 curl 또는 HTTP 스크립트
- 고정 입력을 주는 CLI 호출과 정상 스냅샷 비교
- UI를 구동해 DOM과 콘솔과 네트워크를 단언하는 headless 브라우저 스크립트
- 캡처한 trace 재생
- 최소 부분 집합만 띄우는 일회용 harness
- 무작위 입력 1,000개를 넣는 속성 기반 또는 fuzz loop
- 두 정상 상태 사이를 자동 탐색하는 이분 탐색 harness
- 구 버전과 신 버전 출력을 비교하는 차분 loop
- 사람이 클릭해야만 할 때 쓰는 최후 수단인 사람 개입 bash 스크립트
loop를 확보한 다음에는 loop 자체를 제품처럼 다듬는다. 더 빠르게 만들고(설정 캐시, 무관한 초기화 생략, 테스트 범위 축소), 신호를 더 날카롭게 만들고(오류 없음이 아니라 구체적 증상에 대해 단언), 더 결정적으로 만든다(시간 고정, 난수 시드 고정, 파일 시스템 격리, 네트워크 동결). 저자의 표현으로 30초짜리 불안정한 loop는 없는 것보다 조금 나은 정도이고, 2초짜리 결정적 loop가 디버깅의 무기가 된다.
1단계의 completion criterion이 구체적으로 규정되어 있다. completion criterion은 그 단계가 끝났다고 판단하는 조건을 뜻한다. 여기서는 이미 최소 한 번 실행해 본 명령 하나를 댈 수 있어야 하고, 그 명령이 네 조건을 만족해야 한다.
| 조건 | 내용 |
|---|---|
| red 가능 | 실제 버그 코드 경로를 지나고 사용자가 말한 정확한 증상에 대해 단언한다. 오류 없이 실행된다는 수준으로는 부족하다 |
| 결정적 | 매 실행에서 같은 판정을 낸다. 간헐적 버그라면 고정된 높은 재현 비율 |
| 빠름 | 분이 아니라 초 단위 |
| 에이전트 실행 가능 | 사람이 지켜보지 않아도 실행된다 |
이 명령이 존재하기 전에 이론을 세우려고 코드를 읽고 있다면 멈추라고 지시한다. 가설로 바로 건너뛰는 것이 이 스킬이 막으려는 바로 그 실패이기 때문이다. red 가능한 명령이 없으면 2단계로 넘어가지 않는다.
나머지 단계는 다음과 같이 이어진다.
| 단계 | 내용 |
|---|---|
| 2. 재현과 최소화 | loop를 실행해 실패를 확인한 뒤, 여전히 실패하는 가장 작은 시나리오까지 입력과 호출자와 설정을 하나씩 줄인다 |
| 3. 가설 | 3~5개 가설을 반증 가능한 형태로 만들어 순위를 매기고, 시험 전에 사용자에게 보여 준다 |
| 4. 계측 | 예측 하나당 탐침 하나를 대응시키고 변수는 한 번에 하나만 바꾼다 |
| 5. 수정과 회귀 테스트 | 올바른 seam이 있을 때만 회귀 테스트를 먼저 쓰고 수정한다 |
| 6. 정리 | 원래 재현이 사라졌는지 확인하고 계측을 제거한다 |
최소화의 완료 조건은 남은 모든 요소가 실패에 기여하고 있는 상태다. 어느 하나를 빼면 loop가 통과로 바뀐다. 최소화를 하는 이유는 3단계의 가설 공간을 줄이고 5단계의 깨끗한 회귀 테스트를 얻기 위해서다.
3단계에서 가설을 여러 개 만들게 하는 이유도 명시된다. 가설을 하나만 세우면 처음 떠오른 그럴듯한 생각에 고정된다. 각 가설은 예측을 진술해야 한다. 예측을 진술할 수 없는 가설은 느낌일 뿐이므로 버리거나 날카롭게 만든다.
5단계에는 이 저장소 특유의 규정이 있다. 올바른 seam이 없다면 그 사실 자체가 발견이다. 코드베이스 구조가 버그를 고정하지 못하게 막고 있다는 뜻이므로 기록해 다음 단계로 넘긴다. 얕은 seam에 회귀 테스트를 두면 거짓 안심을 준다.
디버그 로그에는 [DEBUG-a4f2] 같은 고유 접두사를 붙인다. 정리가 grep 한 번으로 끝나기 때문이다. 태그가 없는 로그는 살아남고 태그가 붙은 로그는 사라진다.
deep module 설계 어휘
codebase-design은 절차가 아니라 어휘를 제공하는 스킬이다. deep module을 설계하기 위한 용어 8개를 정의하고, component나 service나 API나 boundary 같은 대체어를 쓰지 말라고 못 박는다. 일관된 언어 자체가 이 스킬의 목적이다.
deep module은 작은 interface 뒤에 많은 동작을 두고, 깨끗한 seam 위에 놓이며, 그 interface를 통해 테스트되는 모듈을 말한다.
| 용어 | 정의 | 금지 대체어 |
|---|---|---|
| module | interface와 implementation을 가진 모든 것. 함수, 클래스, 패키지, 계층을 가로지르는 슬라이스 모두 해당 | unit, component, service |
| interface | 호출자가 올바르게 쓰기 위해 알아야 하는 모든 것. 타입 시그니처뿐 아니라 불변 조건, 순서 제약, 오류 모드, 필수 설정, 성능 특성 포함 | API, signature |
| implementation | 모듈 내부의 코드 본체 | |
| depth | interface에서의 leverage. 호출자나 테스트가 배워야 하는 interface 한 단위당 행사할 수 있는 동작의 양 | |
| seam | 그 자리를 편집하지 않고 동작을 바꿀 수 있는 위치. Michael Feathers의 용어 | boundary |
| adapter | seam에서 interface를 만족시키는 구체적 대상. 무엇이 들어 있는지가 아니라 어떤 자리를 채우는지를 가리킨다 | |
| leverage | depth가 호출자에게 주는 것. 구현 하나가 N개 호출 지점과 M개 테스트에 걸쳐 회수된다 | |
| locality | depth가 유지보수자에게 주는 것. 변경과 버그와 지식과 verification이 한 곳에 모인다 |
interface의 정의가 넓은 점이 특징이다. 타입 시그니처만이 아니라 호출자가 알아야 하는 모든 사실이 interface에 속한다. 그래서 TypeScript의 interface 키워드나 클래스의 공개 메서드로 좁히는 해석을 명시적으로 기각한다.
원칙 네 가지가 따라붙는다.
- depth는 implementation이 아니라 interface의 속성이다. deep module 내부는 작고 교체 가능한 부품으로 구성될 수 있다. 그 부품이 interface에 드러나지만 않으면 된다. 모듈은 외부 seam과 별개로 자기 구현 안에 내부 seam을 가질 수 있고, 그 내부 seam은 모듈 자신의 테스트가 쓴다.
- 삭제 테스트. 모듈을 지웠다고 상상한다. 복잡도가 사라지면 통과용 껍데기였고, 복잡도가 N개 호출자에 걸쳐 되살아나면 제 몫을 하던 모듈이다.
- interface가 곧 테스트 표면이다. 호출자와 테스트가 같은 seam을 지난다. interface 너머를 테스트하고 싶어진다면 모듈 형태가 잘못됐을 가능성이 크다.
- adapter가 하나면 가정된 seam, 둘이면 실재하는 seam이다. 실제로 무언가가 달라지지 않는 자리에 seam을 만들지 않는다.
테스트하기 좋은 interface를 만드는 방법도 세 가지로 제시된다. 의존을 만들지 말고 받는다. 부수 효과를 내지 말고 결과를 반환한다. 표면적을 작게 유지한다. 메서드가 적으면 필요한 테스트가 줄고 인자가 적으면 테스트 준비가 단순해진다.
저자는 Ousterhout의 정의 중 하나를 명시적으로 기각한다. depth를 구현 줄 수 대 interface 줄 수의 비율로 재는 방식이다. 그렇게 하면 구현을 부풀리는 쪽에 보상이 돌아가기 때문이며, 대신 leverage로서의 depth를 쓴다.
이 어휘를 소비하는 스킬이 둘 있다. tdd는 seam의 형태 자체가 문제가 될 때 이 스킬을 참고 문서로 불러 쓴다. improve-codebase-architecture는 코드베이스를 조사해 얕은 모듈을 깊게 만들 후보를 찾을 때 이 어휘로만 제안을 서술한다.
코드베이스 조사
improve-codebase-architecture는 코드베이스에서 설계상의 마찰을 찾아 deepening opportunity로 제시한다. 얕은 모듈을 깊게 만드는 리팩터링 후보를 뜻한다.
조사 범위를 먼저 정하는 규칙이 있다. 모듈을 깊게 만드는 것은 앞으로 그 모듈을 바꿀 때 회수되는 투자이므로, 최근에 바뀐 부분에 무게를 더 준다. 사용자가 방향을 지정했으면 그것을 따르고, 지정하지 않았으면 커밋 이력을 훑어 자주 등장하는 파일과 영역을 찾아 그 영역을 먼저 본다.
조사는 고정된 체크리스트가 아니라 마찰이 느껴지는 지점을 기록하는 방식으로 진행한다. 개념 하나를 이해하는 데 작은 모듈 여러 개를 오가야 하는 곳, interface가 implementation만큼 복잡한 곳, 테스트만을 위해 순수 함수를 뽑아냈지만 실제 버그는 그 함수를 호출하는 방식에 숨어 있는 곳, 결합이 강한 모듈이 seam 밖으로 새는 곳, 현재 interface로는 테스트하기 어려운 곳이 예시로 제시된다.
산출물은 저장소가 아니라 운영체제 임시 디렉터리에 쓰는 자체 완결 HTML 보고서다. 후보마다 관련 파일, 문제, 해결책, 이득, 개선 전후 도식, 추천 강도 배지를 담은 카드를 만든다. 도식은 관계가 그래프 형태일 때 Mermaid를 쓰고 더 편집자적인 표현이 필요할 때 직접 만든 SVG를 쓴다.
이 스킬의 한계도 저자가 직접 명시한다. 구조 조사이지 구제가 아니다. 오래된 코드베이스에서 실제 후보를 찾아 주기는 하지만 얽힌 구조를 대신 풀어 주지는 않는다.
스펙과 티켓 분해
to-spec은 현재 대화 맥락과 코드베이스 이해를 스펙으로 바꾼다. 인터뷰를 새로 하지 않고 이미 아는 것만 종합한다. 스펙 템플릿은 문제 진술, 해결책, 사용자 스토리, 구현 결정, 테스트 결정, 범위 밖, 추가 참고 사항으로 구성된다.
특기할 규정은 스펙에 파일 경로와 코드 조각을 넣지 않는 것이다. 금방 낡기 때문이다. 예외는 프로토타입이 산출한 조각이 산문보다 결정을 정확하게 담을 때다. 상태 기계나 reducer나 스키마나 타입 형태가 여기 해당한다. 이때도 동작하는 데모 전체가 아니라 결정을 담은 부분만 잘라 넣고 프로토타입에서 왔다는 사실을 짧게 적는다.
to-tickets는 스펙이나 대화를 티켓으로 쪼갠다. 티켓은 tracer bullet 수직 슬라이스다. 각 슬라이스는 스키마부터 API, UI, 테스트까지 모든 계층을 관통하는 좁지만 완전한 경로를 자르고, 완료 시 그 자체로 시연하거나 검증할 수 있으며, 새 컨텍스트 하나에 들어가는 크기여야 한다. 티켓마다 먼저 끝나야 하는 다른 티켓을 블로킹 관계로 선언한다.
수직 슬라이싱의 예외가 wide refactor다. 컬럼 이름 변경이나 공용 심볼의 타입 변경처럼 기계적 변경 하나의 영향 범위가 코드베이스 전체로 퍼지는 경우다. 편집 한 번이 수천 개 호출 지점을 동시에 깨뜨리므로 어떤 수직 슬라이스도 통과 상태로 착지할 수 없다. 이때는 tracer bullet으로 억지로 만들지 않고 expand-contract로 순서를 잡는다.
| 단계 | 내용 | 블로킹 관계 |
|---|---|---|
| expand | 기존 형태 옆에 새 형태를 추가해 아무것도 깨지지 않게 한다 | 없음 |
| migrate | 호출 지점을 영향 범위 단위(패키지별, 디렉터리별)로 나눈 배치로 옮긴다 | expand가 블로킹 |
| contract | 남은 호출자가 없어진 뒤 기존 형태를 삭제한다 | 모든 migrate 배치가 블로킹 |
이 순서가 통하는 이유는 migrate 단계 내내 기존 형태가 살아 있어 CI가 배치마다 통과 상태를 유지하기 때문이다. 배치마저 단독으로 통과 상태를 유지할 수 없으면 순서는 유지하되 공용 통합 브랜치를 쓰고, 그 브랜치가 최종 통합 검증 티켓 하나를 블로킹하게 한다. 이 경우 통과 상태는 그 지점에서만 보장한다.
티켓의 게시 방식은 설정된 이슈 트래커에 따라 달라진다. 로컬 마크다운이면 .scratch/{기능}/issues/ 아래에 티켓 하나당 파일 하나를 의존 순서로 번호를 붙여 쓴다. 실제 이슈 트래커면 이슈 하나씩 의존 순서로 게시하고 플랫폼의 네이티브 블로킹 관계를 쓴다.
대규모 작업의 지도
wayfinder는 한 세션에 담기지 않는 크고 모호한 작업을 다룬다. 이 저장소에서 인지 부담이 가장 큰 흐름이다.
출발점은 느슨한 아이디어가 도착했지만 목적지까지 가는 길이 아직 보이지 않는 상태다. 이 스킬은 목적지에 곧장 달려드는 것이 아니라 길을 찾는 작업으로 자신을 규정한다.
기본 자세는 계획이지 실행이 아니다. 각 티켓은 결정 하나를 해소하고, 실행에 들어가기 전에 정할 것이 남지 않았을 때 지도가 완성된다. 그냥 작업을 해버리고 싶어지는 충동은 대체로 지도의 가장자리에 도달했고 인계할 시점이라는 신호로 읽는다.
지도는 이슈 트래커의 이슈 하나(wayfinder:map 라벨)이고 티켓은 그 자식 이슈다. 지도는 저장소가 아니라 인덱스다. 내려진 결정을 나열하고 세부를 담은 티켓을 가리킬 뿐, 결정은 그 티켓 한 곳에만 존재한다. 지도 본문은 목적지, 참고 사항, 지금까지의 결정, 아직 명세되지 않음, 범위 밖 다섯 개 절로 구성된다.
fog of war는 이 스킬의 핵심 장치다. 오고 있다는 것은 알지만 아직 또렷하게 짚어낼 수 없는 결정과 조사의 영역을 뜻한다. 지도는 의도적으로 불완전하게 유지된다. 아직 보이지 않는 것을 미리 그리지 않는다.
티켓으로 만들지 안개로 남길지 가르는 기준은 지금 답할 수 있는지가 아니라 지금 질문을 정확하게 진술할 수 있는지다. 질문이 이미 날카로우면 막혀 있어도 티켓으로 만든다. 그만큼 날카롭게 표현할 수 없으면 아직 명세되지 않음 절에 남긴다. 안개를 미리 티켓 크기로 쪼개지 않는데, 안개 한 덩어리가 나중에 여러 티켓이 될 수도 하나도 안 될 수도 있기 때문이다.
범위 밖은 안개와 성격이 다르다. 안개는 목적지 쪽으로만 모이므로 목적지 너머의 작업은 안개가 아니다. 범위 밖 항목은 별도 절에 기록하고 졸업하지 않는다. 이미 만들어진 티켓이 목적지 너머로 드러나면 그 티켓을 닫고 범위 밖 절에 한 줄을 남긴다.
티켓 종류는 네 가지이고 각각 사람이 함께해야 하는지가 정해져 있다.
| 종류 | 사람 개입 | 용도 |
|---|---|---|
| research | 불필요 | 결정이 기다리는 사실을 문서나 외부 API에서 확보. 서브에이전트가 research 스킬을 호출해 해소 |
| prototype | 필요 | 반응할 대상이 될 값싸고 거친 산출물을 만들어 논의 해상도를 높인다 |
| grilling | 필요 | 대화. 기본값. grilling과 domain-modeling을 함께 호출 |
| task | 경우에 따라 | 결정 이전에 끝나야 하는 수작업. 서비스 가입, 접근 권한 확보, 데이터 이동 |
사람이 함께해야 하는 티켓은 그 대화를 통해서만 해소된다. 에이전트가 사람 쪽 답을 대신 만들어 내면 규칙이 깨진 것이다. 자기 질문에 스스로 답하는 인터뷰가 그 예다.
한 세션에서 티켓을 두 개 이상 해소하지 않는다. research 티켓만 예외다.
두 기준 코드 리뷰
code-review는 고정점과 HEAD 사이의 diff를 두 기준으로 검토한다. Standards는 저장소의 문서화된 코딩 표준을 따르는지 보고, Spec은 원래 이슈나 스펙을 충실히 구현했는지 본다.
두 기준은 각각 별도의 서브에이전트로 병렬 실행된다. 서로의 컨텍스트를 오염시키지 않기 위해서다. 그 뒤 상위 스킬이 두 보고를 나란히 제시한다.
분리하는 근거는 한 기준을 통과하면서 다른 기준에서 실패하는 변경이 실재하기 때문이다. 표준을 다 지켰지만 엉뚱한 것을 구현한 코드는 Standards 통과에 Spec 실패다. 이슈가 요구한 대로 동작하지만 프로젝트 관례를 깬 코드는 그 반대다. 그래서 최종 보고에서 두 기준의 발견 사항을 병합하거나 다시 순위 매기지 않는다. 기준을 가로질러 하나의 승자를 뽑는 것이 분리로 막으려는 바로 그 행위다.
Standards 기준에는 저장소가 아무것도 문서화하지 않아도 항상 적용되는 smell baseline이 붙는다. Fowler의 Refactoring 3장에서 가져온 코드 냄새 12종이며 Mysterious Name, Duplicated Code, Feature Envy, Data Clumps, Primitive Obsession, Repeated Switches, Shotgun Surgery, Divergent Change, Speculative Generality, Message Chains, Middle Man, Refused Bequest가 여기 속한다. 각 항목은 무엇인지와 어떻게 고치는지 형식으로 적혀 있다.
두 가지 규칙이 이 baseline을 제한한다. 저장소의 문서화된 표준이 항상 우선하며 baseline이 지적할 것을 저장소 표준이 허용하면 그 지적을 억제한다. 그리고 baseline 항목은 확정 위반이 아니라 항상 판단이 필요한 지적으로 다룬다. 보고서에는 "가능성 있는 Feature Envy"처럼 적힌다. 도구가 이미 강제하는 항목은 건너뛴다.
에이전트용 문서 설계 원리
writing-for-agents는 이 저장소에서 가장 이론적인 문서다. 에이전트가 소비하는 모든 문서에 적용되는 참고 문서이며, 스킬이든 AGENTS.md든 포인터로 도달하는 문서든 포장만 다를 뿐 글쓰기는 같다고 전제한다. 목표가 같은 산출물을 내는 것이 아니라 매 실행에서 같은 과정을 밟게 하는 것이기 때문이다.
context pointer는 에이전트의 컨텍스트 안에 있으면서 컨텍스트 밖의 자료를 가리키고 그 자료에 도달할 조건을 담은 참조다. 스킬의 description이 그 예이고 AGENTS.md에서 문서를 가리키는 한 줄도 같은 대상이다.
핵심 주장은 언제 얼마나 안정적으로 도달할지를 정하는 것이 가리키는 대상이 아니라 포인터의 문구라는 점이다. 꼭 필요한 자료가 약한 문구 뒤에 있다면 그것은 변동성 결함이다. 문구를 먼저 날카롭게 하고 그래도 안 되면 그때 본문에 인라인한다. 포인터를 다듬는 규칙은 세 가지다. 발동 역할을 하는 첫 단어를 앞에 놓고, 분기마다 트리거 하나만 두며, 본문이 이미 담고 있는 정체성 서술은 잘라 낸다.
두 가지 부하를 구분한다.
| 부하 | 대상 | 성격 |
|---|---|---|
| 컨텍스트 부하 | 모델 | 항상 로드되는 자료가 매 턴 쓰는 토큰과 주의. 발동 여부와 무관하게 비용이 든다 |
| 인지 부하 | 사람 | 어떤 문서가 있고 언제 무엇을 꺼내야 하는지를 사람이 기억해야 하는 비용 |
인지 부하를 다루는 태도가 특징적이다. 최소화 대상이 아니라 사람의 판단권에 대한 대가로 본다. 사람의 판단이 중요한 곳에는 인지 부하를 쓰고 그렇지 않은 곳에서는 없앤다. 포인터로만 도달하는 자료는 포인터 한 줄 값만 내고 컨텍스트 부하를 피한다. 포인터조차 없는 자료는 전적으로 인지 부하에 얹혀 간다.
정보 계층은 자료가 얼마나 즉각적으로 필요한지에 따른 세 단계 사다리다.
| 단계 | 성격 |
|---|---|
| 파일 내 단계 | 에이전트가 순서대로 수행하는 것. 최상위 단계 |
| 파일 내 참고 | 필요할 때 조회하는 정의와 규칙과 사실 |
| 분리된 참고 | 별도 파일로 밀어내고 context pointer로 도달하며 포인터가 발동할 때만 로드 |
progressive disclosure는 이 사다리를 내려가는 이동을 말한다. 필요한 시점에만 정보를 단계적으로 노출하는 설계다. 이 문서는 그것을 토큰 최적화가 아니라 계층을 보호하는 방법으로 규정한다. 아래로 너무 적게 내리면 위가 부풀고 너무 많이 내리면 에이전트가 실제로 필요로 하는 자료를 숨기게 된다.
판단 기준은 분기다. 모든 분기가 필요로 하는 것은 인라인하고 일부 분기만 도달하는 것은 포인터 뒤로 민다. 단계가 있는 문서에서 내려보내야 할 참고 자료를 붙잡고 있으면 단계가 묻히고, 그것을 읽을지가 동전 던지기가 된다.
같은 파일 안에서의 짝 개념이 co-location이다. 사다리가 얼마나 아래로 갈지를 정한다면 co-location은 그 자리에서 무엇이 옆에 놓일지를 정한다. 한 개념의 정의와 규칙과 단서를 흩어 놓지 않고 한 제목 아래 모아 둔다. 판별 기준은 문서가 에이전트를 위해 쓴 문서처럼 읽히는지다.
completion criterion은 두 가지 성질로 지렛대가 된다.
- 명확성은 에이전트가 완료와 미완료를 구분할 수 있는지다. "이해에 도달했다"처럼 모호한 기준은 조기 종료를 부른다. 아직 남은 단계가 눈에 보이면 완료했다는 상태 쪽으로 주의가 끌리기 때문이다. 방어 순서가 정해져 있다. 기준을 날카롭게 하는 것이 먼저이고, 도저히 날카롭게 할 수 없으면서 실제로 서두르는 것이 관찰될 때만 이후 단계를 숨긴다.
- 요구 강도는 얼마나 많은 것을 요구하는지다. "수정된 모든 모델이 설명되었다"는 "변경 목록을 만들어라"보다 훨씬 철저한 작업을 강제한다. 요구 강도는 단계에만 묶이지 않는다. "모든 규칙이 적용되었다"가 평평한 참고 자료 묶음을 묶는 방식이며, 그래서 참고 자료만으로 된 문서도 철저함의 기준을 가질 수 있다.
leading word는 모델의 pre-training 안에 이미 존재하는 압축된 개념어다. 문장이 아니라 토큰으로 반복해 쓰면 분산된 정의가 쌓이면서 최소한의 토큰으로 넓은 행동 영역을 고정한다. 예시가 구체적이다. "빠르고 결정적이고 부담이 적은"이 tight 하나로 줄고, "믿을 수 있는 loop"가 red 하나로 줄어 모호한 관문이 관측 가능한 상태가 된다.
새 단어를 만들 수도 있지만 사전에 학습된 단어가 무료로 주는 것을 정의 토큰으로 지불해야 하므로 기존 단어를 먼저 찾는다. leading word는 두 곳에서 작동한다. 본문에서는 같은 단어가 나올 때마다 에이전트가 같은 행동을 꺼내게 하고, 포인터에서는 프롬프트와 문서와 코드베이스가 같은 단어를 쓸 때 자료에 더 안정적으로 도달하게 한다.
이 지렛대 옆의 실패 모드가 부정형 지시다. 금지로 조종하면 금지된 행동이 컨텍스트로 끌려 들어와 오히려 더 떠오르기 쉬워진다. 코끼리를 생각하지 말라고 하면 코끼리만 남는 것과 같다. 목표 행동을 긍정형으로 진술해 금지 대상을 아예 언급하지 않는 쪽을 택한다. 긍정형으로 표현할 수 없는 강한 가드레일일 때만 금지가 자리를 얻고, 그때도 목표 행동을 함께 적는다.
가지치기 항목은 네 가지다.
- 의미마다 단일 출처를 유지한다. 같은 의미가 두 곳에 있으면 유지 비용과 토큰을 쓰고 그 의미의 계층상 순위를 실제보다 부풀린다
- 환경 자체도 출처다.
package.json스크립트, 설정 파일, 디렉터리 구조,--help출력이 여기 해당한다. 문서가 그것을 다시 적으면 조회 결과의 캐시가 되므로 조회가 비쌀 때만 값을 한다. 적어 두지 않은 관례, 선택의 이유, 설정이 말해 주지 않는 함정이 캐시할 대상이다 - 모든 줄이 여전히 문서의 목적과 관련되는지 확인한다. 관련성을 잃는 경로는 둘이다. 애초에 설명만 하는 줄이거나, 세상이 바뀌어 낡은 줄이다
- 모델이 기본값으로 이미 지키는 지시를 문장 단위로 찾아 삭제한다. 판정 기준은 독자가 아니라 모델이며, 두 사람이 이견을 보이면 토론이 아니라 문서를 실행해 판정한다
마지막 항목의 판정은 leading word에도 적용된다. 기본값을 이기지 못할 만큼 약한 단어는 아무 효과가 없다. 해법은 다른 기법이 아니라 더 강한 단어다.
메인 플로우와 컨텍스트 위생
ask-matt 라우터가 스킬 사이의 경로를 정의한다. 대부분의 작업이 지나는 경로는 아이디어에서 출시까지의 단일 흐름이다.
grill-with-docs로 아이디어를 인터뷰로 벼린다. 작업 디렉터리가 있으면 항상 여기서 시작한다.CONTEXT.md와 ADR에 학습 내용이 남는 상태 유지형이기 때문이다.- 대화만으로 모든 질문을 정리할 수 없으면
prototype으로 우회한다. 상태나 비즈니스 로직이나 눈으로 봐야 하는 UI처럼 실행해 봐야 답이 나오는 질문이 여기 해당한다. 왕복 양방향 모두handoff가 다리 역할을 한다. - 여러 세션에 걸치는 작업이면
to-spec으로 스펙을 만들고to-tickets로 티켓을 쪼갠 뒤 티켓마다implement를 실행한다. 한 세션에 들어가면 곧바로implement로 간다.
implement는 사전에 합의된 seam에서 tdd를 구동하고 마무리로 code-review를 실행한 뒤 커밋한다.
컨텍스트 위생 규칙이 이 흐름에 붙는다. 1단계부터 3단계까지는 하나의 끊기지 않은 context window 안에서 진행하고 to-tickets 이전에는 compact나 clear를 하지 않는다. 인터뷰와 스펙과 티켓이 같은 사고 위에 쌓이도록 하기 위해서다. 반면 implement는 티켓마다 새 컨텍스트에서 시작한다. 각 티켓이 자체 완결이므로 직전 티켓의 컨텍스트는 버려도 된다.
이 규칙의 한계는 smart zone이다. 저자는 최신 모델 기준 약 15만 토큰을 모델이 여전히 예리하게 추론하는 구간으로 본다. 그 안에서 to-tickets에 도달하지 못하면 성능이 저하된 채 밀어붙이지 말고 가장 가까운 단계 경계에서 compact하라고 지시한다.
메인 플로우에 합류하는 진입로는 세 가지다.
| 진입로 | 상황 | 합류 지점 |
|---|---|---|
triage |
직접 만들지 않은 이슈가 쌓임. 버그 신고, 들어온 기능 요청 | 에이전트가 집을 수 있는 이슈를 만들어 implement로 넘긴다 |
diagnosing-bugs |
무언가 고장남. 한눈에 안 잡히는 버그, 간헐적 실패, 회귀 | 고정할 seam이 없다는 결론이면 improve-codebase-architecture로 넘긴다 |
wayfinder |
한 세션에 담기지 않는 크고 안개 낀 작업 | 지도가 걷히면 to-spec으로 합류한다 |
triage의 적용 범위에 단서가 붙는다. 직접 만들지 않은 이슈만 대상이다. to-tickets가 만든 티켓은 이미 에이전트용이므로 triage하지 않는다.
wayfinder의 합류 지점에도 단서가 있다. 지도가 걷히면 인계하지 직접 만들지 않는다. to-spec이 지도의 연결된 결정들을 만들 수 있는 계획으로 압축하는 단계이므로, 지도를 곧바로 implement로 넘기면 그 압축을 건너뛰고 연결된 세부를 버리게 된다.
단계 경계에서의 선택지도 다섯 가지로 정리되어 있다. 그대로 진행하기, /clear로 창을 비우기, handoff로 이식 가능한 마크다운 파일을 쓰기, 서브에이전트에 좁게 범위를 정한 작업을 보내기, /compact로 현재 컨텍스트를 압축해 새 세션에 넘기기다. handoff의 용도는 좁게 규정된다. 다른 harness, 다른 디렉터리, 동료에게 넘길 때, 그리고 단계 중간에 곁가지 작업을 떼어낼 때만 쓴다.
결과
이 저장소는 정량 벤치마크를 제시하지 않는다. 스킬의 효과를 재는 A/B 비교나 평가 지표가 없고, 근거는 저자의 실무 경험과 소프트웨어 공학 고전 인용이다. 대신 ADR 0002가 배포 경로에 대한 검증 기록을 구체적으로 남긴다.
배포 경로 두 가지
두 경로가 있고 서로 배타적이다.
| 경로 | 방식 | 갱신 | 편집 |
|---|---|---|---|
| Claude Code 플러그인 | 관리되는 읽기 전용 묶음을 구독 | 저자가 배포하면 자동 | 불가 |
| skills.sh 설치기 | 편집 가능한 파일을 프로젝트에 복사 | npx skills update로 수동 |
가능 |
둘 다 설치하면 모든 스킬이 두 벌씩 남는다. 그래서 README는 하나만 고르라고 명시한다.
두 경로가 갈린 이유는 플러그인 매니페스트 형식의 차이다. Claude Code의 .claude-plugin/plugin.json은 skills를 명시적 경로 배열로 받는다. 그래서 승격된 스킬만 하나씩 나열해 나머지를 모호함 없이 제외할 수 있다. Codex의 .codex-plugin/plugin.json은 skills를 단일 경로 문자열로만 받고 배열은 거부하며, 그 경로 아래에서 SKILL.md를 재귀 탐색한다. 버킷 두 개를 한 경로로 지정할 방법이 없다.
두 가지 우회책을 시험하고 기각했다. ./skills/를 통째로 가리키면 deprecated/, in-progress/, personal/, misc/까지 함께 배포된다. 심볼릭 링크로 만든 평면 디렉터리는 설치를 견디지 못한다. Codex가 플러그인 트리를 캐시로 복사하면서 심볼릭 링크를 버리기 때문에 스킬이 빈 채로 도착한다.
남은 선택지는 skills/를 승격 스킬만 담도록 재구성하거나 평면 디렉터리에 사본을 커밋하는 것인데, 둘 다 구조적 결정이라 플러그인 배포에 끼워 넣을 일이 아니라고 판단했다. 결론은 Claude Code 플러그인을 먼저 배포하고 skills.sh를 범용 설치기로 유지하며 Codex 네이티브 플러그인은 연기하는 것이다.
공식 마켓플레이스 검증 기록
2026-08-05 업데이트에서 mattpocock-skills가 Claude Code 공식 마켓플레이스에 등재됐다. 모든 Claude Code 설치에 기본으로 들어 있는 claude-plugins-official이며, 사용자가 마켓플레이스를 먼저 추가할 필요가 없다.
Claude Code 2.1.222에서 검증한 내용은 다음과 같다.
claude plugins install mattpocock-skills가 마켓플레이스를 먼저 추가하지 않아도 해소되며mattpocock-skills@claude-plugins-official로 보고된다claude plugin details mattpocock-skills가 버전 1.2.0을 보고하고 승격된 스킬을 로드한다- 등재 항목의
source가 sha를 고정하고 있다. 태그를 다는 순간이 아니라 그 고정점이 움직일 때 설치 사용자에게 릴리스가 도달한다 - 작성 시점에 고정점이 main보다 커밋 두 개 뒤에 있어
plugin.json의 24개가 아니라 22개 스킬이 목록에 나타났다 - 세션 내
/plugin install은 검증하지 못했다./plugin이 headless 세션에서 제공되지 않기 때문이다
네 번째 항목은 배포 지연이 관측된 사례라는 점에서 의미가 있다. 공식 마켓플레이스가 커밋 sha를 고정하므로 저자가 릴리스를 태그해도 그 고정점이 갱신되기 전까지는 사용자에게 도달하지 않는다.
setup-matt-pocock-skills가 저장소별 설정을 만든다. 이슈 트래커(GitHub, GitLab, 로컬 마크다운, 기타), triage 라벨 어휘(다섯 개 canonical 역할), 도메인 문서 배치를 각각 한 섹션씩 물어 docs/agents/ 아래에 기록한다. 각 섹션은 추천 답을 먼저 제시해 사용자가 한 단어로 수락할 수 있게 하고, 탐색 단계에서 이미 정해진 섹션은 아예 건너뛴다.
ADR 0001은 이 설정에 대한 의존성을 두 종류로 나눈다.
| 의존 종류 | 해당 스킬 | 설정이 없을 때 | 문서 표기 |
|---|---|---|---|
| 강한 의존 | to-tickets, to-spec, triage |
출력이 틀린다. 특정 트래커에 게시하거나 특정 라벨 문자열을 적용해야 하기 때문 | /setup-matt-pocock-skills를 실행하라는 한 줄을 명시 |
| 약한 의존 | diagnose, tdd, improve-codebase-architecture |
동작은 하고 출력이 덜 날카로워질 뿐 | 모호한 산문으로만 언급 |
이 구분의 목적은 약한 의존 스킬의 토큰을 가볍게 유지하고, 설정 안내가 필요하지 않은 곳까지 관행적으로 복사되는 것을 막는 것이다.
한계
- Codex 네이티브 플러그인 부재. 매니페스트가 승격 부분집합을 표현하지 못해 연기된 상태다. 해소하려면
skills/를 재구성하거나 평면 디렉터리에 사본을 커밋해야 한다. 전자는CLAUDE.md와 스크립트와 버킷 README와 로컬 개발 흐름까지 영향 범위가 넓고, 후자는 동기화 부담과 두 번째 진실의 원천(source of truth)을 만든다. Codex가skills배열이나 포함 목록을 지원하거나 설치 시 심볼릭 링크를 보존하면 재검토한다. - 정량 평가 없음. 스킬의 효과를 재는 벤치마크나 비교 실험이 없다. 각 규율의 근거는 저자의 실무 경험과 고전 인용이므로 다른 팀과 다른 코드베이스에서 같은 효과가 나오는지는 확인되지 않았다.
- 저장소별 설정 선행 조건. engineering 스킬 상당수가
setup-matt-pocock-skills가 만든 설정에 의존한다. 강한 의존 스킬은 설정 없이는 출력이 틀린다. improve-codebase-architecture의 범위 한정. 저자 스스로 이 스킬을 구조 조사이지 구제가 아니라고 밝힌다. 오래된 코드베이스에서 실제 후보를 찾아 주기는 하지만 얽힌 구조를 대신 풀어 주지는 않는다.- in-progress 버킷의 미완성 스킬.
retro,loop-me,writing-beats를 포함한 8개가 의도적으로 공개되어 있으나 플러그인에는 포함되지 않고 문서 페이지도 없다. 설치기로 가져올 수는 있으나 완성도를 보장하지 않는다. - smart zone 가정. 컨텍스트 위생 규칙이 약 15만 토큰이라는 경험적 수치에 기대고 있다. context window와 추론 품질의 관계가 모델마다 다르므로 모델이 바뀌면 함께 조정해야 한다.
핵심 용어
| 용어 | 뜻 |
|---|---|
| user-invoked / model-invoked | 스킬을 가르는 단일 기준. 전자는 사람이 이름을 입력해야만 도달하며 오케스트레이션을 맡고, 후자는 모델도 도달할 수 있으며 재사용 가능한 규율을 담는다 |
| deep module | 작은 interface 뒤에 많은 동작을 두고 깨끗한 seam 위에 놓인 모듈. 설계의 목표 형태다 |
| seam | 그 자리를 편집하지 않고 동작을 바꿀 수 있는 위치. Michael Feathers의 용어이며 interface가 놓이는 자리이자 테스트가 놓이는 자리다 |
| tracer bullet | 모든 계층을 관통하는 좁지만 완전한 수직 슬라이스. 단독으로 시연 가능하고 새 컨텍스트 하나에 들어간다 |
| tight loop | 빠르고 결정적이며 이 버그에서 실패로 바뀌는 재현 loop. diagnosing-bugs 1단계의 산출물이자 나머지 단계의 전제다 |
| context pointer | 컨텍스트 밖 자료를 가리키고 도달 조건을 담은 참조. 도달 여부를 정하는 것은 대상이 아니라 포인터의 문구다 |
나머지 용어(frontier, fog of war, decision ticket, completion criterion, leading word, smell baseline, wide refactor, smart zone)는 요약 source(sources/mattpocock-skills.md)의 용어집에 정리했다.
관련 페이지
- Agent Skills (agentskills/agentskills): 이 저장소가 따르는 Agent Skills 포맷의 오픈 표준 저장소. 이 페이지가 그 포맷 위에 실제 엔지니어링 워크플로를 올린 사례에 해당한다
- Equipping agents for the real world with Agent Skills: Agent Skills 공식 설계 해설. progressive disclosure 3레벨 구조가
writing-for-agents의 정보 계층 사다리와 대응한다 - Beyond the Prompt: Claude Code (Arpan Patel, 2026-05-26): Claude Code 실무 가이드. 커뮤니티 스킬 사례로 이 저장소의
grill-me,tdd,diagnose를 직접 인용한다 - Awesome Harness Engineering: harness 설계 자료 모음. 에이전트를 감싸는 실행 환경을 설계 대상으로 보는 문제의식이 겹친다