Claude Code 설정 동기화와 트러블슈팅
- 1. Claude Code 멀티 계정 셋업 — 한 Mac에서 4계정 분리 운영
- 2. Claude Code 세션 공유 — .jsonl 심볼릭 링크
- 3. Claude Code 설정 동기화와 트러블슈팅
계정을 여럿 쓰다 보면 또 다른 마찰이 생긴다. 한 계정에서 플러그인을 설치하거나 슬래시 커맨드를 추가하면, 다른 계정에는 반영이 안 돼 있다. 계정마다 같은 설정을 다시 해줘야 한다. 계정이 많을수록 이 부담이 커진다.
seamless하게 쓰려면 어떤 설정은 모든 계정에서 동일해야 하고, 어떤 설정은 계정마다 달라야 한다. 그 경계를 정하고 자동화하는 게 이 글의 내용이다.
여러 Claude Code 계정 사이에서 설정·플러그인·MCP 서버 구성을 동기화하고, 깨졌을 때 진단하는 절차를 정리한 글입니다. Ep1에서 다룬 CLAUDE_CONFIG_DIR 기반 계정 분리, Ep2에서 다룬 세션 공유 위에 운영 단계의 구체 절차를 얹습니다.
동기화가 필요한 항목
멀티 계정을 운영하다 보면 어떤 파일은 모든 계정에서 같아야 하고, 어떤 파일은 계정마다 달라야 합니다. 이 구분이 흐릿하면 동기화 스크립트가 계정 고유 설정을 덮어쓰거나, 반대로 업데이트한 플러그인이 특정 계정에만 반영되지 않는 상황이 생깁니다.
~/.claude(기본 인스턴스)와 ~/.claude-2, ~/.claude-3, ~/.claude-4 사이에서 동기화 대상이 되는 항목은 다음과 같습니다.
공유 대상
settings.json은 모델 설정, 훅 정의, 각종 옵션을 담고 있어 계정 간 일관성이 필요한 핵심 파일입니다. 다만 API 키나 OTEL 환경변수처럼 계정 고유 값이 섞여 있을 수 있으므로 그대로 복사하는 것이 항상 안전하지는 않습니다. 뒤에서 설명하는 필터링 방식이 이 문제를 다룹니다.
CLAUDE.md는 전역 시스템 프롬프트입니다. 대부분의 경우 모든 계정에서 같은 지시문을 사용하므로 동기화 대상에 포함합니다.
cwf-hooks-enabled.sh는 CWF 훅 활성화 상태를 제어하는 파일로, 계정 전체에 같은 상태가 유지되어야 합니다.
commands/, hooks/, skills/, agents/, hud/ 디렉토리는 슬래시 커맨드, 훅 스크립트, 스킬·에이전트 정의, HUD 설정을 포함합니다. 한 계정에서 새 슬래시 커맨드를 추가하거나 훅을 수정했을 때 다른 계정에도 반영되어야 하는 경우가 대부분입니다.
plugins/는 플러그인 디렉토리입니다. 복사보다 심볼릭 링크 방식을 사용해 모든 계정이 같은 물리 디렉토리를 참조하게 합니다. 플러그인 업데이트가 즉시 전체 계정에 반영됩니다.
격리가 필요한 항목
세션 데이터(.jsonl)와 히스토리(history.jsonl)는 동기화 대상이 아닙니다. 세션 공유가 필요하면 Ep2에서 다룬 ~/.claude-shared/projects 심볼릭 링크 방식을 사용합니다. 동기화 스크립트가 건드리는 영역이 아닙니다.
OTEL 환경변수(OTEL_*)는 추적·모니터링 인스턴스 전용 설정입니다. .claude-3처럼 트레이싱 용도로 구성된 계정이 있다면, 기본 인스턴스의 OTEL 설정을 그대로 받으면 충돌이 생깁니다. 동기화 시 이 계정에 한해 OTEL 관련 키를 제거하는 필터를 적용해야 합니다.
sync, cctrace 계열 훅도 특정 계정 전용 기능으로, 다른 계정에 복제하면 의도치 않은 동작이 발생할 수 있습니다.
공유·격리 결정 매트릭스
어떤 항목을 공유하고 어떤 항목을 격리할지, 계정별로 예외 조건이 있는 경우를 포함해 정리합니다.
| 항목 | .claude-2, .claude-4 |
.claude-3 (트레이싱) |
동기화 방식 |
|---|---|---|---|
settings.json |
공유 | 공유 (OTEL·sync·cctrace 훅 제거) | 복사 + jq 필터 |
CLAUDE.md |
공유 | 공유 | 복사 |
cwf-hooks-enabled.sh |
공유 | 공유 | 복사 |
commands/ |
공유 | 공유 | rsync --delete |
hooks/ |
공유 | 공유 | rsync --delete |
skills/ |
공유 | 공유 | rsync --delete |
agents/ |
공유 | 공유 | rsync --delete |
hud/ |
공유 | 공유 | rsync --delete |
plugins/ |
공유 | 공유 | 심볼릭 링크 |
projects/ |
격리 (Ep2 별도 공유) | 격리 | — |
history.jsonl |
격리 | 격리 | — |
memory/ |
격리 (선택적 공유 가능) | 격리 | 선택 시 심볼릭 링크 |
OTEL_* env |
유지 | 제거 | jq 필터 |
sync, cctrace 훅 |
유지 | 제거 | jq 필터 |
디렉토리 동기화에 rsync --delete를 사용하는 이유는 기본 인스턴스에서 제거한 파일이 다른 계정에서도 삭제되어야 하기 때문입니다. --update 플래그만 사용하면 한쪽에서 삭제한 슬래시 커맨드나 훅이 다른 계정에 남아 있는 상태가 됩니다.
역방향 동기화(각 계정에서 기본 인스턴스로 반영)에는 --update 플래그를 사용합니다. 최신 파일만 덮어쓰므로 기본 인스턴스를 실수로 덮어쓰는 위험이 없습니다. .claude-3의 settings.json은 역방향 동기화 대상에서 제외합니다. 필터링된 버전이기 때문에 그대로 반영하면 기본 인스턴스의 OTEL 설정이 사라집니다.
마이그레이션 절차
단일 계정에서 멀티 계정으로 전환하거나, 멀티 계정 환경에 동기화를 새로 추가하는 경우 모두 동일한 순서로 진행합니다.
백업
동기화를 처음 적용하기 전에 각 인스턴스의 settings.json을 백업합니다. rsync --delete 방향 동기화는 대상 디렉토리의 파일을 삭제할 수 있으므로, 복원 경로를 먼저 확보합니다.
cp ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%s)
cp ~/.claude-2/settings.json ~/.claude-2/settings.json.bak.$(date +%s)
cp ~/.claude-3/settings.json ~/.claude-3/settings.json.bak.$(date +%s)
cp ~/.claude-4/settings.json ~/.claude-4/settings.json.bak.$(date +%s)동기화 스크립트 배치
sync-claude.sh를 기본 인스턴스의 스크립트 디렉토리에 저장합니다.
mkdir -p ~/.claude/scripts
# sync-claude.sh 파일을 ~/.claude/scripts/sync-claude.sh 위치에 배치스크립트의 핵심 변수는 두 가지입니다. SRC는 기본 인스턴스 경로($HOME/.claude), DSTS는 대상 인스턴스 배열($HOME/.claude-2, $HOME/.claude-3, $HOME/.claude-4)입니다.
수동 실행으로 초기 동기화
첫 실행은 수동으로 합니다. 결과를 직접 확인하고 의도치 않은 덮어쓰기가 없는지 점검할 수 있습니다.
bash ~/.claude/scripts/sync-claude.sh정상 실행 시 출력 형식은 다음과 같습니다.
[역방향] .claude-2/3/4 -> .claude
<- .claude-2
<- .claude-3
<- .claude-4
[순방향] .claude -> .claude-2/3/4
[.claude-2]
-> settings.json 동기화
-> CLAUDE.md 동기화
-> cwf-hooks-enabled.sh 동기화
-> commands/ 동기화
-> hooks/ 동기화
-> skills/ 동기화
-> agents/ 동기화
-> hud/ 동기화
-> plugins/ symlink
[.claude-3]
...
[OK] 완료플러그인 심볼릭 링크 확인
plugins/ 처리는 복사가 아니라 심볼릭 링크 교체입니다. 스크립트는 다음 순서로 실행합니다.
rm -rf "$DST/plugins"
ln -sf "$SRC/plugins" "$DST/plugins"초기 실행 후 링크가 제대로 생성됐는지 확인합니다.
ls -la ~/.claude-2/plugins ~/.claude-3/plugins ~/.claude-4/plugins
# 각 줄이 ~/.claude/plugins를 가리키고 있어야 함세션 종료 훅 등록 (자동화)
매 세션 종료 시 자동으로 동기화하려면 SessionEnd 훅에 등록합니다. ~/.claude/settings.json의 hooks 블록에 추가합니다.
{
"hooks": {
"SessionEnd": [
{
"description": "설정 동기화",
"hooks": [
{
"command": "bash ~/.claude/scripts/sync-claude.sh"
}
]
}
]
}
}훅 등록 후 settings.json을 다시 동기화해야 변경 사항이 다른 계정에 전파됩니다. 훅 등록 직후 수동으로 한 번 더 실행합니다.
롤백
동기화 후 문제가 생겼을 때는 백업 파일로 복원합니다.
# settings.json 복원
cp ~/.claude/settings.json.bak.<타임스탬프> ~/.claude/settings.json
# 계정별 복원도 동일한 방식
cp ~/.claude-2/settings.json.bak.<타임스탬프> ~/.claude-2/settings.json디렉토리 전체(commands/, hooks/ 등)가 덮어쓰인 경우 git 저장소에서 관리하고 있었다면 해당 커밋으로 되돌립니다. 그렇지 않다면 동기화 전 별도 백업을 유지하는 것이 안전합니다.
자주 발생하는 문제
.claude-3의 settings.json이 수동 수정 후 원복됨
SessionEnd 훅에 동기화 스크립트가 등록되어 있으면, 세션이 끝날 때마다 기본 인스턴스의 settings.json이 jq 필터를 거쳐 .claude-3/settings.json을 덮어씁니다. .claude-3 고유 설정을 직접 수정해도 다음 동기화에서 초기화됩니다.
.claude-3 전용으로 유지해야 하는 설정이 있다면 두 가지 방법 중 하나를 선택합니다. 첫째, 해당 설정을 기본 인스턴스 settings.json에 포함시키되 jq 필터에서 제외 조건을 추가합니다. 둘째, 동기화 스크립트를 수정해 .claude-3의 특정 키를 병합(merge)하도록 변경합니다.
새 훅 이름이 .claude-3에서 제거됨
jq 필터는 훅 command 문자열에 sync 또는 cctrace가 포함된 경우 대소문자 무관하게 해당 훅을 제거합니다.
test("sync"; "i") or test("cctrace"; "i")새로 추가하는 훅 이름에 이 문자열이 포함되어 있으면 의도치 않게 .claude-3에서 제거됩니다. 예를 들어 sync-validate나 run-cctrace는 필터에 걸립니다. validate-setup이나 trace-report 같은 이름은 안전합니다.
훅 이름을 확인하는 방법은 다음과 같습니다.
# 현재 settings.json에서 훅 command 목록 추출
jq '[.. | objects | .command // empty] | unique' ~/.claude/settings.jsonplugins 심볼릭 링크가 깨짐
~/.claude/plugins 원본 디렉토리가 이동되거나 이름이 변경되면 다른 계정의 심볼릭 링크가 끊깁니다. 증상은 Claude Code 기동 시 플러그인을 로드하지 못하는 오류입니다.
확인 명령은 다음과 같습니다.
ls -la ~/.claude-2/plugins
# 출력에 "broken symbolic link" 또는 빨간색 경로 표시가 나타나면 깨진 상태재생성은 각 계정에 대해 수행합니다.
rm ~/.claude-2/plugins ~/.claude-3/plugins ~/.claude-4/plugins
ln -sf ~/.claude/plugins ~/.claude-2/plugins
ln -sf ~/.claude/plugins ~/.claude-3/plugins
ln -sf ~/.claude/plugins ~/.claude-4/pluginssessions-index.json 경합
cc-session-sync나 qmd 같은 외부 도구가 ~/.claude-shared/projects/sessions-index.json을 생성하고 관리하는 경우, 여러 도구가 동시에 이 파일을 갱신하면 경합이 발생할 수 있습니다. 하나의 도구가 읽은 뒤 수정해 저장하기 전에 다른 도구가 덮어쓰면 변경 사항이 유실됩니다.
Claude Code 자체는 sessions-index.json을 사용하지 않습니다. .jsonl 파일을 직접 스캔하므로 Resume 기능은 색인 손상과 무관하게 동작합니다. 외부 도구의 색인 조회에만 영향이 있습니다.
해결 방법은 도구별 실행 시간을 분산하거나 파일 잠금을 사용하는 것입니다.
# crontab 예시 — 30분 차이로 충돌 회피
0 */6 * * * /path/to/tool-a
30 */6 * * * /path/to/tool-b색인 파일이 손상된 경우 삭제하면 다음 도구 실행 시 자동으로 재생성됩니다.
rm ~/.claude/projects/sessions-index.jsonmemory 디렉토리 격리로 인한 컨텍스트 단절
projects/ 디렉토리를 공유하더라도 memory/ 디렉토리는 각 계정에 독립적으로 유지됩니다. 계정 1에서 세션 중에 저장한 메모리 정보를 계정 2에서 같은 세션을 재개해도 볼 수 없습니다.
memory까지 공유가 필요한 경우에는 심볼릭 링크로 연결합니다.
mkdir -p ~/.claude-shared/memory
rsync -a --ignore-existing ~/.claude/memory/ ~/.claude-shared/memory/
for ACCT in ~/.claude ~/.claude-[0-9]*; do
rm -rf "$ACCT/memory"
ln -sf ~/.claude-shared/memory "$ACCT/memory"
donememory를 공유하면 한 계정의 변경이 다른 계정에도 즉시 반영됩니다. 계정별로 분리된 메모리 컨텍스트가 필요한 경우에는 이 설정을 적용하지 않습니다.
PROJ_KEY 충돌
Claude Code는 프로젝트 경로를 인코딩해 PROJ_KEY를 생성합니다. 경로 구분자(/와 -)가 혼재하면 서로 다른 경로가 같은 PROJ_KEY로 인코딩될 수 있습니다.
/a/b-c → a[sep]b[sep]c
/a-b/c → a[sep]b[sep]c충돌이 발생하면 두 프로젝트가 세션 목록을 공유하는 상황이 생깁니다. 심볼릭 링크 구조 자체와는 무관한 Claude Code 기존 제한 사항입니다.
예방하는 방법은 프로젝트 경로에 -와 /를 혼용하지 않는 것입니다. ~/Projects/my-app과 ~/Projects/my_app처럼 일관된 명명 규칙을 유지합니다.
진단 절차
설정이 예상대로 동작하지 않을 때 순서대로 확인합니다.
심볼릭 링크 상태 확인
ls -la ~/.claude/projects
ls -la ~/.claude-2/projects ~/.claude-3/projects ~/.claude-4/projects
ls -la ~/.claude-2/plugins ~/.claude-3/plugins ~/.claude-4/plugins각 항목이 의도한 경로를 가리키고 있는지, 링크가 끊겨 있지는 않은지 확인합니다.
settings.json 파싱 검증
JSON 형식 오류가 있으면 Claude Code가 settings.json을 읽지 못합니다. 각 인스턴스의 파일을 검증합니다.
jq . ~/.claude/settings.json > /dev/null && echo "OK" || echo "파싱 오류"
jq . ~/.claude-2/settings.json > /dev/null && echo "OK" || echo "파싱 오류"
jq . ~/.claude-3/settings.json > /dev/null && echo "OK" || echo "파싱 오류"
jq . ~/.claude-4/settings.json > /dev/null && echo "OK" || echo "파싱 오류"훅 목록 추출
등록된 훅 커맨드 목록을 확인합니다. .claude-3에서 특정 훅이 제거되고 있는지 비교할 때 사용합니다.
# 기본 인스턴스 훅
jq '[.. | objects | .command // empty] | unique' ~/.claude/settings.json
# .claude-3 훅 (필터 적용 후)
jq '[.. | objects | .command // empty] | unique' ~/.claude-3/settings.json파일 소유권 확인
공유 디렉토리나 심볼릭 링크 대상이 루트 소유로 설정되어 있으면 Claude Code가 파일을 쓰지 못합니다.
ls -la ~/.claude-shared/
# 소유자가 현재 사용자인지 확인
# 필요 시 소유권 교정
chown -R $(whoami) ~/.claude-shared/동기화 로그 확인
SessionEnd 훅이 실패하는 경우 Claude Code 로그에서 오류를 확인합니다. 로그 경로는 운영 체제에 따라 다릅니다.
macOS 기준 로그는 ~/Library/Logs/Claude/ 아래에 있습니다. 훅 실행 오류는 해당 디렉토리의 로그 파일에서 확인할 수 있습니다.
동기화 스크립트 수동 실행으로 재현
자동 동기화에서 발생하는 문제를 재현하려면 수동으로 실행합니다.
bash ~/.claude/scripts/sync-claude.sh출력에서 [OK] 완료가 나오지 않거나 오류 메시지가 보이면 스크립트 내부 각 단계를 개별로 실행해 어느 단계에서 실패하는지 확인합니다.
백업 디렉토리 현황
오래된 백업이 누적되면 디스크 용량이 증가합니다. 주기적으로 확인하고 정리합니다.
# 백업 크기 확인
du -sh ~/.claude/projects.bak.* ~/.claude-2/projects.bak.* 2>/dev/null
# 30일 이상 된 백업 삭제
find ~/.claude ~/.claude-[0-9]* -maxdepth 1 -name "projects.bak.*" -mtime +30 -exec rm -rf {} \;시리즈 마무리
Ep1에서는 CLAUDE_CONFIG_DIR과 쉘 함수로 한 머신에서 여러 Claude Code 인스턴스를 독립 디렉토리로 분리하는 방법을 다뤘습니다. Ep2에서는 ~/.claude-shared/projects 심볼릭 링크 구조로 계정 간 세션을 공유하는 방법을, 이 글에서는 sync-claude.sh 기반 설정 동기화와 운영 중 발생하는 문제의 진단·복구 절차를 정리했습니다.
멀티 계정 구성에서 지켜야 할 패턴은 명확합니다. 설정 파일(settings.json, CLAUDE.md, 커맨드·훅 디렉토리)은 기본 인스턴스에서 관리하고 나머지 계정에 전파합니다. plugins/는 심볼릭 링크로 모든 계정이 같은 원본을 참조하게 하고, 세션 데이터(projects/)는 ~/.claude-shared/를 물리적 저장소로 두고 심볼릭 링크로 연결합니다. 이 패턴이 지켜지면 계정 수가 늘어도 운영 복잡도는 선형으로 증가하지 않습니다. 반면 계정별로 설정을 따로 편집하거나 플러그인을 중복 설치하기 시작하면 어느 계정이 기준인지 추적하기 어려워집니다. 동기화 스크립트의 역할은 기본 인스턴스를 단일 진실 공급원(single source of truth)으로 유지하는 것입니다.