오늘 하루 만에 개인 지식 베이스를 만들고, 그걸 Telegram으로 원격 조종하는 시스템을 만들었다. 돌이켜보면 이것이 나의 첫 하네스 엔지니어링이었다.
시작: Karpathy의 LLM Wiki
모든 것은 Andrej Karpathy의 LLM Wiki 패턴에서 시작했다. 핵심 아이디어는 간단하다 — RAG처럼 매번 원본에서 검색하는 대신, LLM이 위키를 점진적으로 구축하고 유지관리하게 만드는 것이다.
구조는 3계층이다:
- Raw sources (
raw/) — 원본 자료. 불변. - Wiki (
wangsyObsidian/) — LLM이 유지관리하는 마크다운 파일들. Obsidian vault. - Schema (
CLAUDE.md) — LLM에게 “이렇게 일해라”를 알려주는 규칙서.
Claude Code를 열고 Karpathy Gist를 공유하면서 시작했다. Claude가 기존 Obsidian vault 구조를 분석하고, CLAUDE.md 스키마를 작성하고, index.md와 log.md를 생성하고, 기존 42개 페이지를 색인했다. 한 시간도 안 걸렸다.
문제: 이 컴퓨터 앞에 앉아 있어야 한다
위키가 돌아가기 시작하니까 바로 문제가 보였다. 원격에서는 쓸 수가 없다.
출퇴근길에 흥미로운 기사를 발견해도, 회의 중에 메모할 것이 생겨도, 집 컴퓨터 앞에 앉아서 Claude Code를 열어야만 ingest할 수 있다. 지식 베이스는 24시간인데 입력 통로는 컴퓨터 앞에 있는 시간만큼만 열려 있는 셈이다.
내가 원한 것은 세 가지였다:
- 어디서든 URL이나 텍스트를 보내면 즉시 ingest
- 어디서든 질문하면 위키 기반으로 답변
- 이미 매일 쓰고 있는 앱에서
답은 Telegram Bot이었다.
아키텍처: 봇은 얇게, 두뇌는 Claude에게
설계 원칙을 하나 잡았다: 봇은 메시지를 중계할 뿐, 모든 지식 작업은 Claude Code가 한다.
스마트폰 → Telegram → Bot 서버(내 PC) → Claude Code CLI → Wiki
봇의 역할은 정말 단순하다:
- Telegram 메시지를 받는다
claude -p로 Claude Code에 전달한다- 결과를 Telegram으로 돌려보낸다
위키의 모든 규칙(어디에 저장할지, 어떻게 교차참조할지, index를 어떻게 업데이트할지)은 CLAUDE.md에 있고, Claude Code가 그대로 따른다. 봇 코드에는 위키 로직이 한 줄도 없다.
이게 왜 중요한가? 하네스 엔지니어링의 핵심 원칙과 연결된다:
“에이전트가 실수하면 에이전트가 아니라 하네스를 고쳐라”
봇이 위키 로직을 갖고 있으면, 규칙을 바꿀 때 봇 코드와 CLAUDE.md 두 곳을 고쳐야 한다. 봇을 얇게 유지하면 CLAUDE.md만 고치면 된다. 하네스(CLAUDE.md)가 단일 진실의 근원이 된다.
구현: 생각보다 간단했다
Telegram Bot 생성
BotFather에게 /newbot — 30초면 끝난다. 토큰을 받는다.
봇 코드 (Python, 약 100줄)
핵심은 run_claude 함수 하나다:
async def run_claude(prompt: str) -> str:
proc = await asyncio.create_subprocess_exec(
"claude", "-p",
"--allowedTools", "Read,Write,Edit,Glob,Grep,WebFetch,...",
cwd=str(WIKI_DIR),
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await proc.communicate(input=prompt.encode())
return stdout.decode().strip()
claude -p는 Claude Code의 비대화형 모드다. stdin으로 프롬프트를 넘기면 stdout으로 결과가 나온다. --allowedTools로 필요한 도구(파일 읽기/쓰기, 웹 가져오기)를 허용한다.
나머지는 Telegram 핸들러를 붙이는 것 뿐:
- URL이 오면 → “이 URL을 ingest해줘”
- 텍스트가 오면 → “위키에서 이 질문에 답해줘”
- 파일이 오면 →
raw/에 저장 → “이 파일을 ingest해줘” /lint명령 → “위키를 lint해줘”
systemd로 상시 운영
.service 파일 하나 만들고 systemctl enable --now — PC가 켜져 있는 한 봇은 항상 살아 있다.
실사용 흐름
출퇴근길에 기사 발견:
Telegram에 URL 붙여넣기 → 봇이 자동 ingest → raw/에 원본 보존 → Atlas/에 요약 페이지 생성 → index.md 업데이트 → log.md 기록
회의 중 떠오른 질문:
Telegram에 “지난 프로젝트 설정이 어떻게 됐더라?” 입력 → 봇이 위키 검색 → 답변 도착
누군가 전달한 정보 기록:
Telegram에 /ingest 김과장이 내일 미팅에서 예산안 가져온다고 함 → raw/에 보존 → 위키에 통합
삽질 기록
순탄하지만은 않았다. 기록해둔다.
--prompt옵션은 없다 —claude --print --prompt "..."가 아니라claude -p "..."이다. prompt는 위치 인수.--allowedTools와 위치 인수 충돌 —claude -p --allowedTools "..." "prompt"에서 prompt가 인식 안 됨. stdin 파이프로 해결.- 비대화형 모드에서 도구 권한 —
-p모드는 도구 승인 프롬프트를 띄울 수 없다.--allowedTools로 사전 허용 필수.
이런 삽질들이 모두 하네스를 이해하는 과정이었다. 에이전트(Claude)의 문제가 아니라 하네스(호출 방식, 권한 설정)의 문제였고, 하네스를 고치니 해결됐다.
이것이 하네스 엔지니어링인가?
돌이켜보면, 오늘 한 것은 정확히 하네스 엔지니어링이었다:
- Schema 설계 —
CLAUDE.md에 위키의 규칙과 워크플로우를 정의 - 입출력 채널 설계 — Telegram Bot으로 원격 접근 경로 구축
- 도구 권한 설계 —
--allowedTools로 에이전트가 쓸 수 있는 도구 범위 지정 - 얇은 중계층 — 봇은 로직 없이 메시지만 전달, 모든 판단은 에이전트가
긱뉴스에서 읽었던 그 문장이 떠오른다:
“남이 만든 하네스를 그대로 복사해 쓰는 것은 남의 옷을 입는 것과 비슷하다”
Karpathy의 LLM Wiki 구조를 가져왔지만 그대로 쓰지 않았다. 내 Obsidian vault 구조에 맞추고, Calendar를 raw source로 재정의하고, Telegram 입력 채널을 추가했다. 남의 패턴을 가져와서 내 것으로 만드는 과정 — 그것이 하네스 엔지니어링의 시작이었다.
다음 단계
- 이미지 ingest 지원 (Telegram 사진 메시지)
- 긴 응답의 마크다운 포맷팅 개선
- Obsidian URI 연동 (응답에서 바로 페이지 열기)
- 주기적 자동 lint
하루 만에 여기까지 온 것이 믿기지 않는다. 대부분의 코드는 Claude가 짰고, 나는 방향을 잡고 결정을 내렸다. 이것도 하네스 엔지니어링의 일부인 것 같다 — 에이전트가 일하는 구조를 설계하는 것이 곧 에이전트와 함께 일하는 방식이니까.











