
chezmoi로 apm을 고정 관리하다가 어느덧 '자유롭게 설치할 수 없는' 환경이 되어버린 이야기
요약
dotfiles 관리 도구인 chezmoi와 Claude Code의 패키지 매니저인 apm을 함께 사용할 때 발생하는 설정 고착화 문제를 다룹니다. 모든 설정을 강제로 동기화하려다 발생한 불편함을 해결하기 위해, 공통 패키지는 의존성 리포지토리로 관리하고 나머지는 로컬 자유도를 보장하는 구성으로 개선한 경험을 공유합니다.
핵심 포인트
- chezmoi로 apm 설정을 엄격히 관리할 경우 패키지 테스트가 어려워질 수 있음
- apm의 의존성(dependency) 기능을 활용해 공통 패키지를 리포지토리 단위로 관리
- base 패키지는 자동 동기화하고, 나머지 패키지는 터미널 로컬 환경에 맡기는 구조 제안
도입
나는 평소 사용하는 dotfiles(홈 디렉터리 설정 파일군)를 chezmoi로 관리하고 있다. 그 대상 중 하나로, Claude Code의 스킬 등을 관리하는 패키지 매니저 「apm (Agent Package Manager)」의 설정 파일도 chezmoi 관리 하에 두었다.
이 apm 설정 파일 apm.yml
(의존 패키지 목록)과 apm.lock.yaml
(해결 결과를 고정하는 락 파일(lock file). npm의 package-lock.json에 해당함)을 오랫동안 chezmoi로 관리해 온 결과, 터미널마다 새로운 패키지를 가볍게 테스트하는 것이 전혀 불가능해졌다는 사실을 깨달았다. apm.yml은 chezmoi 관리 하에서 실질적으로 읽기 전용(read-only)이 되어 있었고, apm.lock.yaml의 내용이 바뀔 때마다 모든 터미널에서 강제적으로 패키지 재설치가 실행되는 구성이었던 것이다.
dotfiles 관리 도구와 패키지 매니저를 조합해서 사용하는 사람이라면, 이와 비슷한 문제로 막혔던 경험이 있을지도 모른다. 왜 이런 구성이 되었는지, 그리고 최종적으로 어떻게 수정했는지 되돌아보고자 한다.
애초의 경위
처음에는 Claude Code의 스킬류도 chezmoi로 직접 관리했지만, 머지않아 apm의 존재를 알게 되어 apm을 사용하는 방향으로 전환했다. 당초에는 원하는 스킬을 apm install --global로 개별적으로 설치해 나가는 운용 방식이었다.
그 후, "모든 터미널에서 공통으로 사용하고 싶은 패키지는 별도의 리포지토리(repository)에 의존 관계(dependency)로 묶어두면 된다"는 것을 깨달았다. agent-deps(공개된 타인의 공개 스킬 참조를 집약하는 리포지토리)와 my-agent-toolkit(비공개, 자작 스킬·MCP 정의를 묶는 리포지토리)이라는 두 개의 리포지토리를 만들고, 각각의 apm.yml에 실제로 사용하고 싶은 스킬을 의존 관계로 나열했다. 이 두 리포지토리만 apm install --global 해두면, 그 안의 의존성까지 포함하여 apm이 해결하여 설치해 준다.
apm.yml은 한때 "ad-hoc하게 apm install <pkg>를 해도 그 자리에서는 성공한 것처럼 보이지만, 다음 chezmoi apply에서 조용히 변경 사항이 사라지는" 알아채기 어려운 사고가 발생하고 있었다. 이를 방지하기 위해 apm.yml을 mode 444(읽기 전용)로 배포하여, apm install <pkg>를 즉시 EACCES로 실패하게끔 수정했던 경위가 있었다.
사고를 방지하려는 의도는 맞았지만, 여기에 더해 apm.lock.yaml의 내용이 바뀔 때마다 apm install --global을 모든 터미널에서 강제 실행하는 chezmoi 스크립트도 심어두었다. 이 두 가지가 결합된 결과, 터미널마다 새로운 패키지를 시도하는 것 자체가 불가능해졌다. 읽기 전용이기 때문에 신규 추가는 그 자리에서 실패하고, 설령 락 파일의 내용이 바뀌더라도 다음 chezmoi apply에서 모든 터미널 분량의 강제 재설치가 실행되어 버린다.
깨달은 "정말로 하고 싶은 것"
브레인스토밍을 통해 정리해 보니, 정말로 하고 싶은 것은 다음 두 가지였다.
- 모든 터미널에서 공통으로 사용하고 싶은 base 패키지(
agent-deps·my-agent-toolkit)는 자동으로 동기화되었으면 좋겠다. - 그 외의 패키지는 터미널마다 자유롭게 테스트하거나 설치하거나 삭제하고 싶다.
즉, "전부를 고정 관리할 것인가" 아니면 "전부를 chezmoi 관리에서 제외할 것인가"의 이지선다가 아니라, base 패키지만을 동기화 대상으로 삼고 그 외에는 터미널 로컬의 자유에 맡기는 중간 단계의 구성이 필요했다.
최종적인 구성 — 공통화는 별도 리포지토리, chezmoi는 설치만 시킬 뿐
도달한 결론은 심플했다. "공통화"는 apm의 의존 관계 기능에 완전히 맡기고, chezmoi의 역할은 "해당 의존 리포지토리가 아직 설치되어 있지 않다면 apm install --global을 실행한다"는 단 한 점으로 축소한다.
apm.yml · apm.lock.yaml 자체는 chezmoi의 관리 대상에서 완전히 제외했다. 대신 chezmoi가 가지는 것은 다음과 같은 작은 멱등(idempotent) 스크립트 하나뿐이다.
#!/usr/bin/env bash
set -euo pipefail
export PATH="$HOME/.local/bin:$PATH"
...
핵심은 ensure_pkg 함수뿐이다. apm_modules/<owner>/<repo> (apm이 패키지를 전개하는 대상 디렉토리)의 존재 여부를 확인하여, 없으면 apm install --global을 실행한다. 이것만으로 apm.yml의 내용 자체에는 전혀 손대지 않는다.
이 구성은 각각의 역할이 명확하게 나누어져 있다.
공통화하고 싶은 패키지: agent-deps (공개) · my-agent-toolkit (비공개)라는 리포지토리(Repository) 측에서 관리한다. 여기에 추가하면 어떤 단말기에서도 위 스크립트가 자동으로 설치해 준다.
단말기마다 자유롭게 테스트하고 싶은 패키지: apm.yml · apm.lock.yaml이 chezmoi의 관리에서 벗어나 완전히 로컬 소유가 됨으로써, 언제든 자유롭게 apm install <pkg> --global을 할 수 있고, chezmoi apply를 해도 사라지지 않게 되었다.
새롭게 모든 단말기에서 공통화하고 싶은 패키지가 늘어났을 때도, agent-deps · my-agent-toolkit 측에 스킬을 추가하거나, 위 스크립트에 ensure_pkg 호출을 한 줄 추가하는 것만으로 충분하다.
요약
이번의 가장 큰 문제는, "공통화하고 싶은 두 개의 base 패키지"를 위해 선택한 수단(락 파일(Lock file) 변경의 모든 단말기 강제 반영)이 "그 외에는 자유롭게 테스트하고 싶다"라는 요구와 양립할 수 없는 구성이었다는 점에 있었다.
dotfiles로 도구의 설정 파일을 관리할 때는, "동기화하고 싶은 범위"와 "단말기 로컬에 남기고 싶은 자유"를 사전에 분리해 둘 필요가 있다. 이번에는 그 분리를 공통화의 실체를 별도 리포지토리 및 apm의 의존성 해결(Dependency resolution)에 완전히 맡기고, chezmoi 측은 최소한의 설치 트리거(Trigger)만 가지는 형태로 실현했다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기