결정 사항을 레포지토리에 기록하기: AI 코딩 워크플로우의 근간이 되는 ADRs
요약
AI 코딩 워크플로우에서 결정 사항(ADRs)을 채팅 기록이 아닌 레포지토리에 통합하는 것이 필수적입니다. 이를 통해 플래너, 빌더, 리뷰어 등 모든 에이전트가 동일한 진실의 출처를 참조할 수 있습니다. 이는 '복사 붙여넣기 세금'과 버전 불일치(Drift) 문제를 해결하여 안정적인 개발 프로세스를 구축하는 핵심 방법론입니다.
핵심 포인트
- 결정 사항은 채팅 기록이 아닌 레포지토리에 보관해야 합니다.
- 레포지토리 통합은 모든 에이전트가 동일한 컨텍스트를 공유하게 합니다.
- 수동적인 복사-붙여넣기는 주의력 손실과 버전 불일치(Drift)를 초래합니다.
- 결정 사항을 중앙화하는 것이 AI 코딩 워크플로우의 근간입니다.
_본 기사는 Medium에 먼저 게시되었습니다: [https://medium.com/@r3dtuxedo/put-your-decisions-in-the-repo-adrs-as-the-backbone-of-an-ai-coding-workflow-2a86fad560aa]
채팅 프로젝트에 남아있는 명세서(specs)와 결정 로그는 코드에서 벗어납니다. 이들을 레포지토리로 옮기고, AGENTS.md에 연결하면 플래너(planner), 빌더(builder), 리뷰어(reviewer) 에이전트들이 마침내 같은 페이지를 읽게 됩니다.
며칠 전, r/ClaudeCode의 한 사용자가 자신이 사용하는 전체 Claude Code 루프를 게시하며 어느 단계를 변경해야 할지 질문했습니다. 이는 신중하게 구성된 환경이었는데, 브리프(brief)가 담긴 claude.ai Project 내의 '플래너' 채팅, 26개의 항목이 기록된 결정 로그와 상태 파일로 이루어져 있었습니다. 여기에 세 개의 Plan 서브 에이전트가 포함된 플랜 모드, lint 및 typecheck 후크, CI, Claude GitHub Action 리뷰, 그리고 가장 위험도가 높은 PR에 대한 /ultrareview까지 진행되었습니다.
비용 목록은 솔직한 부분이었습니다. 기능당 세 단계의 검토 레이어가 필요했습니다. "Cursor와 claude.ai 간에 계획을 수동으로 붙여넣기"가 필요했고, 모든 기능이 끝날 때마다: 스쿼시-머지(squash-merge)를 수행하고, "그 후 결정 사항과 상태를 플래너 프로젝트에 다시 기록해야 했습니다."
제가 여기서 답하고 싶은 질문 중 하나는 다음과 같습니다:
별도의 플래너 (claude.ai Project)가 가치가 있는가요, 아니면 문서 폴더(docs folder) 내의 Claude Code에서 명세서와 리뷰를 통해 동일한 결과를 얻을 수 있나요?
제 대답은 문서 폴더입니다. 채팅 프로젝트 자체가 나쁘다는 의미는 아니라, 레포지토리 외부에 존재하는 결정 사항은 빌더나 리뷰어 에이전트가 직접 가져오지 않는 한 볼 수 없기 때문입니다.
사람들은 이 질문의 여러 버전을 계속 던지고 있습니다: 그 자체로 존재하는 Claude Code 루프 스레드, 수많은 레포지토리(repo)에 걸쳐 Claude Code 세션을 관리하기 위해 구축된 6개월짜리 개인용 하네스, 대부분의 PR(Pull Request)을 스스로 작성한 에이전트 루프, 그리고 2시간 간격으로 반복 작업에 갇힌 Codex 사용자입니다. 여기에는 실제 파일과 함께 장문의 답변이 있습니다.
복사 붙여넣기 세금 (The copy-paste tax)
플래너(planner) 채팅이 진실을 담고 있습니다. 빌더(builder, 에디터 내의 Claude Code)가 코드를 가지고 있습니다. 리뷰어는 디프(diff)를 봅니다. 당신은 이들 사이의 버스 역할을 합니다.
모든 이동에는 대가가 따릅니다:
- 주의력(Attention). 계획을 한 도구에 붙여넣고, 결과를 다른 도구에 넣고, 리뷰를 다시 첫 번째 도구로 가져옵니다.
- 드리프트(Drift). 결정 사항 로그는 병합(merge) 후에 업데이트되는데, 당신이 기억해야 합니다. 그때까지 두 가지 버전은 불일치하며, 에이전트가 오래된 버전을 자신 있게 따를 때까지 아무도 알아차리지 못합니다.
- 맹목적인 리뷰어(Blind reviewers). 오직 디프만 보는 리뷰어는 코드가 합리적인지 여부를 알려줄 수 있습니다. 하지만 결정 사항 자체가 컨텍스트에 없기 때문에 그 코드가 당신이 결정한 것인지 아닌지는 알 수 없습니다.
이러한 패턴은 Claude 외부에서도 나타납니다. r/ChatGPTPro Codex 스레드에서 한 작성자는 각 라운드가 1~2시간이 걸리고 그들이 "오류/출력을 다시 붙여넣는" 루프를 설명합니다. 가장 유용한 답변들은 모델에 관한 것이 아니었습니다. 한 사람은 계획을 세우는 데 두세 배의 시간을 할애하며 "저는 AI가 패키지, DB(데이터베이스), 언어, 보안 등을 선택하도록 거의 허용하지 않습니다"라고 말했습니다. 또 다른 사람은 "하나의 작업, 하나의 테스트, 기록된 결과 하나"를 제안했는데, 그 이유는 "긴 세션은 오래된 가정을 담기 시작하기 때문입니다."
그것들은 결정 사항과 사양(spec)입니다. 유일한 질문은 그것들이 어디에 존재하는가 하는 것입니다.
사양(Spec)에는 무엇을 넣고, ADR에는 무엇을 넣을까
저는 두 가지 종류의 파일을 사용하며, 그 구분이 형식보다 더 중요합니다.
스펙(Spec)은 기능별이며 임시적입니다. 현재 우리가 무엇을 구축하고 있는지—목표, 수용 검사(acceptance checks), 범위 경계(scope boundary), 미해결 질문, 그리고 현재 상태—를 설명합니다. 해당 기능이 배포되면 스펙은 완료됩니다. 저는 이를 보관하지만, 다음 달에 아무도 읽을 필요는 없습니다.
ADR은 결정별이며 영구적입니다. 아키텍처 결정 기록(Architecture Decision Record)은 그 이후의 모든 것을 형성하는 하나의 결정을 포착합니다. 예를 들어, 테넌트가 어떻게 격리되는지, 어떤 큐를 사용하는지, 마이그레이션이 왜 추가 전용(append-only)인지 등입니다. 이 형식은 Michael Nygard가 2011년에 작성한 게시물 Documenting Architecture Decisions에서 유래했습니다. ADR은 제목(Title), 배경(Context), 결정(Decision), 상태(Status), 결과(Consequences)의 다섯 부분으로 구성됩니다. Nygard의 규칙은 여전히 올바릅니다: 각 기록을 1~2페이지로 유지하고, 순차적으로 번호를 매기며 절대 번호를 재사용하지 않으며, 결정이 뒤집힐 경우 이전 기록을 보관하고 '대체됨(superseded)'으로 표시해야 합니다.
마지막 규칙이 바로 ADR을 에이전트(agent)에게 유용하게 만드는 요소입니다. "0011에 의해 대체됨(Superseded by 0011)"으로 표시된 0007을 읽는 에이전트는 역사와 현재의 규칙 둘 다를 알 수 있습니다.
제가 무언가를 어디에 배치할지 결정하는 테스트입니다:
- 이 내용이 해당 기능 병합 후에도 코드를 계속 제약하나요? 그렇다면 ADR입니다.
- 이것이 이 기능의 범위(scope), 단계(steps) 또는 수용 여부(acceptance)에 관한 것인가요? 스펙에 넣습니다.
- 명령(command), 관례(convention), 또는 포인터(pointer)인가요? AGENTS.md에 넣습니다.
ADR을 작성하는 데 별도의 도구가 필요하지는 않지만, 알아두면 좋은 두 가지가 있습니다. adr-tools는 작은 CLI(명령줄 인터페이스)입니다: adr init doc/architecture/decisions를 실행하면 디렉터리와 첫 번째 기록이 생성되고, adr new "Use Postgres RLS for tenant isolation"을 사용하면 번호가 매겨진 새 기록이 추가되며, adr new -s 9 "..."는 ADR 9를 대체하는 기록을 작성하고 이전 기록의 상태를 업데이트합니다. Archgate는 더 나아가서 작동합니다: ADR은 .archgate/adrs/에 YAML 프론트매터와 함께 존재하며, ADR에는 archgate check가 코드베이스를 검사하는 동반 파일인 .rules.ts가 가질 수 있습니다. 이 체크는 위반 사항이 발생하면 종료 코드 1로 종료되어 CI(지속적 통합)가 병합을 차단할 수 있게 합니다. 현재 작성 시점 기준으로 Claude Code와 Cursor용 에디터 플러그인이 베타 버전으로 제공됩니다.
AGENTS.md 및 CLAUDE.md에 연결하기
docs/ 내의 파일들은 에이전트가 언제 읽어야 하는지 지시받기 전까지는 아무런 역할을 하지 못합니다. 이것이 바로 AGENTS.md의 역할입니다.
AGENTS.md는 개방형 형식입니다: 리포지토리 루트에 있는 일반 마크다운 파일로, 코딩 에이전트가 빌드 단계, 컨벤션 및 지침을 읽는 데 사용됩니다. Codex도 이를 읽으며, 다른 많은 도구들도 마찬가지입니다. Claude Code는 CLAUDE.md를 읽고, 현재 문서에서는 이 두 파일이 어떻게 상호 작용하는지 설명합니다. 최근 버전들은 경로에 CLAUDE.md가 없을 때만 AGENTS.md를 직접 읽습니다. 만약 두 파일을 모두 유지한다면, 한 소스를 공유하는 문서화된 방법은 CLAUDE.md 상단에서의 임포트입니다:
@AGENTS.md
## Claude Code
...
같은 페이지에서 발견한 하나의 세부 사항이 저를 당황하게 했습니다. Claude에게 말로 AGENTS.md를 읽으라고 지시하는 CLAUDE.md는 Claude가 파일을 열기로 결정할 때만 작동합니다. 반면, @ 임포트는 실행 시 로드됩니다. 저는 제 자체 리포지토리에서 '말로 하는 버전'을 사용했었고, 이에 대해서는 아래에 더 설명하겠습니다.
Anthropic은 각 CLAUDE.md를 200줄 미만으로 유지할 것을 권장하며, 임포트된 파일들은 로드 시점에 로드되므로 임포트를 통해 컨텍스트가 저장되지 않습니다. 따라서 모든 ADR을 임포트해서는 안 됩니다. 대신 AGENTS.md에 인덱스와 읽기 규칙을 작성하고, 에이전트가 현재 사양(spec)에서 연결하는 두세 개의 기록만 열도록 하세요.
결정 사항을 기반으로 검토하기
이 부분이 제가 리뷰 방식을 가장 많이 바꾼 부분입니다.
일반적인 AI 리뷰는 diff를 받아서 “이것을 검토하세요”라고 합니다. 이 과정에서 명명 규칙, 누락된 null 체크, 추가 테스트 등 그럴듯한 관찰 결과를 반환합니다. 일부는 유용하지만, 많은 부분이 노이즈이며, 코드가 작동은 하지만 결정 사항(decision)을 위반하는 값비싼 실수를 잡아내지 못합니다.
결정 사항에 민감한(decision-aware) 리뷰는 세 가지를 받습니다: diff, 이 기능의 spec(명세), 그리고 해당 spec이 연결된 ADRs(Architectural Decision Records). 이 리뷰의 질문은 더 좁습니다. 즉, “이 diff가 spec의 수용성 검사(acceptance checks)를 충족하는가? 그리고 연결된 어떤 ADR을 위반하는가?”입니다. 이것은 긴 채팅 기록보다 범위가 작고, “검토하세요”라는 요청보다 훨씬 날카로운 질문입니다. 제가 절감되는 시간만큼 숫자를 매길 수는 없습니다. 다만, 발견 사항들이 더 구체적이고 검증 가능해졌다고 말할 수 있습니다: “이 쿼리가 ADR 0007의 RLS(Row Level Security) 규칙을 우회합니다”는 참이거나 거짓일 뿐입니다.
또한 이 방식은 ‘결정 사항 기록’이라는 번거로운 작업을 해결해 줍니다. 만약 PR 템플릿에서 이를 요구하고, 리뷰어가 ADR 없이 도착한 새로운 패턴을 플래그 지정할 경우, 결정 사항을 기록하는 것이 변경 사항 배포 과정의 일부가 됩니다: 같은 diff 내에서 검토되고, 같은 커밋에서 병합됩니다.
이러한 루프를 운영하는 사람들의 두 가지 주의사항:
- r/ClaudeCode 스레드에서는 한 댓글 작성자가 작업별 리뷰 서브 에이전트(per-task reviewer subagents)가 실제 결함을 포착했지만, 더 큰 빌드의 최종 전체 브랜치 검토(final whole-branch review)에서는 “작업별 리뷰들이 놓친 세 가지 중요한 문제점, 모두 작업 간의 상호 작용에 관한 것”을 여전히 발견했다는 내용을 공유했습니다. 작업별 결정 사항 기반 검토가 전체 브랜치에 대한 단일 검토를 대체할 수는 없습니다.
- r/ClaudeAI 스레드에서 bunker라는 도구(샌드박스 환경의 Claude 에이전트가 GitHub 이슈를 구현하고 두 번째 Claude 세션이 이를 검토하는 곳)에 대해, CI(지속적 통합), 자체 설정 또는 에이전트 지침과 관련된 모든 것은 인간의 승인을 기다립니다. 한 댓글 작성자가 이것이 리뷰어의 프롬프트, 즉 “스스로 기준을 낮출 수 있는 유일한 장소”까지 포함하는지 물었습니다. ADRs에도 동일하게 적용됩니다. 에이전트는 초안을 작성할 수 있지만, 인간이 이를 승인해야 합니다.
간단한 실습 예시
제가 사용하는 레이아웃을 소개합니다. 이 서비스는 레딧 스레드에 나온 것과 유사한 가상의 멀티테넌트 주문 서비스입니다.
.
├── AGENTS.md
├── CLAUDE.md
...
ADR (아키텍처 결정 기록)
# 0007. Postgres 행 수준 보안을 이용한 테넌트 격리 강제화 (Enforce tenant isolation with Postgres row-level security)
Status: Accepted
...
사양서 (Spec)
# Spec 0012: 대량 주문 가져오기 (CSV) (Bulk order import (CSV))
Status: In progress
...
AGENTS.md 스니펫
## 사양서 및 결정 사항 (Specs and decisions)
- 계획을 세우기 전에 `docs/decisions/README.md` (ADR 인덱스)를 읽으세요.
...
검토자 (The reviewer)
.claude/agents/adr-reviewer.md에 있는 Claude Code 서브 에이전트:
---
name: adr-reviewer
description: "스펙 및 연결된 ADR 대비 브랜치 diff를 검토합니다." (Reviews a branch diff against its spec and linked ADRs.)
...
그리고 작업을 체크박스로 변환하는 PR 템플릿 라인:
- [ ] 사양서 업데이트 완료 (Spec updated) (체크박스 및 로그 포함)
- [ ] 결정 사항: 새로운/대체된 ADR 연결, 또는 "없음" (Decisions: new/superseded ADRs linked, or "none")
사용처
ai-catapult는 Claude Code, Codex 및 OpenCode 플러그인을 사용하는 소규모 MIT 라이선스 CLI입니다. npx ai-catapult init .을 실행하면 LLM이 관여하지 않는 결정론적 스캐폴드(scaffold)가 작성됩니다: AGENTS.md, CLAUDE.md, GEMINI.md, .ai/ 거버넌스 트리, 그리고 남은 작업을 나열하는 .ai/handoff/NEXT-STEPS.md입니다. ADR을 포함한 판단 호출(judgment calls)은 에이전트 내부에서 실행되는 플러그인에 맡겨집니다.
이 레포지토리는 해당 레이아웃을 실제로 사용하고 있습니다(dogfoods). 사양서는 docs/specifications/ACTIVE/에, 결정 사항은 docs/architecture/adr/에 위치하며, AGENTS.md는 스스로를 "에이전트가 사용하는 운영 계약의 단일 진실 공급원(single source of truth for agent-facing operating contracts)"이라고 부릅니다. 또한 ADR-0001은 로그 기록 후 다시 반영하는 루프(log-it-back loop)가 작동하는 모습도 보여줍니다: 검토 라운드에서 결정 사항의 일부가 뒤집되었을 때, 수정 사항이 채팅에 들어가는 대신 날짜가 찍힌 정정 노트(errata note) 형태로 ADR에 기록되었습니다.
또한 제가 언급했던 실수가 있습니다. CLAUDE.md 파일은 마크다운 링크로 AGENTS.md를 가리키는데, 이는 Claude Code 문서에서 경고하는 "말로 된" 버전입니다. @AGENTS.md여야 합니다. 그리고 ADR-0001은 Nygard의 것보다 길어서 1~2페이지가 넘습니다. 둘 다 제 목록에 있습니다.
하나의 결정 사항부터 시작하기 (Start with one decision)
전체 채팅 프로젝트를 마이그레이션할 필요는 없습니다. 에이전트(agent)가 무시했을 때 문제가 될 다음 결정 사항을 docs/decisions/에 한 페이지짜리 ADR로 작성하고, 다음 기능의 사양(spec)은 메시지가 아닌 파일로 작성하세요. 위에 있는 여섯 줄을 AGENTS.md에 추가하고, 이를 CLAUDE.md에서 가져와(import) 전체 레포지토리 대신 사양과 연결된 ADR들을 검토자에게 지적하세요.
검토자가 "이것은 ADR 0007을 위반합니다(violates)"라고 말했고 그것이 맞았을 때, 당신은 창들 사이에서 계획을 붙여넣는 것을 멈추게 될 것입니다.
본 기사는 AI의 도움을 받아 작성되었으며 저자가 검토했습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기