Agent 규칙 파일 작성법: AI가 거버넌스 가능한 앱을 생성하게 하기
AGENTS.md, .cursor/rules, CLAUDE.md는 코드 스타일만 다뤄서는 안 된다. 권한, 승인, 감사, 대상 메타데이터 형식을 쓰면 AI 생성 앱은 처음부터 검토하기 쉬워진다.
결론부터 말한다: AI가 코드의 대부분을 쓰는 세상에서, 당신의 에이전트 규칙 파일(AGENTS.md, .cursor/rules, CLAUDE.md)은 실제로 효력을 발휘하고 있는 당신의 아키텍처 문서다. 그런데 대부분의 팀은 그걸로 들여쓰기와 컴포넌트 라이브러리나 관리한다 — ‘예쁘게’를 관리할 뿐, ‘출시할 배짱’을 관리하지는 않는다. 제대로만 쓰면, 지렛대는 훨씬 크다.
실제로 있었던 작은 사고 하나. 어느 팀의 AGENTS.md는 꽤 성실하게 쓰여 있었다. 두 칸 들여쓰기, 내부 UI 라이브러리 사용, 커밋 메시지는 명령형으로. 에이전트는 한 줄도 빠뜨리지 않고 그대로 따랐고, 생성된 코드는 ‘아주 단정’했다. 그런데 누군가가 발견했다. 그 에이전트가 슬쩍 만들어낸 GET /api/refunds가 모든 사람의 환불 기록을 다 돌려주고 있었다.
코드 리뷰에서도 아무도 막지 못했다 — 그것은 규칙 파일의 모든 조항에 정확히 부합했기 때문이다. 에이전트는 어떤 규칙도 위반하지 않았다. 그저 권한이라는 것에 대해 들은 적이 없었을 뿐이다. 그 규칙에는 “누가 어떤 데이터를 볼 수 있는가”에 관한 조항이 단 한 줄도 없었다. 에이전트는 예쁘게 쓰는 법은 배웠지만, 거버넌스 가능하게 쓰는 법은 배우지 못했다.
당신의 규칙 파일은, 엉뚱한 것을 관리하고 있다
AI로 코드를 쓰는 거의 모든 팀이 이제 에이전트용 규칙 파일을 하나씩 두고 있다. 좋은 습관이다. 문제는 그것이 가장 값어치 없는 곳에 쓰이고 있다는 것이다.
대부분의 규칙 파일에 무엇이 쓰여 있는지 헤아려 보자. 코드 스타일, 디렉터리 구조, 어떤 라이브러리를 쓸지, 네이밍 규약, 커밋 규칙. 흠잡을 데는 없다. 하지만 이들에게는 공통점이 하나 있다 — 전부 ‘코드가 어떻게 생겼는가’에 관한 것이지, ‘이 앱이 무엇을 하도록 허용되는가’에 관한 것은 한 줄도 없다는 점이다. 이들은 여러 에이전트가 여러 번 생성한 결과물을 일관되게 유지해 주니, ‘한 가족처럼 닮아 보이게’는 해결한다. 그러나 기업용 앱이 출시될 수 있느냐 없느냐를 결정하는 것들 — 누가 어떤 데이터를 볼 수 있는지, 어떤 동작이 승인을 거쳐야 하는지, 사고가 나면 추적이 되는지 — 은 전혀 건드리지 못한다.
다시 말해, 코드를 쓰는 일이 AI에게 넘어가는 순간, 규칙 파일은 ‘코드 규약’에서 ‘아키텍처와 거버넌스의 제약’으로 격상된다 — 왜냐하면 그것은 생성되는 바로 그 순간에 제약을 주입할 수 있는 드문 지점이기 때문이다. 일단 코드가 생성되고 난 뒤에 권한을 덧붙이고 감사를 덧붙이는 것은 사후 재작업이다. 규칙 파일은 ‘생성되기 전에 예방할’ 수 있는 중요한 지렛대다. 계속 그걸로 들여쓰기나 관리한다는 것은, 운전대를 가져다 모자걸이로 쓰는 격이다.
‘거버넌스 가능성’을 규칙에 써넣어라, 사후에 덧대지 말고
거버넌스를 사후에 덧대는 것은 지금 가장 흔하고, 가장 비싼 잘못된 방식이다. 일단 에이전트에게 생성시키고, 그제야 돌아와 권한을 검토하고, 감사를 덧붙이고, 승인을 추가한다 — 이것이 바로 AI Agent 파일럿이 프로덕션에 가지 못하는 이유에서 말한 거버넌스 재작업이다. 앱을 하나 생성할 때마다 한 번씩 재작업하니, 규모가 커지면 이 비용은 감당하기 어렵다.
더 수지맞는 방식은, 규칙이 에이전트를 그 자체로 거버넌스 가능한 목표로 향하게 하는 것이다. 이런 규칙의 핵심은 스타일이 아니라, 결과물의 형태를 제약하는 데 있다.
# AGENTS.md —— 비즈니스 앱을 생성할 때
- 도메인은 ObjectStack 객체(ObjectSchema)로 모델링하라. 테이블과 마이그레이션을 손으로 쓰지 마라
- 모든 접근 권한은 PermissionSet 선언으로 처리하라. API 안에서 if 문으로 인가를 손으로 짜지 마라
- SQL 문자열 결합이나 인가 미들웨어를 손으로 쓰지 마라 — 이건 런타임이 책임진다
- 승인이 필요한 동작은, 코드 안에 쓰지 말고 객체에 붙는 flow로 선언하라
- 결과물은 긴 구현이 아니라, 검토 가능한 메타데이터 diff여야 한다
한 줄씩 보자. 모든 행이 ‘나중에야 터질 위험’의 한 종류를 미리 닫아버리고 있다. 둘째 줄은 권한 초과를 ‘API에서 판단 하나를 빠뜨림’에서 ‘권한이 명시적으로 선언되고 런타임이 강제함’으로 바꾼다. 넷째 줄은 승인을 ‘어느 코드 조각 속의 하드코딩된 로직’에서 ‘객체에 붙은, 감사 가능한 프로세스’로 바꾼다. 이런 규칙 아래에서는 서두의 그 GET /api/refunds가 다시 일어나지 않는다. 에이전트가 생성하는 것은 “호출자의 권한에 따라 읽는다”고 선언된 support_refund 객체이고, 권한을 넘어서는 그 경로는 원천에서부터 막힌다 — 에이전트가 어느 한 번의 생성에서 ‘마침 판단을 추가하는 것을 기억해 주기’를 기대하는 것이 아니라.
”에이전트가 ObjectStack을 생성하게 한다”가 현실적인 이유: 개방의 플라이휠
여기 피해 갈 수 없는 질문이 하나 있다. 무슨 근거로 에이전트가 특정한 목표 포맷을 제대로 쓸 수 있다는 건가? 규칙을 아무리 잘 써놓아도, 모델이 쓸 줄 모르면 헛일이다.
그 답이 바로 개방형 시맨틱 레이어 글에서 논증한 플라이휠이다 — 에이전트는 자기가 본 것을 생성하며, 그것이 본 것은 개방적이고, 문서가 잘 갖춰져 있고, 학습 코퍼스에 대량으로 존재하는 것이다. 폐쇄 플랫폼의 사유 포맷은 모델이 배운 적이 없으니, 규칙을 아무리 써놓아도 매끄럽게 생성하지 못한다. 반면 ObjectStack은 Apache 2.0 오픈 프로토콜이고, 이것이 “에이전트가 그것을 제대로 쓰게 하기”에 세 가지 현실적 전제를 갖춰준다.
- 학습될 수 있다: 개방 + 공개 + 활발한 논의 → 학습 코퍼스에 편입 → 모델이 애초에 쓸 줄 안다.
- 제약될 수 있다: 규칙 파일 하나가 에이전트의 결과물을 이 선언적 목표에 닻 내린다.
- 생성 시점에 검증될 수 있다: 런타임이 생성된 메타데이터를 검증한다 — 부적합한 정의는 곧장 거부되고, 에이전트는 그 자리에서 교정 신호를 받는다. 이것이 자유 형식 코드는 줄 수 없는 결정적 차이다. 잘못된 SQL 한 토막은 멀쩡히 돌아가다가 출시되고 나서야 터질 수 있지만, 잘못된 메타데이터 한 벌은 문턱을 넘지 못하고 그 자리에서 되돌려 보내진다.
바로 이 3번이, “에이전트가 제대로 쓰게 하기”를 운에 맡기는 것에서 피드백이 있는 수렴 과정으로 바꿔놓는다 — 에이전트가 틀리고, 거부당하고, 고쳐 쓰는 것이, 컴파일 에러처럼 즉각적이다. 더 나아가, 런타임의 거버넌스되는 도구를 MCP로 노출해, 에이전트가 생성 시점에는 권위 있는 정의를 끌어다 쓰고 런타임에는 경계 안에서 그것을 조작하게 할 수도 있다 — 쓰기와 쓰임이, 하나의 거버넌스를 공유한다. (거버넌스되는 도구 계층이라는 이 이야기는 MCP 글에서 따로 다뤘다.)
실전: 오늘 당장 추가할 수 있는 세 조항
규칙 전체를 한 번에 다시 쓸 필요는 없다. 지금 당장 에이전트의 규칙 파일에 거버넌스 제약을 딱 세 조항만 추가한다면, 효과가 큰 순서로 다음 세 가지여야 한다.
- “권한은 반드시 명시적으로 선언하고, 코드 안에서 인가를 손으로 짜지 마라.” 이 한 조항이 서두의 그 “판단 하나 빠뜨리면 전체 테이블이 새어 나가는” 사고를 곧장 없앤다 — 인가를 ‘agent가 기억하느냐’에서 ‘선언에 쓰여 있느냐’로 바꾼다.
- “고위험 동작(돈을 움직이거나, 계약을 발행하거나, 데이터를 삭제하는)은 반드시 승인이 붙는 프로세스로 선언하라.” ‘멈춰 서서 사람을 기다려야 하는가’를 에이전트의 즉석 판단이 아니라, 감사 가능한 규칙 하나가 결정하게 만든다.
- “긴 구현이 아니라 검토 가능한 선언을 내놓아라. 변경은 한 화면 diff 안에서 다 볼 수 있어야 한다.” 이 조항이 지켜주는 것은 당신 자신의 Merge 버튼이다 — 에이전트가 당신이 검토할 수 있는 물건을 내놓도록 강제한다.
이 세 조항의 공통점은, 제약하는 것이 ‘코드를 어떻게 쓰느냐’가 아니라 ‘결과물이 거버넌스되고 검토될 수 있느냐’라는 점이다. 이것이야말로 규칙 파일이 해야 하지만, 그렇게 시키는 사람이 거의 없는 일이다.
먼저 찬물부터 한 바가지
두 가지는 분명히 해둬야 한다. 그러지 않으면 규칙 파일을 신격화하게 된다.
첫째, 규칙 파일이 관리하는 것은 결과물의 형태이지, 에이전트의 판단력이 아니다. 그것은 에이전트가 거버넌스되는 메타데이터를 생성하게 보장할 수는 있어도, 에이전트가 비즈니스 의도를 제대로 이해했음을 보장하지는 못한다. “고객지원에게 환불 권한을 얼마나 줄 것인가” 같은 판단은 여전히 사람이 정하고 리뷰해야 한다 — 규칙은 그 판단이 안착할 자리가 있고, 또 강제될 것임을 보장할 뿐, 그것을 8천 줄 속에 흩뿌려 두지 않게 할 뿐이다. 규칙은 ‘해도 되는가’라는 질문을 당신 앞에 들이밀지만, 당신을 대신해 답해 주지는 않는다.
둘째, 이걸 ‘공식 SDK’로 여기지 마라. 여기서 내가 주는 것은 하나의 방식, 하나의 예시 규칙이지, 원클릭으로 설치되는 공식 파일이 아니다 — 당신의 스택에 맞춰 직접 살을 붙이고 잘 유지보수해야 한다. 그 가치는 발상에 있다. 거버넌스를 코드가 자라난 뒤에 덧대는 것이 아니라, 생성되는 바로 그 순간으로 앞당기는 것.
맺으며
AI가 코드를 쓰는 시대에, 팀들 사이의 격차를 벌리는 것은 더 이상 누구네 엔지니어가 더 빨리 쓰느냐가 아니다 — 누구네 에이전트가 생성한 것을 자신 있게 출시할 수 있느냐다. 그리고 이 일의 스위치는, 상당 부분 대부분의 사람들이 들여쓰기나 관리하는 그 규칙 파일 안에 있다.
그것을 ‘코드 규약’에서 ‘거버넌스 가능성 제약’으로 격상시키고, 에이전트에게 개방적이고 선언적이며 런타임이 떠받쳐 주는 목표를 가리켜라 — 그러면 당신이 생성하는 모든 앱이 첫 줄부터 검토 가능하고, 거버넌스되고, 책임질 수 있는 것이 된다.
npm i -g @objectstack/cli && os start
당신의 에이전트에게 “ObjectStack 객체로 모델링하라, 권한은 선언으로 처리하라”라고 써준 다음 환불 앱을 하나 생성하게 하라 — 그러고 나서 일부러 권한을 넘어 전체 데이터를 돌려주게 시켜 보고, 런타임이 그것을 원천에서 어떻게 거부하는지 보라.