Claude 플러그인 구축하기, 파트 2
요약
Anthropic 마켓플레이스에 Claude 플러그인을 게시하기 위한 실질적인 검토 프로세스와 기술적 요구사항을 다룹니다. 로컬 테스트 환경과 실제 마켓플레이스 환경의 차이점을 분석하고, 매니페스트 관리 및 의존성 해결 방법을 설명합니다.
핵심 포인트
- 마켓플레이스 제출을 위한 엄격한 매니페스트 스키마 준수 필요
- 매니페스트를 단일 진실 공급원(SSOT)으로 관리하여 검증 시간 단축
- 정확한 의존성 명시 및 PyPI를 통한 해결 가능성 확인 필수
- 엔트리 포인트의 명명 규칙(main 함수) 준수 및 인터페이스 격리
코드가 마침내 오류 없이 실행되었을 때, 진짜 작업이 시작되었습니다. 이 시리즈의 파트 1에서는 빈 저장소(repository)에서 작동하는 플러그인을 만드는 과정을 다루었습니다. 하지만 해당 플러그인을 Anthropic 마켓플레이스(marketplace)에 게시하는 것은 완전히 다른 문제였습니다. 이는 마치 프로토타입을 샌드박스(sandbox)에서 공공 갤러리로 옮기는 것과 매우 유사했습니다. 샌드박스는 빠르게 반복(iterate)할 수 있게 해주지만, 갤러리에는 체크리스트와 검토 프로세스, 그리고 대부분의 개발자가 첫 번째 빌드에 성공한 후에야 알게 되는 일련의 기대치들이 존재합니다. 이 시리즈의 두 번째 파트에서는 검토자들과의 수주간의 피드백 과정을 줄여준 실질적인 단계들과, 게시 과정 전반에 걸쳐 LoreConvo가 어떻게 저의 노트, 결정 사항, 그리고 의존성(dependencies)을 체계적으로 정리해 주었는지 다룹니다.
로컬 테스트에서 마켓플레이스 제출까지
플러그인의 첫 번째 버전은 소수의 단위 테스트(unit tests)와 로컬 Claude 세션에 의해 구동되는 단일 저장소 내에 존재했습니다. 그 환경은 관대합니다. 외부 제약 조건을 걱정할 필요 없이 동일한 세션을 다시 불러오고, 프롬프트(prompt)를 수정하고, 동일한 코드를 다시 실행할 수 있기 때문입니다. 하지만 Anthropic 마켓플레이스는 깨끗한 컨테이너(container)에서 플러그인을 실행하고, 매니페스트(manifest)를 검증하며, 선언된 모든 의존성(dependency)이 PyPI에서 해결될 수 있는지 확인합니다. 첫 번째 놀라움은 매니페스트 스키마(schema)의 엄격함이었습니다. 샌드박스에서는 선택 사항처럼 보였던 필드들인 required_python_version, runtime_dependencies 등이 반드시 존재해야 하며 정확해야 합니다. 단 하나의 의존성이라도 누락되면, 제 컴퓨터에서는 코드가 완벽하게 실행되었음에도 불구하고 자동 검증기(automated validator)가 업로드 전체를 거부했습니다.
그러한 함정을 피하기 위해, 저는 매니페스트(manifest)를 단일 진실 공급원(single source of truth)으로 취급하기 시작했습니다. 라이브러리를 추가할 때마다 즉시 매니페스트를 업데이트하고, 마켓플레이스(marketplace)가 사용하는 것과 동일한 검증 스크립트를 실행했습니다. 이 스크립트는 일치하지 않는 버전 지정자(version specifiers), 누락된 선택적 필드(optional fields)를 잡아내며, 의존성(dependency)이 나열되어 있지만 한 번도 임포트(import)되지 않은 경우 경고를 보냅니다. 제출 전 로컬에서 이 스크립트를 실행함으로써, 3시간이 걸리던 디버깅 세션이 5분짜리 무결성 검사(sanity check)로 바뀌었습니다.
또 다른 숨겨진 요구 사항은 플러그인 엔트리 포인트(entry point)의 명명 규칙입니다. 마켓플레이스는 entry_point에 의해 정의된 모듈 내에 main이라는 이름의 호출 가능한(callable) 함수가 있기를 기대합니다. 리팩터링(refactor) 중에 함수 이름을 변경하면 로그에 명확한 오류가 나타나지 않은 채 제출이 실패했습니다. 실제 구현체로부터 main을 다시 내보내는(re-exports) 작은 래퍼(wrapper)를 추가함으로써, 공개 인터페이스(public interface)를 내부 리팩터링으로부터 격리하고 리뷰 프로세스를 원활하게 유지할 수 있었습니다.
의존성 고정(Dependency Pinning) 및 재현성(Reproducibility)
리뷰가 지연되는 가장 흔한 이유 중 하나는 환경에 따라 서로 다른 빌드로 해결되는 의존성입니다. 제가 사용한 샌드박스(sandbox)에서는 데이터 처리 라이브러리의 최신 패치 버전을 사용했지만, 마켓플레이스 컨테이너는 작은 버그 수정 사항이 누락된 이전 버전의 휠(wheel) 파일을 가져왔습니다. 그 결과 플러그인이 승인된 후에야 나타나는 런타임 오류(runtime error)가 발생했고, 결국 두 번째 리뷰 과정을 거쳐야만 했습니다.
해결책은 모든 의존성을 대상 환경에서 테스트한 특정 버전으로 고정(pin)하는 것입니다. 원하는 정확한 버전을 설치한 후 pip freeze로 생성된 requirements.txt 파일이 매니페스트와 함께 커밋해야 할 올바른 아티팩트(artifact)입니다. 이를 runtime_dependencies에서 참조하면 마켓플레이스에 재현 가능한 환경을 제공하며, 어떤 버전이 각 릴리스(release)의 일부였는지에 대한 명확한 감사 추적(audit trail)을 확보할 수 있습니다. 라이브러리를 업그레이드해야 할 때는 한 번에 하나의 버전씩 올리고, 전체 테스트 스위트(test suite)를 실행한 뒤, 최소한의 변경 사항만 제출하세요. 리뷰어들은 이러한 점진적인 접근 방식을 선호하며, 관련 없는 코드를 망가뜨릴 위험도 크게 줄어듭니다.
PyPI 릴리스 사이클 탐색하기
매니페스트(manifest)와 의존성(dependencies)이 확정된 후에도, PyPI 릴리스 프로세스에는 고유의 실패 모드(failure modes)가 존재합니다. 마켓플레이스는 PyPI에서 패키지를 직접 가져오기 때문에, 배포 메타데이터(distribution metadata)에 공백이 있으면 검증 과정에서 파일 누락 오류가 발생합니다.
메타데이터의 기본 사항은 생각보다 훨씬 중요합니다. pyproject.toml에는 완전한 설명(description), 유효한 라이선스 식별자(license identifier), 그리고 플러그인의 목적과 일치하는 분류기(classifiers)가 포함되어야 합니다. 저의 첫 번째 시도에서는 분류기 하나가 누락되어 자동 스캐너가 해당 패키지를 미완성 상태로 표시했습니다. 두 번째 교훈은 기술적인 문제라기보다 프로세스에 관한 것이었습니다. 2단계 릴리스 접근 방식, 즉 프리릴리스(alpha)를 먼저 업로드하여 마켓플레이스가 이를 기준으로 검증하게 한 뒤, 리뷰를 통과하면 안정적인(stable) 릴리스를 게시하는 방식은 안전망 역할을 합니다. 만약 마켓플레이스가 프리릴리스에서 파일 누락을 보고하면, 다운스트림(downstream) 사용자들이 고정(pinned)했을 수도 있는 버전에는 영향을 주지 않고 교체할 수 있습니다. twine upload를 사용하여 업로드를 자동화하고 리포지토리에 휠(wheel)의 SHA-256 체크섬(checksum)을 저장해 두면, 리뷰어가 검증을 요청할 때 정확한 해시(hash)를 즉시 준비할 수 있습니다.
개발 메모리 최신 상태로 유지하기
이 모든 단계는 많은 컨텍스트(context)를 생성합니다. 의존성 버전에 대한 결정, 리뷰어 피드백에서 얻은 노트, 휠(wheel)을 빌드한 정확한 명령어 등이 그것입니다. 이러한 정보를 검색 가능하게 유지하고 적절한 프로젝트와 연결해 두는 것이, 매끄러운 두 번째 릴리스와 고통스러운 릴리스를 가르는 차이점입니다.
LoreConvo는 이러한 워크플로에 자연스럽게 녹아들었습니다. 디버깅 세션이나 리뷰 반복(iteration)을 마칠 때마다, 자동 저장 훅(auto-save hook)이 간결한 요약, 결정된 사항, 그리고 추론 가능한 기술 스택(tech-stack) 정보들을 포착했습니다. 데이터는 로컬 SQLite 파일에 저장되었으며, 클라우드 계정이나 동기화 서비스는 필요하지 않았습니다. 메모리가 여러 환경에 걸쳐 존재하기(the memory is cross-surface) 때문에, Claude Code에서 세션을 시작한 후 나중에 새로운 Claude 채팅 세션에서 동일한 컨텍스트를 다시 확인할 수 있었습니다. 자동 로드 훅(auto-load hook)이 가장 관련성 높은 이전 컨텍스트를 자동으로 불러왔기에, PyPI 업로드 스크립트를 실행하기 위해 새 터미널을 열었을 때 git 히스토리를 뒤져볼 필요 없이 마지막으로 검증된 정확한 매니페스트(manifest) 버전을 바로 확인할 수 있었습니다.
프로젝트 태깅(Project tagging) 기능을 통해 플러그인 작업과 다른 실험들을 분리하여 관리할 수 있었습니다. 모든 세션에 플러그인의 프로젝트 이름을 태깅함으로써, 세션 조사 범위를 관련 히스토리로만 필터링할 수 있었습니다. 세션 연결(Session linking) 기능은 관련 세션들을 자동으로 연결해주어, 초기 프로토타입부터 최종 마켓플레이스 제출까지의 과정이 하나의 탐색 가능한 서사(narrative)로 나타났습니다. 팀원과 특정 결정 사항을 공유해야 할 때, 팀 메모리(Team memory) 기능(Pro 티어)을 사용하면 선택한 세션을 JSON으로 내보내고 파일을 보낼 수 있었습니다. 팀원은 서버 없이 단 하나의 명령어로 해당 파일을 가져올 수 있었습니다.
Pro 티어의 관련 세션 탐색(related session discovery) 기능은 리뷰 과정에서 특히 유용했습니다. 피드백 단계가 끝날 때마다 시스템은 유사한 컨텍스트를 공유하는 이전 세션들을 제시해주었는데, 덕분에 제가 잊고 있었던 3주 전의 의존성 고정(dependency pinning)에 관한 논의를 불러올 수 있었습니다. "이 라이브러리 버전에 대해 우리가 무엇을 결정했었지?"라고 물었을 때, 추측이 아닌 실제 세션을 즉시 불러올 수 있다는 점은 리뷰 피드백 루프(review feedback loop)를 상당히 단축해 주었습니다.
퍼블리싱 여정에서 얻은 교훈
퍼블리싱 여정은 Claude 플러그인을 구축할 때 가장 어려운 부분이 코드 그 자체가 아니라, 매니페스트 (manifests), 의존성 (dependencies), 그리고 문서화 (documentation)로 이루어진 주변 생태계라는 점을 명확히 해주었습니다. 매니페스트를 권위 있는 소스 (authoritative source)로 취급하고 업로드할 때마다 로컬에서 이를 검증하면, 리뷰 과정에서 발생하는 대부분의 당혹스러운 상황을 제거할 수 있습니다. 모든 의존성을 고정 (pinning)하고 2단계 PyPI 릴리스를 사용하는 것은, 한 달에 한 번 겪던 골칫거리를 반복 가능하고 스트레스가 적은 절차로 바꾸어 놓았습니다.
그리고 결정 사항을 자동으로 캡처하고, 화면 전환 시에도 유지되며, 전적으로 사용자의 통제하에 있는 로컬 세션 메모리 (local session memory)를 계속 유지한다는 것은, 터미널을 닫는 순간 빌드에 관한 조직적 지식 (institutional knowledge)이 증발하지 않음을 의미합니다.
자신의 AI 프로젝트를 위해 메모리 우선 워크플로우 (memory-first workflow)를 시도해 볼 준비가 되셨나요? /tools에서 전체 도구 세트를 살펴보거나 /contact를 통해 컨설팅을 요청하세요.
이 글이 유용했다면, Building a Claude Plugin, Part 1과 The Real Cost of AI Session Context Loss도 읽어보시기 바랍니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기