Claude Code, Codex, 그리고 .agents 폴더를 통해 40개 이상의 기술(Skills)을 관리하는 방법
요약
Claude Code와 Codex 사용 시 축적된 40개 이상의 기술(Skills)로 인해 발생하는 성능 저하와 맥락 혼선 문제를 다룹니다. 에이전트에게 불필요한 기술이 노출되는 '기술 유출' 현상을 해결하기 위해 Go CLI를 개발하게 된 과정을 설명합니다.
핵심 포인트
- 기술(Skills) 축적으로 인한 시작 지연 및 잘못된 도구 제안 문제 발생
- 에이전트에게 모든 기술을 노출할 경우 발생하는 맥락 혼선(Skill Bleed)
- 단순 파일 이동이 아닌 모델 중심의 효율적인 기술 관리 필요성
- Go CLI를 통한 에이전트 노출 기술의 선택적 제어
저는 세 개의 기술(skills)로 시작했습니다. 1년 후에는 40여 개가 되었습니다. 모든 Claude Code 세션은 그 기술들을 전부 불러왔습니다. 모든 Codex 실행도 그 기술들을 전부 불러왔습니다. 제가 시도한 모든 .agents 기반 도구들도 전부 불러왔습니다. 폴더는 전역적(global)이지만, 작업은 그렇지 않습니다.
이 포스트는 기술의 축적이 어떻게 매 세션마다 조용한 세금(tax)이 되었는지, 이를 해결하기 위해 무엇을 시도했는지(그중 대부분은 망가졌습니다), 그리고 정답이 스크립트가 아닌 모델이었기에 결국 작성하게 된 작은 Go CLI에 대해 다룹니다.
40여 개의 기술이 생겨난 과정
어느 날 갑자기 앉아서 40개의 기술을 설치한 것이 아닙니다. 그것들은 조금씩 흘러 들어왔습니다:
- 사내 도구용 업무 기술 (work skills) — 배포 도우미(deploy helpers), 런북 스캐폴더(runbook scaffolders), API 인증 래퍼(API auth wrapper)
- 개인 프로젝트 기술 (personal project skills) — SQLite 마이그레이션 도우미, 블로그 포스트 초안 작성기, GitHub 이슈 템플릿 생성기
- 연구 기술 (research skills) — PDF-to-notes 흐름, arxiv 요약기, 인용 정리기
- 프론트엔드 기술 (frontend skills) — Tailwind 클래스 정리기, React 컴포넌트 스캐폴더, 소규모 접근성 린터(accessibility linter)
- 백엔드 기술 (backend skills) — Postgres 인덱스 분석기, OpenAPI 스펙 생성기
- 그리고 한 번 만들고 두 번 사용한 뒤 절대 삭제하지 않은 실험적인 기술들의 긴 꼬리(long tail)
문제를 인지했을 때쯤, 개수는 40개를 넘어선 상태였습니다. 그중 일부는 진심으로 매일 사용했습니다. 일부는 딱 한 번 사용했습니다. 하지만 그 모든 것들이 시작 시점에 제 에이전트(agents)들에게 노출되었습니다.
기술 유출(skill bleed)의 실제 비용
매 세션마다 모든 기술을 확인하는 비용은 단순히 시작 지연 시간(startup latency)뿐만이 아닙니다. 물론 그것도 실제적인 문제입니다. 진짜 문제는 잘못된 순간에 잘못된 기술이 제안되는 것입니다.
제가 관심을 갖기 시작하게 만든 몇 가지 구체적인 마찰(friction) 순간들은 다음과 같습니다:
- Claude에게 개인적인 이메일 초안 작성을 도와달라고 요청했는데, 회사의 이메일 템플릿 기술 (email templating skill)을 사용하라고 제안했습니다. 기술 이름만 보면 적용 가능해 보였지만, 실제로는 그렇지 않았습니다.
- 개인적인 SQLite 프로젝트를 작업하는 동안 Codex가 내부 데이터베이스 스키마 (database schema) 문서를 불러왔습니다. 스키마도 다르고, 도메인도 다르고, 모든 것이 달랐지만, 기술이 특정 키워드와 일치했습니다.
- 완성되지 않은 실험적인 기술들이 결정론적 리팩터링 (deterministic refactors) 과정에서 계속 나타났습니다. 에이전트가 제가 20분 동안 작성하고 한 번도 테스트하지 않은 도구를 친절하게 제안하곤 했습니다.
- 하나의 기술이 다른 프로젝트의 기술과 이름 충돌 (name collision)이 발생했습니다. 에이전트는 먼저 발견된 것을 선택했습니다.
이 중 어느 것도 치명적인 문제는 아닙니다. 하지만 이는 지속적인 저강도의 마찰 (low-grade friction)이며, 기술이 쌓일수록 상황은 악화됩니다. 솔직히 말하자면, 에이전트는 당신이 시킨 대로 하고 있는 것입니다. 당신이 이 모든 기술에 대해 알려주었기 때문에, 에이전트에게는 모두 사용 가능한 대상인 것입니다.
해결책은 반드시 다음과 같아야 합니다: 에이전트에게 더 적은 수의 기술만 알려주는 것.
내가 처음에 시도했던 것들
단순히 파일 이동하기
순진한 첫 번째 시도: 필요하지 않을 때 기술들을 ~/.claude/skills 밖으로 옮기는 것이었습니다. 기본적으로 드래그 앤 드롭 방식이었죠.
이 방법은 즉시 실패했습니다. 기술 설치 프로그램(Skill installers) — 현재 아주 많습니다 — 은 글로벌 경로 (global path)에 기록을 합니다. 그래서 일주일 뒤면 ~/.claude/skills는 원래 크기로 돌아가 있었고, 제가 새로 설치한 것들이 더해져 있었습니다. 수동 이동은 설치 프로그램과의 접촉에서 살아남지 못합니다.
서로 다른 디렉토리를 가리키는 셸 별칭 (Shell aliases)
다음 시도: 각 컨텍스트 (context)를 위한 별칭 (alias)을 만드는 것이었습니다.
alias claude-work='CLAUDE_SKILLS_DIR=~/.claude/work-skills claude'
alias claude-personal='CLAUDE_SKILLS_DIR=~/.claude/personal-skills claude'
문제는 모든 에이전트가 기술 경로에 대한 환경 변수 (env var) 오버라이드를 준수하지 않는다는 점입니다. 어떤 것은 준수하고, 어떤 것은 그렇지 않으며, 어떤 것은 어설프게 준수합니다. 그리고 준수하는 경우라 할지라도, 서드파티 설치 프로그램들은 여전히 글로벌 위치에 기록하기 때문에 디렉토리들이 즉시 어긋나게 됩니다.
이것은 화요일에는 작동하다가 목요일에는 망가지는 종류의 해결책입니다.
심볼릭 링크 (Symlinks)를 활용한 bash 스크립트
좀 더 근접했습니다. 저는 다음과 같은 작업을 수행하는 스크립트를 작성했습니다:
~/.claude/skills삭제~/.claude/skills를~/.claude/profiles/<name>/skills로 연결하는 심볼릭 링크 (Symlink) 생성~/.codex/skills및~/.agents/skills에 대해서도 동일한 작업 수행
작동했습니다. 한동안은요. 그러다 제 에이전트(Agents)들이 이미 공유된 심볼릭 링크 토폴로지(Topology) — ~/.claude/skills -> ~/.agents/skills — 안에 있다는 것을 깨달았을 때 망가졌습니다. 과거 어느 시점에 공유된 하위 집합을 중복 제거(Dedupe)하기 위해 그렇게 설정해 두었기 때문입니다. 제 스크립트는 두 경로를 보고 각각 별개의 루트(Root)로 취급했지만, 실제로는 하나였습니다. Bash가 혼란에 빠졌습니다. 심볼릭 링크가 순환(Circular) 구조가 되었습니다. 저는 토요일 오전 내내 이를 풀어내는 데 시간을 허비했습니다.
결정적인 문제는 스크립트가 아니었습니다. 문제는 파일 시스템에서 '어떤' 작업을 실행하느냐가 아니라는 사실을 깨달은 것이었습니다. 진짜 문제는 이 폴더들이 무엇을 의미하는지에 대한 모델(Model)이 부재하다는 것이었습니다.
폴더가 아닌 프로필 (Profiles)
제가 도달한 모델은 다음과 같습니다: **프로필 (Profile)**은 특정 목적을 위한 이름이 붙은 기술(Skills)의 집합입니다. work, personal, research, frontend 등 사용자의 컨텍스트에 맞는 무엇이든 될 수 있습니다.
각 프로필은 ~/.skillmux/profiles/<name>/ 아래에 자신만의 기술 복사본을 저장합니다. 프로필을 활성화하면 ~/.claude/skills, ~/.codex/skills, ~/.agents/skills가 해당 프로필의 내용으로 다시 연결(Relink)됩니다. 모든 에이전트가 한 번에 업데이트됩니다.
이 방식은 태그 기반 접근 방식보다 뛰어난데, 그 이유는 해결 과정에서의 모호함(Resolution ambiguity)이 없기 때문입니다. 기술은 하나의 프로필에 있거나 다른 프로필에 있습니다 (혹은 둘 다 있을 수도 있습니다. 복사 비용은 저렴하니까요). 또한 프로젝트별 기술 설정보다 뛰어난 이유는 프로필을 재사용할 수 있기 때문입니다. 제가 frontend 프로필을 사용한다면, 그것이 이 React 앱이든 저 React 앱이든 동일하게 적용됩니다.
또한 설치 프로그램(Installers)과 싸울 필요도 없습니다. 프로필이 활성화되어 있으면, 설치 프로그램은 활성화된 프로필의 디렉토리에 내용을 작성합니다. 글로벌 경로(Global path)는 여전히 존재하고, 여전히 작동하며, 여전히 쓰기가 가능하지만, 이제
curl로 설치:
curl -fsSL https://raw.githubusercontent.com/boringstackoverflow/skillmux/main/install.sh | sh
또는 Homebrew:
brew install boringstackoverflow/tap/skillmux
또는 Go 툴체인 (Go toolchain)이 있는 경우 go install 사용:
go install github.com/boringstackoverflow/skillmux/cmd/skillmux@latest
4단계 명령 워크플로 (The four-command workflow)
설치가 완료되면, 전체 일일 워크플로(daily workflow)는 단 네 개의 명령어로 이루어집니다.
최초 설정 (First-time setup)
$ skillmux init --profile work --yes
discovered roots:
~/.claude/skills
...
init은 기존의 에이전트 기술(agent skill) 폴더를 찾아내고, 심볼릭 링크 토폴로지 (symlink topology)를 해결하며, 백업 매니페스트 (backup manifest)를 작성한 뒤, 활성화된 프로필을 통해 이들을 다시 연결 (relink)합니다. 첫 번째 프로필에는 이미 존재하던 기술들이 그대로 심어지므로, 기존 데이터가 사라질 걱정은 없습니다.
다른 컨텍스트를 위한 프로필 생성
$ skillmux profile create research
created profile: research (empty)
또는 한 번에 수행하기:
$ skillmux use research --create
프로필 전환
$ skillmux use research
switched: work → research
relinked: ~/.claude/skills, ~/.codex/skills, ~/.agents/skills
이제 모든 에이전트는 research 프로필만 보게 됩니다. work를 위해 설치했던 기술들은 work 프로필에 그대로 남아 있으며, 다시 전환하기 전까지는 보이지 않습니다.
활성화된 프로필 확인
$ skillmux current
research
이것이 루프(loop)입니다. 기기당 한 번의 init, 새로운 컨텍스트가 필요할 때마다 profile create, 전환할 때는 use, 현재 위치를 잊었을 때는 current를 사용하면 됩니다.
프로젝트별 고정 (Per-project pinning)
자주 cd로 들어가는 저장소(repo)의 경우, 루트 디렉토리에 .skillmux.toml 파일을 생성합니다:
profile = "frontend"
agents = ["claude", "codex"]
그 다음 다음 명령을 실행합니다:
skillmux enter
그게 전부입니다. 프로젝트가 skillmux에게 어떤 프로필을 사용할지 알려주는 방식입니다. 자동화를 원한다면 셸(shell)의 chpwd 훅(hook)이나 cd 래퍼(wrapper)에 연결하여 사용하세요.
Skillmux가 하지 않는 것
솔직한 범위(scope)에 대한 메모입니다. 자신이 해결할 수 있는 것보다 더 많은 것을 해결하는 척하는 도구들은 토요일 오전 시간을 낭비하게 만드는 주범이기 때문입니다.
- 아직 Windows를 지원하지 않습니다. Windows의 심볼릭 링크 (Symlink) 의미론은 충분히 다르기 때문에, 어설픈 상태로 배포하고 싶지 않습니다. 이것이 꼭 필요하다면 이슈 (Issue)를 생성하여 사용자의 환경에 대해 알려주세요.
- 기술 (Skills) 간의 의존성 해결 기능이 없습니다. 만약 기술 A가 기술 B를 임포트 (Import)한다면, 그것은 사용자와 기술 작성자 간의 문제입니다. Skillmux는 단지 폴더를 관리할 뿐입니다.
- 레지스트리 (Registry) 또는 패키지 관리 기능이 없습니다. Skillmux는 기술을 설치하지 않습니다. 기존의 설치 흐름 (수동, 설치 프로그램 기반, 마켓플레이스 등)이 이미 있다고 가정하며, 그와 병행하여 프로필 활성화가 작동하도록 만듭니다.
- 기술 검증 또는 샌드박싱 (Sandboxing) 기능이 없습니다. 임의의 코드를 실행하는 기술을 설치한다면, 그 책임은 여전히 사용자에게 있습니다. Skillmux는 파일을 이동할 뿐, 읽지는 않습니다.
- 런타임 데이터 (Runtime data)를 관리하지 않습니다. 세션 (Sessions), 로그 (Logs), 캐시 (Caches), 인증 파일 (Auth files), 셸 히스토리 (Shell histories) 등은 모두 범위 외입니다. Skillmux는 기술 폴더와
~/.skillmux/에 있는 작은 상태 디렉토리 (State directory)만 다룹니다.
이러한 사항의 대부분은 의도적인 것입니다. 모델이 작기 때문에 도구도 작습니다. 프로필 (Profiles), 네이티브 폴더 (Native folders), 가역적 작업 (Reversible operations). 그게 전부입니다.
가역성 (Reversibility)
제가 가장 제대로 구현하고 싶었던 부분은 다음과 같습니다: 백업 매니페스트 (Backup manifest) 없이는 어떠한 파괴적인 작업도 일어나지 않아야 한다는 점입니다.
관리되는 폴더를 건드리는 모든 작업은 ~/.skillmux/backups/<timestamp>-<reason>/ 아래에 TOML 매니페스트를 작성합니다. 백업 목록을 나열할 수 있고, ID를 통해 어떤 백업에서든 복구할 수 있으며, 폴더를 정확히 원래 상태로 되돌리는 방식으로 삭제 (Uninstall)할 수 있습니다.
$ skillmux backup list
20260524-194523-pre-init init: profile work
20260524-211002-pre-create profile create: research
...
uninstall 명령은 동일한 작업을 자동으로 수행하며, 감사를 위해 ~/.skillmux/를 유지합니다. 탈출구 (Escape hatch)는 항상 열려 있습니다. 저는 이 도구가 한 번 도입하면 다시는 빠져나올 수 없는 그런 도구 중 하나가 되는 것을 원하지 않았습니다.
시도해 보세요
만약 이 내용 중 공감 가는 부분이 있다면 — 예를 들어, 에이전트 (Agent)가 잘못된 시점에 잘못된 기술을 제안하고 있거나, ~/.claude/skills 폴더가 머릿속으로 다 파악할 수 없을 정도로 조용히 커져 버렸다면 — 한 번 시도해 보세요.
curl -fsSL https://raw.githubusercontent.com/boringstackoverflow/skillmux/main/install.sh | sh
skillmux init --profile work --yes
Repo: https://github.com/boringstackoverflow/skillmux
Landing page: https://boringstackoverflow.github.io/skillmux/
Docs: https://boringstackoverflow.github.io/skillmux/docs.html
Issue, PR, 그리고 디자인 피드백 모두 환영합니다. 저는 특히 저보다 더 복잡한 토폴로지를 가진 분들의 의견에 관심이 많습니다. 왜냐하면 그곳에서 제 가정이 가장 약하기 때문입니다.
Skillmux는 MIT 라이선스이며, Go 언어로 작성되었고 macOS와 Linux(arm64 + x86_64)용 단일 바이너리로 배포됩니다. boringstackoverflow가 제작했습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기