AGENTS.md가 작업을 분류해 필요한 논제 하나로만 안내하고, 나머지는 필요할 때만 로드된다.
lopopolo/harness-engineering · 문서형 저장소(실행 앱 아님) · 논제 12개(docs/) · 플레이북 2 + 평가 가이드 1 · 출처 매니페스트 sources.json 92건(schema v2) · 프로즈 md/mdx 약 10,365줄 · 검증 툴 Python 3.13 + uv · 라이선스 CC BY 4.0 · 최신 커밋 226c8d3(2026-07-18) · 클론 소스 직접 분석)
사람이 처음부터 끝까지 정독하는 책이 아니다. 코딩 에이전트에게 "이 저장소를, 네가 고칠 시스템과 함께 봐"라고 던져주면, 에이전트가 루트의 AGENTS.md를 읽고 지금 작업에 필요한 논제 하나만 골라 로드한다. 나머지 11개 논제와 92개 출처는 그대로 잠들어 있다가, 결정을 바꿀 수 있을 때만 깨어난다.
즉 이 저장소의 정체는 두 겹이다. ① 내용: "하네스 엔지니어링"이라는 2026년 실천 운동의 교본(12개 논제). ② 형식: 그 교본을 에이전트가 소비하기 좋은 모양으로 짠 아키텍처 자체가, 6번 논제("저장소가 에이전트를 가르치게 하라")의 실물 예시다.
저자 Ryan Lopopolo는 OpenAI에서 코딩 에이전트 Codex를 다루는 엔지니어로, "하네스 엔지니어링"이라는 용어의 원조 에세이(2026-02-11, openai.com)를 쓴 사람이다. 이 저장소 README 맨 위에 그가 트위터에 남긴 말이 걸려 있다 — 자기 글·트윗·팟캐스트·강연에 에이전트를 갖다 대기만 해도 출력이 크게 좋아진다는 것. 이 저장소는 바로 그 "갖다 댈 대상"을, 흩어진 링크가 아니라 하나의 정돈된 컨텍스트로 묶은 결과물이다.
AGENTS.md)를 두고, ② 한 번에 전부가 아니라 필요한 조각만 적시에 읽히게 구조화하며, ③ 각 주장에 출처·라이선스 경계를 붙여 재배포 가능 범위를 명시한다는 것이다.규모 감각을 잡아 보자. 프로즈(.md/.mdx)가 약 10,365줄, 그중 12개 논제 본문과 2개 플레이북·평가 가이드가 알맹이다. 여기에 출처를 기계적으로 검증하는 파이썬 스크립트 5개(약 2,700줄)와 92건짜리 출처 매니페스트(sources.json)가 붙는다. 별점 수치는 이 글에서 인용하지 않지만, TrendShift 데일리 #9에 오른 이유는 분명하다 — "하네스 엔지니어링"이 2026년 에이전트 개발의 핵심 키워드로 떠올랐고, 이 저장소가 그 개념의 정본(canonical) 레퍼런스를 자처하기 때문이다.
"AI 에이전트를 잘 쓰는 법"을 정리한 자료는 널려 있다. awesome-* 리스트, 미디엄 블로그, 프롬프트 모음집… 그런데 이들 대부분은 사람이 읽는 것을 전제로 만들어졌다. harness-engineering이 눈에 띄는 이유는, 처음부터 끝까지 "코딩 에이전트가 소비할 것"을 겨냥해 설계됐다는 점이다. 저자 스스로 사용법을 이렇게 적는다 — "코딩 에이전트를 이 저장소와, 그 에이전트가 개선할 시스템에 동시에 갖다 대라."
6번 논제의 제목은 "저장소가 에이전트를 가르치게 하라(Make the repository teach the agent)"이다. 그리고 이 저장소 자체가 그 원칙의 시연이다. 루트 AGENTS.md가 작업을 분류해 딱 필요한 논제 하나로 라우팅하고, 각 폴더마다 편집 규칙(AGENTS.md/CLAUDE.md)이 중첩돼 있으며, 출처는 타입이 붙은 JSON으로 관리되고 파이썬으로 검증된다. 문서의 내용(what)과 문서의 구조(how)가 같은 주장을 두 번 한다.
요리책 vs. 잘 정리된 주방. 보통의 "AI 팁 모음"은 두꺼운 요리책이다 — 처음부터 끝까지 읽어야 뭐가 어디 있는지 안다. harness-engineering은 잘 정리된 주방에 가깝다. 입구(AGENTS.md)에 "지금 만들 요리가 뭐냐"만 답하면, 필요한 칸(논제 하나)으로 안내하고 나머지 서랍은 닫힌 채 둔다. 요리사(에이전트)는 냉장고를 통째로 뒤질 필요가 없다.
에이전트에게 컨텍스트를 많이 주는 것과 잘 주는 것은 다르다. 12개 논제 + 92개 출처를 한꺼번에 프롬프트에 밀어넣으면 오히려 주의가 흐려지고 비용이 폭증한다. 이 저장소의 핵심 불변식은 "큰 탐색 가능한 지식 저장소 + 작은 활성 작업 세트"다. 루트가 안내만 하고, 논제 본문이 종합하며, 사례·1차 출처는 "결정을 바꿀 수 있을 때만" 로드된다. 이 점진적 공개(progressive disclosure)가 성능과 직결된다.
블로그 글은 링크만 걸면 끝이지만, 이 저장소는 92개 출처 각각에 대해 정본 URL·저자·날짜·아카이브 위치·로컬 스냅샷·라이선스·검토 날짜를 sources.json에 기록하고, 파이썬 검증기로 무결성을 자동 점검한다(해시·경로·상호참조). "누구 말인지, 재배포해도 되는지"를 기계가 확인하는 것이다. 이는 AI 학습자료가 흔히 놓치는 저작권·출처 위생을 정면으로 다룬다.
"하네스 엔지니어링"이라는 뜨는 개념의 원조 저자가 직접 정리한 정본이라는 권위, 그리고 그 저장소 구조 자체가 "에이전트용 저장소를 어떻게 짜는가"의 모범답안이라는 이중 가치. 여기에 CC BY 4.0으로 자유 재사용까지 열어 두어, 각자 자기 저장소에 이식하기 쉽다.
npm 패키지도, CLI도, 플러그인도 아니다. pip install이나 npm i로 뭔가 돌아가는 게 아니라, 읽히는 텍스트다. 유일하게 "실행"되는 부분은 출처 검증용 파이썬 스크립트뿐이고, 그건 저장소를 편집·유지보수하는 사람을 위한 것이지 사용자가 매번 돌리는 게 아니다. 사용법은 "에이전트에게 읽히기"다.
이 저장소엔 웹 서버도 UI도 없다. 그래서 스택을 세 개의 층으로 다시 그린다: 사람과 에이전트가 읽는 콘텐츠 층, 출처를 기록하는 데이터 층, 그 데이터를 검증하는 도구 층.
| 요소 | 정체 · 역할 |
|---|---|
| Markdown (.md) | 논제 본문·플레이북·라우팅 문서의 기본 포맷. 총 48개 파일 |
| MDX (.mdx) | sources/raw/에 보존한 원문 스냅샷(하이퍼볼라 글 14편 + ACP 문서). 15개 |
| Prettier | .prettierrc.json에서 proseWrap: always — 산문을 항상 줄바꿈해 diff를 안정시킨다(에이전트가 만드는 변경도 깔끔) |
| .gitattributes | 스냅샷·트위터 코퍼스를 linguist-vendored로 표시 → 언어 통계·diff에서 제3자 원문 제외 |
모든 출처는 sources/sources.json 한 곳에 모인다. 단순 링크 목록이 아니라 스키마가 있는(schema_version 2) 구조다.
# sources.json 최상위 (발췌)
{
"schema_version": 2,
"as_of": "2026-07-18",
"maintainer": "Ryan Lopopolo",
"license": { "id": "CC-BY-4.0", ... },
"sources": [ /* 92건: 글·강연·트윗·영향·사례 */ ]
}
각 출처 레코드는 출처의 종류(kind)와 증거 취급 방식(evidence.type)을 분리해 기록한다. 증거 타입은 네 가지다:
| evidence.type | 뜻 |
|---|---|
| linked | 링크만 보존(정본 URL + 아카이브 URL). 재배포 권리 없음 |
| snapshot | 바이트를 로컬에 저장 + sha256 해시 + 취득일 + 권리 근거 |
| repository_note | 저장소가 직접 쓴 관찰(버전 이력이 곧 출처) |
| private_review | 비공개 자료 — 접근 라벨만 남기고 원문은 노출 금지 |
검증·수집 로직은 sources/scripts/에 있다. 특징은 전부 uv 단일 파일 스크립트(PEP 723) — 의존성을 파일 상단 주석에 박아, 별도 설치 없이 uv run 한 방으로 돈다.
| 스크립트 | 줄수 | 역할 |
|---|---|---|
| source_manifest.py | 673 | 매니페스트의 타입드 모델 + JSON 경계 파서(핵심) |
| twitter_corpus.py | 858 | 공개 X 게시물 코퍼스의 타입드 모델·정합성 |
| test_manifest.py | 668 | 매니페스트/코퍼스 단위 테스트 |
| validate_manifest.py | 281 | 실행 진입점 — 관계·해시·경로 검증기 |
| fetch_openai.py | 141 | 원조 에세이 페치 헬퍼(httpx + stamina 재시도) |
source_manifest.py는 이 저장소에서 가장 "코드다운 코드"이자, 6번 논제를 파이썬으로 시연한 부분이다. Parse, don't validate 원칙을 그대로 적용한다 — 외부 JSON을 받아 한 번 파싱해서 신뢰할 수 있는 도메인 타입으로 바꾸고, 이후 내부 코드는 그 타입만 믿는다.
# source_manifest.py — 브랜디드 타입 + 엄격한 경계 파서 (발췌)
SCHEMA_VERSION = 2
SOURCE_ID = re.compile(r"[a-z0-9]+(?:-[a-z0-9]+)*\Z")
SHA256 = re.compile(r"[0-9a-f]{64}\Z")
SourceId = NewType("SourceId", str) # 브랜디드 타입
Sha256Digest = NewType("Sha256Digest", str)
def require_https(value, name):
parsed = urlsplit(require_text(value, name))
if parsed.scheme != "https" or not parsed.netloc:
raise ValueError(f"{name}는 절대 HTTPS URL이어야")
return HttpsUrl(parsed_ok) # 통과한 값에만 타입 부여
uv는 Rust로 짠 초고속 파이썬 패키지/실행 도구다. PEP 723은 스크립트 맨 위 주석에 필요한 파이썬 버전·의존성을 직접 적는 표준. 그러면 uv run --script foo.py가 격리 환경을 즉석에서 만들어 실행한다. "requirements.txt도, 가상환경 활성화도 없이" 파일 하나가 곧 실행 단위가 된다. fetch_openai.py 상단이 실제 예시다:# /// script
# requires-python = ">=3.13"
# dependencies = ["httpx==0.28.1", "stamina==26.1.0"]
# ///
불변식 6번: "번들을 비례적으로 유지한다" — 링크와 데이터를 검증하려고 빌드 시스템이나 의존성 그래프를 일부러 두지 않는다. 문서 저장소에 과한 기계장치를 얹지 않는 것. 그래서 스택 지도가 이렇게 얇다: Markdown + JSON + 파이썬 5개 파일. 이 "덜어냄" 자체가 이 저장소의 주장(과잉 통제는 오히려 해롭다)과 일치한다.
ARCHITECTURE.md는 이 저장소를 한 문장으로 규정한다: "검색에 최적화된 컨텍스트 번들". 루트는 소개하고 안내하며, 에이전트 가이드는 작업별 결정을 라우팅하고, 논제 색인은 발전된 논증들의 이름을 대며, 플레이북은 그것을 절차로 바꾸고, 출처 라이브러리는 증거를 보존한다. 각 층은 자기 일만 하고 다음 깊이를 가리킨다.
여기서 핵심은 "라우팅은 적시에(route just in time)"라는 불변식이다. 보통의 작업은 가장 작은 관련 논제 집합만 받는다. 사례와 출처 코퍼스는 결정을 바꿀 수 있을 때만 로드된다. 이게 4번 논제(컨텍스트를 적시에 라우팅)의 실행이다.
소비자와 별개로, 저장소를 고치는 사람/에이전트는 각 폴더의 중첩 가이드를 따른다. 이 이중 경로가 "읽기용 문서"와 "편집 규칙"을 깔끔히 분리한다.
README.md=공개 정의·약속·진입점, AGENTS.md=라우팅, docs/README.md=논제 색인, sources/=증거·출처. 한 개념은 한 곳에서만 정의되고 나머지는 그리로 링크한다. 중복 정의는 "에이전트가 따를 수 있는 상충하는 선례"를 만들기 때문에 금기다.| # | 불변식 | 뜻 |
|---|---|---|
| 1 | 하나의 내비게이션 계약 | 루트=소개·라우팅, docs/README=색인, 논제=종합, evals·playbooks=적용, sources=증거. 역할 고정 |
| 2 | 적시 라우팅 | 보통 작업엔 최소 논제 집합만. 사례·코퍼스는 결정을 바꿀 때만 로드 |
| 3 | 논증과 증거의 분리 | 완결된 논증은 논제 페이지에, 원문·출처는 라이브러리에 |
| 4 | 경계에서 권리 보존 | 로컬 스냅샷은 재배포 근거가 있을 때만. 아니면 링크+메타+제한 인용 |
| 5 | 행동 효과로 테스트 | 에이전트가 용어를 따라 말하는 것이 아니라 결정이 바뀔 때 성공 |
| 6 | 번들을 비례적으로 | 링크·데이터 검증에 빌드 시스템·의존성 그래프를 두지 않음 |
도서관의 안내 데스크 vs. 서고. 큰 도서관(92개 출처 = 서고)을 통째로 짊어지고 다니면 아무 일도 못 한다. 대신 입구의 안내 데스크(AGENTS.md)가 "당신 질문엔 이 책 한 권"이라 짚어 주고, 그 책이 필요로 할 때만 서고의 원자료를 꺼내 온다. 불변식 2번 "적시 라우팅"이 바로 이 안내 데스크의 규칙이다.
눈여겨볼 패턴은 중첩된 AGENTS.md/CLAUDE.md다. 루트뿐 아니라 docs/·playbooks/·sources/·sources/scripts/ 각각에 편집 규칙이 놓여 있다. 에이전트가 그 폴더로 "내려갈 때" 그 층의 규칙을 적시에 만나도록 — 여기서도 4번 논제(적시 라우팅)가 파일 배치로 구현돼 있다.
docs/ 아래 폴더는 12개 논제 + lineage(계보)다. lineage는 논제가 아니라 "영향·대안 프레이밍"을 다루는 관련작업 섹션이라, 색인(docs/README.md)은 "열두 개 논제(twelve theses)"라고 명시한다. 폴더 수만 세면 13개로 오해하기 쉽다.
가장 실용적인 수확. 당신의 프로젝트에도 AGENTS.md를 두고, "작업 유형 → 읽어야 할 문서 1~2개"로 라우팅하라. 전부를 README에 몰아넣지 말고, 작은 활성 세트 + 큰 탐색 저장소로 나눠라. CLAUDE.md는 @AGENTS.md 한 줄로 임포트하고 "링크는 적시에 따라가라"만 지시하면 된다.
source_manifest.py는 외부 JSON을 받아 경계에서 한 번 파싱해 브랜디드 타입(NewType)으로 바꾼다. 이후 내부 로직은 "이 값은 이미 HTTPS URL이다/이미 sha256이다"를 타입으로 보장받는다. 함수마다 재검증하는 방어 코드가 사라진다. 데이터 파이프라인·설정 로더를 짤 때 그대로 이식할 수 있는 패턴이다.
당신이 쓰는 config.json/.env를 받아, @dataclass(frozen=True) + NewType으로 파싱 함수 하나를 만들어 보라. 잘못된 값은 로딩 시점에 예외로 죽고, 통과한 값만 타입을 얻는다. 그다음 validate_*.py처럼 CI에서 도는 검증 스크립트를 붙이면 끝.
AI 학습자료를 만들다 보면 "이 그림·이 문장, 재배포해도 되나?"가 늘 걸린다. 이 저장소는 그걸 데이터 모델로 푼다: 증거 타입 4종, 스냅샷엔 해시·취득일·권리 근거, 제3자 원문은 linguist-vendored로 격리. "링크·아카이브·인용은 재라이선스가 아니다"를 COPYING.md가 반복해 못박는다.
| 논제 | 내 저장소에 물어볼 질문 |
|---|---|
| 1. 워커 고정 | 모델/에이전트를 바꿨을 때 무엇을 재검증해야 하나? |
| 4. 적시 컨텍스트 | 에이전트가 필요한 문서를 전부 로드하지 않고 찾을 수 있나? |
| 5. 도구 가독성 | 도구가 존재하지만 발견·해석이 어려워 사람이 중계하고 있진 않나? |
| 6. 저장소가 가르침 | 한 개념에 권위 있는 주인 하나가 있나? 반쯤 끝난 마이그레이션이 상충 선례를 남기진 않았나? |
| 7. 권한 vs 능력 | 위험한 변경에 범위·승인·감사·복구 계약이 분리돼 있나? |
| 8. 증명 | 초록불 테스트가 사용자 주장을 증명하나, 내부 일관성만 증명하나? |
| 12. 효과성 | 토큰·줄 수가 아니라 희소한 사람 주의당 유용한 결과로 최적화하나? |
신입에게 넘기는 "사수의 감". 예전엔 코드 품질 기준(어디까지 다듬을지, 어떤 지름길이 허용되는지)을 옆자리 선배가 눈치로 알려줬다. 에이전트에겐 옆자리가 없다. 그래서 그 "사수의 감"을 예시 코드·타입·린트·리뷰 정책으로 저장소에 심어 둔다. 이게 "저장소가 에이전트를 가르친다"의 실제 의미다.
| 용도 | 요구사항 |
|---|---|
| 그냥 읽기 | 아무것도 필요 없음 — GitHub 웹, 아무 마크다운 뷰어, 또는 코딩 에이전트 |
| 에이전트에 적용 | 코딩 에이전트(Codex·Claude Code 등) + 개선할 대상 저장소. 번들은 읽기 전용 보조 컨텍스트 |
| 출처 검증 실행 | uv + Python ≥ 3.13. uv run --script sources/scripts/validate_manifest.py / test_manifest.py |
| 에세이 페치 | fetch_openai.py — 의존성(httpx·stamina)은 uv가 자동 설치. Cloudflare 차단 시 정본→아카이브 순 시도 |
| GPU | 불필요. 로컬 추론 없음 — 에이전트가 알아서 자기 모델을 쓴다 |
즉 "무거운 실행 환경"이 없다. 불변식 6번대로, 이 저장소는 자기 링크·데이터를 검증할 딱 그만큼의 파이썬만 둔다. 검증 스크립트조차 편집자용이지 사용자용이 아니다. 사용자에게 필요한 건 사실상 "에이전트에게 이 폴더를 읽혀라" 한 줄이다.
플레이북은 못박는다 — 번들을 다른 대상에 적용할 때 그것은 보조적·읽기 전용이다. 대상의 지시·소유자·계약·현재 상태가 로컬 진실로서 지배한다. "권한을 넓히거나, 채점 기준을 약화시켜 통과시키거나, 자기보고를 정책으로 승격"하지 말라. 변경 권한이 없으면 증거·제안까지만 기록하고 멈추라.
git clone --depth 1로 내려받고 uv run --script sources/scripts/validate_manifest.py를 실행해 92개 출처가 검증을 통과하는지 확인한다. 그다음 docs/domain-modeling/README.md를 읽고, 본문 각주 링크가 sources.json의 어떤 레코드로 이어지는지 한 개만 손으로 추적해 본다. "논증 ↔ 증거" 분리(불변식 3)를 눈으로 확인.
당신 프로젝트에 AGENTS.md를 만들고 "작업 유형 → 읽어야 할 문서 1~2개" 표를 넣는다. 규칙: 미해결 결정이 있을 때만 논제로 보내고, 없으면 그냥 진행하라고 써라. CLAUDE.md엔 @AGENTS.md + "링크는 적시에, 전체 선로딩 금지"만. 에이전트에게 실제 작업을 시켜 필요한 문서만 여는지 관찰.
당신 저장소에서 에이전트가 자꾸 헛도는 반복 작업 하나를 고른다. 플레이북 순서대로: ① 기준선 관찰 → ② 가장 이른 실패 핸드오프 지목(컨텍스트/능력/도메인/권한/증명/피드백 중 분류) → ③ 가장 작은 되돌릴 수 있는 개입 → ④ 대상 네이티브 검사로 검증 → ⑤ 새 세션으로 재실행 → ⑥ 유지/수정/제거 판정. 결과 기록표까지 채운다.
source_manifest.py를 본떠, 당신 데이터(북마크·데이터셋 카탈로그 등)를 위한 JSON 스키마 + 경계 파서를 NewType·@dataclass(frozen=True)로 짠다. require_https()처럼 통과한 값에만 타입을 부여하고, 잘못된 입력은 로딩 시 예외로. test_*.py로 엣지 케이스 테스트를 붙이고 PEP 723으로 uv run 단일 파일로 만든다.
evals/README.md대로 개입 하나(예: 컨텍스트 라우팅 추가)를 격리한다. 워커(모델·에이전트)를 고정하고 대상·작업·권한·외부 상태를 동일하게 맞춘 뒤, 개입 유무 두 조건을 순서 무작위·복수 반복으로 돌린다. 결과를 수용된 결과 · 증명 · 아키텍처 · 궤적 비용(토큰·재시도) 네 축으로 따로 채점. "개입이 실제로 회수/호출됐는지"를 별도 사실로 기록해, 무효 결과(한 번의 롤아웃을 대표로 취급 등)를 피한다.
| 주차 | 주제 · 목표 | 핵심 자료 |
|---|---|---|
| 1주차 | 하네스 엔지니어링 개념 잡기. 원조 에세이 정독 + 12개 논제 훑기. "모델을 고정하고 환경을 엔지니어링한다"는 관점 체화 | OpenAI 에세이 · docs/README.md 색인 · README.md |
| 2주차 | 적시 컨텍스트 · 점진적 공개. AGENTS.md/CLAUDE.md 규약, 라우팅 vs 선로딩. 내 저장소에 라우팅 문서 직접 작성 | docs/just-in-time-context/ · AGENTS.md · ARCHITECTURE.md |
| 3주차 | 타입드 경계 설계. Parse-don't-validate, Python NewType/dataclass, PEP 723·uv 단일 파일 스크립트. 검증기+테스트 구현 |
sources/scripts/source_manifest.py · Alexis King 원글 · uv/PEP 723 문서 |
| 4주차 | 증명·권한·평가. 주장-정합 증거(proof), 권한 vs 능력 분리(authority), 하네스 효과 측정(evals)·출처 위생(COPYING) | docs/proof/ · docs/authority/ · evals/ · COPYING.md |
docs/lineage/가 밝히듯, 이 실천의 뿌리엔 matklad의 ARCHITECTURE.md(짧고 안정적인 코드맵), Alexis King의 "Parse, don't validate", Martin Fowler의 Strangler Fig(점진적 교체) 같은 고전이 있다. 새로운 유행처럼 보이지만, 좋은 소프트웨어 아키텍처 원칙을 "에이전트 독자"에게 맞춰 재조립한 것에 가깝다.
CLAUDE.md는 이를 임포트.source_manifest.py가 실제 적용. (Alexis King, 2019)uv run --script가 즉석 격리 환경으로 실행.sources.json이 출처를 증거 취급 방식으로 나누는 4분류. 링크만 / 해시 붙인 로컬 사본 / 저장소 자체 관찰 / 비공개(접근 라벨만).