
내가 Claude Code를 사용하는 방식: 채팅창이 아닌 하나의 시스템으로서
요약
Claude Code를 단순한 채팅 도구가 아닌, 표준과 검증 프로세스가 갖춰진 하나의 시스템으로 활용하는 방법을 다룹니다. 모델의 신뢰성을 높이기 위해 워크플로우, 가드레일, 그리고 비판적 사고를 유도하는 지침 설정의 중요성을 강조합니다.
핵심 포인트
- 모델 자체보다 모델을 둘러싼 시스템의 설계가 신뢰성을 결정함
- 에이전트가 비판적 태도를 유지하도록 CLAUDE.md에 명시적 지침 설정
- 민감 정보 유출 방지를 위한 셸 스크립트 기반의 자동 가드레일 구축
- 반복되는 지시 대신 문서화된 표준(standards)을 통한 워크플로우 관리
신뢰성은 모델에 있는 것이 아닙니다. 모델을 둘러싼 시스템에 있습니다.
지난주 나는 Claude Code를 나의 dotfiles repository로 지정하고, 저장소를 공개하기 전에 개인적인 정보가 유출되지 않도록 확인해 달라고 요청했습니다. Claude Code는 추적 중인 193개의 파일 모두를 전부 읽었습니다. grep(검색)이나 샘플링이 아닌, 메인 세션과 병렬로 실행되는 3개의 리뷰어 에이전트(reviewer agents)로 나뉘어 전체를 읽어 들였습니다. 감사 결과, 단 하나의 실제 문제점이 발견되었습니다. 몇 달 동안 열어보지 않았던 파일 내의 HTML 주석 안에 예시 플레이스홀더(placeholder) 텍스트로 클라이언트의 이름이 포함되어 있었습니다.
그 후 Claude Code는 78개의 에디터 설정 파일들을 나의 개인 저장소로 이동시켰고, 해당 파일들이 존재하지 않았던 것처럼 공개 저장소의 단일 커밋 히스토리(single-commit history)를 다시 작성한 뒤, 강제 푸시(force-push)를 수행했습니다. 이 푸시는 스스로 작성한 가드(guard) 뒤에서 실행되었습니다. 남은 민감한 파일의 개수를 세고, 그 개수가 0이 되지 않으면 푸시를 거부하는 몇 줄의 셸(shell) 스크립트였습니다.
이 모든 일이 모델이 똑똑해서 일어난 것이 아닙니다. 모델은 어디에서나 똑똑하지만, 거의 어디에서도 신뢰할 수 없습니다. 이 일은 내가 몇 달 동안 구축해 온 시스템 안에서 세션이 실행되었기 때문에 가능했습니다. 즉, 문서화된 표준(standards), 패키지화된 워크플로우(workflows), 되돌릴 수 없는 모든 작업에 대한 인간의 승인 단계(human gates), 모든 주장 전의 검증(verification), 그리고 세션보다 오래 지속되는 메모리(memory)가 갖춰진 시스템 말입니다. 이 글은 그 시스템을 형성한 실제 에피소드들과 함께 해당 시스템을 둘러보는 여정입니다.

표준을 한 번 작성해 두세요
Claude Code가 모든 세션에서 불러오는 지침 파일인 나의 글로벌 CLAUDE.md는 다음 문장으로 시작합니다:
"나에게 항상 옳다고 말하지 마세요. 비판적이 되세요. 우리는 대등한 관계입니다."
그 문장은 내가 아는 그 어떤 프롬프트 기법보다 더 큰 역할을 합니다. AI 어시스턴트의 기본적인 실패 모드는 '동조(agreement)'입니다. 당신이 평범한 제안을 하면, 모델은 당신을 축하하며 그것을 구현해 버립니다. 회의론(skepticism)을 기본 규칙으로 설정하면 어시스턴트는 반론을 제기하는 동료로 변모하며, 이는 단순히 항상 그 자리에 존재하기 때문에 지속적인 비용이 들지 않습니다.
이것이 이 글의 다른 모든 내용 뒤에 깔린 패턴입니다. 만약 당신이 에이전트에게 같은 말을 두 번 하고 있다는 것을 깨닫는다면, 대신 한 번만 기록해 두세요.
헌법(constitution)은 의도적으로 얇게 유지됩니다. 상세한 표준은 언어별 규칙 파일(php.md, javascript.md, rust.md, git.md 등)에 존재하며, 헌법은 이를 참조하기만 합니다. 에이전트는 작업이 해당 규칙과 일치할 때 규칙 파일을 로드합니다. Rust 질문이 나의 Laravel 컨벤션(conventions)에 대한 토큰 비용을 지불할 일은 결코 없습니다. 이러한 점진적 공개(progressive disclosure) 패턴은 각 프로젝트 내부에서도 반복됩니다. 프로젝트의 CLAUDE.md는 실제 계약 세부 사항이 담긴 스펙(spec) 파일들을 가리키는 얇은 기능 테이블을 보유합니다. 이제 컨텍스트 윈도우(context windows)는 커졌지만, 공짜는 아닙니다. 관련 없는 규칙들로 컨텍스트가 가득 찬 에이전트는 중요한 규칙을 적용하는 능력이 측정 가능한 수준으로 떨어집니다.
사람들이 놓치는 두 가지 세부 사항이 있습니다. 첫째, 규칙은 코드 스타일에 관한 것만이 아닙니다. 나의 규칙 파일에는 머신 지식(machine knowledge)도 담겨 있습니다. 로컬 도메인이 어떻게 서빙되는지, 데이터베이스가 어디에 있는지, git 워크트리(worktrees)가 URL에 어떻게 매핑되는지 등이 포함됩니다. 이를 통해 에이전트는 이 글의 뒷부분에서 설명할 것처럼, 별도의 지시 없이도 앱의 격리된 복사본을 실행하고 브라우저 테스트를 수행하는 방법을 알게 됩니다. 둘째, 지식이 어디에 저장되는지에 대한 규율이 있습니다. 영구적이고 공유 가능한 모든 것은 버전 관리되는 헌법이나 스펙에 들어갑니다. 에이전트의 개인 메모리는 저장소(repo)에 속하지 않는 것만을 위한 것입니다.
다음은 요약된 실제 규칙의 한 예시입니다:
결론이 어떤 요소의 존재 여부에 달려 있는 경우,
단언하기 전에 명령의 전체 출력(full output)을 읽으세요.
상태 명령을 tail, head 또는 좁은 범위의 grep으로 파이프(pipe)한 뒤
결론을 내리지 마세요...
그리고 맞습니다, 헌법(constitution)은 에이전트가 작성하는 모든 내용에서 엠 대시(em dash)와 이모지(emoji) 사용을 금지합니다. 엠 대시는 AI가 생성한 텍스트임을 나타내는 가장 눈에 띄는 특징이며, 이 금지 조치는 더 평이한 문장을 쓰도록 강제합니다. 이 글 또한 동일한 규칙을 따릅니다.
그 대가는 눈에 보이지 않지만, 그것이 핵심입니다. 모든 세션과 모든 프로젝트는 제가 어떻게 일하는지를 이미 알고 있는 상태에서 시작됩니다. 저는 몇 달 동안 모델에게 저의 포맷팅 선호도, git 에티켓, 또는 테스트 컨벤션(testing conventions)을 설명한 적이 없습니다.
반복되는 작업을 기술(skills)로 패키징하기
표준(Standards)은 에이전트가 어떻게 행동하는지를 다룹니다. 기술(Skills)은 에이전트가 무엇을 할 줄 아는지를 다룹니다. Claude Code에서의 기술은 적용 시점에 대한 설명과 따라야 할 절차가 담긴 마크다운(markdown) 파일이며, 에이전트는 작업이 해당 설명과 일치할 때 이를 로드합니다. 에이전트가 실제로 실행할 수 있는 런북(runbook)이라고 생각하면 됩니다.
제가 가진 기술에는 SSH를 통해 프로덕션 플릿(production fleet)을 점검하는 서버 감사(nginx, PHP-FPM, MySQL, Redis, 백업, 보안 태세), 디프 헝크(diff hunks) 대신 브랜치를 체크아웃하고 파일 전체를 읽는 머지 리퀘스트(merge request) 리뷰, 버그 진단 루프, 인시던트 조사 플레이북(incident investigation playbook), 그리고 계획이 무너질 때까지 심문하는 것이 유일한 임무인 'grilling'이라는 기술이 포함됩니다. 각각의 기술은 제가 스스로 두 번째 설명하고 있다는 것을 깨달은 작업에서 시작되었습니다. 프론트매터(frontmatter)가 전체 트리거 메커니즘이며, 이것이 제 MR 리뷰 기술의 실제 헤더입니다:
---
description: "브랜치를 체크아웃하고 전체 파일 내용을 읽음으로써 GitLab MR 또는 GitHub PR을 리뷰합니다. 리뷰를 게시할 수도 있습니다..."
...
제가 모든 기술을 직접 작성한 것은 아닙니다. 커뮤니티 팩(Community packs)은 에디터 플러그인과 동일한 방식으로 공개 플러그인 마켓플레이스에서 설치할 수 있습니다. 단 하나의 팩(superpowers: github.com/obra/superpowers)만으로도 브레인스토밍, 테스트 주도 개발(TDD), 체계적인 디버깅, 그리고 성공에 대한 어떤 주장보다도 증거를 요구하는 검증 규율을 제공합니다. 오늘 시작하신다면, 무언가를 구축하기 전에 먼저 설치하십시오.
사람들을 놀라게 하는 한 가지 선호 방식은, CLI (Command Line Interface) 도구와 MCP (Model Context Protocol) 서버가 모두 존재할 때 저는 CLI를 선택한다는 점입니다. MCP는 외부 도구를 에이전트(agent)에 직접 연결하기 위한 프로토콜이며 진정으로 유용하지만, 서버의 도구 스키마(tool schemas)는 사용 여부와 관계없이 모든 세션에서 컨텍스트(context)를 차지합니다. 반면 CLI는 호출되는 순간에만 토큰을 소모하며, 권한 범위(permission-scope)를 지정하기도 더 쉽습니다. 따라서 GitHub 서버 대신 gh나 glab을 사용하고, 브라우저 서버 대신 브라우저 자동화 CLI를 사용합니다. 속도와 토큰 예산(token budget) 측면 모두에서 이득입니다.
제가 가장 많이 사용하는 기술은 가장 작은 기술이기도 합니다. later는 후속 메모를 현재 프로젝트의 노트 파일에 보관하는 아주 작은 셸(shell) 명령입니다. 전체 저장 메커니즘은 추가 경로로부터 단 세 줄로 구성됩니다:
local file="$PWD/$NOTES_FILE_NAME"
[ -f "$file" ] || printf '%s\n\n' "$NOTE_HEADING" > "$file"
printf -- '- [ ] %s\n' "$note" >> "$file"
에이전트가 한 터미널에서 작업 중간에 있을 때, 저는 다른 터미널에서 later "check the failing seeder"라고 입력하며, 어떤 작업도 중단되지 않습니다. 세션이 유휴 상태(idle)가 될 때 Claude Code가 실행하는 스크립트인 Stop hook이 대기열을 감시하다가 상황이 진정되면 이를 다시 불러옵니다. 이로 인해 후속 작업들이 제 머릿속에만 머물지 않게 되며, 이를 기록하는 과정이 진행 중인 작업을 방해하는 일도 없어집니다.
되돌릴 수 없는 작업에 게이트(Gate) 설치하기
지금까지 언급한 모든 것은 에이전트가 자유롭게 행동할 수 있는 영역입니다. 다음 단계는 에이전트가 절대로 자유롭게 해서는 안 되는 일들, 즉 동작 계약(behavior contracts) 변경, git 히스토리 수정, 코드 배포 등에 관한 것입니다.
중요한 변경 사항은 OpenSpec(github.com/Fission-AI/OpenSpec)을 통해 진행됩니다. 이는 사양(specifications)이 저장소 내의 버전 관리되는 파일이며, 모든 동작 변경이 사양에 대한 제안된 델타(delta)로 시작되는 사양 주도 워크플로우(spec-driven workflow)입니다. 저는 기본 아티팩트 세트(제안, 설계, 작업, 사양 델타)에 요약 아티팩트를 확장하는 커스텀 스키마를 사용하여 이를 운영합니다.
새로운 기능은 다음의 7단계를 거칩니다:
- 브레인스토밍 (Brainstorm). 브레인스토밍 (Brainstorming) 기술이 의도, 제약 조건, 성공 기준이 명확해질 때까지 한 번에 하나씩 질문을 던지며 저를 인터뷰합니다.
- 검증 (Grill). 검증 (Grilling) 기술은 설계에 대해 적대적으로 공격합니다: 엣지 케이스 (edge cases), 레이스 컨디션 (race conditions), 잘못된 가정 등을 파고듭니다. 살아남은 계획만이 구축됩니다.
- 제안 (Propose). 에이전트가 제안, 설계, 작업, 그리고 사양 델타 (spec deltas)를 생성합니다. 제가 검토한 후 커밋 (commit)합니다.
- 적용 (Apply). 에이전트가 작업을 구현합니다. 제가 검토한 후 커밋 (commit)합니다.
- 푸시 (Push), 풀 리퀘스트 (pull request) 생성, 그리고 다른 모델 제품군 (model family)을 실행하는 자동 리뷰어인 PR-Agent (github.com/The-PR-Agent/pr-agent)가 이를 리뷰하도록 합니다. 본인의 풀 리퀘스트를 직접 리뷰해서도 안 됩니다.
- 리뷰에서 발견된 사항을 수정하고, 깨끗한 결과가 나올 때까지 5단계를 반복합니다.
- 아카이브 (Archive). 사양 델타 (spec deltas)가 정식 사양 (canonical specs)으로 통합되면, 커밋 (commit)하고 푸시 (push)합니다. 이제 풀 리퀘스트는 최종 인간 관문인 리뷰 및 머지 (merge)를 위한 준비가 완료되었습니다.
두 가지 요소가 이 과정을 단순한 의식 그 이상으로 만듭니다. 첫째, 모든 단계의 경계는 인간의 관문이자 커밋 (commit)입니다. 에이전트는 제안을 생성하고 멈추며, 구현하고 멈춥니다. 에이전트는 스스로 계속할 권한을 절대 부여하지 않는데, 건너뛸 수 있는 리뷰 지점은 리뷰 지점이 아니기 때문입니다. 둘째, 5단계의 서로 다른 모델을 통한 리뷰는 편집증이 아니라 관점의 의도적인 중복 (redundancy)입니다. 다르게 훈련된 모델들은 서로 다른 사각지대를 가지고 있습니다. 리뷰어는 작성자 모델이 볼 수 없는 것을 잡아냅니다.
이 모든 것의 밑바탕에는 git 규칙이 자리 잡고 있습니다. 에이전트는 요청받지 않는 한 절대 브랜치 (branch)를 생성하지 않고, 커밋 (commit)하지 않으며, 푸시 (push)하지 않고, 무엇보다 강제 푸시 (force-push)를 하지 않습니다. 감사 (audit) 중에 에이전트가 제 dotfiles 히스토리를 다시 작성했을 때, 에이전트는 먼저 정확히 두 가지 질문을 던졌습니다 (amend 및 force-push를 할까요? 두 번째 리포지토리에서도 파일을 untrack 할까요?). 그리고 푸시 자체는 다음과 같은 가드 (guard) 뒤에서 실행되었습니다:
if [ "$leftover" -eq 0 ] && [ "$leak" -eq 0 ]; then
git push --force-with-lease origin main
else
...
그 두 변수는 푸시(push)하려는 트리(tree) 내에 남겨진 개인 파일과 유출된 클라이언트 이름의 개수를 계산했습니다. 만약 두 값 중 하나라도 0이 아니었다면, 아무것도 이동하지 않았을 것입니다. 모델을 신뢰하되, 그 신뢰를 if 문에 연결하십시오.
필요할 때만 알 수 있는 비밀 정보 (Secrets on a need-to-know basis)
이 글을 시작하는 감사(audit) 과정에서는 찾을 비밀 정보가 없었기 때문에 모든 추적된 파일(tracked file)을 안전하게 읽을 수 있었습니다. 이것은 운이 아닙니다. 설계(architecture)입니다.
공개 저장소(public repo)의 .gitignore는 기본적으로 거부(deny)합니다. 첫 번째 규칙은 모든 경로를 무시하며, 각 추적된 파일은 이름에 의해 다시 포함(re-include)됩니다. 새로운 파일이 무엇이든(토큰, 세션 덤프, 에디터 상태 파일 등), 실수로 버전 관리(version control)에 들어가는 것은 물리적으로 불가능합니다. 반드시 의도적으로 허용 목록(allowlist)에 추가되어야 합니다. 머신 및 클라이언트 관련 세부 정보는 두 번째 프라이빗 저장소(private repository)에 존재하며, 링크 스크립트가 이를 적절한 위치에 심볼릭 링크(symlink)로 연결합니다. 공개 저장소에는 심볼릭 링크조차 남지 않으며, 그 어떤 흔적도 남기지 않습니다.
런타임 비밀 정보(Runtime secrets) 또한 1Password를 통해 동일한 최소 권한(least-privilege) 로직을 따릅니다. 에이전트의 op CLI는 에이전트 전용으로 생성된 단 하나의 볼트(vault)에만 접근 권한을 부여하는 서비스 계정(service account)으로 인증됩니다. 저의 개인 볼트는 에이전트에게 보이지 않습니다. 해당 볼트에 비밀 정보를 넣는 것은 키링(keyring) 전체를 넘겨주는 대신 단 하나의 열쇠를 건네주는 것과 같은 의도적인 행위입니다. 에이전트가 자격 증명(credential)이 필요할 때, op read를 통해 런타임에 이를 가져오므로, 값은 프로세스 환경(process environment)을 통해 전달될 뿐 커밋된 파일이나 세션의 기본 컨텍스트(default context)에 절대 남지 않습니다.
이 중 어느 것도 생소한 것이 아닙니다. 이는 여러분이 이미 CI 러너(CI runner)에 적용하고 있는 규율을, 새로운 종류의 동료에게 적용하는 것뿐입니다. 매우 유능하지만 신중함(discretion)이라는 개념이 없는 동료 말입니다. 동료에게 정확히 필요한 것만 제공하십시오. 그러면 전체 저장소(full-repo)를 읽을 수 있다 하더라도, 애초에 존재하지 않았던 정보는 유출될 수 없습니다.
확산(Fan out), 검증, 그리고 실제 테스트
193개의 파일을 순차적으로 읽는 하나의 에이전트(agent)는 속도가 느릴 뿐만 아니라, 더 심각하게는 자신의 컨텍스트(context)를 노이즈로 가득 채우게 됩니다. 그래서 감사(audit) 과정에서는 작업을 분할했습니다. 세 개의 서브 에이전트(subagents, 메인 에이전트가 생성하고 조정할 수 있는 독립적인 에이전트 세션)가 각각 트리의 일부분을 맡아 파일들을 완전히 읽어 들였고, 메인 세션은 셸 초기화 파일(shell init files), git 자격 증명 설정(git credentials configuration), 도구 설정(tool settings)과 같이 민감하고 판단력이 요구되는 파일들을 직접 관리했습니다. 서브 에이전트들은 발견 사항을 보고했고, 메인 세션은 이를 검증했습니다.
확산(Fan-out)은 읽기 작업에만 국한되지 않습니다. 저의 일부 서브 에이전트들은 자신만의 지침을 가진 전문가들입니다. 예를 들어 Laravel 디버거, 기능 빌더(feature builder), 코드 단순화 도구(code simplifier) 등이 있습니다. 좁은 범위의 과업(brief)과 깨끗한 컨텍스트를 가진 전문가는 전체 세션을 뒤에 끌고 다니는 범용 에이전트(generalist)를 정기적으로 압도합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기