reborn-verify3 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/assets//352/267/234/354/271/231/354/240/201/352/270/260/SKILL.md +57 -0
- package/assets//354/275/224/353/223/234/352/262/200/355/206/240.md +42 -0
- package/cli.mjs +317 -0
- package/package.json +16 -0
- package/skill/SKILL.md +56 -0
- package/tail.mjs +26 -0
- package/verify3.json +88 -0
- package//354/225/210/353/202/264/354/212/244/355/202/254.md +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# reborn-verify3 — 검수3 세팅기
|
|
2
|
+
|
|
3
|
+
클로드 코드가 **제 결과물을 다시 보게 만드는 설정 셋**을 한 줄로 겁니다.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx --yes reborn-verify3@latest
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
| | 무엇 | 어디 | 손으로 하려면 |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| ① | **플랜 모드** — 계획을 먼저 보여 주고 승인받은 다음에만 고친다 | `~/.claude/settings.json` 의 `permissions.defaultMode` | `shift+tab` 두 번 |
|
|
12
|
+
| ② | **검토 에이전트** — 코드를 쓴 에이전트가 아닌 다른 에이전트가 그 코드를 본다 | `~/.claude/agents/코드검토.md` | 에이전트 파일을 직접 적는다 |
|
|
13
|
+
| ③ | **규칙 적기** — 같은 실수를 CLAUDE.md 에 한 줄로 남긴다 | `~/.claude/skills/규칙적기/SKILL.md` | CLAUDE.md 를 열어 직접 적는다 |
|
|
14
|
+
|
|
15
|
+
## 옵션
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx --yes reborn-verify3@latest --check # 지금 뭐가 걸려 있는지만 잰다 (안 고친다)
|
|
19
|
+
npx --yes reborn-verify3@latest --dry-run # 무엇을 어디에 쓸지 보여만 준다
|
|
20
|
+
npx --yes reborn-verify3@latest --undo # 되돌린다
|
|
21
|
+
npx --yes reborn-verify3@latest --local # 이 폴더의 .claude/ 에 건다 (전역 대신)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 남의 설정을 건드립니다 — 그래서 규율이 셋입니다
|
|
25
|
+
|
|
26
|
+
1. `settings.json` 에 쓰기 전에 **반드시 백업**을 뜹니다 (`settings.json.verify3bak_<타임스탬프>`)
|
|
27
|
+
2. `defaultMode` 에 **이미 값이 있으면 덮지 않습니다.** 알리고 넘어갑니다
|
|
28
|
+
3. `--undo` 는 **우리가 쓴 것만** 정확히 되돌립니다 (백업 통째 복원이 아닙니다)
|
|
29
|
+
|
|
30
|
+
## 손으로도 됩니다
|
|
31
|
+
|
|
32
|
+
셋 다 파일입니다. 열어 보면 그대로 보이고, 이 도구 없이 직접 만들어도 똑같습니다.
|
|
33
|
+
위 표의 「어디」와 「손으로 하려면」이 전부입니다. 저희가 하는 건 그걸 한 줄로 거는 것뿐입니다.
|
|
34
|
+
|
|
35
|
+
## 실제로 돌려 본 것 (2026-09-06 · 빈 폴더)
|
|
36
|
+
|
|
37
|
+
생긴 파일 4개 — `settings.json` · `agents/코드검토.md` · `skills/규칙적기/SKILL.md` · `skills/verify3-guide/SKILL.md`
|
|
38
|
+
`--undo` 로 `settings.json` 이 `{}` 로 돌아가고 심은 파일 셋이 사라집니다. 백업은 남습니다.
|
|
39
|
+
`defaultMode` 가 이미 `acceptEdits` 일 때는 그대로 두고 「덮지 않았습니다」를 띄웁니다.
|
|
40
|
+
|
|
41
|
+
## 이 말은 하지 않습니다
|
|
42
|
+
|
|
43
|
+
- 「이러면 버그가 없어진다」 — 줄어드는 것이지 없어지는 게 아닙니다
|
|
44
|
+
- 「무조건 빨라진다」 — 플랜 모드는 한 박자 **느려집니다.** 되돌릴 일이 줄 뿐입니다
|
|
45
|
+
- 클로드 코드는 Anthropic 의 제품이고 저희가 만든 것이 아닙니다. 제휴 관계가 없습니다
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 같은 방식으로 골라 담은 것들
|
|
50
|
+
|
|
51
|
+
이 셋처럼 **무엇을 어디에 쓰는지 보여 주고 되돌릴 수 있는** 스킬 48종을 한 줄로 깝니다 — **리본랩스 스킬팩**, 8,900원.
|
|
52
|
+
목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.
|
|
53
|
+
|
|
54
|
+
https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=verify3
|
|
55
|
+
|
|
56
|
+
MIT · REBORN LABS
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 규칙적기
|
|
3
|
+
description: 클로드가 **같은 실수를 두 번째로** 했을 때 CLAUDE.md 에 한 줄 적어 다음부터 안 틀리게 한다. "또 이러네", "아까도 그랬는데", "이거 매번 설명해야 해", "규칙으로 박아줘" 같은 말이 나오면 쓴다.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 규칙적기
|
|
7
|
+
|
|
8
|
+
## 언제
|
|
9
|
+
|
|
10
|
+
**두 번째다.** 처음 틀린 것은 실수고, 두 번째부터가 규칙이다.
|
|
11
|
+
한 번 틀렸다고 규칙을 적으면 CLAUDE.md 가 금방 못 읽을 만큼 길어지고,
|
|
12
|
+
길어진 CLAUDE.md 는 **세션마다 통째로 문맥에 실려** 값이 든다.
|
|
13
|
+
|
|
14
|
+
## 어디에
|
|
15
|
+
|
|
16
|
+
| 범위 | 파일 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| 이 저장소에서만 | `<저장소>/CLAUDE.md` |
|
|
19
|
+
| 이 폴더 아래에서만 | `<폴더>/CLAUDE.md` — 그 폴더에서 일할 때만 실린다 |
|
|
20
|
+
| 어느 프로젝트에서나 | `~/.claude/CLAUDE.md` |
|
|
21
|
+
|
|
22
|
+
★기본은 **저장소**다. 전역에 적으면 상관없는 프로젝트에서도 매 호출 실린다.
|
|
23
|
+
|
|
24
|
+
## 어떻게 적나
|
|
25
|
+
|
|
26
|
+
한 줄에 셋이 들어간다 — **무엇을 · 왜 · 어기면 어떻게 되나.**
|
|
27
|
+
|
|
28
|
+
```markdown
|
|
29
|
+
- 마이그레이션은 `main` 에 직접 넣지 않는다 — 롤백이 배포와 묶여 되돌릴 수가 없다.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
이유가 없으면 다음 사람(과 다음 세션의 클로드)이 그 줄을 **안전하게 지운다.**
|
|
33
|
+
"하지 마라"만 적힌 줄은 맥락이 사라진 순간 근거 없는 금지가 된다.
|
|
34
|
+
|
|
35
|
+
## 순서
|
|
36
|
+
|
|
37
|
+
1. **무엇이 반복됐는지 한 문장으로 말한다.** 그 문장이 곧 규칙의 앞머리다.
|
|
38
|
+
2. 해당 CLAUDE.md 를 읽는다. **이미 같은 말이 있는지 먼저 본다** — 대개 있다. 있으면
|
|
39
|
+
새 줄을 만들지 말고 **그 줄을 고친다**(안 지켜졌다는 건 문장이 약했다는 뜻이다).
|
|
40
|
+
3. 적절한 절에 한 줄 추가한다. 절이 없으면 만든다.
|
|
41
|
+
4. **적은 줄을 그대로 보여 준다.** 어디에 무엇을 적었는지 사람이 봐야 한다.
|
|
42
|
+
|
|
43
|
+
## 말로 안 되는 것은 관문으로
|
|
44
|
+
|
|
45
|
+
세 번 이상 어겨진 규칙은 **문장이 문제가 아니다.** 그때는 검사기를 만든다 —
|
|
46
|
+
스크립트 하나가 어기면 `exit 1` 하게 하고, 그 명령을 규칙 줄에 같이 적는다.
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
- 릴스 발행본 이름은 언제나 `*_13x.mp4` — 배수에서 이름을 만들면 관문이 못 찾는다.
|
|
50
|
+
검사: `node scripts/check_reel_name.mjs`
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 안 하는 일
|
|
54
|
+
|
|
55
|
+
- 한 번짜리 실수를 규칙으로 만들기
|
|
56
|
+
- 코드를 읽으면 알 수 있는 것 적기 (구조·함수 위치·의존)
|
|
57
|
+
- 이 대화에서만 쓸 임시 지시 적기
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 코드검토
|
|
3
|
+
description: 방금 쓴 코드를 **쓴 사람이 아닌 눈**으로 다시 본다. 파일을 고친 직후, 커밋·PR 전, "이거 맞나" 싶을 때 부른다. 고치지 않고 **무엇이 왜 틀렸는지만** 돌려준다.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 코드검토
|
|
8
|
+
|
|
9
|
+
너는 **이 코드를 쓰지 않았다.** 앞 대화에서 무엇을 하려 했는지 모르고, 알 필요도 없다.
|
|
10
|
+
코드가 실제로 무엇을 하는지만 읽는다.
|
|
11
|
+
|
|
12
|
+
## 왜 따로 있나
|
|
13
|
+
|
|
14
|
+
코드를 쓴 에이전트는 방금 제가 세운 가정을 그대로 들고 검토한다.
|
|
15
|
+
"이 값은 항상 있다"고 믿고 쓴 코드는, 같은 문맥에서 다시 봐도 그 믿음째로 통과한다.
|
|
16
|
+
서브에이전트는 **제 문맥에서 돌기 때문에** 그 믿음을 물려받지 않는다. 그게 이 파일의 전부다.
|
|
17
|
+
|
|
18
|
+
## 보는 순서
|
|
19
|
+
|
|
20
|
+
1. **입력이 없거나 이상할 때** — null·빈 배열·0·음수·아주 큰 값. `x || 기본값` 은 0을 삼킨다.
|
|
21
|
+
2. **실패 경로** — 예외를 삼키고 성공처럼 넘어가는 자리, `catch {}`, 확인 안 하는 반환값.
|
|
22
|
+
3. **경계** — off-by-one, 마지막 원소, 빈 컬렉션, 첫 순회.
|
|
23
|
+
4. **부수효과** — 파일 덮어쓰기, 전역 상태, 순서 의존.
|
|
24
|
+
5. **실제로 돌아가나** — 테스트가 있으면 돌린다. 없으면 최소 재현을 만들어 돌려 본다.
|
|
25
|
+
|
|
26
|
+
## 돌려주는 형식
|
|
27
|
+
|
|
28
|
+
발견마다 세 줄이다. **고치지 마라** — 판단은 부른 쪽이 한다.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
[심각도] 파일:줄
|
|
32
|
+
무엇이 틀렸나 — 한 문장
|
|
33
|
+
어떤 입력에서 어떻게 깨지나 — 구체적인 값으로
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
심각도는 `치명`(데이터 손상·보안·조용한 오답) · `버그`(특정 입력에서 깨짐) · `냄새`(지금은 돌지만 곧 문다) 셋뿐이다.
|
|
37
|
+
|
|
38
|
+
## 안 하는 일
|
|
39
|
+
|
|
40
|
+
- 스타일·포매팅 지적 (린터가 한다)
|
|
41
|
+
- "이렇게 쓰면 더 우아하다" (묻지 않았다)
|
|
42
|
+
- 아무 문제도 못 찾았는데 억지로 하나 만들어 내기 — **없으면 "없다"고 말한다**
|
package/cli.mjs
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* reborn-verify3 — 클로드 코드가 **제 결과물을 다시 보게 만드는 설정 셋**을 건다.
|
|
4
|
+
*
|
|
5
|
+
* npx --yes reborn-verify3@latest 깐다
|
|
6
|
+
* npx --yes reborn-verify3@latest --check 지금 뭐가 걸려 있는지만 잰다 (안 고친다)
|
|
7
|
+
* npx --yes reborn-verify3@latest --dry-run 무엇을 어디에 쓸지 보여만 준다
|
|
8
|
+
* npx --yes reborn-verify3@latest --undo 되돌린다
|
|
9
|
+
* npx --yes reborn-verify3@latest --self-test 검사기가 양방향으로 도는지 시험한다
|
|
10
|
+
*
|
|
11
|
+
* ★★남의 settings.json 을 건드린다. 그래서 규율이 셋이다:
|
|
12
|
+
* ① 쓰기 전에 **반드시 백업**을 뜬다 (settings.json.verify3bak_<타임스탬프>)
|
|
13
|
+
* ② `defaultMode` 에 **이미 값이 있으면 안 덮는다** — 알리고 넘어간다
|
|
14
|
+
* ③ `--undo` 가 우리가 쓴 것만 정확히 되돌린다 (백업 통째 복원이 아니다)
|
|
15
|
+
*
|
|
16
|
+
* ★목록도 명령도 전부 공개돼 있다. 이 도구 없이 손으로 해도 똑같다 — README 에 적어 두었다.
|
|
17
|
+
*/
|
|
18
|
+
import { homedir } from "node:os";
|
|
19
|
+
import { dirname, join } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, copyFileSync, rmSync, statSync } from "node:fs";
|
|
22
|
+
import { TAIL, 링크, 마지막 } from "./tail.mjs";
|
|
23
|
+
|
|
24
|
+
const HOME = homedir();
|
|
25
|
+
const 여기 = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const 인자 = process.argv.slice(2);
|
|
27
|
+
const 확인만 = 인자.includes("--check");
|
|
28
|
+
const 미리보기 = 인자.includes("--dry-run");
|
|
29
|
+
const 되돌리기 = 인자.includes("--undo");
|
|
30
|
+
const 자기시험모드 = 인자.includes("--self-test");
|
|
31
|
+
const 여기에 = 인자.includes("--local");
|
|
32
|
+
|
|
33
|
+
const c = { g: "\x1b[32m", r: "\x1b[31m", y: "\x1b[33m", d: "\x1b[90m", cy: "\x1b[36m", b: "\x1b[1m", 0: "\x1b[0m" };
|
|
34
|
+
const 굵게 = (t) => String(t).replace(/\*\*(.+?)\*\*/g, `${c[0]}${c.b}$1${c[0]}${c.d}`);
|
|
35
|
+
|
|
36
|
+
const 퍼널 = "verify3";
|
|
37
|
+
const 뿌리 = 여기에 ? join(process.cwd(), ".claude") : join(HOME, ".claude");
|
|
38
|
+
const 설정경로 = join(뿌리, "settings.json");
|
|
39
|
+
const 에이전트경로 = join(뿌리, "agents", "코드검토.md");
|
|
40
|
+
const 규칙스킬경로 = join(뿌리, "skills", "규칙적기");
|
|
41
|
+
const 안내스킬경로 = join(뿌리, "skills", "verify3-guide");
|
|
42
|
+
|
|
43
|
+
/* ══ 원장 ═══════════════════════════════════════════════════════ */
|
|
44
|
+
|
|
45
|
+
function 원장읽기() {
|
|
46
|
+
const p = join(여기, "verify3.json");
|
|
47
|
+
if (!existsSync(p)) return { 됨: false, 이유: `원장이 없다: ${p}` };
|
|
48
|
+
try { return { 됨: true, d: JSON.parse(readFileSync(p, "utf8")) }; }
|
|
49
|
+
catch (e) { return { 됨: false, 이유: `원장을 못 읽는다: ${e.message}` }; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** ★조건 없이 단정하는 말 [[kmong-no-unbounded-guarantee]] */
|
|
53
|
+
const 금칙 = [/버그가\s*없어진/, /무제한/, /평생/, /100\s*%\s*보장/, /무조건/, /절대\s*안\s*틀/, /완벽하게/];
|
|
54
|
+
/** ★검사기가 자기 인용을 막지 않게 낫표 안은 벗기고 잰다 [[forbidden-word-checker-blocks-its-own-quotes]] */
|
|
55
|
+
const 인용벗기기 = (s) => String(s).replace(/「[^」]*」/g, "○");
|
|
56
|
+
|
|
57
|
+
function 원장검사(D) {
|
|
58
|
+
const 문제 = [];
|
|
59
|
+
if (!D?.제품?.["★면책"] || !String(D.제품["★면책"]).includes("우리가 만든 것이 아니다"))
|
|
60
|
+
문제.push("제품.★면책 이 없다 — 남의 제품 위에 얹는 도구다");
|
|
61
|
+
if (!Array.isArray(D?.세팅) || D.세팅.length !== 3)
|
|
62
|
+
문제.push(`세팅이 ${D?.세팅?.length ?? 0}개다 — 셋이어야 한다 (이름이 「검수3」이다)`);
|
|
63
|
+
for (const s of D?.세팅 ?? []) {
|
|
64
|
+
for (const k of ["번호", "이름", "무엇", "어디", "값", "손으로", "근거"])
|
|
65
|
+
if (!s?.[k]) 문제.push(`세팅 ${s?.이름 ?? "?"}: ${k} 가 비었다`);
|
|
66
|
+
}
|
|
67
|
+
if (!Array.isArray(D?.["★말하지_않는_자리"]) || D["★말하지_않는_자리"].length < 3)
|
|
68
|
+
문제.push("「말하지 않는 자리」가 3개 미만이다 — 안내가 광고가 된다");
|
|
69
|
+
const 전문 = 인용벗기기(JSON.stringify(D));
|
|
70
|
+
for (const re of 금칙) if (re.test(전문)) 문제.push(`조건 없이 단정하는 말이 있다 — ${re}`);
|
|
71
|
+
return 문제;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ══ 재기 — 「걸었다」가 아니라 「지금 걸려 있나」를 본다 ═══════════ */
|
|
75
|
+
|
|
76
|
+
function JSON읽기(p) {
|
|
77
|
+
if (!existsSync(p)) return null;
|
|
78
|
+
try { return JSON.parse(readFileSync(p, "utf8")); } catch { return "깨짐"; }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function 재기() {
|
|
82
|
+
const s = JSON읽기(설정경로);
|
|
83
|
+
return [
|
|
84
|
+
{ 번호: 1, 이름: "플랜 모드",
|
|
85
|
+
상태: s === "깨짐" ? "설정을 못 읽는다"
|
|
86
|
+
: s?.permissions?.defaultMode === "plan" ? "걸려 있다"
|
|
87
|
+
: s?.permissions?.defaultMode ? `다른 값이다 (${s.permissions.defaultMode})`
|
|
88
|
+
: "안 걸려 있다",
|
|
89
|
+
됨: s !== "깨짐" && s?.permissions?.defaultMode === "plan", 어디: 설정경로 },
|
|
90
|
+
{ 번호: 2, 이름: "검토 에이전트",
|
|
91
|
+
상태: existsSync(에이전트경로) ? "걸려 있다" : "안 걸려 있다",
|
|
92
|
+
됨: existsSync(에이전트경로), 어디: 에이전트경로 },
|
|
93
|
+
{ 번호: 3, 이름: "규칙 적기",
|
|
94
|
+
상태: existsSync(join(규칙스킬경로, "SKILL.md")) ? "걸려 있다" : "안 걸려 있다",
|
|
95
|
+
됨: existsSync(join(규칙스킬경로, "SKILL.md")), 어디: 규칙스킬경로 },
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* ══ 심기 ═══════════════════════════════════════════════════════ */
|
|
100
|
+
|
|
101
|
+
function 백업(p) {
|
|
102
|
+
const 이름 = `${p}.verify3bak_${new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}`;
|
|
103
|
+
copyFileSync(p, 이름);
|
|
104
|
+
return 이름;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* ① 플랜 모드. ★이미 `defaultMode` 가 있으면 **안 덮는다.**
|
|
109
|
+
* 남의 설정을 조용히 바꾸면 그 사람은 왜 모드가 달라졌는지 영영 모른다.
|
|
110
|
+
*/
|
|
111
|
+
function 플랜모드걸기() {
|
|
112
|
+
mkdirSync(뿌리, { recursive: true });
|
|
113
|
+
let s = {};
|
|
114
|
+
let 백업본 = null;
|
|
115
|
+
if (existsSync(설정경로)) {
|
|
116
|
+
const 읽은 = JSON읽기(설정경로);
|
|
117
|
+
if (읽은 === "깨짐") return { 됨: false, 말: "settings.json 이 JSON 이 아니다 — 손대지 않았다" };
|
|
118
|
+
s = 읽은 ?? {};
|
|
119
|
+
백업본 = 백업(설정경로);
|
|
120
|
+
}
|
|
121
|
+
s.permissions ??= {};
|
|
122
|
+
const 옛값 = s.permissions.defaultMode;
|
|
123
|
+
if (옛값 === "plan") return { 됨: true, 말: "이미 plan 이다", 손댐: false };
|
|
124
|
+
if (옛값) return { 됨: false, 말: `이미 ${옛값} 로 정해 두셨습니다 — 덮지 않았습니다`, 손댐: false, 백업본 };
|
|
125
|
+
s.permissions.defaultMode = "plan";
|
|
126
|
+
s.__verify3 = { defaultMode: "plan", 건날: new Date().toISOString().slice(0, 10) };
|
|
127
|
+
writeFileSync(설정경로, JSON.stringify(s, null, 2) + "\n", "utf8");
|
|
128
|
+
return { 됨: true, 말: "plan 으로 걸었다", 손댐: true, 백업본 };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function 파일심기(원본, 대상, 최소 = 300) {
|
|
132
|
+
mkdirSync(dirname(대상), { recursive: true });
|
|
133
|
+
copyFileSync(원본, 대상);
|
|
134
|
+
if (!existsSync(대상)) throw new Error(`심었는데 없다 — ${대상}`);
|
|
135
|
+
if (statSync(대상).size < 최소) throw new Error(`${대상} 이 ${statSync(대상).size}바이트다 — 복사가 끊긴 것 같다`);
|
|
136
|
+
return 대상;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function 폴더심기(원본, 대상) {
|
|
140
|
+
mkdirSync(dirname(대상), { recursive: true });
|
|
141
|
+
cpSync(원본, 대상, { recursive: true });
|
|
142
|
+
const p = join(대상, "SKILL.md");
|
|
143
|
+
if (!existsSync(p)) throw new Error(`심었는데 SKILL.md 이 없다 — ${p}`);
|
|
144
|
+
if (readFileSync(p, "utf8").length < 300) throw new Error(`${p} 이 너무 짧다 — 복사가 끊긴 것 같다`);
|
|
145
|
+
return 대상;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function 심기() {
|
|
149
|
+
const 한것 = [];
|
|
150
|
+
한것.push({ 번호: 1, ...플랜모드걸기() });
|
|
151
|
+
파일심기(join(여기, "assets", "코드검토.md"), 에이전트경로, 800);
|
|
152
|
+
한것.push({ 번호: 2, 됨: true, 말: "심었다", 손댐: true });
|
|
153
|
+
폴더심기(join(여기, "assets", "규칙적기"), 규칙스킬경로);
|
|
154
|
+
한것.push({ 번호: 3, 됨: true, 말: "심었다", 손댐: true });
|
|
155
|
+
폴더심기(join(여기, "skill"), 안내스킬경로);
|
|
156
|
+
return 한것;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* ══ 되돌리기 — 우리가 쓴 것만 정확히 ═══════════════════════════ */
|
|
160
|
+
|
|
161
|
+
function 되돌리다() {
|
|
162
|
+
const 한것 = [];
|
|
163
|
+
const s = JSON읽기(설정경로);
|
|
164
|
+
if (s && s !== "깨짐") {
|
|
165
|
+
if (s.__verify3 && s.permissions?.defaultMode === "plan") {
|
|
166
|
+
백업(설정경로);
|
|
167
|
+
delete s.permissions.defaultMode;
|
|
168
|
+
if (!Object.keys(s.permissions).length) delete s.permissions;
|
|
169
|
+
delete s.__verify3;
|
|
170
|
+
writeFileSync(설정경로, JSON.stringify(s, null, 2) + "\n", "utf8");
|
|
171
|
+
한것.push("① 플랜 모드 기본값을 뺐다 (원래 없던 칸이다)");
|
|
172
|
+
} else if (s.permissions?.defaultMode === "plan") {
|
|
173
|
+
한것.push("① defaultMode 가 plan 이지만 저희가 건 표식이 없어 손대지 않았다");
|
|
174
|
+
} else 한것.push("① 걸려 있지 않다");
|
|
175
|
+
} else 한것.push("① settings.json 이 없거나 못 읽는다");
|
|
176
|
+
|
|
177
|
+
for (const [n, p] of [["②", 에이전트경로], ["③", 규칙스킬경로], ["", 안내스킬경로]]) {
|
|
178
|
+
if (existsSync(p)) { rmSync(p, { recursive: true, force: true }); if (n) 한것.push(`${n} ${p} 를 지웠다`); }
|
|
179
|
+
else if (n) 한것.push(`${n} 걸려 있지 않다`);
|
|
180
|
+
}
|
|
181
|
+
return 한것;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* ══ 화면 ═══════════════════════════════════════════════════════ */
|
|
185
|
+
|
|
186
|
+
function 머리(D) {
|
|
187
|
+
console.log(`\n${c.b}${D.제품.한글}${c[0]} ${c.d}— ${D.제품.이름}${c[0]}`);
|
|
188
|
+
console.log(`${c.d}클로드 코드가 제 결과물을 다시 보게 만드는 설정 ${D.세팅.length}가지. 값은 ${D.값.가격}, ${D.값.라이선스}.${c[0]}\n`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function 표(D, 잰것) {
|
|
192
|
+
for (const s of D.세팅) {
|
|
193
|
+
const m = 잰것.find((x) => x.번호 === s.번호);
|
|
194
|
+
const 색 = m?.됨 ? c.g : c.y;
|
|
195
|
+
const 표식 = m?.됨 ? "✓" : "·";
|
|
196
|
+
console.log(` ${색}${표식}${c[0]} ${c.b}${s.번호}. ${s.이름}${c[0]} ${c.d}— ${s.무엇}${c[0]}`);
|
|
197
|
+
console.log(` ${c.d}어디: ${s.어디}${c[0]}`);
|
|
198
|
+
console.log(` ${c.d}손으로 하려면: ${s.손으로}${c[0]}`);
|
|
199
|
+
if (m) console.log(` ${색}지금: ${m.상태 ?? m.말}${c[0]}`);
|
|
200
|
+
console.log();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function 꼬리(깔았나) {
|
|
205
|
+
if (!깔았나) return;
|
|
206
|
+
const t = TAIL[퍼널];
|
|
207
|
+
console.log();
|
|
208
|
+
for (const 줄 of t.이음) console.log(`${c.d}${굵게(줄)}${c[0]}`);
|
|
209
|
+
console.log(`\n ${c.b}${t.제목}${c[0]} ${c.d}— ${t.한줄}${c[0]}`);
|
|
210
|
+
console.log(` ${c.cy}${링크(퍼널)}${c[0]}`);
|
|
211
|
+
console.log(`${c.d}${마지막}${c[0]}\n`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* ══ 자기시험 — ★양방향 ═══════════════════════════════════════ */
|
|
215
|
+
|
|
216
|
+
function 자기시험() {
|
|
217
|
+
const 나쁨 = [];
|
|
218
|
+
const r = 원장읽기();
|
|
219
|
+
if (!r.됨) { console.log(`${c.r}✗ ${r.이유}${c[0]}`); process.exit(1); }
|
|
220
|
+
const D = r.d;
|
|
221
|
+
|
|
222
|
+
const 문제 = 원장검사(D);
|
|
223
|
+
if (문제.length) 나쁨.push(...문제.map((m) => `오탐 또는 진짜 문제: ${m}`));
|
|
224
|
+
|
|
225
|
+
const 흉내 = () => JSON.parse(JSON.stringify(D));
|
|
226
|
+
{ const x = 흉내(); x.제품["★면책"] = "저희가 만든 제품입니다";
|
|
227
|
+
if (!원장검사(x).length) 나쁨.push("미탐: ★면책을 지웠는데 안 잡힌다"); }
|
|
228
|
+
{ const x = 흉내(); x.세팅.pop();
|
|
229
|
+
if (!원장검사(x).length) 나쁨.push("미탐: 세팅이 둘인데 안 잡힌다"); }
|
|
230
|
+
{ const x = 흉내(); delete x.세팅[0].근거;
|
|
231
|
+
if (!원장검사(x).length) 나쁨.push("미탐: 세팅의 근거를 지웠는데 안 잡힌다"); }
|
|
232
|
+
{ const x = 흉내(); x["★말하지_않는_자리"].pop();
|
|
233
|
+
if (!원장검사(x).length) 나쁨.push("미탐: 말하지 않는 자리가 둘인데 안 잡힌다"); }
|
|
234
|
+
{ const x = 흉내(); x.세팅[0].무엇 = "이걸 걸면 버그가 없어진다";
|
|
235
|
+
if (!원장검사(x).length) 나쁨.push("미탐: 조건 없이 단정하는 문구가 안 잡힌다"); }
|
|
236
|
+
/* ★오탐 — 금칙어를 낫표 안에 인용한 것은 잡으면 안 된다 */
|
|
237
|
+
{ const x = 흉내(); x["★말하지_않는_자리"].push("「무조건 빨라진다」 는 말은 하지 않는다");
|
|
238
|
+
if (원장검사(x).length > 문제.length) 나쁨.push("오탐: 금칙어를 낫표로 인용했는데 잡힌다"); }
|
|
239
|
+
|
|
240
|
+
/* 재기가 양방향으로 도는가 — 없는 자리를 「걸려 있다」고 하면 안 된다 */
|
|
241
|
+
const 잰것 = 재기();
|
|
242
|
+
if (잰것.length !== 3) 나쁨.push(`재기가 ${잰것.length}줄을 냈다 — 3줄이어야 한다`);
|
|
243
|
+
for (const m of 잰것) if (typeof m.됨 !== "boolean") 나쁨.push(`재기 ${m.번호}: 됨 이 불리언이 아니다`);
|
|
244
|
+
|
|
245
|
+
/* 심을 원본이 실제로 있는가 */
|
|
246
|
+
for (const [p, 최소] of [[join(여기, "assets", "코드검토.md"), 800],
|
|
247
|
+
[join(여기, "assets", "규칙적기", "SKILL.md"), 800],
|
|
248
|
+
[join(여기, "skill", "SKILL.md"), 800]]) {
|
|
249
|
+
if (!existsSync(p)) 나쁨.push(`심을 원본이 없다: ${p}`);
|
|
250
|
+
else if (statSync(p).size < 최소) 나쁨.push(`심을 원본이 ${statSync(p).size}바이트다: ${p}`);
|
|
251
|
+
}
|
|
252
|
+
/* 에이전트·스킬 frontmatter 가 실제로 있는가 — 없으면 클로드가 못 읽는다 */
|
|
253
|
+
for (const [p, 키] of [[join(여기, "assets", "코드검토.md"), "name:"],
|
|
254
|
+
[join(여기, "assets", "규칙적기", "SKILL.md"), "description:"],
|
|
255
|
+
[join(여기, "skill", "SKILL.md"), "description:"]]) {
|
|
256
|
+
const t = readFileSync(p, "utf8");
|
|
257
|
+
if (!t.startsWith("---\n") || !t.includes(키)) 나쁨.push(`${p}: frontmatter 에 ${키} 가 없다`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (나쁨.length) {
|
|
261
|
+
console.log(`\n${c.r}✗ 자기시험 ${나쁨.length}건${c[0]}`);
|
|
262
|
+
for (const m of 나쁨) console.log(` ${c.r}· ${m}${c[0]}`);
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
console.log(`\n${c.g}✓ 자기시험 통과${c[0]} ${c.d}— 원장 검사 양방향(미탐 5·오탐 1) · 재기 3줄 · 심을 원본 3종 · frontmatter 확인${c[0]}\n`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* ══ 본체 ═══════════════════════════════════════════════════════ */
|
|
269
|
+
|
|
270
|
+
function 본체() {
|
|
271
|
+
if (자기시험모드) return 자기시험();
|
|
272
|
+
|
|
273
|
+
const r = 원장읽기();
|
|
274
|
+
if (!r.됨) { console.log(`${c.r}✗ ${r.이유}${c[0]}`); process.exit(1); }
|
|
275
|
+
const D = r.d;
|
|
276
|
+
const 문제 = 원장검사(D);
|
|
277
|
+
if (문제.length) {
|
|
278
|
+
console.log(`\n${c.r}✗ 원장이 규격을 안 지킨다${c[0]}`);
|
|
279
|
+
for (const m of 문제) console.log(` ${c.r}· ${m}${c[0]}`);
|
|
280
|
+
process.exit(1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
머리(D);
|
|
284
|
+
|
|
285
|
+
if (되돌리기) {
|
|
286
|
+
for (const 줄 of 되돌리다()) console.log(` ${c.d}${줄}${c[0]}`);
|
|
287
|
+
console.log(`\n${c.g}✓ 되돌렸습니다.${c[0]} ${c.d}백업은 ${설정경로}.verify3bak_* 로 남아 있습니다.${c[0]}\n`);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (확인만) { 표(D, 재기()); console.log(`${c.d}고치려면 옵션 없이 한 번 더 돌리세요.${c[0]}\n`); return; }
|
|
292
|
+
|
|
293
|
+
if (미리보기) {
|
|
294
|
+
표(D, 재기());
|
|
295
|
+
console.log(`${c.d}--dry-run 이라 아무것도 안 썼습니다. 쓸 자리는 위 「어디」 세 곳입니다.${c[0]}\n`);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
let 한것;
|
|
300
|
+
try { 한것 = 심기(); }
|
|
301
|
+
catch (e) { console.log(`${c.r}✗ ${e.message}${c[0]}\n`); process.exit(1); }
|
|
302
|
+
|
|
303
|
+
표(D, 재기());
|
|
304
|
+
|
|
305
|
+
const 안된것 = 한것.filter((x) => !x.됨);
|
|
306
|
+
for (const x of 안된것) console.log(` ${c.y}! ${x.번호}번: ${x.말}${c[0]}`);
|
|
307
|
+
if (안된것.length) console.log();
|
|
308
|
+
|
|
309
|
+
const 깔았나 = 재기().some((m) => m.됨);
|
|
310
|
+
if (깔았나) {
|
|
311
|
+
console.log(`${c.g}✓ 끝났습니다.${c[0]} ${c.d}클로드 코드를 새로 켜면 적용됩니다 — 이미 열려 있는 세션은 그대로입니다.${c[0]}`);
|
|
312
|
+
console.log(`${c.d}되돌리기: npx --yes reborn-verify3@latest --undo${c[0]}`);
|
|
313
|
+
}
|
|
314
|
+
꼬리(깔았나);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
본체();
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reborn-verify3",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "클로드 코드 결과물을 다시 보게 만드는 설정 셋을 한 줄로 겁니다 — ①플랜 모드 기본값(계획을 먼저 보여주고 승인 뒤에만 고친다) ②코드를 쓴 에이전트가 아닌 다른 에이전트가 다시 보는 검토 서브에이전트 ③같은 실수를 CLAUDE.md 에 한 줄로 적어 두는 스킬. 셋 다 손으로도 할 수 있고, 무엇을 어디에 쓰는지 전부 보여 줍니다. --undo 로 되돌립니다.",
|
|
5
|
+
"keywords": ["claude", "claude-code", "agent-skills", "plan-mode", "code-review", "subagent", "claude-md", "korean"],
|
|
6
|
+
"homepage": "https://rebornlabs.kr/verify3?utm_source=installer&utm_medium=cli&utm_campaign=verify3",
|
|
7
|
+
"bugs": { "url": "https://mobility.rebornlabs.kr/cs" },
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "REBORN LABS",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"bin": { "reborn-verify3": "cli.mjs" },
|
|
12
|
+
"files": ["cli.mjs", "tail.mjs", "skill/", "assets/", "verify3.json", "README.md", "안내스킬.md"],
|
|
13
|
+
"engines": { "node": ">=18" },
|
|
14
|
+
"scripts": { "test": "node cli.mjs --self-test", "check": "node cli.mjs --check" },
|
|
15
|
+
"publishConfig": { "access": "public" }
|
|
16
|
+
}
|
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verify3-guide
|
|
3
|
+
description: 클로드 코드가 제 결과물을 스스로 다시 보게 만드는 설정 셋(플랜 모드 · 검토 에이전트 · 규칙 적기)이 지금 어떻게 걸려 있는지 알려 주고, 하나씩 껐다 켜는 법을 안내한다. "플랜 모드", "계획 먼저", "shift tab", "코드 검토 시켜줘", "클로드가 자꾸 엉뚱한 걸 만든다", "같은 실수를 반복한다", "verify3", "검수3" 같은 이야기가 나올 때 쓴다.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 검수3 — 지금 무엇이 걸려 있나
|
|
7
|
+
|
|
8
|
+
`reborn-verify3` 가 건 것은 셋이다. **셋 다 파일이라 열어 보면 그대로 보인다.**
|
|
9
|
+
|
|
10
|
+
| | 무엇 | 어디 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| ① | 플랜 모드 기본값 | `~/.claude/settings.json` → `permissions.defaultMode: "plan"` |
|
|
13
|
+
| ② | 검토 서브에이전트 | `~/.claude/agents/코드검토.md` |
|
|
14
|
+
| ③ | 규칙 적기 스킬 | `~/.claude/skills/규칙적기/SKILL.md` |
|
|
15
|
+
|
|
16
|
+
지금 상태를 재려면: `npx --yes reborn-verify3@latest --check`
|
|
17
|
+
|
|
18
|
+
## ① 플랜 모드 — 무엇이 달라지나
|
|
19
|
+
|
|
20
|
+
클로드가 **파일을 고치기 전에 계획을 먼저 보여 주고 승인을 기다린다.**
|
|
21
|
+
승인 전에는 읽기·검색만 한다.
|
|
22
|
+
|
|
23
|
+
- 한 세션만 끄기: 그 세션에서 `shift+tab` 을 눌러 모드를 돌린다
|
|
24
|
+
- 아예 되돌리기: `npx --yes reborn-verify3@latest --undo`
|
|
25
|
+
- 한 번만 다른 모드로 시작: `claude --permission-mode acceptEdits`
|
|
26
|
+
|
|
27
|
+
★**느려지는 게 맞다.** 한 박자 늦는 대신 엉뚱한 걸 다 만들고 되돌리는 일을 줄인다.
|
|
28
|
+
탐색적으로 빠르게 굴려야 하는 세션에서는 `shift+tab` 으로 그때만 푸는 게 낫다.
|
|
29
|
+
|
|
30
|
+
## ② 검토 에이전트 — 언제 부르나
|
|
31
|
+
|
|
32
|
+
파일을 고친 **직후**, 커밋·PR 전에 부른다.
|
|
33
|
+
|
|
34
|
+
> "방금 고친 것 코드검토 에이전트로 다시 봐줘"
|
|
35
|
+
|
|
36
|
+
같은 세션의 클로드에게 "다시 봐"라고 하면 **제가 세운 가정을 그대로 들고** 다시 본다.
|
|
37
|
+
서브에이전트는 제 문맥에서 돌아 그 가정을 물려받지 않는다. 그래서 따로 있다.
|
|
38
|
+
|
|
39
|
+
돌려주는 건 `치명 / 버그 / 냄새` 세 등급의 목록이고, **고치지는 않는다.** 판단은 사람이 한다.
|
|
40
|
+
|
|
41
|
+
## ③ 규칙 적기 — 언제 부르나
|
|
42
|
+
|
|
43
|
+
같은 실수를 **두 번째로** 봤을 때.
|
|
44
|
+
|
|
45
|
+
> "또 이러네, 규칙으로 박아줘"
|
|
46
|
+
|
|
47
|
+
CLAUDE.md 에 한 줄 적는다 — **무엇을 · 왜 · 어기면 어떻게 되나.**
|
|
48
|
+
이유 없는 "하지 마라"는 다음 세션이 안전하게 지운다.
|
|
49
|
+
|
|
50
|
+
★세 번 이상 어겨진 규칙은 문장이 약한 게 아니라 **말로 될 일이 아니다.** 그때는 검사기를 만든다.
|
|
51
|
+
|
|
52
|
+
## 안 하는 말
|
|
53
|
+
|
|
54
|
+
- 「이러면 버그가 없어진다」 — 줄어드는 것이지 없어지는 게 아니다
|
|
55
|
+
- 「무조건 빨라진다」 — 플랜 모드는 한 박자 느려진다. 되돌릴 일이 줄 뿐이다
|
|
56
|
+
- 클로드 코드는 Anthropic 의 제품이다. 이 설치기는 그 위에 설정을 얹을 뿐이다
|
package/tail.mjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「끝난 뒤 한 칸」 문안 — 정본은 `skillpack/tail_copy.mjs` 다.
|
|
3
|
+
* 사본이 여기 있는 이유는 하나뿐이다: npm 패키지는 폴더 밖을 import 할 수 없다.
|
|
4
|
+
*
|
|
5
|
+
* 규율: ① 끝난 뒤 딱 한 칸 · ② 못 깔았으면 안 띄운다 · ③ 파일을 안 남긴다
|
|
6
|
+
* ④ 고지 블록 금지 · ⑤ 첫 줄은 방금 한 일에서 이어져야 한다
|
|
7
|
+
* ★클로드킷·자비스 풀스택은 여기서 말하지 않는다 — 스킬팩 구매 이후다(2026-08-24 전략).
|
|
8
|
+
*/
|
|
9
|
+
/* ★맨 주소를 상수로 두지 않는다 — 계측 관문이 「utm 없는 링크」로 잡는다.
|
|
10
|
+
화면에 나가는 것은 아래 링크() 가 만든 utm 붙은 주소뿐이다. */
|
|
11
|
+
const 랜딩경로 = "https://rebornlabs.kr" + "/skillpack";
|
|
12
|
+
export const 랜딩 = 랜딩경로;
|
|
13
|
+
export const 링크 = (퍼널) => `${랜딩}?utm_source=installer&utm_medium=cli&utm_campaign=${퍼널}`;
|
|
14
|
+
|
|
15
|
+
export const TAIL = {
|
|
16
|
+
verify3: {
|
|
17
|
+
이음: [
|
|
18
|
+
"방금 한 일은 **클로드가 제 결과물을 스스로 다시 보게 만드는 설정 셋을 건 것**입니다.",
|
|
19
|
+
"셋 다 손으로 할 수 있고, 무엇을 어디에 썼는지 위에 그대로 적어 두었습니다.",
|
|
20
|
+
],
|
|
21
|
+
제목: "리본랩스 스킬팩",
|
|
22
|
+
한줄: "같은 방식으로 골라 담은 48종을 한 줄로. 8,900원",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const 마지막 = "목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.";
|
package/verify3.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"제품": {
|
|
3
|
+
"이름": "reborn-verify3",
|
|
4
|
+
"한글": "검수3 세팅기",
|
|
5
|
+
"만든곳": "REBORN LABS",
|
|
6
|
+
"확인일": "2026-09-06",
|
|
7
|
+
"★면책": "클로드 코드는 Anthropic 의 제품이고 우리가 만든 것이 아니다. 이 설치기는 그 위에 설정 셋을 얹을 뿐이다."
|
|
8
|
+
},
|
|
9
|
+
"세팅": [
|
|
10
|
+
{
|
|
11
|
+
"번호": 1,
|
|
12
|
+
"이름": "플랜 모드",
|
|
13
|
+
"무엇": "클로드가 계획을 먼저 보여 주고 승인받은 다음에만 파일을 고친다",
|
|
14
|
+
"어디": "~/.claude/settings.json 의 permissions.defaultMode",
|
|
15
|
+
"값": "plan",
|
|
16
|
+
"손으로": "shift+tab 두 번",
|
|
17
|
+
"근거": "claude --permission-mode 의 유효값 6종 중 하나 (2026-09-06 실측: acceptEdits, auto, bypassPermissions, manual, dontAsk, plan)"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"번호": 2,
|
|
21
|
+
"이름": "검토 에이전트",
|
|
22
|
+
"무엇": "코드를 쓴 에이전트가 아니라 다른 에이전트가 그 코드를 다시 본다",
|
|
23
|
+
"어디": "~/.claude/agents/코드검토.md",
|
|
24
|
+
"값": "서브에이전트 1종",
|
|
25
|
+
"손으로": "에이전트 파일을 직접 적는다",
|
|
26
|
+
"근거": "서브에이전트는 제 문맥에서 돌아 앞 대화의 판단을 물려받지 않는다"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"번호": 3,
|
|
30
|
+
"이름": "규칙 적기",
|
|
31
|
+
"무엇": "같은 실수를 만나면 CLAUDE.md 에 한 줄 적어 다음부터 안 틀리게 한다",
|
|
32
|
+
"어디": "~/.claude/skills/규칙적기/SKILL.md",
|
|
33
|
+
"값": "스킬 1종",
|
|
34
|
+
"손으로": "CLAUDE.md 를 열어 직접 적는다",
|
|
35
|
+
"근거": "CLAUDE.md 는 세션마다 문맥에 실린다"
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"값": { "가격": "0원", "라이선스": "MIT" },
|
|
39
|
+
"★실측": {
|
|
40
|
+
"잰날": "2026-09-06",
|
|
41
|
+
"어디서": "빈 폴더에서 cli.mjs --local 로 실제 실행",
|
|
42
|
+
"생긴파일": [
|
|
43
|
+
".claude/settings.json",
|
|
44
|
+
".claude/agents/코드검토.md",
|
|
45
|
+
".claude/skills/규칙적기/SKILL.md",
|
|
46
|
+
".claude/skills/verify3-guide/SKILL.md"
|
|
47
|
+
],
|
|
48
|
+
"되돌리기": "--undo 로 settings.json 이 {} 로 돌아가고 심은 파일 셋이 사라졌다. 백업은 남는다",
|
|
49
|
+
"안덮기": "defaultMode 가 이미 acceptEdits 이면 그대로 두고 「덮지 않았습니다」를 띄웠다"
|
|
50
|
+
},
|
|
51
|
+
"★결과물": [
|
|
52
|
+
{
|
|
53
|
+
"번호": 1,
|
|
54
|
+
"무엇": "플랜 모드가 실제로 걸린 설정 파일",
|
|
55
|
+
"화면": "settings.json 에 permissions.defaultMode: plan 이 쓰이는 것",
|
|
56
|
+
"근거": "2026-09-06 빈 폴더 실행 결과. 실행 전에는 파일 자체가 없었다"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"번호": 2,
|
|
60
|
+
"무엇": "검토 에이전트가 실제로 잡아낸 것",
|
|
61
|
+
"화면": "일부러 흔한 실수를 심은 배송비 함수 5줄 → 검토 4건",
|
|
62
|
+
"근거": "2026-09-06 claude -p 로 실제 실행. 아래 검토 칸이 그때 나온 글 그대로다",
|
|
63
|
+
"검토대상": "export function 배송비(주문) { const 무게 = 주문.무게 || 1; ... }",
|
|
64
|
+
"검토": [
|
|
65
|
+
{ "등급": "치명", "자리": "cart.mjs:2", "무엇": "|| 기본값이 무게 0을 falsy 로 보고 1로 바꾼다", "언제": "{무게: 0} → 배송비 500원이 잘못 청구된다" },
|
|
66
|
+
{ "등급": "치명", "자리": "cart.mjs:5", "무엇": "쿠폰을 뺀 뒤 하한이 없어 음수 배송비가 나온다", "언제": "{쿠폰할인: 10000} → -9,500원" },
|
|
67
|
+
{ "등급": "버그", "자리": "cart.mjs:2", "무엇": "음수 무게가 그대로 통과한다", "언제": "{무게: -5} → 기본 배송비가 -2,500원" },
|
|
68
|
+
{ "등급": "버그", "자리": "cart.mjs:1-5", "무엇": "인자가 없거나 숫자가 아닐 때 방어가 없다", "언제": "배송비(null) 예외 · {무게:\"abc\"} → NaN 이 그대로 나간다" }
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"번호": 3,
|
|
73
|
+
"무엇": "규칙이 쌓여 다음부터 안 틀리는 것",
|
|
74
|
+
"화면": "CLAUDE.md 에 규칙 줄이 한 줄씩 늘어나는 것",
|
|
75
|
+
"근거": "위 검토 ①에서 나온 실수를 규칙 한 줄로 적은 것",
|
|
76
|
+
"규칙줄": [
|
|
77
|
+
"기본값은 `x ?? 기본` 으로 준다 — `x || 기본` 은 0 과 빈 문자열을 삼킨다",
|
|
78
|
+
"돈이 되는 값은 하한을 건다 — 할인을 빼고 나면 음수가 나온다",
|
|
79
|
+
"밖에서 온 값은 숫자인지 재고 쓴다 — NaN 은 조용히 끝까지 간다"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"★말하지_않는_자리": [
|
|
84
|
+
"「이러면 버그가 없어진다」 — 줄어드는 것이지 없어지는 게 아니다",
|
|
85
|
+
"「클로드 코드가 우리 것」 — Anthropic 의 제품이다",
|
|
86
|
+
"「무조건 빨라진다」 — 플랜 모드는 한 박자 느려지는 대신 되돌릴 일을 줄인다"
|
|
87
|
+
]
|
|
88
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: verify3-guide
|
|
3
|
+
description: 클로드 코드가 제 결과물을 스스로 다시 보게 만드는 설정 셋(플랜 모드 · 검토 에이전트 · 규칙 적기)이 지금 어떻게 걸려 있는지 알려 주고, 하나씩 껐다 켜는 법을 안내한다. "플랜 모드", "계획 먼저", "shift tab", "코드 검토 시켜줘", "클로드가 자꾸 엉뚱한 걸 만든다", "같은 실수를 반복한다", "verify3", "검수3" 같은 이야기가 나올 때 쓴다.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 검수3 — 지금 무엇이 걸려 있나
|
|
7
|
+
|
|
8
|
+
`reborn-verify3` 가 건 것은 셋이다. **셋 다 파일이라 열어 보면 그대로 보인다.**
|
|
9
|
+
|
|
10
|
+
| | 무엇 | 어디 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| ① | 플랜 모드 기본값 | `~/.claude/settings.json` → `permissions.defaultMode: "plan"` |
|
|
13
|
+
| ② | 검토 서브에이전트 | `~/.claude/agents/코드검토.md` |
|
|
14
|
+
| ③ | 규칙 적기 스킬 | `~/.claude/skills/규칙적기/SKILL.md` |
|
|
15
|
+
|
|
16
|
+
지금 상태를 재려면: `npx --yes reborn-verify3@latest --check`
|
|
17
|
+
|
|
18
|
+
## ① 플랜 모드 — 무엇이 달라지나
|
|
19
|
+
|
|
20
|
+
클로드가 **파일을 고치기 전에 계획을 먼저 보여 주고 승인을 기다린다.**
|
|
21
|
+
승인 전에는 읽기·검색만 한다.
|
|
22
|
+
|
|
23
|
+
- 한 세션만 끄기: 그 세션에서 `shift+tab` 을 눌러 모드를 돌린다
|
|
24
|
+
- 아예 되돌리기: `npx --yes reborn-verify3@latest --undo`
|
|
25
|
+
- 한 번만 다른 모드로 시작: `claude --permission-mode acceptEdits`
|
|
26
|
+
|
|
27
|
+
★**느려지는 게 맞다.** 한 박자 늦는 대신 엉뚱한 걸 다 만들고 되돌리는 일을 줄인다.
|
|
28
|
+
탐색적으로 빠르게 굴려야 하는 세션에서는 `shift+tab` 으로 그때만 푸는 게 낫다.
|
|
29
|
+
|
|
30
|
+
## ② 검토 에이전트 — 언제 부르나
|
|
31
|
+
|
|
32
|
+
파일을 고친 **직후**, 커밋·PR 전에 부른다.
|
|
33
|
+
|
|
34
|
+
> "방금 고친 것 코드검토 에이전트로 다시 봐줘"
|
|
35
|
+
|
|
36
|
+
같은 세션의 클로드에게 "다시 봐"라고 하면 **제가 세운 가정을 그대로 들고** 다시 본다.
|
|
37
|
+
서브에이전트는 제 문맥에서 돌아 그 가정을 물려받지 않는다. 그래서 따로 있다.
|
|
38
|
+
|
|
39
|
+
돌려주는 건 `치명 / 버그 / 냄새` 세 등급의 목록이고, **고치지는 않는다.** 판단은 사람이 한다.
|
|
40
|
+
|
|
41
|
+
## ③ 규칙 적기 — 언제 부르나
|
|
42
|
+
|
|
43
|
+
같은 실수를 **두 번째로** 봤을 때.
|
|
44
|
+
|
|
45
|
+
> "또 이러네, 규칙으로 박아줘"
|
|
46
|
+
|
|
47
|
+
CLAUDE.md 에 한 줄 적는다 — **무엇을 · 왜 · 어기면 어떻게 되나.**
|
|
48
|
+
이유 없는 "하지 마라"는 다음 세션이 안전하게 지운다.
|
|
49
|
+
|
|
50
|
+
★세 번 이상 어겨진 규칙은 문장이 약한 게 아니라 **말로 될 일이 아니다.** 그때는 검사기를 만든다.
|
|
51
|
+
|
|
52
|
+
## 안 하는 말
|
|
53
|
+
|
|
54
|
+
- 「이러면 버그가 없어진다」 — 줄어드는 것이지 없어지는 게 아니다
|
|
55
|
+
- 「무조건 빨라진다」 — 플랜 모드는 한 박자 느려진다. 되돌릴 일이 줄 뿐이다
|
|
56
|
+
- 클로드 코드는 Anthropic 의 제품이다. 이 설치기는 그 위에 설정을 얹을 뿐이다
|