AI 개발 오케스트라 — Claude가 설계하고, Codex가 구현하고, Gemini가 문서화한다

이경규·5일 전

AI 개발 오케스트라 — Claude가 설계하고, Codex가 구현하고, Gemini가 문서화한다

JSON·A2A·MCP부터 Figma 디자인 검증, GitHub PR, TestFlight·App Store 자동 배포까지 하나로 연결하는 AI 개발 환경

2026년 10월 29일 기준

AI 코딩 도구를 하나만 사용해도 상당히 많은 작업을 할 수 있다.

Codex에 기능 개발을 맡기면 프로젝트를 분석하고 코드를 수정한다. Claude Code에 아키텍처를 검토해 달라고 하면 기존 구조의 문제를 찾아준다. Gemini CLI를 이용하면 변경된 내용을 한국어 기술 문서로 정리할 수도 있다.

그런데 실제 개발에서는 조금 다른 문제가 생긴다.

Claude가 계획한 내용을 Codex에 다시 설명해야 한다. Codex가 수정한 코드를 Claude에게 검토받기 위해 또 전달해야 한다. 마지막에는 Gemini에게 무엇이 바뀌었는지 처음부터 설명한다.

각 도구는 뛰어나지만, 세 도구를 번갈아 사용하는 것만으로는 개발 과정이 자동화되지 않는다.

오히려 같은 코드를 여러 번 분석하면서 컨텍스트와 토큰이 낭비될 수 있다.

그리고 여기에는 더 중요한 문제가 있다.

누가 코드를 수정할 수 있는지, 누가 테스트를 확인하는지, 누가 최종 승인하는지가 명확하지 않다면 AI가 늘어날수록 관리해야 할 위험도 커진다.

그래서 필요한 것이 **AI 개발 오케스트라(Development Orchestra)**다.

오케스트라의 핵심은 여러 AI를 동시에 실행하는 것이 아니다.

서로 다른 역할을 맡기고, 구조화된 작업 결과를 전달하고, 검증을 거쳐 하나의 제품을 완성하는 것이다.

이번에 구성할 개발팀은 세 가지 AI를 사용한다.

  • Claude Code: 요구사항 분석, 아키텍처 설계, 위험 판단, 독립 코드 리뷰
  • Codex: 실제 코딩, 파일 수정, 테스트, 버그 수정, Git 커밋과 PR 생성
  • Gemini CLI: 한국어·영문 기술 문서, API 문서, README, 변경 이력 정리

디자인은 Claude의 디자인 기능 또는 디자이너가 제공한 Figma를 사용한다.

구현 후에는 iOS Simulator에서 실제 화면을 실행한다. 단순히 스크린샷이 비슷한지 보는 것이 아니라 버튼의 위치, 크기, 간격, 색상, 폰트까지 수치로 비교한다.

마지막에는 GitHub Actions를 이용해 빌드와 테스트를 검증하고 TestFlight까지 자동 업로드한다.

App Store 배포는 최종적으로 사람이 승인하도록 한다.

목표는 AI 세 개를 연결하는 것이 아니라, 기획부터 스토어 업로드까지 실제로 운영할 수 있는 개발 파이프라인을 만드는 것이다.


1. AI 세 개를 번갈아 쓰는 것과 오케스트라는 다르다

일반적으로 여러 AI를 사용하는 개발자는 다음과 같은 방식으로 작업한다.

개발자
   ↓
Claude에게 설계 요청
   ↓
결과 복사
   ↓
Codex에게 구현 요청
   ↓
변경 내용 복사
   ↓
Claude에게 코드 리뷰 요청
   ↓
수정 내용 전달
   ↓
Gemini에게 문서 작성 요청

문제는 같은 정보를 계속 전달한다는 점이다.

프로젝트 구조와 기존 설계, 변경 대상 파일 등을 여러 AI가 반복해서 읽는다.

또 AI가 작성한 긴 설명이 다음 AI의 컨텍스트로 들어가면서 불필요한 정보가 쌓인다.

작업이 길어질수록 다음 문제가 나타날 수 있다.

  • 에이전트마다 서로 다른 프로젝트 상태를 기준으로 작업
  • 이전에 승인한 설계가 다음 작업에 반영되지 않음
  • 테스트를 실행하지 않았는데 완료했다고 보고
  • 구현한 AI가 자신의 코드를 직접 검토하고 승인
  • 리뷰와 재수정이 끝없이 반복
  • 여러 AI가 동일한 파일을 동시에 수정

오케스트라는 이런 문제를 줄이기 위해 작업 흐름을 고정한다.

요구사항
    ↓
Claude — 계획
    ↓
개발자 — 계획 승인
    ↓
Codex — 구현
    ↓
빌드 및 테스트
    ↓
Claude — 독립 리뷰
    ↓
Codex — 제한된 수정
    ↓
디자인 QA
    ↓
Gemini — 문서
    ↓
GitHub PR
    ↓
개발자 승인
    ↓
CI/CD

중요한 점은 각 단계의 입력과 출력이 명확해야 한다는 것이다.

Claude가 계획한 결과는 파일로 저장한다.

Codex는 승인된 계획만 읽는다.

Claude는 Codex의 전체 대화를 읽는 대신 Git Diff와 테스트 결과를 확인한다.

Gemini는 최종 확정된 코드와 변경 내역만 받아 문서를 작성한다.

이렇게 하면 세 AI가 같은 이야기를 반복할 필요가 줄어든다.


2. Claude·Codex·Gemini 역할을 고정한다

이번 오케스트라에서는 각 모델의 역할을 명확하게 구분한다.

역할담당주요 작업제한
PlannerClaude Code분석·설계·계획코드 수정 금지
ImplementerCodex코드 작성·수정승인 범위 밖 변경 금지
TesterCodex + CI빌드·테스트실패 무시 금지
ReviewerClaude CodeDiff·설계·보안 검토코드 직접 수정 금지
FixerCodex리뷰 지적사항 수정무관한 리팩터링 금지
DocumenterGemini CLI한국어·영문 문서앱 소스 수정 금지
Final Approver개발자PR·디자인·배포 승인AI에 최종 권한 위임 금지

이 역할은 각 모델의 절대적인 성능 순위를 의미하지 않는다.

Claude가 모든 설계에서 가장 뛰어나고, Codex가 모든 코딩에서 가장 빠르며, Gemini가 항상 한국어를 가장 잘 작성한다는 주장은 아니다.

이번 개발 환경에서 그렇게 역할을 배분하는 것이다.

실제 프로젝트에서 평가한 결과에 따라 모델을 교체할 수도 있다.

Claude는 왜 설계와 리뷰를 맡을까?

설계 단계에서는 코드를 빠르게 작성하는 것보다 무엇을 변경해야 하는지 판단하는 것이 중요하다.

요구사항을 분석하고 기존 아키텍처와 충돌하는 부분을 찾는다.

또 구현 결과를 기존 설계와 비교하는 독립 리뷰를 담당한다.

여기서 중요한 것은 설계와 리뷰를 같은 대화에 계속 누적하지 않는 것이다.

Claude Reviewer는 Implementer의 상세한 추론 과정보다 승인된 계획과 실제 변경 내용을 기준으로 검토해야 한다.

Codex는 왜 실제 구현을 맡을까?

Codex는 파일 변경과 테스트 실행을 중심으로 사용한다.

SwiftUI 화면 구현, 네트워크 로직 수정, 테스트 작성, 반복적인 코드 정리 같은 작업을 담당한다.

계획을 변경해야 할 만큼 큰 문제가 발견되면 독단적으로 아키텍처를 바꾸지 않고 Claude Planner 또는 개발자에게 다시 전달한다.

Gemini는 왜 문서 전담으로 둘까?

코드 구현과 문서 작성을 분리하기 위해서다.

개발이 끝난 뒤 새로운 기능과 변경 내용을 한국어로 정리하고, 필요한 경우 영문 API 문서나 팀 공유 문서로 변환한다.

문서의 정확성을 유지하려면 실제 코드에 존재하지 않는 기능을 만들어내지 않도록 해야 한다.

따라서 Gemini에는 최종 승인된 변경사항만 전달한다.


3. MCP·A2A·Plugin·Skill은 어떻게 다를까?

오케스트라를 구성하려면 먼저 용어를 구분해야 한다.

여러 기능이 모두 AI를 연결하는 기술처럼 보이지만 실제 역할은 다르다.

기술역할
MCP에이전트가 외부 도구와 데이터에 접근
A2A독립적인 에이전트 간 작업과 결과 전달
Plugin기능과 도구를 배포·설치하는 패키지
Skill특정 작업을 수행하는 절차와 지침
Hook실행 전후 등 지정된 시점에 동작
Subagent상위 에이전트에서 위임받은 작업 수행
Orchestrator역할·상태·권한·재시도·결과 관리

MCP는 주로 도구 연결에 사용한다.

Claude Code
     ↓
Figma MCP
     ↓
디자인 데이터
Codex
     ↓
GitHub MCP
     ↓
Repository / Pull Request

A2A는 서로 독립적인 에이전트가 작업을 교환하기 위한 프로토콜이다.

Orchestrator
      ↓
A2A Task
      ↓
Remote Agent
      ↓
Artifact / Result

하지만 세 가지 AI CLI를 연결하기 위해 반드시 A2A 서버를 구축해야 하는 것은 아니다.

같은 컴퓨터에서 순차적으로 실행한다면 CLI와 JSON 파일만으로도 충분할 수 있다.

A2A는 여러 컴퓨터나 독립적인 Agent Server로 확장할 때 선택하는 것이 현실적이다.


4. 개발 환경 준비 — macOS를 기준으로 시작한다

이번 실습은 macOS와 SwiftUI 프로젝트를 기준으로 한다.

필요한 도구는 다음과 같다.

macOS

Xcode

Git

Node.js

Python 3

Claude Code

Codex CLI

Gemini CLI

GitHub CLI

GitHub Actions

세 가지 AI CLI는 각각 인증이 필요하다.

구독형 사용과 API 키를 직접 사용하는 방식은 요금 체계가 다를 수 있으므로 따로 확인해야 한다.

Codex CLI 설치

npm install -g @openai/codex
codex --version
codex login

Claude Code 설치

Claude Code는 공식 설치 스크립트 또는 지원되는 패키지 관리자를 통해 설치한다.

macOS·Linux에서 공식 설치 스크립트를 사용하는 예는 다음과 같다.

curl -fsSL https://claude.ai/install.sh | bash

설치 후 실행한다.

claude --version
claude

Gemini CLI 설치

npm install -g @google/gemini-cli
gemini --version
gemini

GitHub CLI

macOS에서 Homebrew를 사용한다면 다음과 같이 설치한다.

brew install gh
gh auth login

기본 개발 도구를 확인한다.

git --version
python3 --version
node --version
xcodebuild -version

설치 명령은 사용 중인 운영체제와 공식 배포 방식에 따라 달라질 수 있다.

특히 조직에서 관리하는 개발 장비에서는 승인된 설치 방식과 인증 정책을 사용해야 한다.


5. 프로젝트 공통 규칙을 만든다

각 AI가 서로 다른 규칙을 사용하면 오케스트라의 의미가 줄어든다.

먼저 프로젝트의 공통 규칙을 한곳에 정리한다.

예를 들어 다음과 같이 구성할 수 있다.

my-ios-app/
│
├── CLAUDE.md
├── AGENTS.md
├── GEMINI.md
│
├── .ai/
│   ├── context/
│   │   ├── architecture.md
│   │   ├── coding-rules.md
│   │   └── design-rules.md
│   │
│   ├── policies/
│   │   ├── protected-files.json
│   │   └── stop-conditions.json
│   │
│   ├── tasks/
│   └── orchestrator/
│
├── Sources/
├── Tests/
├── docs/
└── .github/workflows/

.ai/는 이번 오케스트라에서 사용하는 사용자 정의 폴더다.

Claude Code나 Codex, Gemini CLI가 이 폴더의 모든 파일을 자동으로 읽는다는 뜻은 아니다.

Orchestrator가 필요한 파일을 선택해 전달하도록 구성한다.

공통 코딩 규칙

예를 들어 .ai/context/coding-rules.md에 다음 내용을 저장한다.

# Project Coding Rules

- Swift 6 기준으로 작성한다.
- iOS Deployment Target을 유지한다.
- SwiftUI를 기본 UI 프레임워크로 사용한다.
- 기존 Public API를 임의로 변경하지 않는다.
- 외부 Dependency는 승인 없이 추가하지 않는다.
- 요구사항과 무관한 파일을 수정하지 않는다.
- 변경 후 관련 테스트를 실행한다.
- 테스트하지 않은 내용을 완료했다고 보고하지 않는다.
- 비밀정보를 소스 코드에 포함하지 않는다.

Claude에는 계획과 리뷰 지침을, Codex에는 구현 범위와 테스트 지침을, Gemini에는 문서 작성 규칙을 추가한다.

중요한 것은 공통 규칙과 역할별 규칙을 분리하는 것이다.


6. AI끼리 긴 대화를 하지 않는다 — JSON이 필요한 이유

여러 AI를 연결할 때 가장 쉽게 발생하는 낭비는 컨텍스트 중복이다.

예를 들어 Claude가 5,000자짜리 계획을 작성했다고 생각해보자.

Codex에 그 계획 전체를 전달한다.

Codex는 작업 결과를 8,000자짜리 설명으로 반환한다.

다시 Claude에게 전체 설명과 기존 계획을 전달한다.

이런 방식이 반복되면 토큰 사용량이 계속 증가할 수 있다.

따라서 이번 오케스트라에서는 AI 간 작업 전달에 JSON 계약을 사용한다.

단, JSON 형식 자체가 반드시 토큰을 절약해주는 것은 아니다.

필드가 지나치게 많거나 설명을 그대로 넣으면 오히려 길어질 수 있다.

핵심은 짧은 구조화 데이터와 파일 참조를 사용하는 것이다.

긴 자연어 설명
       ↓
작업에 필요한 필드만 선택
       ↓
JSON
       ↓
다음 Agent

그리고 실제 코드를 JSON에 전부 포함하지 않는다.

코드는 Repository에 이미 존재한다.

따라서 파일 경로와 Git 커밋, Diff를 참조하면 된다.


7. Claude가 Codex에 전달하는 JSON

예를 들어 SwiftUI 검색 화면에 취소 관련 버그가 있다고 생각해보자.

Claude가 수정 계획을 작성하고 다음 JSON을 저장한다.

.ai/tasks/IOS-102/plan.json

{
  "schema_version": 1,
  "task_id": "IOS-102",
  "role": "implementer",
  "objective": "Fix search cancellation race",
  "base_commit": "abc1234",
  "allowed_files": [
    "Sources/Search/SearchViewModel.swift",
    "Tests/SearchViewModelTests.swift"
  ],
  "constraints": [
    "Do not change public APIs",
    "Do not add dependencies",
    "Ignore stale request results"
  ],
  "acceptance": [
    "Build succeeds",
    "Cancellation tests pass",
    "Existing tests pass"
  ],
  "max_retries": 2
}

Codex는 이 작업 지시만 읽고 구현을 시작한다.

여기서 중요한 필드는 allowed_files다.

AI가 요청한 범위 밖의 파일을 수정하지 않도록 제한한다.

다만 프롬프트에 제한을 적는 것만으로 파일 수정 권한이 강제되지는 않는다.

실제 파일 변경 후 허용 목록과 비교하는 검사가 필요하다.

예를 들어 Python에서 다음처럼 검사할 수 있다.

import json
import subprocess
from pathlib import Path

plan = json.loads(
    Path(".ai/tasks/IOS-102/plan.json").read_text()
)

changed = subprocess.check_output(
    ["git", "diff", "--name-only"],
    text=True
).splitlines()

allowed = set(plan["allowed_files"])
unexpected = set(changed) - allowed

if unexpected:
    raise RuntimeError(
        f"Unexpected changes: {sorted(unexpected)}"
    )

이 검사는 작업 트리의 추적 대상 변경을 확인하는 기본 예제다.

실제 운영에서는 새로 생성한 파일, 삭제, 이름 변경, 스테이징된 파일, 기준 커밋 이후의 변경까지 검사해야 한다.

또 보안상 중요한 파일은 쓰기 권한 자체를 제한하는 것이 더 안전하다.


8. Codex의 결과도 JSON으로 전달한다

Codex가 코드를 수정한 뒤 긴 설명을 반환할 필요는 없다.

예를 들어 다음과 같이 결과를 저장한다.

implementation.json

{
  "task_id": "IOS-102",
  "status": "completed",
  "base_commit": "abc1234",
  "head_commit": "def5678",
  "changed_files": [
    "Sources/Search/SearchViewModel.swift",
    "Tests/SearchViewModelTests.swift"
  ],
  "build": "passed",
  "tests": {
    "passed": 18,
    "failed": 0
  },
  "test_log": "artifacts/tests/result.txt",
  "diff_ref": "abc1234..def5678"
}

Claude Reviewer는 이 파일을 확인한다.

필요한 코드 변경은 다음처럼 읽는다.

git diff abc1234..def5678

전체 프로젝트를 다시 분석하는 대신 실제 변경사항만 살펴보는 것이다.

리뷰 과정에서 관련된 기존 코드가 더 필요하다면 해당 파일만 추가로 읽는다.

이 방식은 컨텍스트를 줄이면서도 검증에 필요한 근거를 보존하는 데 도움이 된다.


9. JSON Schema로 AI 결과를 검증한다

AI가 JSON으로 답변하도록 지시하더라도 항상 올바른 형식이 나온다는 보장은 없다.

필수 필드가 빠지거나 예상하지 못한 상태값이 들어갈 수 있다.

따라서 JSON Schema를 사용하는 편이 좋다.

예를 들어 작업 결과 상태를 다음 세 가지로 제한한다.

{
  "type": "object",
  "required": [
    "task_id",
    "status",
    "changed_files"
  ],
  "properties": {
    "task_id": {
      "type": "string"
    },
    "status": {
      "enum": [
        "completed",
        "failed",
        "blocked"
      ]
    },
    "changed_files": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "additionalProperties": false
}

Python의 jsonschema 패키지로 검증할 수 있다.

pip install jsonschema
import json
from jsonschema import validate

with open("schema.json") as file:
    schema = json.load(file)

with open("implementation.json") as file:
    result = json.load(file)

validate(
    instance=result,
    schema=schema
)

실제 프로젝트에서는 역할별로 별도의 Schema를 만드는 것이 좋다.

계획, 구현, 리뷰, 테스트, 문서화가 모두 같은 필드를 사용할 필요는 없기 때문이다.

AI의 자연어 답변을 신뢰하는 대신, 구조와 실제 결과를 검증하는 것이 중요하다.


10. Context Pack으로 전체 프로젝트 반복 분석을 줄인다

JSON으로 작업을 전달하더라도 AI가 매번 Repository 전체를 탐색하면 효율이 떨어진다.

그래서 필요한 것이 Context Pack이다.

Context Pack은 현재 작업에 필요한 프로젝트 정보만 모은 자료다.

예를 들어 다음 내용을 포함한다.

Task Context

- 현재 목표
- 관련 모듈
- 변경 대상 파일
- 기존 아키텍처
- 코딩 규칙
- 금지된 변경
- 테스트 명령

프로젝트 전체 문서 대신 현재 작업에 필요한 파일을 제공한다.

Repository
     ↓
Context Builder
     ↓
관련 파일 선택
     ↓
Context Pack
     ↓
Claude / Codex

특히 파일이 수천 개 이상인 프로젝트에서는 중요하다.

예를 들어 네트워크 오류 처리를 수정하는데 모든 SwiftUI 화면 코드를 컨텍스트에 넣을 이유는 없다.

반대로 네트워크 상태가 화면에 전달되는 흐름은 필요할 수 있다.

따라서 Context Pack에는 단순히 파일 수를 줄이는 것뿐 아니라 작업에 필요한 의존 관계를 남기는 것이 중요하다.


11. Orchestrator는 상태 머신으로 만든다

여러 AI를 연결할 때 가장 중요한 것은 누가 언제 실행되는지다.

이 과정을 상태 머신으로 관리하면 실패한 위치를 찾고 작업을 다시 시작하기 쉬워진다.

CREATED
   ↓
PLANNING
   ↓
PLAN_APPROVAL
   ↓
IMPLEMENTING
   ↓
TESTING
   ↓
REVIEWING
   ↓
FIXING
   ↓
DESIGN_QA
   ↓
DOCUMENTING
   ↓
PR_READY
   ↓
WAITING_HUMAN
   ↓
COMPLETED

실패 상태도 별도로 정의한다.

FAILED_BUILD

FAILED_TEST

REJECTED_REVIEW

FAILED_DESIGN_QA

MAX_RETRY_EXCEEDED

BLOCKED_POLICY

WAITING_APPROVAL

예를 들어 Codex가 두 번 수정했는데 같은 테스트가 계속 실패한다면 더 이상 자동 재시도하지 않는다.

현재 변경 내용과 로그를 보존하고 개발자에게 넘긴다.

이렇게 해야 AI가 같은 오류를 계속 분석하고 수정하는 무한 Loop를 줄일 수 있다.

간단한 상태 모델

from enum import StrEnum

class TaskState(StrEnum):
    CREATED = "created"
    PLANNING = "planning"
    PLAN_APPROVAL = "plan_approval"
    IMPLEMENTING = "implementing"
    TESTING = "testing"
    REVIEWING = "reviewing"
    FIXING = "fixing"
    DESIGN_QA = "design_qa"
    DOCUMENTING = "documenting"
    PR_READY = "pr_ready"
    WAITING_HUMAN = "waiting_human"
    COMPLETED = "completed"
    FAILED = "failed"

실제 Orchestrator에서는 현재 상태와 시도 횟수, 마지막 성공 단계, 작업별 파일 경로를 저장해야 한다.

단순히 상태값만 저장하는 것으로는 충분하지 않다.

실행 중 컴퓨터가 종료되거나 API 호출이 실패해도 다음 실행에서 안전하게 복구할 수 있어야 한다.


12. 실제 AI CLI 호출은 어떻게 연결할까?

여기서는 세 도구를 같은 컴퓨터에서 실행하는 최소 구성을 사용한다.

처음부터 A2A 서버를 만들 필요는 없다.

Claude — 계획 생성

Claude Code는 비대화형 실행을 지원한다.

claude -p \
  --output-format json \
  "Read task.json and produce a plan."

--output-format json은 CLI 실행 결과를 구조화된 형식으로 반환한다.

하지만 여기서 주의할 점이 있다.

Claude CLI가 반환하는 JSON 형식과 우리가 정의한 plan.json의 업무용 Schema는 다르다.

따라서 Claude의 응답 본문에서 계획 JSON을 추출하고, 별도 Schema로 검증하는 Adapter가 필요하다.

Codex — 구현

Codex에서는 비대화형 실행을 사용할 수 있다.

codex exec \
  "Implement the approved plan in plan.json"

자동화 환경에서는 실행 로그를 구조화하려면 해당 버전의 JSON 이벤트 출력 옵션을 사용할 수 있다.

실제 코드를 수정하는 작업은 허용된 작업 디렉터리와 샌드박스 안에서 실행해야 한다.

또 실행 권한이나 자동 승인 옵션을 무분별하게 확대하면 안 된다.

Gemini — 문서 작성

Gemini CLI의 Headless Mode를 활용할 수 있다.

gemini -p \
  "Summarize the approved diff as Korean documentation" \
  --output-format json

Gemini CLI는 JSON 출력 외에 Streaming JSON도 지원한다.

자동화에서는 종료 코드와 오류 정보를 함께 확인해야 한다.

Orchestrator의 역할

각 CLI는 서로 다른 JSON 응답 구조를 가진다.

따라서 Orchestrator는 다음을 수행한다.

CLI 실행
   ↓
종료 코드 확인
   ↓
Provider 응답 파싱
   ↓
업무용 JSON 추출
   ↓
Schema 검증
   ↓
다음 상태로 이동

이 Adapter를 잘 만들어두면 모델이나 CLI를 교체하더라도 전체 파이프라인을 크게 변경하지 않을 수 있다.


13. 공식 플러그인과 Skill은 어디에 사용할까?

최근에는 MCP 서버와 스킬을 직접 설치하는 것 외에 기능을 묶어서 제공하는 플러그인 방식도 넓어지고 있다.

이번 오케스트라에서는 모든 도구를 처음부터 직접 구현하지 않는다.

공식 기능을 우선 사용하고, 부족한 부분만 별도의 Adapter와 Skill로 보완한다.

제품활용할 기능
Claude CodePlugin, Skills, Subagents, Hooks, MCP
CodexPlugins, Skills, MCP, SDK, App Server
Gemini CLIExtensions, Skills, Hooks, Headless Mode, A2A Remote Subagents
FigmaMCP, 디자인 컨텍스트, Variables, Code Connect
GitHubCLI, Actions, Branch Protection, Environments

예를 들어 Figma 디자인을 가져오기 위해 별도의 이미지 분석 스크립트를 처음부터 만들 필요는 없다.

공식 Figma MCP가 제공하는 get_design_context, get_screenshot, get_variable_defs 같은 도구를 먼저 활용할 수 있다.

Claude Code에서는 Subagent를 통해 설계 담당과 리뷰 담당을 분리한다.

Codex에서는 반복적인 구현과 테스트 절차를 Skill로 정의할 수 있다.

Gemini CLI에서는 문서 작성용 Extension 또는 Skill을 구성할 수 있다.

여기서 플러그인은 기능을 연결하는 수단이지, 작업 승인과 검증을 대신하는 시스템은 아니라는 점을 기억해야 한다.

14. 디자인이 없다면 Claude Design에서 시작한다

이제 실제 앱 개발로 넘어가 보자.

프로젝트에 디자인 시안이 없다면 Claude의 디자인 기능을 이용해 초기 화면과 디자인 시스템을 구성할 수 있다.

예를 들어 다음과 같이 요청한다.

iOS 18 이상을 지원하는
재고 관리 앱의 디자인을 만들어줘.

화면:
- 홈 대시보드
- 재고 목록
- 상품 상세
- 장바구니

스타일:
- 밝고 단순한 디자인
- 일관된 색상과 간격
- SF Symbols 활용
- Dynamic Type 고려
- 라이트·다크 모드 지원

먼저 디자인 시스템과
화면별 구조를 제안해줘.

이후 개발자는 결과물을 검토한다.

디자인이 승인되면 관련 컴포넌트와 레이아웃 정보를 개발 작업으로 전달한다.

Claude Design 기능의 실제 제공 범위와 Claude Code 연결 명령은 사용하는 제품·플랜·버전에 따라 달라질 수 있으므로, 해당 환경에서 사용 가능한 공식 연동 기능을 확인해야 한다.

중요한 것은 디자인을 만드는 주체가 Claude라는 사실보다 승인된 디자인을 버전이 있는 작업 기준으로 남기는 것이다.

디자인이 확정되지 않은 상태에서 Codex가 코드를 작성하고, 다시 Claude가 디자인을 바꾸는 작업을 반복하면 불필요한 재작업이 발생한다.

따라서 디자인 승인 단계를 두는 것이 좋다.

15. 디자이너가 준 Figma는 그대로 가져온다

실제 회사 프로젝트에서는 디자이너가 Figma 파일을 제공하는 경우가 많다.

이때 AI에게 스크린샷만 보여주고 비슷하게 만들어 달라고 요청하는 방식은 정확도가 떨어질 수 있다.

이미지에는 버튼 위치와 색상이 보이지만 다음 정보는 명확하지 않을 수 있다.

  • Auto Layout 설정
  • 컴포넌트 계층
  • 디자인 Variables
  • 간격과 패딩
  • 폰트 스타일
  • 컴포넌트 상태
  • 화면 크기별 동작
  • 실제 이미지 리소스

이런 정보를 얻기 위해 공식 Figma MCP를 사용한다.

Figma MCP 연결

Figma의 원격 MCP 서버 주소는 다음과 같다.

https://mcp.figma.com/mcp

공식적으로 지원하는 AI 클라이언트에서는 Figma 플러그인을 설치하거나 MCP 서버를 추가해 연결할 수 있다.

최초 연결 시 Figma 계정 인증이 필요하다.

이후 디자이너가 전달한 Figma 화면에서 Copy link to selection으로 특정 Frame의 링크를 복사한다.

Claude 또는 Codex에 다음과 같이 요청한다.

다음 Figma Frame을 분석해줘.

[Figma Frame URL]

get_design_context와 get_screenshot을 사용해서
디자인 구조와 화면을 확인해줘.

색상, 폰트, 간격, Auto Layout,
컴포넌트 정보와 리소스를 정리해줘.

현재 프로젝트의 SwiftUI Design System에
매핑할 수 있는 구조를 제안해줘.

디자이너가 승인한 디자인은
임의로 변경하지 마.

Figma MCP는 디자인 정보를 제공한다.

최종 SwiftUI 코드를 완성하는 것은 Codex의 역할이다.

또 Figma MCP가 React·Tailwind 형태의 디자인 설명을 반환하더라도 실제 프로젝트가 SwiftUI라면 이를 그대로 복사하지 않는다.

SwiftUI의 레이아웃 방식과 기존 컴포넌트 구조에 맞게 변환해야 한다.

16. Figma 전체를 읽지 말고 필요한 Frame만 가져온다

Figma MCP를 연결했다고 해서 전체 디자인 파일을 매번 읽는 것은 비효율적이다.

큰 Figma 파일에는 수십 개의 화면과 수백 개의 컴포넌트가 포함될 수 있다.

이런 정보를 한꺼번에 전달하면 컨텍스트를 상당히 많이 사용할 수 있다.

따라서 다음처럼 접근한다.

Figma File
     ↓
get_metadata
     ↓
필요한 Frame 선택
     ↓
get_design_context
     ↓
get_variable_defs
     ↓
get_screenshot
     ↓
필요한 Asset 다운로드

get_metadata는 디자인의 전체 구조를 가볍게 파악할 때 유용하다.

get_design_context는 선택한 요소의 구조화된 디자인 정보를 제공한다.

get_variable_defs는 색상과 간격, 타이포그래피 등에 사용된 Variables를 확인하는 데 활용한다.

get_screenshot은 실제 렌더링 결과를 비교하기 위한 기준 이미지로 사용한다.

특히 Figma MCP 응답은 상당히 커질 수 있으므로 화면별로 나눠 처리하는 것이 좋다.

AI 개발 오케스트라에서도 디자인 데이터는 작업별 Context Pack으로 관리해야 한다.

17. Figma 디자인을 JSON으로 저장한다

Codex가 Figma 데이터를 매번 다시 요청하지 않도록 디자인 정보를 JSON으로 정리할 수 있다.

예를 들어 로그인 화면의 버튼 정보를 다음처럼 저장한다.

{
  "schema_version": 1,
  "design_revision": "figma-rev-20261029",
  "screen": "LoginView",
  "reference": {
    "width": 393,
    "height": 852,
    "unit": "pt"
  },
  "components": {
    "loginButton": {
      "x": 24,
      "y": 650,
      "width": 345,
      "height": 52,
      "cornerRadius": 12,
      "background": "#2563EB"
    }
  }
}

이 값은 구조를 설명하기 위한 예시다.

실제 프로젝트에서는 Figma에서 확인한 수치를 사용한다.

또 좌표의 기준을 명확하게 지정해야 한다.

Figma Frame 기준 좌표와 iOS의 Safe Area 기준 좌표는 서로 다를 수 있기 때문이다.

디자인 JSON에는 화면 크기와 기준 좌표계를 함께 저장하는 것이 좋다.

이후 Codex는 해당 JSON과 프로젝트의 Design System을 참조해 SwiftUI 화면을 구현한다.

18. Codex가 SwiftUI 화면과 기능을 구현한다

Claude가 디자인과 구현 계획을 승인받았다면 이제 Codex가 작업을 시작한다.

이번 예제에서는 로그인 화면의 디자인을 구현하고 기존 인증 로직을 연결한다고 가정하자.

Codex에 전달하는 지시는 다음과 같다.

승인된 plan.json과 design.json을 기준으로
LoginView를 구현해줘.

조건:
- Swift 6
- SwiftUI
- iOS Deployment Target 유지
- 기존 AuthenticationService 재사용
- 외부 Dependency 추가 금지
- 기존 Public API 유지

디자인:
- Figma의 색상과 간격 사용
- 새로운 디자인 임의 생성 금지
- Dynamic Type 대응

검증:
- xcodebuild 실행
- 관련 Unit Test 실행
- 변경 파일 목록 보고

허용된 파일 외에는 수정하지 마.

Codex는 승인된 Worktree에서만 코드를 수정한다.

대규모 작업은 작은 단위로 나누는 것이 좋다.

Design Tokens
     ↓
공통 컴포넌트
     ↓
화면 구현
     ↓
상태 관리 연결
     ↓
네트워크 연결
     ↓
테스트

코드 수정 후에는 반드시 빌드해야 한다.

AI가 Swift 문법에 맞는 코드를 생성했다고 해서 실제 프로젝트에서 컴파일된다는 보장은 없기 때문이다.

19. Xcode 빌드와 테스트를 자동화한다

Codex는 코드 수정 후 빌드와 테스트를 실행한다.

예를 들어 iOS Simulator에서 다음과 같이 빌드할 수 있다.

xcodebuild \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -configuration Debug \
  -destination 'platform=iOS Simulator,name=iPhone 17' \
  build

실제 프로젝트에서는 설치된 Simulator 이름과 Scheme을 확인해야 한다.

테스트 실행은 다음과 같다.

xcodebuild \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -destination 'platform=iOS Simulator,name=iPhone 17' \
  test

실패하면 Codex가 실패 로그를 분석하고 수정한다.

다만 모든 로그를 다음 AI에게 전달하지 않는다.

실패한 테스트 이름과 핵심 오류 메시지, 로그 파일 경로만 전달한다.

또 같은 오류가 반복된다면 정해진 재시도 횟수에서 중단한다.

예를 들어 두 번 수정해도 동일한 빌드 오류가 해결되지 않으면 Claude Planner에게 계획 재검토를 요청할 수 있다.

이렇게 하면 코딩 에이전트가 원인 분석과 수정 작업을 끝없이 반복하는 상황을 줄일 수 있다.

20. Figma와 Simulator 화면은 눈으로만 비교하지 않는다

이제 중요한 디자인 QA 단계다.

일반적으로 AI가 화면을 구현하면 스크린샷을 찍어 비교한다.

하지만 화면이 비슷해 보인다고 해서 실제 디자인과 일치하는 것은 아니다.

예를 들어 다음과 같은 차이가 생길 수 있다.

버튼 X 위치: +4pt

버튼 높이: -2pt

Corner Radius: -2pt

폰트 크기: +1pt

텍스트 Baseline: +3pt

이런 차이는 육안으로 놓치기 쉽다.

특히 여러 화면에서 반복되면 전체 앱의 완성도에 영향을 준다.

따라서 디자인 QA는 두 가지 방식으로 나누는 것이 좋다.

첫 번째는 수치 기반 QA다.

좌표와 크기, 색상, 간격, 폰트 등을 비교한다.

두 번째는 이미지 기반 QA다.

Figma 기준 이미지와 Simulator 스크린샷을 비교한다.

두 가지 결과를 함께 사용해야 실제 디자인과의 차이를 더 정확하게 확인할 수 있다.

21. Figma와 iOS의 좌표계를 먼저 일치시킨다

수치 QA에서 가장 먼저 해야 할 일은 측정 기준을 맞추는 것이다.

Figma에서 버튼의 Y 위치가 650이라고 해서 Simulator에서도 무조건 650pt여야 하는 것은 아니다.

Figma는 디자인 Frame을 기준으로 좌표를 제공한다.

iOS에서는 화면 전체, Window, Safe Area, 특정 부모 View 중 어디를 기준으로 측정하는지에 따라 좌표가 달라진다.

또 iPhone의 화면 Point와 실제 스크린샷 Pixel은 다르다.

예를 들어 다음과 같은 조건을 맞춰야 한다.

항목확인할 내용
기기동일한 iPhone 모델
화면 크기Figma Frame과 iOS Point 크기
좌표 기준전체 화면 또는 Safe Area
Display ScalePoint와 Pixel 변환
AppearanceLight / Dark
언어한국어 / 영어
Dynamic Type동일한 글자 크기
키보드표시 여부
상태 바시간·배터리 등 테스트 조건
UI 상태로딩·완료·오류 등 동일 상태

실제 레이아웃을 비교할 때는 부모 View와 자식 View의 좌표계도 구분해야 한다.

이 기준을 제대로 맞추지 않으면 화면은 정상인데 QA 결과에는 수십 pt의 차이가 발생할 수 있다.

22. XCUITest에서 실제 UI의 좌표와 크기를 가져온다

XCUITest에서는 Accessibility 요소의 Frame을 확인할 수 있다.

따라서 테스트 대상 View에 Accessibility Identifier를 부여하면 위치와 크기를 측정할 수 있다.

SwiftUI에서는 다음과 같이 설정한다.

Button("로그인") {
    // Login action
}
.accessibilityIdentifier("loginButton")

XCUITest에서 해당 버튼의 Frame을 가져온다.

import XCTest

final class LoginLayoutTests: XCTestCase {
    func testLoginButtonFrame() {
        let app = XCUIApplication()
        app.launch()

        let button = app.buttons["loginButton"]

        XCTAssertTrue(button.waitForExistence(timeout: 5))

        let frame = button.frame

        XCTAssertEqual(
            frame.width,
            345,
            accuracy: 1
        )

        XCTAssertEqual(
            frame.height,
            52,
            accuracy: 1
        )
    }
}

여기서 345pt와 52pt는 예제 디자인 수치다.

실제 테스트에서는 Figma에서 확보한 값을 사용해야 한다.

위치까지 비교하려면?

XCUITest의 frame은 화면 좌표계에서 표현되는 접근성 요소의 경계다.

따라서 Figma JSON의 좌표와 비교하려면 기준을 맞춰야 한다.

예를 들어 화면 전체를 기준으로 한 X 좌표를 비교할 수 있다.

XCTAssertEqual(
    frame.minX,
    24,
    accuracy: 1
)

하지만 모든 SwiftUI View가 개별 Accessibility 요소로 노출되는 것은 아니다.

또 Accessibility Frame은 내부 컴포넌트의 세부적인 레이아웃 값을 모두 제공하지 않는다.

따라서 정밀한 디자인 QA에서는 테스트 전용 Geometry 측정 정보를 앱 내부에서 수집하는 방식을 추가할 수 있다.

예를 들어 GeometryReader의 측정 결과를 테스트 전용 데이터로 전달하는 것이다.

단, 이런 계측 코드는 Release 빌드에 불필요하게 포함하지 않는 편이 좋다.

23. 색상·폰트·간격·Corner Radius까지 검증한다

레이아웃 QA를 Frame 비교에서 끝내면 부족하다.

실제 디자인에는 더 많은 수치가 포함된다.

예를 들어 로그인 버튼 하나에도 다음 정보가 있다.

X / Y 좌표

Width / Height

Corner Radius

Background Color

Font Family

Font Size

Font Weight

Line Height

Text Alignment

Padding

이 값들을 JSON으로 관리하면 자동 비교할 수 있다.

예를 들어 다음과 같은 QA 결과를 만들 수 있다.

{
  "screen": "LoginView",
  "design_revision": "figma-rev-20261029",
  "result": "failed",
  "differences": [
    {
      "component": "loginButton",
      "property": "y",
      "expected": 650,
      "actual": 654,
      "delta": 4,
      "unit": "pt"
    },
    {
      "component": "loginButton",
      "property": "cornerRadius",
      "expected": 12,
      "actual": 10,
      "delta": -2,
      "unit": "pt"
    }
  ]
}

이 결과를 Codex에게 전달한다.

Codex는 전체 화면을 다시 만들지 않고 해당 항목만 수정한다.

여기서 중요한 것은 실제 측정값을 확보하는 방법이다.

Accessibility Frame만으로 Corner Radius나 실제 적용된 Font Weight를 모두 읽을 수 있는 것은 아니다.

이런 값은 디자인 토큰과 앱 내부 컴포넌트 설정을 비교하거나, 테스트 전용 계측을 추가해야 한다.

또 텍스트는 시스템 폰트 렌더링과 Dynamic Type, 언어 설정에 따라 차이가 발생할 수 있다.

따라서 모든 속성에 똑같은 오차 허용 범위를 적용해서는 안 된다.

예를 들어 좌표와 크기는 Point 단위로 비교하고, 색상은 색 공간을 통일해 비교한다.

폰트의 실제 렌더링 결과는 이미지 비교와 함께 확인하는 것이 좋다.

24. Screenshot Diff와 수치 QA를 함께 실행한다

수치 비교는 정확하지만 모든 시각적 문제를 발견하지 못할 수 있다.

예를 들어 버튼 위치와 크기는 정확하지만 아이콘이 잘못됐을 수 있다.

반대로 스크린샷이 매우 비슷해 보여도 버튼의 실제 터치 영역은 다를 수 있다.

따라서 두 가지 검증을 함께 사용한다.

Figma 디자인
      ↓
디자인 수치 JSON
      ↓
수치 QA   ───────────┐
                    │
Simulator 실행       │
      ↓             │
Screenshot          │
      ↓             │
Image Diff ─────────┤
                    ↓
                QA Result
                    ↓
                  Codex

이미지 비교에는 Pixel Diff나 SSIM 같은 방법을 사용할 수 있다.

다만 실제 이미지 비교를 하려면 두 이미지가 같은 해상도와 좌표계를 가져야 한다.

또 시스템 상태 바, 커서, 애니메이션, 날짜, 네트워크 데이터처럼 매번 달라지는 영역은 테스트에서 고정하거나 비교 대상에서 제외해야 한다.

QA 통과 기준

예를 들어 다음과 같이 정의할 수 있다.

항목예시 기준
핵심 버튼 Frame허용 오차 이내
색상지정된 색상 오차 이내
Corner Radius디자인 토큰과 일치
텍스트크기·Weight·정렬 확인
스크린샷 Diff프로젝트 임계값 이내
접근성주요 요소 식별·조작 가능
Dynamic Type레이아웃 깨짐 없음

실제 임계값은 프로젝트와 디자인 시스템에 맞게 정해야 한다.

이 기준을 통과하면 Codex는 디자인 구현이 완료됐다고 보고할 수 있다.

하지만 중요한 화면은 디자이너가 최종 확인하는 편이 좋다.

자동 QA는 디자이너의 판단을 완전히 대체하는 것이 아니라 반복적인 수치 검사를 줄여주는 역할이다.

25. Claude가 Codex의 코드를 독립적으로 리뷰한다

구현과 테스트가 끝났다면 Claude가 코드를 검토한다.

여기서 중요한 것은 같은 Claude 세션이 계획부터 검수까지 모든 작업을 수행하지 않도록 하는 것이다.

Planner와 Reviewer를 분리하면 구현 과정에서 발생한 설명이나 추측에 덜 의존하고 실제 변경 내용을 기준으로 검토하도록 구성할 수 있다.

Claude Reviewer에게 전달하는 정보는 다음과 같다.

Approved Plan

Git Diff

Test Result

Design QA Result

Protected File Policy

전체 프로젝트 대화를 전달할 필요는 없다.

리뷰 항목은 다음과 같이 정리할 수 있다.

검수 항목확인 내용
요구사항계획을 제대로 구현했는가
변경 범위허용하지 않은 파일을 수정했는가
아키텍처기존 설계를 유지했는가
동시성취소·재시도·공유 상태 문제
테스트실제로 실행하고 통과했는가
디자인Figma 수치 QA를 통과했는가
보안비밀정보와 권한 문제
유지보수불필요한 복잡성 추가 여부

Claude는 리뷰 결과를 JSON으로 반환한다.

{
  "task_id": "IOS-102",
  "verdict": "changes_requested",
  "findings": [
    {
      "severity": "high",
      "file": "Sources/Search/SearchViewModel.swift",
      "issue": "Stale response may update current state",
      "required_change": "Check request identity before updating"
    }
  ]
}

Codex는 지적된 문제만 수정한다.

계획에 없는 새로운 리팩터링을 시작하지 않도록 제한한다.

그리고 리뷰가 반복되면 최대 횟수에서 멈춘다.

26. 누가 Git PR을 만들고, 누가 검증할까?

이 부분은 오케스트라의 책임을 명확하게 만드는 핵심이다.

이번 구조에서는 Codex가 코드를 작성하고 PR을 생성한다.

Claude는 독립적으로 리뷰한다.

GitHub Actions는 실제 빌드와 테스트 결과를 검증한다.

최종 PR 승인은 사람이 담당한다.

작업담당
Branch 생성Orchestrator / Codex
Worktree 생성Orchestrator
코드 작성Codex
커밋Codex
Pull Request 생성Codex
코드 리뷰Claude
리뷰 수정Codex
자동 빌드·테스트GitHub Actions
디자인 수치 QA자동 검사
디자인 최종 확인디자이너
개발 문서 작성Gemini
최종 PR 승인개발자
Main 병합개발자 또는 승인된 자동화

Codex는 GitHub CLI를 이용해 PR을 생성할 수 있다.

gh pr create \
  --base main \
  --head feature/IOS-102 \
  --title "Fix search cancellation race" \
  --body-file .ai/tasks/IOS-102/pr.md

여기서 중요한 점이 있다.

Claude의 코드 리뷰 결과는 GitHub의 공식 승인 권한을 자동으로 대체하지 않는다.

AI 리뷰는 CI 상태 검사나 PR 코멘트로 기록할 수 있다.

최종 병합은 GitHub의 Branch Protection 또는 Ruleset 정책을 통과해야 한다.

권장 설정은 다음과 같다.

Pull Request Required

Required Status Checks

Required Human Review

No Direct Push to Main

No Force Push

Deployment Approval Required

특히 AI 계정이 PR을 작성하고 동일한 권한으로 승인까지 할 수 있다면 역할을 분리한 의미가 줄어든다.

따라서 AI에는 필요한 최소한의 GitHub 권한만 제공하는 것이 좋다.

27. Gemini가 한국어 개발 문서를 완성한다

코드 리뷰와 테스트가 끝나면 Gemini가 문서를 작성한다.

여기서도 전체 코드를 처음부터 전달하지 않는다.

Gemini에는 다음 정보를 제공한다.

승인된 변경사항

최종 Git Diff

Public API 변경

테스트 결과

기존 README

문서 작성 규칙

예를 들어 다음 문서를 작성하도록 할 수 있다.

docs/
 ├── architecture.md
 ├── api-guide.ko.md
 ├── migration-guide.ko.md
 └── release-notes.ko.md

문서 작성 지시는 다음과 같다.

최종 승인된 Git Diff를 기준으로
한국어 개발 문서를 작성해줘.

작성할 문서:
- Architecture
- API Guide
- Migration Guide
- Release Notes

규칙:
- 실제 코드에 존재하는 API만 설명
- 변경되지 않은 기능을 새 기능으로 소개하지 않기
- 자연스러운 한국 개발자 용어 사용
- 클래스와 API 이름은 원문 유지
- 코드 예제는 실제 구현과 일치해야 함
- 검증하지 않은 동작은 추측으로 구분

앱 소스 코드는 수정하지 마.

Gemini는 문서 전용 경로에서만 작업하도록 구성한다.

이때 문서의 내용을 자동 검사할 수도 있다.

예를 들어 문서에서 언급한 공개 API가 실제 코드에 존재하는지 검사할 수 있다.

문서가 완성되면 PR에 추가한다.

문서는 코드 변경이 확정된 뒤 작성해야 한다.

Codex가 계속 구현을 수정하는 동안 Gemini가 문서를 작성하면 문서와 실제 코드가 달라질 수 있기 때문이다.

28. GitHub Actions로 PR마다 빌드와 테스트를 실행한다

이제 CI 단계다.

개발자가 PR을 생성하면 GitHub Actions가 자동으로 실행된다.

기본적인 작업은 다음과 같다.

Pull Request
      ↓
Checkout
      ↓
Xcode 환경 준비
      ↓
Dependency Resolve
      ↓
Build
      ↓
Unit Test
      ↓
UI Test
      ↓
Design QA
      ↓
Artifact 업로드
      ↓
Status Check

다음은 Xcode 프로젝트의 빌드와 테스트를 실행하는 기본적인 GitHub Actions 예제다.

.github/workflows/ios-ci.yml

name: iOS CI

on:
  pull_request:
    branches:
      - main

permissions:
  contents: read

jobs:
  build-and-test:
    runs-on: macos-15

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Select Xcode
        run: |
          xcodebuild -version

      - name: Resolve dependencies
        run: |
          xcodebuild \
            -resolvePackageDependencies \
            -project MyApp.xcodeproj \
            -scheme MyApp

      - name: Build and Test
        run: |
          xcodebuild \
            -project MyApp.xcodeproj \
            -scheme MyApp \
            -destination 'platform=iOS Simulator,name=iPhone 17' \
            -resultBundlePath TestResults.xcresult \
            test

      - name: Upload Test Results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-results
          path: TestResults.xcresult

위 예제는 기본 구조다.

실제 프로젝트에서는 GitHub Runner에서 사용할 수 있는 Xcode 버전과 Simulator를 확인해야 한다.

특히 최신 Xcode가 필요한 프로젝트는 Runner 이미지와 Xcode 설치 상태를 함께 관리해야 한다.

프로덕션 CI에서는 Actions 버전을 고정하거나 검증된 버전을 사용하는 것도 권장한다.

또 Design QA는 별도 테스트 스크립트나 XCUITest를 추가해 실행해야 한다.

기본 xcodebuild test 명령만으로 Figma 수치 검증까지 자동으로 수행되는 것은 아니다.

29. GitHub Actions에서 TestFlight와 App Store까지 자동화한다

CI가 통과하면 CD 단계로 넘어간다.

iOS 앱을 배포하려면 코드만 빌드해서는 안 된다.

코드 서명과 Provisioning Profile, App Store Connect 인증이 필요하다.

전체 흐름은 다음과 같다.

Main Merge
     ↓
Release Build
     ↓
Code Signing
     ↓
Archive
     ↓
Export IPA
     ↓
TestFlight Upload
     ↓
내부 테스트
     ↓
개발자 승인
     ↓
App Store 심사 제출
     ↓
Apple 심사 및 출시

여기서 중요한 것은 TestFlight 업로드와 App Store 출시를 분리하는 것이다.

PR이 병합됐다는 이유만으로 곧바로 App Store에 출시되도록 설정하지 않는 편이 안전하다.

App Store Connect API Key

자동 업로드에는 App Store Connect API Key를 사용할 수 있다.

이 키는 Git Repository에 저장하면 안 된다.

GitHub Secrets 또는 보안이 설정된 GitHub Environment에서 관리해야 한다.

Fastlane에서는 다음과 같이 API Key를 사용할 수 있다.

api_key = app_store_connect_api_key(
  key_id: ENV["ASC_KEY_ID"],
  issuer_id: ENV["ASC_ISSUER_ID"],
  key_content: ENV["ASC_KEY_CONTENT"]
)

실제 환경에서는 키 내용과 인증서, Provisioning Profile을 안전하게 제공해야 한다.

Fastlane으로 TestFlight 업로드

예를 들어 Fastfile에 다음 Lane을 정의할 수 있다.

default_platform(:ios)

platform :ios do
  lane :beta do
    api_key = app_store_connect_api_key(
      key_id: ENV["ASC_KEY_ID"],
      issuer_id: ENV["ASC_ISSUER_ID"],
      key_content: ENV["ASC_KEY_CONTENT"]
    )

    build_app(
      scheme: "MyApp",
      export_method: "app-store"
    )

    upload_to_testflight(
      api_key: api_key,
      skip_waiting_for_build_processing: true
    )
  end
end

이 예제를 실제로 실행하려면 코드 서명과 빌드 환경이 사전에 구성돼 있어야 한다.

또 skip_waiting_for_build_processing은 업로드 후 빌드 처리 완료를 기다리는 동작을 생략하는 옵션이다.

따라서 TestFlight 빌드가 즉시 테스터에게 제공된다는 의미는 아니다.

GitHub Actions에서 실행

다음은 GitHub Environment 승인을 거친 뒤 Fastlane을 실행하는 CD 작업의 핵심 구조다.

name: TestFlight Release

on:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  release:
    runs-on: macos-15
    environment: testflight

    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: bundle install

      - name: Upload to TestFlight
        env:
          ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
          ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
          ASC_KEY_CONTENT: ${{ secrets.ASC_KEY_CONTENT }}
        run: bundle exec fastlane ios beta

실제 배포 구성에서는 서명 인증서와 Provisioning Profile 준비, Xcode 선택, Release 빌드 검증, 빌드 번호 관리 등을 추가해야 한다.

또 GitHub Environment에 필수 승인자를 설정해 승인 전에는 배포 작업이 실행되지 않도록 구성한다.

App Store 자동 출시까지 할까?

기술적으로는 Fastlane과 App Store Connect API를 활용해 메타데이터와 빌드를 제출하고 심사 과정을 자동화할 수 있다.

하지만 이 글의 오케스트라에서는 App Store 제출 전에 사람 승인을 요구한다.

다음 항목을 최종적으로 확인해야 하기 때문이다.

  • 앱 버전과 빌드 번호
  • 릴리스 노트
  • 스토어 스크린샷
  • 개인정보 처리 내용
  • 앱 심사 메타데이터
  • 결제 및 구독 관련 변경
  • 심각한 버그 존재 여부
  • 최종 테스트 결과

그리고 App Store Connect에 업로드했다고 해서 심사가 자동으로 통과되는 것은 아니다.

AI는 배포 준비를 자동화할 수 있지만, 실제 출시 책임까지 대신하는 것은 아니다.

30. Paseo를 사용하면 더 간단하게 만들 수 있을까?

지금까지 설명한 오케스트라는 직접 작업 상태와 CLI 실행, JSON 계약을 관리하는 방식이다.

이 구조는 유연하지만 직접 만들어야 할 부분도 많다.

여기서 선택할 수 있는 도구가 Paseo다.

Paseo는 여러 AI 코딩 에이전트를 하나의 환경에서 실행하고 관리하는 오픈소스 개발 도구다.

Claude Code, Codex, OpenCode 등 주요 도구를 지원하며 Gemini CLI도 ACP 기반 연결 방식으로 사용할 수 있다.

대표적인 기능은 다음과 같다.

  • 여러 AI 에이전트 동시 실행
  • 에이전트별 Git Worktree 관리
  • 작업 위임과 결과 확인
  • 파일 및 Git Diff 검토
  • 터미널과 PR 작업
  • 데스크톱·웹·모바일 접근
  • MCP 및 자체 Plugin 확장
  • CLI와 SDK 자동화

Paseo의 오케스트레이션 스킬을 추가하는 방법은 다음과 같다.

npx skills add getpaseo/paseo

프로젝트에서 제공하는 /paseo-handoff는 Claude에서 계획한 작업을 다른 에이전트로 넘기는 등의 작업에 활용할 수 있다.

직접 만든 JSON 기반 파이프라인과 비교하면 다음과 같다.

구분직접 구축Paseo 활용
AI 실행CLI Adapter 구현Provider 연결 활용
Worktree직접 생성·관리내장 기능 활용
작업 전달JSON 계약 직접 구현에이전트 위임 기능 활용
상태 확인자체 대시보드 필요제공 UI 활용
세부 승인 정책자유롭게 설계별도 정책 구현 가능
Figma 수치 QA직접 구현별도 구현 필요
App Store 배포GitHub Actions별도 CI/CD 구성

Paseo를 설치하면 여러 AI를 연결하는 작업은 간단해질 수 있다.

하지만 이번 글에서 구성한 전체 개발 파이프라인이 자동으로 완성되는 것은 아니다.

JSON Schema 검증, Figma 수치 QA, GitHub PR 승인, App Store 배포 권한 등은 별도의 정책과 구현이 필요하다.

따라서 작게 시작한다면 Paseo 같은 기존 도구를 활용하고, 팀의 요구사항이 복잡해지면 직접 만든 Orchestrator를 추가하는 방법도 현실적인 선택이다.

31. 실제 운영에서는 보안과 실패 복구가 더 중요하다

AI 오케스트라가 제대로 작동하려면 정상적인 상황뿐 아니라 문제가 발생하는 상황도 고려해야 한다.

예를 들어 다음과 같은 문제가 발생할 수 있다.

Codex 작업 중단

Claude 리뷰 실패

Gemini 문서 생성 실패

GitHub API 오류

CI Runner 장애

TestFlight 업로드 실패

이때 모든 작업을 처음부터 다시 시작하면 비효율적이다.

이미 성공한 단계의 결과물을 보존하고 마지막 성공 지점부터 재개하는 것이 좋다.

작업 식별자와 버전 관리

모든 JSON 결과물에 다음 정보를 포함할 수 있다.

{
  "task_id": "IOS-102",
  "schema_version": 1,
  "base_commit": "abc1234",
  "head_commit": "def5678",
  "design_revision": "figma-rev-20261029",
  "attempt": 1,
  "status": "reviewing"
}

이렇게 하면 서로 다른 코드 버전과 디자인 버전이 섞이는 문제를 줄일 수 있다.

무한 Loop 방지

같은 오류가 반복되면 작업을 중단해야 한다.

예를 들어 다음 정책을 사용할 수 있다.

구현 재시도 최대 2회

리뷰 수정 최대 2회

동일 오류 반복 시 중단

계획 변경은 개발자 승인

배포 실패 시 자동 재제출 제한

특히 PR 생성과 스토어 배포처럼 외부 상태를 변경하는 작업에서는 중복 실행을 조심해야 한다.

작업이 실패했다고 해서 같은 명령을 무조건 반복하면 중복 PR이나 중복 빌드가 생성될 수 있다.

따라서 실행 결과를 먼저 확인하고 동일한 작업이 이미 완료됐는지 검사하는 것이 좋다.

비밀정보 관리

API Key, 인증서, App Store Connect Key는 AI 사이의 JSON 메시지에 포함하지 않는다.

Git에도 커밋하지 않는다.

또 모든 AI에게 동일한 권한을 줄 필요도 없다.

Claude
설계·리뷰 중심의 읽기 권한

Codex
승인된 Worktree의 수정 권한

Gemini
문서 디렉터리 수정 권한

CI/CD
서명과 업로드 권한

개발자
최종 승인 권한

이러한 권한 제한은 프롬프트뿐 아니라 실제 파일 시스템과 CI 설정에도 적용해야 한다.

32. 최종적으로 완성되는 개발 환경

지금까지 설명한 내용을 하나로 연결하면 다음과 같다.

개발자
  │
  ▼
요구사항 등록
  │
  ▼
Orchestrator
  │
  ├── Context Pack
  ├── JSON Contract
  ├── State Management
  └── Permission Policy
  │
  ▼
Claude Planner
  │
  ▼
plan.json
  │
  ▼
개발자 계획 승인
  │
  ▼
Figma / Claude Design
  │
  ▼
Design Tokens JSON
  │
  ▼
Codex Implementer
  │
  ├── SwiftUI 구현
  ├── 코드 수정
  ├── Unit Test
  └── Build
  │
  ▼
Simulator UI Test
  │
  ▼
Figma 수치 QA
  │
  ▼
Screenshot Diff
  │
  ▼
Claude Reviewer
  │
  ▼
review.json
  │
  ▼
Codex Fixer
  │
  ▼
최종 테스트
  │
  ▼
Gemini Documenter
  │
  ├── README
  ├── API Guide
  ├── Architecture
  └── Release Notes
  │
  ▼
Codex Git PR
  │
  ▼
GitHub Actions
  │
  ├── Build
  ├── Unit Test
  ├── UI Test
  ├── Design QA
  └── Status Check
  │
  ▼
개발자 / 디자이너 승인
  │
  ▼
Main Merge
  │
  ▼
GitHub Actions CD
  │
  ├── Archive
  ├── Code Signing
  ├── TestFlight Upload
  └── App Store Release

이 구조에서 AI는 각자 맡은 작업을 수행한다.

그리고 결과물은 JSON, Git Diff, 테스트 로그, 디자인 QA 결과로 연결된다.

사람은 모든 코드를 직접 작성하지 않아도 된다.

대신 중요한 설계와 승인 지점에서 판단한다.

마치며 — AI 개발팀은 모델을 많이 붙인다고 완성되지 않는다

Claude Code, Codex, Gemini CLI는 각각 강력한 개발도구다.

하지만 세 도구를 동시에 사용한다고 해서 자동으로 좋은 개발 환경이 만들어지는 것은 아니다.

오히려 역할을 제대로 구분하지 않으면 같은 코드를 여러 번 분석하고, 불필요한 컨텍스트를 소비하고, 서로 다른 판단으로 코드를 반복 수정할 수 있다.

그래서 이번 오케스트라에서는 역할을 명확하게 나눴다.

Claude는 설계와 판단, 독립 리뷰를 맡는다.

Codex는 실제 코드 작성과 테스트, 수정 작업을 담당한다.

Gemini는 최종 구현을 바탕으로 한국어·영문 개발 문서를 작성한다.

그리고 이 모든 작업은 JSON 계약과 상태 관리로 연결한다.

디자인 역시 단순히 비슷하게 보이는 수준에서 끝내지 않는다.

Figma에서 확보한 실제 수치와 Simulator의 측정값을 비교하고, 스크린샷 Diff까지 확인한다.

GitHub PR은 Codex가 만들 수 있지만, 리뷰와 CI 검증을 통과한 뒤 사람이 최종 승인한다.

배포도 마찬가지다.

GitHub Actions를 통해 TestFlight 업로드까지 자동화하되, App Store 출시에는 명확한 승인 단계를 남긴다.

필요하다면 Paseo 같은 도구를 활용해 여러 에이전트를 관리하는 부담을 줄일 수도 있다.

결국 중요한 것은 어떤 AI가 코드를 가장 잘 작성하는지에만 있지 않다.

계획부터 구현, 검수, 문서화, 배포까지 서로 다른 역할이 책임을 가지고 이어지는 구조를 만드는 것이다.

AI 코딩 도구가 발전할수록 개발자가 직접 작성해야 하는 코드의 양은 줄어들 수 있다.

하지만 무엇을 만들지 결정하고, 결과가 올바른지 검증하고, 실제 사용자에게 배포할지 승인하는 책임은 여전히 중요하다.

앞으로 AI 개발 환경의 경쟁력은 단순히 모델을 여러 개 연결하는 것보다 그 모델들이 얼마나 적은 중복 작업으로, 얼마나 검증 가능한 결과를 만들어내는지에서 결정될 가능성이 크다.

AI 개발 오케스트라는 바로 그 과정을 체계화하려는 시도다.

좋은 AI 개발팀은 많은 AI를 사용하는 팀이 아니라, 각 AI가 자기 역할을 정확히 수행하고 사람이 최종 통제할 수 있는 팀이다.

참고자료

OpenAI — Codex 공식 개발 문서

Codex CLI, SDK, App Server, Skills와 자동화 기능을 설명한다.

Codex Developers

Anthropic — Claude Code 공식 문서

Claude Code의 설치, Plugin, Subagent, Hook, MCP 및 비대화형 실행을 확인할 수 있다.

Claude Code Documentation

Google — Gemini CLI Headless Mode

JSON 및 Streaming JSON 출력, 종료 코드, CLI 자동화 방법.

Gemini CLI Headless Mode

Google — Gemini CLI 공식 저장소

Extensions, Skills, Hooks, MCP, A2A 관련 기능과 릴리스 정보를 확인할 수 있다.

Gemini CLI GitHub

Figma — Figma MCP Server

디자인 데이터, Variables, 컴포넌트, 레이아웃과 이미지 정보를 AI 개발도구에 전달하는 공식 MCP 문서.

Figma MCP Server

Figma — Tools and Prompts

get_design_context, get_metadata, get_screenshot, get_variable_defs 등 디자인 분석 도구의 역할을 설명한다.

Figma MCP Tools

A2A Protocol — 공식 프로토콜

Agent Card, Task, Message, Artifact 등 에이전트 간 작업 전달을 위한 표준 구조.

A2A Protocol

GitHub — Protected Branch와 승인 정책

Required Reviews, Required Status Checks, Branch Protection 등의 사용 방법.

About Protected Branches

GitHub — Actions

macOS Runner, Workflow, Artifact, Environment와 승인 기능을 설명한다.

GitHub Actions Documentation

Apple — App Store Connect API

앱 빌드 업로드, 메타데이터, 배포 자동화에 사용하는 공식 API.

App Store Connect API

Fastlane — TestFlight 자동 배포

upload_to_testflight와 App Store Connect API Key 인증 방식.

Fastlane Pilot

Fastlane — App Store 배포

App Store Connect 업로드, 메타데이터, 스크린샷과 심사 제출 자동화.

Fastlane Deliver

Paseo — 오픈소스 AI 오케스트라

여러 AI 에이전트 실행, Worktree 관리, 코드 리뷰, PR 및 CLI 자동화 기능.

Paseo GitHub

Paseo — Orchestration

에이전트 간 작업 위임과 Provider 선택, 다중 Worktree, MCP 및 SDK 사용법.

Paseo Orchestration

profile
iOS 앱 개발자

0개의 댓글