Yosegi — 호스트 자체 컴포넌트로 화면 구축하기
버전: 2026-08-13. 에이전트 harness는 오래된 스킬 복사본을 로드할 수 있습니다. 이 날짜가 저장소의
skills/yosegi/SKILL.md에 있는 날짜보다 오래된 경우, 구 버전을 읽고 있는 것입니다 — 계속 진행하기 전에 다시 설치하십시오.
Yosegi는 호스트 프로젝트의 컴포넌트를 사실(fact)로 변환하여 화면을 구축할 수 있게 하고, 구현 전에 검토할 수 있도록 화면을 Story(CSF)로 내보냅니다. 자체 렌더링 환경이나 GUI가 없으므로, 호스트의 Storybook에서 결과물이 어떻게 보이는지 확인합니다. Storybook이 없는 호스트의 경우, 결과물은 일반 React 컴포넌트 파일(--target component)이 됩니다 — 아래 1단계 분기에서 절차가 어떻게 변경되는지 설명합니다.
이 문서는 절차이며, 당신이 이를 수행하는 주체입니다. CLI(및 이에 상응하는 MCP 도구)는 절차가 참조하는 도구입니다.
사용 시기
- 기존 디자인 시스템에서 화면 제안 또는 UI 목업을 검토 가능한 형태로 구성할 때
- 구현 전에 새로운 화면의 초고를 Storybook에서 볼 수 있게 할 때
- UI를 작성하기 전에 호스트가 어떤 컴포넌트를 가지고 있고 실제로 어떤 props를 받는지 조회할 때
- 승인된 목업 Story를 실제 페이지로 변환할 때. 1단계와 2단계를 수행한 후 5단계로 이동하세요.
사용하지 말아야 할 경우: 일회성 컴포넌트 변경.
가치가 있는 이유
레지스트리의 역할은 좁습니다. 컴포넌트의 props에 대한 진실 공급원(source of truth)입니다 — 실제 prop 이름, 실제 enum 옵션, 필수 항목, slots 대 children, 함수 prop의 호출 시그니처 등. 호스트의 컴포넌트는 포크(fork)된 라이브러리와 다릅니다. variant enum 이름이 변경되었고, 크기 척도가 형제 컴포넌트 간에 다르며, icon prop은 element 대신 컴포넌트 참조를 받고, ReactNode prop은 children 대신 명명된 slot이며, 서로 다른 세 컴포넌트가 하나의 export 이름을 공유합니다. 이러한 것들은 React나 상위 라이브러리에 대한 친숙함에서 유추할 수 없으며, 레지스트리가 존재한다고 말하는 prop 대신 예상하는 prop을 작성하면 결함을 배송하게 됩니다. 이것이 1단계와 2단계의 inspect 호출이 필요한 이유이며, 그렇기 때문에 그럴듯해 보이는 목업이 결함을 배송하는 것입니다.
레지스트리는 화면의 뼈대, 구성 관용어, 또는 레이아웃을 제공하지 않습니다 — DataGrid를 구동하는 그리드 라이브러리 훅 호출, { stickyHeader: true }와 같은 호스트별 meta, 컴포넌트 주변에 필요한 wrapper 등. 이러한 정보는 호스트 자체의 Stories에서, 그리고 페이지/라우트 생성기가 있는 호스트의 경우 Example 템플릿(2단계)에서 제공됩니다. 호스트의 템플릿과 Story 적용 범위가 풍부할수록, 화면을 구축하는 데 실제로 필요한 것 중 레지스트리가 차지하는 비중은 줄어듭니다 — 그리고 이는 부족함이 아닙니다. 레지스트리와 호스트 자체 예제는 서로 다른 질문에 답하며, 각자가 답하는 질문에 대해 모두 중요합니다.
참고 자료
아래 단계에서 보내기 전에는 미리 열지 마십시오. 3a 경로(Story를 직접 작성)를 따르는 경우, 전혀 열지 않을 수도 있습니다. registry status와 component inspect의 출력과 이 파일의 본문만으로도 전체 화면을 구축하기에 충분히 설명적인 경우가 많습니다. 그러나 일단 필요해지면, 이 파일의 내용만 기억하지 말고 참고 자료를 사용하십시오 — 이 파일에는 세부 사항이 반복되지 않습니다.
| 파일 | 읽을 시기 |
|---|---|
references/registry.md | inspect 출력에 해석할 수 없는 것이 있을 때 — 불투명한 prop의 shape: / signature: 줄, 문서화되지 않은 prop, 잘못 보이는 import 지정자 |
references/cli.md | 명령어나 플래그가 위에서 설명되지 않았거나, CLI가 실행되지 않거나, MCP 등가물이 필요할 때 |
references/screen-json.md | Screen JSON 경로(3b)를 선택한 경우에만. 형식과 표현할 수 없는 것 |
references/errors.md | 명령어가 오류나 경고를 출력하는 즉시. 모든 코드와 수정 방법 |
references/implementation.md | 3단계의 메타 템플릿 및 5단계 전 |
1단계. 레지스트리 구축
Yosegi는 호스트에서 읽을 수 있는 tsconfig.json이 필요합니다(props는 TypeScript 타입에서 비롯되며, 이것만으로 충분합니다). Storybook은 Story가 저장되고 렌더링을 확인하는 곳이지만, 필수 사항은 아닙니다.
Storybook을 감지할 수 없는 경우 —
.storybook/(또는 이에 상응하는) 설정 디렉토리가 없거나, 호스트의package.json에storybook스크립트가 없거나,--index가 가리킬index.json이 없는 경우 — 결과물은 Story 대신 일반 React 컴포넌트 파일이 됩니다 (screen generate --target component,references/cli.md참조). 출력 위치나 검토 방법을 직접 선택하지 마십시오. 무엇이든 구축하기 전에 사용자에게 (a) 컴포넌트 파일이 어디에 있어야 하는지, (b) 결과를 어떻게 확인할지(예: 호스트 앱의 임시 라우트에서 렌더링) 물어보십시오. Yosegi는 검토 표면을 규정하지 않으며, 어느 하나를 추측하는 것은 prop을 추측하는 것과 같은 규칙을 위반합니다. 이러한 답변을 얻으면 아래 절차는 세 가지 차이점을 제외하고 동일하게 유지됩니다:registry build는--index/--storybook-url없이 실행됩니다(큐레이션을 잃지만 그 외에는 아무것도 잃지 않음); 3a 경로에서는 사용자가 지정한 위치에 컴포넌트 파일을 작성하고, 3b에서는--target component --out <해당 위치>.tsx를 전달합니다; 4단계의 Storybook 검사는 호스트의 타입 검사와 사용자가 지정한 확인 방법으로 대체됩니다.
- CLI를 실행할 수 있습니까?
npx yosegi(또는pnpm yosegi,yarn yosegi,bunx yosegi)를 인수 없이 실행하면 모든 명령어가 출력됩니다. 단,@yosegi/yosegi가 이미 호스트의 의존성에 있어야 합니다. 그렇지 않으면 먼저 설치하십시오(references/cli.md참조). Node.js 20 이상, React + TypeScript 호스트가 필요합니다. 명령어가 실패하면references/cli.md의 "CLI가 실행되지 않는 경우"를 참조하십시오. 가장 유용한 방법은 이전 세션에서 레지스트리가 이미 존재하는 경우<data-dir>/registry.json의builtWithCliPath를 읽는 것입니다. - 지금
--data-dir을 지정하고 모든 명령어에 동일한 값을 전달하십시오. 호스트 패키지 루트 아래의.yosegi를 사용하는 것이 기본값이며 권장됩니다. 아래 예제에서는 여전히 명시적으로 작성하지만, 기본값은 현재 작업 디렉토리를 따르고 다른 곳에서 실행된 명령어는 구축한 것을 찾지 못할 수 있습니다. - 이미 레지스트리가 있고, 최신 상태입니까? 먼저
yosegi registry status --data-dir .yosegi를 실행하십시오. 이 명령어는 기록된 입력에서 레지스트리 버전을 다시 계산하고source: current또는source: stale을 정확한 재구축 명령어와 함께 보고하므로,component list의 헤더를 눈으로 확인할 필요가 없습니다. "Registry not found"는 첫 번째 실행임을 의미합니다. Storybook-index 부분은 최선의 노력(best-effort)이며, index에 도달할 수 없다고 보고하면서 소스 판정은 그대로 유효할 수 있습니다. 이 부분을 "확인할 수 없음"으로 읽고, "stale" 또는 "current"로 읽지 마십시오. 도달할 수 없는 개발 서버가current소스 판정을 신뢰하는 것을 막지 마십시오.status가 stale을 보고할 때마다,REGISTRY_VERSION_MISMATCH가 출력될 때마다, 또는status가source: unknown을 보고할 때마다(레지스트리가 기록된 입력보다 오래된 경우,built: not recorded) 재구축하십시오 — 거기서는 다시 계산할 것이 없으므로, age가 유일한 신호입니다. 또한 명령어가 레지스트리가 현재 실행 중인 다른 Yosegi 버전으로 구축되었다고 경고할 때마다 재구축하십시오. 이전 Yosegi는 현재 Yosegi가 내보낼 수 있는 필드(예: 함수 prop의 호출 시그니처)를 내보낼 수 없으며, 다른 신호로는 이 차이를 보여주지 않습니다. 버전 문자열은 콘텐츠 해시이므로 동일하게 유지되므로, 변경되지 않은 호스트에서 재구축된 레지스트리는 동일한 버전을 유지합니다. 레지스트리는 스냅샷이며, 오래된 레지스트리는 없는 것보다 나쁩니다.
yosegi registry build \
--source "app/components/**/*.tsx" \
--tsconfig <host>/tsconfig.json \
--index http://localhost:6006/index.json \
--storybook-url http://localhost:6006 \
--report tmp/registry-report.json \
--data-dir .yosegi
위 6006는 Storybook 자체의 기본 포트이며, 첫 번째 빌드이고 다른 정보가 없기 때문에 사용된 것입니다. 반드시 호스트의 포트는 아닙니다. 실행하기 전에 호스트의 package.json Storybook 스크립트(또는 사용자에게)를 확인하여 실제 사용하는 포트를 알아내십시오. 첫 번째 빌드 이후의 모든 재구축은 추측보다 더 나은 소스를 가집니다: component list의 헤더는 레지스트리가 마지막으로 구축될 때 사용된 정확한 --storybook-url을 담은 rebuild: 줄을 출력합니다 (references/cli.md 참조).
플래그와 기본값은 references/cli.md에 있습니다. --index는 전제 조건이 있는 유일한 부분입니다: 개발 서버 URL은 호스트의 Storybook이 이미 실행 중이어야 함을 의미합니다. 이것이 없으면 Story에서 파생된 카테고리와 recommended 표시를 잃지만, 그 외에는 아무것도 잃지 않습니다.
출력되는 통계를 읽으십시오:
files: 0→ glob이 일치하는 항목을 찾지 못했습니다. 명령어는 여전히 성공하고 세 가지 합성 기본 요소만 보유한 레지스트리를 작성하므로, "Wrote 3 components"를 성공으로 읽지 마십시오.files가 양수인데componentCandidates: 0이거나,anyShapedProps가 높은데withNodeSlots: 0인 경우 → 빌드가 성공했지만 품질이 저하되었습니다. 첫 번째는 glob이 React 컴포넌트를 전혀 포함하지 않았음을 의미합니다. 두 번째는@types/react가 확인되지 않아 모든ReactNodeprop이json으로 평탄화되고 slot이 감지되지 않았음을 의미합니다. 두 경우 모두Warning:줄에서 수정 방법을 알려줍니다. 계속 진행하기 전에 해결하고 재구축하십시오.extractedComponents에 비해propsUnreadable이 높은 경우 → tsconfig가 잘못되었을 가능성이 높습니다. 지금 해결하십시오 (references/cli.md,registry metadata참조). 해당 상태의 컴포넌트는 나중에 완전히 올바른 props를 거부합니다.
2단계. 사용하려는 모든 컴포넌트 조회
페이지/라우트 생성기의 Example 템플릿이 구축 중인 화면과 가장 가까운 일치 항목이라면, 먼저 읽거나 아래 명령어와 함께 읽으십시오. 템플릿이 뼈대와 구성 관용어를 결정하고, 레지스트리는 템플릿이 열어둔 정확한 props를 확인합니다.
yosegi component list --category app/components/ui --data-dir .yosegi
yosegi component list --query card --data-dir .yosegi
yosegi component inspect "app/components/ui/button#Button" --data-dir .yosegi
레지스트리는 수백 개의 항목에 이를 수 있으므로 --category / --query로 범위를 좁히고, 요약에서 방향을 잡은 다음, 작성할 모든 컴포넌트를 inspect하십시오. inspect는 권위적이며, 당신의 프레임워크 지식은 그렇지 않습니다. references/registry.md를 읽어 출력을 해석하는 방법을 이해하십시오 — enum 옵션, 불투명한 prop 아래의 shape: 및 signature: 줄, 호스트가 실제로 작성하는 import 지정자, 문서화되지 않은 prop의 의미 등.
recommended로 표시된 컴포넌트를 선호하십시오. 해당 컴포넌트는 자체 Story를 가지고 있습니다.
그런 다음 호스트의 관례를 수집하십시오. Story는 호스트의 저장소에 저장되고 호스트의 코드로 검토됩니다. 이 단계를 건너뛰면 작동하는 UI가 생성되더라도 다시 돌려보내질 수 있습니다.
- 데이터 계약이 이미 존재하는 경우 찾으십시오 — OpenAPI/JSON Schema 정의, GraphQL 스키마, API 응답을 위한 수동 작성 TypeScript 타입 등 호스트의 데이터 계층이 사용하는 모든 형태. 모의 데이터를 발명하기 전에 읽으십시오. 이는 컴포넌트 props보다 더 많은 것을 결정합니다: 필수 필드 대 Nullable 필드, 특정 필드에서 null의 의미(예: null 제한은 "unknown"이 아닌 "unlimited"를 의미할 수 있음), 상호 배타적인 필드, 그리고 그만큼 유용하게 없는 것(계약에 정렬 또는 검색 필드가 없으면 화면도 이를 발명하지 않아야 함). 이것이 목업을 모양새 제안에서 실제 데이터 형태를 반영하는 것으로 바꾸는 것입니다. 위치는 호스트마다 다릅니다(
openapi/schemas/,.graphql파일, 생성된types.ts). 이 도메인에 존재하는 것을 찾아 그럴듯해 보이는 추측보다 따르십시오. - 호스트의 라우트/페이지 디렉토리(
app/routes/또는 페이지를 제공하는 위치)에서 동일한 도메인의 기존 화면을 검색하십시오. 성숙한 제품에서는 종종 존재하며, 이를 찾으면 작업이 완전히 재구성될 수 있습니다. 예를 들어, 기존bookings.calendar._index라우트가 "예약 화면 만들기"를 "기존 예약 흐름에 대한 교차 목록 제안"으로 바꿀 수 있습니다. 이는 요청받은 목업이 구축해야 할 올바른 것인지 결정하므로, 아래 체크포인트 전에 수행하고 거기서 제기할 질문을 형성하게 하십시오. - 무엇이든 구축하기 전에
git status를 실행하고 출력 디렉토리를 살펴보십시오. 동일한 화면에 대한 이전의 커밋되지 않은 시도가 이미 작업 트리에 있을 수 있습니다. 컨텍스트 재설정 후 재발행된 요청에서 흔히 발생합니다. 그 옆에 복제본을 만드는 대신 기존 항목과 조정하십시오. 이미 존재하는 파일을 다시 수행하려면 — 호스트 생성기가 대상 경로가 존재할 때 거부하거나 이전 시도를 교체해야 하는 경우 — 삭제 대신 이동(이름 변경)하십시오. 삭제는 가능하지 않을 수 있으며, 이름 변경은 어느 쪽이든 경로를 비웁니다. - 호스트에 새 페이지나 화면을 위한 생성기가 있는지 확인하십시오 — plop/hygen 생성기,
bun add-route스타일 스크립트, 종종 호스트의AGENTS.md또는package.json스크립트에 문서화되어 있습니다. 이러한 생성기가 있는 호스트에서 새 화면 파일을 처음부터 직접 작성하는 것은 잘못입니다. 생성기가 승인된 템플릿을 복제하고 파일 및 명명 규칙을 강제하므로, 직접 파일을 만드는 대신 실행하십시오. 이는 또한 3단계에서 인라인 트리 Story와 페이지 모듈 및 얇은 wrapper Story 사이의 선택을 결정합니다. 이러한 생성기가 있는 호스트는 거의 항상 후자를 원합니다. - 저장소 루트에서 출력 디렉토리까지 모든 수준에서
AGENTS.md/CLAUDE.md를 읽고, 이들이 가리키는 문서를 따르십시오. - 출력 위치 근처의 기존 Story를 하나 또는 두 개 읽으십시오. 여러 컴포넌트를 결합한 구성된 예제가 페이지 뼈대, 간격 및 컴포넌트 선택에 대해 모방할 가치가 있습니다. 구성 관용어의 경우 — 컴포넌트가 실제로 어떻게 조립되는지, 단지 어떤 props를 받는지가 아니라: DataGrid를 구동하는 그리드 라이브러리 훅 호출,
{ stickyHeader: true }와 같은 호스트별meta, 컴포넌트 주변에 필요한 wrapper — 기존 Story가 진실의 원천이며, 레지스트리는 그렇지 않습니다. 레지스트리
…
참고: 원본 내용이 잘려서 제공되었으므로, 위 내용까지만 번역했습니다. 전체 문서의 나머지 부분(3단계, 4단계, 5단계 등)도 동일한 방식으로 번역되어야 합니다.