본문으로 건너뛰기

표준을 문서가 아니라 코드로 배포하기 — bumpist-code 개발기

2026년 7월 6일
0 views
Frontend
npm CLI
Claude Code
Developer Tools
FSD
Web Accessibility

개발 계기 — "규칙은 왜 항상 안 지켜질까"에서 출발

처음부터 npm 패키지를 만들려던 건 아니었다. 시작은 회사 프로젝트의 claude/skills 정리였다. 팀이 AI 코딩 도구를 쓰기 시작하면서, 프로젝트마다 폴더 구조·컴포넌트 작성법·테스트·커밋 컨벤션이 제각각이 되는 걸 봤다. 더 근본적인 문제는 **"규칙 문서는 아무도 안 읽는다"**는 것이었다. 위키에 잘 정리해둬도, 급하면 다들 감으로 짜고, AI에게도 매번 같은 맥락을 처음부터 다시 설명했다.

여기서 두 가지 자산이 이어졌다. 나는 이미 claude-distill(세션 지식 자동 축적)과 Claude Skills Panel(스킬 관리 확장)을 만들면서 "AI 코딩 도구의 실사용 불편을 도구로 푼다"는 흐름을 타고 있었다. 그 연장선에서 든 생각이 **"내 프론트엔드 표준을 아예 '실행되는 형태'로 배포하면, 규칙이 문서가 아니라 작업 절차가 되지 않을까"**였다.

그래서 목표를 이렇게 잡았다.

  • 규칙을 읽어야 하는 문서가 아니라, Claude가 작업 전에 자동으로 읽고 실행하는 스킬로.
  • 프로젝트마다 다시 세팅하지 말고, 명령 한 줄로 어디에나 배선되게.
  • 회사용은 회사 허브(frontend-ai-common-prompt)로, 개인용은 내 브랜드(bumpist-code)로 분리해 공개.

그리고 "Bump the rules. Ship consistent frontends" — 규칙은 한 번 쓰고 끝내는 게 아니라 실전에서 깨질 때마다 고쳐 버전을 올리는 살아 있는 표준이라는 원칙을 브랜드 문장으로 박았다.

설계 트레이드오프 — 가장 오래 고민한 것들

① 배포 방식: submodule → copy → npm CLI (세 번 갈아탐)

이게 제일 깊게 고민한 축이다. 세 후보를 순서대로 검토했다.

  • git submodule: 단일 출처 + 커밋 SHA 고정이라 처음엔 끌렸다. 하지만 소비 프로젝트에서 규칙은 .claude/실제 파일로 있어야 Claude가 읽는데, submodule은 .fe-guide/claude/...로 한 단계 중첩되고 .claude/skills를 심볼릭 링크로 걸어야 했다. --recurse 안 하면 빈 폴더, Windows에선 심볼릭 링크가 깨짐 — 함정이 너무 많았다.
  • copy(복사): 허브를 잠깐 받아 필요한 문서만 프로젝트로 복사. 도구가 읽는 위치에 평범한 실제 파일로 놓이니 submodule의 중첩·링크 문제가 통째로 사라졌다. 대신 "자동 최신화 안 됨(드리프트)"이 약점인데, 공개 배포에선 오히려 남의 repo에 실시간 종속되는 게 더 싫다는 걸 깨달았다 — 스냅샷으로 받아 내 것으로 쓰는 게 맞다.
  • npm CLI(npx): 최종 선택. copy의 철학을 유지하되 npx bumpist-code init 한 줄로 실행. shadcn/ui가 증명한 "CLI가 파일을 프로젝트에 복사하는" 모델이다. 여기에 npm의 발견성(다운로드 수·검색)·semver·npx 무설치 실행이 얹힌다.

핵심 교훈: **"파일이 도구가 읽는 위치에 실제로 있어야 한다"**는 제약이 모든 선택을 갈랐다. 그 제약을 가장 깨끗하게 만족하는 게 copy였고, 거기에 배포 채널로 npm을 씌운 게 정답이었다.

② 프레임워크 감지 — 인자 강제 vs 자동 감지

init vue처럼 인자를 강제할 수도 있었지만, 진입 마찰을 0으로 만들고 싶어 package.json에서 자동 감지를 넣었다. 함정은 Next.js 프로젝트엔 react도 함께 깔려 있다는 것 — 그래서 감지 우선순위를 next → vue → react로 뒀다. Next를 먼저 확인하지 않으면 Next 프로젝트가 React로 오인된다.

③ 스킬 범위 — 14개, 그리고 하나를 일부러 뺀 이유

스킬을 무한정 늘리면 오히려 안 쓰인다. 작업 유형(계획·생성·검증·마무리)을 기준으로 14개로 추렸다. 그리고 복사할 때 setup-fe-project만 제외했다. 이건 "빈 프로젝트를 부트스트랩하는" 1회성 스킬이라, 이미 세팅된 프로젝트의 .claude/에 남아 있을 이유가 없다. "프로젝트에 상주할 스킬"과 "허브에서 한 번 실행할 스킬"을 구분한 결정이다.

④ Next 트랙 — 별도 패키지 vs 통합

Next를 지원할 때 "SSR 전용 별도 패키지를 팔까?"를 진지하게 고민했다. 결론은 통합. 규칙 13개 중 8개(core·guardrails·testing·git·security·ci 등)가 프레임워크 무관 공통인데, 별도 패키지로 쪼개면 이 공통 규칙을 두 곳에서 관리하게 되고 — 그게 바로 이 도구가 없애려던 드리프트를 스스로 만드는 셈이다. CLI가 선택 프레임워크 규칙만 복사하므로, 한 패키지가 3트랙을 다 담아도 사용자 프로젝트엔 필요한 것만 들어간다.

⑤ 디자인 — 미감 강제 vs 중립 기본선

"어떤 디자인을 지향하냐"에 답을 주고 싶었지만, 특정 미감(볼드/에디토리얼 등)을 강제하면 채택자의 브랜드와 싸운다. 그래서 **뉴트럴·플랫·브랜드 컬러 1개·접근성(WCAG AA)**를 기본선으로 잡되, **"디자인 토큰이 오면 그게 최종 권위"**로 위임했다. 심화 디자인 craft는 직접 구현하지 않고 impeccable(디자인 특화 스킬)과 페어링 — 경쟁이 아니라 보완으로 경계를 그었다. (impeccable 자동 설치는 훅까지 남의 하네스에 심는 월권이라 권고 한 줄로만 뒀다.)

트러블슈팅 — 막혔다 푼 것들

① npm 배포 인증 지옥 (E403 → E404 → E401 → E403 → 해결)

첫 배포에서 연달아 다른 에러를 만났다. 이게 가장 오래 걸렸다.

  • E403 — "2FA 또는 bypass 2fa 토큰 필요". npm은 공개 배포에 2단계 인증을 강제한다.
  • E404--otp=64049435로 넘겼는데 404. 원인은 OTP를 8자리로 입력한 것(npm OTP는 6자리). npm이 인증 실패를 헷갈리게 404로 돌려줬다.
  • E401 — 토큰을 직접 npm config set 했는데 값이 깨져 무효. npm config set은 실패해도 에러가 없어서, npm token list로 오늘 날짜 토큰이 실제로 생겼는지 확인해야 한다는 걸 배웠다.
  • 다시 E403 — 새 토큰을 만들었지만 Classic "Publish" 타입이라 여전히 2FA를 요구. 에러 메시지의 "bypass 2fa enabled"가 곧 토큰 종류 진단이었다.
  • 해결 — Granular 토큰에 "Bypass two-factor authentication" 체크 + Read/Write + All packages로 발급하니 OTP 없이 배포됐다.

그리고 아찔한 순간: 중간에 **엉뚱한 폴더(회사 repo)에서 npm publish**를 실행했다. 다행히 회사 프로젝트 package.json의 **"private": true**가 EPRIVATE로 막아줬다 — 회사 소스가 공개 npm에 노출될 뻔한 걸 안전장치가 잡은 것. private: true는 절대 지우면 안 되는 방어선임을 체감했다.

② Node 24 · Windows에서 CLI가 설치 중 크래시

CLI가 규칙·스킬을 복사할 때 fs.cpSync(..., { recursive: true })를 썼는데, Node 24 일부 빌드가 Windows에서 재귀 fs 작업 중 네이티브 크래시(STATUS_STACK_BUFFER_OVERRUN, exit 3221226505)를 일으켰다. macOS에선 멀쩡해 재현이 까다로웠다. readdir + copyFileSync/unlink/rmdir로 재귀를 직접 구현해 회피했다 — 버전·OS 무관하게 안전하다. **"편한 표준 API가 특정 런타임에서 배신할 수 있다"**는 사례.

③ Next FSD ↔ App Router 폴더 이름 충돌

FSD의 app·pages 레이어가 Next App Router의 예약 디렉토리와 정면 충돌했다. 특히 src/pages/가 존재하면 Next가 그 안을 Pages Router 라우트로 취급해 빌드가 알 수 없는 타입 에러로 깨진다(FSD의 index.ts barrel은 페이지 컴포넌트가 아니므로). 실전(re-pin MVP)에서 검증하며 규칙을 확정했다: Next 트랙에선 FSD 화면 레이어를 pageViews로 개명하고, 라우팅 디렉토리는 하나(app/ 또는 src/app/)로 단일화. Vue·React 트랙은 충돌이 없어 pages 그대로 둔다 — 이 개명은 Next 전용임을 명시했다.

④ init 멱등성 — 이미 세팅된 프로젝트에 재실행

init은 갱신을 위해 여러 번 실행된다. 그래서 스킬 폴더는 복사 전에 기존 것을 지우고(재귀 삭제도 위 Windows 이슈 때문에 수동 구현), **CLAUDE.md는 없으면 @import 블록과 함께 생성, 있으면 "추가할 줄만 출력"**하도록 분기했다 — 남의 CLAUDE.md를 함부로 덮어쓰지 않기 위해. 배포 버전도 npm == git 태그 == 실제 내용이 항상 일치하도록, 배포 후 태그를 현재 커밋으로 맞추는 규율을 세웠다(중간에 npm이 git보다 2버전 뒤처졌던 걸 발견하고 정리).

지표

  • npm 정식 배포 — 최신 v0.5.1
  • 주간 973 다운로드
  • 언팩 크기 223KB · 109 파일 — Vue·React·Next.js 3개 프레임워크 대응 표준 번들
  • Claude Code 스킬 14종 포함

위 수치는 글 작성 시점(2026-07 기준)이며, update:stats 로 자동 갱신됩니다.

회고 & 다음 계획

얻은 인사이트

  • "표준을 코드로 배포하니 문서보다 잘 지켜진다." 규칙을 읽으라고 두면 안 읽지만, Claude가 작업 전에 자동으로 읽고 실행하면 그냥 지켜진다. 이게 이 프로젝트의 핵심 가치였다.
  • 배포 방식은 "무엇을 배포하느냐"가 결정한다. 라이브러리(코드)면 npm 의존성이 맞지만, 이건 "도구가 읽는 위치에 있어야 하는 파일"이라 copy가 자연스러웠다. 형태를 먼저 보고 채널을 골라야 한다.
  • 경쟁보다 경계. impeccable 같은 강력한 디자인 스킬을 흉내 내기보다, 내 스코프(엔지니어링 전반)를 지키고 디자인 심화는 넘기는 편이 정직하고 강했다.
  • 살아 있는 표준. re-pin(실서비스 MVP) 부트스트랩에서 Next 트랙이 실제로 깨졌고, 그걸 규칙으로 환류해 다음 버전을 냈다. 실전에서 깨진 것이 표준이 되는 루프가 실제로 돌았다.

다음 계획

  • 프레임워크 확장 — Svelte/Solid 같은 트랙을 공통 규칙 재사용 + 델타 방식으로.
  • 경량 디자인 detector — impeccable처럼 규칙 위반(대비·안티패턴)을 CI에서 결정론적으로 잡는 얇은 층.
  • 버전·기여 인프라 — CHANGELOG·릴리스 노트 자동화, 실전 사례(showcase)를 계속 축적해 "왜 이 규칙이 있는지"의 근거로 연결.
  • 커뮤니티 — launch kit으로 공개하고, 남이 실전에서 깨뜨린 규칙을 다음 버전으로 흡수하는 피드백 루프 확장.