← 유영준
혼자 굴리는 에이전트 런타임 · 2/4편2026-07-26

이 글은 개인 AI 에이전트 Nova가 썼습니다. 사실과 수치는 유영준의 기록이고, 사실 확인과 최종 책임은 유영준에게 있습니다.

내 마크다운 폴더는 이미 멀티에이전트 시스템이었다

개인 AI 어시스턴트 런타임을 직접 만들어 굴리는 기록. 2편.

AI 코딩 에이전트 세션을 동시에 다섯에서 여섯 개 굴린다. 각 세션이 다른 프로젝트를 잡고, 같은 저장소의 다른 파일을 만지고, 각자 커밋한다. 이틀 동안 커밋 41개가 나온 날도 있다.

그렇게 굴리다 보니 같은 계열의 사고가 계속 났다.

각각을 개별 사고로 보고 개별 처방을 했다. 앵커는 다시 읽고 쓰기, 기록은 append만 하기, 미러는 손으로 안 쓰기. 그런데 계속 났다.

진단: 이건 파일 관리 문제가 아니다

원인을 찾다가 Cognition이 쓴 「Don't Build Multi-Agents」를 읽었다. 원칙이 둘이다.

  1. 컨텍스트를 공유하라. 메시지 조각이 아니라 전체 트레이스를 공유해야 한다.
  2. 행동은 암묵적 결정을 수반하고, 충돌하는 결정은 나쁜 결과를 낳는다.

두 번째 문장이 내 사고 목록을 그대로 설명한다. 네 종류의 사고가 전부 "다른 세션이 무슨 결정을 했는지 모른 채 행동한" 결과다.

그리고 여기서 관점이 바뀌었다. 나는 "AI 어시스턴트를 쓰는 사람"이라고 생각했는데, 실제로 내가 운영하는 건 멀티에이전트 시스템이었다. 병렬 세션이 에이전트고, 정본 마크다운 파일이 에이전트들 사이의 유일한 통신 채널이다.

세션들은 서로 대화하지 않는다. 같은 파일을 읽고 쓴다. 그게 이 시스템의 전부다.

이렇게 보면 사고가 선형이 아니라 조합적으로 늘어난다는 것도 설명된다. 세션이 N개면 결정 충돌 가능 쌍은 N제곱에 비례한다.

그리고 26KB의 정체가 밝혀졌다

진행 상태를 담은 정본 파일이 100KB였다. 뜯어보니 이렇게 나왔다.

전체            100KB  ≈ 25k tokens
  갱신 헤더 블록  26KB  (26%)   ← 상태가 아니라 변경 이력
  종결 행         16KB  (30%)   ← 드롭·완료·결과확정
  최장 행        3.5KB
  중앙값 행       535B

파일 맨 위에 갱신 이력 블록이 26KB 있었다. 처음에는 이걸 쓰레기로 봤다. 상태 파일에 이력이 왜 있나. 지우면 26% 감량이다.

Cognition의 원칙 1을 읽고 다시 봤다. 그 26KB가 정확히 "전체 트레이스 공유"의 시도였다. 세션들이 서로에게 "내가 뭘 왜 했는지"를 남기는 장치다. 그게 없으면 다음 세션이 맥락 없이 상태만 보게 된다.

즉 쓰레기가 아니라 필요한 기능이 잘못된 장소에 있는 것이었다.

문제는 한 파일이 상반된 두 일을 겸하고 있었다는 점이다.

기능 원하는 성질
상태 공유 작고 현재적 (매번 통째로 읽히므로)
트레이스 공유 append-only로 상세 (결정 맥락이 손실되면 안 되므로)

한 파일에 둘을 넣으면 상태가 이력에 파묻힌다. 그게 100KB의 정체였다. 분리가 정답인 이유는 토큰 절약이 아니라 여기 있다.

처방: 행을 계약으로 만들었다

상태를 산문으로 저장하면 기계가 못 읽는다. 실측해보니 살아있는 94개 행 중 발표일을 기계가 판독할 수 있는 건 40%, 다음 액션을 판독할 수 있는 건 22%였다.

그리고 그게 사고의 직접 원인이었다. 발표 도래 열두 건이 몇 달 쌓인 것도, 다음 할 일이 과소보고된 것도, 상태를 데이터가 아니라 산문으로 저장한 대가다.

그래서 행 계약을 만들었다.

<상태> · 마감 MM/DD HH:MM · 발표 YYYY-MM-DD · 다음: <액션>

그 뒤에는 자유 산문을 쓴다. 모르는 값은 발표 미공지처럼 명시한다. 빈칸은 감시가 안 걸리니까 금지다.

마이그레이션은 빅뱅으로 안 한다. 행을 건드리면 그 행만 계약형으로 올려놓고 나온다. 94행을 한 번에 고치는 계획은 세우면 안 지켜진다. 만지는 행만 고치면 자연 수렴한다.

준수율은 스크립트로 측정한다. 숫자가 안 보이면 수렴하는지 알 수 없다.

채택하지 않은 것들

여기가 더 중요한 부분일 수 있다.

단일 스레드로 회귀. Cognition의 실제 권고다. 병렬 에이전트를 만들지 말고 단일 스레드에 이력 압축 모델을 붙여라. 안 받았다. 병렬 운용은 내 요구사항이지 실수가 아니다. 여러 프로젝트가 실제로 동시에 마감을 향해 간다. 대신 충돌 면적을 줄이는 쪽으로 갔다. 얇은 행과 파일 분리다.

git worktree로 병렬 격리. 코딩 에이전트 병렬화의 표준 해법이다. 코드 저장소에는 지금도 쓴다. 이 저장소에는 안 썼다. 스케줄러와 훅과 런타임이 고정 경로를 물고 있어서, 경로 의존성을 정리하지 않고 worktree를 쓰면 자동화가 조용히 죽는다.

외부 메모리 프레임워크 도입. Letta나 mem0 같은 것들. 안 받았다. 지금 병목은 저장소 기술이 아니라 문서 구조다. 파일 분리로 해결되는 문제에 런타임 의존성을 늘리지 않는다. Letta에서 가져온 건 아이디어 하나뿐이다. 항상 로드되는 블록에 문자 수 제한을 스키마로 박는 것.

기술 도입을 결정할 때 이 순서가 중요하다고 생각한다. 구조로 해결되는 문제인지 먼저 확인한다. 프레임워크는 구조를 고쳐도 안 되는 문제에 쓴다.

그날 같은 사고가 실시간으로 재현됐다

이 진단을 쓰고 커밋하려던 순간에, 다른 세션이 먼저 커밋했다. 그 커밋이 내가 스테이징해둔 492줄 삭제분을 그대로 쓸어갔다.

결과 자체는 같다. 그 492줄은 지워질 예정이었고 지워졌다. 다만 커밋 메시지의 귀속이 틀어진다. 나중에 "이 파일이 왜 없어졌지"를 추적할 때 엉뚱한 커밋을 보게 된다.

같은 날 쓴 진단 문서의 항목이 그날 실시간으로 재현된 셈이다. 이건 좀 웃겼고, 동시에 이 문제가 아직 안 고쳐졌다는 증거다.

남은 구멍

기록 파일의 append-only는 여전히 문서 규칙이다. 이미 두 번 사고가 났고 기계 강제가 없다.

다음 후보는 훅이다. 기존 내용이 줄어드는 쓰기를 거부하는 방식. 파일 전체를 덮어쓰려는 시도를 도구 호출 단계에서 막는다.

문서 규칙에서 코드 강제로 옮기는 이 작업이 이 시스템 운영의 대부분이라는 걸 이제 안다. 규칙을 잘 쓰는 게 아니라 규칙이 안 지켜져도 사고가 안 나게 만드는 것이 일이다.

남은 질문

이 글을 쓰면서 계속 걸리는 부분이 있다. 나는 혼자 일한다. 팀이 없다. 그런데 내가 겪은 문제 목록은 여러 명이 같은 코드베이스를 만지는 팀의 문제와 정확히 같다. 정본이 어디인지, 누가 무슨 결정을 했는지, 미러가 왜 어긋났는지.

에이전트를 병렬로 굴리는 순간 혼자서도 분산 시스템을 운영하게 된다. 그리고 분산 시스템의 문제는 도구를 좋게 만들어서 사라지지 않는다. 통신 채널을 설계해야 사라진다.

물어야 할 건 이거다. 내 시스템에서 두 행위자가 서로의 결정을 알게 되는 경로가 정확히 무엇인가? 그 경로를 이름 붙여 말할 수 없으면, 그 시스템은 아직 설계되지 않은 것이다.