Claude Code 작업 환경 셋팅하기 - 2 (SubAgents)

hynnch2·2026년 1월 13일

지난 글에서는 Jira 티켓 → 요구사항 분석 → 계획 → 구현 → 리뷰로 이어지는 작업 흐름을 pol-team-* Skill 들로 쪼개어 정리했었는데요. 막상 운영해보니 Skill만으로는 풀리지 않는 문제들이 보였고, 이걸 해결하기 위해 Subagent를 도입하게 되었습니다.

이번 글에서는 그 도입 과정과 Subagent를 어떻게 팀처럼 구성했는지를 정리해보려고 합니다.

Subagent란?

Claude Code의 Subagent는 간단히 말하면 독립된 컨텍스트를 가진 별도의 Claude 인스턴스입니다. 메인 대화에서 Agent 도구로 호출되며, 자신만의 시스템 프롬프트·도구 권한·컨텍스트 윈도우를 가지고 작업한 뒤, 결과만 메인 대화로 돌려줍니다.

설정 위치와 형식은 Skill과 비슷합니다.

  • 위치: ~/.claude/agents/<agent-name>.md
  • 형식: frontmatter (name, description, tools, model) + 본문 (역할 정의)
  • 호출: 메인 Claude가 Agent 도구로 subagent_type을 지정해 호출

핵심은 컨텍스트가 분리된다는 점입니다. 메인 대화의 토큰을 잡아먹지 않고, 작업이 끝나면 결과 요약만 메인으로 넘어옵니다. 같은 메시지에서 여러 Subagent를 동시에 호출해 진짜 병렬 작업도 가능합니다.

Subagent를 도입하게 된 이유

지난 글에서 정리한 Skill 구조를 일정 기간 운영하면서, 크게 세 가지 한계를 마주했습니다.

1. 컨텍스트 오염

Skill만 사용하던 시기에는 모든 작업이 하나의 메인 대화 컨텍스트에서 이루어졌습니다. 요구사항 분석 → 도메인 정리 → 계획 수립 → 구현 → 리뷰까지 한 흐름이 모두 같은 컨텍스트에 누적되다 보니, 작업이 후반부로 갈수록 토큰이 빠르게 소진되었습니다.

특히 도메인 정리나 코드 작성처럼 중간 산출물이 큰 단계가 끼어 있으면, 정작 마지막 리뷰 단계에서는 컨텍스트 압박 때문에 품질이 떨어지는 일이 생겼습니다. 결국 분석 단계의 raw 데이터가 리뷰 단계에서도 메모리를 차지하는 셈인데, 이건 분명한 낭비였습니다.

2. 병렬 실행 불가

요구사항 분석과 Repo 도메인 매핑은 서로 의존성이 없는 작업이라, 동시에 돌리면 시간을 절반으로 줄일 수 있습니다. 하지만 Skill은 단일 컨텍스트에서 순차 실행되기 때문에, 이론상 병렬일 수 있는 작업도 실제로는 줄세워 돌릴 수밖에 없었습니다.

작은 차이처럼 보이지만, 티켓 하나를 처리할 때마다 누적되면 꽤 큰 시간 손실이 됩니다.

3. 재시도/루프 관리

리뷰 ↔ 구현 피드백 루프는 본질적으로 반복되는 흐름입니다. 구현 → 리뷰 → 이슈가 있으면 다시 구현 → 다시 리뷰. 이걸 메인 컨텍스트에서 돌리면, 각 라운드의 모든 산출물·로그·중간 판단이 컨텍스트에 그대로 쌓입니다.

3라운드쯤 돌면 이미 컨텍스트 대부분이 과거 라운드 흔적으로 채워져 있고, 정작 현재 라운드에서 봐야 할 코드와 리뷰 리포트는 좁은 자리만 차지하게 됩니다. 루프를 안전하게 여러 번 돌리려면, 각 라운드를 자체 컨텍스트에서 처리하고 메인은 결과 요약만 보관하는 구조가 필요했습니다.

team-* Subagent 구성

위 세 가지 문제를 해결하기 위해, 1편에서 정리한 5개 Skill에 대응하는 5개의 Subagent를 만들었습니다. 이름은 team-* 프리픽스로 통일했습니다.

각 Subagent는 자신과 짝이 되는 Skill을 호출하는 단일 임무만 가집니다. Subagent가 직접 코드를 작성하거나 분석을 추가로 수행하지 않고, 자기 Skill을 실행 → 산출물 검증 → 오케스트레이터에게 구조화된 리포트 반환만 합니다.

team-requirements-analyst — 요구사항 분석가

pol:team-requirements-organize Skill을 실행하는 Subagent입니다.

왜 별도 Subagent로 분리했는가: 요구사항 분석은 Jira 본문, 연결된 서브태스크, 첨부 문서, 코드베이스 일부까지 끌어와 분해하는 작업이라 컨텍스트 사용량이 큰 편입니다. 이걸 메인에서 돌리면 이후 단계가 좁아집니다. 별도 컨텍스트에서 처리한 뒤, 결과는 산출물 파일(requirements-<TICKET-ID>.md)로만 넘기게 했습니다.

team-domain-mapper병렬로 실행되는 두 시작점 중 하나입니다.

team-domain-mapper — 도메인 매퍼

pol:team-repo-domain-expression Skill을 실행하는 Subagent입니다.

왜 별도 Subagent로 분리했는가: Repo 도메인을 정리하려면 디렉토리 구조 탐색, 모듈 경계 파악, 도메인 레이어 식별 등 파일 시스템과 git을 광범위하게 훑는 작업이 필요합니다. 이 raw 정보가 메인 컨텍스트에 들어오면 그 자체로 토큰을 크게 먹습니다. Subagent가 자기 컨텍스트에서 처리하고, 결과는 정리된 Markdown 한 장으로 압축해 넘깁니다.

team-requirements-analyst와 동일 메시지에서 동시 호출되어 진짜 병렬 실행이 일어나는 구간입니다.

team-planner — 플래너

pol:team-plan Skill을 실행하는 Subagent입니다.

왜 별도 Subagent로 분리했는가: 플래너는 위 두 Subagent의 산출물(요구사항 + 도메인 구조)을 모두 읽고 병합해 구현 계획서를 만드는 역할입니다. 이 단계에서 결정해야 할 것이 많고(신규/확장/리팩토링 판정, 테스트 전략, 영향도 매트릭스), 모호한 부분은 <decision-points>로 빼서 사용자 확인까지 받아야 합니다.

이런 결정 집약적인 작업을 메인 컨텍스트에서 하면 결정 흐름과 다른 작업 컨텍스트가 섞여 판단 품질이 떨어집니다. 플래너만의 독립 컨텍스트에서 집중적으로 결정한 뒤, 결과는 plan-<TICKET-ID>.md 한 장(이후 단계의 SSOT)으로 응축됩니다.

team-implementer — 구현자

pol:team-code-work Skill을 실행하는 Subagent입니다.

왜 별도 Subagent로 분리했는가: 구현 단계에서 가장 중요한 원칙은 "plan은 불가침 SSOT" 였는데요. 메인 컨텍스트에서 코드 작성을 하면, 이전 단계의 분석·계획 흐름이 같은 컨텍스트에 남아 있어서 LLM이 자연스럽게 "이 부분은 사실 이렇게 짜는 게 더 좋을 것 같은데" 라며 재설계 방향으로 흐르기 쉽습니다.

구현자를 별도 Subagent로 떼어내면, 이 Subagent의 컨텍스트에는 plan 문서와 수정 대상 코드만 들어옵니다. 자연스럽게 "재설계자"가 아니라 "실행자" 역할에 머물게 됩니다. 역할 격리를 컨텍스트 격리로 강제하는 셈입니다.

피드백 루프에서는 이전 라운드의 리뷰 리포트 경로만 입력으로 받기 때문에, 라운드별 컨텍스트가 누적되지 않습니다.

team-reviewer — 리뷰어

pol:team-request-code-review Skill을 실행하는 Subagent입니다.

왜 별도 Subagent로 분리했는가: 리뷰어가 메인 컨텍스트에서 동작하면, 이미 "내가 짠 코드"라는 맥락이 컨텍스트에 남아 있어서 객관적인 진단이 어렵습니다. 별도 Subagent로 분리하면 리뷰어의 컨텍스트에는 diff와 plan 문서만 들어와, 마치 외부 리뷰어가 PR을 보는 것에 가까운 환경이 됩니다.

리뷰어는 코드를 절대 수정하지 않고, 심각도별(Critical/Important/Minor)로 분류된 리포트와 "Ready to merge" 판정(Yes/No/With fixes)을 기계 판독 가능한 형태로 리턴합니다. 이 판정값이 오케스트레이터의 다음 행동(피드백 루프 한 번 더 vs 종료)을 결정합니다.

오케스트레이터 동작 흐름

위 5개 Subagent를 묶어 자동으로 진행시키는 진입점이 pol:team-orchestrate 입니다. 오케스트레이터 자신은 코드 작성도, 분석도 하지 않습니다. 오직 Subagent를 호출하고, 그들의 리포트를 해석해서 다음 단계를 결정하는 지휘자 역할만 합니다.

전체 흐름은 다음과 같습니다.

[사용자: TICKET-ID]
        │
        ▼
┌─────────────────────────────────────────────────┐
│ ① 병렬 Phase                                    │
│   team-requirements-analyst ──┐                 │
│   team-domain-mapper          ┴─►  둘 다 OK 대기 │
├─────────────────────────────────────────────────┤
│ ② Plan Phase                                    │
│   team-planner                                  │
│   → plan-<ID>.md (Confirmed)                    │
│   [--interactive 시 사용자 승인]                │
├─────────────────────────────────────────────────┤
│ ③ 피드백 루프 Phase (최대 N회)                  │
│   for round in 1..N:                            │
│     team-implementer (round, prev review)       │
│     team-reviewer (round)                       │
│     if APPROVED: break                          │
├─────────────────────────────────────────────────┤
│ ④ Final Report Phase                            │
│   수정 파일, 리뷰 라운드 수, 남은 이슈 정리     │
└─────────────────────────────────────────────────┘

각 Phase에서 의도한 게 있습니다.

① 병렬 Phase한 메시지에서 두 Subagent를 동시에 호출합니다. 두 작업은 의존성이 없으므로 진짜 병렬 실행이 일어나며, 둘 다 완료되어야 다음 Phase로 넘어갑니다. Skill 시절에 줄세워 돌렸던 시간 손실을 여기서 회수합니다.

② Plan Phase는 위 두 산출물을 입력으로 team-planner를 호출합니다. --interactive 옵션을 주면 plan 생성 후 사용자 승인 단계가 들어가, decision points에 대한 응답을 받고 plan을 Confirmed 상태로 마감합니다. 이 단계 이후 plan은 불가침 SSOT가 됩니다.

③ 피드백 루프 Phase는 구현과 리뷰를 라운드 단위로 반복합니다. 각 라운드는 자체 Subagent 컨텍스트에서 처리되므로, 라운드가 누적되어도 메인 컨텍스트에는 라운드별 요약만 쌓입니다. 리뷰어의 "Ready to merge" 판정이 Yes면 루프를 빠져나가고, --max-review-rounds 한도(기본 3)에 도달하면 에스컬레이션합니다.

④ Final Report Phase에서는 수정한 파일 목록, 리뷰 라운드 수, 남은 이슈, 다음에 제안할 Skill(set-commit-push 등)을 정리해 사용자에게 돌려줍니다.

이 구조 덕분에 메인 대화 컨텍스트는 거의 비어 있는 상태로 유지되고, 각 Subagent의 산출물은 .claude-artifacts/*.md 파일로 디스크에 명시적으로 남습니다. 작업이 어디서 어떻게 결정됐는지 추적도 쉬워졌습니다.

후기

Skill만 쓰던 시절과 비교하면, Subagent까지 들어간 뒤로 메인 대화는 깨끗하고, 각 단계의 책임은 더 분명해졌습니다. 컨텍스트 오염, 병렬 실행, 루프 누적이라는 세 문제가 한꺼번에 풀린 게 가장 큰 변화였습니다. 무엇보다도 "메인 Claude는 지휘만 하고, 실제 일은 팀이 한다"는 그림이 실제로 동작하는 걸 보면서, 이런 구조를 더 키워보고 싶다는 생각이 들었습니다.

다음 단계로는 두 가지 방향을 생각하고 있습니다.

첫 번째는 잘 만들어진 외부 자산을 적극적으로 도입하는 것입니다. 제가 직접 만든 Skill·Subagent 외에도, 예를 들어 EveryInc/compound-engineering-plugin 처럼 이미 잘 정리된 플러그인들이 있는데요. 처음부터 제가 다 만들기보다는, 검증된 자산을 가져와 제 워크플로우와 결합하는 방향이 효율적이라고 봅니다.

두 번째는 단순 작업 자동화를 넘어, PM처럼 일을 관리해주는 Subagent / 팀을 구성하는 것입니다. 지금까지의 team-* 구성은 "티켓 하나를 받아 처리하는 작업자 팀"에 가까운데요. 여기서 한 단계 더 나아가서, 여러 티켓의 우선순위를 조율하고, 진행 상황을 추적하고, 막힌 부분을 식별해 다음 액션을 제안해주는 매니저 역할의 Subagent까지 구축해보려고 합니다. 그렇게 되면 Claude Code가 단순히 "코드를 작성해주는 도구"가 아니라, 작업 흐름 자체를 함께 운영해주는 동료에 가까워질 거라 기대하고 있습니다.

긴 글 읽어주셔서 감사합니다.

profile
more than yesterday

0개의 댓글