Teaching agents product design at Vercel
Vercel이 에이전트 스킬, 린트 규칙, Vercel Agent 코드 리뷰, 평가, 그리고 사람이 이끄는 업데이트 루프로 에이전트에게 프로덕트 디자인을 가르치는 방법

코딩 에이전트는 동작하는 UI를 빠르게 만들어 냅니다. 하지만 어려운 부분은 결이 다릅니다. 에이전트는 제품의 스타일을 흉내 내고, 패턴을 맞추고, 컨벤션을 따르려 애쓸 수 있습니다. 할 수 없는 것은 그 패턴이 왜 존재하는지 이해하는 일입니다. 코드는 무엇이 배포됐는지를 보여줄 뿐, 왜 그 컴포넌트, 그 문구, 그 인터랙션이 표준이 됐는지는 알려주지 않습니다. 그 근거는 디자인 리뷰, PR 코멘트, 슬랙 스레드, 그리고 그 자리에 있었던 사람들 안에 있습니다. 에이전트에게는 코드베이스에 없는 컨텍스트란 존재하지 않는 것과 같습니다.
Vercel은 에이전트 네이티브 팀입니다. 우리는 합의된 제품 결정을 코드처럼 다룹니다. 저장소에 두고, 변경을 그 기준에 비추어 리뷰하고, 그곳에서 일하는 모든 에이전트가 쓸 수 있게 합니다.
이를 구현한 방식이 product-design입니다. 세 부분으로 이뤄진 시스템입니다.
- 제품 판단이나 코드베이스 판단이 필요한 결정의 배경 컨텍스트를 코딩 에이전트에게 주는 에이전트 스킬.
- 명확한 규칙을 자동으로 강제하는 린터.
- 슬랙, Figma, GitHub에서 근거를 모아 가이드라인 업데이트 안을 만들어 리뷰에 올리는 리뷰 루프.
어떤 팀이든 자기 표준 위에 같은 구조를 세울 수 있습니다.
product-design 스킬의 내부
스킬은 그것이 관장하는 코드 옆, 저장소 안에 함께 삽니다. 구조를 단순화하면 이렇습니다.
repository/
├── AGENTS.md
├── .agents/
│ └── skills/
│ └── product-design/
│ ├── AGENTS.md
│ ├── SKILL.md
│ ├── references/
│ │ ├── product-judgment.md
│ │ ├── interface-quality.md
│ │ ├── resilience.md
│ │ ├── surfaces.md
│ │ ├── surfaces-{surface}.md
│ │ ├── copy.md
│ │ ├── rules.md
│ │ ├── glossary.md
│ │ ├── patterns.md
│ │ └── coverage-gaps.md
│ └── exemplars/
│ └── pr-{name}.md
└── tooling/
└── scripts/
└── evals/
├── fixtures.json
├── rules-checklist.json
└── <fixture>/
├── before/
└── after/저장소 루트의 AGENTS.md는 코딩 에이전트에게 언제 이 스킬을 로드할지 알려줍니다. 스킬 내부의 AGENTS.md는 로드 순서, 검증, 거버넌스를 정의합니다. SKILL.md는 런타임 워크플로우를 담당합니다.
references/에는 제품 판단, 인터페이스 품질, 복원력, 카피, 표준 제품 명칭, 인터랙션 패턴, 서피스별 결정이 담깁니다.
exemplars/는 이미 배포된 풀 리퀘스트에서 반복할 만한 결정과 피해야 할 실수를 함께 기록합니다. coverage-gaps.md는 아직 표준이 없는 영역을 나열합니다.
copywriting-eval/은 카피와 인터페이스 언어의 동작을 테스트합니다. 프로덕트 디자인 워크플로우 전반을 평가하지는 않습니다.
스킬이 라우팅하는 방식
SKILL.md는 먼저 요청 모드를 판별합니다. shape, implement, review, copy, harden 중 하나입니다. 덕분에 감사가 수정으로 번지거나, 카피 작업이 리디자인으로 확장되는 일을 막습니다. 백엔드 전용 작업, 텔레메트리, 콘솔 에러, 생성 파일, 배포되는 UI에 영향이 없는 테스트는 건너뜁니다.
스킬은 내용을 복제하는 대신 표준 출처로 라우팅합니다. 컴포넌트 API, 디자인 시스템 규칙, 접근성 기준, 인터랙션 가이드는 각자의 주인 곁에 그대로 둡니다.
라우팅은 작업과 서피스 양쪽에 따라 구체적으로 갈립니다. 실질적인 변경은 product-judgment와 interface-quality를 먼저 로드합니다. 카피, 컴포넌트, 레이아웃, 인터랙션, 접근성, 복원력 작업은 각각 좁은 레퍼런스로 라우팅됩니다. 모달이라면 파괴적 액션 패턴과 표준 동사를 로드합니다. 설정 폼이라면 레이블, 검증, 점진적 공개, 접근 가능한 이름 가이드를 로드합니다.
아래 단순화한 구조를 출발점으로 삼고, 경로와 표준을 여러분의 것으로 바꾸면 됩니다.
---
name: product-design
description: >-
apps/vercel-site의 프로덕트 디자인과 사용자에게 보이는 제품 구현을 위한 단일
진입점. 사용자가 보고, 이해하고, 선택하고, 행동하는 것을 바꾸는 작업이라면
언제나 사용한다. 요구사항과 플로우 설계, 페이지와 컴포넌트의 신규 구축 또는
리디자인, URL·스크린샷·diff·Vercel Agent 지적 사항 리뷰, 제품 카피·정보
구조·컴포넌트 선택·Geist 준수·위계·레이아웃·인터랙션·접근성·반응형 동작 개선,
그리고 로딩·빈 상태·에러·권한·결제·파괴적 상태 개선이 여기 해당한다.
design, UX, UI, 사용성, 플로우, 온보딩, 설정, 대시보드, 구축, 개선, 수정,
감사, 리뷰, 다듬기, 단순화, 프로덕션 준비 요청에서 트리거한다. 백엔드 동작이
사용자에게 보이는 결과를 바꿀 때도 사용한다. 사용자에게 보이는 영향이 없는
백엔드 전용 작업, 배포되는 UI에 영향이 없는 테스트, 텔레메트리 전용 작업,
문서, 마케팅 콘텐츠에는 사용하지 않는다.
---
# Vercel Product Design
인터페이스를 사용자에게, 제품에게, 그리고 Vercel에게 올바른 것으로 만든다. 동작하는 코드만으로는 충분하지 않다. 올바른 인터랙션을 고르고, 범위와 결과를 분명히 드러내고, 해피 패스 너머의 현실을 다루고, 렌더된 결과를 검증한다.
## 운영 원칙(Operating Contract)
- **픽셀이 아니라 할 일에서 시작한다.** 누가 행동하는지, 무엇을 이루려 하는지, 어떤 제품 객체가 관여하는지, 시스템이 무엇을 바꿀지를 파악한다.
- **산출물보다 결과를 먼저 정의한다.** 서피스나 컴포넌트를 고르기 전에 현재의 사용자 문제, 원하는 동작, 성공 신호, 하지 않을 것(non-goals)을 정한다.
- **취향이 아니라 근거를 쓴다.** 결정은 제품 동작, 저장소의 표준 가이드, 합의된 디자인 결정, 검증된 인접 패턴으로 거슬러 올라갈 수 있어야 한다.
- **사실과 결정을 분리한다.** 가정과 아직 결론이 나지 않은 제품 선택은 명시적으로 표시한다. 구현 세부사항 속에 숨기지 않는다.
- **배포된 코드는 근거이지, 자동으로 선례가 되지는 않는다.** 그것은 무엇이 존재하는지를 증명할 뿐, 왜 옳은지를 증명하지 않는다. 현재 컴포넌트, 제품 동작, 명시된 가이드에 비추어 확인한다.
- **가장 작고 일관된 개입을 고른다.** UI를 추가하기 전에 더 나은 기본값, 동작, 재사용을 먼저 검토한다. 하나의 할 일을 풀기 위해 관련 없는 설정이나 추상화를 만들지 않는다.
- **꾸미기 전에 결정한다.** 스타일링이나 카피 수정에 앞서 정보 구조, 컴포넌트 시맨틱, 인터랙션, 상태 동작을 먼저 정리한다.
- **도달 가능한 모든 상태를 설계한다.** 제품이 실제로 진입할 수 있는 상태만 포함하되, 데이터가 채워진 성공 케이스에서 멈추지 않는다.
- **실제 서피스를 검증한다.** 소스 확인은 동작을 확인해 주고, 렌더된 인터페이스는 시각·인터랙션 품질을 확인해 준다. 코드만 보고 시각 검증을 했다고 주장하지 않는다.
- **사용자용 진입점은 하나로 유지한다.** `product-design`을 호출하고, 내부에서 아래의 표준 출처로 라우팅한다.
## 요청 모드(Request Modes)
행동하기 전에 사용자의 동사와 대상 산출물로 모드를 판별한다.
| 모드 | 대표 요청 | 요구되는 동작 |
| ---- | -------- | ------------ |
| Shape | "이 플로우를 설계해 줘", "이건 어떻게 동작해야 해?", UI가 확정되지 않은 기능 브리프 | 문제와 근거를 정리하고, 실질적인 대안을 비교한 뒤 플로우, 상태, 수용 기준, 리스크, 미결 결정을 정의한다. 요청받지 않으면 수정하지 않는다. |
| Implement | "만들어", "고쳐", "개선해", "규칙에 맞춰", "전부에 product-design 돌려" | 실질적인 제품 결정을 먼저 해결한 뒤, 범위 안에서 가장 작고 일관된 end-to-end 변경을 구현한다. 관련 없는 리뷰 지적 사항을 끌어안지 않는다. |
| Review | "감사해 줘", "비평해 줘", "뭐가 잘못됐어?", 코드 리뷰 | 소스와 렌더된 근거를 확인하고, 우선순위를 매긴 지적 사항을 보고한다. 요청받지 않으면 수정하지 않는다. |
| Copy | "카피 고쳐 줘", "이 에러 문구 다시 써 줘" | 사용자에게 보이는 문구, 접근 가능한 이름, 그리고 직접 필요한 JSX만 수정한다. 구조적 장애물은 범위를 조용히 넓히지 않고 보고한다. |
| Harden | "다듬어 줘", "프로덕션 준비", "엣지 케이스 처리해 줘" | 이미 정해진 제품 방향은 유지하면서 상태, 복원력, 반응형, 접근성, 마무리 결함을 고친다. |
의도가 모호할 때는 그 동사가 뒷받침하는 가장 좁은 모드를 쓴다. URL, 스크린샷, 라우트, 컴포넌트는 범위를 지정할 뿐, 그것만으로 수정을 허가하지는 않는다.
실질적인(material) 결정이란 사용자의 할 일, 기본값, 범위, 결과, 내비게이션, 인터랙션 서피스, 도달 가능한 상태를 바꾸는 결정이다. 카피 표기 정리, 토큰 교체, 이미 확립된 컴포넌트 대체는 보통 실질적인 결정이 아니다.
## 결정 권한(Decision Authority)
충돌은 다음 순서로 해결한다.
1. 사용자가 명시한 목표와 제약.
2. 검증된 사용자/제품 근거와 시스템의 실제 사실.
3. 저장소의 표준 가이드: `AGENTS.md`, Geist 컴포넌트 API, `packages/geist/STYLE_GUIDE.md`, 라우팅된 스킬.
4. 안정적인 근거를 갖춘, 합의된 제품/디자인 결정과 exemplar.
5. 같은 제품 영역에서 검증된 인접 배포 패턴.
6. 일반적인 인터페이스 휴리스틱.
## 워크플로우
### 1. 범위와 모드를 정한다
작업 계획서나 리뷰 노트에 대상 서피스와 요청 모드를 명시한다.
### 2. 제품 컨텍스트를 로드한다
UI를 제안하기 전에, 해당되는 `AGENTS.md` 체인, 제공된 브리프와 디자인, 그리고 변경(mutation)·권한·검증·에러·부수 효과를 결정하는 제품 로직을 읽는다.
### 3. 제품 결정을 모델링한다
Shape, Implement, Harden, 전체 Review, 또는 실질적인 제품/플로우 변경이라면 `product-judgment.md`를 읽고, 사용자, 할 일, 현재 동작, 원하는 결과, 성공 신호, 하지 않을 것, 객체, 범위, 액션, 결과, 되돌릴 수 있는지, 권한, 미결 결정을 담은 간결한 내부 브리프를 작성한다.
### 4. 서피스와 상태를 매핑한다
진입점, 보이는 영역, 오버레이, 전환, 이탈, 복귀 경로를 목록화한다. 도달 가능한 상태만 매핑하며, 여기에는 로딩, 빈 상태, 데이터가 적은 상태, 채워진 상태, 검증, 에러, 권한, 비활성, 낙관적 업데이트, 오래된 데이터, 파괴적 상태, 반응형 변형이 포함된다.
### 5. 라우팅된 레퍼런스를 로드한다
| 필요한 것 | 로드할 것 |
| -------- | -------- |
| 제품/플로우/컴포넌트 결정 | `product-judgment.md` + `component-guide` |
| 구현, 실질적인 시각 변경, 전체 리뷰 | `interface-quality.md` |
| 카피 또는 접근 가능한 이름 | `copy.md` + `surfaces.md` 라우팅 |
| 레이아웃, 타이포그래피, 색상, 여백, Geist API | `design-guidelines` + `packages/geist/STYLE_GUIDE.md` |
| 키보드, 포커스, 폼, 터치, 애니메이션, URL 상태, 성능 | `web-interface-guidelines` |
| 오버플로, 로컬라이제이션, 극단적 데이터, 네트워크/에러 복원력 | `resilience.md` |
### 6. 결정한 다음 구현한다
기계적이지 않은 모든 변경에 대해 다음에 답할 수 있어야 한다. 이 변경은 어떤 사용자 문제를 해결하는가, 왜 이 컴포넌트가 적절한가, 인터페이스가 반드시 전달해야 하는 결과는 무엇인가, 어떤 근거가 이 결정을 뒷받침하는가, 가장 작고 일관된 변경은 무엇인가.
### 7. 검증한다
1. 주된 할 일과 수용 기준을 확인한다.
2. 저장소의 린트 검사를 돌린다.
3. 좁은 뷰포트와 넓은 뷰포트를 관련 범위에서 확인한다.
4. 실질적으로 바뀐 모든 도달 가능한 상태를 직접 거쳐 본다.
5. 키보드 순서, 포커스 이동, 로딩 동작, 포인터/터치 타깃을 검증한다.
6. 긴 콘텐츠, 큰 값, 제한된 너비, 로컬라이제이션/RTL 리스크를 테스트한다.
7. 구조적으로 보이는 변경에는 `review-design-system`을 로드한다.
## 프로덕트 디자인 표준
- 사용자의 주된 할 일과 주된 액션이 헷갈릴 수 없게 만든다.
- 사용자의 멘탈 모델과 현재 컨텍스트를 유지한다. 그것을 바꾸는 것이 검증된 문제를 해결하는 경우가 아니라면.
- 중요한 액션에서는 정확한 대상, 범위, 결과를 이름으로 밝힌다.
- 내비게이션에는 내비게이션 컴포넌트를, 액션에는 액션 컴포넌트를 쓴다.
- 서피스가 얼마나 지속되어야 하는지는 중요도에 맞춰 고른다.
- 모달을 추가하기 전에 인라인 공개를 먼저 검토한다.
- 고급 컨트롤은 필요할 때 드러내되, 기본 경로가 그 복잡도를 짊어지게 하지 않는다.
- 사용자가 배우고 관리해야 하는 설정을 추가하기보다, 강력한 기본값과 직접적인 동작을 택한다.
- 커스텀 HTML이나 스타일링보다 시맨틱한 Geist 컴포넌트와 그 API를 먼저 쓴다.
- 컨테이너를 추가하기 전에 위계, 여백, 정렬을 먼저 쓴다.
- 검증과 복구 가능한 에러를 거치는 동안 사용자 입력을 보존한다.
- 로딩 중에도 컨트롤 레이블은 그대로 두고, 컴포넌트의 loading/busy 어포던스를 쓴다.
- 파괴적 액션은 그 영향에 비례하게 만들고, 시스템이 정직하게 지원할 수 있을 때 되돌리기를 제공한다.
- 구조, 상태, 브랜드 의도를 명확히 하는 경우가 아니라면 장식적인 새로움, 모션, 카피를 추가하지 않는다.
## 리뷰 산출물
사용자 영향 순으로 정렬한 지적 사항을 먼저 제시한다.
- **P0:** 주된 할 일을 막거나, 심각한 접근성 실패를 만들거나, 되돌릴 수 없는 사용자 피해를 일으킬 수 있음.
- **P1:** 할 일 실패 가능성이 높거나, 결과를 오해하게 만들거나, 핵심 상태가 빠졌거나, 반응형/접근성에 중대한 결함이 있음.
- **P2:** 유의미한 마찰, 비일관성, 약한 위계, 복구 가능성 문제.
- **P3:** 사소한 완성도 또는 일관성 개선.
각 지적 사항에는 파일/라인 또는 렌더된 위치, 검증 상태, 표준 출처, 사용자에게 미치는 결과, 그리고 가장 작은 구체적 수정안을 포함한다.
## 스킬 무결성(Skill Integrity)
- 규칙은 현재 출처를 검증하고 사람이 수락한 뒤에만 추가하거나 변경한다.
- 범위, 근거, 증거, 예외, 그리고 나쁜 예/좋은 예를 기록한다.
- 가장 좁은 목적지를 택한다. 표준 출처, 라우팅된 레퍼런스, exemplar, 린트/평가 검사, 커버리지 갭 중에서.
- 결정적 검사는 기계적으로 유지한다. 판단은 그 근거와 허용 재량과 함께 산문으로 남긴다.
- 스크린샷 하나, 배포된 파일 하나, 리뷰어 코멘트 하나만으로 보편 규칙을 만들지 않는다.라우팅은 이 스킬을 유용하게 만드는 요소의 절반일 뿐입니다. 나머지 절반은, 스킬이 결과를 내놓은 뒤에도 그 결과의 출처를 추적할 수 있게 만드는 방식입니다.
지적 사항을 추적 가능하게 만들기
카피 규칙에는 안정적인 ID가 있고, 각 규칙은 자신의 표준 출처를 가리킵니다.
rule/destructive-names-action
출처: copy.md > Actionable; verbs.md
규칙: 파괴적 CTA는 '동사 + 명사'를 따른다.
Confirm, OK, 또는 동사 하나만 쓰지 않는다.Vercel Agent가 패치를 제안할 때는, 제안을 올리기 전에 안전한 Vercel Sandbox 안에서 저장소의 빌드, 테스트, 린터로 그 변경을 검증합니다.
더 빠른 피드백을 위해 린터를 쓰세요
린터가 규칙을 안정적으로 강제할 수 있다면 우리는 결정적 검사를 선호합니다. 린터는 빠르고 실행 비용이 싸기 때문에, 개발자와 코딩 에이전트가 나중의 리뷰를 기다리지 않고 작업 중에 바로 피드백을 받습니다.
코드는 정적 옵션이 두세 개인지 셀 수 있으므로, 라디오 버튼을 권하는 일은 린터가 할 수 있습니다. 파괴적 액션에 대해 올바른 대상과 결과를 이름 짓는 일은 제품 컨텍스트가 필요하므로 스킬이 담당합니다.
코드베이스에 있는 규칙의 예시는 다음과 같습니다.
- 포커스 관리, 키보드 내비게이션, 레이어링을 깨뜨리는 중첩 모달을 막습니다.
- 정적 옵션이 두세 개일 때 셀렉트 대신 라디오 버튼을 권해, 모든 선택지가 항상 보이게 합니다.
- 아이콘 버튼과 폼 컨트롤에 접근 가능한 이름을 요구하고, 공용 포커스 토큰을 우회하는 커스텀 포커스 링을 거부합니다.
- 레이아웃 클래스는 허용하되,
className이 디자인 시스템 컴포넌트의 색상, 라운드, 그림자를 덮어쓰지 못하게 막습니다. - 긴 콘텐츠가 제대로 스크롤되고 헤더와 푸터가 고정될 수 있도록
Modal.Body를 요구합니다. - 원시 그림자를 테마를 인지하는 Material 클래스로 바꾸고, Material에 이미 포함된 처리와 중복되는 테두리를 거부합니다.
- 4px 그리드에서 벗어난 임의의 여백을 표시하고, 대응하는 표준 유틸리티가 있으면 제안합니다.
각 규칙은 그 패턴이 왜 문제인지 설명하고 구체적인 수정안을 제시합니다. 일부 규칙은 더 이상 쓰지 않는 Tailwind 유틸리티 이름 교체처럼 안전한 마이그레이션을 자동으로 고칩니다.
합의된 결정은 여러 형태를 띨 수 있습니다.
Checkbox best practices처럼, 해당 Geist 컴포넌트 옆에 놓인 사람이 읽는 가이드.
product-design 스킬 안의 에이전트용 가이드.
코드가 안정적으로 검사할 수 있을 때의 린트 규칙.
아래 린트 규칙은 하나의 제품 가이드라인이 결정적 검사로 인코딩되는 방식을 보여줍니다.
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Suggest Radio buttons when Select has 2-3 static options',
category: 'Design System',
recommended: true,
},
schema: [],
messages: {
preferRadio:
'Select with {{ count }} static options. Consider using Radio buttons — they show all options at once without requiring a click to open.',
},
},
create(context) {
return {
JSXElement(node) {
const opening = node.openingElement;
if (opening.name.type !== 'JSXIdentifier') return;
if (opening.name.name !== 'Select') return;
const hasDynamic = node.children.some(
(child) =>
child.type === 'JSXExpressionContainer' &&
child.expression.type === 'CallExpression',
);
if (hasDynamic) return;
const optionChildren = node.children.filter(
(child) =>
child.type === 'JSXElement' &&
child.openingElement.name.type === 'JSXIdentifier' &&
child.openingElement.name.name === 'option',
);
if (optionChildren.length < 2 || optionChildren.length > 3) return;
context.report({
node: opening,
messageId: 'preferRadio',
data: { count: String(optionChildren.length) },
});
},
};
},
};이런 규칙들은 각각 한 부류의 실수를 자동으로 잡아내고, 그만큼 코드 리뷰는 실제로 판단이 필요한 결정에 집중할 수 있게 됩니다.
평가로 가이드를 검증하는 방법
린트 규칙은 결정적이지만 에이전트의 행동은 달라질 수 있습니다. 그래서 우리는 스킬이 본 적 없는 인터페이스로 스킬을 테스트합니다.
에이전트가 before 상태를 수정하면, 판정자가 루브릭에 맞춰 결과를 확인합니다.
평가는 스킬에 문서화된, 실제로 배포된 예시에서 가져옵니다. 홀드아웃은 기대되는 수정 내용을 감춰서, 가이드가 일반화되는지를 테스트합니다. 또한 스킬 없이 픽스처를 돌려, 스킬이 실제로 에이전트의 행동을 바꿨는지 측정합니다.
규칙 준수 정확도는 배포된 결과와의 유사도와 분리해서 채점합니다. 배포된 코드에도 결함이 있을 수 있고, 그럴 때 에이전트는 그것을 재현할 게 아니라 개선해야 하기 때문입니다.
가이드를 최신으로 유지하기
컴포넌트, 명칭, 워크플로우, 실패 상태가 바뀌면 제품 표준도 바뀝니다. 그리고 모든 업데이트에는 근거와 사람의 리뷰가 필요합니다.
우리의 주간 근거 수집 워크플로우는 product-design을 개선할 만한 디자인 피드백을 모읍니다. 슬랙 대화를 검색하고 Figma 파일, 풀 리퀘스트, 리뷰 코멘트, 프리뷰 링크를 근거로 보존합니다. 근거가 불완전하면 검증에 필요한 코드나 커밋을 기록해 둡니다.
이 워크플로우는 수집과 판단을 분리합니다.
- 수집자(collector)는 규칙을 제안하지 않고 메시지, 링크, 주변 컨텍스트만 모읍니다.
- 별도의 판정자(judge)가 근거를 묶고, 출처를 검증하고, 미해결 질문을 기록합니다.
- 잡(job)이 후보, 기각된 주제, 추가 요청, 커버리지 갭이 담긴 리뷰 패킷을 만듭니다.
모든 후보는 출처로 연결되며 보류 상태로 남습니다. 경험 많은 리뷰어의 코멘트는 우선순위를 올릴 수 있지만, 그래도 모든 후보에는 근거가 필요합니다.
자동화는 리뷰 패킷에서 끝납니다. 어떤 후보가 에이전트 가이드, 린트 규칙, 예시, 평가가 될지 아니면 아무 변경도 하지 않을지는 사람이 정합니다. 채택된 변경은 가장 좁은 관련 파일로 들어가고, 머지 전에 해당 검사를 통과해야 합니다.
여러분의 코드베이스에 product-design을 만드는 법
우리의 셋업은 Vercel의 제품, 컴포넌트, 리뷰 히스토리를 반영한 것이지만, 다른 팀도 이 구조를 자기 표준에 맞게 바꿔 쓸 수 있습니다.
1. 반복되는 결정에서 시작하세요
같은 리뷰 코멘트가 계속 반복되는 제품 서피스를 하나 고르세요. 파괴적 액션, 에러 상태, 설정 폼, 빈 상태, 내비게이션 같은 것들입니다. 배포된 코드와 실제 리뷰에서 예시를 모으고, 그 결정과 왜 중요한지, 예외, 출처를 적어 두세요.
명확한, 깔끔한, 직관적인 같은 넓은 형용사로 시작하지 마세요. 에이전트에게는 관찰 가능한 결정이 필요합니다. 파괴적 액션은 동사 + 명사를 쓴다는 쓸 수 있는 규칙입니다. 버튼은 명확해야 한다는 아닙니다.
# 결정: {이름}
상태: 제안됨 | 채택됨 | 기각됨
범위:
결정:
근거:
증거:
예외:
나쁜 예:
좋은 예:
가정:
미결 결정:다른 곳으로 넓히기 전에, 먼저 여러분의 서피스에 맞는 항목부터 채우세요.
2. 명시적인 트리거와 확실한 경계를 두세요
에이전트가 언제 스킬을 로드해야 하는지를 저장소의 상시 지침에 적고, 스킬이 다루는 파일과 서피스, 그리고 건너뛰어야 할 영역을 정의하세요. 별도의 Next.js 평가에서는 사용 가능한 스킬이 있는데도 에이전트가 이를 호출하지 못한 경우가 56%였습니다. 트리거는 가이드 내용과 분리해서 테스트하세요. 스킬을 로드하지 못한 것과 규칙을 따르지 못한 것은 서로 다른 문제이기 때문입니다.
사용자에게 보이는 UI를 설계하거나, 수정하거나, 리뷰할 때는
.agents/skills/product-design/SKILL.md를 로드한다.
적용 대상:
- 사용자에게 보이는 페이지와 컴포넌트
- 카피, 인터랙션, 접근성, 반응형 동작, 상태
건너뛸 것:
- 사용자에게 보이는 영향이 없는 백엔드 전용 작업
- 텔레메트리, 생성 파일, 문서, 마케팅에이전트에게 어떤 서피스와 레퍼런스를 로드했는지 보고하게 한 뒤, 지적 사항이 실제로 그 출처를 인용하는지 확인하세요.
3. 라우팅, 규칙, 근거를 분리하세요
짧은 진입점으로 서피스를 식별하고 좁은 레퍼런스를 로드하세요. 세부 내용은 리뷰어들이 이미 이야기하고 있는 서피스와 결정을 기준으로 정리하세요. 폼, 모달, 내비게이션, 제품 용어, 워크플로우 상태, 서피스 간 공통 패턴 같은 것들입니다.
규칙에 안정적인 ID를 부여하고 예시와 출처로 연결하세요. 배포된 예시는 유용한 결정과 알려진 결함을 함께 기록하고, 빠진 가이드는 커버리지 갭 목록으로 계속 눈에 보이게 두세요.
# {서피스}
로드 시점:
표준 출처 담당:
## rule/{stable-id}
범위:
규칙:
이유:
예외:
출처:
## 예시
나쁜 예:
좋은 예:
## 커버리지 갭
- {빠진 결정 또는 근거}커버리지 갭 목록은 빠진 가이드를 명시적으로 드러냅니다.
4. 명확한 규칙에는 코드를 쓰세요
린터가 문제를 안정적으로 식별할 수 있다면 규칙은 거기서 강제하세요. 제품이나 코드베이스 컨텍스트가 필요한 결정에는 에이전트 가이드를 쓰세요. 새로운 표준, 정책적 선택, 아직 결론이 나지 않은 제품 결정은 사람에게 남겨 두세요.
문서화된 예시로 학습용 픽스처를 만들고, 기대 수정 내용이 스킬에 없는 인터페이스로 홀드아웃을 만드세요. 검색(retrieval)과 적용(application)은 따로 테스트하세요. 에이전트가 스킬을 로드했는지와 규칙을 따랐는지는 서로 다른 질문이기 때문입니다.
렌더하지 않고도 코드가 그 실패를 식별할 수 있는가?
- 아니오: 에이전트 가이드를 쓴다.
- 예: 그 규칙이 오탐(false positive)을 피할 수 있는가?
- 아니오: 에이전트 가이드를 쓴다.
- 예: 위반에 대한 구체적인 수정안이 있는가?
- 예: 린터를 쓴다.
- 아니오: 경고 또는 에이전트 가이드를 쓴다.
제품이나 코드베이스 컨텍스트가 필요하다: 에이전트 가이드를 쓴다.
새로운 표준이나 제품 정책을 세운다: 사람의 결정을 요구한다.
어느 쪽이든, 회귀를 잡을 수 있는 예시나 평가를 추가한다.예외를 잔뜩 두지 않으면 규칙이 안정적으로 유지되지 않는다면, 그 규칙은 다시 에이전트 가이드로 옮기세요.
5. 담당자와 업데이트 루프를 정하세요
새 근거는 정기적으로 리뷰하되, 가이드나 검사를 바꾸기 전에는 반드시 사람의 승인을 받으세요. 무엇이, 왜 바뀌었고, 어떤 출처가 그것을 뒷받침했는지 기록하는 결정 로그를 유지하세요. 새 규칙은 제품 변경처럼 다뤄서 하나하나 리뷰하고 테스트하고, 더 이상 도움이 되지 않는 규칙은 제거하세요.
수집자(collector) 프롬프트
너는 수집자다. 메시지, 링크, 파일, 주변 컨텍스트를 모아라.
가공하지 않은 산출물만 기록한다. 후보를 채점하거나 규칙을 제안하지 않는다.
판정자(judge) 프롬프트
너는 판정자다. 관련 근거를 묶기 전에 커버리지를 먼저 검증하라.
검증된 사실, 추론, 미해결 질문을 분리한다.
모든 후보는 보류 상태로 둔다. 가이드를 수정하지 않는다.
사람 리뷰
선택한다: 규칙, 레퍼런스, exemplar, 린트 규칙, 평가, 커버리지 갭, 또는 변경 없음.
안정적인 근거, 명시적인 범위와 예외, 그리고 승인자를 요구한다.서피스 하나와, 여러분의 팀이 이미 반복하고 있는 결정에서 시작하세요. 그 결정들을 코드가 쓰이고 리뷰되는 곳에 두되, 무엇이 표준이 되는지에 대한 책임은 사람에게 남기세요.
직접 만들어 보세요
가장 어려운 부분은 첫 서피스를 고르는 일입니다. 어느 팀에나 기록해 둘 만한 결정이 있습니다. 문제는 그 결정이 누군가의 머릿속에 있느냐, 아니면 에이전트가 찾을 수 있는 곳에 있느냐입니다. 이 패턴으로 무언가를 만들었거나, 우리가 어떻게 셋업했는지 궁금한 점이 있다면 알려주세요.