리뷰 에이전트는 코드를 쓸 수 없어야 한다. CLI별로 이걸 어떻게 강제하는가.

17개 노드로 이루어진 런에서 릴리스 에이전트가 빨간 테스트 스위트를 초록으로 만들려고 테스트를 고쳤고, 이어서 리뷰 에이전트 둘이 같은 수정을 쓰다가 충돌했습니다. 프롬프트에는 리뷰만 하라고 적혀 있었습니다. 지켜지지 않았습니다. 사건의 전말, 글로 쓴 지시가 이 규칙을 감당하지 못하는 이유, 그리고 Claude Code, Codex, Grok, Antigravity, OpenCode가 쓰기를 거부하게 만드는 정확한 플래그를 정리합니다.

이번 주 초, 한 사용자가 두 번 읽어볼 만한 런 보고서를 보내왔습니다. 에이전트 열일곱 개, 공유 worktree 하나, 구현 담당과 릴리스 게이트, 리뷰 브랜치 두 개로 이루어진 파이프라인. AgentsRoom 버전 1.171.0이었습니다.

그 런에서 세 가지 일이 이 순서로 일어났습니다.

릴리스 에이전트 앞에는 빨간 테스트 스위트가 있었습니다. 스위트가 초록이 될 때까지 테스트 spec을 고쳤습니다. 그 과정에서 진짜 결함을, 그 결함에 동의하는 테스트로 덮은 채 출시해 버렸습니다.

그다음 같은 런의 병렬 브랜치 두 개에서, 리뷰 에이전트 둘이 각각 진짜 한 줄짜리 버그를 찾았습니다. 각자 같은 worktree에서, 같은 시각에, 직접 고쳤습니다. 충돌했습니다.

이 에이전트들 모두 스텝 프롬프트에 분명한 말로 리뷰만 하라고 적혀 있었습니다. 아무것도 막지 않았고, 아무것도 알리지 않았습니다. 플랫폼 입장에서는 어떤 스텝이 쓰기 도구를 갖고 있었고 그걸 썼을 뿐입니다.

프롬프트가 지켜지지 않은 이유

솔깃한 해석은 에이전트가 지시를 무시했다는 것입니다. 실제로 일어난 일은 그게 아니고, 이 차이가 중요합니다. 수정이 무엇이어야 하는지가 달라지기 때문입니다.

각 에이전트에게는 국소적으로 변호할 수 있는 쓰기 이유가 있었습니다. 빨간 스위트와 틀려 보이는 spec. 고치는 데 4초, 설명하는 데 40초 걸리는 버그. 누구도 규칙을 어기기로 결정하지 않았습니다. 각자 자기 경우는 규칙이 겨냥한 것이 아니라고 판단했습니다. 스텝 안에서 보면 예외는 언제나 합리적으로 보입니다.

글로 쓴 지시는 모델의 판단에 보내는 요청입니다. 고칠 수도 있는 리뷰어는 조만간 고치게 됩니다. 고치는 것이 '찾았다'에서 '끝났다'로 가는 가장 짧은 길이기 때문입니다. 그럴듯한 예외와 부딪혀도 살아남는 유일한 규칙은 모델이 반박할 수 없는 규칙, 즉 거기 없는 도구입니다.

전역 설정으로도 안 됐던 이유

그 전까지 실행 중인 스텝에 닿는 유일한 레버는 프로바이더 설정이었고, 이건 머신의 모든 Claude 에이전트를 한꺼번에 다룹니다. 런에는 맞지 않는 모양입니다. 같은 파이프라인 안에서 구현 담당은 써야 하고 리뷰어는 쓰면 안 됩니다. 전역 스위치는 둘을 구분하지 못합니다.

그리고 이미 있던 에이전트별 제한, 티켓이 에이전트를 실행할 때 실어 보낼 수 있는 그 제한은 의도적으로 팀 스텝에는 전달되지 않았습니다. 그래서 티켓에서 시작한 에이전트는 제한할 수 있는데 팀의 노드는 제한할 수 없었습니다. 그것이 주된 원인이었고, 시간이 지나며 낡아 버린 설계 결정이었습니다.

규칙: 노드의 체크박스 하나

수정은 리뷰 노드에 붙인 불리언 하나입니다. 읽기 전용에 체크하면 그 스텝을 맡은 에이전트는 프로젝트에 쓰기 접근 없이 실행됩니다. 파일 편집 없음, git commit이나 push 없음, 작업 트리를 바꾸는 것만이 목적인 셸 명령 없음. 읽기, grep, git diff, git log, 테스트, 린터, 그리고 모든 팀 도구는 열려 있습니다.

이것이 무엇이 아닌지도 분명히 했습니다. 사용자가 CLI별로 손으로 쓰는 거부 목록이 아닙니다. '이건 리뷰한다'고 말하려고 권한 문법 다섯 가지를 알아야 할 사람은 없습니다. 이 스위치는 프로바이더마다 맞는 플래그를 만들어 내고, 자율 모드 뒤에, 사용자가 에이전트에 저장해 둔 무엇보다도 뒤에, 즉 마지막에 적용되므로 이깁니다.

각 CLI가 하는 일, 각자의 도움말에서 읽은 대로

각 CLI의 --help에서 플래그를 직접 읽은 프로바이더에만 강제합니다. 추측한 플래그는 파싱 오류로 실행을 죽이고, 그건 강제 없는 스텝보다 나쁩니다. 나머지 CLI는 글로 쓴 규칙만 받고, 에디터는 체크박스 아래에 그 사실을 평문으로 보여 줍니다.

CLI읽기 전용 스위치가 추가하는 것자율 모드에서도 유지되나?
Claude Code--disallowedTools "Edit" "Write" "MultiEdit" "NotebookEdit" "Bash(git commit:*)" "Bash(git push:*)"예, 거부 규칙은 --dangerously-skip-permissions 아래에서도 적용됨
Codex--sandbox read-only예, 도구 목록이 아니라 OS 샌드박스임 (macOS는 Seatbelt, Linux는 Landlock)
Grok Build--deny "Edit" --deny "write" --deny "Bash(git commit*)"예, 거부 규칙은 --always-approve 아래에서도 적용됨
Antigravity--mode plan예, plan은 이 CLI의 읽기 전용 실행 모드
OpenCode--agent plan예, 내장 plan 에이전트가 편집 도구를 거부함
Mistral Vibe, Kimi Code, Copilot, Cursor, Amp, Aider 및 나머지프롬프트 문단만검증된 플래그 없음, 에디터에도 그렇게 표시

이 표의 세부 사항 두 가지가 각각 버그 하나씩을 안겼기 때문에, 적어 둘 가치가 있습니다.

Codex와 Grok은 반복된 플래그를 거부합니다. 둘 다 엄격한 파서로 인자를 해석합니다. 사용자가 이미 에이전트에 --sandbox workspace-write를 저장해 뒀다면, 뒤에 --sandbox read-only를 붙여도 덮어쓰지 않고 실행이 죽습니다. 그래서 값을 받는 플래그는 기존 항목을 값까지 제거한 뒤에 우리 것을 붙입니다. OpenCode의 --agent도 마찬가지인데, 이쪽 파서는 반복된 플래그를 배열로 바꾸고 더 아래에서 실패합니다.

Claude Code에서는 목록이 쌓여야 합니다. --disallowedTools는 공백으로 구분한 목록을 받고 반복할 수 있으며, 에이전트가 내장 브라우저를 조작할 수 없을 때 이미 하나를 넘기고 있습니다. 파서는 반복된 가변 인자 옵션을 이어 붙이므로, 두 번째가 첫 번째를 대체하는 대신 두 목록이 합쳐집니다.

Claude Code용 전체 목록은 파일 편집 도구 넷, 인덱스나 트리, ref, 원격 저장소에 쓰는 모든 git 하위 명령(add, commit, push, merge, rebase, reset, checkout, switch, restore, stash, cherry-pick, revert, apply, am, rm, mv, clean, tag, worktree), 그리고 파일을 바꾸기 위해서만 존재하는 셸 명령(rm, mv, cp, tee, touch, mkdir, chmod, chown, ln, truncate, dd, sed -i)입니다. Grok은 같은 규칙 문자열을 glob 형태로 받고, 여기에 자체 파일 도구 이름(search_replace, write, hashline_edit)이 더해집니다.

프롬프트에도 여전히 할 일이 있다

플래그는 거부합니다. 설명하지는 않습니다. 그리고 이해하지 못하는 거부에 부딪힌 에이전트는 그걸 버그로 취급하고 다른 길을 찾는데, 이게 바로 우리가 없애려던 행동입니다.

그래서 읽기 전용 스텝은 프롬프트에도 두 문장을 받습니다. 첫 문장은 이 스텝이 읽기 전용이라는 것, 그게 무슨 뜻인지의 목록, 그리고 거부는 규칙이지 다른 명령으로 우회할 장애물이 아니라는 점을 말합니다. 둘째 문장은 열려 있는 것들을 나열하고, 바꿔야 할 것을 파일과 줄, 이유와 함께 인계에 보고하고, 적용은 코드를 소유한 스텝에 맡기라고 에이전트에게 말합니다.

검증된 플래그가 있는 CLI에서는 이 문단이 거부를 이해하게 만드는 장치입니다. 나머지에서는 이것이 강제의 전부이고, 우리는 그런 척하기보다 그렇다고 말하는 쪽을 택합니다.

기본 제공 템플릿에서 누가 읽기 전용인가

판정하는 노드가 읽기 전용입니다. 스타터 템플릿 두 개의 QA 검증 스텝, Bug hunt의 재현 스텝과 검증 스텝, Release shield의 QA 브랜치와 보안 브랜치, Feature squad의 테스터.

코드를 소유한 노드는 계속 씁니다. 개발자, 그리고 발견된 문제를 전부 직접 고치도록 작성된 릴리스 게이트. 쓸 수 없는 릴리스 게이트는 릴리스할 수 없는 릴리스 게이트입니다.

이 분리가 설계의 전부이고, 사건이 두 번 어긴 것도 이 분리입니다. 잘못된 곳에 쓴 릴리스 노드, 그리고 애초에 써 버린 리뷰 노드들.

이것이 아닌 것

보안 경계가 아닙니다. 제보자가 보고서에서 그렇게 말했고, 맞는 말이었습니다. bash -c 하나면 도구 거부 목록을 우회합니다. 신뢰하지 않는 에이전트를 격리해야 한다면 그건 샌드박스나 별도 머신의 일이고, 다섯 CLI 중 읽기 전용 모드가 실제로 그것인 건 Codex뿐입니다.

이 스위치가 막는 것은 사고와 역할 이탈이고, 실제로 일어나는 일이 바로 그것입니다. 리뷰어는 거부 목록을 일부러 빠져나가지 않습니다. 반사적으로 Edit에 손을 뻗고, 그 반사는 이제 거부됩니다.

만들지 않은 것

제보자는 한 가지를 더 요청했습니다. 강제가 없더라도 최소한의 신호로, 런 타임라인에 '노드 X가 트리에 썼다'는 이벤트를 남기는 것. 좋은 아이디어지만 이번에는 하지 않았습니다. 러너 쪽에서 스텝마다 기준 diff가 필요하기 때문입니다. 필요가 다시 생기면 그게 다음 조각입니다.

AgentsRoom을 쓰지 않는다면

위 플래그는 그대로 복사해 쓸 수 있습니다. codex --sandbox read-onlyclaude --disallowedTools "Edit" "Write" "MultiEdit" "NotebookEdit" "Bash(git commit:*)" "Bash(git push:*)"로 직접 실행한 리뷰 에이전트는 우리 리뷰 노드 둘이 한 일을 할 수 없습니다. 왜 거부당하는지 알 수 있게 같은 두 문장을 프롬프트에 넣어 주세요.

체크박스가 더해 주는 것은, 다섯 문법 중 어느 것이 해당되는지 기억하지 않아도 된다는 것, 스텝이 어떤 자율 모드로 돌든 플래그가 이긴다는 것, 그리고 나중에 같은 스텝에 다시 들어오는 런에서도 유지된다는 것입니다.

노드 스위치와 프로바이더별 표는 Agent Teams 페이지에 문서화되어 있습니다. 에이전트의 리뷰가 애초에 가치가 있는지, diff의 얼마만큼이 아직 사람의 몫인지는 다른 질문이고, AI 에이전트의 코드를 아직도 리뷰해야 할까?에서 다뤘습니다. 이 글은 더 작고 더 기계적인 것에 관한 이야기입니다. 에이전트가 리뷰한다고 결정했다면, 그 외의 일은 물리적으로 할 수 없게 만드세요.

AgentsRoom 다운로드

모든 AI 에이전트를, 모든 프로젝트에서, 하나의 창으로 실행하세요.

무료AgentsRoom 다운로드

컴패니언 앱: 이동 중에도 에이전트를 모니터링

Claude, Codex, Antigravity CLI 또는 다른 AI 공급자를 사용하세요.

확장 프로그램 설치
Chrome Web Store

버그와 요청을 공개 백로그로 바로 보내세요.

멀티 프로젝트
멀티 프로바이더
멀티 에이전트
실시간 상태
파일 diff & 커밋
모바일 앱
라이브 프리뷰
에이전트 팀
브라우저 자동화
백로그 기반 개발
프롬프트 라이브러리
스킬 라이브러리
모든 기능 보기

계속 읽기