만드는 방법
한 명의 개발자, AI 코딩 어시스턴트, 그리고 기계가 검사하는 수많은 규칙.
글: Nick
Prison Life는 저와 Claude Code(Anthropic의 코딩 에이전트)가 함께 작성합니다. 게임이 무엇인지, 어떤 선택지를 고를지는 제가 정하고, 타이핑의 대부분은 어시스턴트가 합니다. 코드를 검토하는 사람은 저와 리뷰용 AI 에이전트뿐이라서, 저는 자동화에 의지합니다. 규칙은 좋은 의도가 아니라 자동 검사와 빌드로 강제됩니다.
작업 위임
메인 Claude Code 세션은 작업을 계획하고, 작업 추적기와 설계 결정 기록, 변경 이력을 관리합니다. 코드는 직접 쓰지 않습니다. 아무리 작은 변경이라도 전문 AI 에이전트에게 넘깁니다. 각 에이전트에게는 역할과 모델을 정해 둔 정의서가 있습니다.
| 역할 | 모델 등급 | 업무 |
|---|---|---|
| 아키텍처 | Opus | 데이터 모델, 틱, 스레드, 경로 탐색, 결정 |
| 시뮬레이션 코드 | Opus | 시뮬레이션 시스템, 캐릭터 AI, 핫 루프 |
| 성능 | Opus | 프로파일링, 벤치마크 회귀 |
| 리뷰 (읽기 전용) | Opus | diff를 검토하며 파일을 편집할 수 없음 |
| 클라이언트와 도구 | Sonnet | Godot 클라이언트, UI, 도구 |
| 테스트 | Sonnet | 인수 기준에 따른 테스트 |
| 콘텐츠 데이터 | Sonnet | 스키마에 따른 JSON 정의 |
| 검색, 검사 실행 | Haiku | 코드 검색, 검사 실행과 실패 요약 |
어려운 일은 가장 강력한 모델에게, 반복적인 일은 더 저렴한 모델에게 맡깁니다. 저렴한 AI 에이전트가 검사를 두 번 통과하지 못하면 작업은 한 단계 위로 올라가고, 최상위 등급도 두 번 실패하면 멈추고 저에게 물어봅니다.
‘안 돼’라고 말하는 훅
Claude Code의 훅은 어시스턴트의 동작 전후에 실행되는 스크립트입니다. 제 훅은 세 가지 규칙을 강제합니다.
- 빨간불인 채로 끝낼 수 없습니다. 세션이나 AI 에이전트가 코드를 변경한 뒤 종료하려고 하면, 훅이 빠른 검사(빌드와 빠른 테스트)를 실행합니다. 실패하면 종료가 거부됩니다.
- 메인 세션은 코드를 편집할 수 없습니다. 훅이 메인 세션의 소스, 테스트, 콘텐츠, 도구에 대한 쓰기를 거부합니다.
- 리뷰어는 읽기 전용입니다. 편집 도구가 제거되어 있고, 훅이 파일이나 프로젝트 이력을 바꾸는 명령도 거부합니다.
이 장치들은 실수를 막기 위한 것이지, 작정하고 우회하는 것을 막기 위한 것이 아닙니다. 마음먹고 셸 꼼수를 쓰면 피해 갈 수 있고, 훅 중 하나는 AI 에이전트 안의 빨간불은 보지만 막지는 못합니다(메인 세션의 종료 훅이 그래도 잡아냅니다). 이 점은 숨기지 않고 말씀드리고 싶습니다.
기록된 결정과 검사
- 사소하지 않은 선택은 모두 기록합니다. 작업, 마일스톤, 설계 결정은 작업 추적기 안에서 코드 옆에 일반 텍스트로 보관됩니다. 둘 이상의 작업에 영향을 주는 선택지 중에서 하나를 고를 때는, 배경과 결과를 함께 적어 둡니다.
- 검사는 제 컴퓨터에서 실행됩니다. 클라우드 CI는 없습니다. 하나의 로컬 스크립트에
fast,test,bench,full의 네 가지 모드가 있습니다. 스크립트와 훅은 Windows와 macOS 모두에서 PowerShell 7입니다. - 모든 변경에 검사가 따릅니다. 로컬 자동화가 설명이 부실하거나 서식이 엉망인 변경을 거부합니다. 코드 변경에는 빠른 검사도 실행하고, 메모나 웹사이트만 건드리는 변경은 빌드를 건너뜁니다.
- 기준 파일은 보호됩니다. 고정된 결정론 해시, 골든 저장 파일, 벤치마크 기준선은 제가 명시적으로 승인했을 때만 바뀌며, 조용히 바뀌는 일은 없습니다.
- 프로젝트 자체가 진실의 원천입니다. 로컬 메모리 도구가 프로젝트와 지난 대화를 검색할 수 있게 색인하지만, 중요한 내용은 모두 작업, 기록된 결정, 문서 중 하나로도 남아 있습니다.
결정론적 코어
시뮬레이션은 Godot 참조가 없는 순수한 .NET 라이브러리에 들어 있고, Godot 클라이언트는 그 상태를 읽고 명령을 보내기만 합니다. 코어는 고정된 규칙을 따릅니다. 월드는 명령으로만 바뀌고, 시간은 정수 틱이며, 무작위성은 월드의 시드가 있는 생성기에서만 나옵니다. 같은 시드와 같은 명령 로그는 같은 월드를 만들어야 합니다. 이 규칙들은 검토만이 아니라 컴파일러와 테스트로 검증됩니다. 방법은 개발 일지 #1에서, 월드와 저장, 리플레이는 개발 일지 #2에서 볼 수 있습니다.
- 명령은 유일한 입구입니다. 각 명령에는 안정적인 타입 ID와 바이너리 인코딩이 있으며, 거부된 것을 포함한 모든 명령이 결과와 함께 기록됩니다.
- 틱은 정해진 순서의 세 단계로 이루어집니다. 시스템의 순서는 코드의 한 곳에서 정해지며, 이를 바꾸면 모든 해시가 바뀝니다.
- 무작위성에는 직접 만든 생성기(SplitMix64와 xoshiro256**)를 씁니다. 이름이 붙은 스트림은 월드 시드에서 파생되어 월드 상태에 저장됩니다. 순서와 무관해야 하는 작업에는 도메인, 키, 틱으로 구동하는 상태 없는 키 기반 생성기를 씁니다.
- 상태 해시는 결정론 확인에 쓰는, 순서에 민감한 64비트 해시입니다. 암호학적 해시가 아닙니다.
- 월드는 이산적인 층 위에 놓인 1×1m 타일의 격자입니다. 벽, 문, 바닥은 건설 명령으로만 바뀝니다.
- 저장과 리플레이는 검사를 거치는 하나의 파일 컨테이너를 공유합니다. 리플레이는 시드와 명령 로그에 중간중간 확인용 해시를 더한 것이며, 재생하면서 단계별로 확인합니다.
- 벤치마크는 헤드리스 시나리오 러너에서 얻으며, 기기별 기준선과 틱당 할당 0바이트 게이트가 있습니다.
설계 목표는 초당 20틱에서 최대 1,000명의 수감자와 직원입니다. 이것은 목표일 뿐입니다. 아직 캐릭터가 없어서 벤치마크 러너는 있지만 그 규모로는 아무것도 측정하지 않았습니다.