Claude Code 개발 환경을 안전하고 재현 가능하게 설정하는 방법
Claude Code에서 Node, Docker, .env, 권한, hooks, 검증 절차를 재현 가능하게 설정합니다.
새 PC나 막 clone한 저장소에서 첫 번째 의미 있는 수정 전에 반나절을 쓰는 일은 없어야 합니다. 문제는 대개 정해져 있습니다. Node.js 버전이 다르고, npm과 pnpm이 섞이고, .env가 오래되었고, Docker volume에 예전 schema가 남아 있으며, 로컬 명령이 문서화되어 있지 않습니다. Claude Code는 이 시간을 줄여 주지만, 먼저 안전한 경계를 만들어야 합니다.
목표는 에이전트에게 모든 것을 맡기는 것이 아닙니다. 목표는 모든 개발자와 모든 Claude Code 세션이 같은 지침, 같은 패키지 매니저, 같은 비밀 정보 규칙, 같은 검증 명령을 쓰는 재현 가능한 환경입니다.
공식 문서를 기준으로 확인하세요. 설치는 Claude Code setup, 설정은 settings, 권한은 permissions, hooks는 hooks guide를 봅니다. ClaudeCodeLab 안에서는 입문 가이드, CLAUDE.md 모범 사례, hooks 가이드도 함께 보면 좋습니다.
flowchart TD
A["로컬 도구 확인"] --> B["Node와 패키지 매니저 고정"]
B --> C["의존성과 .env.example 생성"]
C --> D["CLAUDE.md에 규칙 저장"]
D --> E["settings.json에서 권한 제한"]
E --> F["hooks로 위험 명령 차단"]
F --> G["doctor, env check, test 실행"]
먼저 정할 정책
개발 환경도 운영 코드처럼 다룹니다. 중요한 규칙은 저장소에 남기고, 실제 비밀값은 에이전트 컨텍스트에 넣지 않으며, 데이터를 삭제하거나 코드를 배포할 수 있는 명령은 사람이 승인해야 합니다.
| 영역 | 파일 또는 명령 | 이유 |
|---|---|---|
| 런타임 | .nvmrc, packageManager, Corepack | Node와 pnpm 차이를 막음 |
| 비밀 정보 | .env.example, .gitignore, permissions.deny | 실제 키가 prompt와 commit에 들어가지 않게 함 |
| 프로젝트 메모리 | CLAUDE.md | 매 세션 같은 규칙을 읽게 함 |
| 권한 | .claude/settings.json | 읽기, Bash, 기본 모드를 제어 |
| hooks | .claude/hooks/* | 도구 실행 전 결정적 차단을 수행 |
| 검증 | doctor, check:env, test | 감이 아니라 명령 결과로 확인 |
복사해서 쓰는 초기화 스크립트
이 스크립트는 Git Bash, WSL, macOS, Linux에서 사용하는 전제입니다. 최소 TypeScript 프로젝트를 만들고, 환경 변수를 검증하며, pnpm을 고정하고, 비밀 파일 읽기를 막고, PreToolUse hook을 추가합니다.
#!/usr/bin/env bash
set -euo pipefail
APP_DIR="${1:-claude-dev-lab}"
mkdir -p "$APP_DIR"
cd "$APP_DIR"
command -v node >/dev/null || { echo "Node.js가 필요합니다"; exit 1; }
command -v claude >/dev/null || { echo "Claude Code CLI가 필요합니다"; exit 1; }
corepack enable
corepack prepare [email protected] --activate
cat > package.json <<'JSON'
{
"name": "claude-dev-lab",
"private": true,
"type": "module",
"packageManager": "[email protected]",
"scripts": {
"doctor": "node --version && pnpm --version && claude --version",
"check:env": "tsx src/env.ts",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"dotenv": "latest",
"zod": "latest"
},
"devDependencies": {
"@types/node": "latest",
"tsx": "latest",
"typescript": "latest",
"vitest": "latest"
}
}
JSON
mkdir -p src .claude/hooks .vscode
printf "22\n" > .nvmrc
cat > .gitignore <<'EOF'
node_modules
.env
.env.*
!.env.example
dist
coverage
EOF
cat > .env.example <<'EOF'
NODE_ENV=development
DATABASE_URL=postgresql://app:app@localhost:5432/app
REDIS_URL=redis://localhost:6379
EOF
cat > src/env.ts <<'TS'
import { config } from "dotenv";
import { z } from "zod";
config();
const Env = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url().optional()
});
const parsed = Env.safeParse(process.env);
if (!parsed.success) {
console.error(parsed.error.flatten().fieldErrors);
process.exit(1);
}
console.log("env ok", {
nodeEnv: parsed.data.NODE_ENV,
hasRedis: Boolean(parsed.data.REDIS_URL)
});
TS
cat > CLAUDE.md <<'EOF'
# 프로젝트 지침
## 환경 설정
- `.nvmrc`에 적힌 Node 버전을 사용합니다.
- Corepack을 통해 pnpm을 사용합니다. npm이나 yarn으로 바꾸지 않습니다.
- `.env.example`을 로컬에서 `.env`로 복사한 뒤 값은 사람이 직접 수정합니다.
- `.env`나 비밀 파일을 읽거나 출력하거나 commit하지 않습니다.
- 코드를 바꾸기 전에 `pnpm run doctor`와 `pnpm run check:env`를 실행합니다.
- 코드를 바꾼 뒤에는 가장 좁은 관련 테스트를 실행하고 결과를 기록합니다.
## 작업 규칙
- 먼저 탐색하고 짧은 계획을 제시합니다.
- 명시적 승인 없이 파괴적 명령이나 배포 명령을 실행하지 않습니다.
- 설정 변경은 터미널 기록이 아니라 재현 가능한 파일에 남깁니다.
EOF
cat > .claude/hooks/block-dangerous.mjs <<'JS'
import { readFileSync } from "node:fs";
const input = JSON.parse(readFileSync(0, "utf8") || "{}");
const command = String(input.tool_input?.command ?? "");
const blockedPatterns = [
/rm\s+-rf\s+(\/|~|\$HOME)/,
/git\s+push\b/,
/curl\b.+\|\s*(bash|sh)/,
/Invoke-WebRequest\b.+\|\s*iex/i
];
if (blockedPatterns.some((pattern) => pattern.test(command))) {
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "위험한 명령을 차단했습니다. 대상과 영향을 사람이 먼저 확인해야 합니다."
}
}));
} else {
console.log("{}");
}
JS
cat > .claude/settings.json <<'JSON'
{
"defaultMode": "plan",
"permissions": {
"allow": [
"Read",
"Bash(pnpm install)",
"Bash(pnpm run *)",
"Bash(git status *)",
"Bash(claude --version)",
"Bash(claude doctor)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(git push *)",
"Bash(rm -rf *)"
]
},
"env": {
"CLAUDE_CODE_SUBPROCESS_ENV_SCRUB": "1"
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/block-dangerous.mjs"
}
]
}
]
}
}
JSON
pnpm install
cp .env.example .env
pnpm run doctor
pnpm run check:env
pnpm test
Windows 네이티브 환경에서는 먼저 도구 체인을 확인합니다.
winget install Anthropic.ClaudeCode
claude --version
claude doctor
node --version
corepack enable
pnpm --version
pnpm --version이 실패하면 Node와 Corepack을 먼저 고칩니다. claude doctor가 proxy, certificate, login 문제를 보고하면 정확한 오류를 저장한 뒤 그 제약 안에서 원인 분석을 요청합니다.
더 안전한 요청문
claude -p "
이 저장소의 개발 환경 설정을 점검하고 부족한 부분을 보완해 주세요.
규칙:
- .env, .env.*, secrets/ 아래 파일을 읽지 마세요
- packageManager를 따르고 pnpm을 npm이나 yarn으로 바꾸지 마세요
- Docker volume을 삭제하거나 git push를 실행하지 마세요
허용:
- README, package.json, CLAUDE.md, .claude/settings.json 읽기
- pnpm install, pnpm run doctor, pnpm run check:env, pnpm test 실행
마지막에 실행한 명령, 수정한 파일, 발견한 실패, 남은 수동 작업을 짧게 보고해 주세요.
"
구체적인 활용 사례
| 사례 | 적용 방식 |
|---|---|
| 새 SaaS 프로토타입 | PostgreSQL과 Redis를 Docker Compose로 추가하고 첫날부터 재현성 확보 |
| 팀 저장소 온보딩 | Claude Code가 문서와 설정을 읽고 허용된 검사를 실행하며 빠진 절차를 보완 |
| 콘텐츠 또는 상품 사이트 | CTA, 분석 이벤트, OGP, AdSense 민감 페이지를 보호 |
| 사내 도구 | DB seed, queue, mock, 테스트 명령을 표준화 |
Docker가 많은 프로젝트는 Docker Compose를 이어서 보세요. 팀 작업은 Claude Code 팀 협업이 도움이 됩니다. CI에는 같은 명령을 CI/CD 설정에 연결합니다.
자주 생기는 실패
패키지 매니저를 섞지 마세요. pnpm-lock.yaml이 있으면 npm install을 실행하지 않게 해야 합니다. 이 규칙을 CLAUDE.md에 쓰고 packageManager를 package.json에 유지합니다.
Claude Code가 .env를 읽게 하지 마세요. 검토 가능한 파일은 .env.example이고 실제 값은 로컬에만 둡니다. .gitignore와 permissions.deny를 함께 사용합니다.
Docker volume도 주의해야 합니다. 오래된 volume 때문에 올바른 migration이 실패처럼 보일 수 있습니다. 삭제 전에는 대상, 위험, 대안을 설명하게 하세요.
호스트 머신에서 bypassPermissions를 쉽게 쓰지 마세요. 격리된 컨테이너나 VM에서만 사용합니다. 신뢰하지 않는 저장소의 hooks도 세션 시작 전에 사람이 읽어야 합니다.
재현성 체크리스트
claude --version과claude doctor가 통과한다.nvmrc또는.node-version이 있다package.json에packageManager가 있다- lockfile은 한 종류만 있다
.env.example은 최신이고.env는 무시된다CLAUDE.md에 setup, 금지 사항, 검증 명령이 있다.claude/settings.json이 비밀 읽기,git push, 파괴적 명령을 막는다- 최종 보고에는 명령과 결과가 포함된다
CTA와 검증 결과
로컬 환경이 불안정하면 구매 링크, 폼, 분석 이벤트, 광고 페이지가 쉽게 깨집니다. 반복 가능한 흐름으로 만들려면 무료 치트시트에서 시작하고, 제품 템플릿을 확인하거나 교육 및 도입으로 팀에 적용하세요.
이 흐름으로 최소 프로젝트를 만들고 의존성을 설치한 뒤 .env.example을 복사하고 pnpm run doctor, pnpm run check:env, pnpm test를 순서대로 실행했습니다. 가장 효과적이었던 보호는 .env 읽기 차단과 git push 또는 파괴적 명령을 막는 hook이었습니다. Masa의 실제 업무에서도 setup 실패는 어려운 명령보다 기록되지 않은 전제에서 더 자주 발생합니다.
무료 PDF: Claude Code 치트시트
이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.
개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.
작성자 소개
Masa
Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.
관련 글
Obsidian 메모를 CLAUDE.md로 바꾸는 Claude Code 워크플로
Obsidian 작업 메모를 CLAUDE.md 운영 노트로 정리해 Claude Code 세션의 문맥 반복을 줄입니다.
Claude Code Revenue CTA Routing: 글에서 PDF, Gumroad, 상담으로 보내기
독자 의도에 따라 무료 PDF, Gumroad 상품, 상담으로 나누는 Claude Code CTA 설계입니다.
Claude Code 팀 인계 규칙: 리뷰 증거, 권한, 롤백, 수익 경로까지 넘기는 법
Claude Code 작업을 팀에 넘길 때 필요한 증거, 권한 규칙, 롤백, 무료 PDF, Gumroad, 상담 경로 체크리스트.