Community코딩 & 개발github.com

oliverswitzer/lens

제품 렌즈를 설정하고 유지 관리합니다. 제품의 목적, 핵심 루프, 아바타, 인터뷰 대상, 증거, 주장, 집중 가설, 출시된 표면 및 아이디어, 대안 및 경쟁사, 시장 인사이트, 콘텐츠 기둥 및 결정을 하나의 git 추적 JSON 그래프로 관리하며, 독립형 주석 가능 index.html과 diff 보기를 제공합니다.

lens란 무엇인가요?

이 스킬은 AI 에이전트가 제품 중심의 구조화된 지식 그래프(렌즈)를 생성하고 지속적으로 업데이트할 수 있도록 설계되었습니다. 렌즈는 단일 JSON 파일(model.json)로 모든 제품 관련 정보(목적, 핵심 루프, 사용자 아바타, 인터뷰 증거, 가설, 경쟁사 분석 등)를 체계적으로 저장하며, 빌드 시 독립적인 HTML 파일(index.html)로 변환되어 팀원 누구나 브라우저에서 열고 주석을 달 수 있습니다. 이는 제품 관리, 사용자 리서치, 경쟁 분석 등에 활용되며, 특히 Claude Code, Cursor, Codex와 같은 AI 코딩 도구와 통합되어 코드베이스 변경 시 자동으로 렌즈를 업데이트하는 워크플로우를 지원합니다. 각 주장은 관찰됨(Heard/seen), 소유자 관점(Owner's view), 테스트되지 않음(Untested)의 세 가지 유형으로 분류되며, 증거와 출처가 명확히 연결되어 신뢰성을 보장합니다. 또한 내장된 diff 뷰를 통해 변경 사항을 시각적으로 추적할 수 있고, 모든 변경은 git으로 관리되어 협업과 감사 추적이 용이합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/oliverswitzer/product-lens/tree/main/skills/lens

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

렌즈

렌즈는 하나의 JSON 그래프 <lens>/model.json이며, 누구나 열고 주석을 달 수 있는 독립형 <lens>/index.html로 빌드됩니다. <lens>는 스캐폴딩된 폴더(기본값 docs/lens)입니다. <lens>/README.md는 노드 종류, 관계, 주장 형태 및 무결성 규칙을 문서화합니다. 빌드는 규칙을 위반하는 모델을 거부하므로, 빌드 성공이 첫 번째 검증입니다.

이 스킬 자체의 폴더에는 template/ (저장소로 복사될 내용), scripts/ (경쟁사 도우미), competitors.md가 포함되어 있습니다. 저장소에서는 .claude/skills/lens/에서 찾을 수 있고, 전역 설치 시 ~/.claude/skills/lens/에 있습니다. 아래에서 $SKILL은 해당 폴더를 의미합니다.

요구 사항: Node 20+ 및 git. package.json이나 종속성은 필요하지 않습니다.

새 렌즈 설정

  1. 폴더를 선택합니다. 사용자에게 렌즈가 위치할 폴더를 묻습니다. 기본값은 docs/lens입니다. 이미 model.json이 있는 경우 덮어쓰기를 거부합니다.

  2. 템플릿을 복사합니다 (빌드된 index.html 제외):

    mkdir -p docs/lens && cp -R "$SKILL/template/." docs/lens/ && rm -f docs/lens/index.html
    echo '[]' > docs/lens/ids.lock.json      # 스타터의 ID는 사용자 ID가 아니므로 빈 상태로 시작
    
  3. 사용자 인터뷰 후 스타터 모델을 대체합니다. model.json에는 모든 일반적인 종류를 보여주는 가상의 "Acme Notes" 예제가 포함되어 있습니다. 그 형태를 유지하고 내용을 대체합니다. 한 번에 한 주제씩 질문하고, 빈 질문 대신 구체적인 초안을 제시하여 수정하도록 합니다:

    • 제품명(title) 및 소유자 이름(소유자 사람 노드, p-owner ID, 선호하는 다른 ID가 없으면 그대로 사용, 모든 뷰 주장에서 title은 "<이름>의 관점"으로 표시됨);
    • 한 문장으로 된 목적(purpose, 소유자 출처를 인용하는 view 주장);
    • 2~5개의 순서가 있는 loop-step으로 구성된 핵심 루프;
    • 대상 사용자(avatar, 페르소나 맵 포함) 및 문제점(problem);
    • 이미 보유한 인터뷰 또는 기타 증거(source + person 노드, 인용구나 타임스탬프를 절대 임의로 만들지 말고, 대본이 없으면 소유자 보고서로 기록);
    • 출시된 것(surface, shipped: true, 실제 스크린샷 포함)과 아이디어에 불과한 것(shipped: false);
    • 사람들이 대신 사용하는 것(alternative);
    • 지금 증명할 최대 3개의 베팅(hypothesis 노드, focus: 1|2|3). 사용자가 증거 없이 말하는 모든 것은 view(그들의 관점) 또는 hypothesis입니다. 출처와 at 없이는 어떤 것도 observed가 될 수 없습니다. 공개될 수 있는 파일에 실제 이름을 원하지 않는 한 자리 표시자 이름("인터뷰 대상자 A")을 사용합니다.
  4. 예제를 정리합니다. 참조하는 노드가 없으면 assets/example.png를 삭제하고, 스크린샷을 assets/surfaces/<surface-id>/<slug>.png로 연결합니다. 표면 code 및 adrs 경로는 저장소 루트를 기준으로 하며 존재해야 합니다(adrs는 저장소가 의사 결정 기록을 보관하는 위치(예: docs/adr/)를 가리킴).

  5. 빌드 및 테스트:

    node docs/lens/build.mjs && node --test docs/lens/tests/*.test.mjs
    
  6. 렌즈를 확인합니다. 주석은 오리진(origin)별로 브라우저에 저장되므로, 파일을 직접 열지 말고 서빙하여 확인합니다:

    python3 -m http.server 8767 --bind 127.0.0.1    # 저장소 루트에서 실행
    open "http://127.0.0.1:8767/docs/lens/index.html"
    
  7. 경쟁사 광고를 추적할 경우 docs/lens/assets/ads/**/*.mp4에 대한 .gitignore 라인을 제안합니다. model.json, ids.lock.json, index.html, assets/ 및 나머지 폴더를 저장소의 커밋 규칙에 따라 커밋합니다.

작업 기반 마련

소유자에게 무엇이든 묻기 전에 관련 노드, 해당 주장 및 출처를 읽습니다. 구체적인 종합 분석을 제공하여 수정하도록 합니다. 표면의 경우, 동작이 중요할 때 해당 코드(code, adrs)를 확인합니다. 의사 결정 기록은 결정된 사항을 알려줄 뿐, 오늘날 코드가 실제로 하는 일은 알려주지 않습니다.

증거 추가

모든 진술은 kind, evidence 및 선택적 next가 있는 주장입니다:

  • observed (들음/봄): 누군가 말하거나 행동한 것. at(대본 타임스탬프 또는 문서 섹션)을 사용하여 출처를 인용합니다. 인용 또는 가깝게 요약하며, 애매한 표현("유용할 수 있음")을 격상시키지 않습니다.
  • view (소유자 관점): 소유자의 해석. 해당 people에 모델의 owner가 포함된 출처를 인용해야 합니다.
  • hypothesis (테스트되지 않음): 테스트되지 않은 모든 것. 에이전트 제안 및 구현 아이디어를 포함합니다.
  • 가설은 노드 종류 중 하나이기도 합니다: 각 증거 조각을 stance(supports 또는 contradicts) 및 at과 함께 기록합니다. 신뢰도를 설정하지 마십시오. focus 가설의 게이지는 다음 빌드에서 해당 증거를 기반으로 계산됩니다(지지하는 별개의 인터뷰 대상자 수; 누군가 반박하면 한 단계 낮춤; 소유자 관점은 절대 높이지 않음). 지지와 마찬가지로 쉽게 반박 증거도 기록합니다.
  • 모든 약한 주장에 next를 제공합니다: 통화에서 물어볼 수 있을 만큼 구체적인 질문. 다음 대화에 나타납니다.
  • 누가 말했는지 명확히 합니다: 소유자가 제기하고 누군가 동의한 아이디어는 그들의 필요가 아닙니다.
  • 새 인터뷰는 date, people, locator 및 짧은 takeaways가 있는 source이며, 이를 지지하는 주장으로 인용됩니다. 제품과 관련 없는 개인 정보는 남기지 않습니다. 저장소가 비공개이고 인터뷰 대상자가 동의한 경우에만 <lens>/sources/ 아래에 대본을 보관합니다.

표면 업데이트 (변경 후)

변경으로 인해 표면의 모양이나 기능이 변경되는 경우, 동일한 브랜치에서:

  1. 실행 중인 제품에서 변경된 상태를 <lens>/assets/surfaces/<surface-id>/<slug>.png로 캡처합니다(오래된 것은 대체하고 1~4개 유지).
  2. 표면의 screenshots 항목을 업데이트합니다: caption, capturedAt (오늘 날짜), origin: "app", version. 페이지는 표면의 code에 대한 마지막 커밋보다 오래된 스크린샷을 플래그 표시합니다.
  3. 동작이 변경된 경우 unique / situations를 업데이트하고, 파일이 이동된 경우 code / adrs를 업데이트합니다.

완전히 새로 출시된 표면은 shipped: true, 최소 하나의 스크린샷, 해결하는 문제에 대한 serves 엣지, 루프 단계에 대한 implements 엣지가 있는 새 surface 노드입니다.

아이디어 추가 (브레인스토밍에서)

논의되었지만 구축되지 않은 표면은 shipped: false인 surface로, 아이디어 아래에 시각적으로 구분되어 나타납니다. unique(hypothesis 주장으로), situations, heard(사람들이 말한 것과 증거), origin: "design"인 screenshots 목업을 제공합니다. 출시되면 shipped를 뒤집고 목업을 실제 캡처로 대체합니다.

콘텐츠 기둥 또는 아이디어 추가

마케팅 테마는 pillar입니다. 구체적인 게시물, 비디오 또는 이벤트는 pillar under의 content-idea이며 format이 있습니다. 기둥이나 아이디어를 speaks-to 아바타에 연결하고, 아이디어는 보여주는 표면을 features하며, 이미 유사한 접근 방식을 실행하는 경쟁사를 like합니다. 콘텐츠가 사람들에게 도달할 때까지 아이디어와 기둥은 테스트되지 않은 것으로 간주됩니다. 아이디어에 대한 가설의 증거로 발생한 일을 기록합니다.

시장 인사이트 추가

외부 리서치의 트렌드는 Market insights 탭의 insight입니다. 기사를 Market research 출처로 기록하고(선택적으로 sources/ 아래에 스냅샷), 사실을 관찰된 findings으로 명시하며, 아바타에 대한 의미를 뷰 또는 가설로 유지하고 출처의 한계에 대한 발견을 포함합니다. 영향을 미치는 모든 것에 bears-on으로 연결합니다.

경쟁사 추가 또는 업데이트

$SKILL/competitors.md를 따릅니다: 리서치(실제 브라우저 광고 확인, 장벽 회피 금지), scripts/add-product.py, 스테이징된 광고 캡처, scripts/apply-staged-ads.py(모든 항목 확인 후 한 번에 적용), scripts/smoke-ads.mjs, 그런 다음 .mp4 없이 커밋합니다. 렌즈의 목적과 집중 가설에 따른 제품과 비교하며, 마케팅 페이지와 비교하지 말고 해당 비교를 테스트되지 않음으로 레이블 지정합니다.

사용성 결과는 렌즈 콘텐츠가 아닙니다

상호 작용 문제(아무도 찾지 못하는 버튼, 누락된 포커스 상태)는 팀의 이슈 트래커에 속합니다. 거기에 기록하고, 제품적 의미가 있는 경우에만 렌즈에 기록합니다.

이름 변경 또는 제거

ids.lock.json은 마지막 빌드의 모든 주석 가능한 ID를 기록합니다. 사라지는 ID는 model.json의 renamed("old-id": "new-id" 또는 의도적으로 제거된 경우 null)에 매핑되어야 합니다. 그렇지 않으면 빌드가 실패합니다. 이것이 기존 주석을 계속 연결하는 방법입니다.

렌즈 자체 변경

components/ 아래의 모든 변경(뷰 표시, 라우팅, 유효성 검사, diff)은 <lens>/tests/에서 실패하는 테스트로 시작합니다(node:test; tests/fixture.mjs에 공유 픽스처, 가상 이름만 사용). 로직은 순수 모듈에 유지하고, components/app.js만이 DOM에 접근합니다. 그런 다음 테스트를 실행하고, 브라우저에서 동일한 시나리오를 확인합니다.

Diff 시각화

소유자가 변경 사항을 보거나, 검토하거나, 시각화하도록 요청할 때:

node docs/lens/diff.mjs [rev]          # 기본 HEAD; 변경 목록 출력
python3 -m http.server 8767 --bind 127.0.0.1
open "http://127.0.0.1:8767/docs/lens/index.html"

녹색 윤곽선은 추가된 항목이고 노란색은 변경된 항목입니다. 제거된 항목은 배너에 빨간색으로 나열됩니다. 각 추가 또는 변경된 행은 해당 항목으로 연결됩니다. 변경 사항은 ID로 매칭되므로 단일 주장이 전체 카드 없이 강조 표시됩니다. 커밋하기 전에 항상 이를 지우고 확인합니다:

node docs/lens/build.mjs
grep -c LENS-V2-DIFF docs/lens/index.html   # 반드시 0이어야 함

재빌드 및 확인

node docs/lens/build.mjs && node --test docs/lens/tests/*.test.mjs

그런 다음 브라우저에서 영향을 받은 뷰를 확인합니다. 주석은 브라우저 로컬(origin 기준)이므로 전환하기 전에 내보냅니다. 마지막으로 렌즈 링크, 변경 사항, 증거 및 모든 제한 사항을 제공합니다.

관련 스킬