AI ToolsEN

프로젝트 유형별 CLAUDE.md 템플릿 5종 — 복붙용 파일과 에이전트가 실제로 따르는 규칙

Next.js·Python ML·모노레포·데이터 파이프라인·연구 노트북용 CLAUDE.md/AGENTS.md 템플릿 5종. 어떤 줄이 장식이고 어떤 줄을 에이전트가 실제로 따르는지, 그리고 규칙 파일로 사이드 이펙트를 통제하는 법까지.

프로젝트 유형별 CLAUDE.md 템플릿 5종 — 복붙용 파일과 에이전트가 실제로 따르는 규칙

프로젝트 유형별 CLAUDE.md 템플릿 5종 -- 복붙용 파일과, 에이전트 행동을 실제로 바꾸는 규칙의 조건

앞서 쓴 CLAUDE.md·.cursorrules·AGENTS.md 가이드는 이 파일들이 *무엇인지*를 설명했습니다. 그 뒤에 가장 많이 받은 질문은 훨씬 단순했습니다. "그냥 복사해서 쓸 수 있는 걸 하나 주세요."

이 글이 그 답입니다. Next.js 앱, Python ML 리포, 모노레포, 데이터 파이프라인, 연구 노트북 프로젝트 -- 다섯 개의 템플릿과, 대부분의 템플릿 모음이 건너뛰는 부분: 어떤 줄이 장식이고 어떤 줄을 에이전트가 실제로 따르는가. 모든 템플릿은 실제로 행동을 바꾸는 것만 남기고 잘라냈고, 마지막에는 이 블로그 자체의 규칙 파일을 인용합니다. 그 파일이 남들과 다른 한 가지를 하기 때문입니다.

먼저, 에이전트가 실제로 읽는 방식

규칙 파일은 문서가 아닙니다. 매 턴마다 시스템 프롬프트에 끼워 넣어지는 조각입니다. 여기서 템플릿의 가치를 결정하는 결과 세 가지가 나옵니다.

  1. 길이는 세금입니다. 모든 줄이 매 턴 컨텍스트를 씁니다. 400줄짜리 CLAUDE.md는 세 번째 턴쯤이면 대부분 무시됩니다. 40~80줄을 목표로 하고, 긴 내용은 필요할 때 에이전트가 열어볼 수 있는 링크 파일로 빼세요.
  2. 설명보다 명령어가 이깁니다. "pytest를 씁니다"는 아무 효과가 없습니다. pytest tests/ -x -q는 에이전트가 실제로 실행하는 것입니다. 정확한 명령어·경로·파일명을 적은 규칙은 지켜지고, 철학을 서술한 규칙은 흐릿하게 요약되다 사라집니다.
  3. 금지에는 이유와 대안이 있어야 합니다. "any 쓰지 마"는 어겨집니다. "any 쓰지 마 -- unknown으로 받고 좁혀라. 상위 API 레이어가 타입이 없기 때문이다"는 지켜집니다. 이제 에이전트가 당신이 열거하지 않은 경계 사례까지 스스로 판단할 수 있으니까요.

하나 더. 2026년 기준 AGENTS.md가 도구 공통 이름입니다(Claude Code, Codex, Cursor, Gemini CLI, Copilot 모두 읽습니다). Claude Code는 CLAUDE.md도 추가로 읽습니다. 원본 하나를 두고 나머지는 심볼릭 링크로 거세요: ln -s AGENTS.md CLAUDE.md. 아래 템플릿은 어느 이름으로 써도 동작합니다.

템플릿 1: Next.js 앱 (App Router, TypeScript, Tailwind)

가장 흔한 프로젝트 유형이고, 에이전트가 눈에 안 보이는 관례를 가장 자주 깨는 곳입니다 -- 서버/클라이언트 컴포넌트 경계, 데이터 페칭, env 처리.

markdown
# Project: <name> — Next.js 15 App Router

## Commands
- Dev: `npm run dev` · Build: `npm run build` (PR 전 반드시 통과) · Lint: `npm run lint`
- Tests: `npm test` (Vitest). 파일 하나만: `npx vitest run src/lib/foo.test.ts`
- Type check: `npx tsc --noEmit` — `src/types/`를 건드렸으면 반드시 실행

## Architecture
- `src/app/(marketing)/` 공개 페이지 · `src/app/(app)/` 인증 라우트 · `src/app/api/` 라우트 핸들러
- `src/lib/` 순수 함수와 서버 전용 데이터 접근 (파일 상단에 `import 'server-only'`)
- `src/ui/` 표현 컴포넌트. `src/ui/`에서 데이터 페칭 금지.
- DB: Prisma는 `src/lib/prisma.ts`를 통해서만. 다른 곳에서 `new PrismaClient()` 금지.

## Rules
- 기본은 Server Component. `'use client'`는 훅/이벤트 핸들러가 필요할 때만, 그 파일은 작게.
- 페칭은 `page.tsx`/`layout.tsx` 또는 `src/lib/`에서 하고 아래로 내려보낸다. `useEffect` 페칭 금지.
- 환경변수는 `src/lib/env.ts`(zod 검증)에서만 읽는다. 인라인 `process.env.X` 금지. 시크릿에 `NEXT_PUBLIC_` 접두사 금지.
- Tailwind만. CSS 모듈 금지, 인라인 `style=`은 동적 값에만.
- 라우트 핸들러는 `NextResponse.json`을 반환하고, DB를 만지기 전에 zod로 body를 검증한다.
- 라우트를 바꿨으면 `curl`로 한 번 쳐보고 상태 줄을 요약에 붙인다.

## Don't
- PR 설명에 이유를 적지 않고 의존성을 추가하지 않는다.
- `prisma/schema.prisma`를 수정했으면 `npx prisma generate`를 돌리고 마이그레이션을 언급한다.

여기서 중요한 건 "src/lib/prisma.ts에서만"과 env.ts 규칙입니다. 에이전트가 가장 자주 만드는 두 버그(중복 클라이언트, 시크릿 유출)를 막습니다. "curl로 한 번 쳐보라"는 줄은 "구현했습니다"를 "확인했습니다"로 바꿉니다.

템플릿 2: Python ML / 연구 코드베이스

ML 리포에서 에이전트는 (a) 엉뚱한 GPU에서 학습을 돌리고, (b) 설정 기본값을 조용히 바꾸고, (c) 노트북을 깨진 채로 둡니다. 이 셋을 겨냥한 템플릿입니다.

markdown
# Project: <name> — PyTorch 학습 + 평가

## Environment
- Python env: `conda activate <env>` (base env 금지). 의존성은 `pyproject.toml`; 추가는 pip가 아니라 `uv add`.
- GPU: 먼저 `nvidia-smi`. `CUDA_VISIBLE_DEVICES=<빈 id>`를 쓰고, 10GB 이상 쓰이는 GPU에는 절대 띄우지 않는다.
- 데이터는 `/data/<project>/` (읽기 전용). 출력은 `runs/<date>-<name>/`. `data/`에 쓰지 않는다.

## Commands
- 스모크 테스트 (30초): `python train.py --config configs/smoke.yaml`
- 본 실행: `python train.py --config configs/base.yaml --run-name <name>` (`runs/`에 로그)
- 평가: `python eval.py --ckpt runs/<run>/best.pt --split val`
- 테스트: `pytest tests/ -x -q` — 설정 변경을 커밋하기 전 반드시 통과

## Rules
- 설정 변경은 `configs/` 아래 새 YAML로. `base.yaml`을 제자리에서 고치지 않는다. 가설 이름으로 파일명을 짓는다.
- 모든 실행은 `runs/<run>/config.yaml`(고정 사본)과 `metrics.json`을 남긴다. 안 남기는 스크립트는 먼저 고친다.
- 숫자는 그 숫자를 만든 run 디렉터리와 함께 보고한다. **run 경로 없는 숫자는 결과가 아니다.**
- 보고하는 실행에는 `--seed`가 필수. 1% 이상 개선을 주장하려면 시드 3개.
- 노트북(`notebooks/`)은 스크래치다. 살아남아야 할 것은 테스트와 함께 `src/`로 옮긴다.
- `eval.py`의 메트릭 로직을 바꾸지 않는다. 메트릭이 틀렸으면 이슈를 열고, 실험 중간에 인라인으로 고치지 않는다.

## When training fails
- OOM → `batch_size` 절반, `grad_accum` 두 배, run 이름에 기록. 해상도/시퀀스 길이를 몰래 낮추지 않는다.
- NaN loss → 멈추고 원인 배치를 저장(`--dump-nan-batch`)한 뒤 보고. `nan_to_num`을 끼워 넣지 않는다.

제값을 하는 규칙 둘: "run 경로 없는 숫자는 결과가 아니다"와 NaN 규칙입니다. 둘 다 에이전트가 진전처럼 보이지만 진전이 아닌 일을 하는 걸 막습니다.

템플릿 3: 모노레포 (Turborepo / pnpm workspaces)

실패 양상은 범위입니다. 에이전트는 앱 하나를 고치려고 공유 패키지를 건드리고, 패키지 하나 바꿨는데 리포 전체 테스트를 돌립니다. 모노레포는 중첩 AGENTS.md가 제값을 하는 곳입니다.

markdown
# Monorepo: <name> — pnpm + Turborepo

## Layout
- `apps/web` (Next.js) · `apps/api` (Fastify) · `apps/worker` (BullMQ)
- `packages/ui` (공유 React) · `packages/db` (Prisma + client) · `packages/config` (eslint/tsconfig)
- 패키지마다 자체 `AGENTS.md`가 있다. **가장 가까운 파일이 이긴다.** 수정 전에 읽는다.

## Commands (리포 루트에서)
- 설치: `pnpm i` · 전체 빌드: `pnpm turbo build` · 패키지 하나 테스트: `pnpm --filter @acme/api test`
- 변경분 린트: `pnpm turbo lint --filter=...[origin/main]`
- `packages/`를 건드린 게 아니면 필터 없이 `pnpm turbo test`를 돌리지 않는다.

## Rules
- `packages/*` 변경은 모든 앱의 변경이다. PR 제목에 명시하고(`[packages/db] ...`) 의존하는 앱 전부의 테스트를 돌린다.
- 앱 간 import 금지 (`apps/web` → `apps/api`). 공유 코드는 `packages/`로.
- 버전 올리기: `pnpm changeset` — `package.json` 버전을 손으로 고치지 않는다.
- 생성 코드(`packages/db/generated/`, codegen `*.d.ts`)는 절대 편집하지 않는다. 생성기를 다시 돌린다.

## Ownership
- `packages/db` 스키마 변경에는 마이그레이션 파일 **그리고** `packages/db/CHANGELOG.md` 한 줄이 필요하다.
- `apps/worker` 잡은 멱등이어야 한다. 재시도 계약은 `apps/worker/AGENTS.md`.

그리고 중첩 파일 하나, packages/db/AGENTS.md:

markdown
# packages/db
- 스키마: `prisma/schema.prisma`. 변경 후: `pnpm prisma generate && pnpm prisma migrate dev --name <what-changed>`.
- 로컬 DB가 아닌 곳에 `prisma db push` 금지.
- 새 테이블에는 마이그레이션, 앱 부팅에 필요한 행이 있으면 `seed.ts` 항목, CHANGELOG.md 한 줄이 필요하다.

중첩 파일은 일부러 짧습니다. 루트 파일이 한 디렉터리에서만 의미 있는 DB 규칙을 짊어지지 않게 하려고 존재합니다.

템플릿 4: 데이터 파이프라인 (Airflow / dbt / 웨어하우스)

파이프라인은 폭발 반경이 가장 큽니다. 잘못된 WHERE 절 하나가 다른 팀이 읽는 테이블에 쓰레기를 백필합니다. 규칙은 되돌릴 수 있음과 드라이런에 관한 것입니다.

markdown
# Project: <name> — Airflow DAG + BigQuery 위 dbt 모델

## Commands
- 로컬 Airflow: `make airflow-up` (docker) · DAG 파싱 확인: `python dags/<dag>.py`
- dbt: `dbt build --select <model>+ --target dev` (노트북에서 `--target prod` 금지)
- 쿼리 드라이런: `bq query --dry_run --use_legacy_sql=false < query.sql` — 스캔 바이트를 요약에 붙인다
- 테스트: `dbt test --select <model>` 와 `pytest tests/`

## Rules
- 새 모델에는 `schema.yml`의 `description`과, 키에 대한 `unique` + `not_null` 테스트가 최소한 있어야 한다.
- 증분 모델은 `unique_key`를 정의하고 같은 파티션을 다시 돌려도 안전(멱등)해야 한다.
- 백필: DAG에 명시적 `--backfill-approved` 플래그 없이 한 번에 7일 초과 금지. 실행 전에 무엇이 덮어써지는지 말한다.
- 다른 모델이 읽는 모델에 `SELECT *` 금지. 컬럼을 나열한다.
- 비용: 100GB 이상 스캔하는 쿼리는 파티션 필터가 있거나, 왜 없는지 주석이 있어야 한다.
- 타임존: 웨어하우스는 전부 UTC. 변환은 표현 레이어에서만.

## Don't
- 데이터셋 이름을 하드코딩하지 않는다. `{{ source() }}` / `{{ ref() }}`.
- 데이터를 "고치려고" 행을 지우지 않는다. 보정 모델을 쓰고 이유를 문서화한다.

돈을 가장 많이 아끼는 줄은 드라이런 규칙입니다. 신뢰를 가장 많이 지키는 줄은 "실행 전에 무엇이 덮어써지는지 말한다"입니다.

템플릿 5: 연구 노트북 프로젝트 (논문 재현, 실험, 블로그)

이 블로그가 굴러가는 프로젝트 유형입니다. 논문을 재현하고, 스윕을 돌리고, 글로 씁니다. 규칙은 출처에 관한 것입니다 -- 글에 들어가는 모든 숫자는 그것을 만든 셀로 거슬러 올라가야 합니다.

markdown
# Project: <name> — 실험 + 글쓰기

## Layout
- `notebooks/<topic>-<n>.ipynb` 탐색용 · `src/` 테스트 있는 재사용 코드 · `results/<topic>/*.json` 원시 출력 · `figures/` 는 `scripts/plot_*.py`만 생성
- `drafts/` 글. 글은 `results/` 파일을 인용하지, 손으로 친 숫자를 쓰지 않는다.

## Commands
- Env: `conda activate research` · 실행 전 GPU 확인: `nvidia-smi`
- 실험 실행: `python src/run.py --exp <name> --out results/<topic>/<name>.json`
- 그림 전체 재생성: `python scripts/plot_all.py` (멱등; PNG를 커밋)

## Rules
- 모든 실험 스크립트는 설정, 시드, git 커밋 해시, 소요 시간, 원시 메트릭을 저장한다. 예외 없음.
- 글의 주장("X가 4.6배 빠르다")은 그것을 뒷받침하는 JSON에 링크되어야 한다. JSON이 없으면 그 문장은 나가지 않는다.
- 베이스라인은 처리군과 같은 세션, 같은 하드웨어에서 돌린다. 논문의 숫자와 비교할 때는 반드시 그렇다고 밝힌다.
- 결과가 논문과 다르면 그대로 보고하고 설정 차이를 나열한다. 맞을 때까지 튜닝하지 않는다.
- 노트북은 커밋 전 출력을 지운다(`nbstripout`). `notebooks/final/`만 예외.

## Writing
- 소제목과 굵은 주장이 본문 숫자보다 앞서 나가면 안 된다. 발행 전 굵은 글씨를 감사한다.
- 실험이 보여주지 *않는* 것을 별도 절로 적는다.

이 글에서 규칙 하나만 가져가신다면 "JSON 없이는 그 문장은 나가지 않는다"를 가져가세요. 신뢰받는 블로그와 그렇지 않은 블로그의 가장 큰 차이 하나입니다.

우리 CLAUDE.md가 위 템플릿들과 다른 점

지금 읽고 계신 이 블로그의 규칙 파일은 위 어떤 템플릿보다 한 걸음 더 갑니다. 규칙 파일로 사이드 이펙트를 통제합니다. 코드베이스의 모든 바깥 효과 -- 이메일, Stripe, DB 쓰기, Sanity 발행 -- 는 choke point 파일과 함께 매니페스트에 등록돼 있고, 규칙 파일은 에이전트에게 이렇게 말합니다.

새 출구(새 SDK, 새 API, 새 write 경로)는 코드보다 먼저 effects.manifest.json에 등록합니다. choke_point·log_stream·recon 세 필드를 못 채우면 그 효과는 아직 추가할 준비가 안 된 겁니다 -- 사용자에게 물으세요.

그리고

"실행하지 않는" 경로도 skip(reason)으로 남깁니다. 조용히 흘러가는 fall-through를 만들지 않습니다.

그리고, 가장 많은 버그를 잡아낸 줄:

완료를 선언하기 전에 npm run verify를 돌립니다. exit 0이 아니면 완료가 아닙니다.

이 세 줄이 "에이전트가 어딘가에 이메일 발송을 추가했다"를 "에이전트는 어디에 로그가 남고 조용히 멈추면 어떻게 알아챌지를 등록하지 않고는 이메일 발송을 추가할 수 없었다"로 바꿨습니다. 규칙 파일은 그러라고 있는 겁니다. 코드베이스를 설명하려고가 아니라, 틀린 일을 하기 어렵게 만들려고.

전체 거버넌스 체계가 없어도 패턴은 빌려 쓸 수 있습니다. 일반형은 이렇습니다.

markdown
## Side effects
- 보내거나, 결제하거나, 외부에 쓰거나, 지우는 것은 전부 `src/lib/<effect>.ts`를 거친다. 다른 곳에서 클라이언트를 만들지 않는다.
- 행동하지 *않기로* 한 모든 분기는 이유를 로그에 남긴다. 조용한 skip 금지.
- 작업 완료를 말하기 전에 `npm run verify`가 exit 0이어야 한다. 마지막 줄을 붙인다.

규칙 파일을 커밋하기 전 체크리스트

  • [ ] 80줄 안팎인가? 아니면 무엇을 링크 문서로 뺄 수 있는가?
  • [ ] 모든 규칙이 명령어·경로·파일명을 지목하는가 -- 철학이 아니라?
  • [ ] 모든 "하지 마"에 이유와 대안이 있는가?
  • [ ] "구현했다"를 "확인했다"로 바꾸는 줄이 하나 있는가 (테스트 명령, curl, 드라이런)?
  • [ ] 특수 규칙이 필요한 한 디렉터리에는 루트를 불리는 대신 중첩 AGENTS.md를 뒀는가?
  • [ ] 모든 도구가 같은 파일을 읽도록 심볼릭 링크를 걸었는가 (ln -s AGENTS.md CLAUDE.md)?

다섯 템플릿은 함께 제공하는 다운로드에 한 파일로도 들어 있어서, 스크롤 없이 필요한 것만 복사하실 수 있습니다.

참고 자료

더 많은 콘텐츠를 받아보세요

SNS에서 새로운 글과 튜토리얼 소식을 가장 먼저 받아보세요

이메일로 받아보기

관련 포스트