본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 05. 27. 10:50

WezTerm으로 AI 멀티 에이전트 개발 환경을 직접 만든 이야기 — wez-mux의 설계와 구현

요약

WezTerm의 CLI 기능을 활용하여 여러 AI 에이전트를 동시에 기동하고 연계할 수 있는 멀티 에이전트 개발 환경 'wez-mux'의 설계와 구현 과정을 소개합니다. Claude Code와 Codex CLI를 효율적으로 활용하기 위해 터미널 멀티플렉서 위에 오케스트레이션 계층을 구축하는 방법을 다룹니다.

핵심 포인트

  • WezTerm의 강력한 CLI API를 활용한 커스텀 개발 환경 구축
  • Claude Code Agent Teams의 split-pane 모드 한계 극복
  • Go 언어를 이용한 wez-mux의 설계 및 구현 방식
  • 멀티 에이전트 간 역할 분담을 통한 개발 효율성 극대화

서론

주식회사 Funrepeat의 AI 구동 개발 기술 책임자를 맡고 있는 사카모토라고 합니다.

평소에는 Claude Code나 Codex CLI를 활용한 개발을 추진하고 있습니다!

이 기사에서는 WezTerm의 페인(Pane) 기능을 활용하여 여러 AI 에이전트를 동시에 기동·연계시키는 CLI 도구인 wez-mux를 Go로 직접 만든 이야기를 소개합니다.

wez-mux init で4ペインのマルチエージェント環境が立ち上がる様子

2026년에 들어서면서, 필자의 관측 범위 내에서는 Claude Code나 Codex CLI와 같이 터미널 상에서 동작하는 AI 코딩 에이전트를 개발 현장에서 목격할 기회가 늘어났습니다.

단독으로 사용하는 것만으로도 충분히 강력하지만, "명령·구현은 Claude에게, 설계·리뷰는 Codex에게"와 같은 방식으로 역할을 분담한다면 더 효율적이지 않을까?

그렇게 생각하여, 터미널 멀티플렉서(Terminal Multiplexer) 위에 오케스트레이션(Orchestration) 계층을 구축해 보기로 했습니다.

왜 WezTerm인가

Claude Code Agent Teams라는 공식 기능

Claude Code에는 Agent Teams라는 실험적 기능이 있습니다 (2026년 5월 26일 시점에서도 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS를 통한 활성화가 필요한 experimental 취급이며, Claude Code v2.1.32 이후 버전이 필요합니다).

팀 리더가 되는 세션이 여러 개의 테마별 에이전트를 생성하고, 공유 태스크 리스트나 메시징을 통해 협업하는 구조입니다.

하지만 이 Agent Teams의 split-pane 모드(각 에이전트의 페인을 나열하여 볼 수 있는 모드)가 지원되는 것은 2026년 5월 26일 시점에서 tmux와 iTerm2뿐입니다 (공식 문서 기재 사항).

WezTerm을 포함한 다른 터미널 사용자들은 in-process 모드(하나의 터미널 내에서 Shift+Down으로 전환하는 방식)만 사용할 수 있습니다.

그렇게 되면 각 에이전트가 무엇을 하고 있는지 실시간으로 볼 수 없기 때문에, 멀티 에이전트의 묘미가 반감되어 버립니다.

WezTerm의 CLI가 우수함

WezTerm은 GPU 가속(GPU Acceleration)을 지원하는 크로스 플랫폼 터미널 에뮬레이터로, Lua를 통한 높은 확장성을 가지고 있습니다.

그리고 무엇보다, wezterm cli라는 서브 커맨드(Subcommand) 군이 매우 충실합니다.

wezterm cli split-pane — 페인 분할 (방향·크기 지정 가능)
wezterm cli send-text — 임의의 페인에 텍스트 전송
wezterm cli get-text — 페인의 출력 텍스트 취득 (스크롤백 포함)
wezterm cli list — 모든 페인의 목록 취득 (JSON 출력 대응)
wezterm cli kill-pane — 페인 종료

이 정도의 API가 있다면, tmux-bridge와 같은 통신 기반을 WezTerm 상에 구축할 수 있지 않을까 생각했습니다.

애초에 WezTerm을 선택한 가장 큰 이유는 커스터마이징의 높은 자유도입니다.

게다가 페인 간에 메시지를 주고받을 수 있는 API가 WezTerm 자체에 갖춰져 있는데, 굳이 tmux로 옮겨가며 구축하는 것은 어쩐지 아깝다는 생각이 든 것도 직접 만드는 계기가 되었습니다.

smux로부터의 착상

설계의 출발점이 된 것은 smux라는 도구입니다.

smux는 tmux 상에서 동작하는 멀티 에이전트 오케스트레이터로, tmux-bridge라는 통신 기반을 통해 각 페인의 에이전트에 메시지를 송수신하는 구조를 가지고 있습니다.

smux의 설계에서 참고한 점을 몇 가지 꼽겠습니다.

라벨 기반 어드레싱 (Label-based Addressing)

tmux의 페인은 숫자 ID로 관리되지만, smux에서는 codertester와 같은 라벨로 페인을 지정할 수 있습니다.

wez-mux에서도 마찬가지로, 레지스트리 파일(프로젝트 하위의 .wez-mux/registry.json)에서 라벨과 페인 ID의 매핑을 관리합니다.

{
"workspace": "multi-agent",
"cwd": "/home/me/project/my-app",
...

이를 통해 페인 ID(실행할 때마다 바뀌는 수치)를 의식하지 않고 라벨(label)로 메시지를 송수신할 수 있습니다.

# 라벨로 메시지 전송 → 내부적으로 pane_id 13으로 라우팅
wez-mux send worker-top "[task:code-auth-core] 구현해 주세요"
# 라벨로 페인의 출력을 가져옴
...

레지스트리(registry)를 프로젝트 로컬에 두는 방식을 채택했기 때문에, 여러 프로젝트를 병행해서 열고 있어도 라벨 공간이 간섭되지 않습니다.

비동기 메시지 패싱 (Asynchronous Message Passing)

메시지 전송 후 폴링(polling)으로 상대방의 완료를 기다리지 않는다는 설계 방침입니다.

orchestrator가 메시지를 보내면, 이후에는 상대방 에이전트가 작업을 완료한 뒤 orchestrator의 페인(pane)으로 답장을 보냅니다.

이 "던져두기 + 콜백 (fire-and-forget + callback)" 패턴은 터미널 기반의 에이전트 간 통신으로서 자연스러운 형태입니다.

아키텍처 (Architecture)

4개의 에이전트 역할 (Agent Roles)

wez-mux는 하나의 탭 내를 4개의 페인으로 분할하고, 각각에 서로 다른 역할을 가진 AI 에이전트를 배치합니다.

페인런타임 (Runtime)역할
orchestratorClaude Code사령탑. 태스크 관리·디스패치(dispatch)·진척 보고만 수행 (구현·리뷰 금지)
...

역할을 너무 세분화하면 에이전트를 병렬로 구동할 때 레이트 리밋 (rate limit) 측면에서 어려움이 생겼기 때문에, 최종적으로 이 정도의 입도로 결정되었습니다.

Claude와 Codex의 구분 사용에 대해서는, 체감상 코딩 정밀도가 Codex 쪽이 조금 더 높다고 느끼고 있습니다.

따라서 설계 단계에서 Codex (designer)가 본격적으로 만들어 놓은 뒤, 구현은 worker (Claude)에게 병렬로 던지는 구성이 현재로서는 가장 효율적이라고 판단했습니다.

6페인에서 4페인으로 — 단순화를 위한 시행착오

초기에는 analyzer·designer·coder·tester·reviewer와 같이 역할별로 독립된 페인을 가지는 6페인 구성이었으며, 여기에 orchestrator/designer에는 Opus, tester에는 Haiku를 사용하는 등 모델도 세세하게 나누었습니다.

실제로 구동해 보니 다음과 같은 과제들이 보였습니다.

  • 컨텍스트 소비 (Context Consumption) — orchestrator가 중계하는 메시지가 많아, Opus를 사용하더라도 긴 세션에서는 한계에 도달함
  • 과도한 역할 세분화 — analyzer와 designer, coder와 tester는 실질적으로 동일한 에이전트가 이어서 담당해도 문제가 없는 경우가 많음
  • 유휴 페인 발생 — 설계 단계에서는 구현 계열의 3개 페인이 놀고 있어 화면 활용이 비효율적임

그래서 과감하게 정리했습니다.

  • 역할 통합 — analyzer/designer/reviewer는 designer로 통합하여 Codex에게 맡김. coder/tester는 worker로 통합하여 구현과 동시에 테스트도 작성하게 함
  • 모델 지정 폐지model 필드를 config에서 삭제. Claude Code 측은 런타임의 기본값에 맡기고, 에이전트별로 세세하게 모델을 교체하지 않으며, 필요하다면 실행 명령 측에서 조정할 수 있는 여지만 남겨둠
  • worker를 2개 페인으로 준비 — 구현은 병렬화 효과가 가장 높으므로, worker-top / worker-bot 2개의 페인을 나란히 배치하여 2개의 태스크를 동시에 실행할 수 있도록 함
  • Docs as Code — 에이전트 간의 결과 전달을 메시지가 아닌 파일 참조로 변경하여, orchestrator의 컨텍스트 소비를 극적으로 감소시킴 (후술)
  • 자체 관리 — 각 에이전트는 태스크 완료 후 스스로 /clear를 실행하여 컨텍스트를 리셋함 (후술)

결과적으로 페인 수는 줄었지만 오히려 병렬도는 높아졌고, orchestrator의 컨텍스트 소비도 실용적인 범위 내로 들어왔습니다.

페인 레이아웃 (Pane Layout)

┌──────────────┬────────────┬──────────────┐
│              │ worker-top │              │
│ orchestrator ├────────────┤ designer     │
... 

왼쪽에는 orchestrator, 중앙에는 2개의 worker, 오른쪽에는 designer를 배치하고 있습니다.

orchestrator는 사용자가 직접 조작하는 페인(pane)이며, designer는 Codex를 위한 페인입니다.

worker를 세로로 2개의 페인으로 나열함으로써 구현의 병렬성을 확보하는 동시에 화면의 세로 영역을 효율적으로 활용하고 있습니다.

태스크 보드(Task Board)를 통한 병렬 실행

wez-mux의 큰 특징은 파일 기반의 **태스크 보드 (Task Board)**를 통한 병렬 실행 관리입니다.

초기 구현에서는 orchestrator가 직렬적으로 designer → worker 순으로 태스크를 위임하고, 매번 완료를 기다렸습니다.

worker가 2개의 페인을 열고 있음에도 하나씩만 동작하는 것은 비효율적입니다.

그래서 태스크 보드(.wez-mux/board.json)를 도입했습니다.

각 태스크는 ID, 담당자, 상태, 의존 관계를 가지며, 의존 태스크가 모두 완료되면 자동으로 'ready' 상태로 승격됩니다.

# 태스크 생성 (의존 관계 포함)
wez-mux task create --id design-auth --type design --assign designer --desc "인증 모듈 조사+설계+태스크 분해"
wez-mux task create --id code-auth-core --type code --assign worker-top --deps design-auth --desc "인증 코어 구현+테스트"
...

태스크의 의존 관계를 도식화하면 다음과 같습니다.

이를 실행하면 worker-top과 worker-bot이 항상 동시에 가동되는 형태로 병렬 실행됩니다.

실제로 designer의 설계를 받아 orchestrator가 worker로 디스패치(dispatch)하는 모습은 다음과 같이 동작합니다.

designer → orchestrator → worker のディスパッチが流れる様子

Docs as Code — 문서 주도형 통신

에이전트 간의 통신에서 가장 문제가 되는 것이 **컨텍스트 소비 (Context Consumption)**입니다.

조사 결과나 설계 내용을 메시지에 전문(full text)으로 포함하여 보내면, orchestrator의 컨텍스트가 금방 고갈됩니다.

이 문제를 해결하기 위해 Docs as Code 접근 방식을 채택했습니다.

각 에이전트의 성과물은 .wez-mux/docs/ 디렉토리에 Markdown 파일로 저장하며, 에이전트 간에는 문서의 경로(path)만을 주고받습니다.

<project-dir>/
└── .wez-mux/
├── board.json ← 태스크 보드 (상태 관리)
...
# Before: 메시지에 전문을 포함 (컨텍스트 소비 큼)
wez-mux send worker-top "[task:code-auth-core] 설계 결과: {거대한 JSON 전문...}"
# After: 문서 경로만 전달 (컨텍스트 소비 작음)
...

받은 에이전트는 Read 도구를 사용하여 문서를 읽습니다.

이를 통해 orchestrator의 컨텍스트 소비를 극적으로 줄였습니다.

이벤트 주도형 오케스트레이션 (Event-driven Orchestration)

초기 구현에서는 orchestrator가 sleep 120 && wez-mux read worker-top 40과 같은 폴링(polling)을 수행했으나, 이는 직렬적인 동작이 되어버립니다.

AI 에이전트는 방치하면 폴링을 하기 쉬우므로, SKILL.md에 sleep이나 폴링 루프를 절대 금지한다고 명시하고 있습니다.

현재는 완전한 이벤트 주도형입니다.

orchestrator는 ready 태스크를 디스패치하면 즉시 대기 상태로 돌아가며, worker/designer로부터 완료 통지가 도착할 때마다 task ready로 다음 후보를 확인합니다.

능동적으로 상태를 확인하러 가는 것은 '통지를 받은 직후'뿐입니다.

/clear

태스크 완료 후의 자체 이벤트 주도 방식만으로는 컨텍스트 소비를 완전히 억제할 수 없습니다.

worker나 designer는 태스크 하나당 파일 읽기/쓰기 및 코드 생성을 수행하기 때문에, 방치하면 세션 내의 컨텍스트가 점점 비대해집니다.

그래서 태스크 완료 통지를 보낸 후, 스스로 /clear를 실행하여 컨텍스트를 리셋한다는 규칙을 도입했습니다.

/clear

또한 SKILL.md의 시스템 프롬프트(System Prompt)도 휘발되기 때문에, orchestrator가 보내는 dispatch 메시지에는 매번 「완료 시 할 일 목록」을 포함합니다.

[task:code-auth-core] 구현해 주세요. 참조: .wez-mux/docs/design-auth.md
【완료 시 절차】
1. wez-mux doc write code-auth-core --content '<결과>'
...

처음에는 orchestrator가 /clear를 강제로 보내는 방안도 검토했으나, 상대방이 출력 중일 때 에러가 발생하는 등 불안정했기 때문에, 완료 직후 본인이 자발적으로 /clear를 실행하는 방식으로 결정되었습니다.

designer에 의한 조사·설계·리뷰의 일관된 흐름

설계와 분해를 수행한 에이전트가 완성된 결과물의 리뷰까지 담당하는 구성입니다.

구체적으로는 designer (Codex)가 다음 사항을 전담합니다.

설계를 작성한 본인이 리뷰까지 수행함으로써 「설계 의도와의 괴리」를 가장 효율적으로 검출할 수 있습니다.

Claude (orchestrator/worker)와 Codex (designer)로 모델 벤더(Model Vendor)가 나뉘어 있기 때문에, 구현 측과의 관점 차이도 보장할 수 있습니다.

Go를 이용한 구현

기술 스택

  • Go 1.22 — 단일 바이너리 배포가 용이
  • github.com/spf13/cobra — CLI 프레임워크
  • gopkg.in/yaml.v3 — 설정 파일 파싱
  • wezterm cli — WezTerm의 페인(Pane) 조작 API

프로젝트 구성

wez-mux/
├── main.go
├── cmd/ # Cobra 서브 커맨드
...

커맨드 목록

커맨드기능
wez-mux init4페인 분할 + 모든 에이전트 자동 실행
wez-mux send <label> "msg"레이블 지정 메시지 전송 (자동 Enter)
wez-mux read <label> [lines]페인의 출력 취득 (스크롤백 대응)
wez-mux task create/update/list/get/ready/reset태스크 보드 조작
wez-mux doc write/read/path문서 조작
wez-mux list관리 중인 페인 목록
wez-mux statusWezTerm 실제 페인과의 대조를 통한 live status
`wez-mux kill [label--all]`

init의 분할 로직

wez-mux init은 현재 있는 페인을 기점으로, 3번의 페인 분할을 통해 4개의 페인을 만듭니다.

// 1. orchestrator를 기점으로 오른쪽으로 66% 분할 → 오른쪽 절반이 worker-top이 됨
workerTopID, _ := client.SplitPane(orchestratorID, wezterm.SplitPaneOptions{
    Direction: "right", Percent: 66, CWD: cwd,
    ...

먼저 좌우 분할로 영역을 확보한 뒤 세로 분할을 수행합니다.

반대로 하면 No space for split! 에러가 발생했습니다.

init은 추가로 .wez-mux/ 디렉토리 (board.json + registry.json + docs/) 생성, 각 에이전트의 기동, 그리고 syscall.Exec를 통해 자신의 프로세스를 orchestrator의 Claude Code로 교체합니다.

설정 파일과 권한 관리

페인 구성은 YAML로 정의합니다.

permission 필드로 에이전트의 권한 레벨을 제어할 수 있습니다.

workspace: multi-agent
layout:
  rows:
    ...

에이전트별 모델 지정은 런타임(Runtime) 측의 기본값에 맡기고, 설정 파일은 페인 구성과 권한·런타임 종류만을 선언하는 형태로 정리했습니다.

권한(permission) 값Claude CodeCodex CLI용도
auto--permission-mode auto--full-auto기본 자동
bypass--dangerously-skip-permissions--full-auto승인 없이 실행
default플래그 없음플래그 없음필요에 따라 승인을 요청

wez-mux에서는 기본적으로 프로젝트의 리포지토리(Repository) 하위만을 조작 대상으로 삼고 있습니다.

그 전제하에, orchestrator와 worker는 bypass로 설정하여 승인 없이 심리스(Seamless)하게 동작하게 하고, Codex에서 동작하는 designer는 auto로 설정하여 조사·설계·리뷰를 진행하기 쉽게 구성했습니다.

권한 관련 플래그는 CLI 측의 사양 변경에 영향을 받기 쉬우므로, 위 설정은 2026년 5월 26일 시점에 필자가 검증한 설정입니다.

SKILL.md — 에이전트의 역할(Role) 정의

각 에이전트의 역할은 SKILL.md에서 정의합니다.

예를 들어 worker의 역할 정의에는 Spec-Driven 테이블 주도 테스트(Table-Driven Test) 패턴을 포함하고 있습니다.

skill을 사용하여 프로젝트를 진행하기 용이한 구현 패턴 등을 정의해 두면, 이를 읽어 들여 작업을 진행하도록 했습니다.

orchestrator의 SKILL.md에는 폴링(Polling) 방지를 위한 절대 금지 사항을 명시하고 있습니다.

sleep 사용, wez-mux read를 통한 폴링, 루프를 통한 대기, 나아가 직접 코드를 작성하거나 조사, 리뷰하는 것도 모두 금지하여, 순수하게 디스패치(Dispatch)와 진척 관리만을 담당하도록 제약을 걸었습니다.

향후 전망

macOS 대응 및 배포

현재 구현은 WSL (Windows) 환경에 최적화되어 있으며, 앞서 언급한 바와 같이 wezterm.exe 호출이나 WEZTERM_PANE 부재 시의 폴백(Fallback) 처리 등 Windows 유래의 특성을 흡수하는 코드가 곳곳에 포함되어 있습니다.

반면 macOS 상의 WezTerm에서 그대로 동작할지는 미검증 상태이며, 아마도 세밀한 수정이 필요할 것입니다.

향후에는 macOS에서도 동작하도록 정비하여 배포 가능한 상태로 만드는 것을 목표로 하고 있습니다.

  • wezterm 바이너리 해결의 범용화wezterm / wezterm.exe의 탐색 순서를 정리하고, macOS의 표준 경로 및 Homebrew 경로도 폴백에 포함
  • 플랫폼 계층의 분리 — WSL 고유 처리를 internal/platform/ 상당으로 분리하여, macOS에서는 그대로 통과
  • 배포 형태 정비go install 대응, Homebrew tap, 셸(Shell) 보완(Completion) 생성, CI에서의 릴리스 빌드
  • 셋업 문서 — macOS / WSL 각각의 최초 셋업 절차를 README에 정리

기타 기능 개선

  • 동적 역할 선택 및 페인(Pane) 추가 — 현재는 init 시에 4개의 페인을 고정으로 띄우는 방식이지만, orchestrator가 태스크 내용에 따라 필요한 역할을 자동으로 선택하고, 부족할 경우 페인을 동적으로 추가하는 방향으로 진화시키고 싶습니다.

아이디어의 원천은 macOS를 대상으로 앞서 나가고 있는 Maestri이며, 실제로 사용해 보니 에이전트 간을 선으로 연결하여 PTY를 통해 대화하게 하는 경험이 wez-mux의 동작과 상당히 유사하게 느껴졌습니다.

Maestri는 GUI 중심이지만, wez-mux는 마우스 조작을 최대한 배제하고 CLI만으로 완결하는 것을 축으로 삼아, 유사한 경험을 터미널 상에서 구현하는 것이 목표입니다.

  • 워크플로우 템플릿 — 자주 발생하는 패턴(버그 수정, 기능 추가, 리팩터링)의 태스크 분해 템플릿
  • 메시지 로그 — 에이전트 간의 모든 메시지를 파일로 저장
  • Web 대시보드 — 태스크 보드의 상태를 브라우저에서 시각화

요약

WezTerm의 페인 기능과 CLI API를 활용함으로써, tmux에 의존하지 않고 멀티 에이전트 개발 환경을 구축할 수 있었습니다.

Go로 싱글 바이너리(Single Binary)화 함으로써, wez-mux init 한 번으로 4개의 AI 에이전트가 실행되는 환경을 손에 넣을 수 있습니다.

개발을 진행하는 과정에서 컨텍스트 소비(Context Consumption), 폴링(Polling) 문제, 권한 관리(Permission Management), worker로의 태스크 분담 등 많은 과제에 직면했습니다.

역할 통합을 통한 4페인(4-pane)화, 태스크 보드(Task Board)를 통한 병렬 실행, Docs as Code를 통한 컨텍스트 절약, 이벤트 드리븐(Event-driven) + 자체 /clear 명령어, 그리고 config 기반의 권한 관리와 같은 해결책들은 모두 실제로 구동하며 문제에 부딪힌 후에 탄생한 것들입니다.

끝까지 읽어주셔서 감사합니다.

주식회사 Funrepeat에서는 함께 일할 동료를 모집하고 있습니다.

저희 회사는 AI 구동 개발(AI-driven development) 및 Microsoft 계열(Power Platform / Copilot Studio 등) 프로젝트에서 다수의 개발 실적을 보유하고 있습니다. 업무 상담이나 의뢰도 편하게 문의해 주세요.

참고

  • smux (ShawnPana/smux) — tmux 기반의 멀티 에이전트 오케스트레이터
  • Maestri — macOS용 AI 에이전트 오케스트레이션 캔버스
  • WezTerm CLI 문서
  • Claude Code Agent Teams
  • spf13/cobra — Go CLI 프레임워크

Discussion

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0