본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 08. 21:52

CLAUDE.md에는 파일 위치 지도가 아닌 불변성(Invariants)을 기록해야 합니다

요약

CLAUDE.md 작성 시 단순한 파일 구조 대신 에이전트가 반드시 지켜야 할 '불변성(Invariants)'과 그 이유를 기록해야 합니다. 에이전트가 추론할 수 없는 보안 경계와 데이터 무결성 규칙을 명시함으로써 잠재적인 데이터 유출과 오류를 방지할 수 있습니다.

핵심 포인트

  • 파일 지도 대신 에이전트가 깨뜨려서는 안 될 불변성을 기록할 것
  • 규칙을 작성할 때는 반드시 그 이유(Why)를 함께 명시할 것
  • SQLite와 같이 보안 기능이 부족한 환경일수록 명시적 규칙이 필수적임
  • 단계별 게이트를 통한 마이크로 스텝 방식의 작업 프로세스 권장

제가 보는 대부분의 CLAUDE.md 파일은 폴더 지도와 명명 규칙(naming convention)으로 구성되어 있습니다. 이는 에이전트(agent)에게 전달할 수 있는 가장 가치 없는 정보에 가깝습니다. 왜냐하면 에이전트는 이미 저장소(repo)로부터 구조를 추론할 수 있기 때문입니다. 에이전트가 추론할 수 없는 것은 절대 깨져서는 안 되는 규칙과 그 뒤에 숨겨진 이유입니다.

에이전트는 컴파일이 되고, 타입(types)을 통과하며, 보안이나 데이터 불변성(invariant)을 조용히 위반하는 코드를 기쁘게 작성할 것입니다. 파일 지도는 이를 막는 데 아무런 도움이 되지 않습니다. 하지만 이유와 함께 작성된 불변성 목록은 도움이 됩니다.

다음은 Next.js + SQLite SaaS 프로젝트에서 저에게 효과적이었던 형태입니다.

이유와 함께 불변성(invariants)을 기록하세요

"쿼리를 lib/db에 넣으세요"라고 하지 마세요. 대신 다음과 같이 작성하세요:

  • 모든 쓰기(writes) 작업은 서버 액션(server action) 또는 라우트 핸들러(route handler)를 거쳐야 하며, 인증(auth)은 그곳에서 확인되어야 합니다. 클라이언트는 신뢰할 수 없으며, 서버만이 유일하게 강제할 수 있는 경계(boundary)입니다.
  • 사용자가 소유한 모든 쿼리에는 소유권 서술어(ownership predicate)가 포함되어야 합니다. SQLite에는 행 수준 보안(row-level security)이 없으므로, 이 한 줄이 테넌트 간 읽기(cross-tenant reads)를 막는 유일한 수단입니다. 이를 잊는 것은 에이전트가 발견할 수 있는 오류가 아니라, 소리 없는 데이터 유출입니다.
  • 성공 URL(success URL)로부터는 절대 액세스 권한이나 자금 상태를 부여하지 마세요. 오직 검증된 서버 이벤트(verified server event)를 통해서만 허용하세요.

"이유와 함께"라는 부분이 중요합니다. Claude는 맹목적으로 믿어야 하는 규칙보다 자신이 이해하고 있는 규칙을 훨씬 더 안정적으로 따릅니다.

명시할 가치가 있는 SQLite의 주의사항 (저는 보통 Postgres를 사용합니다)

저는 행 수준 보안(RLS)이 안전장치 역할을 하는 Postgres 기반으로 구축합니다. Postgres에서는 쿼리가 소유권 필터를 잊더라도 RLS가 테넌트 간 읽기를 차단할 수 있습니다. 하지만 SQLite에는 그런 기능이 없습니다. 따라서 SQLite에서는 "모든 사용자 범위 쿼리에 소유권 서술어를 포함할 것"은 단순한 스타일 조언이 아니라, 멀티 테넌트 경계(multi-tenant boundary) 그 자체입니다. 만약 이것이 CLAUDE.md에 불변성으로 명시되지 않는다면, 에이전트는 결국 이를 누락한 쿼리를 작성할 것이고 아무런 경고도 발생하지 않을 것입니다. (Postgres의 경우, 서술어를 유지하면서 RLS도 함께 사용하세요. 이중 안전장치(Belt and suspenders)를 갖추는 것입니다.)

무엇을 만들지가 아니라, 어떻게 작동해야 하는지를 알려주세요

불변성 (Invariants)은 목적지를 설명합니다. 불변성은 에이전트가 검토 불가능한 거대한 도약 한 번으로 목적지에 도달하는 것을 막지는 못합니다. 따라서 훌륭한 CLAUDE.md의 나머지 절반은 작업 방법 (working method)입니다.

저의 방식은 단계별 게이트가 있는 마이크로 스텝 (phase-gated micro-stepping)이며, 핵심적인 움직임은 에이전트가 스스로 자신의 진행을 승인하지 않는다는 것입니다.

  • 작업은 단계(범위 설정, 빌드, 검증, 리뷰, 수정, 배포)별로 실행되며, 각 단계 사이에는 인간의 체크포인트 (human checkpoint)가 있습니다. 에이전트는 모든 경계에서 멈추고, 보고하며, 명시적인 진행 허가 문구를 기다립니다. "좋아 보이네요 (looks good)" 같은 말로는 진행할 수 없습니다.
  • 빌드 단계 자체도 마이크로 스텝으로 나뉩니다. 한 번에 한 섹션씩 진행하며, 각 섹션이 끝날 때마다 타입 체크 (typecheck), 테스트, 그리고 함정 스캔 (pitfall scan)을 수행한 뒤 커밋 (commit)하고 멈춥니다.
  • 회로 차단기 (circuit breaker): 약 5번의 시도 안에 체크를 통과(green)하지 못하면, 무한 루프를 도는 대신 멈추고 보고합니다.
  • 다중 파일 변경 전의 방어적 커밋 (defensive commits), 완전한 구현만 허용 (// TODO 스텁 금지), 그리고 새로운 세션이 저장소를 다시 읽지 않고도 재개할 수 있도록 하는 긴밀한 상태 요약 핸드오프 (state-summary handoff).

깨진 불변성은 작은 게이트 단계에서 즉시 드러나지만, 거대한 자율적 디프 (autonomous diff)는 이를 묻어버립니다. 이것은 거의 아무도 작성하지 않는 CLAUDE.md의 부분이지만, 에이전트의 행동을 가장 많이 변화시키는 부분입니다.

"테스트해야 할 위험 경로" 섹션 추가하기

가장 영향력이 큰 블록입니다. 이는 실패했을 때 비용이나 데이터를 발생시키는 흐름이며, 에이전트가 지루하다는 이유로 건너뛰는 것들입니다:

  • 회원가입 / 로그인 / 로그아웃
  • 인증되지 않았을 때의 보호된 경로 리다이렉트 (protected route redirect)
  • CRUD 권한 부여 (사용자 A가 사용자 B의 행을 건드릴 수 없음)
  • 신규 데이터베이스에서의 마이그레이션 (migration)
  • 기존 데이터베이스에서의 마이그레이션
  • seed 명령어를 두 번 실행 (중복 방지)
  • 프로덕션 빌드 (production build)
  • .env.example만 있는 상태에서 클론(clone) 후 첫 실행

파일의 마지막을 "이 작업이 완료되었다고 말하기 전에, 이것들이 여전히 통과함을 증명하세요"로 끝내는 것은 에이전트를 자신만만한 코드 생성기에서 신중한 엔지니어에 더 가까운 존재로 변화시킵니다.

전체 파일

Next.js + SQLite SaaS를 위한 완전하고 주관이 뚜렷한 CLAUDE.md (Drizzle, Server Actions, Next 16 캐싱 규칙, 보안 기준선, 마이크로 스텝핑(micro-stepping) 방법론, 이유를 포함한 안티 패턴(anti-patterns), 그리고 위험 경로 체크리스트 포함). https://gist.github.com/HalbonLabs/485186f4b2846bb1d13d2240651df21d

저는 생업으로 프로덕션급 Next.js 템플릿을 제작하고 있으며 (Template Empire), 이를 "구매자가 처음 클론(clone)했을 때 코드가 깨지는 것을 무엇이 막아줄 것인가"라는 관점에서 생각합니다. 이는 결과적으로 "에이전트가 절대 틀려서는 안 되는 것은 무엇인가"라는 질문과 동일합니다. 그 이면에 있는 더 깊은 표준들은 공개되어 있습니다: templateempire.io/standards

여러분의 CLAUDE.md에는 배포할 때 반드시 포함해야 하는 어떤 불변성(invariants)이 들어있나요?

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0