본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 22. 21:30

HagiCode가 13개의 에이전트 CLI 도구를 단일 시스템에 통합하는 방법

요약

HagiCode는 Claude Code, Codex, Copilot 등 다양한 Agent CLI 도구들을 단일 시스템에서 통합 관리할 수 있는 플랫폼입니다. 계층형 아키텍처와 추상화 계층을 도입하여 새로운 도구의 플러그인 확장이 용이하도록 설계되었습니다.

핵심 포인트

  • 다양한 Agent CLI를 통합하는 계층형 아키텍처 설계
  • 비즈니스 로직과 특정 CLI 간의 얇은 추상화 계층 구축
  • 새로운 도구 추가 시 유지보수성을 높이는 플러그인 방식 채택
  • 13개의 주요 AI 에이전트 도구 지원

HagiCode가 13개 에이전트 CLI 도구를 단일 시스템에 통합하는 방법

솔직히 말해서, 어렵지도 않고 간단하지도 않습니다. 저희는 계층형 아키텍처(layered architecture)를 사용하여 Claude Code, Codex, Copilot, Gemini와 같은 다양한 Agent CLI들을 통일적으로 관리하고—언제든지 새로운 도구를 플러그인할 수 있는 방법을 논해보겠습니다.

배경 (Background)

이 이야기는 골치 아픈 문제에서 시작되었습니다.

최근 몇 년 동안 에이전트 CLI들이 싹처럼 많이 생겨났습니다. Claude Code, OpenAI Codex, GitHub Copilot, Gemini CLI, Kimi, Qoder, Kiro 등 매달마다 새로운 것이 하나씩 나옵니다. 사용자들에게 “HagiCode를 하나 설치하고 모든 Agent의 전체 기능을 사용하게” 하고자 하는 프로젝트였기 때문에, 저희는 단 하나의 CLI에만 의존할 수 없었습니다. 하지만 또한 각 CLI별로 설치, 상태 확인(health checks), 스케줄링을 다루는 완전한 로직 세트를 작성하는 것도 불가능했습니다. 코드가 너무 부풀어 올라서 아무도 건드리기 두려워하는 엉킨 실타래처럼 유지보수가 불가능해질 것이기 때문입니다.

더 골치 아픈 것은, 이 CLI들이 각자 완전히 다른 특성을 가지고 있다는 점이었습니다. 어떤 것은 stdio를 사용하고, 어떤 것은 gRPC를 사용하며, 어떤 것은 단순히 셸 진입점(shell entry point)만 제공합니다. 그리고 스트리밍 출력 형식은 각각 고유한 언어를 구사합니다. 만약 저희가 비즈니스 코드에 if (provider == ClaudeCode)와 같은 판단문을 직접 작성한다면, 6개월 안에 아무도 건드리기 두려워하는 “레거시 코드(legacy code)” 더미가 되어버릴 것입니다. 결국 누가 무너져 내릴 것 같은 벽돌을 만지고 싶겠습니까?

이 모든 문제점들을 해결하기 위해 저희는 결정을 내렸습니다: 비즈니스 계층과 특정 CLI 사이에 얇은 추상화 계층(thin abstraction layer)과 공유 런타임(shared runtime)을 추가하는 것입니다. 이는 간단해 보이지만, HagiCode가 새로운 CLI를 얼마나 빠르게 통합할 수 있는지를 직접적으로 결정합니다. 곧 구체적인 내용을 설명드리겠습니다.

HagiCode 소개 (About HagiCode)

여기서 공유되는 해결책은 저희의 HagiCode 프로젝트 실습을 통해 나온 것입니다. HagiCode는 매우 순수한 목표를 가진 AI 코드 어시스턴트 통합 플랫폼입니다. 즉, 하나의 설치와 하나의 설정을 사용하여 사용자에게 모든 주류 Agent CLI들을 제공하는 것입니다.

사실 그 답은 창밖의 대나무 그림자처럼 AIProviderType 열거형 (enum) 안에 숨겨져 있습니다. 마음만 먹고 찾아본다면 바로 볼 수 있죠. 원래의 정의는 다음과 같습니다:

public enum AIProviderType
{
    ClaudeCodeCli = 0,
...

이 열거형에는 총 14개의 값이 있지만, IFlowCli=5 경로는 이제 차단되었습니다. AIProviderFactory에서 명시적으로 제외되어 있습니다:

if (providerType == AIProviderType.IFlowCli)
{
    throw new NotSupportedException("IFlowCli is no longer supported");
...

IsActivelySupportedProviderType()를 통한 필터링과 결합하면, 시스템에서 실제로 "살아있는" 것은 13개입니다: Claude Code, Codex, GitHub Copilot, CodeBuddy, OpenCode, Hermes, Qoder, Kiro, Kimi, Gemini, DeepAgents, Reasonix, Pi.

이것이 "13"이라는 숫자가 나온 이유입니다. 마케팅용 숫자가 아니라, 코드에서 직접 계산한 결과입니다. 결국 숫자는 거짓말을 하지 않습니다. 거짓말을 하는 건 우리뿐이죠.

계층형 아키텍처 (Layered Architecture): 변경 사항 제어

13개의 CLI를 연결하는 핵심 아이디어는 단 한 문장으로 요약됩니다: 비즈니스 로직이 호출하는 특정 CLI가 무엇인지 신경 쓰지 않게 만드는 것입니다.

우리는 이를 위에서 아래로 내려다보며 6개의 계층으로 나누었습니다:

1. 식별 계층 (Identity Layer) — AIProviderType

열거형 (enum)은 각 CLI의 "ID 번호"입니다. CLI가 언급되는 모든 곳에서 이 열거형 값이 해당 CLI를 식별합니다. 문자열 (String)과 열거형은 ToStringValue() / ToAIProviderType()을 통해 서로 변환됩니다. 단순하지만 필수적입니다.

2. 비즈니스 계약 계층 (Business Contract Layer) — IAIProvider / IAIProviderFactory

비즈니스 측면에서는 "프롬프트를 보내고 스트리밍 응답을 받는다"와 같은 보편적인 동작을 정의하는 IAIProvider 인터페이스 (interface)만을 인식합니다. 그 밑단에 있는 것이 Claude인지 Codex인지는 비즈니스 로직에서 중요하지 않습니다. 편지를 보내는 것과 같습니다. 편지를 건네주기만 하면 되지, 집배원의 성이 무엇인지는 누가 신경 쓰겠습니까?

3. 어댑터 계층 (Adapter Layer) — *CliProvider

3. 어댑터 계층 (Adapter Layer) — *CliProvider

각 CLI는 PiCliProvider, ReasonixCliProvider, ClaudeCodeCliProvider와 같은 얇은(thin) 어댑터를 가집니다. 이 어댑터들은 할 일이 매우 적습니다. 범용 비즈니스 요청을 특정 CLI가 이해할 수 있는 매개변수로 번역하고, 다시 특정 CLI의 출력을 번역하는 것입니다. 의도적으로 얇게 작성되었기 때문에 새로운 CLI를 추가한다는 것은 기본적으로 기존 것을 복사하여 수정하는 것만 의미합니다.

4. 공유 런타임 계층 (Shared Runtime Layer) — ICliProvider<TOptions>

이 계층은 HagiCode.Libs에 존재하며 실제 핵심 작업을 수행합니다. 크로스 플랫폼으로 프로세스를 실행하고, stdio 전송을 처리하며, 스트리밍 출력을 파싱하고, 타임아웃 및 재시도를 처리하는 것입니다. 모든 어댑터가 동일한 런타임을 재사용하기 때문에 새로운 CLI를 온보딩할 때 프로세스 관리를 기본적으로 다시 작성할 필요가 없습니다.

비유를 들자면: 어댑터 계층은 '통역사'이고, 공유 런타임 계층은 '배송 회사'입니다. 통역사는 메시지가 명확하도록 만드는 역할만 합니다. 소포가 어떻게 배달되는지, 길에 교통 체증이 있는지 여부는 배송 회사의 문제입니다. 각자 자신의 역할을 수행하며 세상은 평화롭습니다.

5. 팩토리 라우팅 계층 (Factory Routing Layer) — AIProviderFactory

CreateProvider 내부에서, switch 문을 통해 AIProviderType에 기반하여 해당 어댑터를 인스턴스화하고, 그 과정에서 IsConfigured를 검증합니다. 이곳만이 '구체적인 타입(concrete types)'을 아는 유일한 장소이며, 팩토리 내부에 엄격하게 격리되어 있습니다. 변경은 오직 한 구석에서만 허용되며, 다른 모든 곳은 깨끗하게 유지됩니다.

6. 디렉터리 / UI 투영 계층 (Directory / UI Projection Layer) — main-professions.yaml

이 계층은 흥미로운데, 코드가 아니라 데이터입니다.

주요 직업 목록(예:

참고로, 이것이 HagiCode에서 가장 큰 리팩토링(refactor)입니다. 초기 버전에는 AgentCliInstallRegistry라는 코드에 내장된 레지스트리가 있었습니다. 나중에 유지보수 비용이 너무 높다는 것—더 많은 코드, 더 지친 사람들—을 발견하여 전체를 해체하고 데이터 기반 + 상태 모니터링 접근 방식으로 대체했습니다. 이것이 HagiCode가 이제 전문 직업 유형을 신속하게 확장할 수 있는 이유이기도 합니다.

설치 문제 해결 방법

13개의 CLI 모두 설치가 필요하며, 각각 다른 공식 설치 방법을 가지고 있습니다—이것은 또 하나의 산입니다.

저희의 접근 방식은 **Docker Compose 사전 설치 + 외부 관리 폴백(fallback)**입니다. Docker 이미지가 주요 CLI들(Claude Code, Codex, Copilot, CodeBuddy, OpenCode, Qoder, Kiro, Kimi, Gemini, Pi)을 미리 설치하므로, 사용자는 이미지를 당겨와서 사용하기만 하면 됩니다—하나씩 명령어를 입력할 필요가 없습니다. 그리고 당연히 더 좋은 기분으로 설치됩니다.

로컬 환경에서 별도의 설치가 필요한 경우, 설치 명령어 매트릭스는 대략 다음과 같습니다 (공식 문서를 기반으로 검증됨):

CLI공식 설치 방법
Claude Codenpm install -g @anthropic-ai/claude-code
...
프론트엔드 {% raw %}PrimaryProfessionCard.tsx도 그에 맞춰 변경되었습니다—이제 **
  1. AIProviderType에 enum 값 추가
  2. 기존의 *CliProvider를 복사하여 새로운 CLI의 파라미터 및 출력 파싱(output parsing)에 맞게 수정
  3. AIProviderFactoryswitch 문에 라우팅 라인 추가
  4. 기본 직업(primary profession) 디렉토리에 진입하는 경우, main-professions.yaml에서 이를 설정
  5. 이미지에 설치 명령어를 추가 (또는 외부 관리 방식으로 전환)

이 전체 과정을 통해 핵심 변경 사항은 200줄의 코드를 넘지 않습니다. 이것이 바로 이 추상화(abstraction)의 진정한 가치입니다. CLI가 추가될 때마다 발생하는 한계 비용(marginal cost)은 매우 낮으며, 비즈니스 로직(business code)은 단 한 줄도 수정할 필요가 없습니다. 모든 길은 로마로 통하지만, 우리의 길은 조금 더 걷기 편할 뿐입니다.

요약 (Summary)

돌이켜보면 "13개의 CLI를 통합한다"는 말은 위협적으로 들릴 수 있지만, 세분화해 보면 실제로는 두 가지 계층의 작업으로 나뉩니다.

한 계층은 AIProviderType enum + IAIProvider 계약(contract) + 얇은 어댑터(thin adapters) + 공유 런타임(shared runtime)을 통해 **변경 사항을 격리(isolating change)**하여, 비즈니스 로직을 특정 CLI로부터 분리하는 것입니다. 다른 한 계층은 main-professions.yaml과 같은 YAML 프리셋을 사용하여 디렉토리와 UI를 구동함으로써 **설정의 데이터화(data-ifying configuration)**를 구현하여, 새로운 항목이 추가될 때마다 코드를 수정해야 하는 상황을 방지하는 것입니다.

이 솔루션은 우리가 시행착오를 겪고 실제 HagiCode 개발 과정에서 몇 차례 반복(iteration)을 거친 끝에 안정화된 결과물입니다. 만약 여러분이 유사한 "멀티 프로바이더 통합(multi-provider integration)" 시스템을 구축하고 있다면, 이 계층화된 접근 방식이 참고가 되기를 바랍니다. 결국, 향후 몇 년 동안 에이전트 CLI(Agent CLIs)는 계속해서 쏟아져 나올 것입니다. 따라서 "현재 얼마나 많은 CLI를 지원하는가"보다 "새로운 CLI를 얼마나 빠르게 통합할 수 있는 아키텍처인가"가 훨씬 더 중요합니다.

원문 및 라이선스 (Original Article & License)

읽어주셔서 감사합니다. 이 글이 도움이 되었다면 좋아요, 북마크 또는 공유를 고려해 주세요.
이 글은 AI의 도움을 받아 작성되었으며, 출판 전 저자의 검토를 거쳤습니다.

AI 자동 생성 콘텐츠

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

원문 바로가기
0

댓글

0