DeepSeek Harness · 엔지니어링 방법론

Agent Notes와 AGENTS.md: AI로 AI를 만드는 규율

네 상태 설계 노트와 AI가 읽는 코딩 규약, 팀이 바로 베낄 수 있어요.

강의 목표이 레슨을 마치면 세 가지를 말할 수 있어요. 설계 노트가 폴더 경로로 네 상태를 어떻게 담는지, 어떤 변경이 같은 PR에 노트를 반드시 붙여야 하는지, AGENTS.md가 구두 규칙을 게이트·리뷰가 집행할 하드 계약으로 어떻게 쓰는지. 끝나면 자기 팀에도 그대로 세울 수 있어요.
인터랙티브 데모 · 노트 한 편의 일생

먼저 해보고 이야기해요. 아래는 DSH 저장소 .agents/notes/ 아래 네 폴더이고, 숫자는 로컬 스냅샷의 실제 노트 수예요. 「재생」을 누르면 실제 노트 하나가 proposed에서 implemented로 갔다가 archived로 들어가는 길을 보고, 「거부 루트」로 바꾸면 다른 노트가 반려된 뒤 동결되는 길을 봐요. 가운데 줄은 포맷 게이트 검진 항목이라, 단계마다 누가 지키는지 한눈에 보여요.

proposed/25편
제안, 구현 전 리뷰
검증을 기다리는 아이디어
implemented/506편
결정이 전달됨
코드와 동기화된 살아있는 문서
rejected/11편
반려 후 동결
같은 실수를 막는 백신
archived/142편
영구 동결된 역사
다시 건드리면 안 되는 화석층
포맷 게이트 verify-agent-note-format (CI가 자동 실행)
# Agent Note: 제목
Status 줄이 폴더와 일치
## Problem 로 시작
Alternatives considered 필수
「재생」을 눌러 실제 노트 한 편의 전체 흐름을 보세요.
실제 노트 서랍(제목을 누르면 한 줄 요약, 모두 저장소에서 찾을 수 있는 원본)
로직 분해 · AI가 코드를 쓰는 저장소가 기억 상실을 가장 두려워하는 이유

DSH는 AI가 대규모로 코드를 쓰는 저장소예요. AI 세션은 매번 새로 시작되고, 사람도 석 달 전에 왜 어떤 안을 반려했는지 기억하지 못해요. 그래서 같은 나쁜 아이디어가 반복 제안되고, 같은 코드가 다시 리팩터되며, 문서는 쓰이고 아무도 갱신하지 않아 서서히 썩어요.

DSH의 답은 두 가지예요. 상태를 따라 흐르는 설계 노트 세트 Agent Notes — 코드와 문서가 담지 못하는 두 가지, 왜 이렇게 했는지와 무엇을 포기했는지. 그리고 AI가 읽는 행동 수칙 AGENTS.md — 저장소의 하드 규칙을 AI가 매 세션 읽는 표준 지시로 적어요.

먼저 노트를 봐요. 노트마다 경로가 곧 완전한 정체성이에요: {lifecycle}/{class}/yyyy-mm-dd-topic.md. 생명주기는 최상위 폴더 — proposed, implemented, rejected 세 활성 상태와 archived 아카이브 층. 카테고리는 중첩 폴더 — feature, bug-fix, simplification, architecture, process, testing 여섯 가지의 닫힌 집합이고, 하나라도 더 있으면 게이트가 거부해요. 로컬 스냅샷 숫자: proposed 25편, implemented 506편, rejected 11편, archived 142편. 각 노트에는 중국어 대응 파일과 일관성 기록도 있어요.

그리고 그 하드 규칙, 루트 AGENTS.md 122행에 있어요. 비일상적 변경은 같은 PR에서 노트를 최소 하나 추가하거나 갱신해야 해요. 무엇이 비일상적일까요? 동작, 아키텍처, 패키지 간 계약, 프로세스 도구, 디스크 포맷, 프로토콜 포맷, 또는 유지보수자가 나중에 다시 볼 수 있는 결정. 순수 기계적 국소 편집만 면제예요. 노트는 코드와 같은 리뷰·같은 머지를 타니, 코드 먼저 올리고 문서는 나중에 같은 일은 없어요.

노트마다 Alternatives considered 절도 있어야 하고, 실제 대안과 탈락 이유를 적어요. .agents/notes/README.zh.md 115행 원문은 이래요: “결정을 기록하면서 무엇을 이겼는지 적지 않는 것은, 같은 논쟁을 다시 초대하는 일이다.” 이 절이 기억 상실 방어의 핵심이에요. 다음에 누군가(또는 AI)가 같은 안을 내면, 노트를 열어 그때 누구에게 왜 졌는지 볼 수 있어요.

상태가 곧 폴더

노트 상태를 바꾸려면 파일을 옮기고 Status 줄을 고치는 두 일이 같은 변경에 있어야 하며, 게이트가 교차 검사해요. proposed가 implemented로 갈 때 Proposal 절은 현재형의 Decision으로 다시 써야 해요.

rejected는 백신

반려된 제안은 동결 보관하고, 결론은 Status 줄에 첫눈에 보여요. 보존에도 문턱이 있어요. 근거가 여전히 유혹적이고 영향 큰 실수를 막을 때만 남기고, 아니면 세 파일을 함께 지워요.

archived는 화석

지도 가치가 낮아진 implemented 노트는 아카이브 층으로 옮긴 뒤 영구 동결이에요. 편집·번역·이동·삭제 금지, manifest는 추가만. 역사는 증거이고, 고친 증거는 증언할 수 없어요.

핵심 증거 · 포맷은 게이트가 관리하고, 흑백으로 명시

이 체계는 문서 층에서 멈추지 않아요. scripts/verify-agent-note-format.ts는 94행으로 doc-sync 게이트의 일부이며 CI마다 돌아요. 아래는 규칙 표예요. 생명주기별 Status 줄 문법과 필수 절.

scripts/verify-agent-note-format.ts22–33행
const STATUS: Record<string, RegExp> = {
  proposed: /^Status: proposed$/,
  implemented: /^Status: implemented$/,
  rejected: /^Status: rejected — .+$/,
}

/** Required `##` headings per lifecycle, beyond the universal `## Problem` opener. */
const REQUIRED: Record<string, string[]> = {
  proposed: ['## Proposal', '## Acceptance criteria', '## Risks'],
  implemented: ['## Decision', '## Consequences'],
  rejected: ['## Proposal'],
}
소스 스냅샷 안내: 로컬 저장소 deepseek-harness-master 기준, 확인 파일 scripts/verify-agent-note-format.ts, 확인일 2026-08-13. 코드 블록은 소스 원문을 유지합니다.

rejected 정규식을 보세요. Status 줄에는 거부 이유가 한 줄 있어야 하고, rejected만 쓰면 통과하지 못해요. 규칙 표 몇 줄 아래에는 BANNED_IMPLEMENTED 정규식(36행)이 있어요. implemented 노트에는 Proposal, Plan, Migration plan, Acceptance criteria 같은 제안 말투 제목이 금지예요. implemented 노트는 현재형의 사실을 적고, 계획은 이미 결정이 되었어야 하니까요.

또 하나의 반직관 설계: 활성·아카이브 노트 684편에 색인 디렉터리가 없어요. 트리 자체가 목록이고, 검색은 폴더와 전문 검색이에요. INDEX.md를 만들고 싶다고요? 구조 검사 스크립트가 .agents/notes/ 루트를 돌며 그 파일명을 딱 보고, 나타나면 바로 에러예요. 문구도 단호해요. 중앙 Agent Note 색인은 금지, 생명주기·카테고리 트리를 보거나 저장소 전체를 검색하세요. 같은 루프가 생명주기 집합을 닫힌 집합으로 못 박아, 모르는 최상위 폴더는 “알 수 없는 생명주기”로 신고해요. 잘못된 자리의 노트는 순회에서 사라지니까요.

출처: scripts/agent-note-tree.ts 44–56행의 구조 검사 루프, 확인일 2026-08-13.

왜 색인을 금할까요? 중앙 색인은 가장 빨리 썩는 문서예요. 노트를 추가할 때마다 갱신해야 하고, 한 번 잊으면 거짓말하기 시작해요. 색인을 지우면 부패 가능성은 제로예요. 설계 이유 자체도 노트예요: implemented/process/2026-07-19-remove-generated-agent-note-index.md.

AGENTS.md · AI가 읽는 하드 계약은 어떤 모습인가

이제 나머지 절반을 봐요. 루트 AGENTS.md는 149행이고, AI가 매 세션 로드해요. Conventions 절은 조목조목 베낄 만해요. 가장 대표성 있는 네 조항을 골랐고, 출처는 모두 루트 AGENTS.md예요:

  1. 타입 경계를 믿으세요(115행). 타입이 있는 동일 프로세스 경계에서는 TypeScript를 믿고, 정적 인터페이스가 이미 보장한 값에 런타임 검증과 방어 테스트를 또 쓰지 마세요. 검증은 진짜 경계에만: 설정 파싱, 모델이 돌려준 JSON, 디스크 파일, 프로세스·프로토콜 경계.
  2. 플러그인에 조절 가능 파라미터를 하드코딩하지 마세요(112행). 배포마다 바뀌는 선택은 설정 파일에서 고칠 수 있는 필드여야 하고, DEFAULT_* 상수 하나는 설정 가능이 아니에요. 프로토콜 상수와 보안 불변조건은 예외 — 그건 용접해 두세요.
  3. 설정이 틀리면 크게 실패하세요(113행). 로드 때 발견할 수 있는 불일치는 로드 때 던지고, 안 되면 가장 빨리 파싱할 수 있는 순간에 던지세요. 빠진 참조를 조용히 건너뛰지 마세요.
  4. 빈 catch는 서명이 있어야 해요(118행). 원문: “An empty catch names what it swallows and why nothing else can reach it; keep the try to one statement.” 어떤 예외를 삼켰는지, 왜 다른 예외는 여기 못 오는지 적어야 하고, try 블록은 문장 하나만 허용해요.

이 조항들의 공통점: 하나하나 검사할 수 있어요. 게이트가 검사하거나, 리뷰어가 한눈에 위반 여부를 판단해요. “코드는 우아해야 한다”처럼 적어도 의미 없는 구호는 하나도 없어요.

문서 자체에도 게이트가 있어요. 단어 예산: 루트 AGENTS.md는 1600단어를 넘지 못하고, 넘으면 verify-doc-budgets가 빨개져요 — 내용을 있어야 할 계층으로 옮기거나 압축하세요(docs/AGENTS.md 57행). 사실 하나, 집 하나: 같은 규칙의 권위 출처는 하나, 나머지는 링크만(15–17행). 이중 언어 페어: 문서마다 영어, 중국어, .i18n.yaml 세 파일이고, 기록에 양쪽 git blob hash를 두며, 한쪽을 고치고 페어를 다시 확인하지 않으면 게이트가 빨개져요(docs/i18n/README.md 10–11행). 이 게이트들은 pnpm run doc-sync가 돌리고, 전체 목록은 scripts/run-gates.ts에 있어요.

가로 비교 · 의사결정 기록, 다른 곳은 어디에 두나

Claude Code:클로즈드 소스이고, 의사결정 기록은 블로그·릴리스 노트·코드 주석에 흩어져 있어요. 복원 소스에는 값진 주석이 있어요 — 예를 들어 autoCompact.ts 67–70행의 BigQuery 프로덕션 데이터가 붙은 서킷 브레이커 주석(Compaction 이중 경로 레슨 참고). 코드에 박힌 미니 의사결정 기록이고 품질도 낮지 않아요. 다만 상태가 없고, 포맷 게이트가 없고, 생명주기로 검색할 수 없으며, 반려된 안은 거의 찾을 곳이 없어요.

Grok Build: 확인된 로컬 스냅샷 기준, 저장소에 동등한 설계 노트 디렉터리가 없고, 근거는 주로 모듈 주석과 commit 역사에 있어요. 모듈 주석은 괜찮아요(각 mod.rs 맨 앞에 한 줄 책임 설명). 하지만 반려된 안이라는 차원은 없어요. DSH의 rejected 노트 11편은 세 곳 비교에서 유일해요.

팀은 어떻게 베낄까요? 세 단계. 1) 저장소에 notes/와 네 폴더를 만들고, 파일명에 날짜와 주제를 넣어요. 2) 포맷을 고정: 제목, Status 줄, Problem 시작, Alternatives considered 필수 — 위 규칙 표로 약 15줄 검증 스크립트를 짜 CI에 걸면 반나절 분량이에요. 3) AGENTS.md에 기계나 리뷰가 검사할 하드 계약 3–5조를 세우고, 어떤 변경에 설계 노트를 붙여야 하는지부터 시작하세요. 개수는 욕심내지 마세요. DSH도 적은 규칙에서 자랐어요.

수업 실습
01

자기 저장소용 최소 AGENTS.md를 쓰세요

다섯 조항만. 각 조항은 세 줄 이하; 스크립트로 검사하거나 리뷰어가 십 초 안에 위반을 판단할 수 있어야 하고; 그중 하나는 어떤 변경에 설계 노트를 붙여야 하는지 규정해야 해요. 쓴 뒤 테스트: 동료에게 다섯 조항을 보여주고 집행 못 하는 게 무엇인지 물어요. 집행 못 하면 지우고 다시 쓰세요.

02

규정 위반 흐름을 한 번 추론해 보세요

누군가 proposed 노트 하나를 git mv로 implemented/에 바로 옮기고, Status 줄도 안 고치고 Proposal도 Decision으로 안 바꿨어요. 위 22–33행 규칙 표를 보고 verify-agent-note-format이 낼 오류를 모두 적으세요. 한 층 더: 왜 게이트는 그 두 일과 파일 이동이 같은 변경에 있어야 한다고 할까요?

Takeaway: Agent Notes는 폴더 경로로 상태를 담고, 포맷 게이트로 노트마다 “왜”와 “누구를 이겼는지”를 쓰게 하며, 비일상 변경은 같은 PR에 노트를 붙여야 해요. AGENTS.md는 집행 가능한 하드 계약만 받아요. 기억 상실을 막는 핵심 동작은 하나: 반려된 안을 이유와 함께 동결 보관하는 것.