designpaca/research/skills/06-skill-audit.md
Yun Chan 8808c672dc designpaca 초기 구현 — 스킬 · 설치 CLI · 배포 파이프라인
웹 디자인 파이프라인 스킬과 이를 5개 에이전트에 설치하는 CLI 를 담은 모노레포.

스킬 (packages/skill)
- SKILL.md 261줄 + 참조 문서 16개 3,349줄. progressive disclosure 로
  본문은 절차와 인덱스만, 지식은 references/ 로 분리
- 0~6단계 파이프라인. 규모에 따라 전체·연장·국소 세 경로로 분기
- 하드 게이트 12개는 grep·카운트로 검증 가능한 것만. 취향 판단은 제외
- 미학 프리셋 5종, AI 슬롭 지문 목록, 한글 조판 규칙,
  SVG 필터·three.js·인터랙티브 모션·HTML-in-Canvas 실전 지침

설치 CLI (packages/cli, packages/core)
- npx designpaca 온보딩 TUI. Claude Code · Codex · Cursor · Windsurf · AGENTS.md
- 매니페스트에 설치 시점 해시를 기록해 사용자가 고친 파일은 update 가 건너뛴다
- 타깃별로 본문의 references/ 경로를 실제 설치 위치로 재작성
- AGENTS.md 는 항상 로드되므로 본문 대신 303자 포인터만 주입
- Windsurf 는 12,000자 상한 초과 시 설치를 차단

배포 (build/ci, .forgejo/workflows)
- 태그 v* → 검사·테스트·빌드 → npmjs 배포 + Forgejo 레지스트리 미러
  → draft 릴리스 → Cloudflare Pages. 재실행 멱등

근거 (research/)
- 약 250개 웹 소스 조사 결과와 도그푸딩 검증 2건. 스킬의 모든 수치는 여기서 나온다

테스트 22개 통과 (core 16 · cli 6)
2026-08-20 10:48:00 +09:00

1306 lines
79 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 06. designpaca SKILL.md 감사
작성일: 2026-08-20
대상: `D:\workspace\designpaca\packages\skill\SKILL.md` (235줄 본문) + `references/` 13개 파일
기준: `05-recommendations.md` 설계 원칙 10가지, `03-format-specs.md` 포맷 스펙
방법: 전 파일 실측(줄 수·문자 수·토큰 추정·경로 존재 여부), 어댑터 소스 4개 정독
`motion.md` 는 미작성 상태이며 지적 대상에서 제외했다. `svg-filters.md`(555줄)·`three.md`(667줄)는 감사 중 생성되어 포함했다.
---
## 0. 총평
**본문은 좋다.** 원칙 1·4·5·6·9는 사실상 그대로 구현됐고, 특히 원칙 4(조건부 규칙 + 설명 의무)와 원칙 6(design.md)는 조사한 어떤 커뮤니티 스킬보다 잘 되어 있다. 235줄 / 약 4,600토큰으로 컴팩션 생존선(5,000토큰) 안에 들어간다 — design-taste-frontend가 실패한 지점을 통과했다.
**문제는 두 곳에 몰려 있다.**
1. **문서 사이의 SSOT 붕괴** — 성능 예산 표가 3개 문서에 서로 다른 항목으로 존재하고, 가로 스크롤 기준 폭이 320px과 375px로 갈린다.
2. **어댑터의 경로 재작성 누락** — Cursor·AGENTS.md 설치본에서 본문의 `references/...` 27곳이 전부 존재하지 않는 경로를 가리킨다. 설치는 되지만 참조 문서를 못 연다.
누락된 원칙은 8(트리트먼트 보정) 하나다. 7(선언)과 10(미학/버그 분리)은 다른 형태로 이미 녹아 있다.
### 판정 요약
| 원칙 | 판정 | 근거 한 줄 |
|---|:---:|---|
| 1. references 분리 / 본문 500줄 | **준수** | 본문 235줄, 참조 13개, 인덱스 표 있음, 링크 1단계 |
| 2. 핵심 규칙 최상단 | **준수** | 28~38줄. 본문 전체가 5,000토큰 안이라 배치 리스크 자체가 없다 |
| 3. description 3부 구성 | **미흡** | 320자·3인칭·용도·트리거 ✓ / **배제 조건 없음, 한국어 리터럴 발화 없음** |
| 4. 조건부 + 오버라이드 | **준수** | 18~26줄 우선순위 체인 + "왜 이 브리프에 맞는지 한 문장" 설명 의무 |
| 5. 검증 가능한 하드 게이트 | **미흡** | 12개 중 3번이 취향 판단. 2번·11번은 정의/대안 누락 |
| 6. design.md | **미흡** | 읽기·쓰기 모두 있음 ✓ / **재실행 시 어느 단계부터인지 분기 없음** |
| 7. 코드 전 평문 선언 | **부분 준수** | 단계별 통과 조건이 그 역할을 함. 통합 선언 블록만 없음 |
| 8. 트리트먼트 보정 | **누락** | 모든 브리프가 동일한 7단계를 통과한다 |
| 9. 대담함 한 곳 | **준수** | 핵심규칙 4 + 2단계 리스크 + preflight §5 Q3 / 검증 수치만 없음 |
| 10. 미학/버그 규칙 분리 | **부분 준수** | 하드 게이트 선언문 ✓ / 성능·접근성의 협상 가능선이 문서마다 다름 |
---
## 1. 반드시 고칠 것 (우선순위 순)
### F1. 어댑터 경로 재작성 누락 — Cursor·AGENTS.md 설치본이 참조 문서를 못 연다
본문에 `references/` 로 시작하는 경로가 **27곳** 있다. Claude Code·Codex는 스킬 디렉터리를 통째로 복사하므로 상대 경로가 맞다. Cursor와 AGENTS.md는 본문만 다른 위치로 옮기고 references를 **다른 디렉터리**에 푼다.
| 타깃 | 본문이 가리키는 곳 | 실제 파일 위치 |
|---|---|---|
| Cursor | `references/galleries.md` | `.cursor/rules/designpaca/references/galleries.md` |
| AGENTS.md (project) | `references/galleries.md` | `.designpaca/references/galleries.md` |
| AGENTS.md (user) | `references/galleries.md` | `~/.designpaca/reference/references/galleries.md` |
`cursor.ts` 41~51줄과 `agents-md.ts` 40~42줄이 **문서 끝에 매핑 안내를 붙이긴 한다.** 그러나 본문 27곳의 인라인 경로는 그대로다. 에이전트는 "→ `references/galleries.md`" 를 읽고 프로젝트 루트 기준으로 열려다 실패한다. 매핑 안내는 문서 맨 아래에 있어 그때 참조되지 않는다.
**수정안**`common.ts` 에 헬퍼 추가:
```ts
/** 본문의 `references/...` 상대 경로를 실제 설치 위치로 바꾼다.
* 본문에서 `references/` 는 참조 파일 경로로만 쓰이므로 단순 치환이 안전하다. */
export function rewriteRefPaths(body: string, prefix: string): string {
return body.replaceAll("references/", `${prefix}/references/`);
}
```
`cursor.ts` 54줄:
```ts
// 현재
{ kind: "write", path: mdc, content: header + ctx.skill.body + note },
// 제안
{ kind: "write", path: mdc,
content: header + rewriteRefPaths(ctx.skill.body, ".cursor/rules/designpaca") + note },
```
`agents-md.ts` 38줄:
```ts
// 현재
ctx.skill.body,
// 제안
rewriteRefPaths(ctx.skill.body, ctx.scope === "user" ? "~/.designpaca" : ".designpaca"),
```
덤으로 `agents-md.ts` 28줄의 user 스코프 refRoot 가 `~/.designpaca/reference` 라서 최종 경로가 `~/.designpaca/reference/references/galleries.md``reference`가 두 번 들어간다. `path.join(ctx.home, ".designpaca")` 로 줄이면 project 스코프와 구조가 같아지고 위 헬퍼도 한 규칙으로 끝난다.
---
### F2. AGENTS.md 에 본문 전체(14KB)를 주입한다 — 항상 로드되는 자리에 온스킬 분량이 들어간다
`agents-md.ts` 38줄이 `ctx.skill.body` 를 통째로 넣는다. 본문은 14,088 바이트다.
AGENTS.md 는 **스킬이 아니다. 조건 없이 항상 로드된다.**
> "AGENTS.md is just standard Markdown." / "Think of AGENTS.md as a **README for agents**"
> — agents.md (03-format-specs §3.2)
그리고 Codex 는 root부터 아래로 병합하며 **기본 32 KiB 에서 자른다**. 한 블록이 14KB를 먹으면 프로젝트의 실제 AGENTS.md 내용이 잘려나갈 수 있다. 게다가 designpaca 와 무관한 모든 대화(버그 수정, 테스트 작성)에서 이 14KB를 매번 지불한다.
`03-format-specs.md` §8.4(c) 가 이 경우를 명시적으로 다뤘다: **"전체를 넣지 마라. 포인터만 넣는다."**
**수정안**`agents-md.ts` 35~45줄의 `block` 을 포인터로 교체:
```ts
const block = [
"## designpaca — 웹 디자인 파이프라인",
"",
"이 리포에서 UI를 새로 만들거나 다시 디자인할 때는 마크업·스타일을 쓰기 전에",
`\`${refPrefix}/SKILL.md\` 를 읽고 그 파이프라인(0~6단계)을 따른다.`,
"",
"- 프로젝트 루트에 `design.md` 가 있으면 그것이 최상위다. 스킬 기본값을 덮는다.",
"- 참조 문서는 각 단계에서 지시하는 것만 그때 연다. 처음부터 전부 읽지 마라.",
"",
`<!-- designpaca v${ctx.skill.version} — \`npx designpaca update\` 가 관리한다. 직접 고치면 업데이트가 멈춘다. -->`,
].join("\n");
```
이때 `referenceActions``SKILL.md` 도 함께 쓰도록 바꿔야 한다(현재는 references만 쓴다). `skillDirActions` 를 재사용하고 `.designpaca/` 를 루트로 주면 된다.
블록이 약 400바이트로 줄고, 본문은 필요할 때만 읽힌다.
부수: `agents-md.ts` 18줄의 `detect``.git` 존재만으로 `true` 를 낸다. 사실상 모든 리포에서 기본 선택된다. 항상 로드되는 타깃이 기본 선택되는 것은 위험하다. `AGENTS.md` 파일이 실제로 존재할 때만 `true` 로 좁히는 편이 낫다.
---
### F3. 성능 예산 표가 3개 문서에 서로 다른 항목으로 존재한다
SKILL.md 3단계는 "여기서 예산을 정하고 5단계에서 검증한다"고 한다(120·131줄). 그런데 **대조할 표가 세 개고 항목 집합이 서로 다르다.**
| 항목 | SKILL.md 122127 | tokens.md 147153 | preflight.md 5561 |
|---|:---:|:---:|:---:|
| 히어로까지 JS | 150KB | 150KB (데모 400KB) | 150KB |
| WebGL 추가분 | +200KB | +200KB (데모 +600KB) | 없음 |
| 첫 인터랙션 | 3초 | 3초 (데모 5초) | 3초 |
| 폰트 파일 수 | 없음 | 2개 이하 (데모 3개) | 없음 |
| 총 전송량 | 없음 | 없음 | **1MB** |
| LCP | 없음 | 없음 | **2.5초** |
| CLS | 없음 | 없음 | **0.1** |
| 애니메이션 속성 | 합성 전용 | transform/opacity (타협 없음) | 없음 |
3단계에서 정한 예산에 총 전송량·LCP·CLS 가 없는데 5단계가 그걸 검증하라고 한다. 반대로 3단계가 정한 폰트 개수는 5단계에서 검증하지 않는다.
**수정안**`tokens.md` §5 를 단일 원본(SSOT)으로 삼는다.
1. `tokens.md` §5 표에 `총 전송량 1MB / 2MB`, `LCP 2.5초 / 3.5초`, `CLS 0.1 / 0.1` 세 행을 추가한다. (데모 열 값은 팀 리드 판단)
2. SKILL.md 120~129줄의 표를 지우고 두 줄로 바꾼다:
```markdown
**성능 예산도 여기서 정한다. 나중에 정하면 이미 늦는다.** 표는 `references/tokens.md` §5.
기본선: 히어로까지 JS 150KB(gzip) / 첫 인터랙션 3초 / 애니메이션은 `transform`·`opacity` 만.
브리프가 데모·포트폴리오라면 예산을 올려도 된다. **올린다는 사실과 이유를 명시해라.**
```
3. `preflight.md` §2 표의 "기본 예산" 열을 지우고 `tokens.md` §5 를 참조하게 한다. 이 문서는 **실측 열만** 갖는다.
본문 8줄이 줄고, 값이 어긋날 경로가 사라진다.
---
### F4. 하드 게이트 3번은 검증 불가능하다 — 취향 판단이 섞여 있다
```
3. 코너 반경이 규칙 없이 섞여 있는가?
```
"규칙 없이"를 누가 판정하는가. 게이트 서문(173줄)이 "취향이 아니라 **버그**다. 여기엔 오버라이드가 없다"라고 선언한 목록에 주관 판단이 하나 들어가면, 모델은 그 항목을 통과 표시하고 넘어가는 법을 배운다. 그러면 나머지 11개의 권위도 같이 내려간다. (`01-local-skill-teardown.md` §4.1 — design-taste-frontend 가 "use sparingly" 표현으로 실패한 것과 같은 구조)
**수정안** — 셀 수 있는 형태로:
```
3. `border-radius` 값이 토큰 밖에 있거나, 서로 다른 값이 3종 이상인가?
```
같은 이유로 두 항목에 손이 필요하다.
**2번**`2. 한 페이지에서 강조색이 2개 이상인가?`
`tokens.md` §2 규칙 1은 "예외: 상태색(성공/경고/오류)은 강조색이 아니라 기능색이다"라는 예외를 둔다. 게이트에는 그 예외가 없어서 상태색이 있는 폼 페이지가 오탐으로 걸린다.
`2. 상태색(성공·경고·오류)을 제외하고, 한 페이지에서 강조색이 2개 이상인가?`
**11번**`11. 사용자가 주지 않은 수치가 페이지에 있는가?`
판정은 가능하지만 **대안이 없다.** 걸렸을 때 무엇을 하라는 지시가 없으면 모델은 숫자를 지우고 섹션을 망가뜨리거나, 그냥 놔둔다. `antipatterns.md` §3 "근거 없는 지표 배너" 행에 대안이 있지만 게이트에서 그리로 연결되지 않는다.
→ 항목 뒤에 한 줄 추가:
```
걸렸으면 셋 중 하나다: (a) 숫자를 `—` 로 바꾸고 "확인 필요" 라벨을 붙인다,
(b) 사용자에게 실제 값을 묻고 멈춘다, (c) 그 섹션 자체를 다른 구조로 바꾼다.
숫자 모양의 구멍은 정직하고, 지어낸 숫자는 슬롭이다.
```
나머지 9개는 전부 grep 또는 계산으로 판정된다. 유지.
---
### F5. Cursor 어댑터 — Windsurf 를 감지하면서 Windsurf 가 읽지 않는 파일을 쓴다
`cursor.ts``label: "Cursor / Windsurf"`(14줄), `hint`(15줄), `detect`(22~23줄, `.windsurf`·`.windsurfrules` 확인)로 Windsurf 를 포함한다고 선언한다. 그런데 산출물은 `.cursor/rules/designpaca.mdc` 하나다.
**Windsurf 는 `.cursor/rules/*.mdc` 를 읽지 않는다.** (`03-format-specs.md` §5)
| 항목 | Cursor | Windsurf |
|---|---|---|
| 경로 | `.cursor/rules/*.mdc` | `.windsurf/rules/*.md` (또는 `.devin/rules/*.md`) |
| 프론트매터 | `description` / `globs` / `alwaysApply` | `trigger` / `globs` |
| 크기 상한 | 500줄 권고 | **12,000자 하드** |
`.windsurfrules` 가 있는 프로젝트에서 이 어댑터를 선택하면 사용자는 설치됐다고 믿지만 Windsurf 는 아무것도 못 읽는다.
**수정안 — 둘 중 하나.**
**(a) 정직하게 좁힌다 (권장, 변경 최소)**
- 14줄 `label: "Cursor"`
- 15줄 `hint: ".cursor/rules/designpaca.mdc — 프로젝트 단위"`
- 22~23줄 `.windsurf`·`.windsurfrules` 감지 제거
**(b) Windsurf 어댑터를 따로 만든다**
`.windsurf/rules/designpaca.md` 에 아래 프론트매터로 쓴다. 본문 문자 수가 **7,271자**라 12,000자 상한 안에 들어간다(측정치, 여유 4,700자).
```yaml
---
trigger: model_decision
description: <SKILL.md description 그대로>
---
```
`trigger: always_on` 을 쓰면 안 된다. 디자인 스킬이 모든 메시지의 시스템 프롬프트에 상주하게 된다.
---
## 2. 원칙별 상세 감사
### 원칙 1 — references 분리 / 본문 500줄 · 5,000토큰 · 참조 1단계
**판정: 준수.**
| 측정 항목 | 값 | 기준 | 판정 |
|---|---|---|---|
| 본문 줄 수 | 235 | ≤ 500 | ✓ |
| 본문 문자 수 | 7,271 | — | — |
| 본문 바이트 | 14,088 | — | — |
| 본문 추정 토큰 | 약 4,600 | < 5,000 | (여유 400) |
| 참조 파일 | 13 (motion.md 제외) | | |
| 참조 링크 깊이 | 1단계 | 1단계 | |
| 인덱스 | 219~233줄 | 있어야 | |
44줄의 지시가 특히 정확하다:
> 참조 문서는 **해당 단계에 들어갈 때 읽는다.** 처음부터 전부 읽지 마라 — 컨텍스트 낭비다.
`02-prompt-techniques.md` 기법 4(인덱스-후-선택) 그대로 구현했다. 프리셋도 "고른 프리셋 파일 **하나만** 읽어라. 읽지 마라"(107줄) 명시했다.
**참조 깊이 확인**: `presets/README.md` 개별 프리셋은 형식상 2단계로 보이나, SKILL.md 100~105줄이 개별 프리셋 파일을 **직접** 링크하므로 실질 1단계다. 문제없다.
**미흡 — 긴 참조 파일에 목차가 없다.**
| 파일 | | 목차 |
|---|---:|:---:|
| three.md | 667 | 없음 |
| svg-filters.md | 555 | 없음 |
| experimental-canvas.md | 350 | 없음 |
| antipatterns.md | 267 | 없음 |
> "For reference files longer than 100 lines, include a table of contents at the top. **This ensures Claude can see the full scope of available information even when previewing with partial reads.**"
> — Anthropic Skill authoring best practices
667줄 파일은 부분 읽기(`head -100` ) 훑을 가능성이 높고, 그때 뒷부분의 존재 자체를 모른다. 파일 상단에 3~8줄짜리 섹션 목록을 넣으면 해결된다. 우선순위는 낮다(설계 결함이 아니라 누락).
---
### 원칙 2 — 핵심 규칙 최상단
**판정: 준수.**
28~38줄 "핵심 규칙" 5개 + 접근성 예외 선언이 본문 16% 지점에 있다. 그리고 18~26줄 우선순위 체인이 그보다 앞이다. 배치가 맞다.
**하드 게이트가 171줄(71% 지점)에 있는 점**은 원칙 2와 형식상 어긋나지만, 실측 결과 **문제가 되지 않는다.** 본문 전체가 4,600토큰이라 컴팩션 재부착 예산 5,000토큰 안에 통째로 들어간다.
> "Claude Code re-attaches the most recent invocation of each skill after the summary, keeping the first 5,000 tokens of each."
> — Claude Code skills docs
design-taste-frontend(22,000토큰) §9·§14를 잃는 실패를 designpaca 구조적으로 피했다. **여유는 400토큰뿐이므로, 앞으로 본문에 무엇을 추가하든 같은 분량을 다른 데서 빼야 한다.** F3(성능 예산 8줄 삭제) 여유를 만든다.
---
### 원칙 3 — description 3부 구성
**판정: 미흡.**
측정: 320자, 3인칭, 용도 ✓, 트리거 ✓("~ 쓴다" + "Use when...").
| 요소 | 상태 |
|---|---|
| 무엇을 하는가 | " 디자인 과정을 끌고 가는 파이프라인 스킬" |
| 대상 | "랜딩 페이지·포트폴리오·마케팅 사이트·웹앱 UI" |
| 영문 트리거 | "Use when building or redesigning any website..." |
| **한국어 리터럴 발화** | **없음** |
| **배제 조건** | **없음** |
SKILL.md 16줄에는 "쓰지 않는다" 목록이 있지만, **본문은 스킬이 발동한 뒤에야 읽힌다.** 발동 여부를 결정하는 것은 description 뿐이다.
> `description: Explain exactly when this skill **should and should not** trigger.`
> — Codex 스킬 문서 (03-format-specs §3.1)
사용자는 한국어로 대화한다. `codex-image` 스킬이 한국어 발화를 나열한 이유가 그것이다(`01-local-skill-teardown.md` 패턴 D).
**수정안** 현재 320자를 430자로. 스펙 상한 1,024자, Claude Code 목록 상한 1,536자 안이며, 스킬 목록 예산(컨텍스트 1%) 관점에서도 여전히 안전한 범위다.
```yaml
description: "웹 디자인 전 과정을 끌고 가는 파이프라인 스킬. 랜딩 페이지·포트폴리오·마케팅 사이트·웹앱 UI를 새로 만들거나 기존 사이트를 리디자인할 때 쓴다. \"랜딩 만들어줘\", \"디자인 예쁘게 해줘\", \"이 페이지 다시 디자인\", \"히어로 섹션 만들어줘\", \"UI 좀 살려줘\", \"design a landing page\", \"make this look better\", \"redesign this page\" 같은 요청에 발동한다. 레퍼런스 조사 → 방향 결정 → 디자인 토큰 → 구현 → 셀프 감사까지 순서대로 진행하고, AI가 만든 티 나는 결과물을 구체적 지문 목록으로 차단한다. 대시보드의 데이터 밀도 설계·차트·순수 백엔드, 그리고 버그 수정이나 기능 추가처럼 시각 결과가 목적이 아닌 작업에는 쓰지 않는다."
```
바뀐 것: 한국어 발화 5개 추가, 영문 발화 3개로 확장, 배제 조건 문장 추가, 중복되던 "(SVG 필터·three.js·인터랙티브 모션)" 축약.
---
### 원칙 4 — 조건부 규칙 + 오버라이드
**판정: 준수. 이 스킬에서 가장 잘 된 부분이다.**
18~26줄:
> ```
> 사용자의 명시적 지시 > 프로젝트의 design.md > 프로젝트의 기존 토큰·코드 > designpaca 기본값
> ```
> 사용자가 "보라색으로 해달라"고 하면 보라색으로 한다. 아래 규칙은 **브리프가 침묵할 때의 기본값**이지 금지 목록이 아니다. 단 기본값을 벗어날 때는 **왜 이 브리프에 그것이 맞는지 한 문장으로 말하고** 진행한다. 말할 수 없으면 그건 결정이 아니라 기본값 회귀다.
`05-recommendations.md` 원칙 4가 요구한 요소(우선순위 체인 / 오버라이드 경로 / 설명 의무) 전부 있다. 마지막 문장은 design-taste-frontend §4.1의 "AND you can articulate why"보다 짧고 명확하다.
**작은 어긋남 하나.** 26줄이 "아래 규칙은 ... 금지 목록이 아니다"라고 선언한 , 171~186줄이 "여기엔 오버라이드가 없다" 한다. 문서 안에 등급이 있는데 26줄이 사실을 예고하지 않는다.
**수정안** 26줄 끝에 문장 추가:
```markdown
예외는 두 곳이다. 38줄의 접근성과 5단계의 하드 게이트 12개는 브리프가 요청해도 오버라이드하지 않는다. 그 둘은 취향이 아니라 결함이기 때문이다.
```
---
### 원칙 5 — 검증 가능한 하드 게이트
**판정: 미흡.** (수정안은 F4)
게이트 12 + 카운트 규칙 5 = 17개. `05-recommendations.md` 권한 20~30개 이하이며 적정하다. Hallmark 58개나 design-taste-frontend 60개처럼 "정직한 검사가 불가능한 분량" 아니다.
서문(173줄) 정확하다:
> 취향이 아니라 **버그**다. 여기엔 오버라이드가 없다. 체크박스가 아니라 질문이니 실제로 검사해라.
"체크박스가 아니라 질문" 명시한 것은 좋다. `02-prompt-techniques.md` 기법 15의 핵심이다.
**항목별 검증 가능성:**
| # | 항목 | 판정 방법 | 판정 |
|:--:|---|---|:---:|
| 1 | 인라인 hex/rgb/oklch, 인라인 font-family | grep | |
| 2 | 강조색 2개 이상 | 토큰 개수 | 상태색 예외 누락 |
| 3 | 코너 반경이 규칙 없이 섞임 | | ** 주관** |
| 4 | 테마 뒤집힘 | 섹션별 배경 명도 비교 | |
| 5 | 320~1920px 가로 스크롤 | 렌더 확인 | ( F6 참조) |
| 6 | 버튼 라벨 2줄 접힘 | 렌더 확인 | |
| 7 | 버튼 대비 4.5:1 미만 | 계산 | |
| 8 | transform/opacity 애니메이션 | grep | |
| 9 | `100vh` 사용 | grep | |
| 10 | `addEventListener('scroll')` | grep | |
| 11 | 사용자가 주지 않은 수치 | 브리프 대조 | 대안 누락 |
| 12 | div 가짜 스크린샷 | 소스 확인 | |
**카운트 규칙 5개는 전부 검증 가능하다.** 다만 4번째 항목에 미세한 긴장이 있다:
> - 작은 대문자 라벨(eyebrow) 개수 ≤ `ceil(섹션수 / 3)`
`antipatterns.md` §0 2위 항목은 "헤드라인·섹션 라벨이 전체 대문자" 검출률 10.5% 지목하며 대안을 **"라벨을 없애고 헤드라인만으로 섹션을 구분"** 이라고 한다. antipatterns 0개를, SKILL.md `ceil(n/3)`개를 허용한다. 성립하려면 SKILL.md 쪽이 "**전체 대문자가 아닌** 작은 라벨은 `ceil(n/3)`까지"라는 뜻이어야 한다. 지금 문장으로는 읽히지 않는다.
**수정안** 192줄:
```markdown
- 작은 라벨(eyebrow) 개수 ≤ `ceil(섹션수 / 3)`. **전체 대문자 라벨은 개수와 무관하게 0개다**(antipatterns §0)
```
---
### 원칙 6 — design.md
**판정: 미흡 (핵심은 준수, 분기 하나 누락).**
읽기(0단계 50줄) 쓰기(6단계 202~215줄) 모두 있다. Superdesign·Hallmark·stitch-design-taste 시스템이 각각 도달한 패턴을 그대로 구현했고, 213줄이 특히 좋다:
> 마지막 줄이 가장 중요하다. **하지 않기로 한 결정을 적어두지 않으면 다음 사람이 그것을 "빠뜨린 것"으로 착각하고 되돌린다.**
**누락 — 두 번째 실행에서 어느 단계부터인지가 없다.**
50줄이 말한다:
> 먼저 프로젝트 루트에 `design.md` 가 있는지 확인한다. 있으면 읽고, 그 결정을 이 스킬의 기본값보다 우선한다. 같은 프로젝트를 두 번째로 작업할 때 지난번과 다른 디자인이 나오면 그건 실패다.
그런데 파이프라인은 42줄에서 "**순서를 바꾸지 마라.** 단계에는 통과 조건이 있고, 통과하지 못하면 다음 단계로 가지 않는다" 한다. `design.md` 있는 프로젝트에서 페이지 하나를 추가할 , 모델은 R1/R2/R3 갤러리 조사를 다시 하고 프리셋을 다시 고르고 리스크를 다시 정해야 한다. 그러면 50줄이 경고한 "지난번과 다른 디자인" 정확히 발생한다.
**수정안** 0단계 50줄 뒤에 분기 추가:
```markdown
`design.md` 가 있으면 **1·2단계를 건너뛴다.** 레퍼런스와 방향은 이미 정해져 있다.
읽고 그 값을 3단계 토큰으로 그대로 가져간 뒤 4단계로 간다.
1·2단계를 다시 도는 것은 사용자가 "방향을 바꾸자"고 명시할 때뿐이며,
그때는 새 결정으로 `design.md` 를 갱신한다.
```
그리고 219줄 참조 표의 "언제 읽나" 열에도 분기를 반영해두면 좋다.
**낮은 우선순위 — 프로젝트 간 회전 장치가 없다.**
`design.md` **한 프로젝트 안의** 일관성을 보장한다. 서로 다른 프로젝트 5개가 전부 `swiss-minimal` 고르는 것은 막지 못한다. 프리셋이 4개뿐이라 위험은 실재한다. Hallmark `.hallmark/log.json` 으로 문제다(`02-prompt-techniques.md` 기법 12).
다만 designpaca 프로젝트 단위 설치가 기본이라 전역 로그를 자리가 애매하다. **지금 단계에서는 넘기고**, 대신 2단계에 줄을 넣어두는 정도가 비용 대비 합리적이다:
```markdown
프리셋을 고른 이유를 한 줄로 적어라. "제품이 복잡해서"처럼 브리프에서 나온 이유여야 한다.
"무난해서"는 이유가 아니다 — 그건 네 기본값이지 이 브리프의 결정이 아니다.
```
---
### 원칙 7 — 코드 전 평문 선언
**판정: 부분 준수. 추가는 선택이다.**
원칙 7이 요구한 것은 "코드를 쓰기 전에 선택을 사용자가 읽을 있는 형태로 낸다"이다. designpaca 이것을 **단계별 통과 조건**으로 분산 구현했다:
| 단계 | 선언 산출물 | 위치 |
|---|---|---|
| 0 | 브리프 3줄 | 54~58줄 |
| 1 | R1/R2/R3 + 6축 수치 + 회색조 위계 | `reference-method.md` §6 필수 블록 |
| 2 | 문장 컨셉 + 프리셋 + 리스크 하나 | 96~98줄 |
| 3 | 토큰 실제 + 성능 예산 | 131줄 |
그리고 237줄이 "**단계를 보고하며 진행해라.** 사용자는 어느 단계인지 알아야 개입할 있다" 받친다. 238줄의 "가정은 소리 내서 말해라" 같은 계열이다.
**이것으로 충분하다.** Hallmark 통합 프리뷰 블록은 구조 위에 얹으면 오히려 같은 정보를 출력하게 된다.
**다만 한 가지가 빠져 있다** 3단계와 4단계 사이에 **되돌아볼 없는 지점** 있다. 4단계에 들어가면 코드가 나오기 시작하고, 그때 사용자가 방향을 바꾸면 전부 버려야 한다. 2단계 통과 조건(109줄) 사용자 확인을 요구하지 않는다.
**수정안(선택)** 3단계 통과 조건(131줄) 뒤에 줄:
```markdown
> 통과 조건: 토큰이 실제 값으로 적혔고, 성능 예산이 숫자로 정해졌다.
> **4단계로 넘어가기 전에 0~3단계의 결정을 6줄로 요약해 보여준다.** 여기가 되돌리기 가장 싼 지점이다.
> `무엇을 / 누구에게 / R1·R2·R3 / 컨셉 / 프리셋 / 리스크` 각 한 줄.
```
6줄이면 토큰 비용이 거의 없고, 잘못된 방향으로 400줄 HTML을 만드는 것보다 훨씬 싸다.
---
### 원칙 8 — 트리트먼트 보정
**판정: 누락. 추가를 권한다.**
SKILL.md 12~16줄은 **범위** 정의한다(쓴다 / 쓰지 않는다). 범위 안에 들어온 모든 브리프는 동일한 7단계를 통과한다.
문제는 범위 안에도 편차가 크다는 것이다.
| 브리프 | 현재 요구되는 | 적절한가 |
|---|---|---|
| 브랜드 랜딩 페이지 | R1/R2/R3 조사 + 리스크 하나 + design.md | 적절 |
| 사내 도구 설정 화면 | 동일 | **과잉** |
| API 문서 페이지 | 동일 | **과잉** |
| 데모용 실험 페이지 | 동일 | 적절 |
`03. 화려함은 4순위다`(34줄) `핵심 규칙 4. 대담함은 한 곳에만`(35줄) 과잉 장식은 막는다. 그러나 **"감수할 리스크 하나"(98줄) 필수**다:
> **감수할 리스크 하나** — 정당화할 수 있는 과감한 선택 하나. 없으면 그 디자인은 안전하고 잊힌다
사내 문서 페이지에 "잊히지 않기 위한 과감한 선택" 요구하는 것은 잘못된 목표다. `artifact-design` 문제를 정확히 짚었다:
> **Calibrate treatment, not whether to design.** ... Many requests call for a more utilitarian treatment: a plan, a memo, a demo. Make it polished ... **but avoid over-designing.**
> **When unsure: a well-composed page is never the wrong answer; an over-designed visual identity sometimes is.**
**수정안** 0단계 브리프 게이트에 하나 추가. 3줄 블록 바로 (58줄과 60줄 사이):
```markdown
**트리트먼트를 정한다.** 같은 완성도를 어느 형태로 전달할지의 문제다.
- **에디토리얼** — 랜딩, 포트폴리오, 캠페인, 제품 소개. 사용자가 자랑할 물건.
→ 전 단계를 그대로 돈다. 리스크 하나는 필수다.
- **유틸리티** — 사내 도구, 문서 페이지, 관리 화면, 데모.
→ 1단계 레퍼런스는 R1 하나로 줄인다. 2단계 리스크는 **생략한다**.
타입 위계·여백·토큰·접근성은 그대로 지킨다. 여기서 완성도가 결정된다.
거대한 히어로도 스크롤 연출도 필요 없다.
확신이 서지 않으면 유틸리티로 간다.
**잘 구성된 페이지가 틀린 답이 된 적은 없다. 과잉 디자인된 아이덴티티는 가끔 틀린 답이다.**
```
그리고 2단계 98줄의 리스크 항목을 조건부로:
```markdown
- **감수할 리스크 하나** — 정당화할 수 있는 과감한 선택 하나. 없으면 그 디자인은 안전하고 잊힌다.
**(유틸리티 트리트먼트면 생략한다. 거기서는 안전한 것이 맞다.)**
```
추가 분량 11줄. F3에서 8줄을 빼므로 순증 3줄, 토큰 여유 안에 들어간다.
---
### 원칙 9 — 대담함은 한 곳에만
**판정: 준수. 검증 수치만 없다.**
지점에 일관되게 박혀 있다:
- 핵심 규칙 4 (35줄): "**대담함은 곳에만.** 리스크는 하나다. 나머지는 조용히 받쳐준다. 곳에서 소리치면 죽는다."
- 2단계 (98줄): "감수할 리스크 하나"
- `preflight.md` §5 Q3: "감수하기로 리스크가 실제로 들어갔는가? 구현 중에 안전한 쪽으로 후퇴하지 않았는지"
Q3이 특히 좋다. 원칙 9의 "위험을 지는 것도 위험이다" 검사 항목으로 바꿨다.
**미흡 — 검증 가능한 수치가 없다.**
`05-recommendations.md` 원칙 9가 권한 "액센트 면적 상한" 어디에도 없다. `tokens.md` §2 규칙 2("채도가 높은 색은 면적을 좁게") 정성적이고, `reference-method.md` 축3의 "accent 면적 %(10% 이하가 정상)" **레퍼런스를 분석할 때** 쓰는 값이지 자기 결과물 검사용이 아니다.
**수정안** 카운트 규칙(188~196줄) 추가:
```markdown
- 강조색이 차지하는 화면 면적 ≤ 뷰포트의 10% (`reference-method.md` 축3과 같은 기준)
```
Hallmark 값을 5% 잡는다. 10% `reference-method.md` 일치하므로 문서 정합성 면에서 10% 낫다.
---
### 원칙 10 — 미학 규칙과 버그 규칙 분리
**판정: 부분 준수.**
분리 개념은 곳에 있다:
- 38줄: "**접근성은 예외다. 이것만은 협상하지 않는다.** 키보드·포커스·대비·`prefers-reduced-motion` 어떤 이펙트보다, 어떤 브리프보다 우선한다. **픽셀은 왜곡해도 DOM은 살린다.**"
- 173줄: "취향이 아니라 **버그**. 여기엔 오버라이드가 없다."
마지막 문장("픽셀은 왜곡해도 DOM은 살린다") HTML-in-Canvas 같은 실험 경로까지 커버하는 좋은 문장이다.
**미흡 3가지.**
**(a) 접근성 선언과 하드 게이트가 어긋난다.**
38줄이 협상 불가로 지목한 넷은 `키보드 · 포커스 · 대비 · prefers-reduced-motion` 이다. 하드 게이트 12개 접근성 항목은 7번(버튼 대비)뿐이다. 키보드·포커스·reduced-motion 게이트에 없다.
`preflight.md` §1 표가 셋을 모두 다루고, 5단계 통과 조건(198줄) `preflight.md` 통과를 요구하므로 **기능적으로는 커버된다.** 그러나 "협상하지 않는다" 선언한 하나만 게이트에 있는 것은 읽는 사람에게 불일치로 보인다.
수정안: 게이트를 늘리지 말고(분량), 173줄 서문에 줄:
```markdown
접근성 전체는 `preflight.md` §1에서 검사한다. 아래는 그 외에 자주 깨지는 것들이다.
```
**(b) 성능의 협상 가능선이 문서마다 다르다.**
- SKILL.md 핵심 규칙 5(36줄): "데모·포트폴리오 브리프면 예산을 올려도 되지만 **올렸다고 말해야 한다**" 조건부
- `tokens.md` §5 표: `애니메이션 속성 | transform/opacity 만 | 동일 (타협 없음)` 성능 안에서도 항목만 절대
- 하드 게이트 8번: `transform`/`opacity` 애니메이션 절대
성능은 "예산은 조건부, 애니메이션 속성은 절대"라는 이중 구조인데, SKILL.md 36줄만 읽으면 전부 조건부로 읽힌다.
수정안: 36줄 끝에 문장:
```markdown
단 애니메이션 속성만은 예외다. `transform`·`opacity` 제한은 예산과 무관하게 지킨다 — 그건 예산 문제가 아니라 렌더링 파이프라인 문제다.
```
**(c) 하드 게이트에 실무 렌더링 버그 개가 빠졌다.**
`05-recommendations.md` 원칙 10이 여러 소스에서 반복 확인된 것으로 정리한 항목 다음이 어디에도 없다:
| 항목 | 근거 | 현재 상태 |
|---|---|---|
| `width: 100vw` 금지 (스크롤바 있는 데스크톱에서 깨짐) | Hallmark anti-patterns | 없음 |
| 이미지가 들어가는 그리드 트랙에 `minmax(0, 1fr)` | Hallmark gate 50 | 없음 |
| 디스플레이 텍스트에 `overflow-wrap: anywhere` | Hallmark gate 51 | `preflight.md` §3에 있음 |
| 페이지 레벨 sticky 아래 다른 `top: 0` sticky 금지 | Hallmark gate 56 | 없음 |
| LCP 요소에 `loading="lazy"` 금지 | Hallmark anti-patterns | `preflight.md` §2에 반대 방향으로만 있음( 화면 lazy 누락) |
앞의 셋은 **하드 게이트가 아니라 `layout.md` §4(반응형)에 넣는 것이 맞다.** 게이트를 15개로 늘리는 것보다 낫다. LCP lazy `preflight.md` §2 "자주 걸리는 " 추가하면 된다.
---
## 3. 중복과 모순
### 3.1 모순 — 값이 실제로 다르다
| # | 항목 | 위치 A | 위치 B | 조치 |
|:--:|---|---|---|---|
| M1 | 가로 스크롤 검사 | SKILL.md 179줄 `320~1920px 사이 어느 폭에서든` | `preflight.md` 76줄 `375px 폭에서`<br>`layout.md` 109줄 `모바일 폭(375px)에서` | **320~1920px 로 통일.** 320px 은 실제로 존재하는 최소 폭(iPhone SE 세로)이고 375px 만 검사하면 그 아래가 뚫린다 |
| M2 | 성능 예산 항목 집합 | SKILL.md 122~127 (4항목) | `tokens.md` 147~153 (5항목)<br>`preflight.md` 55~61 (5항목, 서로 다름) | **F3** 참조. `tokens.md` §5 를 SSOT 로 |
| M3 | eyebrow 허용 개수 | SKILL.md 192줄 `≤ ceil(섹션수/3)` | `antipatterns.md` §0 2위 `라벨을 없애고 헤드라인만으로` (사실상 0) | **원칙 5 수정안** 참조. "전체 대문자는 0개" 를 명시해 두 규칙을 분리 |
M1 이 실질적으로 가장 위험하다. 하드 게이트 5번은 "오버라이드 없음"인데 참조 문서 두 곳이 더 느슨한 기준을 준다. 모델은 느슨한 쪽을 근거로 통과 표시할 수 있다.
### 3.2 중복 — 값은 같으나 두 번 이상 나온다
| # | 내용 | 위치 | 판단 |
|:--:|---|---|---|
| D1 | 기계 검사 3종(grep / 카피 치환 / 이펙트 끄기) | SKILL.md 165~169 · `preflight.md` §0 A·B·C | **유지.** SKILL.md 쪽이 "반드시 돌려라"라는 강조 역할을 하고 5줄뿐이다 |
| D2 | 프리셋 4종 표 | SKILL.md 100~105 · `presets/README.md` 8~13 | **유지.** 표가 SKILL.md 에 있으면 README 를 안 열어도 되어 오히려 토큰 절약. 현재 두 표는 정확히 일치한다 |
| D3 | 성능 예산 표 | 3곳 | **F3 로 정리** |
| D4 | 터치 타깃 44×44px | `preflight.md` §3 · `layout.md` §4 | 유지. 서로 다른 단계에서 필요 |
| D5 | 강조색 1개 규칙 | SKILL.md 게이트 2 · `tokens.md` §2 규칙1 · `preflight.md` §5 Q5 · `antipatterns.md` | 유지. 다만 상태색 예외는 `tokens.md` 에만 있다 → F4 |
| D6 | 한글 조판 규칙 | `antipatterns.md` §8 (전체) · `layout.md` §3 (요약 + 포인터) | **좋은 형태.** `layout.md` 가 요약하고 원본을 가리킨다 |
| D7 | 참조 문서 지도 | SKILL.md 219~233 · 각 단계 인라인 링크 | 유지. 원칙 1의 인덱스 요건 |
D6 은 다른 문서들이 따라야 할 모범이다. 요약 5줄 + "자세한 건 여기"가 전문 복사보다 낫다.
### 3.3 모순 아님 (확인함)
- **다크 모드**: `tokens.md` §2 "다크를 기본값으로 삼지 마라" vs `presets/dark-instrument.md`. 프리셋이 6~13줄에서 "다크 기본값은 단일 슬롭 시그니처 1위다. 이유를 댈 수 없으면 라이트로 가라"고 먼저 못 박고 정당화 사유 3개를 제시한다. **정확히 원칙 4의 오버라이드 구조다.** 손댈 필요 없다.
- **벤토 그리드**: `layout.md` §1 "새 기본값이라 차별화가 아니다" vs `antipatterns.md` §3 "기본 선택지로 쓰지 마라". 같은 말이고 `layout.md` 가 조건부 사용법까지 준다.
---
## 4. 분량 판정
**결론: 자르지 않아도 된다. 다만 F3(성능 예산 표 8줄)은 분량이 아니라 SSOT 때문에 빼야 한다.**
| 지표 | 값 | 기준 | 여유 |
|---|---|---|---|
| 본문 줄 수 | 235 | ≤ 500 | 265줄 |
| 본문 추정 토큰 | 약 4,600 | < 5,000 | **약 400토큰** |
토큰 여유가 400뿐이라는 점이 실제 제약이다. 감사에서 제안한 추가분은:
| 제안 | 증감 |
|---|---|
| F3 성능 예산 삭제 | **-8줄** |
| 원칙 8 트리트먼트 블록 | +11줄 |
| 원칙 4 등급 예고 1문장 | +1줄 |
| 원칙 6 design.md 분기 | +4줄 |
| 원칙 7 3단계 요약 지시 | +2줄 |
| 원칙 9 액센트 면적 카운트 | +1줄 |
| 원칙 10 (a)(b) 1문장 | +2줄 |
| F4 게이트 2·3·11 수정 | +3줄 |
| 원칙 5 eyebrow 문구 | +0줄 (치환) |
| **합계** | **+16줄 / +300토큰** |
4,900토큰이 되어 5,000 선에 붙는다. **한 곳을 더 빼는 것을 권한다.**
가장 만한 곳은 **219~233줄 참조 문서 지도 표(15줄)** . 단계가 이미 인라인으로 파일을 지목하고 있어 정보가 중복된다. 다만 원칙 1의 인덱스 요건이라 완전 삭제는 곤란하다.
절충: 표를 유지하되 "언제 읽나" 열을 단계 번호만으로 축약(`1단계 — 어느 갤러리를 볼지 정할 때` `1`). 5줄 절약.
또는 **151~152줄 실험 경로 2줄** 4-3 안으로 흡수. 미세하다.
---
## 5. 작업 2 — 포맷 어댑터 검증
### 5.1 요약
| 파일 | 판정 | 핵심 |
|---|:---:|---|
| `claude-code.ts` | **정확** | 경로·스코프 전부 스펙과 일치 |
| `codex.ts` | **경로 재검토 필요** | `~/.codex/skills` 실측으로 존재하나 공식 문서엔 없다 |
| `cursor.ts` | **수정 필요** | 경로 재작성 누락 · Windsurf 오표기 · YAML 인용 · 네이티브 스킬 경로 미사용 |
| `agents-md.ts` | **수정 필요** | 본문 전체 주입 · 경로 재작성 누락 |
### 5.2 `claude-code.ts` — 문제없음
`~/.claude/skills/designpaca/` (user) / `.claude/skills/designpaca/` (project). `03-format-specs.md` §2.1 표와 정확히 일치한다. `SKILL.md` 그대로 쓰므로 프론트매터 변환 리스크도 없다.
가지만 알아둘 것: Claude Code 심링크를 따라가고 같은 타깃이 경로에서 보이면 **한 번만 로드한다.**
> "if the same target is reachable from more than one location, Claude Code loads the skill once"
그러나 지금 어댑터는 타깃에 **실제 파일을 복사**한다. 사용자가 Claude Code Codex 선택하면 같은 내용의 별도 디렉터리가 생긴다. 동작에는 문제가 없다( 도구가 자기 경로만 본다). 유지보수 관점에서 `update` 갱신하는지만 확인하면 된다.
### 5.3 `codex.ts` — `~/.codex/skills` 는 실측으로 맞지만 문서 근거가 없다
**실측 결과 (이 머신):**
```
C:\Users\encep\.codex\skills\
├── .system\
│ ├── .codex-system-skills.marker ← Codex 가 만든 파일
│ ├── imagegen\ openai-docs\ plugin-creator\
│ ├── review-agent\ skill-creator\ skill-installer\
├── frontend-design\ (2026-06-28)
├── web-design-guidelines\ (2026-06-28)
├── object-separation\ (2026-07-15)
├── viven-wiki\ (2026-04-14)
└── codex-primary-runtime\ (2026-04-24)
```
`.system/.codex-system-skills.marker` 아래 번들 스킬 6개는 **Codex CLI 자신이 만든 **이다. 사용자가 4월부터 디렉터리에 스킬을 넣어 쓰고 있다. `~/.codex/skills/` Codex 스킬 루트인 것은 거의 확실하다.
**그러나 공식 문서는 이 경로를 언급하지 않는다.** 재확인차 다시 fetch 했고 결과는 동일했다:
> Codex scans: `$CWD/.agents/skills` → `$CWD/../.agents/skills` → `$REPO_ROOT/.agents/skills` → `$HOME/.agents/skills` → `/etc/codex/skills` → 번들.
> **The documentation does not mention `~/.codex/skills` or `.codex/skills` as scan locations.**
> — learn.chatgpt.com/docs/build-skills (2026-08-20 재확인)
`~/.codex/config.toml` 에도 스킬 경로 설정은 없다(색상 항목만 검색됨).
**권고 — 두 가지 중 하나.**
**(a) `~/.agents/skills/designpaca/` 타깃으로 추가한다 (권장).**
경로 하나가 **Codex · Cursor · VS Code Copilot 셋 다** 문서상 스캔 대상이다.
| 도구 | `~/.agents/skills` 스캔 | 근거 |
|---|:---:|---|
| Codex | O | learn.chatgpt.com/docs/build-skills |
| Cursor | O | cursor.com/docs/context/skills |
| VS Code Copilot | O | code.visualstudio.com/docs/copilot/customization/agent-skills |
사용자 머신의 `C:\Users\encep\.agents\skills\` design-taste-frontend 16개가 이미 있고, `~/.claude/skills/` 그리로 심링크되어 있다. **사용자가 이미 이 배치를 쓰고 있다.** 어댑터가 관행을 따르는 것이 자연스럽다.
**(b) `codex.ts` 유지하되 곳에 쓴다.**
`~/.codex/skills/designpaca/` (실측) + `~/.agents/skills/designpaca/` (문서). 파일이 중복되지만 확실하다.
**프로젝트 스코프는 별개 문제다.** `codex.ts` 25줄이 `.codex/skills/designpaca` 쓰는데, 문서가 말하는 리포 스코프는 `.agents/skills` . `.codex/skills` 실측 근거도 문서 근거도 없다.
```ts
// codex.ts 25줄 — 현재
const root = scopeRoot(ctx, [".codex", "skills", "designpaca"], [".codex", "skills", "designpaca"]);
// 제안 (project 만 교체)
const root = scopeRoot(ctx, [".codex", "skills", "designpaca"], [".agents", "skills", "designpaca"]);
```
### 5.4 `cursor.ts` — 네 가지
** 경로 재작성 누락 F1.** 가장 중요하다.
** `description` 인용부호 없이 쓰인다.**
```ts
// 34줄
`description: ${ctx.skill.description}`,
```
`skill-source.ts` 16~18줄이 원본의 따옴표를 벗겨서 넘긴다. 현재 값은 320자에 `: ` `#` 없어 **지금은 유효한 YAML 이다**(실측 확인). 그러나 description 콜론+공백이 번이라도 들어가면 순간 `.mdc` 프론트매터가 깨지고, Cursor 조용히 규칙을 무시한다. 원칙 3 수정안대로 문장을 늘리면 위험이 커진다.
```ts
// 제안
`description: ${JSON.stringify(ctx.skill.description)}`,
```
JSON 문자열은 YAML 유효한 double-quoted scalar 이므로 그대로 있다.
** `globs:` 문제없다.**
```ts
"globs:",
"alwaysApply: false",
```
Cursor 문서의 4가지 규칙 타입 우리가 원하는 것은 "Apply Intelligently"(`description` 있음, `globs` 없음). `globs:` YAML null 이므로 조건을 만족한다. Cursor UI 자신이 형태를 생성한다.
`alwaysApply: false` 정확하다. Cursor 문서가 `alwaysApply: true` "Use sparingly, this is your global config"라고 경고한다. 디자인 스킬이 모든 세션에 상주해서는 된다.
**굳이 더 정확히 하려면** 자체를 빼는 쪽이 문서 표현("no `globs`") 가깝다. 낮은 우선순위.
** Windsurf F5.**
** 추가 권고 Cursor 이제 Agent Skills 네이티브 지원한다.**
`.mdc` 변환은 레거시 경로다. Cursor 다음 넷을 스캔한다: `.agents/skills/`, `.cursor/skills/`, `~/.agents/skills/`, `~/.cursor/skills/`.
**`.cursor/skills/designpaca/` SKILL.md 그대로 쓰면 변환이 필요 없고, 경로 재작성 문제(F1) 사라지고, references 그대로 옮겨간다.** 5.3(a) `~/.agents/skills/` 타깃을 추가하면 Cursor user 스코프까지 번에 덮인다.
**권고 배치:**
```
1순위 ~/.agents/skills/designpaca/ → Codex + Cursor + Copilot (user)
.agents/skills/designpaca/ → 같은 셋 (project)
2순위 .cursor/rules/designpaca.mdc → .mdc 를 쓰는 기존 워크플로 호환용 (레거시)
```
`cursor.ts` 16줄의 `scopes: ["project"]` 재검토 대상이다. 주석은 "Cursor 전역 규칙은 파일이 아니라 설정(User Rules)이라 프로젝트 범위만 지원한다" 하는데, **스킬은 `~/.cursor/skills/` 로 파일 설치가 된다.** 주석은 `.mdc` 규칙에 대해서는 맞고 스킬에 대해서는 틀리다.
** references `.cursor/rules/` 안에 두는 .**
`cursor.ts` 30줄이 `.cursor/rules/designpaca/` 참조 문서를 푼다. Cursor `.cursor/rules/` 재귀 스캔하고, 프로젝트 규칙은 `.mdc` 확장자여야 하므로 우리 `.md` 파일들은 규칙으로 잡히지 않는다. **지금은 안전하다.** 다만 규칙 전용 디렉터리에 규칙이 아닌 파일 13개를 넣는 것은 깨지기 쉬운 가정이다. `.designpaca/` 빼면 AGENTS.md 타깃과 경로 규칙도 통일된다.
### 5.5 `agents-md.ts` — 세 가지
** 본문 전체 주입 F2.** 가장 중요하다.
** 경로 재작성 누락 F1.**
** user 스코프 경로.**
24줄이 `~/.codex/AGENTS.md` 쓴다. 어댑터 라벨은 "범용 AGENTS.md" 인데 경로는 Codex 전용이다. 머신에는 해당 파일이 이미 있고(436바이트) 마커 주입은 기존 내용을 보존하므로 **동작은 문제없다.**
다만 범용이라는 이름값을 하려면 user 스코프에서는 AGENTS.md 대신 `~/.agents/skills/designpaca/` 가는 것이 맞다. 5.3(a) 타깃이 생기면 `agents-md` `scopes: ["project"]` 좁히는 것이 깔끔하다.
** `detect` 너무 넓다.**
```ts
// 18줄
return await exists(path.join(ctx.cwd, "AGENTS.md")) || await exists(path.join(ctx.cwd, ".git"));
```
`.git` 있으면 참이므로 사실상 모든 리포에서 기본 선택 후보가 된다. AGENTS.md **조건 없이 항상 로드되는** 유일한 타깃이다. 기본 선택이 되기에는 비용이 크다. `AGENTS.md` 파일이 실제로 존재할 때만 `true` 좁히기를 권한다(없어도 사용자가 수동 선택하면 만들어진다 17줄 주석의 의도는 유지된다).
** 마커 처리는 되어 있다.**
`marker.ts` `upsertBlock`/`removeBlock`/`extractBlock` 블록 내용을 보존한다. AGENTS.md 사용자 소유 문서이므로 설계가 맞다. `agents-md.ts` 44줄의 안내 주석("직접 고치면 업데이트가 멈춘다") 적절하다.
가지: `upsertBlock` 블록이 없으면 **문서 끝에 덧붙인다**(marker.ts 28~29줄). AGENTS.md 가까운 파일이 이기고 root 부터 아래로 병합되므로 위치 자체는 무해하다. 다만 32 KiB 상한을 고려하면 F2 블록이 작아지는 것이 중요하다.
### 5.6 `common.ts` / `skill-source.ts` — 문제없음
- `.designpaca_version` 스킬 디렉터리에 쓰는 것: Agent Skills 스펙이 추가 파일을 허용하므로 무해하다. Cursor 재귀 스캔도 `SKILL.md` 찾으므로 영향 없다.
- `splitFrontmatter` 얕은 파서인 것: 현재 프론트매터가 `name` + `description` 2줄이라 충분하다. **YAML 블록 스칼라(`>-`, `|`)를 지원하지 않는다.** 원칙 3 수정안대로 description 여러 줄로 쓰고 싶다면 파서를 먼저 손봐야 한다. 지금은 double-quoted 유지하는 것이 안전하다.
- `walk()` `.orig` `.designpaca_version` 제외한다: `motion.md` 처럼 아직 없는 파일은 자연히 빠지고, 나중에 추가하면 자동으로 따라간다. 정상.
**추가 권고 — 빌드 타임 검증.**
SKILL.md 본문이 가리키는 `references/*.md` 15개 실제 존재는 14개다(측정 시점 기준). CLI 패키징 전에 다음을 확인하면 깨진 링크가 배포되는 것을 막는다:
```
본문에서 /references\/[\w\/-]+\.md/ 를 전부 뽑아 파일 존재를 확인.
없으면 빌드 실패.
```
`03-format-specs.md` §8.6 검증 체크리스트를 그대로 스크립트화하면 된다.
---
## 6. 조치 목록 (팀 리드용)
### 반드시 (5개)
| # | 파일 | 위치 | 내용 |
|:--:|---|---|---|
| F1 | `core/src/targets/common.ts`<br>`cursor.ts` 54줄<br>`agents-md.ts` 38줄 | — | `rewriteRefPaths()` 추가 후 Cursor·AGENTS.md 본문의 `references/` 27곳을 실제 설치 경로로 치환 |
| F2 | `core/src/targets/agents-md.ts` | 35~45줄 | 본문 14KB 전체 주입 → 포인터 블록(약 400B)으로 교체. `detect``AGENTS.md` 존재로 좁힘 |
| F3 | `skill/SKILL.md` 120~129<br>`references/tokens.md` §5<br>`references/preflight.md` §2 | — | 성능 예산 표를 `tokens.md` §5 단일 원본으로. SKILL.md 는 2줄 요약, preflight 는 실측 열만 |
| F4 | `skill/SKILL.md` | 176·177·185줄 | 게이트 2번에 상태색 예외, 3번을 `border-radius 3종 이상`으로 교체, 11번에 대안 3가지 추가 |
| F5 | `core/src/targets/cursor.ts` | 14·15·22~23줄 | Windsurf 표기 제거(또는 별도 어댑터). Windsurf 는 `.cursor/rules/*.mdc` 를 읽지 않는다 |
### 권장 (10개)
| # | 대상 | 내용 |
|:--:|---|---|
| R1 | `SKILL.md` 0단계 | 트리트먼트 축(에디토리얼 / 유틸리티) 추가 — 원칙 8 |
| R2 | `SKILL.md` 0단계 50줄 | `design.md` 가 있으면 1·2단계 건너뛰기 분기 — 원칙 6 |
| R3 | `SKILL.md` 프론트매터 | description 에 한국어 리터럴 발화 + 배제 조건 추가 — 원칙 3 |
| R4 | 새 어댑터 | `~/.agents/skills/designpaca/` 타깃 추가 — 한 번 써서 Codex·Cursor·Copilot 커버 |
| R5 | `codex.ts` 25줄 | project 스코프를 `.codex/skills``.agents/skills` 로 |
| R6 | `cursor.ts` 34줄 | `description: ${JSON.stringify(...)}` 로 YAML 인용 |
| R7 | `SKILL.md` 179줄 / `preflight.md` 76 / `layout.md` 109 | 가로 스크롤 검사 폭을 320~1920px 으로 통일 — M1 |
| R8 | `SKILL.md` 192줄 | eyebrow 규칙에 "전체 대문자는 0개" 명시 — M3 |
| R9 | `SKILL.md` 카운트 규칙 | 강조색 면적 ≤ 뷰포트 10% 추가 — 원칙 9 |
| R10 | `three.md` · `svg-filters.md` · `experimental-canvas.md` · `antipatterns.md` | 파일 상단에 3~8줄 섹션 목차 |
### 낮은 우선순위 (5개)
| # | 대상 | 내용 |
|:--:|---|---|
| L1 | `SKILL.md` 26줄 | "예외는 두 곳(접근성·하드 게이트)" 1문장 — 원칙 4 |
| L2 | `SKILL.md` 36줄 | 애니메이션 속성 제한은 예산과 무관하다는 1문장 — 원칙 10(b) |
| L3 | `SKILL.md` 173줄 | "접근성 전체는 preflight §1에서" 1문장 — 원칙 10(a) |
| L4 | `SKILL.md` 131줄 | 4단계 진입 전 6줄 요약 지시 — 원칙 7 |
| L5 | `layout.md` §4 / `preflight.md` §2 | `100vw` 금지 · 이미지 그리드 트랙 `minmax(0,1fr)` · 이중 sticky 금지 · LCP `loading="lazy"` 금지 — 원칙 10(c) |
| L6 | `cursor.ts` 30줄 | references 를 `.cursor/rules/` 밖(`.designpaca/`)으로 |
| L7 | CLI 빌드 | 본문의 `references/*.md` 링크 존재 검증을 패키징 전 게이트로 |
---
## 7. 확인 못한 것
- **Cursor 에서 Skills 와 `.mdc` Rules 가 동시에 있을 때의 우선순위** — 공식 문서에 명시가 없다. R4 를 적용하면 `.cursor/skills/designpaca/``.cursor/rules/designpaca.mdc` 가 공존할 수 있는데, 중복 로드되는지 하나가 이기는지 확인되지 않았다. 둘 중 하나만 설치하도록 CLI 가 배타 선택을 강제하는 편이 안전하다.
- **`~/.codex/skills/` 가 실제로 Codex 의 사용자 스킬 스캔 경로인지** — 디렉터리 구조상 거의 확실하나(Codex 가 `.system/` 을 관리), 공식 문서 근거가 없고 실제 발동 테스트는 하지 않았다. Codex 를 띄워 `/designpaca` 가 뜨는지 한 번 확인하면 결론이 난다.
- **Windsurf 실제 동작** — `.windsurf/rules/*.md``trigger: model_decision` 동작을 실기로 확인하지 않았다. 문서(docs.devin.ai, 리다이렉트 후) 기준이다.
- **본문 토큰 수 정확값** — 4,600은 한글 1자≈1토큰 가정의 보수적 추정이다. 실제 토크나이저 기준으로는 더 적을 수 있다. 5,000선에 붙는 판단이 걸려 있으므로 `/context``/doctor` 로 실측하기를 권한다.
- **`references/motion.md`** — 미작성. 파이프라인 4-4가 이 문서를 지목하고 참조 지도(230줄)에도 등재되어 있다. 작성 완료 시 F1의 경로 치환 대상에 자동 포함된다.
---
# §3. F1~F5 반영 재검증
검증 시점: 2026-08-20. `packages/core/src/targets/` 6개 파일 + `SKILL.md` + `tokens.md` + `preflight.md` 정독.
## 3.0 통과한 것
| 확인 항목 | 결과 |
|---|:---:|
| `types.ts``TargetId``"windsurf"` 추가됨 | O |
| `index.ts``ADAPTERS``windsurf` 등록됨 | O |
| `installer.ts:81``plan.blocked` 를 throw 한다 | O |
| Windsurf 상한 검사가 **경로 재작성 후** 길이로 이뤄진다 (45줄 생성 → 59줄 검사) | O |
| `REF_PREFIX` 세 개 모두 `references/` 를 포함하지 않아 이중 치환이 없다 | O |
| `agents-md.ts``skillMd` 를 재작성해서 `skillDirActions` 에 넘긴다 | O |
| `agents-md.ts``detect``AGENTS.md` 실존으로 좁혀졌다 | O |
| user 스코프 refRoot 의 `reference` 중복이 제거됐다 (`~/.designpaca/skill`) | O |
| `cursor.ts` 에서 Windsurf 감지·라벨이 분리됐다 | O |
| 성능 예산 값이 세 문서에서 충돌하지 않는다 (전수 grep) | O |
| `tokens.md` 5장에 "이 표가 유일한 원본" 선언 + 5단계 열 추가 | O |
| `preflight.md` 2장이 실측 열만 갖는다 | O |
| 하드 게이트 2·3·11 이 검증 가능한 형태로 교체됐다 | O |
게이트 11은 내가 제안한 것보다 나은 형태로 들어갔다. `{{SETUP_TIME}}` 같은 **명시적 placeholder** 를 허용하고 그것을 6단계 `design.md` 미확정 목록으로 넘기는 구조는, 단순히 대시로 바꾸는 것보다 추적이 된다. 게이트 4도 "정의 없이 섹션마다 다른 것이 실패"로 좁혀져 리듬으로 의도한 테마 반전이 오탐되지 않는다.
`preflight.md` 0장에 새로 들어간 두 줄은 실측에서 나온 것으로 보이고 둘 다 정확하다:
> **React·Vue·Astro 등 프레임워크 프로젝트 → 프로덕션 빌드 결과에 돌린다.** 소스만 보면 렌더된 DOM 이 없어 대비·가로 스크롤·LCP 를 잴 수 없다.
> grep 검사는 **주석과 문자열을 제외**해라. "100vh 금지"라고 쓴 주석이 게이트 #9 에 걸리는 오탐이 실제로 나왔다.
---
## 3.1 V1 — F1 이 절반만 고쳐졌다 (참조 파일 내부 상호 링크)
`rewriteRefPaths`**본문(`body` / `skillMd`)에만** 적용된다. `referenceActions`(common.ts 26~37줄)와 `skillDirActions`(9~23줄)는 `skill.files` 를 **그대로 복사**한다.
참조 파일 안에도 스킬 루트 기준 링크가 4곳 있다:
| 파일:줄 | 내용 |
|---|---|
| `references/layout.md:70` | "`references/antipatterns.md` 의 한글 조판 섹션을 읽어라" |
| `references/preflight.md:5` | "슬롭 지문 검출과 자가 채점표는 `references/antipatterns.md` 에 있다" |
| `references/preflight.md:35` | "`references/antipatterns.md` 의 grep 목록을 소스에 돌린다" |
| `references/tokens.md:143` | "상세는 `references/motion.md`" |
Cursor·Windsurf·AGENTS.md 설치본에서 이 네 곳은 프로젝트 루트 기준 `references/antipatterns.md` 를 가리키고, 그 경로에는 아무것도 없다. **본문은 고쳐졌는데 참조 파일끼리는 여전히 끊긴다.**
특히 `preflight.md:35` 가 아프다. 5단계 기계 검사 B가 antipatterns 의 grep 목록을 여는 지점인데, 그게 실패하면 슬롭 검출이 통째로 건너뛰어진다.
**수정안**`common.ts` 의 두 함수가 파일 내용도 재작성하게 한다.
```ts
export function skillDirActions(root: string, skill: SkillSource, refPrefix?: string): FileAction[] {
const rw = (s: string) => (refPrefix ? rewriteRefPaths(s, refPrefix) : s);
const actions: FileAction[] = [
{ kind: "write", path: path.join(root, "SKILL.md"), content: rw(skill.skillMd) },
];
for (const [rel, content] of skill.files) {
actions.push({ kind: "write", path: path.join(root, ...rel.split("/")), content: rw(content) });
}
actions.push({ kind: "write", path: path.join(root, ".designpaca_version"), content: `${skill.version}\n` });
return actions;
}
// referenceActions 도 같은 방식으로 refPrefix 를 받는다
```
호출부:
- `claude-code.ts` / `codex.ts``refPrefix` 를 넘기지 않는다(스킬 디렉터리 통째 복사라 상대 경로가 맞다)
- `cursor.ts:46``referenceActions(refRoot, ctx.skill, REF_PREFIX)`
- `windsurf.ts:49` — 동일
- `agents-md.ts:53``skillDirActions(refRoot, ctx.skill, refPrefix)` 로 바꾸고, 지금 인라인으로 하는 `skillMd` 재작성(54~56줄)은 제거한다(함수가 처리한다)
---
## 3.2 V2 — 단순 치환이 오작동한다 (`research/references/`)
팀 리드가 물어본 항목이다. **오작동할 여지가 있다.**
`replaceAll("references/", prefix + "/references/")` 는 문자열이 어디에 있든 자른다. 프로젝트 안에 이미 그런 문자열이 있다:
```
> 근거: research/references/04-ai-slop-signatures.md, 03-trends-2026.md (조사일 2026-08-20)
```
이 "근거" 줄은 **6개 참조 파일 하단에 각 1개씩** 있다: `antipatterns.md:271`, `galleries.md:163`, `layout.md:113`, `preflight.md:129`, `reference-method.md:240`, `tokens.md:194`.
치환하면 이렇게 망가진다:
```
research/.cursor/rules/designpaca/references/04-ai-slop-signatures.md
```
**지금은 터지지 않는다.** 참조 파일이 재작성 대상이 아니기 때문이다. 그러나 **V1 을 고치는 순간 정확히 이 6곳이 깨진다.** SKILL.md 본문에 `research/references/` 가 한 번이라도 들어가도 마찬가지다.
SKILL.md 본문은 지금 깨끗하다. 파일 경로가 아닌 `references/` 등장이 0곳임을 실측으로 확인했다.
**수정안** — 앞 경계를 명시한다.
```ts
/**
* 본문의 `references/...` 상대 경로를 실제 설치 위치로 바꾼다.
*
* 앞에 경로 세그먼트가 붙은 것은 우리 참조가 아니다 — 각 참조 파일 하단의
* `research/references/...` 근거 줄이 그렇다. 단순 치환하면 그것까지 망가진다.
*/
export function rewriteRefPaths(body: string, prefix: string): string {
return body.replace(/(^|[^\w./-])references\//g, (_m, lead: string) => `${lead}${prefix}/references/`);
}
```
실제 문자열로 검증했다:
| 입력 | 출력 |
|---|---|
| "- 어디서 찾는가 → `references/galleries.md`" | "`.cursor/rules/designpaca/references/galleries.md`" 정상 |
| "> 근거: research/references/04-ai-slop-signatures.md" | **변경 없음** 정상 |
| "상세는 `references/motion.md`." | 정상 |
| 표 셀 안의 "`references/presets/editorial.md`" | 정상 |
| 줄 시작 "references/tokens.md 로 시작하는 줄" | `^` 앵커로 매치, 정상 |
회귀 테스트에 `research/references/` 케이스를 추가하기를 권한다. V1 수정과 함께 들어가야 한다.
---
## 3.3 V3 — AGENTS.md 포인터 블록의 강도
팀 리드 질문: "에이전트가 실제로 SKILL.md 를 열게 만들 만큼 충분한가."
**구조는 맞다.** 조건절("UI 를 새로 만들거나 다시 디자인할 때는")이 무관한 대화에서 무시되게 하고, 순서 제약("마크업·스타일을 쓰기 전에")이 늦게 읽는 것을 막고, 경로가 구체적이다. AGENTS.md 는 항상 로드되므로 조건절 없이 쓰면 매 대화에서 노이즈가 된다. 지금 형태가 옳다.
**약한 지점 두 개.**
**(a) 읽지 않았을 때의 결과가 없다.** SKILL.md 자신은 결과를 말한다 — "1단계를 건너뛴 디자인은 5단계에서 실패 처리한다"(32줄), "세 줄을 못 쓰면 아직 작업을 시작할 수 없다"(52줄). 포인터에는 그런 문장이 없어서 "권고"로 읽힌다. 스킬은 호출 메커니즘이 받쳐주지만 AGENTS.md 포인터는 지시 준수만으로 버틴다. 결과 문장 하나가 그 차이를 메운다.
**(b) 안에 무엇이 있는지 모른다.** "파이프라인(0~6단계)"만으로는 여는 값어치를 판단할 근거가 없다. 원칙 1이 참조 파일에 목차를 요구하는 것과 같은 논리다. 목차는 여는 비용을 낮추는 게 아니라 **여는 이유**를 준다.
**수정안**`agents-md.ts` 40~50줄. 약 400B → 약 700B (32KiB 예산의 2%).
```ts
const block = [
"## designpaca — 웹 디자인 파이프라인",
"",
"UI 를 새로 만들거나 다시 디자인할 때는, 마크업·스타일을 쓰기 전에",
`\`${refPrefix}/SKILL.md\` 를 읽고 그 파이프라인(0~6단계)을 따른다.`,
"**읽지 않고 만든 화면은 이 프로젝트의 토큰 규약과 감사 기준을 통과하지 못한다.**",
"",
"안에 있는 것 — 규모 판정(전체/연장/국소) · 레퍼런스 조사법 · 디자인 토큰과 성능 예산 ·",
"미학 프리셋 4종 · 슬롭 지문 목록과 grep · 출시 전 하드 게이트 12개.",
"",
"- 프로젝트 루트에 `design.md` 가 있으면 그것이 최상위다. 스킬 기본값을 덮는다.",
`- 참조 문서는 \`${refPrefix}/references/\` 에 있다. 각 단계가 지시하는 것만 그때 연다.`,
"",
`<!-- designpaca v${ctx.skill.version} — \`npx designpaca update\` 가 관리한다. 직접 고치면 업데이트가 멈춘다. -->`,
].join("\n");
```
부수: 현재 43줄의 "이 리포에서" 는 user 스코프(`~/.codex/AGENTS.md`)에서는 리포가 아니다. 위 안에서는 그 표현을 뺐다.
---
## 3.4 V4 — Windsurf 어댑터 스펙 대조
`03-format-specs.md` 5장과 전 항목 일치한다.
| 스펙 | 문서 근거 | `windsurf.ts` | 판정 |
|---|---|---|:---:|
| 경로 | `.windsurf/rules/*.md` (legacy) / `.devin/rules/*.md` (권장) | `.windsurf/rules/designpaca.md` | O |
| 확장자 | `.md` (`.mdc` 아님) | `.md` | O |
| 프론트매터 키 | `trigger`, `globs` | `trigger`, `description` | O (아래 주) |
| trigger 값 | `always_on` / `model_decision` / `glob` / `manual` | `model_decision` | O |
| 워크스페이스 상한 | 12,000자/파일 | 12,000 하드, 초과 시 `blocked` | O |
| 글로벌 상한 | 6,000자 | (글로벌 미지원) | 해당 없음 |
**`description` 키에 대한 주의.** 내가 fetch 한 문서의 프론트매터 예시는 `trigger``globs` 만 보여준다. `model_decision` 모드 설명이 *"Description shown always; full content retrieved when Cascade deems relevant"* 이므로 description 필드는 이 모드의 전제이고 커뮤니티 예시들도 이 조합을 쓴다. **다만 공식 예시로 확인하지는 못했다.** 실기 확인 전까지는 "근거 있는 추정"으로 두는 게 정확하다.
현재 규칙 파일 최종 크기는 **9,061자**(경로 재작성 후, 헤더 포함) / 상한 12,000. 여유 2,939자. V1 수정으로 참조 파일도 재작성되더라도 규칙 파일 본문은 변하지 않으므로 이 값은 그대로다.
**`.devin/rules/` 병행 배치는 지금 하지 않는 게 맞다.** 문서가 `.windsurf/rules/` 를 legacy 로 표기하긴 하나 여전히 읽고, 두 곳에 쓰면 규칙이 두 번 적용될 수 있다.
---
## 3.5 V5 — description YAML 인용 (R6 미적용, 유지 권고)
`cursor.ts:33``windsurf.ts:40` 이 여전히 인용부호 없이 쓴다.
```ts
`description: ${ctx.skill.description}`,
```
현재 description 값(320자)에는 콜론+공백도 `#` 도 없어 **지금은 유효한 YAML 이다**(실측 확인). 그러나 원칙 3 수정안대로 배제 조건 문장을 넣으면 콜론이 들어갈 확률이 크게 오른다. 깨지면 Cursor·Windsurf 가 **조용히 규칙을 무시한다** — 에러가 나지 않아 알아채기 어렵다.
```ts
`description: ${JSON.stringify(ctx.skill.description)}`,
```
JSON 문자열은 YAML 의 유효한 double-quoted scalar 이므로 그대로 쓸 수 있다. 두 줄 고치면 끝난다.
---
## 3.6 V6 — 본문이 5,000토큰 선을 넘었다
F3~F4 반영 후 실측:
| 시점 | 줄 | 문자 | 추정 토큰 |
|---|---:|---:|---:|
| 감사 시작 | 235 | 7,271 | 약 4,600 |
| **F1~F5 반영 후** | **232** | **7,938** | **약 5,024** |
Claude Code 의 컴팩션 재부착 예산은 스킬당 앞 5,000토큰이다. **지금 선을 막 넘었다.**
추정치는 보수적이다(한글 1자를 1토큰으로 계산). 실제 토크나이저에서는 더 적게 나올 수 있다. 그래도 여유가 사라진 것은 사실이고, 4장의 원칙 8 블록(+14줄, 약 +300토큰)을 넣으면 확실히 넘는다.
넘으면 잘리는 것은 문서 **끝** — 참조 문서 지도 표와 "작업 중 지켜야 할 것" 섹션이다. 치명적이진 않지만(각 단계가 참조 파일을 인라인으로 지목하므로) 관리해야 한다.
**확보 방안 — 참조 문서 지도 표를 압축한다.** 216~233줄 표는 각 단계가 이미 인라인으로 하는 말을 반복한다. 표를 지우고 4줄로:
```markdown
## 참조 문서 지도
전부 `references/` 에 있다. **각 단계가 지시할 때 그것만 연다.**
1단계 `galleries.md` `reference-method.md` · 2단계 `presets/README.md` + 고른 프리셋 1개 · 3단계 `tokens.md` `antipatterns.md`(한글 조판) ·
4단계 `layout.md` `svg-filters.md` `three.md` `motion.md` `experimental-canvas.md` · 5단계 `preflight.md` `antipatterns.md`
```
약 13줄 절약(약 250토큰). 원칙 1의 인덱스 요건은 유지된다 — 어떤 파일이 있고 언제 읽는지가 여전히 한눈에 보인다.
`/context``/doctor` 로 실측하기를 권한다. 내 추정보다 낮게 나오면 표를 유지해도 된다.
---
## 3.7 V7 — M1(가로 스크롤 폭)이 아직 열려 있다
R7 권장 항목이라 미적용이 예상 범위이지만, 하드 게이트와 직결되므로 다시 올린다.
| 위치 | 값 |
|---|---|
| `SKILL.md:174` 하드 게이트 5 | `320~1920px 사이 어느 폭에서든` |
| `references/preflight.md:88` | `375px 폭에서 가로 스크롤 없음` |
| `references/layout.md:109` | `모바일 폭(375px)에서 가로 스크롤이 없다` |
하드 게이트는 "오버라이드 없음"이라고 선언한 목록인데 참조 문서 두 곳이 **더 느슨한 기준**을 준다. 모델이 375px 만 확인하고 게이트를 통과 표시할 근거가 문서 안에 있다. 320px 으로 통일하면 된다(iPhone SE 세로 폭이 320px 이고, 그 아래가 뚫린 채 남는다).
---
# §4. 원칙 8 설계안 — 규모별 경로 분기
## 4.1 문제
지금은 모든 브리프가 0~6 전 단계를 통과한다. "이 버튼 색 좀 바꿔줘"에 갤러리 3곳 조사와 프리셋 선택과 리스크 결정을 요구하면, 모델은 **스킬 전체를 무시하는 법을 배운다.** 한 번 무시하면 하드 게이트도 같이 사라진다.
반대 방향도 실패다. 경로를 쉽게 열어주면 전부 짧은 쪽으로 도망가고, 그러면 핵심 규칙 1("레퍼런스 없이 시작하지 않는다")이 무력해진다.
## 4.2 선행 사례에서 가져온 것
**Hallmark — 신호 발화(signal firing).** 규모를 "판단"하게 하지 않고 **사실 신호의 발화 여부**로 라우팅한다.
> **Route to component-scope** if any signal fires:
> - Brief names a single UI element (button, card, modal, etc.)
> - Brief is ≤30 words referencing one element
> - Target file is a single component
> - User says "just the X," "only the Y," "this one element"
>
> — Nutlope/hallmark `skills/hallmark/SKILL.md`
이것이 핵심 발명이다. **"작은 작업인가?"는 모델이 자기에게 유리하게 답할 수 있고, "새로 만드는 화면이 있는가?"는 사실이다.** 팀 리드가 요구한 "자의적 선언 방지"의 답이 여기 있다.
Hallmark 는 경로마다 무엇이 남는지도 명시한다. component-scope 는 macrostructure·nav/footer archetype·hero enrichment 를 건너뛰지만 **8가지 상태(default/hover/focus/active/disabled/loading/error/success)는 오히려 더 강하게 요구**한다. 축소가 아니라 **초점 이동**이다.
**design-taste-frontend — 모드 감지를 첫 행동으로.**
> ### 11.A Detect the Mode (first action)
> * **Greenfield** / **Redesign - Preserve** / **Redesign - Overhaul**
> If ambiguous, ask **once**: *"Should this redesign preserve the existing brand, or are we starting visually from scratch?"*
모드를 **가장 먼저** 정하고, 애매하면 딱 한 번 묻는다.
**artifact-design — 트리트먼트 보정과 기본 방향.**
> **Calibrate treatment, not whether to design.** ... **When unsure: a well-composed page is never the wrong answer; an over-designed visual identity sometimes is.**
**단 designpaca 는 기본 방향을 반대로 잡아야 한다.** artifact-design 의 주된 실패는 과잉 디자인이지만, designpaca 는 이미 핵심 규칙 3("화려함은 4순위")과 4("대담함은 한 곳에만")로 과잉을 막아뒀다. designpaca 의 주된 실패는 **레퍼런스 없이 기본값에서 시작하는 것**이다(핵심 규칙 1). 그러므로 **애매하면 긴 경로**로 기울어야 한다.
## 4.3 결정 1 — 분기 기준
세 개의 **사실 질문**으로 판정한다. 셋 다 파일을 보면 답이 나오고 모델이 해석으로 뒤집을 여지가 없다.
```
A. 없던 화면을 새로 만드는가?
B. 토큰 체계(색 역할·타입 스케일·간격 리듬·모션 문법)를 새로 정하거나 다시 정의하는가?
C. 프로젝트에 design.md 가 있는가?
```
**왜 이 셋인가.**
- **A(새 화면)** — 셀 수 있다. "기존 페이지에 섹션을 추가"는 화면을 새로 만드는 게 아니므로 아니오다. 그 경우는 아래 섹션 상한이 잡는다.
- **B(토큰 체계)** — 이것이 진짜 경계다. 토큰을 정의·재정의하면 시스템 변경이고 페이지 전체에 파급된다. 기존 토큰 안에서 값을 쓰는 것은 적용이다. 그리고 "토큰 파일을 여는가"로 확인된다.
- **C(design.md)** — 방향이 이미 정해졌다는 파일 증거다. 있으면 1·2단계를 다시 돌 이유가 없고, 오히려 다시 돌면 §2 원칙 6에서 지적한 "지난번과 다른 디자인"이 발생한다.
**A·B 를 "규모", C 를 "이력"으로 나눈 것이 이 설계의 뼈대다.** 규모가 크면 방향이 필요하고, 이력이 있으면 방향은 이미 있다.
**섹션 상한을 하나 더 건다.** A·B 가 둘 다 아니오여도 "기존 페이지 전면 개편"이 국소로 새면 안 된다.
```
국소 경로 조건 — 아래를 전부 만족할 때만
- A 아니오 (새 화면 없음)
- B 아니오 (토큰 체계 재정의 없음)
- 손대는 섹션이 2개 이하
```
"섹션 2개 이하"는 셀 수 있고, 조작하려면 사실을 왜곡해야 한다.
## 4.4 결정 2 — 경로 3개와 각 경로에 남는 것
2개로는 부족하다. "design.md 가 있는 재작업"이 갈 곳이 없어진다. 그게 실무에서 가장 흔한 경우다(같은 사이트에 페이지 추가).
| 경로 | 조건 | 도는 단계 |
|---|---|---|
| **전체** | (A 또는 B) 이고 C 아니오 | 0 → 1 → 2 → 3 → 4 → 5 → 6 |
| **연장** | (A 또는 B) 이고 C 예 | 0 → 3 → 4 → 5 → 6 |
| **국소** | A·B 아니오, 섹션 2개 이하 | 0 → 4 → 5 → 6(추기) |
**어느 경로에서도 남는 것** — 팀 리드 직관대로 하드 게이트와 `design.md` 다. 여기에 판단 하나를 더한다.
| 항목 | 전체 | 연장 | 국소 | 근거 |
|---|:---:|:---:|:---:|---|
| 하드 게이트 12개 | O | O | O | 버그 검사지 미학 검사가 아니다. 버튼 하나를 고쳐도 대비 4.5:1은 지켜야 한다 |
| 접근성(38줄) | O | O | O | 이미 "어떤 브리프보다 우선"이라 경로와 무관하다. **경로별로 다시 쓰지 않는다** — 쓰면 오히려 "경로마다 다를 수도 있나"로 읽힌다 |
| 토큰 경유 | O | O | O | 게이트 1번이 이미 커버한다 |
| `design.md` | 작성 | 갱신 | **한 줄 추기** | 국소마다 전체를 다시 쓰는 것도 과잉이다 |
| 카운트 규칙 | O | O | **손댄 부분만** | 섹션 2개를 고치면서 페이지 전체 eyebrow 를 세는 것은 범위 밖이다. 다만 **내가 추가한 것이 기존 카운트를 넘기게 만드는지**는 본다 |
| 레퍼런스 조사(1단계) | O | X | X | 연장·국소는 `design.md` 가 그 자리를 대신한다 |
| 리스크 하나(2단계) | O | 상속 | X | 연장은 `design.md` 의 리스크를 이어받는다. 국소에는 리스크가 없는 게 맞다 |
**카운트 규칙을 국소에서 "손댄 부분만"으로 좁힌 것이 이 표에서 유일하게 논쟁적인 결정이다.** 전부 돌리자는 주장도 가능하다. 그러나 국소 작업마다 페이지 전체 레이아웃 패밀리를 다시 세게 하면 그 자체가 국소 경로의 존재 이유를 없앤다. Hallmark 가 component-scope 에서 macrostructure 를 아예 건너뛰는 것과 같은 판단이다.
## 4.5 결정 3 — 어디에 쓰나
**0단계 안, 브리프 3줄 다음.** 이유:
- 새 섹션으로 만들면 파이프라인이 8단계처럼 보인다
- 0단계 앞에 두면 "브리프 게이트보다 먼저 하는 것"이 되어 순서가 꼬인다. 규모는 브리프를 읽어야 판정된다
- 0단계는 이미 "브리프 게이트"다. 규모 판정은 게이트의 일부다
분량 목표 **14줄**. 3.6의 참조 지도 압축(-13줄)과 상쇄되어 순증이 거의 없다.
## 4.6 결정 4 — 오용 방지 5층
**(a) 판정을 사실 질문으로.** "작은 작업인가?"가 아니라 "없던 화면을 새로 만드는가?"다. Hallmark 의 신호 발화 방식.
**(b) 선언 + 근거 의무.** 경로를 고르면 어느 조건으로 골랐는지 한 줄로 말한다. 원칙 4의 "설명 의무"와 같은 구조이고, 사용자가 즉시 교정할 수 있는 지점을 만든다.
**(c) 기본값을 긴 쪽으로.** 애매하면 국소가 아니라 연장/전체.
**(d) 승급 규칙(escalation).** 조사한 어느 스킬에도 없는 장치이고, 실무에서 가장 자주 필요한 것이다. 국소로 시작했는데 작업 중에 조건이 깨지는 일은 흔하다 — 버튼 색을 바꾸려다 보니 토큰이 아예 없어서 새로 정의해야 하는 경우.
> 국소로 시작했다가 조건이 깨지면 그 자리에서 멈추고 경로를 올린다. **올렸다고 말해라. 조용히 국소에 머무는 것이 이 스킬의 최대 실패다.**
**(e) 반대 방향 오용도 막는다.** 국소 경로가 "선택"이면 모델은 안전하게 긴 경로를 고른다. 그러면 사용자가 스킬을 끈다. 국소 조건에 해당하면 **국소로 가는 것이 의무**여야 한다. 이 문장이 없으면 경로 분기가 작동하지 않는다.
## 4.7 SKILL.md 에 넣을 최종 문장
### (1) 0단계 — 브리프 3줄 코드블록 다음, "**막혔을 때**" 앞에 삽입
```markdown
**규모를 판정한다.** 셋 다 사실 질문이다. 추측하지 말고 파일을 보고 답해라.
- **A.** 없던 화면을 새로 만드는가?
- **B.** 토큰 체계(색 역할·타입 스케일·간격 리듬·모션 문법)를 새로 정하거나 다시 정의하는가?
- **C.** `design.md` 가 있는가?
| 조건 | 경로 | 도는 단계 |
|---|---|---|
| (A 또는 B) 이고 C 아니오 | **전체** | 0 → 1 → 2 → 3 → 4 → 5 → 6 |
| (A 또는 B) 이고 C 예 | **연장** | 0 → 3 → 4 → 5 → 6 — 방향은 `design.md` 가 이미 답했다 |
| A·B 둘 다 아니오, 손대는 섹션 2개 이하 | **국소** | 0 → 4 → 5 → 6(한 줄 추기) |
고른 경로와 근거를 한 줄로 말해라: *"국소 — 새 화면 없음, 토큰 재정의 없음, 섹션 1개."*
**애매하면 긴 쪽으로.** 단 국소 조건에 해당하면 국소로 가라 — 버튼 하나에 갤러리 3곳을 여는 것은 사용자가 이 스킬을 끄게 만든다.
**국소로 시작했다가 조건이 깨지면 멈추고 올린다.** 토큰을 새로 정의하게 됐거나, 손댄 섹션이 3개를 넘었거나, 방향을 바꿔야 하면. **올렸다고 말해라. 조용히 국소에 머무는 것이 이 스킬의 최대 실패다.**
```
### (2) 파이프라인 도입부 42줄 — 교체
건너뛰기를 허용하되 순서는 고정임을 명시한다. 지금 문장("순서를 바꾸지 마라")과 경로 분기가 정면 충돌한다.
```markdown
일곱 단계다(0~6). 0단계에서 정한 경로에 따라 **일부 단계를 건너뛸 수는 있지만, 도는 단계의 순서는 고정이다.** 각 단계에는 통과 조건이 있고, 통과하지 못하면 다음 단계로 가지 않는다.
```
### (3) 핵심 규칙 1번 32줄 — 교체
지금 문장은 연장·국소 경로를 자동으로 실패시킨다.
```markdown
1. **레퍼런스 없이 시작하지 않는다.** 전체 경로에서 1단계를 건너뛴 디자인은 5단계에서 실패 처리한다. 연장·국소 경로는 `design.md` 가 그 자리를 대신한다 — 그것도 없이 건너뛰면 실패다.
```
### (4) 1단계 제목 68줄과 첫 줄 70줄 — 교체
```markdown
### 1단계 — 레퍼런스 조사 (전체 경로 전용, **건너뛰기 금지**)
이 단계가 designpaca의 심장이다. 머릿속 기본값이 아니라 **실제로 존재하는 사이트**에서 시작한다. 연장·국소 경로는 0단계에서 이미 이 단계를 건너뛰기로 정했고, 그 근거는 `design.md` 다.
```
### (5) 2단계 통과 조건 109줄 — 한 줄 추가
```markdown
> 통과 조건: 한 문장 컨셉 + 프리셋 + 리스크 하나가 적혔다.
> **연장 경로는 이 단계를 돌지 않는다.** `design.md` 의 컨셉·프리셋·리스크를 그대로 이어받는다. 바꾸고 싶으면 전체 경로로 올린다.
```
### (6) 5단계 카운트 규칙 끝 193줄 뒤 — 두 줄 추가
```markdown
**국소 경로는 카운트를 페이지 전체로 다시 세지 않는다.** 내가 손댄 부분이 기존 카운트를 넘기게 만드는지만 본다.
하드 게이트 12개는 경로와 무관하게 전부 돈다.
```
### (7) 6단계 210줄 뒤 — 세 줄 추가 (기존 통과 조건 교체 포함)
```markdown
**국소 경로는 전체를 다시 쓰지 않는다.** `design.md` 끝에 한 줄만 추기한다 — `2026-08-20 · 무엇을 바꿨는지 · 토큰 변경이 있으면 그 값`. 기록 없는 국소 작업이 쌓이면 design.md 가 거짓말이 된다.
> 통과 조건: `design.md` 가 프로젝트 루트에 있다(국소면 추기됐다).
```
## 4.8 분량 정산
| 항목 | 증감 |
|---|---:|
| (1) 0단계 규모 판정 블록 | +14줄 |
| (2) 파이프라인 도입부 교체 | 0 |
| (3) 핵심 규칙 1번 교체 | 0 |
| (4) 1단계 제목·첫 줄 교체 | 0 |
| (5) 2단계 통과 조건 | +1줄 |
| (6) 5단계 카운트 단서 | +2줄 |
| (7) 6단계 국소 추기 | +3줄 |
| 3.6 참조 지도 압축 | **-13줄** |
| **합계** | **+7줄** |
232줄 → 239줄. 토큰은 약 5,024 → 약 5,050 근처. **여전히 선에 붙어 있다.** 참조 지도 압축을 반드시 함께 넣어야 하고, 그래도 `/context` 실측이 필요하다.
## 4.9 이 설계가 하지 않는 것
- **경로를 자동으로 결정하지 않는다.** 모델이 판정하고 선언한다. 자동 판정은 브리프의 뉘앙스를 놓친다.
- **국소 경로에서 품질 기준을 낮추지 않는다.** 하드 게이트·접근성·토큰 경유는 그대로다. 줄어드는 것은 **방향 결정 비용**뿐이다.
- **4번째 경로(예: 탐색/실험)를 만들지 않는다.** 실험은 `experimental-canvas.md` 가 이미 게이트로 다룬다. 경로가 4개가 되면 판정 자체가 부담이 된다.