Installs into .claude/skills of the current project.
Are you the author of Diffmate?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/chaeeun037-diffmate-diffmate)
---
name: diffmate
description: GitHub PR diff 위의 검수 메모 — 변경 파일마다 한 줄 요약을 채우고, 검수자가 줄에 남긴 질문에 답한다. PR 을 올린 직후, 그리고 "메모 답변 달아줘"·"파일 요약 채워줘"·"리뷰 메모" 류 요청에 로드할 것.
---
# diffmate
검수자는 GitHub 에서 diff 를 읽으며 줄에 메모를 남기고, 나는 같은 자리에 답한다.
메모는 GitHub 에 올라가지 않는다. PR 하나에 파일 하나로 로컬에만 쌓인다.
```
~/.diffmate/<owner>__<repo>/<pr>.json
```
모든 조작은 CLI 로 한다. **JSON 을 직접 고치지 않는다** — 검수자가 같은 순간에 메모를 쓰고 있으면
파일을 통째로 덮어써서 그 메모를 날린다.
`DIFFMATE` 에 이 레포를 클론한 경로를 넣는다.
```bash
DIFFMATE=~/diffmate # 자기 경로에 맞춘다
node $DIFFMATE/cli/notes.mjs list
```
## 1. PR 을 올린 직후
아래 둘을 같이 하고, **기다리지 않는다.**
```bash
npm --prefix $DIFFMATE run check # 0 이면 데몬 떠 있음, 1 이면 꺼져 있음
```
1 이면 `npm --prefix $DIFFMATE start` 를 백그라운드로 띄운다. 그다음 파일 요약을 채운다.
저장 경로에 PR 번호가 들어가서 PR 이 생긴 뒤에만 쓸 수 있고, 확장이 3초마다 다시 읽으므로
검수자가 화면을 여는 동안 늦게 도착해도 그대로 뜬다.
데몬이 꺼져 있어도 요약은 기록된다 — CLI 가 파일에 직접 쓴다. 데몬은 확장이 읽을 때 필요하다.
리뷰 커밋이 쌓이면 요약이 낡는다. **답변 차례마다 먼저 `stale` 을 돌려 대상만 다시 읽는다.**
```bash
node $DIFFMATE/cli/notes.mjs stale <owner/repo> <pr>
```
`요약 없음`(새로 생긴 파일)·`바뀜`(커밋으로 내용이 달라짐)·`PR 에서 빠짐` 세 가지가 나온다.
여기 안 나온 파일은 요약을 쓸 때와 같은 내용이므로 다시 읽지 않는다.
답이 달린 파일의 요약을 고쳤으면 **왜 바뀌었는지 그 카드에 한 줄 남긴다** — 앞선 되물음이 옛 요약을 인용하고 있다.
## 2. 파일 요약 쓰기
목표는 변경 설명이 아니라 **틀렸을 때 무엇이 깨지는지**를 먼저 보여주는 것이다.
무엇이 바뀌었는지는 diff 가 이미 말한다.
```
[역할 라벨]. [볼 곳]이 [틀린 상태]면 [결과].
```
1. **역할 라벨** — 파일의 일반 역할이 아니라 이 PR 에서 맡은 일. 짧은 명사구로.
2. **틀리면-문장** — 긍정 조건으로 쓴다. 부정은 한 번까지. 줄표는 쓰지 않는다.
3. **한 줄 = 확인 지점 하나.** 화면 한 줄을 넘기지 않는다. 넘치면 이유를 버리지, 확인 지점을 버리지 않는다.
4. **줄 수 = 서로 다르게 깨지는 방식의 수.** 최대 3줄. 해명으로 늘리지 않고, 반대로 범위가 넓은 파일을
한 줄로 욱여넣지도 않는다 — 그러면 "전부 여기 있다"가 되어 아무것도 못 짚는다.
5. **트레이드오프는 마지막 줄에 `결정: [고른 것]. [치른 값].`** 으로. 이유가 아니라 치른 값을 쓴다.
이유는 설득이고, 값은 검수 대상이다.
6. **배너는 혼자 선다.** "위와 같이" 금지 — GitHub 은 경로순이라 읽는 순서를 보장하지 않는다.
### 확인 지점 고르는 순서
돌려보지 못한 곳 → 에러·타입·테스트 없이 조용히 깨지는 곳 → 이 파일 밖으로 번지는 곳.
**코드에 이미 가드가 있으면 확인 지점이 아니다.** 후보에서 뺀다 —
확인 지점을 하나 올릴 때마다 **그 자리 코드를 열어 가드가 있는지 보고 나서** 올린다. 안 보고 올리면
그럴듯한 위험을 지어내게 된다(실제로 두 건 있었다).
**틀리면-문장이 안 써지면 위험도를 `low` 로 내리고 라벨만 쓴다.** 탈출구가 아니라 기본 동작이다.
지어낸 위험보다 "안 돌려봤다"가 값지다.
### 위험도
틀렸을 때 **번지는 범위**로 가른다. 파일 크기나 변경량은 기준이 아니다.
| 값 | 기준 |
| --- | --- |
| `high` | 이 기능 밖으로 번지거나 측정·데이터 전체가 무효가 된다. PR 당 3개까지 |
| `mid` | 이 파일이 맡은 부분만 틀린다 |
| `low` | 틀리면-문장을 지어내야만 쓸 수 있다. 라벨만 쓴다 |
`low` 가 절반쯤 나와야 정상이다. 전부 경고면 아무것도 경고가 아니다.
### 쉬운 말로 쓴다
**판정: 이걸 만들지 않은 사람이 읽고 무슨 말인지 아는가.** 아니면 다시 쓴다.
작업하는 동안에만 통하던 말은 한 달 뒤의 본인도 못 읽는다.
| 쓰지 않는다 | 이렇게 쓴다 |
| --- | --- |
| 인라인 비콘 | 모든 페이지의 HTML 에 심는 '측정 시작' 신호 |
| 분모가 샌다 | 그 사용자는 통계에서 통째로 사라진다 |
| no-op 이다 | 아무것도 하지 않는다 |
| SPA 로 들어온 세션 | 새로고침 없이 들어온 방문 |
| 마운트 직후 터진다 | 화면에 붙자마자 울린다 |
- **약어와 내부 용어를 아예 쓰지 않는다.** 괄호로 풀어 쓰는 건 두 번째 선택이다. 먼저 쉬운 말을 찾는다.
- **코드 이름은 꼭 필요할 때만** 쓰고, 쓸 때는 그게 무엇인지 함께 쓴다. 이름은 어차피 diff 에 보인다.
- **상수 이름 대신 값과 뜻으로.** `TIMEOUT_MS` → "5초 안에 안 오면".
- 한자·일본어·중국어 문자를 쓰지 않는다. 사용자에게 보이는 문구와 같은 기준이다.
### 쓰지 않는 것
안심 문구("의도한 동작이다"·"여기서 막는다") · 구현 변명("~라서 ~로 미뤘다") ·
이미 막아둔 위험 나열 · 위치 없는 추상어("핵심 로직"·"주의 필요") · 크기 언급("한 줄짜리다" — diff 에 보인다).
### 규칙이 부딪히면
짧게보다 정확하게. 단 줄을 늘리지 말고 이유를 버려서 맞춘다 ·
자연스러운 문장보다 같은 틀 · 마지막 줄은 확인 지점보다 결정.
확인 지점이 4개를 넘으면 파일이나 PR 을 쪼개라는 신호다.
### 넣는 법
```bash
echo '{
"src/pages/_document.tsx": {
"summary": "모든 페이지 HTML에 심는 측정 시작 신호. 첫 줄 경로 검사가 틀리면 전 페이지에서 로그가 나간다.",
"risk": "high", "order": 1
}
}' | node $DIFFMATE/cli/notes.mjs summarize <owner/repo> <pr>
```
`order` 는 검수 권장 순서다. GitHub 은 경로순이라 위험한 파일이 맨 아래 깔리는 일이 흔하다.
변경 파일 전부에 단다.
## 3. 질문에 답하기
```bash
node $DIFFMATE/cli/notes.mjs list # 어느 PR 에 미답변이 남았나
node $DIFFMATE/cli/notes.mjs list <owner/repo> <pr> # 메모 전문
```
`status: "open"` 인 것만 처리한다.
### 답하기 전에 그 자리를 먼저 읽는다
메모마다 `path`·`line`·`lineText` 가 들어 있다. **그 셋으로 코드를 열고 나서 답한다.**
1. 그 파일의 **요약**(`files` 블록)을 읽는다 — 답이 거기 적혀 있는 경우가 있다
2. `line` 주변 코드를 읽는다 — 줄 번호가 없으면 파일 전체의 그 기능 부분
3. 그다음에 답을 쓴다
이 순서를 건너뛰면 질문만 보고 일반 지식으로 답하게 되고, 그럴듯하지만 **그 자리와 어긋난 답**이 나온다.
실제 사례 둘 — 자기가 쓴 요약에 답이 있는데 딴 얘기를 했고, 코드에 이미 있는 가드를 위험으로 지어냈다.
데이터가 깨지는 게 아니라 답의 품질이 조용히 낮아지는 종류라 드러나지 않는다.
| 종류 | 하는 일 |
| --- | --- |
| `question` | 답만 단다. **코드를 고치지 않는다.** |
| `request` | 먼저 고칠 곳을 빠짐없이 찾는다. 고친 뒤에는 **무엇을 어떻게 고쳤는지 답에 적고**, 그 줄이 바뀌었으니 §5 로 앵커를 옮긴다. **고치는 주체가 따로 있으면 앵커를 옮겨 달라는 요청까지 같이 넘긴다** — 이 부탁이 빠지면 메모가 줄을 잃는다. |
| `memo` | 건드리지 않는다. |
```bash
echo '안 돈다. _document 는 서버에서 문자열로만 찍힌다.' \
| node $DIFFMATE/cli/notes.mjs answer <owner/repo> <pr> <noteId>
```
- **카드에는 코드 이야기만 쓴다.** 두 가지가 자꾸 새어 들어온다.
- *내 작업 구조* — 역할 이름·순번·핸드오프·티켓 상태. 읽는 사람은 그 구조를 모르고 알 이유도 없다.
"누구에게 넘겼다"가 아니라 **"이렇게 바꾼다"**로 쓴다. 넘긴 사실이 필요하면 "작업 요청해뒀다" 한 마디면 된다.
- *도구 사정* — 메모를 옮겼다·줄을 못 찾았다·형식을 정리했다. **그건 화면에 이미 보인다.**
옮겨진 카드는 옮겨진 자리에 있고 표시도 붙는다. 글로 또 말하면 정작 코드 이야기가 밀린다.
- 카드가 좁다. **180자 안쪽**(공백 포함, 화면 네다섯 줄)으로 쓴다. 넘치면 문장을 쪼개지 말고
**근거를 버린다** — 결론과 "그래서 어디를 보면 되나"만 남긴다. 더 필요하면 파일을 가리킨다.
- 모르면 모른다고 쓰고, 무엇을 확인하면 되는지 적는다.
- 질문이 틀린 전제 위에 있으면 전제부터 바로잡는다.
## 4. 되물음
검수자가 답글을 달면 그 메모는 다시 `status: "open"` 이 되고 `thread` 에 `by: "me"` 줄이 붙는다.
**`answer` 를 덮어쓰지 않는다** — 답글로 이어야 무엇을 물었는지 남는다.
```bash
echo '<답글>' | node $DIFFMATE/cli/notes.mjs reply <owner/repo> <pr> <noteId>
```
판정은 간단하다. `thread` 의 마지막 줄이 `me` 면 내 차례다.
답글에도 같은 **180자** 상한이 걸린다. 되물음일수록 길어지는데, 앞서 쓴 답을 다시 설명하지 말고
물어본 것만 답한다.
## 5. 코드가 바뀌었거나 메모가 어긋났을 때
`request` 를 처리하면 그 줄이 바뀌어 메모가 엉뚱한 줄에 붙거나 떠돌이로 빠진다.
고친 뒤 새 줄 기준으로 앵커를 옮긴다.
```bash
echo '<새 코드 줄 내용>' | node $DIFFMATE/cli/notes.mjs reanchor <owner/repo> <pr> <noteId> <새 줄번호>
node $DIFFMATE/cli/notes.mjs move <owner/repo> <pr> <noteId> <새 경로>
node $DIFFMATE/cli/notes.mjs normalize <owner/repo> <pr>
```
`move` 는 메모를 다른 파일로 옮긴다(줄 앵커는 버리고 파일 메모가 된다).
`normalize` 는 옛 버전이 만든 저장소를 현재 규칙으로 맞춘다 — 줄 번호가 없으면 파일 메모,
있으면 앵커 해시를 다시 계산한다.
## 6. 끝낼 때
대화에는 **한 줄**만 낸다 — `답변 N건 · 반영 M건`. 답 내용을 다시 풀어 쓰지 않는다. 검수자는 화면에서 본다.