Origin Story

00발단 · 스킬 하나가 던진 질문 실사례

impeccable이라는 디자인 스킬을 평가하다가, 좋은 스킬을 "어디까지 켜둘 것인가"라는 더 오래된 문제에 도착했다. 이 글은 그 문제의 커뮤니티 표준 답안 세 갈래와, keystone이 그중 어디에 서 있는지의 기록이다.

대상 Claude Code 멀티머신 설정 관리 · 계기 pbakaus/impeccable 평가(skill-judge A등급) · 실측 2026-08-04 이 Mac + keystone-hub PR #454
보유 머신
3대
Win 1 · Mac 2 (프로파일 4개)
등록 플러그인
27개
이 Mac enabledPlugins 실측
이번 변경
3줄
PR #454 → squash 병합
버전 드리프트
2.5개월
설치 3.1.1 vs 최신 4.0.4

사건의 순서

1. pbakaus/impeccable(⭐54.9k, Apache-2.0)을 skill-judge 8차원으로 평가: 약 110/120, A등급. craft-floor의 금지 목록과 critique의 격리 서브에이전트 프로토콜은 keystone의 적대 검증 철학과 거의 동형이었다.

2. 문제는 품질이 아니라 라우팅이었다. description이 UI 어휘 전체를 흡수하도록 쓰여 있어, 이미 있는 frontend-design · omd 스위트 · design-loop과 자동 발동이 상시 충돌한다. 스킬이 좋다는 것과 카탈로그가 좋아진다는 것은 다른 명제다.

3. "활성/비활성으로 관리하면 되지 않나"라는 질문에서 스코프 구조를 파봤더니, user 스코프는 머신-로컬이었다. 머신이 세 대면 세 번 꺼야 하고, 더 나쁘게는, 이 환경에서는 CLI로 꺼봤자 다음 keystone apply가 레이어 시드로 되돌린다. runtime-preserve가 보존하는 키는 model 하나뿐이라는 것을 apply.sh 소스에서 확인했다.

4. 그래서 정석 경로로 갔다: 레이어 소스 수정(3줄) → PR #454 → 병합 → apply → 런타임 실측(impeccable=false, 텔레메트리 opt-out env 반영, model 키 보존) → 플러그인 3.1.1→4.0.4 업데이트. 이 한 바퀴가 곧 이 글의 주제다.

이 글이 답하는 질문

"다른 사용자들도 머신이 여러 대일 때 이렇게(git 소스 → 머신별 apply) 하나? 아니면 프로젝트 스코프로만 버티나?" 답은 "둘 다 존재하고, 층이 나뉜다"이다. §02가 그 3층이고, §03이 keystone의 좌표, §04가 그 표준 도구인 chezmoi의 해부다.

Mechanics

01스코프 해부 · 공식 레버 세 개

Claude Code가 공식으로 제공하는 활성/비활성 수단은 세 개다. 전부 이 세션에서 CLI help·공식 문서·로컬 설정 파일로 직접 확인했다.

레버동작전파 범위
disable-model-invocation: trueSKILL.md frontmatter 자동 라우팅에서 완전 제외. description이 컨텍스트에 아예 실리지 않아 상시 토큰도 절약되고, /skill-name 명시 호출은 그대로 동작한다. "좋은데 시끄러운 스킬"의 정답. 스킬 파일이 가는 곳 어디든단, 플러그인 스킬은 캐시 사본이라 직접 수정 시 업데이트에 덮인다
enabledPlugins + claude plugin enable|disable -s user|project|local 플러그인 통째 on/off. -s project는 repo의 settings.json에 기록되므로 git으로 전파: 머신 문제가 애초에 없다. user = 머신-로컬
project = repo 따라 전머신
카탈로그 아카이브keystone 자체 레인 (#401) 안 쓰는 스킬을 아카이브 디렉토리로 이동해 카탈로그에서 제거. 238→180개 실적. 명시 호출도 사라지는 완전 제거라는 점이 위 두 레버와 다르다. keystone apply가 가는 곳
함정 · 이 환경에서 CLI 토글은 지속되지 않는다

keystone은 enabledPlugins를 레이어 소스(layers/10-os-macos/settings.json)에서 시드로 관리한다. 로컬에서 claude plugin disable을 실행해도 다음 apply가 시드 값으로 되돌린다. apply.sh의 runtime-preserve 목록에 있는 키는 model 하나뿐(apply.sh:559)이라는 것을 소스에서 확인했다. "런타임에서 조작한 설정 키는 apply 때 증발한다"는 알려진 사고 계열의 정확한 재현 조건이다.

따라서 이 환경의 유일한 지속 경로는 소스 수정 → PR → apply다. 우회처럼 보이는 CLI 한 줄이 실제로는 다음 apply까지만 사는 일회용이다.

이번에 실제로 흘린 경로

# 1. 레이어 소스 수정 (worktree, 3줄 diff)
"impeccable@impeccable": true → false
env["IMPECCABLE_NO_TELEMETRY"] = "1"   # concept-seed 선택 핑 opt-out

# 2. PR #454 → squash 병합 → 이 Mac apply
./apply.sh --profile personal-macos    # → 런타임 실측: false / "1" / model 보존

# 3. 플러그인 갱신 (설치 캐시는 머신별)
claude plugin update impeccable@impeccable   # 3.1.1 → 4.0.4

# 4. 디자인 작업 repo에서만 켜기 (git으로 전파되므로 머신 무관
.claude/settings.json → { "enabledPlugins": { "impeccable@impeccable": true } }

4번은 대상 프로젝트를 정하는 순간 커밋 한 번으로 끝난다. 맥 두 대는 각자 다음 apply/sync에서 1~3이 자동 정합되고, Windows 레이어에는 impeccable 항목이 원래 없어 적용 대상이 아니다.

Field Survey

02커뮤니티 실태 · 3층 구조 2026-08 검색 실측

"멀티머신에서 ~/.claude를 어떻게 관리하나"를 2026년 8월 기준으로 조사하면 답이 세 층으로 갈린다. 검색에 잡히는 가이드가 전부 2층에 몰려 있다는 사실 자체가 신호다. user 스코프를 동기화하려는 수요는 실재하고, 패턴은 이미 표준화됐다.

1층 · 라이트 다수

동기화 안 함,
프로젝트 스코프로 회피

팀/repo 공유 설정은 .claude/settings.json을 git에 커밋하는 게 공식 경로다. "repo가 따라다니니 머신은 상관없다"로 끝내고, user 스코프 드리프트는 그냥 수용한다.

  • 도구 0개, 학습 비용 0
  • 개인 설정(플러그인·모델·훅)은 머신마다 어긋난 채 방치
  • 머신이 늘수록 "이 맥에선 왜 안 되지"가 누적
공식 문서의 암묵적 기본값
2층 · 파워유저 표준

~/.claude를
dotfiles로 정본화

user 스코프를 "동기화되는 git 정본"으로 만든다. 변형이 넷: chezmoi(머신별 템플릿+암호화), plain git+셸 래퍼(열 때 pull, 닫을 때 push), NAS symlink(동기화 데몬 없이 즉시 공유), 전용 CLI(age 암호화 동기화 도구).

  • 검색 상위 가이드 8건이 전부 이 계열
  • 공통 교훈: ~/.claude 대부분은 머신 고유물(세션 로그·캐시·텔레메트리)이라 전체 동기화가 아니라 선별 동기화가 정답
  • 시크릿은 age 선별 암호화로 분리
keystone이 속한 층 · §03
3층 · 기업

managed settings를
MDM으로 배포

조직이 managed-settings.json을 MDM/배포 도구로 전 머신에 강제한다. 개인 취향이 아니라 fleet 정책(권한·모델·보안 게이트)이 목적이고, 사용자 설정보다 우선순위가 높다.

  • 개인 멀티머신 문제와는 목적이 다름
  • 단, "소스 하나 → 머신 N대 강제 배포"라는 뼈대는 2층·keystone과 동형
엔터프라이즈 전용 레인

2층 변형 비교 · 무엇이 갈리나

변형머신별 분기시크릿동기화 트리거실패 모드
chezmoihostname 템플릿 내장age 선별 암호화 내장autoPush + SessionStart 훅 pull템플릿 학습 곡선
plain git없음 · .gitignore 제외만.gitignore 의존 수동셸 래퍼 (열 때 pull / 닫을 때 push)공개 repo에 시크릿 유출 사고
NAS symlink없음 · 전 머신 동일 강제로컬 유지 (링크 제외)없음 · 즉시 공유NAS 죽으면 전 머신 마비, 충돌 해소 없음
전용 CLI제한적age 내장 내장수동 sync 명령도구 자체가 단일 메인테이너
질문에 대한 직답

"유저 스코프를 프로젝트 스코프로만 대체"가 표준인 것은 아니다. 팀에 강제하면 안 되는 개인 설정: 플러그인 on/off, 모델, 훅, 키바인딩은 repo에 커밋할 수 없어서 user 스코프에 남는다. 멀티머신 사용자는 그걸 dotfiles 계열로 동기화하는 것이 관행이고, keystone은 그 관행의 자체 구현이다.

Position

03keystone의 위치 · 패턴은 주류, 무게는 예외

keystone은 2층에 속한다. chezmoi가 개념으로 제공하는 것을 자체 스크립트로 구현한 형태라 개념 대응이 거의 1:1로 성립하고, 표준에서 벗어난 것은 방식이 아니라 짊어진 무게다.

chezmoi 개념keystone 대응물비고
source state (git repo)keystone-hub/layers/둘 다 "git 소스가 정본, 홈 디렉토리는 산출물"
hostname/OS 템플릿 분기레이어 × 프로파일 4종00-universal + 10-os-{mac,win} + 20-company-{personal,bs}keystone 쪽이 한 축 더 많다. OS만이 아니라 소속(개인/회사)까지 분기
chezmoi apply./apply.sh --profile <name>선언 상태를 머신에 투영
chezmoi doctor / diffkeystone-doctor.py + manifest 드리프트 검출keystone은 diverged 파일을 fail-closed로 보존하는 쪽이 더 보수적
run_once_ 스크립트OS 레이어 post-apply hook예: 플러그인 경로 OS-native 변환커뮤니티가 나중에 도달한 교훈(경로 변환·머신 고유물 제외)을 keystone은 사고를 겪고 규칙으로 선반영
age 선별 암호화settings.local.json 수동 분리 공백keystone에 없는 유일한 chezmoi 부품 · §04 채굴 후보

동형이 아닌 지점 · keystone이 더 무겁게 지는 것

adapter export. chezmoi는 파일을 배포할 뿐이지만, keystone은 같은 소스에서 프로젝트별 CLAUDE.md · AGENTS.md · .cursor/rules까지 생성한다. 멀티 CLI(Claude/Codex/Cursor) 요구는 chezmoi의 설계 범위 밖이다.

runtime-preserve의 역방향 문제. chezmoi는 "소스가 항상 이긴다"로 단순하게 끝나지만, keystone은 라이브 세션이 런타임 설정을 계속 고쳐 쓰는 환경이라 "어떤 키는 런타임이 이겨야 한다"는 예외(현재 model 1개)를 관리해야 한다. 이 비대칭이 이번 impeccable 건에서 확인한 함정의 뿌리다. 예외 목록에 없는 키는 전부 apply가 이긴다.

반론 먼저 · keystone은 과공학 아닌가

단일 사용자 기준으로는 맞는 지적이다. chezmoi 설정 수십 줄이면 될 일을 apply.sh + doctor + adapter export로 하고 있고, 그 유지비는 실제로 발생해 왔다(apply가 런타임 키를 증발시킨 사고, diverged 처리 사고 등). 이 비용이 정당화되는 근거는 두 가지뿐이다: ① 개인/회사 × OS 4프로파일 분리는 chezmoi 템플릿으로도 어차피 직접 짜야 하는 로직이고, ② 멀티 CLI adapter export는 대체재가 없다. 이 두 요구가 사라지면 keystone의 설정 배포 부분은 chezmoi로 대체하는 게 맞다.

Tool Anatomy

04chezmoi · 이점과 사용법

2층의 사실상 표준 도구. 한 문장으로: "홈 디렉토리의 원하는 상태를 git repo에 선언해 두면, 어느 머신에서든 chezmoi apply 한 번으로 그 상태가 된다"는 선언형 dotfiles 관리자다. Go 단일 바이너리라 설치 의존성이 없다.

이점 다섯 · 왜 plain git이 아니라 chezmoi인가

이점내용
1. 머신별 템플릿같은 파일을 머신마다 다르게 렌더링한다. settings.json을 템플릿으로 만들면 "회사 맥에서만 이 플러그인 on" 같은 분기가 파일 하나 안에서 선언된다. plain git은 이게 불가능해서 머신별 브랜치나 수동 편집으로 새는 지점.
2. age 선별 암호화시크릿이 든 파일만 골라 암호화해 커밋한다. repo는 공개해도 되고, 새 머신에서는 개인키만 옮기면 apply가 자동 복호화한다. "공개 dotfiles + 비밀 파일 몇 개" 구조의 정석.
3. 선언형 + 안전한 적용chezmoi diff로 적용 전 차이를 보고, apply는 소스 상태로 수렴시킨다. "지금 이 머신이 선언과 얼마나 다른가"가 항상 한 명령이다.
4. 스크립트 훅run_once_·run_onchange_ 스크립트로 "적용 후 한 번 실행"(도구 설치, 경로 수리)을 선언에 포함시킨다.
5. 자동 동기화 루프autoPush(커밋 즉시 push) + 세션 시작 훅에서 pull. Claude Code 커뮤니티 gist들이 쓰는 패턴. 머신 간 전파가 "다음에 그 머신을 열 때" 자동으로 끝난다.

어떻게 쓰나 · Claude Code 기준 최소 루프

# 첫 머신 · 정본 만들기
brew install chezmoi
chezmoi init                                  # ~/.local/share/chezmoi 가 source repo가 됨
chezmoi add ~/.claude/settings.json           # 관리 대상 등록
chezmoi add ~/.claude/CLAUDE.md ~/.claude/rules/

# 머신별 분기 · 파일을 템플릿으로 승격
chezmoi chattr +template ~/.claude/settings.json
# 템플릿 안에서:
"impeccable@impeccable": {{ if eq .chezmoi.hostname "macbook-pro" }}true{{ else }}false{{ end }}

# 시크릿 · 그 파일만 암호화
chezmoi add --encrypt ~/.claude/settings.local.json

# 두 번째 머신부터
chezmoi init git@github.com:me/dotfiles.git
chezmoi diff                                  # 뭐가 바뀔지 먼저 확인
chezmoi apply

주의 두 가지, 둘 다 커뮤니티 실측에서 나온 것: ① 전체 동기화 금지: ~/.claude의 세션 로그·캐시·플러그인 캐시는 머신 고유물이라 add 대상이 아니다(선별 add가 기본). ② 마켓플레이스 플러그인 실체는 각 머신이 스스로 내려받는다. 동기화 대상은 settings.json의 선언(enabledPlugins)이지 캐시가 아니다. keystone의 "시드는 소스, 캐시는 머신별"과 같은 결론이다.

keystone 환경에서의 판정 · 전환은 비권장, 채굴은 세 개

전환 비권장: 4프로파일 분기와 adapter export가 chezmoi 범위 밖이고, 이미 운영 중인 시스템을 옮기면 이득 없이 마이그레이션 비용만 남는다(§03 반론의 조건이 뒤집히기 전까지).

채굴 후보 ①: age 선별 암호화. 현재 settings.local.json은 "동기화 안 함"으로만 처리되는데, 암호화해 레이어에 실으면 새 머신 셋업에서 시크릿 재입력이 사라진다. : .chezmoiignore식 명시적 제외 선언. keystone의 머신 고유물 제외는 스크립트 로직 안에 흩어져 있는데, 선언 파일 하나로 모으면 감사가 쉬워진다. : autoPush식 세션 훅 pull. 지금은 "다음 apply 때 정합"인데, SessionStart에서 가벼운 pull 체크를 하면 머신 간 드리프트 창이 줄어든다.

Verdict

05판정 · 반론 · 반증 조건

칭찬으로 끝나는 평가는 정보량이 없다. 이 글의 결론 세 개를 각각 반증 조건과 함께 적는다.

결론과 그것이 틀리는 조건

결론반론반증 조건 (이게 관측되면 결론 폐기)
keystone 방식은 커뮤니티 2층의 정석 패턴이다: git 소스 → 머신별 apply는 dotfiles 관행과 동형 동형이라는 사실이 비용까지 정당화하지는 않는다. chezmoi는 남이 유지보수하는 도구고 apply.sh는 우리가 유지보수하는 코드다. 사고 이력(런타임 키 증발, diverged 처리)은 전부 후자에서 났다 분기당 apply發 설정 사고가 반복 관측되면(예: 2회+) 설정 배포 부분만 chezmoi로 이관하는 RFC를 연다
impeccable은 "전역 off + 프로젝트 on"이 맞다: 라우팅 충돌과 품질을 둘 다 잡는 구성 디자인 작업이 잦으면 프로젝트마다 켜는 마찰이 누적된다. 그 경우 keystone 레이어로 포크해 disable-model-invocation: true를 달고 전역 명시-호출 전용으로 두는 쪽이 낫다. 단 업스트림 churn(2.5개월에 메이저 1회) 추적 비용을 산다 한 달 안에 프로젝트 enable 커밋이 3개 repo를 넘으면 포크안으로 전환 검토
chezmoi 전환은 비권장, 채굴만 한다: 4프로파일 + adapter export가 범위 밖 "이미 만들어서 아깝다"가 판단을 오염시킬 수 있다(매몰 비용). 채굴 3건(age 암호화·명시적 제외 선언·세션 훅 pull)을 실제로 안 하면 이 판정은 현상 유지의 변명이었던 것 채굴 후보가 다음 분기까지 이슈로도 등록되지 않으면, 판정 자체를 재심사한다
한 줄 요약

스킬 활성/비활성은 이미 공식 레버가 다 있다(frontmatter · enabledPlugins 스코프 · 아카이브). 진짜 문제는 "어느 머신에서"이고, 그 답의 커뮤니티 표준은 user 스코프의 git 정본화다. keystone은 그걸 이미 하고 있으며, 오늘 impeccable 건은 그 시스템이 정상 작동하는 한 바퀴(소스 3줄 → PR #454 → apply → 실측)의 기록이다.

실측 근거: pbakaus/impeccable 정독(SKILL.md v4.0.4 · craft-floor · critique, 클론 620ba1f) / gh api 저장소 메타(⭐54,893 · fork 3,301) / claude plugin --help·enable/disable scope 플래그 / 공식 skills 문서(disable-model-invocation·user-invocable) / keystone-hub layers 3종 settings.json·apply.sh runtime-preserve 소스 / PR #454 병합·apply 후 런타임 값·플러그인 4.0.4 실측 / 커뮤니티 소스 8건(§02 링크)