
『실전 Claude Code 입문 ― 현장에서 활용하기 위한 AI 코딩 사고법』의 요점
요약
Claude Code의 효율적인 활용을 위한 컨텍스트 관리 전략과 설계 원칙을 소개합니다. 'Progressive Disclosure' 원칙에 따라 계층적 구조로 컨텍스트를 단계적으로 제공하여 성능 저하를 방지하는 방법을 다룹니다.
핵심 포인트
- CLAUDE.md를 활용한 계층적 컨텍스트 관리
- 컨텍스트 롯(Context Rot) 및 성능 저하 방지 전략
- Subagent를 통한 전문 태스크 및 컨텍스트 분리
- 대화 이력 리셋(/clear) 및 불필요한 파일 읽기 지양
아래의 책이 매우 이해하기 쉽고 실용적이어서 정리해 보았습니다. 실제로는 제가 요점을 작성하고, 그 요점을 바탕으로 Claude가 내용을 보강한 문장입니다.
니시미 키미히로(西見公宏)・요시다 신고(吉田真吾)・오시마 유키(大嶋勇樹) 저 / 기술평론사(技術評論社) / 2025년 12월 발매
본 기사의 대상은 "Claude Code를 쓰고는 있지만, 어쩌다 보니 쓰고 있는 상태. 공식 문서(Official Documentation)는 거의 읽어본 적이 없는" 분들입니다.
「필요할 때 필요한 만큼만 컨텍스트(Context)를 읽히는」 설계 원칙.
LLM의 컨텍스트 윈도우(Context Window)는 유한하며, 처음부터 모든 정보를 채워 넣으면 후술할 「컨텍스트 롯(Context Rot)」을 초래한다. 따라서 Claude Code는 다음과 같은 계층 구조로 컨텍스트를 단계적으로 읽히는 메커니즘을 갖는다.
| 층 | 역할 | 읽히는 타이밍 |
|---|---|---|
CLAUDE.md (프로젝트 루트) | 프로젝트 전체의 전제·규약 | 세션 시작 시 상시 |
CLAUDE.md (서브 디렉토리) | 서브 모듈의 규약 | 해당 디렉토리의 파일을 다룰 때 |
Skill (SKILL.md) | 「어떻게」 할 것인가에 대한 절차서 | LLM이 필요하다고 판단했을 때 자동 로드 |
| Subagent | 전문적인 역할을 가진 별도의 에이전트 | 명시적으로 호출되었을 때 |
| 파일 본체 | 구현 상세 | Read 툴로 참조했을 때 |
보충: 이 사상은 Anthropic의 공식 문서에서도 "Progressive Disclosure"로 설명되어 있으며, Skill의 SKILL.md 자체에는 개요만 작성하고 상세 내용은 별도 파일로 나누어 필요할 때 참조하게 하는 것이 베스트 프랙티스(Best Practice)로 여겨진다.
샘플: 단계적 명시를 의식한 CLAUDE.md (클릭하여 전개)
# 프로젝트 개요
EC 사이트의 백엔드 API. Python 3.12 + FastAPI + PostgreSQL.
## 중요한 규약 (상시 참조)
...
docs/
이하는 처음부터 읽히지 않고, 필요해진 타이밍에 Claude가 자발적으로 읽으러 가는 설계.
컨텍스트가 압박받으면 LLM 자체의 성능이 저하되는 현상.
긴 대화 이력이나 대량의 파일 읽기로 컨텍스트 윈도우가 가득 차면, 다음과 같은 문제가 나타난다.
- 지시 사항 누락 (전반부의 중요한 제약 조건을 잊음)
- 추론 품질 저하 (복잡한 판단을 할 수 없게 됨)
- 할루시네이션 (Hallucination) 증가
- 오래된 문맥과 새로운 문맥의 혼선
보충: 일반적으로 「Lost in the Middle」 현상으로도 알려져 있으며, 컨텍스트 중간에 있는 정보일수록 무시되기 쉽다. Anthropic Research에서도 긴 컨텍스트에서의 정확도 저하는 확인된 바 있다.
/clear를 사용하여 (태스크가 전환되는 타이밍에) 수시로 대화 이력을 리셋
- Subagent를 활용하여 컨텍스트를 분리한다
- 불필요한 파일 읽기를 피한다 (grep으로 대상을 파악한 후 Read 하는 등)
- 장대한 로그나 출력은 요약시킨 후 다음 턴으로 넘긴다
메인 에이전트의 컨텍스트를 오염시키지 않기 위해, 전문적·대량의 컨텍스트를 필요로 하는 태스크는 별도의 에이전트로 분리한다.
서브 에이전트는 독립된 컨텍스트 윈도우를 가지며, 태스크 완료 후에는 결과(요약)만 메인으로 반환된다. 즉 "메인 입장에서는 1회의 툴 호출로 보인다"ため, 컨텍스트 효율이 극적으로 좋아진다.
리뷰는 다음과 같은 이유로 컨텍스트를 격하게 소비한다:
- 여러 파일의 전문 읽기가 필요함
- diff의 전후를 이해하기 위해 넓은 범위를 봄
- 정적 분석·테스트 출력 등 외부 툴 결과가 대량으로 흘러 들어옴
이를 메인 코딩 에이전트에게 직접 시키면, 리뷰 후 수정 단계에서 "방금 리뷰한 코드의 상세 내용"이 컨텍스트에서 밀려나는(Push out) 문제가 발생한다.
샘플: 리뷰 전용 서브 에이전트 정의 .claude/agents/reviewer.md (클릭하여 전개)
---
name: reviewer
description: 코드 변경 리뷰 전용. 차분(diff)과 테스트 결과를 읽고, 지적 사항 리스트만 반환한다.
...
이를 통해 메인 에이전트에는 「리뷰 지적 리스트」라는 압축된 정보만 돌아오며, 컨텍스트가 보존된다.
Skill이나 명령어, CLAUDE.md를 작성할 때 가장 중요한 원칙을 먼저 기술한다.
LLM은 「명시되지 않은 것」을 기본적으로 선택 사항(Optional)으로 해석한다.
즉:
- 「가능하다면 테스트도 작성해 주세요」 → 작성되지 않을 가능성이 높음
- 「할 수 있다면 롤백 절차도 준비」 → 준비되지 않을 가능성이 높음
- 「여유가 된다면 문서도 업데이트」 → 99% 업데이트되지 않음
- 「~할 수도 있습니다」 → 거의 채택되지 않음
이는 Claude가 태만하게 행동하는 것이 아니라, 「선택 사항 = 하지 않아도 된다」라고 해석하여 컨텍스트 (Context)를 절약하려는 합리적인 동작이다. 후술할 컨텍스트 롯 (Context Lot)을 피하기 위해서라도, LLM은 옵션을 스킵하는 경향이 있다.
| ❌ 선택 사항으로 취급되는 방식 | ✅ 필수 사항으로 취급되는 방식 |
|---|---|
| 가능하다면 테스트를 추가한다 | 테스트를 반드시 추가한다 |
| ... | ... |
반대로, 정말로 선택 사항이어도 괜찮은 경우에는 명시적으로 「선택 사항」이라고 적을 것. 적지 않으면 에이전트가 「이것은 필수인가? 선택 사항인가?」라고 추측하게 되어 결과가 흔들린다.
(선택 사항) 성능 측정 로그를 추가해도 좋다. 추가할 경우에는 `metrics.timer()`를 사용한다.
이 원칙을 바탕으로, 다음 샘플은 모두 「필수/선택/금지」를 명시한 스타일로 작성한다.
3.1과 나란히 중요한 것이, 규칙이 충돌했을 때의 우선순위를 명시해 두는 것이다.
실제 프로젝트의 문서, Skill, CLAUDE.md는 작성되어 가는 과정에서 반드시 모순이나 트레이드오프 (Trade-off)가 발생한다.
- 「테스트를 반드시 작성한다」라고 적혀 있지만, 「최소한의 차분 (Diff)으로 수정한다」라고도 적혀 있다 → 대량의 테스트 추가는 최소한의 차분인가?
- 「타입 힌트 (Type Hint)를 반드시 붙인다」라고 적혀 있지만, 「서드 파티 (Third-party) 라이브러리의 타입이 깨져 있을 때는 어떻게 하는가?"
- 「보안 최우선」, 「성능 최우선」이 모두 적혀 있다 → 어느 쪽이 위인가?
이를 명시해 두지 않으면, Claude는 매번 그 자리에서 추측하게 되어 결과가 안정되지 않는다. 더욱 나쁜 점은, 컨텍스트의 상태에 따라 판단이 달라지기 때문에 같은 지시라도 어제와 오늘 결과가 달라지는 재현성 부족으로 이어진다는 것이다.
## 설계 방침의 우선순위 (위쪽이 우선)
1. 보안
2. 데이터 정합성
...
이렇게 해두면 「성능을 위해 타입 체크를 생략해도 돼?」라고 물었을 때, Claude는 「순위 3 > 순위 4 이므로 NG」라고 판정할 수 있다.
## 충돌 시의 규칙
- 「테스트 필수」와 「최소 차분」이 충돌할 경우: **테스트 필수 우선**
- 즉, 테스트를 작성하기 위해 코드 변경량이 늘어나는 것은 허용함
...
## 판단이 어려울 경우의 최종 규칙
위의 우선순위로도 판단할 수 없는 경우에는, **임의로 결정하지 말고 사용자에게 확인한다.**
특히 다음 케이스는 반드시 확인:
...
이는 「우선순위를 전부 다 적는 것은 불가능하다」라는 현실에 대한 대처이다. 「명시되지 않은 케이스 = 질문한다」를 명시해 두는 것이 핵심이다.
# 프로젝트 규약
## 규약의 우선순위 (충돌 시 위쪽을 우선)
1. **보안 규칙** (`docs/security.md`)
...
| 상황 | 우선순위 없음 | 우선순위 있음 |
|---|---|---|
| 「테스트 필수」와 「최소 차분」 | 테스트를 생략하여 최소 차분으로 만들거나, 반대의 경우가 생기는 등 매번 흔들림 | 반드시 테스트를 작성한다, 라고 일의적으로 결정됨 |
| ... | ... |
- 대방침 (보안/정합성/가독성/성능 등)의 순위를 적었는가
- 과거에 프로젝트에서 실제로 충돌했던 개별 규칙들 사이의 관계를 적었는가
- 「망설여지면 사용자에게 확인」이라는 가이드라인을 적었는가
- Skill 내의 규칙들끼리 충돌할 수 있는 경우, Skill 내에서도 우선순위를 적었는가
| Skill | 커맨드 (Command) | |
|---|---|---|
| 작성 내용 | "How" (어떻게 생각하고/만들 것인가) | "What & Order" (무엇을 어떤 순서로 실행할 것인가) |
| 호출 방식 | LLM이 문맥(Context)으로부터 자동 판단하여 호출 | 사용자가 /커맨드명으로 명시적으로 호출 |
| 재사용 단위 | 지식 · 노하우 · 규약 | 절차 · 워크플로우 (Workflow) |
| 배치 위치 | .claude/skills/<name>/SKILL.md | .claude/commands/<name>.md |
| 발화 타이밍 | 관련 작업을 하고 있을 때, 언제든 | 커맨드를 입력했을 때, 그때만 |
| 인자 (Argument) | 없음 (문맥에서 판단) | 있음 ($ARGUMENTS로 받을 수 있음) |
이 차이점을 동일한 "버그 수정"이라는 상황에서 대비해 본다.
"사용자로부터 결함 보고를 받았을 때, 어떻게 생각하고 어떻게 움직일 것인가"라는 노하우. 언제 호출될지는 Claude가 문맥(Context)으로부터 판단한다.
파일: .claude/skills/bug-fixing/SKILL.md
샘플: bug-fixing Skill의 내용 (클릭하여 펼치기)
---
name: bug-fixing
description: 버그 수정에 임할 때의 사고법. "버그가 있다", "작동하지 않는다", "에러가 발생한다", "결함", "고쳐줘"와 같은 요구가 있으면 사용한다. 재현 → 특정 → 수정 → 재발 방지 순으로 진행하는 방침을 제공한다.
...
```diff
+ # tests/test_user.py
+ def test_create_user_with_empty_email_raises_error():
+ with pytest.raises(ValidationError):
+ create_user(email="")
+
# app/user.py
def create_user(email: str):
+ if not email:
+ raise ValidationError("email is required")
...
- ❌ 테스트를 작성하지 않고 수정하기
- ❌ try-except로 에러를 뭉개버리기 (swallow error)
...
</details>
**여기가 포인트**: 사용자가 "로그인이 안 되는데"라고 말하는 것만으로, Claude가 `description`을 보고 "이것은 버그 수정 건이구나"라고 판단하여 이 Skill을 자동으로 읽어들인다. **사용자는 Skill의 존재를 의식할 필요가 없다.**
또한, **"필수/권장/임의/금지"를 명시적으로 나누어 작성했다**는 점에 주목하라. 이를 통해 Claude는 "ADR 기안은 하지 않아도 되지만, 재현 테스트는 반드시 수행한다"라고 확실하게 판정할 수 있다.
---
#### 🅱️ 커맨드로 작성하는 경우 ("정해진 절차"를 실행하는 버그 보고 대응)
"Issue가 올라오면 반드시 이 순서로 움직인다"라는 고정 워크플로우 (Workflow). **사용자가 명시적으로 호출한다.**
파일: `.claude/commands/fix-bug.md`
<details>
<summary>샘플: /fix-bug 커맨드의 내용 (클릭하여 펼치기)</summary>
```markdown
---
description: 지정된 Issue 번호의 버그를 수정하는 표준 플로우
---
...
```bash
gh issue view $ARGUMENTS --json title,body,labels
git checkout main
git pull
git checkout -b fix/issue-$ARGUMENTS
bug-fixing
...
git grep -n "<해당 함수명이나 패턴>"
유사한 패턴이 발견된 경우, 사용자에게 보고하고 지시를 구한다 (임의로 수정하지 않는다).
git add .
git commit -m "fix: <Issue 타이틀> (#$ARGUMENTS)"
gh pr create --title "fix: ..." --body "Closes #$ARGUMENTS"
- PR URL을 보고
- 추가한 테스트 이름을 보고
...
</details>
**핵심 포인트**: `/fix-bug 1234`를 실행하면, **매번 동일한 8단계가 동일한 순서로** 진행된다. Step 3 과정에서 `bug-fixing` Skill이 자동으로 참조된다 (Claude가 판단하여 호출).
모든 단계에 **「필수」라고 명시**하고, 건너뛸 수 있는 작업만을 「임의 단계」로 분리했다. 이를 통해 에이전트가 「이번에는 PR 생성을 안 해도 되겠지」라고 멋대로 판단하는 사고를 방지할 수 있다.
---
### 3.5 양자의 관계: 「커맨드는 절차, Skill은 각 단계의 사고법」
위의 예에서 중요한 것은, **커맨드(Command)와 Skill은 충돌하지 않으며 레이어(Layer)가 다르다**는 점이다:
사용자: /fix-bug 1234
...
즉,
- **커맨드 (Command)** = 레시피의 「작업 절차」 부분 (물을 끓인다 → 면을 넣는다 → 3분 기다린다)
- **Skill** = 레시피의 「요령·원칙」 부분 (면수는 버리지 않는다, 소금을 넣는 양, 불 조절)
두 가지가 모두 갖춰져야 비로소 재현성 있는 맛있는 요리(=의도대로의 구현)를 할 수 있다.
---
### 3.6 또 다른 대조 사례: 「DB 마이그레이션 (DB Migration)」
다른 소재에서도 동일한 구조가 보이는지 확인한다.
| | Skill: `db-migration` | 커맨드: `/add-migration` |
|---|---|---|
| **내용** | 「마이그레이션을 작성할 때의 방침」 (파괴적 변경은 2단계로, 롤백(Rollback) 필수, 대규모 테이블은 협의 필요 등) | 「마이그레이션 파일을 만들고, 로컬 DB에서 시도하여, 테스트가 통과하는 것을 확인하기까지의 일련의 절차」 |
| ... |
#### 🅰️ Skill 발췌 (“How”만 작성 · 필수와 임의를 명시)
<details>
<summary>샘플: db-migration Skill 발췌 (클릭하여 전개)</summary>
```markdown
---
name: db-migration
description: DB 스키마 변경 시의 방침. "컬럼 추가", "테이블 생성", "마이그레이션", "스키마 변경" 이야기가 나오면 사용한다.
...
샘플: /add-migration 커맨드 발췌 (클릭하여 전개)
---
description: 새로운 마이그레이션 파일을 생성하고 검증한다
---
...
커맨드 측은 절차만 작성하고, 각 절차의 내용(특히 2번의 「어떻게 작성할 것인가」)은 Skill에 완전히 맡기고 있다. 이것이 이상적인 분업이다.
「Skill로 해야 할지, 커맨드로 해야 할지」 고민된다면, 다음 질문을 순서대로 던져보라:
- 「사용자가 명시적으로 호출하고 싶은가?」 → Yes라면 커맨드
- 「동일한 절차를 매번 밟는가?」 → Yes라면 커맨드
- 「인자(Argument)를 받고 싶은가?」 → Yes라면 커맨드
- 「여러 다른 문맥에서 (반복해서) 참조되는 노하우인가?」 → Yes라면 Skill
- 「"사고법"이나 "규약"을 전달하고 싶은가?」 → Yes라면 Skill
- 「템플릿/샘플과 함께 전달하고 싶은 지식인가?」 → Yes라면 Skill
두 가지 모두에 해당하는 경우도 많다. 그럴 때는 둘 다 만들어서 연계시키는 것이 정답이다 (앞서 언급한 버그 수정 예시처럼).
그리고 둘 다, 「필수/권장/임의/금지」를 명시적으로 적는 것을 잊지 마라. 적지 않으면 Claude는 이를 「임의」로 취급한다.
본서의 메모에도 있듯이, 샘플을 작성해 두면 다음과 같은 메리트가 있다.
- 컨텍스트(Context)의 압박 방지 — 에이전트가 「어떻게 작성해야 하는지」 별도로 찾아볼 필요가 없어진다.
- 의도한 구현이 될 확률 상승 — 퓨샷 러닝 (Few-shot learning) 관점에서 샘플 형식에 맞춘 출력이 나오기 쉬워진다.
- 새로운 멤버 (사람)에게도 읽기 쉬움
샘플은 「규약에 따른 올바른 예」와 「해서는 안 될 예」를 둘 다 작성하면 더욱 의도대로 작동하기 쉽다 (단정적인 문체로 작성하더라도, 나쁜 예를 명시하면 정밀도가 더욱 올라간다).
Bad (모호하며, 필수·임의·금지가 불분명함):
---
name: write-test
description: 테스트를 작성한다
...
문제점:
description이 너무 짧아 트리거(Trigger)되지 않을 가능성이 높음- 「가급적」, 「가능하다면」 등이 임의로 해석되어, 작성되지 않거나 대충 작성됨
- 규약·샘플이 없으므로 출력 포맷이 매번 흔들림
Good(명시적・샘플 포함):
샘플: write-test Skill의 내용 (클릭하여 펼치기)
---
name: write-test
description: pytest를 사용한 유닛 테스트 (Unit Test)를 작성한다. "테스트 추가해줘", "테스트 써줘", "유닛 테스트"라고 말하면 사용한다.
...
```python
# tests/unit/test_calculator.py
import pytest
from app.calculator import divide
def test_divide_normal_returns_quotient():
# Arrange
a, b = 10, 2
# Act
result = divide(a, b)
# Assert
assert result == 5
def test_divide_by_zero_raises_value_error():
with pytest.raises(ValueError, match="cannot divide by zero"):
divide(10, 0)
# ❌ 하나의 함수에 여러 시나리오를 몰아넣고 있음
def test_divide():
assert divide(10, 2) == 5
assert divide(10, 0) # 예외를 기대하고 있을 텐데 어서트 (Assert)가 없음
# ❌ 함수명만 봐서는 무엇을 테스트하는지 알 수 없음
def test_1():
...
</details>
---
## 4. 권한 승인이 번거로운 경우에는 Sandbox를 검토할 것
### 4.1 「승인 피로」라는 현실적인 문제
Claude Code는 「실행했을 뿐으로는 시스템을 변경하지 않는다」는 설계 덕분에, Bash 실행·파일 편집·Web Fetch 등 부작용 (Side Effect)을 동반하는 조작에는 **매번 사용자의 승인**이 필요하다. 이는 보안 원칙으로서 올바른 방향이지만, 실제로 사용해 보면 다음과 같은 문제에 직면한다.
- 루프적인 작업 (lint를 실행 → 수정 → 다시 lint...) 과정에서 매번 승인 다이얼로그가 나타남
- `npm install`과 같이 자식 프로세스 (Child Process)가 대량으로 실행되는 처리에서 승인이 연쇄적으로 발생함
- 「허가할 것이 분명한」 조작의 승인에 주의력을 빼앗겨, 정말 위험한 조작의 승인을 소홀히 하게 됨 (**경고 피로**)
`allow` 리스트를 넓히면 승인은 줄어들지만, 이번에는 **의도하지 않은 파괴적인 조작까지 허용해 버릴 리스크**가 늘어난다. 이 트레이드오프 (Trade-off)를 해결하는 메커니즘이 바로 **Sandbox**이다.
### 4.2 Sandbox의 메커니즘 (네이티브 Sandbox)
Claude Code의 네이티브 Sandbox는 **OS 레벨의 보안 기구(Security Mechanism)를 사용하여 Bash 커맨드와 그 자식 프로세스를 격리**하는 기능이다. Docker 컨테이너를 사용하지 않고, OS 표준 메커니즘 (macOS의 Apple Seatbelt, Linux의 bubblewrap)으로 구현된다.
격리는 주로 2개 계층으로 나뉜다:
| 계층 | 내용 |
|---|---|
| **파일 시스템 (File System)** | 프로젝트 디렉토리 외부로의 쓰기를 차단. `Read`/`Edit` 권한으로 상세 제어 |
| **네트워크 (Network)** | 기본적으로 외부 통신 차단. `WebFetch` 권한으로 허용 도메인을 제어 |
「Sandbox 내에서 완결되는 조작은 안전하다고 간주하여 자동으로 허가한다」는 것이 기본적인 발상이다.
### 4.3 실행 방법과 3가지 모드
Claude Code 실행 후, `/sandbox` 커맨드로 설정한다.
| 모드 | 동작 | 적합한 용도 |
|---|---|---|
| **Sandbox BashTool, with auto-allow** | Sandbox 내에서 실행할 수 있는 커맨드는 자동 허가. Sandbox 외부 액세스가 필요할 때만 일반 승인 플로우로 폴백 (Fallback) | **승인 피로 해소가 목적이라면 이것**. 많은 경우에 권장 |
| ... |### 4.4 settings.json을 통한 상세 설정
`/sandbox` 커맨드는 내부적으로 `settings.json`을 업데이트한다. 직접 작성할 경우의 샘플:
<details>
<summary>샘플: settings.json에서의 sandbox 설정 (클릭하여 펼치기)</summary>
```json
{
"permissions": {
"allow": [
...
포인트 해설:
excludedCommands: ["git"]
— git은 완전한 파일 시스템 액세스 (File System Access)가 필요하므로, Sandbox 외부에서 실행해야 한다 (공식 권장 사항) -
network.allowedDomains
— npm install이나 git push에 필요한 통신 대상만 화이트리스트 (Whitelist)로 등록 -
보호 경로 (Protected Paths)— .git/, .bashrc, .mcp.json, .claude.json 등으로의 쓰기는 어떤 모드에서도 강제적으로 승인이 필요하다. 이는 Claude가 자신의 권한 설정을 마음대로 수정할 위험을 방지하기 위한 하드 가드 (Hard Guard)이다. 평가 순서는 다음과 같다:
deny → ask → allow
deny가 최우선이며, ask를 너무 넓게 설정하면 더 제한적인 allow에 도달할 수 없다:
// ❌ Bad: ask가 너무 넓어서 allow에 도달하지 못함
{
"ask": ["Bash(git *)"],
...
| 상황 | 판단 |
|---|---|
| 프로토타이핑, 조사 태스크에서 Bash가 많이 실행되는 경우 | 도입 권장 (auto-allow 모드) |
| 장시간 자율 실행 (백그라운드에서 실행하고 결과만 확인하고 싶은 경우) | 도입 필수 수준 |
| 프로덕션 코드의 파괴적 변경을 동반하는 작업 | Sandbox + ask로 방어 |
.env나 비밀키를 다루는 작업 | Sandbox에 더해 deny로 .env*를 명시적 차단 |
| 일회성 소규모 수정 | Sandbox 없이도 가능 (단, 상시 사용한다면 활성화 권장) |
보충: Bash 도구에는 dangerouslyOverrideSandbox라는 옵션이 존재하지만, 원칙적으로 사용하지 않는다. LLM에 대한 지시나 프롬프트 인젝션 (Prompt Injection)을 통해 이 인자가 전달되면 Sandbox의 의미가 없어지기 때문에, 정말 필요한 상황 외에는 Bash 도구를 통해 이 파라미터가 사용되지 않도록 주의해야 한다.
- "승인이 번거로우니 전부 allow로 설정하자" → 위험
- "매번 승인하자" → 피로가 쌓여 결국 대충 처리하게 됨
- "Sandbox로 격리하고, 그 안에서 자동 허용" → 안전성을 OS 레벨에서 담보하면서 승인 피로를 회피
특히 본 노트에서 다룬 서브 에이전트 (Sub-agent) 운용이나 스펙 주도 개발 (Spec-driven Development)에서는 Bash 호출이 빈번하게 발생하므로, Sandbox와의 조합이 현실적인 타협점이 된다.
Claude Code에 국한되지 않고, 에이전트 운용에서는 다음과 같은 에이전트 간의 인수인계가 발생한다.
- 메인 에이전트 → 서브 에이전트 (태스크 위임)
- 세션 A → 세션 B (추후 작업 지속)
- Claude Code → 인간 리뷰어 → Claude Code (수정 반영)
- Claude → Claude Code Action (CI/CD에서의 자동 리뷰)
이때 구두(프롬프트 내)로 전달하는 인수인계에는 한계가 있다. 컨텍스트 (Context)는 사라지고, 세션은 종료되며, 다른 에이전트에게는 이력이 보이지 않는다.
따라서 문서가 "영속화된 컨텍스트"로서 기능해야 한다.
스펙 주도 개발 문맥에서 특히 중요한 산출물:
| 문서 | 역할 | 배치 예시 |
|---|---|---|
| 요구사항 정의 / PRD | "무엇을 만들 것인가" | docs/specs/<feature>/requirements.md |
| 설계 / Design Doc | "어떻게 만들 것인가" | docs/specs/<feature>/design.md |
| 태스크 리스트 | "어떤 순서로 만들 것인가" | docs/specs/<feature>/tasks.md |
| ADR | "왜 그렇게 결정했는가" | docs/adr/NNNN-*.md |
| CLAUDE.md | 에이전트에 대한 상시 지시 | 프로젝트 루트 및 서브 디렉토리 |
보충: GitHub의 spec-kit이나 Kiro의 영향으로, requirements.md → design.md → tasks.md의 3종 세트로 진행하는 스펙 주도 개발 스타일이 확산되고 있다. 본서도 이러한 흐름의 연장선에 있다.
문서를 의도한 대로 출력하게 하려면:
- 템플릿을 Skill에 포함시킨다 (앞서 언급한
write-adr...
의 예) -
명령어(Command)로 문서 생성 절차를 고정한다 (/create-spec <feature-name> 등) -
CLAUDE.md에 문서 배치 규약을 명시한다 -
생성된 문서를 다음 단계에서 반드시 읽게(Read) 한다 (태스크 구현 시 design.md를 읽게 하는 등)
샘플: /create-spec 명령어의 내용 (클릭하여 확장)
---
description: 신기능 스펙 문서 3종 세트(requirements/design/tasks)를 작성한다
---
...
도서와 일반적인 베스트 프랙티스(Best Practices)에서 추출한 실전 체크리스트.
CLAUDE.md를 작성했다 (프로젝트 개요 · 중요 규약 · 참조해야 할 상세 문서의 위치) -
서브 디렉터리 고유의 규약은 서브 디렉터리의 CLAUDE.md로 분리했다 -
필수/권장/임의/금지를 명시적으로 구분하여 작성했다 ("가능하다면" 등의 모호한 표현을 배제) -
규칙 충돌 시의 우선순위를 명시했다 (대방침의 순위 + 개별 충돌 패턴) -
**판단 불가능 시에는 "사용자에게 확인"**할 것을 명시했다
-
자주 사용하는 노하우는 Skill로 만들었다 (description에 트리거 단어를 망라)
-
정형화된 작업은 Command로 만들었다
-
Skill/Command의 문서에 샘플을 작성했다
-
settings.json에서permissions의allow/ask/deny를 정리했다 -
승인이 빈번하게 발생하는 작업이 있는 경우/sandbox를 활성화했다 -
.env*나 비밀키는deny로 명시적으로 차단했다 -
태스크가 전환될 때
/clear를 했다 - 대량의 컨텍스트(Context)를 사용하는 작업(리뷰 · 대규모 조사)은 Subagent에게 넘겼다 -
스펙(requirements/design/tasks)을 먼저 만든 후 구현에 들어갔다
-
생성된 문서를 후속 단계에서 읽도록 하는 흐름을 만들었다
-
불필요한 파일의 Read를 피했다 (Grep/Glob으로 범위를 좁힌 후)
-
긴 로그는 요약시킨 후 다음 턴(Turn)으로 진행했다
-
한 세션(Session)을 너무 길게 끌지 않고, 구분이 생기면 종료하고 새 세션으로 전환했다
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기