블로그로 돌아가기

Claude Code Subagent vs 구조화된 태스크 분할: 언제 무엇을 사용할 것인가

Claude Code Subagent vs 구조화된 태스크 분할: 언제 무엇을 사용할 것인가

세 가지를 동시에 처리해야 하는 feature가 있다. 단일 Claude Code 세션 안에서 subagent를 spawn해서 병렬로 작업시킬 수 있다. 아니면 작업을 세 개의 독립적인 태스크로 나누고, 각각을 별도의 tmux 패인에서 실행되는 별도 에이전트에게 맡기고, 서로의 존재를 모른 채 실행시킬 수 있다.

두 접근법 모두 작업을 병렬화한다. 해결하는 문제가 다르다. 잘못된 것을 선택하면 코디네이션 오버헤드에 컨텍스트 윈도우를 태우거나, 원래 태스크보다 수정하는 데 더 오래 걸리는 merge 충돌을 만들게 된다.

이것이 같은 코드베이스에서 13개의 Claude Code 에이전트를 운영하면서 매일 사용하는 의사결정 프레임워크다. 이론이 아니다. 경계가 어디에 있는지 알 때까지 충분히 실수한 결과다.

두 종류의 병렬성

Claude Code는 작업을 동시에 실행하는 두 가지 별개의 방법을 지원한다.

Subagent는 단일 Claude Code 세션 내에서 spawn되는 자식 프로세스다. 부모 에이전트가 여러 subagent를 시작하고, 각각이 문제의 일부를 처리한 후 결과를 수집한다. 같은 작업 디렉토리와 부모의 컨텍스트를 공유한다. 단일 프로세스 내의 스레드로 생각하면 된다.

Parent agent
  ├── Subagent A: "Search lib/ for all usages of parseConfig"
  ├── Subagent B: "Search server/ for all usages of parseConfig"
  └── Subagent C: "Search components/ for all usages of parseConfig"

별도 에이전트는 독립된 Claude Code 세션에서 실행되며, 보통 별도의 tmux 패인에 배치된다. 각각 자체 컨텍스트 윈도우, 자체 CLAUDE.md 아이덴티티 파일, 자체 코드베이스 뷰를 갖는다. 메모리를 공유하지 않는다. 아티팩트를 통해 소통한다: 태스크 코멘트, 상태 업데이트, commit된 코드. 공유 상태가 없는 별도 프로세스로 생각하면 된다.

tmux pane 1: eng1 agent → "Build the REST endpoint"
tmux pane 2: eng2 agent → "Build the React component"
tmux pane 3: qa1 agent  → "Write integration tests for both"

멘탈 모델이 중요한 이유는 유닛 간 작업 흐름을 결정하기 때문이다. Subagent는 부모에게 데이터를 저렴하게 전달할 수 있다. 별도 에이전트는 파일시스템, git, 또는 외부 태스크 트래커를 통해 데이터를 전달한다.

Subagent가 이기는 경우

작업이 상태를 공유하고 결과가 수렴해야 할 때 subagent를 사용한다.

병렬 리서치. 다섯 개 디렉토리에서 패턴을 검색하고, 세 개의 문서 파일을 읽고, 발견사항을 하나의 권고로 종합해야 한다. Subagent가 각각 검색 경로를 맡고, 결과를 반환하고, 부모가 직렬화 오버헤드 없이 조합할 수 있다.

같은 데이터에 대한 독립적 변환. 모듈을 리팩토링하면서 타입 정의, 테스트, 문서를 하나의 일관된 변경으로 업데이트해야 한다. 각 subagent가 파일 하나를 처리하지만, 부모가 commit 전에 세 결과를 모두 보기 때문에 일관성을 보장한다.

빠른 탐색. 디버깅 중이고 git log, 테스트 출력, 런타임 설정을 동시에 확인해야 한다. Subagent가 세 가지를 병렬로 수집하고 부모가 진단을 종합한다.

패턴: 분산시키고, 수집하고, 결합된 결과에 따라 행동한다. 병렬화가 부모가 모든 output에 대해 함께 추론해야 하는 것으로 끝난다면, subagent가 올바른 도구다.

Subagent가 약한 영역: 브랜치당 몇 분 이상 걸리는 것, 겹치는 경로의 파일을 수정하는 것, 독립적 검증이 필요한 것. Subagent는 작업 디렉토리를 공유하므로, 두 subagent가 같은 파일에 쓰면 서로의 작업을 손상시킨다. 그리고 컨텍스트를 공유하므로, 오래 실행되는 subagent는 부모의 가용 윈도우를 소모한다.

별도 에이전트가 이기는 경우

작업이 독립적으로 검증될 수 있고 의미를 갖기 위해 공유 컨텍스트가 필요 없을 때 별도 에이전트를 사용한다.

같은 feature의 다른 컴포넌트. "API 엔드포인트 구축"과 "그것을 호출하는 프론트엔드 구축"은 통합 전까지 독립적이다. API 엔지니어는 React 컴포넌트를 컨텍스트에 필요로 하지 않는다. 프론트엔드 엔지니어는 데이터베이스 스키마가 필요 없다. 각각에게 범위가 지정된 CLAUDE.md를 가진 자체 에이전트를 주면 컨텍스트가 깨끗하게 유지되고 한 에이전트의 복잡성이 다른 에이전트의 작업에 스며드는 것을 방지한다.

다른 수락 기준. 태스크 A가 엔드포인트가 올바른 JSON 형태로 200을 반환할 때 완료이고, 태스크 B가 컴포넌트가 적절한 에러 상태로 데이터를 렌더링할 때 완료라면, 이것들은 별도의 검증 대상이다. QA 에이전트가 각각을 독립적으로 검증할 수 있다. Subagent는 결합된 output을 생성하기 때문에 독립적으로 QA할 수 없다.

코드베이스의 다른 부분을 건드리는 작업. 파일 소유권은 merge 충돌을 방지하는 가장 단순한 방법이다. 에이전트 A가 server/를 소유하고, 에이전트 B가 components/를 소유한다. 어느 쪽도 상대의 영역에 들어가지 않는다. Subagent로 이것을 시도하면 부모가 파일 잠금을 관리해야 하고, 이는 병렬화의 목적을 무효화한다.

다른 시간 범위의 태스크. 한 태스크가 10분, 다른 것이 2시간 걸린다. Subagent에서는 부모가 가장 느린 자식을 기다린다. 별도 에이전트에서는 짧은 태스크가 완료되고, 검증되고, ship되는 동안 긴 태스크는 여전히 실행 중이다.

패턴: 발사하고, 잊고, 별도로 검증한다. 작업의 각 조각이 독립적으로 서고 독립적으로 확인될 수 있다면, 구조화된 태스크를 가진 별도 에이전트가 더 깔끔하다.

핸드오프 문제

실제 결정 포인트는 핸드오프로 귀결된다.

Subagent 핸드오프는 저렴하다. 자식이 같은 컨텍스트에서 부모에게 데이터를 반환한다. 직렬화 없음, 파일 쓰기 없음, 상태 업데이트 대기 없음. 부모가 세 subagent를 시작하고, 세 결과를 반환받고, 부모는 필요한 모든 것을 갖는다.

별도 에이전트 간 핸드오프는 비용이 크지만 내구성이 있다. 에이전트 A가 작업을 완료하고, 코드를 commit하고, 태스크 상태를 업데이트하고, 무엇을 했는지 코멘트한다. 에이전트 B가 그 신호를 포착하고(코디네이터를 통해서든 태스크 트래커를 폴링해서든) 종속 작업을 시작한다. 오버헤드는 현실적이다: 태스크 시스템, 상태 프로토콜, 에이전트가 다른 에이전트의 작업을 발견할 방법이 필요하다.

경험 법칙: 병렬 유닛 간에 핸드오프가 두 번 이상 필요하면 subagent를 사용한다. 단일 fan-out-and-gather라면 subagent가 더 단순하다. 에이전트 A의 output이 에이전트 B의 input이 되고, 그것이 에이전트 C의 input이 되면, 별도 에이전트의 코디네이션 비용은 정당화된다. 각 핸드오프가 에이전트가 크래시하거나 컨텍스트 제한에 도달해도 손실되지 않는 검증된 commit 아티팩트를 생성하기 때문이다.

구체적 예시. 다음을 해야 한다:

  1. 사용자 데이터를 반환하는 모든 API 엔드포인트 찾기
  2. 각각에 rate limiting 추가
  3. 새 rate limit에 대한 테스트 작성
  4. API 문서 업데이트

1단계와 2단계는 밀접하게 결합되어 있다. 검색 결과(1단계)가 수정(2단계)에 직접 투입된다. Subagent가 검색을 처리하고, 부모가 변경을 적용한다. 이것이 subagent 패턴이다.

3단계와 4단계는 서로 독립적이지만 2단계에 의존한다. 테스트는 실제 엔드포인트 코드가 필요하다. 문서는 최종 API 형태가 필요하다. 이것들은 별도 에이전트를 위한 별도 태스크이며, 각각 자체 수락 기준을 갖고, 각각 독립적으로 검증 가능하다.

이것이 Beadbox가 해결하는 문제입니다.

전체 에이전트 플릿이 무엇을 하고 있는지 실시간으로 파악하세요.

베타 기간 중 무료로 사용해 보세요 →

구조화된 태스크 분할 실전

답이 "별도 에이전트"일 때, feature를 서로 방해하지 않고 병렬 실행할 수 있는 태스크로 분해할 방법이 필요하다.

분해 프로세스:

1. 종속성 그래프 식별. 무엇이든 나누기 전에 무엇이 무엇에 의존하는지 매핑한다:

Feature: User profile page with activity feed

- API endpoint: GET /users/:id/profile     (no deps)
- API endpoint: GET /users/:id/activity     (no deps)
- React component: ProfileHeader            (depends on profile API)
- React component: ActivityFeed             (depends on activity API)
- Integration test: profile page end-to-end (depends on all above)

두 API 엔드포인트는 종속성이 없다. 병렬 실행 가능하다. 두 React 컴포넌트는 각각 하나의 API에 의존한다. 통합 테스트는 모든 것에 의존한다.

2. 소유권 경계 설정. 각 태스크에 파일 범위를 부여한다. Profile API 에이전트는 server/routes/profile.tsserver/services/profile.ts를 소유한다. Activity API 에이전트는 server/routes/activity.tsserver/services/activity.ts를 소유한다. 어느 쪽도 상대의 파일을 건드리지 않는다. 공유 유틸리티의 수정이 필요하면, 한 에이전트가 변경을 만들고 다른 에이전트가 기다린다.

3. 태스크별 수락 기준 정의. 각 태스크에는 다른 태스크를 보지 않고 검증할 수 있는 명확한 "완료" 조건이 필요하다. "Profile API가 올바른 형태로 200을 반환한다"는 검증 가능하다. "프로필 페이지가 작동한다"는 불가능하다. 통합에 의존하기 때문이다.

4. 핸드오프 아티팩트 지정. 하류 에이전트가 상류 에이전트로부터 무엇이 필요한가? 보통: 알려진 브랜치의 commit된 코드, 상태 업데이트, 인터페이스 계약을 설명하는 코멘트(API 형태, 컴포넌트 props, 함수 시그니처).

이 분해는 모호한 "프로필 페이지 만들기"를 명시적 종속성과 검증 기준을 가진 다섯 개의 개별 태스크로 변환한다. 각 태스크는 필요한 컨텍스트만을 가진 에이전트에 할당될 수 있다.

Beads를 활용한 구조화된 분할

여기서 실제 태스크 시스템을 갖는 것이 중요해진다. 다섯 개의 병렬 태스크를 포스트잇과 터미널 출력으로 추적할 수 없다.

beads는 로컬 퍼스트 이슈 트래커로, 이 분해를 네이티브로 모델링한다. Epic이 feature를 나타낸다. Children이 서브태스크를 나타낸다. Dependencies가 전제 조건이 완료되기 전에 에이전트가 작업을 시작하는 것을 방지한다.

실전에서 분할은 이렇게 보인다:

# Create the epic
bd create --title "User profile page with activity feed" \
  --type epic --priority p2

# Create subtasks as children
bd create --title "GET /users/:id/profile endpoint" \
  --parent bb-epic1 --type task --priority p2

bd create --title "GET /users/:id/activity endpoint" \
  --parent bb-epic1 --type task --priority p2

bd create --title "ProfileHeader React component" \
  --parent bb-epic1 --type task --priority p2 \
  --deps bb-profile-api

bd create --title "ActivityFeed React component" \
  --parent bb-epic1 --type task --priority p2 \
  --deps bb-activity-api

bd create --title "Profile page integration test" \
  --parent bb-epic1 --type task --priority p2 \
  --deps bb-profile-header,bb-activity-feed

구조가 명시적이다. bd show bb-profile-header를 실행하는 에이전트는 profile API 태스크에 의존한다는 것을 본다. 그 태스크가 아직 완료되지 않았으면, 에이전트는 시작하지 말아야 한다는 것을 안다. API 에이전트가 완료하고 태스크를 완료로 표시하면, 프론트엔드 에이전트의 종속성이 해제된다.

에이전트 워크플로우는 예측 가능한 루프를 따른다:

# Agent claims the task
bd update bb-profile-api --claim --actor eng1

# Agent comments its plan before writing code
bd comments add bb-profile-api --author eng1 "PLAN:
1. Create route handler at server/routes/profile.ts
2. Add service layer at server/services/profile.ts
3. Return shape: { id, name, avatar, bio, joinedAt }
4. Test: curl localhost:3000/users/1/profile returns 200"

# Agent implements, tests, commits
# ...

# Agent marks done with verification steps
bd comments add bb-profile-api --author eng1 "DONE: Profile endpoint implemented.
Returns { id, name, avatar, bio, joinedAt }.
Verified: curl returns 200 with correct shape.
Commit: abc1234"

bd update bb-profile-api --status ready_for_qa

모든 단계가 기록된다. QA 에이전트는 DONE 코멘트를 읽고 정확히 어떻게 검증할지 안다. 하류 에이전트는 PLAN 코멘트를 읽고 코드가 완성되기 전에 API 계약을 안다.

이것은 프로세스를 위한 오버헤드가 아니다. 다섯 개의 병렬 에이전트가 다섯 개의 호환되지 않는 코드 조각을 생산하는 것을 방지하는 최소한의 구조다.

기본 선택

수개월간 프로덕션 작업에서 병렬 에이전트를 운영한 후, 따르는 결정 트리가 이것이다:

Subagent로 시작하는 경우:

  • 태스크가 리서치 또는 탐색(검색, 읽기, 비교)일 때
  • 결과가 단일 행동으로 수렴해야 할 때
  • 전체 작업이 하나의 컨텍스트 윈도우에 들어갈 때
  • 각 병렬 유닛의 독립적 검증이 불필요할 때

별도 태스크로 전환하는 경우:

  • 작업의 다른 부분이 다른 파일을 건드릴 때
  • 각 조각이 자체 수락 기준을 가질 때
  • QA가 조각을 독립적으로 검증하기를 원할 때
  • 작업이 충분히 길어서 한 조각이 다른 것보다 몇 시간 먼저 끝날 수 있을 때
  • 에이전트가 다른 컨텍스트를 필요로 할 때 (프론트엔드 에이전트에게 데이터베이스 내부 구조는 불필요)

복잡한 feature를 위한 하이브리드 접근: 리서치 및 계획 단계에 subagent를 사용하고(분산, 정보 수집, 계획 종합), 구현을 독립 에이전트용 별도 태스크로 분해한다. Spec-driven development 워크플로우가 여기에 자연스럽게 맞는다: subagent를 가진 단일 에이전트가 spec을 작성하고, spec이 멀티 에이전트 플릿용 태스크로 분해된다.

분할 시각화

다섯 개에서 열 개의 구조화된 태스크에 종속성이 있으면, 터미널에서 진행 상황을 추적하기 어려워진다. bd list는 플랫 리스트를 보여준다. 어떤 태스크가 차단되었는지, 어떤 것이 시작 준비가 되었는지, epic이 얼마나 진행되었는지 보여주지 않는다.

이것이 Beadbox가 해결하는 문제다. 같은 beads 데이터베이스를 읽고 진행 표시기, 종속성 관계, 에이전트 할당이 있는 epic 트리를 렌더링한다. 어떤 서브태스크가 완료되었고, 어떤 것이 전제 조건에 차단되어 있고, 어떤 것이 에이전트가 가져갈 준비가 되었는지 볼 수 있다. --deps으로 지정한 종속성 그래프가 병렬 작업의 시각적 맵이 된다.

에이전트가 태스크를 완료하고 상태를 업데이트하면, Beadbox가 실시간으로 변경을 반영한다. 새로고침 없음, bd list 재실행 없음. 트리가 업데이트되고, 진행 바가 움직이고, 차단된 태스크가 종속성 해결과 함께 차단 해제된다.

같은 데이터. 단지 보이는 것.


이런 워크플로우를 구축하고 있다면, GitHub에서 Beadbox에 스타를 남겨주세요.

Like what you read?

Beadbox is a real-time dashboard for AI agent coordination. Free during the beta.

Share