작업자 한 명이 45M 토큰을 쓰지 않게 — dev-kit 연재 ① 토큰과 조율
Claude Code 서브에이전트 작업자에게 이슈를 차례로 맡기며 티켓마다 토큰을 재고, 그 숫자로 다듬은 조율·토큰 규칙을 플러그인 묶음 dev-kit으로 정리한 과정.

작업자 한 명이 45M 토큰을 쓰지 않게
dev-kit 연재 ① — Claude Code 작업자를 하나씩 차례로 돌리며 잰 토큰과, 그 숫자로 다듬은 규칙
왜 만들었나
Claude Code로 GitHub 이슈를 처리할 때 저는 코드를 직접 고치지 않습니다. 조율자 세션 하나가 이슈를 차례로 골라 서브에이전트 작업자에게 맡깁니다. 작업자는 워크트리를 따로 만들어 구현하고, 시험을 돌리고, PR을 열고, CI가 통과하면 병합한 뒤 정리까지 합니다.
이렇게 돌리다 보니 두 가지가 눈에 띄었습니다. 같은 실수가 저장소마다 되풀이됐고, 토큰이 티켓마다 크게 들쭉날쭉했습니다. 작은 티켓은 1~2M 토큰이면 끝나는데, 어떤 티켓은 196턴을 돌며 45M 토큰을 썼습니다.
그래서 작업자가 끝날 때마다 기록을 재고, 원인을 하나 찾아 다음 지시서(작업자에게 주는 프롬프트)와 공용 작업자 정의에 바로 넣었습니다. 그렇게 쌓인 규칙을 특정 저장소와 무관한 형태로 옮겨 Claude Code 플러그인 마켓플레이스 farrar142/dev-kit으로 공개했습니다.
이 연재는 그 규칙을 세 편으로 나눠 소개합니다. 1편은 토큰과 조율, 2편은 시험 속도, 3편은 작업 환경(훅과 질문 패널)입니다. 글의 숫자는 모두 한 프로젝트에서 잰 값이라, 다른 저장소에서는 다시 재야 합니다.
숫자로 본 차이
작업자 하나씩 차례로 도는 흐름
- 큐 짜기결정이 필요한 이슈는 사람과 먼저
맡길 수 있는 이슈만 선행 관계(blocked by) 순서로 줄 세운다
- 모델 고르기Agent 호출에 model을 늘 명시
보통은 sonnet, 최적화·보안·원인 미상 버그는 opus
- 지시서공통 절차는 에이전트 정의에
그 티켓만의 사정만 적는다
- 작업자코드 찾기는 haiku 보조 에이전트에게
워크트리 → 시험 → PR → 병합 → 인계 댓글 → 정리
- CI 기다리기조율자도 같은 PR을 지켜봄
백그라운드에서 기다리다 끝날 때 한 번만 깨우는 스크립트
- 확인·측정·개선원인 하나를 다음 지시서에
병합 커밋과 브랜치를 직접 보고, 턴·토큰을 잰다
1편에서 다루는 dev-kit 구성
| 구성 | 종류 | 하는 일 |
|---|---|---|
| issue-track | 스킬(조율자) | 이슈 큐, 모델 고르기, 지시서, 결과 확인, 토큰 측정, 다음 지시서 개선 |
| issue-worker | 에이전트(sonnet 기본) | 이슈 하나를 워크트리 → 시험 → PR → 병합 → 정리까지 |
| errand | 에이전트(haiku, 읽기 전용) | 「어디에 있나」 같은 코드 찾기를 맡아 결론만 돌려주는 보조 |
| wait-ci.py | 스크립트 | PR의 커밋 상태와 check-runs를 백그라운드에서 기다렸다가 종료 코드로 한 번 알림 |
| worker-stats.py | 스크립트 | 작업자·보조 에이전트의 턴, 입력 토큰, 최대 컨텍스트 |
| token-diet | 스킬(규율) | 파일 부분 읽기, 출력 끝만 보기, 모델 고르기, 도구 호출 120번에서 인계, 백그라운드 대기, 짧은 CLAUDE.md |
- token-diet에는 큰 파일 Read와 큰 heredoc을 막는 훅 두 개도 들어 있습니다. 이 훅들은 [3편](/blog/devkit-3-hooks-panel)에서 다룹니다.
부딪힌 문제와 해결
1. 성격이 다른 일을 한 티켓에 묶었다
도구를 바꾸고 그 도구로 기존 시험 여럿을 옮기는 일을 한 티켓에 넣었습니다. 작업자는 196턴을 돌며 입력 45M 토큰을 썼고, 컨텍스트는 최대 373k까지 갔습니다. 인프라(새 서비스)와 백엔드와 화면을 묶은 티켓도 160턴·32.5M이었습니다.
원인은 계산 방식에 있습니다. 입력 토큰은 대략 턴 수 × 그때의 컨텍스트입니다. 일이 커지면 턴이 늘고, 앞에서 읽은 것이 쌓여 턴마다 컨텍스트도 커집니다. 두 값이 함께 커지니 토큰은 일의 양보다 훨씬 빨리 늡니다.
→ 작업자를 띄우기 전에 티켓을 쪼갭니다. 「도구」와 「그 도구로 시험 옮기기」로, 또는 인프라·백엔드·화면별로 나눕니다. 못 쪼개면 지시서에 단계마다 다음 작업자에게 인계할 지점을 적습니다. 확인 작업이 둘을 넘으면 「바꾸기」와 「확인」 티켓을 따로 둡니다(묶었을 때 132턴·23.5M).
2. 「곧 끝난다」며 인계를 미뤘다
컨텍스트가 커진 작업자는 거의 다 됐다며 계속 진행했고, 그 사이 턴마다 비싼 컨텍스트를 다시 읽었습니다.
→ 판단을 작업자에게 맡기지 않고 숫자로 못 박았습니다. 도구 호출이 120번을 넘으면, PR이 열려 CI만 남은 경우가 아닌 한 멈춥니다. 하던 일을 커밋·push하고 이슈에 인계 댓글(한 것, 남은 것, 다음에 실행할 첫 명령)을 남깁니다. 조율자는 그 댓글을 지시서에 넣어 새 작업자에게 이어서 맡깁니다.
3. 지시서마다 같은 절차를 되풀이했다
지시서마다 워크트리, 시험, PR, 정리 절차를 80줄씩 적었더니 작업자 하나가 지시서만으로 13만~48만 토큰을 썼습니다. 지시서는 대화 맨 앞에 있어 턴마다 다시 읽히기 때문입니다.
→ 공통 절차는 에이전트 정의 파일로 옮기고, 지시서에는 그 티켓만의 사정(이슈 번호, 워크트리, 기준 커밋, 앞 티켓에서 밟은 함정)만 적습니다. 같은 유형의 티켓이 이어지면 지시서를 템플릿으로 두고 빈칸만 채웁니다. 앞 작업자가 찾은 「새 항목마다 손볼 곳」을 끝날 때마다 템플릿에 더했더니, 같은 유형의 두 번째 티켓이 87턴·13M에서 60턴·9.5M으로 줄었습니다. 매 세션 실리는 CLAUDE.md도 요약과 「더 읽을 곳」 링크만 남겨 1,800줄에서 87줄로 줄였습니다.
4. 기다리는 동안 토큰을 썼다
짧은 간격으로 CI를 확인하는 루프는 확인할 때마다 한 턴입니다. 다른 프로세스가 끝나길 기다리는 while pgrep -f …; do sleep 감시 루프는 더 나빴습니다. pgrep -f가 그 루프 자신의 명령줄을 잡아 영원히 끝나지 않았고, 한 작업자가 이것으로 5시간을 멈췄습니다.
→ 긴 명령은 그 명령 자체를 백그라운드로 띄우고, 끝나면 에이전트를 깨우게 합니다. CI는 wait-ci.py가 맡습니다. PR 커밋의 상태(Jenkins 등)와 GitHub Actions check-runs를 함께 보다가 끝날 때 한 번만 알립니다. 결과는 종료 코드로 돌려줍니다: 0 성공, 1 실패(실패 줄을 덧붙임), 2 병합·닫힘, 3 시간 초과, 4 PR 없음.
5. 작업자의 「됐다」를 그대로 옮겼다
작업자가 git add를 빠뜨려 파일 삭제 하나만 병합됐는데, 커밋 메시지는 다 한 것처럼 적혀 있었습니다. 작업자의 중간 알림만 믿고 이미 병합된 PR을 14분 동안 「대기 중」으로 보고한 적도 있습니다.
→ 조율자는 보고 직전에 직접 봅니다. gh pr view로 PR 상태를, git show --stat으로 병합 커밋이 티켓의 변경을 다 담았는지를, 이슈가 닫혔는지를, 원격 브랜치가 남았는지를 확인합니다. 사실 확인은 로컬 작업 트리가 아니라 origin/<기준 브랜치>(main 같은)로 합니다. 다른 세션이 기준 브랜치를 움직이기 때문입니다.
6. 막히면 모델을 올리면 될까
opus로도 인계가 두 번 나거나 같은 실패를 되풀이하면, 문제는 모델이 아니라 티켓 크기였습니다.
→ 더 비싼 모델로 올리지 않고 티켓을 쪼갭니다. CI에서 같은 시험이 시간 한도로 연달아 실패하면 「일시적」이라며 재실행하지 않습니다. 그 PR을 멈춰 두고 최적화 티켓을 먼저 병합합니다. 콘텐츠를 만들던 작업자가 최적화까지 떠안으면 한 티켓이 100턴을 넘었기 때문입니다.
남은 한계
- 숫자는 한 프로젝트, 한 사람의 작업 방식에서 잰 값입니다. 「작은 티켓 1~2M」 같은 기준선은 새 저장소에서 다시 잡아야 합니다.
- 기본은 한 번에 작업자 하나입니다. 서로 독립된 티켓 묶음을 작업자 여럿이 동시에 맡으면, 변경을 합칠 때 충돌하거나 서로의 의도를 깨는 문제가 따로 있어 아직 참고 문서로만 정리해 두었습니다.
worker-stats.py는 작업자 기록이/clear전후 두 폴더로 나뉘면 한쪽만 셉니다.- 규칙 대부분은 사고가 난 뒤에 생겼습니다. 120번 인계도, 감시 루프 금지도 그렇습니다. 그래서 작업자가 끝날 때마다 재는 일을 멈추지 않습니다.
2편에서는 시험 하나에 0.5초·1초·3초 한도를 걸고 E2E를 6분대에서 1.3분으로 줄인 과정을 다룹니다.


