Harness Case Study

AI 연구자 카파시의 트윗 한 편이
진짜 명령어 도구가 되기까지

AI 연구자 안드레이 카파시가 트위터에 던진 아이디어 하나를, 실제로 돌아가는 프로그램으로 만든 기록입니다. 그 아이디어는 “LLM(ChatGPT 같은 AI)이 스스로 관리하는 지식 저장소”. 이걸 하네스(harness, AI가 ‘다 됐다’고 대충 끝내지 못하게 증거를 강제하는 자동 감시 장치)로 구현했습니다. 결과는 코드 저장 4번, 파이썬 코드 2,214줄, 원글이 요구한 기능 100% 구현.

4
Commits
2,214
Lines of Code
23
Tests Passing
100%
Feature Coverage
~3h
Total Time
시작은 카파시의 트윗 한 줄이었다
“It would be nice to have a single markdown-based knowledge base where an LLM is responsible for maintaining and compiling it. You feed it raw data (articles, papers, images, clippings), and the LLM compiles it into a structured wiki with backlinks and indexes. You then query it, generate slides, charts, reports from it.” — Andrej Karpathy, @karpathy on X

이 트윗 한 줄이 실제로 쓰는 명령어 도구(CLI, 터미널에 타이핑해 실행하는 프로그램)가 되려면 무엇이 필요했나. 답은 제대로 된 하네스, 즉 작업이 진짜 끝났는지 자동으로 검증해 주는 장치였다.

raw/
LLM compile
wiki/
LLM query
output/
articles, papers, images → structured wiki → slides, charts, reports
구현 과정: 코드 저장 기록(커밋) 4번으로 따라가기
8093409 · 2026-04-05 00:33
지식 저장소 전체를 한 번에 구현 (카파시가 제안한 구조 그대로)
코드 저장 한 번에 프로젝트 뼈대를 통째로 세웠다. 담긴 것은 이렇다. 명령어 도구(CLI)의 하위 명령 7개, Claude를 코드에서 부르는 공식 라이브러리(Anthropic SDK) 연결, 바뀐 문서만 다시 처리하는 증분 컴파일, 단어 빈도로 문서를 찾는 검색(TF-IDF), 슬라이드 만들기(Marp)와 차트 그리기(matplotlib), 파이썬 웹 화면(Flask), 그리고 자동 테스트 23개(pytest).
39 files · +3,073 lines · src/lkb/(11) + tests/(5) + .claude/(5) + wiki/(5) + samples
dadd74d · 2026-04-05 00:50
AI를 부르는 경로를 두 갈래로 — 구독(Claude Code)과 API 키(Anthropic SDK) 둘 다 지원
유료 API 키가 없어도 Claude Code 구독만으로 돌아가게, AI를 부르는 경로를 둘로 나눴다. 어떤 경로를 쓸지는 자동으로 감지하고, LKB_BACKEND 라는 실행 설정값으로 직접 지정할 수도 있다. 그리고 llm.py 라는 중간 연결 코드가 두 경로를 티 안 나게 알아서 이어준다.
src/lkb/llm.py · 코드 135줄 추가
e7e359e · 2026-04-05 00:58
버그 수정: AI 답변에서 슬라이드·리포트에 쓸 문서 서식(마크다운)만 자동으로 뽑아내기
Claude Code가 슬라이드 내용에 잡담 같은 설명 문장을 섞어서 답하던 문제를 고쳤다. 텍스트에서 원하는 패턴만 골라내는 규칙(정규식)을 써서 마크다운 부분만 뽑아내, 깔끔한 슬라이드와 리포트를 만든다.
src/lkb/output.py · +60 -15 lines
08a1a19 · 2026-04-05 01:33
누락됐던 기능 4개 추가 — 원글이 요구한 기능 100% 채움
카파시의 원글을 다시 읽어 빠진 기능을 찾아냈다 → lint --deep(AI가 문서 뜻을 읽고 빠진 주제를 찾음), output --file(만든 결과물을 저장소에 되넣기), websearch.py(웹 검색은 Tavily 서비스로, 안 되면 Claude가 대신), ask further questions(이어서 파고들 질문 3개 자동 생성).
8 files · +481 lines · lint.py +143 · websearch.py +111 · ask.py/output.py/cli.py 코드 확장
하네스가 대신 처리해 준 것들

코드 2,214줄과 테스트 23개가 단 3시간 만에 나온 이유가 여기 있다. 하네스가 아래 일들을 자동으로 처리해 줬기 때문이다.

/init-project
프로젝트를 훑어 파이썬 3.11 이상이라는 기술 구성을 자동으로 알아낸다. 그 내용을 .claude/CLAUDE.md라는 규칙 파일에 빌드 명령·구조·기술 스택 표로 정리해 준다.
.claude/skills/
이 프로젝트만의 작업 규칙을 담은 안내 파일 4개(백엔드 패턴·구현 계획·QA 시나리오·QA 전략)를 자동으로 만든다. 프로젝트 방식을 고정해, 만들 때마다 기준이 흔들리지 않게 한다.
/team Phase 0~3
기능 단위(모듈) 11개로 이뤄진 src/lkb/ 구조를 먼저 설계한 뒤, 구현을 나눠 맡긴다. 명령어·AI 연결·컴파일·검색·출력·점검·웹 화면을 각 담당 에이전트에게 분배한다.
/qa-scenario-gen
테스트 시나리오를 자동으로 만든다. 저장한 데이터를 다시 불러와 맞는지 확인하기(CRUD 라운드트립), 증분 컴파일, 문서끼리의 연결(백링크)이 안 깨졌는지, 인터넷 없이도 되는지 등 테스트 상황 23개를 뽑아냈다.
/qa-cycle
자동 테스트 23개를 전부(23/23) 통과시키고, 코드 검사·정리 도구(ruff)를 반복해서 돌린다. 실패하면 버그 수정 담당을 자동으로 부른다. 앞의 세 번째 커밋이 바로 그렇게 나온 것이다.
/self-improve
원글을 다시 분석해 빠진 기능 4개를 스스로 찾아냈다(네 번째 커밋). ‘이미 100% 됐다’는 판단을 일부러 의심하고 되짚어 검증하는 순환 구조(폐루프)다.
/loopy-era-eval
‘완성’의 기준을 숫자 하나로 못 박는다. 원글 대비 구현 비율(커버리지 %)을 강제로 측정하고, 기준에 못 미치면 그 결과를 버린다.
.completion-check.md
기능 18개를 하나씩 ‘통과/실패’로 표시하고, 각 근거 파일을 연결한 표를 만든다. 원글의 어느 요구가 됐고 안 됐는지 추적할 수 있는 완료 점검 문서를 자동으로 유지한다.
구현 결과: 기능 단위(모듈) 11개
모듈(기능 단위)줄 수역할
cli.py155사용자가 명령어를 입력하는 진입점(Click 라이브러리 사용). 하위 명령 7개: 수집·컴파일·질문·검색·출력·점검·웹
compile.py327원본(raw/) 폴더를 정리된 위키(wiki/)로 변환. 파일 수정 시각(mtime)을 기준으로 바뀐 것만 다시 처리하고, 문서끼리의 연결(백링크)을 자동 생성
output.py323슬라이드(Marp)·차트(matplotlib)·마크다운 리포트 생성. 여기에 --file 옵션을 붙이면 결과물을 위키에 되넣는다
llm.py281AI 호출 경로 2개(구독형 Claude Code, API 키형 Anthropic SDK)를 관리. 사용량(토큰) 집계와 실패 시 재시도 포함
lint.py359문서를 실행 없이 검사해 깨진 링크를 찾고, --deep 옵션을 켜면 AI가 뜻까지 읽어 빠진 주제나 앞뒤 모순을 잡아낸다
ingest.py174파일이나 웹 주소(URL)에서 문서를 가져온다. 이미지는 자동으로 내려받고, 브라우저 웹 스크랩 도구와도 호환
web.py195파이썬 웹 서버(Flask)로 만든 다크 모드 웹 화면 — 문서 둘러보기와 검색
search.py124단어 빈도 방식(TF-IDF)의 본문 검색 (명령어와 웹 화면 양쪽에서 사용)
websearch.py111웹 검색은 Tavily 서비스로, 안 되면 Claude가 대신. 점검(lint)에서 빠진 주제의 참고 링크를 제안
ask.py85질문·답변 기능 + 이어서 파고들 질문 3개 자동 생성
config.py77실행 설정값과 파일 경로 관리
23/23
pytest pass
PASS
ruff check
18/18
feature coverage
2
LLM backends
원글이 요구한 기능, 100% 다 구현했나 대조표
카파시가 원글에서 말한 것구현증거
raw → compile → wikiPASScompile.py 바뀐 것만 처리하는 증분 컴파일
목차·요약 자동 생성PASS_index.md, _summaries.md
문서 간 연결(백링크, 노트 앱 Obsidian과 호환)PASS[[...]] 문법
Q&APASSask.py
이어서 파고들 질문 제안PASS답변 끝에 ‘더 알아볼 질문’ 3개 첨부
슬라이드 생성(Marp)PASSoutput slides
차트 생성(matplotlib)PASSoutput chart
마크다운 리포트PASSoutput report
Output → Wiki filingPASS--filewiki/outputs/
문서 점검(깨진 링크 찾기)PASSlint.py 실행 없이 검사
AI 의미 점검(deep lint)PASSlint --deep: 빠진 글 4개 탐지
빠진 자료를 웹 검색으로 보완PASSwebsearch.py Tavily, 안 되면 Claude
본문 검색(명령어)PASSsearch.py
웹 화면PASSweb.py Flask
CLI as LLM toolPASS다른 프로그램에서 불러 쓰는 예시를 안내 문서에 명시
Obsidian Web ClipperPASS안내 문서에 연동 가이드 수록
AI 호출 경로 2개PASSClaude Code + SDK
바뀐 것만 처리하는 증분 컴파일PASS파일 수정 시각 기준

굵은 글씨 6개는 첫 버전(v0.1)에서 빠졌다가, 하네스의 self-improve 단계가 원글을 다시 분석해 두 번째 버전(v0.2)에 채워 넣은 기능이다.

하네스가 진짜로 값어치를 하는 지점
하네스 없이

트윗을 읽고 “오, 흥미로운데” 하고 그냥 넘긴다. 만든다 해도 기본 변환 기능(compile.py)까지만 만들고, 문서 점검(lint)과 두 번째 AI 호출 경로, 결과 되넣기(filing)는 전부 빠뜨린다. 원글을 다시 펼쳐 볼 이유가 없기 때문이다.

하네스와 함께

3시간 만에 기능 11개, 코드 2,214줄이 나온다. 게다가 self-improve 단계가 ‘다 끝났다’는 선언을 의심하고 원글을 다시 검증해서, 빠진 기능 4개를 스스로 찾아낸다. 원글 요구의 100% 달성까지 자동으로 추적한다.

핵심 통찰

첫 버전(v0.1)의 ‘완성’을 의심하지 않았다면 AI 의미 점검(lint --deep), 결과 되넣기(output --file), 웹 검색(websearch), 후속 질문(further questions), 이 4개 기능은 영영 빠진 채였을 것이다. 하네스의 self-improve 단계가 ‘원글을 다시 읽어라’는 규칙을 강제로 실행한 결과가 바로 08a1a19 커밋이다.

프로젝트: llm-knowledge-base · 2026-04-05

Inspired by @karpathy's LLM Knowledge Bases