시작
6월에 나는 커스텀 subagent 를 따로 두지 않는다는 원칙을 세웠다. Claude Code 와 Codex 의 기본 subagent 가 필요한 것을 다 포섭한다는 전제였다. 7월 말 다시 보니 기본 subagent 가 주지 않는 것이 세 가지 있었다. 모델 × effort × 변경 권한의 명시적 조합, 누구에게 무엇을 맡겼는지의 선언, 맡긴 결과의 평가다.
7월 29일 저장소를 만들고, 다음 날 야구를 운영 모델로 들였다. 메인 에이전트는 감독이고, 선수는 모델·effort·권한이 고정된 프로필이다. 선수에게 일을 한 번 맡기면 한 타석이다. 야구는 리포트의 겉모양이 아니라 운영 규칙 자체다.
무엇을 만들었나
선수는 세 부류 열두 명이다. Setter 다섯은 설계와 판단까지 맡는 전체 권한 프로필로, effort 가 low 부터 max 까지 나뉜다. Batter 넷은 이미 정해진 범위를 실행하고, Bench 셋은 조사와 증거 수집만 한다. 여기에 코치 셋이 있다. 코치는 다른 모델 제공자의 모델을 읽기 전용으로 불러 자문만 하고, 파일을 바꾸거나 결과를 판정하지 못한다.
감독은 규칙을 따른다. 작업의 권한 경계로 선수 부류를 먼저 고르고, 그 안에서 충분한 가장 낮은 effort 를 고른다. 선수에게는 목표·제약·완료 기준·검증 방법이 담긴 위임을 준다. 구현을 맡긴 선수에게 같은 변경의 리뷰를 다시 맡기지 않는다. 리뷰가 독립적이면 선수 리뷰와 코치 리뷰를 병렬로 돌린다.
설치하면 세션 시작 훅이 규칙을 주입하고 선수 프로필을 ~/.claude/agents 와 ~/.codex/agents 에 맞춰 둔다. 사용자가 손댄 프로필은 해시로 감지해 덮어쓰지 않는다. 선수가 일을 마치면 종료 훅이 등판 한 번을 JSON 파일로 남기고, 스코어북 스킬이 일·주·월 리포트로 모은다.
8월 24일에는 이관 작업을 공격적으로 검토하는 pinch-review 스킬을 더했다. 원본과 똑같이 옮겼다는 것이 맞게 옮겼다는 뜻은 아니다. 원본의 숨은 결함까지 충실하게 옮겨 온 이관을 기존 검증이 통과시킨 사례를 겪고, 동등성이 아니라 숨은 불변식을 공격하는 리뷰 레인을 따로 만들었다.
스택 — 의존성 없는 스크립트와 파일
Node.js ESM 스크립트와 Bash 훅이 전부고, npm 의존성은 하나도 없다. 데이터베이스 대신 등판 한 번을 JSON 파일 하나로 쓴다. Claude Code 와 Codex 두 하네스의 플러그인 마켓플레이스로 배포해, 같은 규칙과 선수 명단을 양쪽에서 쓴다. 테스트도 Bash 로 돈다.
아키텍처 — 세션 안에서 돌고, 기록만 밖에 남는다
서버가 없다. 모든 동작은 사용자의 Claude Code·Codex 세션 안에서 훅과 스킬로 일어나고, 세션 밖에 남는 것은 등판 기록 파일과 리포트뿐이다. 외부 모델을 부르는 건 코치뿐인데, 읽기 전용 샌드박스에서 매번 새로 실행한다.
조합을 고정한다
선수 프로필은 모델과 effort 를 frontmatter 에 고정하고, 호출할 때 덮어쓰지 않는다. 같은 이름의 선수는 늘 같은 비용과 같은 권한으로 뛴다. 호출할 때마다 모델을 고를 수 있게 하면 편하지만, 그러면 “이 일에 누구를 썼나” 라는 기록이 비교할 수 없는 값이 된다.
코치가 일부러 다른 제공자의 모델을 쓰는 것도 같은 방향이다. 계획을 세운 모델 계열과 독립 리뷰를 하는 모델 계열이 기본적으로 겹치지 않게 했다.
채점을 폐기한 날
처음 설계에는 공식 채점이 있었다. 완료 기준이 검증을 통과하면 안타, 추측하지 않고 멈춰서 올리면 볼넷, 실패하면 아웃, 완료라고 했는데 재작업이 생기면 실책이다. 타율로 선수 조합을 조정하려는 의도였다.
9월 3일 리포트는 44타수 44안타, 타율 1.000 이었고 검수 대기가 130건 쌓여 있었다. 판정할 수 있었던 건 전부 안타였고, 나머지는 판정조차 못 한 채 밀려 있었다. 지표가 작업 품질에 대해 아무 신호도 주지 않았고, 위임할 때마다 결과를 확인받는 절차가 오히려 실제 작업을 끊었다. 9월 4일 채점을 폐기했다. 누가 어떤 모델과 effort 로 몇 토큰을 썼는지는 계속 기록하고, 품질 판단은 위임할 때 적는 검증 기준과 감독의 직접 확인으로 돌렸다.
운영하며 겪은 일
채택한 날 철회. 7월 30일 Claude Code 쪽에 선수 명단을 들였다가, 같은 날 등판 기록 수집이 동작하지 않는 걸 확인하고 철회했다. Codex 쪽은 유지했다.
기록 없이 돌아온 명단. 3주 뒤 보니 Claude Code 쪽 명단이 다시 설치돼 있었다. 철회 결론과 디스크 상태가 어긋나 있었는데, 그 사이의 판단은 어디에도 남아 있지 않았다. 8월 21일 재도입을 공식으로 확정하고, 정책을 되돌리거나 폐기할 때도 기록을 남긴다는 규칙을 더했다. 규칙은 늘기만 하는 게 아니고, 되돌림도 사건이다.
돌아보며
채점을 버린 게 이 프로젝트에서 가장 쓸모 있던 판단이었다. 지표를 만든 사람이 그 지표를 믿지 않기로 하는 데 한 달 남짓 걸렸다. 등판 기록은 남겨 두어서, 어떤 조합에 얼마를 썼는지는 지금도 볼 수 있다.
출처
- 공개 저장소 github.com/doominkim/ballclub —
README.md,docs/game-model.md,docs/runtime-flow.md,hooks/hooks.json, 커밋 본문(2026-07-29 ~ 08-24) - 하네스 incident 문서(채택 2026-07-31, 재도입 2026-08-21, pinch-review 2026-08-24, 채점 폐기 2026-09-04)
- 참조한 오픈소스(GitHub): Claude Code · Codex.
- 등판 기록의 작업 내용, 다른 저장소 이름, 외부 모델 키는 싣지 않는다.