오픈소스 기여 이야기: oh-my-opencode에 /subagents 명령어를 추가하다

오픈소스 기여 이야기: oh-my-opencode에 /subagents 명령어를 추가하다

오픈소스 기여 이야기: oh-my-opencode에 /subagents 명령어를 추가하다

AI 에이전트 오케스트라를 지휘하는 지휘자 쿼카

안녕하세요, Quokka Labs의 단테입니다.

오늘은 제가 최근 oh-my-opencode 플러그인에 /subagents 명령어를 기여하게 된 과정과, 이 기능이 왜 필요했는지, 그리고 AI 코딩 에이전트의 내부 구조가 어떻게 동작하는지 공유하려고 합니다.

📎 PR 링크: github.com/code-yeongyu/oh-my-opencode/pull/710

🎬 영상으로 보기: OpenCode & oh-my-opencode 소개 및 사용법 (YouTube)

배경: OpenCode와 oh-my-opencode란?

OpenCode

OpenCode는 터미널 기반의 AI 코딩 어시스턴트입니다. GitHub Copilot처럼 AI가 코드 작성을 도와주지만, 터미널(CLI) 환경에서 동작합니다.

┌─────────────────────────────────────────┐
│  $ opencode                             │
│                                         │
│  You: "login.ts의 버그 수정해줘"          │
│                                         │
│  AI: [파일 읽기, 수정 제안]               │
│                                         │
└─────────────────────────────────────────┘

oh-my-opencode

oh-my-opencode는 OpenCode를 확장하는 플러그인입니다:

  • 다양한 특화 AI 에이전트 제공 (oracle, librarian, explore 등)
  • 커스텀 슬래시 명령어 (/init-deep, /refactor, /subagents)
  • 도구 통합 (LSP, AST-Grep 등)

마치 셸의 "oh-my-zsh"처럼, 기본 도구를 강력하게 확장시켜 줍니다.


문제 인식: 왜 /subagents가 필요했나?

Quokka Problem
복잡한 JSON 설정 파일과 씨름하다 지친 쿼카

oh-my-opencode는 여러 개의 **서브에이전트(Subagent)**를 제공합니다. 각 서브에이전트는 특정 작업에 최적화되어 있는데요:

서브에이전트역할
Sisyphus복잡한 작업을 하위 태스크로 분할하여 관리
oracle고급 추론이 필요한 질문에 답변
librarian코드베이스 탐색 및 문서화
explore새로운 코드베이스 분석

문제는, 각 서브에이전트마다 어떤 LLM 모델을 사용할지 설정해야 하는데, 기존에는 이를 위해 JSON 설정 파일을 직접 편집해야 했습니다:

{
  "agents": {
    "oracle": {
      "model": "claude-opus-4-5"
    },
    "Sisyphus": {
      "model": "gpt-5.1-codex"
    }
  }
}

개발자라면 어렵지 않겠지만, 몇 가지 문제가 있었습니다:

  1. 어떤 모델을 사용할 수 있는지 모른다 - 사용 가능한 모델 목록을 알아야 함
  2. 설정 파일 위치를 찾아야 한다 - 전역/프로젝트 설정 경로가 다름
  3. JSON 문법 오류 - 쉼표 하나 빠뜨려도 전체 설정이 깨짐

터미널에서 자연스럽게 대화형으로 서브에이전트 모델을 변경할 수 있다면 훨씬 편할 것 같았습니다.


해결책: /subagents 명령어

Quokka Solution
깔끔한 TUI 인터페이스를 보며 만족스러워하는 쿼카

제가 기여한 /subagents 명령어는 **대화형 TUI(Terminal User Interface)**를 통해 서브에이전트의 모델을 설정합니다.

User: /subagents

╭─────────────────────────────────────────────────╮
│  🤖 Subagent Configuration                      │
│                                                 │
│  Current Assignments:                           │
│  1. Sisyphus     → gpt-5.1-codex               │
│  2. oracle       → claude-opus-4-5              │
│  3. librarian    → haiku-4.5                    │
│  4. explore      → (default)                    │
│                                                 │
│  Enter number to change model (or 'q' to quit) │
╰─────────────────────────────────────────────────╯

사용자가 번호를 입력하면 해당 에이전트에 사용 가능한 모델 목록이 표시됩니다:

User: 2

╭─────────────────────────────────────────────────╮
│  Available models for: oracle                   │
│                                                 │
│  1. claude-opus-4-5                            │
│  2. claude-sonnet-4.5                          │
│  3. gpt-5.1-codex                              │
│  4. haiku-4.5                                  │
│                                                 │
│  Enter number to select model                   │
╰─────────────────────────────────────────────────╯

모델을 선택하면 자동으로 설정 파일이 업데이트됩니다.


구현 과정: 템플릿 기반 명령어 아키텍처

전체 흐름

AI 코딩 에이전트의 명령어가 어떻게 동작하는지 이해하면, 이 기여가 더 흥미롭게 느껴질 겁니다.

┌──────────────────────────────────────────────────────────────────────┐
│                         사용자 입력: /subagents                        │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│                     STEP 1: 명령어 조회                               │
│                                                                       │
│  OpenCode가 "/subagents"를 보고 명령어 레지스트리(commands.ts)에서     │
│  해당 정의를 찾습니다.                                                 │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│                     STEP 2: 템플릿 주입                               │
│                                                                       │
│  subagents.ts의 템플릿이 AI의 "시스템 프롬프트"에 주입됩니다.          │
│  이것이 AI가 따라야 할 지침입니다.                                     │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│                     STEP 3: AI가 템플릿 실행                          │
│                                                                       │
│  AI가 템플릿 지침을 읽고:                                             │
│  - TUI(텍스트 기반 UI) 표시                                           │
│  - 사용자 입력 대기                                                   │
│  - 설정 파일 읽기/쓰기 수행                                           │
└──────────────────────────────────────────────────────────────────────┘

파일별 역할

1. templates/subagents.ts - 두뇌

이 파일은 AI를 위한 지침을 담고 있습니다. 실행되는 코드가 아니라, AI에게 무엇을 할지 알려주는 프롬프트입니다.

export const SUBAGENTS_TEMPLATE = `You are helping the user configure...

## TWO-STEP TUI FLOW

### STEP 1: List Subagents
Display the current subagent configurations...

### STEP 2: Model Selection
When user enters a number, show available models...
`
왜 자연어로 작성했을까요?
  • AI(GPT, Claude 등)는 자연어를 이해합니다
  • 우리는 본질적으로 지침을 통해 AI의 동작을 "프로그래밍"하고 있습니다
  • 이것을 "프롬프트 엔지니어링"이라고 합니다
템플릿의 주요 섹션:
섹션AI에게 전달하는 내용
## CONTEXT서브에이전트에 대한 배경 정보
## STEP 0"먼저 사용자가 어떤 모델을 쓸 수 있는지 확인해"
## STEP 1"이 번호 목록 형식으로 표시해"
## STEP 2"사용자가 번호를 선택하면 모델 목록을 보여줘"
## CRITICAL RULES"입력을 기다려, 자동으로 진행하지 마"

2. commands.ts - 레지스트리

모든 명령어를 등록하여 OpenCode가 인식할 수 있게 합니다.

const BUILTIN_COMMAND_DEFINITIONS = {
  // 다른 명령어들...
  
  subagents: {
    description: "(builtin) Configure subagent-model assignments via interactive TUI",
    template: `<command-instruction>
${SUBAGENTS_TEMPLATE}    // ← 여기에 템플릿 주입
</command-instruction>

<user-request>
$ARGUMENTS              // ← /subagents 뒤의 인자로 대체됨
</user-request>`,
  },
}

3. types.ts - TypeScript 타입 안전성

export type BuiltinCommandName = 
  | "init-deep" 
  | "ralph-loop" 
  | "subagents"   // ← 추가

TypeScript가 유효한 명령어 이름만 사용하는지 컴파일 타임에 검사합니다.

4. config/schema.ts - 런타임 검증

export const BuiltinCommandNameSchema = z.enum([
  "init-deep",
  "start-work",
  "subagents",   // ← 추가
])

사용자 설정 파일의 유효성을 런타임에 검증합니다.


핵심 인사이트: AI를 자연어로 프로그래밍하기

이번 기여에서 가장 흥미로웠던 점은 **"AI를 자연어로 프로그래밍한다"**는 개념입니다.

전통적 코드 vs 템플릿 기반

전통적 코드:                  템플릿 기반:
─────────────────           ───────────────
if (input === "2") {        "When user enters a number,
  showModels(2);             show available models for
}                            that subagent"

AI가 실행자가 된다

AI는 단순히 질문에 답하는 것이 아니라, 템플릿에 정의된 프로그램을 실행합니다:

┌─────────────────────────────────────────────────────────────────────────┐
│ USER                          OPENCODE                        AI        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  /subagents 입력                                                        │
│         ───────────►                                                    │
│                          "subagents" 조회                               │
│                          commands.ts에서                                │
│                                 │                                       │
│                                 ▼                                       │
│                          템플릿 찾음                                     │
│                          프롬프트에 주입                                 │
│                                 │                                       │
│                                 ▼                                       │
│                          AI에게 전송 ────────►  템플릿 수신              │
│                                                                         │
│                                                 지침 해석:              │
│                                                 "Step 0: 사용 가능한    │
│                                                  모델 확인하기"          │
│                                                        │                │
│                                                        ▼                │
│                                                 설정 파일 읽기:         │
│                                                 - opencode.yaml         │
│                                                 - oh-my-opencode.json   │
│                                                        │                │
│                                                        ▼                │
│  TUI 표시:               ◄──────────────────── Step 1 표시:             │
│  ╭─────────────────────╮                       "현재 서브에이전트..."    │
│  │ 🤖 Subagent Config  │                                                │
│  │ 1. Sisyphus         │                                                │
│  │ 2. oracle           │                                                │
│  ╰─────────────────────╯                                                │
│                                                                         │
│  2 입력                                                                 │
│         ───────────────────────────────────►  "2" 확인                  │
│                                               Step 2 실행:              │
│                                               "#2의 모델 표시"          │
│                                                        │                │
│                                                        ▼                │
│  모델 목록 표시:         ◄──────────────────── 모델 표시                 │
│  ╭─────────────────────╮                                                │
│  │ Models for: oracle  │                                                │
│  │ 1. claude-opus-4-5  │                                                │
│  │ 2. gpt-5.1          │                                                │
│  ╰─────────────────────╯                                                │
│                                                                         │
│  1 입력                                                                 │
│         ───────────────────────────────────►  "1" 확인                  │
│                                               Step 3 실행:              │
│                                               "설정 파일 업데이트"       │
│                                                        │                │
│                                                        ▼                │
│                                               파일 쓰기:                │
│                                               oh-my-opencode.json       │
│                                                        │                │
│  완료 토스트:            ◄──────────────────── 성공 메시지 표시          │
│  ╭─────────────────────╮                                                │
│  │ ✅ oracle 업데이트! │                                                │
│  ╰─────────────────────╯                                                │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

오픈소스 기여의 가치

Quokka Contribution
PR 머지 성공을 축하하는 쿼카

개발자로서 얻은 것

  1. 프롬프트 엔지니어링 깊은 이해 - AI를 프로그래밍하는 새로운 패러다임
  2. 실제 프로덕션 코드 경험 - 많은 사용자가 쓰는 도구에 기여
  3. 코드 리뷰 학습 - 메인테이너들의 피드백을 통한 성장

Quokka Labs가 오픈소스에 기여하는 이유

저희 Quokka Labs는 단순히 기술 서비스를 제공하는 것을 넘어, 기술 생태계에 기여하는 것을 중요하게 생각합니다.

  • 실력 증명: 블로그 글만으로는 보여줄 수 없는 실제 구현 능력
  • 최신 기술 선도: AI 코딩 도구의 최전선에서 직접 개발
  • 커뮤니티와 함께 성장: 사용하기만 하는 것이 아니라 돌려주는 것

마무리

/subagents 명령어는 작은 기능일 수 있지만, AI 에이전트의 템플릿 기반 아키텍처를 이해하고 실제로 기여하는 과정은 매우 의미 있는 경험이었습니다.

만약 여러분도 오픈소스 기여에 관심이 있다면, oh-my-opencode같은 프로젝트는 좋은 시작점이 될 수 있습니다. 코드를 작성하지 않더라도, 프롬프트 템플릿을 개선하는 것만으로도 훌륭한 기여가 됩니다.

관련 링크:

요약

구성 요소역할
템플릿 (subagents.ts)AI를 위한 지침 - "무엇을 해야 하는지"
레지스트리 (commands.ts)/subagents → 템플릿 매핑
타입 (types.ts)TypeScript 컴파일 타임 안전성
스키마 (schema.ts)런타임 설정 검증
AI템플릿 지침 실행
설정 파일사용자의 모델 선호도 저장

핵심은 자연어로 AI를 프로그래밍하고, AI가 복잡한 부분(파일 I/O, JSON 파싱, 사용자 상호작용)을 모두 처리한다는 것입니다.

Comments0
No comments yet.

Related Posts