지금 현장에서 일어나고 있는 일
AI 에이전트에 자율성을 얼마나 줄 것인가. 이 질문은 점점 더 실무적인 문제가 되고 있다. 이번 주 dev.to에서 올라온 세 편의 현장 글이 각기 다른 각도에서 같은 결론을 가리키고 있어서 묶어서 짚어본다.
첫 번째는 Claude Code를 두 달간 마이크로매니징 방식으로 운영하다가 완전 자율 모드로 전환한 개발자의 회고다. 두 번째는 AI 코딩 에이전트가 반복적으로 저지르는 프론트엔드 TypeScript 실수를 막기 위해 4,000줄짜리 Agent Skill을 직접 제작한 사례다. 세 번째는 Cursor가 생성한 Express 백엔드 코드 대부분에서 와일드카드 CORS가 반복적으로 등장하는 이유와 수정 방법을 다룬 글이다. 세 이야기 모두 표면적으로는 다르지만, 핵심 메시지는 하나로 수렴한다. 자율성을 주기 전에 제약의 틀을 먼저 설계하라.
in-the-loop는 확장되지 않는다
첫 번째 사례의 개발자는 AI 에이전트가 파일 하나 수정할 때마다 직접 승인했다. 코드 품질은 좋았지만, 에이전트는 고급 자동완성에 불과했다. 전환점은 'in-the-loop'와 'on-the-loop' 개념을 접하면서였다. in-the-loop는 내가 에이전트의 모든 동작 사이클 안에 있는 구조, 즉 마이크로매니지먼트다. on-the-loop는 방향과 제약을 설정하고 결과를 검토하는 구조, 즉 위임이다.
그가 on-the-loop로 전환할 수 있었던 건 신뢰가 생겨서가 아니었다. 2,700개 이상의 테스트, Psalm·Pint·ESLint·TypeScript 등의 정적 분석 도구, pre-commit hook, CI 파이프라인, 그리고 Actions 패턴·서비스 계약·정책 같은 아키텍처 규칙이 먼저 갖춰져 있었기 때문이다. 이 guardrails들이 '에이전트가 움직일 수 있는 복도'를 정의했고, 그 복도 안에서만 에이전트는 자유롭게 실행된다.
더 흥미로운 부분은 피드백 루프 설계다. 에이전트가 실수하면 코드만 고치는 게 아니라 해당 영역의 CLAUDE.md 하니스 파일을 업데이트하고, 에이전트는 그 파일을 리로드한 뒤 변경을 재적용한다. 결국 에이전트가 하니스를 스스로 업데이트하는 구조, 즉 자기강화 루프가 형성된다. /implement-jira-card 같은 슬래시 커맨드로 TDD 워크플로우 전체를 캡슐화하는 것도 같은 맥락이다. 프로세스를 반복 설명하는 비용을 없애고, 일관성을 구조적으로 강제한다.
Agent Skill은 '예시 모음'이 아니라 '의사결정 지원'이어야 한다
두 번째 사례에서 개발자는 AI가 매번 같은 실수를 반복한다는 걸 깨달았다. res.json()에 런타임 검증 없이 타입 단언을 붙이거나, 불가능한 상태 조합을 표현할 수 있는 분리된 상태 변수를 쓰거나, 페이지 컴포넌트 전체에 'use client'를 슬래퍼처럼 붙이는 패턴들이다. 세션마다 같은 수정을 반복하고, 그 수정은 다음 세션에 전혀 이어지지 않는다.
그가 만든 typescript-react-patterns는 npm 패키지가 아니라 Claude Code와 Cursor 등이 코드 생성 전에 자동으로 참조하는 Agent Skill이다. 17개 파일, 4,000줄 이상. 핵심 설계 원칙은 예시가 아니라 의사결정 지원이다. "어떤 패턴을 써라"가 아니라 "서버 데이터인가? Yes → TanStack Query. URL 공유가 필요한가? Yes → searchParams. 아니면 컴포넌트 몇 개가 쓰나? 1개면 useState, 여러 개면 Zustand"처럼 판단 흐름을 플로우차트로 제공한다.
규칙 분류 방식도 실용적이다. [HARD RULE]은 위반하면 버그가 발생하므로 예외 없음, [DEFAULT]는 명시적 이유 없이 벗어나지 않는 권장 사항, [SITUATIONAL]은 컨텍스트에 따라 다름. 이 분류 하나만으로 에이전트가 모든 가이드라인을 절대 규칙으로 취급하는 문제가 줄어든다고 한다. 팀 단위로 적용하면, 시니어가 반복적으로 코드 리뷰에서 잡던 패턴 오류를 사전에 차단할 수 있다.
AI 생성 코드의 보안 취약점은 훈련 데이터 문제다
세 번째 사례는 더 직접적인 경고다. Cursor로 생성한 Express 백엔드 10개 중 8개에서 cors({ origin: '*' })가 발견된다는 관찰이다. 이건 Cursor만의 문제가 아니다. "CORS 추가해줘"라는 프롬프트에 대해 대부분의 LLM이 와일드카드를 기본값으로 내놓는다. 이유는 단순하다. StackOverflow의 수많은 CORS 예제가 "브라우저 요청이 작동하게 만들어라"는 목적으로 작성됐고, 보안 고려는 없었다. LLM은 그 패턴을 그대로 학습했다.
문제는 단순해 보이지만 실제 공격 벡터가 된다. 와일드카드 CORS에서 credentials: true를 함께 쓰면 브라우저가 직접 거부하기 때문에 개발자가 에러를 다시 AI에게 물어보고, AI는 또 잘못된 우회 방법을 제안하는 악순환이 이어진다. 인증된 API에서 와일드카드 CORS만 있어도 피해자 브라우저 안에서 다른 사이트가 API를 호출해 응답을 읽을 수 있다. CWE-346 Origin Validation Error로 분류되는 취약점이다.
수정은 간단하다. origin: '*' 대신 허용 오리진 배열을 검증하는 함수로 교체하고, CI에 미인가 오리진 차단 여부를 검증하는 통합 테스트를 추가하면 된다. 글에서는 semgrep과 gitleaks를 활용한 pre-commit hook, 또는 SafeWeave 같은 MCP 서버 방식으로 이 패턴을 사전에 탐지하는 방법도 소개한다. 핵심은 AI가 생성한 코드를 리뷰할 때 기능 동작만 보지 말고 보안 패턴도 자동으로 검사하는 파이프라인을 팀이 갖고 있어야 한다는 것이다.
테크 리드가 실제로 챙겨야 할 것들
세 사례를 현장에서 곧바로 쓸 수 있는 관점으로 정리하면 이렇다.
guardrails 없는 자율성은 방치다. on-the-loop 전환을 고려 중이라면 먼저 테스트 커버리지, 정적 분석 도구, 아키텍처 패턴 문서가 갖춰졌는지 확인하라. 이 세 가지가 없는 상태에서 auto-approve를 켜는 건 위임이 아니다.
Agent Skill은 팀의 코드 리뷰 기준을 기계화한 문서다. 반복적으로 코드 리뷰에서 지적하는 패턴이 있다면, 그것부터 CLAUDE.md나 SKILL.md에 넣어라. "예시 코드 몇 줄" 수준이 아니라 "이 상황에서는 이 패턴, 저 상황에서는 저 패턴"이라는 판단 기준까지 담아야 효과가 있다.
AI 생성 코드의 보안 검사는 수동 리뷰에 맡기지 마라. CORS 와일드카드처럼 기능적으로는 정상 동작하지만 보안상 취약한 패턴은 코드 리뷰에서 놓치기 쉽다. semgrep 룰셋이나 전용 MCP 서버를 CI에 넣어 자동으로 플래그를 세우는 구조를 만들어야 한다.
결국 이 구조의 방향은 어디로 가는가
세 사례가 공통으로 가리키는 방향이 있다. AI 에이전트의 자율성은 올라가고, 사람의 역할은 '실행 승인'에서 '결과 검토'와 '제약 설계'로 이동한다는 것이다. 개발자가 에이전트에게 더 많이 위임할수록, 위임의 품질을 결정하는 건 에이전트 성능이 아니라 guardrails의 설계 수준이 된다.
역설적이지만, AI-First 팀에서 사람이 해야 할 가장 중요한 일 중 하나는 AI가 잘못된 방향으로 가지 못하게 하는 제약 시스템을 만드는 것이다. 테스트, 린터, 아키텍처 패턴 문서, Agent Skill, 보안 검사 파이프라인—이것들이 에이전트가 빠른 속도로 움직일 수 있는 '안전한 복도'를 만든다. 복도 없이 속도만 높이면, 에이전트는 더 빨리 잘못된 곳으로 달려갈 뿐이다.