<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>kyu_ios_dev.log</title>
        <link>https://velog.io/</link>
        <description>iOS 앱 개발자</description>
        <lastBuildDate>Mon, 21 Sep 2026 06:07:08 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>kyu_ios_dev.log</title>
            <url>https://velog.velcdn.com/images/kyu_ios_dev/profile/24275a15-6bfb-4b3e-b74e-7376b930af6f/image.PNG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. kyu_ios_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/kyu_ios_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Paseo로 여러 AI 코딩 에이전트를 한 팀처럼 쓰는 방법]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609211</link>
            <guid>https://velog.io/@kyu_ios_dev/2609211</guid>
            <pubDate>Mon, 21 Sep 2026 06:07:08 GMT</pubDate>
            <description><![CDATA[<h3 id="paseo로-여러-ai-코딩-에이전트를-한-팀처럼-쓰는-방법">Paseo로 여러 AI 코딩 에이전트를 한 팀처럼 쓰는 방법</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/781f5d8a-e93e-4848-82e4-a306b1e96a22/image.png" alt=""></p>
<h2 id="claude는-설계하고-codex는-구현하고-다른-agent는-리뷰하게-만들기">Claude는 설계하고, Codex는 구현하고, 다른 Agent는 리뷰하게 만들기</h2>
<p>Codex를 쓰다가 Claude Code도 같이 쓰고 싶을 때가 있습니다.</p>
<p>단순히 두 터미널을 띄워 놓는 것은 어렵지 않습니다.</p>
<p>문제는 역할을 나누기 시작할 때입니다.</p>
<pre><code class="language-text">Claude
→ 설계

Codex
→ 구현

Claude
→ 코드 리뷰

Codex
→ 테스트

Gemini
→ 자료 조사</code></pre>
<p>각 Agent에게 Context를 다시 전달하고, 어느 Agent가 무엇을 하고 있는지 확인하고, 결과를 다시 모아서 다음 Agent에게 넘겨줘야 합니다.</p>
<p>Agent가 두세 개를 넘어가면 사람이 AI 사이에서 메시지를 전달하는 역할을 하게 됩니다.</p>
<p><strong>Paseo는 이 부분을 관리하기 위한 Multi-Agent Orchestration 도구입니다.</strong></p>
<p>Paseo 자체가 새로운 AI 모델을 제공하는 것은 아닙니다.</p>
<p>이미 사용하고 있는:</p>
<pre><code class="language-text">Claude Code

Codex

OpenCode

Gemini CLI

GitHub Copilot

그 외 ACP Agent</code></pre>
<p>를 하나의 Workspace에서 실행하고 관리합니다.</p>
<p>기존 CLI의 로그인 정보, 설정, Skill, MCP Server도 그대로 사용할 수 있습니다.</p>
<hr>
<h2 id="1-paseo가-필요한-상황부터-보자">1. Paseo가 필요한 상황부터 보자</h2>
<p>Agent를 하나만 쓴다면 Paseo가 꼭 필요한 것은 아닙니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Codex

&quot;이 프로젝트의 로그인 기능을 구현해줘.&quot;</code></pre>
<p>정도로 충분하다면 Codex 자체가 더 간단합니다.</p>
<p>Paseo가 재미있어지는 것은 역할이 나뉘기 시작할 때입니다.</p>
<pre><code class="language-text">Main Agent
     │
     ├─ Architecture Agent
     │
     ├─ Implementation Agent
     │
     ├─ QA Agent
     │
     └─ Review Agent</code></pre>
<p>그리고 이 Agent들이 꼭 같은 모델일 필요도 없습니다.</p>
<pre><code class="language-text">Architecture
→ Claude

Implementation
→ Codex

Research
→ Gemini

QA
→ Codex</code></pre>
<p>처럼 Provider까지 나눌 수 있습니다.</p>
<p>Paseo 공식 Orchestration 기능도 서로 다른 Provider와 Model을 사용하는 Agent에게 작업을 위임하고, Agent끼리 메시지를 보내고, 진행상태를 확인하고, 결과를 다시 받아오는 구조를 지원합니다.</p>
<hr>
<h2 id="2-먼저-이해해야-할-것--paseo는-ai-모델이-아니다">2. 먼저 이해해야 할 것 — Paseo는 AI 모델이 아니다</h2>
<p>Paseo를 처음 보면 또 하나의 Coding Agent처럼 느껴질 수 있습니다.</p>
<p>하지만 구조는 이렇습니다.</p>
<pre><code class="language-text">             Paseo
               │
     ┌─────────┼─────────┐
     ↓         ↓         ↓
  Claude     Codex     Gemini
   Code                 CLI</code></pre>
<p>Paseo가 직접 코드를 생각해서 만드는 것이 아니라,</p>
<p><strong>각 Coding Agent를 실행하고 연결하고 관리하는 Control Layer</strong>입니다.</p>
<p>공식 문서에서도 Paseo는 기존 Agent CLI를 subprocess로 실행하며, 자체 Coding Agent를 제공하지 않는다고 설명합니다.</p>
<p>그래서 먼저 사용할 Agent가 설치되어 있어야 합니다.</p>
<hr>
<h2 id="3-가장-쉬운-설치-방법은-desktop-app이다">3. 가장 쉬운 설치 방법은 Desktop App이다</h2>
<p>처음 사용한다면 CLI보다 Desktop App부터 시작하는 것이 편합니다.</p>
<p>Paseo 공식 문서에서도 Desktop App을 권장 방식으로 안내하고 있습니다.</p>
<p>Desktop App에는 Paseo daemon이 포함되어 있어서 별도의 서버를 먼저 구성할 필요가 없습니다.</p>
<p>설치는 공식 다운로드 페이지에서 하면 됩니다.</p>
<p>Paseo를 실행하면 기본 구조는:</p>
<pre><code class="language-text">Paseo Desktop
      ↓
Local Daemon
      ↓
Claude / Codex / 기타 Agent</code></pre>
<p>가 됩니다.</p>
<p>즉 Agent들은 자신의 Mac에서 실행됩니다.</p>
<hr>
<h2 id="4-cli로-설치하고-싶다면">4. CLI로 설치하고 싶다면</h2>
<p>터미널 중심으로 사용한다면 Paseo CLI도 사용할 수 있습니다.</p>
<pre><code class="language-bash">npm install -g @getpaseo/cli</code></pre>
<p>설치 후:</p>
<pre><code class="language-bash">paseo</code></pre>
<p>를 실행합니다.</p>
<p>Paseo daemon이 로컬에서 시작됩니다.</p>
<p>Desktop App을 사용한다면 이 작업을 직접 할 필요가 없습니다.</p>
<hr>
<h2 id="5-claude-code와-codex를-먼저-설치한다">5. Claude Code와 Codex를 먼저 설치한다</h2>
<p>중요합니다.</p>
<p><strong>Paseo를 설치했다고 Claude나 Codex가 설치되는 것은 아닙니다.</strong></p>
<p>각 CLI를 별도로 설치하고 인증해야 합니다.</p>
<p>구조는:</p>
<pre><code class="language-text">Mac

├─ Claude Code
├─ Codex
└─ Paseo</code></pre>
<p>입니다.</p>
<p>Paseo는 설치되어 있는 Native Provider를 찾아서 사용할 수 있습니다.</p>
<p>현재 Native 지원 Provider에는 Claude Code, Codex, OpenCode, Pi 등이 있으며 Gemini CLI나 GitHub Copilot 등은 ACP Catalog를 통해 추가할 수 있습니다.</p>
<hr>
<h2 id="6-먼저-각-agent가-독립적으로-동작하는지-확인한다">6. 먼저 각 Agent가 독립적으로 동작하는지 확인한다</h2>
<p>Paseo부터 설정하기 전에 각각의 CLI가 정상적으로 동작하는지 확인하는 게 좋습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-bash">claude</code></pre>
<p>그리고:</p>
<pre><code class="language-bash">codex</code></pre>
<p>를 직접 실행합니다.</p>
<p>둘 다 프로젝트를 읽고 정상적으로 대답한다면 Paseo 쪽으로 넘어갑니다.</p>
<p>문제가 생겼을 때:</p>
<pre><code class="language-text">Paseo 문제인가?

Claude 인증 문제인가?

Codex 설정 문제인가?</code></pre>
<p>를 구분하기 쉬워집니다.</p>
<hr>
<h2 id="7-프로젝트를-paseo-workspace로-연다">7. 프로젝트를 Paseo Workspace로 연다</h2>
<p>Paseo의 중요한 개념 중 하나가 <code>Workspace</code>입니다.</p>
<p>쉽게 말하면:</p>
<blockquote>
<p><strong>Agent들이 함께 작업할 프로젝트 공간</strong></p>
</blockquote>
<p>입니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">MyApp/
├─ Sources
├─ Tests
├─ Package.swift
└─ MyApp.xcodeproj</code></pre>
<p>가 있다면 이 프로젝트 폴더를 하나의 Workspace로 엽니다.</p>
<p>CLI에서는 이런 식으로 만들 수 있습니다.</p>
<pre><code class="language-bash">paseo workspace create \
  --isolation local \
  --path ~/Projects/MyApp \
  --title MyApp</code></pre>
<p>이제 이 Workspace 안에 여러 Agent를 띄울 수 있습니다.</p>
<hr>
<h2 id="8-처음에는-worktree-없이-시작해도-된다">8. 처음에는 Worktree 없이 시작해도 된다</h2>
<p>Paseo에는 Git Worktree 기능도 있습니다.</p>
<p>각 Agent가 독립적으로 코드를 수정해야 한다면:</p>
<pre><code class="language-text">Main Project

├─ Agent A Worktree
├─ Agent B Worktree
└─ Agent C Worktree</code></pre>
<p>처럼 분리할 수 있습니다.</p>
<p>Paseo가 별도의 Branch와 Directory를 만들어 Agent끼리 같은 파일을 동시에 수정하면서 충돌하는 것을 줄여줍니다.</p>
<p>하지만 처음부터 사용할 필요는 없습니다.</p>
<p>처음에는:</p>
<pre><code class="language-text">하나의 Workspace
+
여러 Agent</code></pre>
<p>정도로 시작하는 것이 이해하기 쉽습니다.</p>
<p>병렬 구현이 필요해졌을 때 Worktree를 추가하면 됩니다.</p>
<hr>
<h2 id="9-paseo에서-가장-먼저-해야-할-것은-agent-profile-만들기다">9. Paseo에서 가장 먼저 해야 할 것은 Agent Profile 만들기다</h2>
<p>Paseo에서 개인적으로 가장 중요한 기능 중 하나가 <code>Agent Profile</code>입니다.</p>
<p>매번:</p>
<pre><code class="language-text">Claude 선택

모델 선택

Thinking 설정

Permission 설정</code></pre>
<p>을 반복하는 대신 역할별 설정을 저장합니다.</p>
<p>예를 들어:</p>
<h3 id="planning">Planning</h3>
<pre><code class="language-text">Provider
Claude

Reasoning
High

When to use
Architecture 설계, 문제 원인 분석,
구현 전에 방향을 정할 때 사용</code></pre>
<h3 id="implementation">Implementation</h3>
<pre><code class="language-text">Provider
Codex

Reasoning
High

When to use
확정된 설계에 따라 실제 코드 수정,
Build와 Test까지 수행</code></pre>
<h3 id="review">Review</h3>
<pre><code class="language-text">Provider
Claude

Reasoning
Medium

When to use
Diff Review,
Bug 가능성,
불필요한 복잡성,
누락된 테스트 확인</code></pre>
<p>Paseo의 Agent Profile에는 Provider, Model, Mode, Thinking Level과 Feature 설정을 저장할 수 있으며 <code>When to use</code> 메모를 Orchestrator가 읽고 작업에 맞는 Profile을 선택할 수 있습니다.</p>
<hr>
<h2 id="10-여기서-말하는-토큰-분배는-조금-다르다">10. 여기서 말하는 ‘토큰 분배’는 조금 다르다</h2>
<p>Paseo가:</p>
<pre><code class="language-text">Claude 30%

Codex 40%

Gemini 30%</code></pre>
<p>처럼 하나의 Token Pool을 비율로 잘라주는 것은 아닙니다.</p>
<p>대신 <strong>비싼 모델을 꼭 필요한 작업에만 사용하도록 역할을 분리</strong>하는 방식입니다.</p>
<p>예를 들면:</p>
<pre><code class="language-text">Architecture
→ Claude / High

Implementation
→ Codex / High

간단한 탐색
→ 저렴한 모델 / Low

Review
→ Claude / Medium

Test
→ Codex / Medium</code></pre>
<p>입니다.</p>
<p>즉:</p>
<pre><code class="language-text">모든 작업
→ 가장 비싼 모델</code></pre>
<p>이 아니라:</p>
<pre><code class="language-text">업무 난이도
       ↓
적절한 Agent
       ↓
적절한 Model
       ↓
적절한 Thinking</code></pre>
<p>으로 나누는 겁니다.</p>
<p>실제로 이게 여러 AI 서비스를 같이 사용하는 팀에서 더 현실적인 비용 관리 방식입니다.</p>
<hr>
<h2 id="11-이제-paseo-tools를-켠다">11. 이제 Paseo Tools를 켠다</h2>
<p>Profile까지 만들었다면 Agent가 다른 Agent를 직접 실행할 수 있게 만듭니다.</p>
<p>Paseo에서:</p>
<pre><code class="language-text">Settings
→ Host
→ Agents
→ Enable Paseo tools</code></pre>
<p>를 활성화합니다.</p>
<p>기본값은 Off입니다.</p>
<p>활성화한 뒤 새 Agent를 시작하거나 기존 Agent를 Reload하면 Paseo Tool을 사용할 수 있습니다.</p>
<p>이제 Main Agent에게 이렇게 요청할 수 있습니다.</p>
<pre><code class="language-text">Paseo Profile을 확인해.

이 기능의 Architecture는 Planning Agent에게 분석시키고,

설계가 끝나면 Implementation Agent에게
구현을 맡겨.

마지막으로 Review Agent에게
독립적인 코드 리뷰를 요청해.

모든 결과를 마지막에 하나로 정리해줘.</code></pre>
<p>여기서부터 진짜 Multi-Agent Workflow가 시작됩니다.</p>
<hr>
<h2 id="12-agent끼리-실제로-역할을-나눌-수-있다">12. Agent끼리 실제로 역할을 나눌 수 있다</h2>
<p>예를 들어 Main Agent에게:</p>
<pre><code class="language-text">회원가입 기능을 추가해야 한다.

먼저 Architecture Agent에게
현재 인증 구조와 변경 범위를 분석하게 해.

파일은 수정하지 않는다.

분석이 끝나면 결과를 가져와서 나에게 보여줘.</code></pre>
<p>라고 합니다.</p>
<p>그러면:</p>
<pre><code class="language-text">Main Agent
      ↓
Planning Agent
      ↓
Repository 분석
      ↓
Architecture 제안
      ↓
Main Agent로 결과 전달</code></pre>
<p>이 됩니다.</p>
<p>그 다음:</p>
<pre><code class="language-text">승인된 설계를 Implementation Profile을 사용하는
Codex Agent에게 넘겨.

구현하고 관련 Unit Test를 실행해.</code></pre>
<p>로 이어갑니다.</p>
<p>Paseo는 Agent 생성뿐 아니라 Agent에게 추가 Prompt를 보내거나 상태를 조회하고, 완료 결과를 확인하는 Tool을 제공합니다.</p>
<hr>
<h2 id="13-병렬-작업은-독립적인-문제에만-사용한다">13. 병렬 작업은 독립적인 문제에만 사용한다</h2>
<p>Multi-Agent라고 무조건 많이 띄우는 것은 좋지 않습니다.</p>
<p>좋은 병렬화:</p>
<pre><code class="language-text">Agent A
→ 현재 Network 구조 조사

Agent B
→ Test 구조 조사

Agent C
→ 관련 Regression 조사</code></pre>
<p>세 작업은 서로 파일을 수정하지 않습니다.</p>
<p>동시에 실행해도 안전합니다.</p>
<p>Paseo 공식 예제에서도 하나는 Request Path를 추적하고, 하나는 Test를 조사하고, 하나는 Regression을 확인한 뒤 결과를 종합하는 Fan-out Workflow를 예로 들고 있습니다.</p>
<p>반대로:</p>
<pre><code class="language-text">Agent A
→ LoginViewModel 수정

Agent B
→ LoginViewModel 수정</code></pre>
<p>을 같은 Directory에서 동시에 돌리면 좋지 않습니다.</p>
<p>이럴 때 Worktree를 씁니다.</p>
<hr>
<h2 id="14-코드-수정이-병렬이라면-worktree를-사용한다">14. 코드 수정이 병렬이라면 Worktree를 사용한다</h2>
<p>예를 들어:</p>
<pre><code class="language-text">Agent A
→ Network Layer Migration

Agent B
→ SwiftUI 화면 Migration

Agent C
→ Unit Test 추가</code></pre>
<p>를 동시에 진행하고 싶다면 각각 독립 Worktree를 만드는 편이 안전합니다.</p>
<p>구조는:</p>
<pre><code class="language-text">origin/main
     │
     ├─ feature/network
     │      └─ Codex
     │
     ├─ feature/ui
     │      └─ Codex
     │
     └─ feature/tests
            └─ Claude</code></pre>
<p>처럼 됩니다.</p>
<p>Paseo가 Workspace를 생성할 때 Worktree Isolation을 지정하면 독립 Branch와 Directory를 만들어줍니다.</p>
<p>Git에 익숙하지 않다면 처음부터 이 기능을 사용할 필요는 없습니다.</p>
<p>여러 Agent가 실제 코드를 동시에 수정해야 할 시점에 추가하면 됩니다.</p>
<hr>
<h2 id="15-paseo-skill도-있다">15. Paseo Skill도 있다</h2>
<p>Agent에게 매번:</p>
<blockquote>
<p>다른 Agent 띄워.</p>
</blockquote>
<p>라고 설명할 필요도 없습니다.</p>
<p>Paseo에는 Orchestration Skill이 있습니다.</p>
<p>대표적으로:</p>
<pre><code class="language-text">/paseo

/paseo-handoff

/paseo-committee

/paseo-advisor</code></pre>
<p>가 있습니다.</p>
<p><code>/paseo-handoff</code></p>
<pre><code class="language-text">현재 작업을
다른 Agent에게 넘기기</code></pre>
<p><code>/paseo-committee</code></p>
<pre><code class="language-text">어려운 문제를
두 Agent에게 독립적으로 분석시키기</code></pre>
<p><code>/paseo-advisor</code></p>
<pre><code class="language-text">현재 구현에 대한
Second Opinion 받기</code></pre>
<p>정도로 이해하면 쉽습니다.</p>
<p>Paseo Settings의 Orchestration Skills에서 설치하거나 CLI에서 설치할 수도 있습니다.</p>
<hr>
<h1 id="여기까지가-paseo의-기본-세팅이다">여기까지가 Paseo의 기본 세팅이다</h1>
<p>정리하면:</p>
<pre><code class="language-text">1. Claude / Codex 설치

2. Paseo 설치

3. Project Workspace 생성

4. Agent Profile 생성

5. Paseo Tools 활성화

6. Main Agent 실행

7. 역할별 Subagent 위임</code></pre>
<p>이 정도만 해도 상당히 쓸 만합니다.</p>
<p>이제 실제 개발 Workflow를 만들어보겠습니다.</p>
<hr>
<h2 id="16-일반적인-개발팀이라면-이렇게-구성해볼-수-있다">16. 일반적인 개발팀이라면 이렇게 구성해볼 수 있다</h2>
<p>개인적으로 처음 구성한다면 Agent를 너무 많이 만들지 않고 세 개 정도로 시작하는 것이 좋습니다.</p>
<pre><code class="language-text">                 Main
                  │
        ┌─────────┼─────────┐
        ↓         ↓         ↓
     Planning   Coding    Review
      Claude    Codex      Claude</code></pre>
<h3 id="planning-agent">Planning Agent</h3>
<p>역할:</p>
<pre><code class="language-text">Architecture 분석

영향 범위 조사

작업 계획

대안 비교</code></pre>
<p>파일 수정은 하지 않습니다.</p>
<h3 id="coding-agent">Coding Agent</h3>
<p>역할:</p>
<pre><code class="language-text">실제 구현

Refactoring

Build

Unit Test</code></pre>
<h3 id="review-agent">Review Agent</h3>
<p>역할:</p>
<pre><code class="language-text">Diff Review

Bug 가능성

Regression

Test 누락

Architecture 위반</code></pre>
<p>중요한 점은 Review Agent가 Implementation Agent와 <strong>다른 Context에서 독립적으로 보는 것</strong>입니다.</p>
<hr>
<h2 id="17-main-agent는-코딩보다-지휘를-담당하게-한다">17. Main Agent는 코딩보다 지휘를 담당하게 한다</h2>
<p>Main Agent까지 직접 코딩하면 Context가 빠르게 커집니다.</p>
<p>그래서 Main Agent는 가능하면:</p>
<pre><code class="language-text">요구사항 이해

Agent 선택

Task 분리

결과 수집

충돌 판단

최종 요약</code></pre>
<p>역할에 집중하게 할 수 있습니다.</p>
<p>구조가 이런 형태가 됩니다.</p>
<pre><code class="language-text">                 Main Agent
                     │
              Task Breakdown
                     │
       ┌─────────────┼─────────────┐
       ↓             ↓             ↓
 Architecture    Implementation   Test
       │             │             │
       └─────────────┼─────────────┘
                     ↓
                   Review
                     ↓
                Main Agent
                     ↓
                 최종 결과</code></pre>
<p>이렇게 하면 하나의 Agent Context가 모든 로그와 코드를 다 먹는 것도 어느 정도 줄일 수 있습니다.</p>
<hr>
<h1 id="18-ios-개발에서는-paseo가-특히-재미있다">18. iOS 개발에서는 Paseo가 특히 재미있다</h1>
<p>iOS 개발 환경에 적용하면 역할을 더 분명하게 나눌 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">                  Paseo
                    │
       ┌────────────┼────────────┐
       ↓            ↓            ↓
    Claude        Codex       Codex
 Architecture   Implementation   QA
       │            │            │
       │            │      XcodeBuildMCP
       │            │            │
       └────────────┼────────────┘
                    ↓
                 Claude
                  Review</code></pre>
<p>여기서 역할은 이렇게 나눌 수 있습니다.</p>
<hr>
<h2 id="19-claude--architecture와-review">19. Claude = Architecture와 Review</h2>
<p>Claude Agent에는:</p>
<pre><code class="language-text">현재 Feature 구조를 분석해.

변경이 필요한 Module과 Dependency를 정리해.

바로 코드를 수정하지 말고
구현 계획과 위험요소만 작성해.</code></pre>
<p>를 맡깁니다.</p>
<p>구현이 끝난 뒤에는 별도의 Claude Review Agent를 띄웁니다.</p>
<pre><code class="language-text">현재 Diff를 독립적으로 Review해.

확인할 것:

- Architecture 위반
- Swift Concurrency 문제
- MainActor 사용
- Retain Cycle
- Error Handling
- 불필요한 복잡성
- Test 누락

파일은 수정하지 말고
문제와 수정 우선순위만 알려줘.</code></pre>
<p>처럼 사용할 수 있습니다.</p>
<hr>
<h2 id="20-codex--실제-구현">20. Codex = 실제 구현</h2>
<p>Architecture가 확정되면 Codex로 넘깁니다.</p>
<pre><code class="language-text">Planning Agent의 설계를 기준으로 구현해.

요청한 범위를 벗어난 Refactoring은 하지 마.

기존 Architecture를 유지하고,

완료 후 Build와 관련 Unit Test를 실행해.

변경 파일과 Test 결과를 요약해.</code></pre>
<p>구조는:</p>
<pre><code class="language-text">Claude
Architecture
    ↓
   Plan
    ↓
Codex
Implementation</code></pre>
<p>입니다.</p>
<p>설계와 구현 Context를 일부러 나눈다는 것이 핵심입니다.</p>
<hr>
<h1 id="21-codex--xcodebuildmcp--simulator--qa">21. Codex + XcodeBuildMCP = Simulator / QA</h1>
<p>여기서 iOS에서는 한 단계 더 갈 수 있습니다.</p>
<p>Codex Agent에 <code>XcodeBuildMCP</code>를 연결합니다.</p>
<p>XcodeBuildMCP는 Xcode Project Discovery, Build/Test, Simulator Boot, 앱 설치·실행, Log Capture, Screenshot, UI hierarchy와 UI Automation 같은 기능을 Agent에게 제공합니다. 최근 구현에서는 <code>tap</code>, <code>swipe</code>, <code>type_text</code> 같은 Simulator Interaction도 지원합니다.</p>
<p>그러면 QA Agent 역할을 따로 만들 수 있습니다.</p>
<pre><code class="language-text">QA Agent
  │
  └─ Codex
       │
       └─ XcodeBuildMCP
              │
              ├─ Build
              ├─ Simulator
              ├─ Launch
              ├─ UI Tree
              ├─ Tap
              ├─ Type
              ├─ Swipe
              ├─ Screenshot
              └─ Logs</code></pre>
<p>이게 iOS 프로젝트에서는 상당히 재미있는 조합입니다.</p>
<hr>
<h2 id="22-qa-agent-profile을-별도로-만든다">22. QA Agent Profile을 별도로 만든다</h2>
<p>Paseo에 다음 Profile을 추가합니다.</p>
<h3 id="ios-qa">iOS QA</h3>
<pre><code class="language-text">Provider
Codex

Thinking
Medium

When to use

iOS Simulator 실행,
Build/Test,
UI Interaction,
Screenshot,
Regression 확인이 필요한 작업.
XcodeBuildMCP를 우선 활용한다.</code></pre>
<p>이제 Main Agent는:</p>
<pre><code class="language-text">구현이 끝났으면
iOS QA Profile을 사용해서
Simulator 검증을 실행해.</code></pre>
<p>라고 위임할 수 있습니다.</p>
<hr>
<h2 id="23-실제-ios-workflow는-이렇게-된다">23. 실제 iOS Workflow는 이렇게 된다</h2>
<p>예를 들어 상품 상세 화면을 수정한다고 해보겠습니다.</p>
<h3 id="1단계">1단계</h3>
<p>Claude:</p>
<pre><code class="language-text">현재 ProductDetail 구조를 분석하고
변경 계획만 작성.</code></pre>
<h3 id="2단계">2단계</h3>
<p>Codex:</p>
<pre><code class="language-text">승인된 Plan을 구현하고
Unit Test 실행.</code></pre>
<h3 id="3단계">3단계</h3>
<p>QA Codex:</p>
<pre><code class="language-text">Simulator에서 앱을 실행.

상품 목록 진입.

첫 번째 상품 선택.

상세 화면 확인.

스크롤.

구매 버튼 확인.

Screenshot 저장.

Console Warning과 Crash 확인.</code></pre>
<h3 id="4단계">4단계</h3>
<p>Claude:</p>
<pre><code class="language-text">Diff와 QA 결과를 같이 보고
최종 Review.</code></pre>
<p>전체로 보면:</p>
<pre><code class="language-text">Requirement
    ↓
Claude
Architecture
    ↓
Codex
Implementation
    ↓
Codex + XcodeBuildMCP
Simulator QA
    ↓
Claude
Review
    ↓
Developer</code></pre>
<p>입니다.</p>
<hr>
<h2 id="24-iphone-duo-qa에도-그대로-확장할-수-있다">24. iPhone Duo QA에도 그대로 확장할 수 있다</h2>
<p>최근 이야기했던 iPhone Duo처럼 화면 상태가 많아지는 환경에서는 더 유용합니다.</p>
<pre><code class="language-text">Closed

Open

Folded

Rotated</code></pre>
<p>상태에서:</p>
<pre><code class="language-text">Layout

Navigation

Safe Area

ReservedRegion

Scroll

Button Interaction</code></pre>
<p>을 반복해서 확인해야 하기 때문입니다.</p>
<p>Paseo 구조에서는:</p>
<pre><code class="language-text">Claude
→ Duo Migration 설계

Codex
→ UI Migration 구현

Codex + XcodeBuildMCP
→ Simulator QA

Claude
→ Diff + QA 결과 Review</code></pre>
<p>처럼 역할을 분리할 수 있습니다.</p>
<p>즉 Paseo가 Simulator를 직접 제어하는 것이 아닙니다.</p>
<p><strong>Paseo가 QA 담당 Codex를 관리하고, Codex가 XcodeBuildMCP를 이용해서 Simulator를 제어하는 구조</strong>입니다.</p>
<p>이 구분은 중요합니다.</p>
<hr>
<h2 id="25-qa-결과는-agent에게-반드시-구조화해서-받는-게-좋다">25. QA 결과는 Agent에게 반드시 구조화해서 받는 게 좋다</h2>
<p>QA Agent가:</p>
<blockquote>
<p>테스트했습니다. 이상 없습니다.</p>
</blockquote>
<p>라고 끝내면 의미가 없습니다.</p>
<p>처음부터 Output 형식을 지정합니다.</p>
<pre><code class="language-text">Scenario

Home → Product → Detail

Simulator

iPhone Duo / iOS 27.1

Result

PASS / FAIL

Checks

Layout
Navigation
Interaction
Warnings
Crash

Evidence

Screenshot Path

Finding

발견된 문제

Recommendation

수정 제안</code></pre>
<p>이렇게 받으면 Main Agent가 결과를 다시 Review Agent에게 전달하기도 쉬워집니다.</p>
<hr>
<h2 id="26-agent를-너무-많이-만들면-오히려-손해다">26. Agent를 너무 많이 만들면 오히려 손해다</h2>
<p>Multi-Agent 이야기를 하면:</p>
<pre><code class="language-text">Planning Agent

Research Agent

UI Agent

Network Agent

DB Agent

Test Agent

QA Agent

Review Agent

Security Agent</code></pre>
<p>처럼 만들고 싶어집니다.</p>
<p>하지만 이렇게 시작하면 Agent 관리가 새로운 일이 됩니다.</p>
<p>처음에는:</p>
<pre><code class="language-text">Planning

Implementation

Review</code></pre>
<p>세 개 정도면 충분합니다.</p>
<p>iOS라면:</p>
<pre><code class="language-text">Planning

Implementation

Simulator QA

Review</code></pre>
<p>정도가 현실적입니다.</p>
<p>독립적인 Reasoning이 필요한 경우에만 Agent를 나누는 편이 좋습니다.</p>
<hr>
<h2 id="27-agent보다-skill이-더-적합한-작업도-있다">27. Agent보다 Skill이 더 적합한 작업도 있다</h2>
<p>반복되는 절차라고 모두 Agent를 만들 필요는 없습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Release Checklist

Swift 6 Migration Rule

PR 작성 규칙

Lint 실행

Build 명령</code></pre>
<p>같은 작업은 독립적인 Agent보다 Skill이나 Project Instruction이 더 적합할 수 있습니다.</p>
<p>반면:</p>
<pre><code class="language-text">Architecture 분석

독립 Code Review

Root Cause 조사

Simulator QA</code></pre>
<p>처럼 별도의 Context에서 판단해야 하는 작업은 Agent로 분리할 가치가 있습니다.</p>
<p>기준은:</p>
<pre><code class="language-text">정해진 절차
→ Skill

독립적인 판단
→ Agent</code></pre>
<p>정도로 시작하면 이해하기 쉽습니다.</p>
<hr>
<h2 id="28-보안과-permission도-profile별로-나누는-게-좋다">28. 보안과 Permission도 Profile별로 나누는 게 좋다</h2>
<p>모든 Agent에게 동일한 권한을 줄 필요도 없습니다.</p>
<p>예를 들어 Review Agent는:</p>
<pre><code class="language-text">Read
→ 허용

Code Write
→ 제한</code></pre>
<p>할 수 있습니다.</p>
<p>Implementation Agent는:</p>
<pre><code class="language-text">Workspace Write
→ 허용</code></pre>
<p>QA Agent는:</p>
<pre><code class="language-text">Build
Simulator
Test</code></pre>
<p>정도만 필요할 수 있습니다.</p>
<p>Paseo는 Provider의 Native Sandbox나 Permission Option을 전달할 수 있지만, 공식 문서에서도 이 설정 자체가 Host Security Boundary를 대신하는 것은 아니라고 설명합니다. 민감한 작업이나 신뢰하지 않는 코드라면 Container나 별도 Machine을 사용하는 편이 안전합니다.</p>
<hr>
<h2 id="29-paseo를-쓰면-agent를-휴대폰에서도-확인할-수-있다">29. Paseo를 쓰면 Agent를 휴대폰에서도 확인할 수 있다</h2>
<p>Paseo는 Desktop뿐 아니라 Mobile, Web, CLI Client를 제공합니다.</p>
<p>Desktop Agent가 긴 작업을 하고 있다면 휴대폰에서:</p>
<pre><code class="language-text">Agent 상태 확인

결과 확인

추가 Prompt

작업 중단</code></pre>
<p>같은 작업을 할 수 있습니다.</p>
<p>Paseo는 Local Machine에서 Agent를 실행하고 Client가 daemon에 연결하는 구조이며 Mobile Device도 Pairing할 수 있습니다.</p>
<p>긴 Build나 Test를 많이 하는 개발자에게는 의외로 편한 부분입니다.</p>
<hr>
<h2 id="30-처음-paseo를-도입한다면-이-구성부터-추천한다">30. 처음 Paseo를 도입한다면 이 구성부터 추천한다</h2>
<p>처음부터 복잡하게 만들 필요는 없습니다.</p>
<h3 id="profile-1--architect">Profile 1 — Architect</h3>
<pre><code class="language-text">Claude

High Reasoning

Architecture / Planning</code></pre>
<h3 id="profile-2--developer">Profile 2 — Developer</h3>
<pre><code class="language-text">Codex

High Reasoning

Implementation</code></pre>
<h3 id="profile-3--reviewer">Profile 3 — Reviewer</h3>
<pre><code class="language-text">Claude

Medium Reasoning

Independent Review</code></pre>
<p>iOS라면 하나 더 추가합니다.</p>
<h3 id="profile-4--ios-qa">Profile 4 — iOS QA</h3>
<pre><code class="language-text">Codex

Medium Reasoning

XcodeBuildMCP
Simulator
Test
Screenshot
Logs</code></pre>
<p>그리고 Main Agent에게 이렇게 말합니다.</p>
<pre><code class="language-text">Paseo Agent Profile을 확인해.

먼저 Architect에게 이 작업을 분석시켜.

설계가 끝나면 Developer에게 구현을 맡겨.

구현 후 iOS QA Agent가
Build와 Simulator 검증을 수행하게 해.

마지막으로 Reviewer가
Diff와 QA 결과를 독립적으로 검토하게 해.

각 단계 결과를 마지막에 하나로 정리해.</code></pre>
<p>이 정도면 Paseo를 쓰는 이유가 꽤 명확하게 느껴집니다.</p>
<hr>
<h2 id="31-가장-중요한-건-agent-숫자가-아니다">31. 가장 중요한 건 Agent 숫자가 아니다</h2>
<p>Paseo를 사용한다고 Agent를 많이 띄우는 것이 목적은 아닙니다.</p>
<p>중요한 것은:</p>
<pre><code class="language-text">누가 계획하는가

누가 구현하는가

누가 검증하는가

누가 최종적으로 책임지는가</code></pre>
<p>를 분리할 수 있다는 점입니다.</p>
<p>특히 모델마다 장점이 조금씩 다르다면:</p>
<pre><code class="language-text">Claude의 장점
→ Architecture / Review

Codex의 장점
→ Implementation / Tool Execution

XcodeBuildMCP
→ Build / Simulator / QA</code></pre>
<p>처럼 역할을 배치할 수 있습니다.</p>
<p>결국 Paseo의 가치는 새로운 AI 모델을 하나 더 쓰는 데 있는 것이 아니라,</p>
<p><strong>이미 사용하는 여러 Coding Agent를 하나의 개발팀처럼 구성할 수 있다는 데 있습니다.</strong></p>
<hr>
<h2 id="마치며">마치며</h2>
<p>지금까지 Coding Agent를 사용하는 방식은 대부분:</p>
<pre><code class="language-text">Developer
    ↓
Agent</code></pre>
<p>였습니다.</p>
<p>하지만 Agent가 여러 개가 되기 시작하면 구조가 달라집니다.</p>
<pre><code class="language-text">                    Developer
                        ↓
                      Paseo
                        ↓
          ┌─────────────┼─────────────┐
          ↓             ↓             ↓
       Claude         Codex         Codex
     Architecture  Implementation     QA
          │             │             │
          └─────────────┼─────────────┘
                        ↓
                     Claude
                      Review</code></pre>
<p>특히 iOS 개발이라면:</p>
<p><strong>Claude = 설계와 Review</strong></p>
<p><strong>Codex = 실제 구현</strong></p>
<p><strong>Codex + XcodeBuildMCP = Simulator와 QA</strong></p>
<p>정도로 역할을 나누는 구성이 상당히 실용적입니다.</p>
<p>그리고 모든 작업에 가장 큰 모델을 사용하는 대신:</p>
<pre><code class="language-text">어려운 설계
→ 비싼 Reasoning

구현
→ Coding Agent

반복 QA
→ 적절한 Agent + Tool

간단한 조사
→ 저렴한 Model</code></pre>
<p>처럼 분산하면 Agent를 여러 개 쓰는 이유가 훨씬 분명해집니다.</p>
<p>Multi-Agent의 핵심은 Agent를 많이 만드는 것이 아닙니다.</p>
<p><strong>각 Agent에게 독립적으로 판단할 가치가 있는 일을 나누고, 그 결과를 다시 하나의 Workflow로 연결하는 것.</strong></p>
<p>Paseo는 바로 그 연결부에 있는 도구입니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/f468e05a-057f-4a8f-bdf3-d93537569373/image.png" alt=""></p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>Paseo — Getting Started</strong><br>Desktop App, CLI, daemon, Mobile Pairing과 기본 설치 방법을 설명합니다.<br><a href="https://paseo.sh/docs">Paseo 시작하기</a></p>
</li>
<li><p><strong>Paseo — Providers</strong><br>Claude Code, Codex 등 기존 Agent CLI를 Paseo가 어떻게 실행하고 관리하는지 설명합니다.<br><a href="https://paseo.sh/docs/providers">Paseo Providers</a></p>
</li>
<li><p><strong>Paseo — Supported Providers</strong><br>Claude Code, Codex 등의 Native Provider와 Gemini CLI, GitHub Copilot 등 ACP Catalog를 확인할 수 있습니다.<br><a href="https://paseo.sh/docs/supported-providers">지원 Agent 목록</a></p>
</li>
<li><p><strong>Paseo — Agent Profiles</strong><br>Provider, Model, Mode, Thinking Level과 역할 설명을 Profile로 저장하는 방법입니다.<br><a href="https://paseo.sh/docs/agent-profiles">Agent Profiles</a></p>
</li>
<li><p><strong>Paseo — Orchestration</strong><br>한 Agent가 다른 Agent를 생성하고 작업을 위임하고 결과를 모으는 핵심 기능입니다.<br><a href="https://paseo.sh/docs/orchestration">Paseo Orchestration</a></p>
</li>
<li><p><strong>Paseo — Common Orchestration Workflows</strong><br>구현 위임, 독립 Review, Parallel Research 같은 실전 예제가 있습니다.<br><a href="https://paseo.sh/docs/orchestration-workflows">Orchestration Workflow</a></p>
</li>
<li><p><strong>Paseo — Git Worktrees</strong><br>여러 Agent가 병렬로 코드를 수정할 때 독립적인 Workspace를 구성하는 방법입니다.<br><a href="https://paseo.sh/docs/worktrees">Paseo Worktrees</a></p>
</li>
<li><p><strong>Paseo — Orchestration Skills</strong><br>Handoff, Committee, Advisor 등 반복 가능한 Multi-Agent Workflow를 제공합니다.<br><a href="https://paseo.sh/docs/skills">Paseo Skills</a></p>
</li>
<li><p><strong>XcodeBuildMCP</strong><br>Build, Test, Simulator, UI Automation, Screenshot, Log 등 iOS 개발을 AI Agent와 연결하기 위한 MCP Server입니다.<br><a href="https://github.com/getsentry/XcodeBuildMCP">XcodeBuildMCP</a></p>
</li>
</ul>
<p>공식 자료 기준으로 보면 Paseo의 핵심은 자체 모델이 아니라 <strong>Provider·Workspace·Agent Profile·Orchestration을 이용해 여러 Coding Agent를 하나의 작업 흐름으로 묶는 것</strong>입니다. 처음에는 Claude/Codex 두 Provider와 Planning·Implementation·Review 정도의 Profile만 만들어도 충분하고, iOS 프로젝트라면 그다음 단계로 XcodeBuildMCP 기반 Simulator QA Agent를 붙이는 방식이 가장 이해하기 쉽습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클린 아키텍처가 뭐길래]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609203</link>
            <guid>https://velog.io/@kyu_ios_dev/2609203</guid>
            <pubDate>Sun, 20 Sep 2026 06:17:00 GMT</pubDate>
            <description><![CDATA[<h3 id="클린-아키텍처가-뭐길래">클린 아키텍처가 뭐길래</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/a6e0d284-8a01-4ea9-820c-4c574b9cd130/image.png" alt=""></p>
<h2 id="ai가-코드를-만드는-시대에는-어떻게-설계하고-관리해야-할까">AI가 코드를 만드는 시대에는 어떻게 설계하고 관리해야 할까</h2>
<p>개발을 시작한 지 얼마 되지 않았을 때 <code>Clean Architecture</code>를 검색하면 이런 그림을 자주 만나게 됩니다.</p>
<pre><code class="language-text">Entities
   ↑
Use Cases
   ↑
Interface Adapters
   ↑
Frameworks &amp; Drivers</code></pre>
<p>동그라미가 여러 개 있고,</p>
<p><code>Domain</code>, <code>Repository</code>, <code>UseCase</code>, <code>Presentation</code> 같은 단어가 등장합니다.</p>
<p>그래서 처음에는 이렇게 생각하기 쉽습니다.</p>
<blockquote>
<p>폴더를 저렇게 나누면 클린 아키텍처인가?</p>
</blockquote>
<p>하지만 클린 아키텍처의 핵심은 폴더 구조가 아닙니다.</p>
<p>더 단순하게 표현하면 이겁니다.</p>
<p><strong>바뀌기 쉬운 코드가 중요한 코드를 흔들지 못하게 만드는 것.</strong></p>
<p>그리고 AI가 코드를 빠르게 만들어주는 시대에는 오히려 이 원칙이 더 중요해지고 있습니다.</p>
<hr>
<h2 id="1-클린-아키텍처는-왜-만들어졌을까">1. 클린 아키텍처는 왜 만들어졌을까</h2>
<p>앱을 처음 만들 때는 구조가 단순합니다.</p>
<p>예를 들어 사용자 정보를 가져온다고 해보겠습니다.</p>
<pre><code class="language-swift">final class ProfileViewModel {

    func loadProfile() async {
        let url = URL(string: &quot;https://api.example.com/profile&quot;)!

        let (data, _) = try! await URLSession.shared.data(from: url)

        let user = try! JSONDecoder().decode(User.self, from: data)

        name = user.name
    }
}</code></pre>
<p>작은 앱에서는 별 문제가 없습니다.</p>
<p>하지만 기능이 늘기 시작합니다.</p>
<pre><code class="language-text">ProfileViewModel
 ├─ API 호출
 ├─ JSON Parsing
 ├─ Cache
 ├─ 로그인 상태 확인
 ├─ Analytics
 ├─ Error 처리
 └─ 화면 상태 관리</code></pre>
<p>어느 순간 <code>ViewModel</code> 하나가 모든 것을 알고 있습니다.</p>
<p>API가 바뀌어도 수정해야 하고,</p>
<p>Cache를 바꿔도 수정해야 하고,</p>
<p>테스트를 작성하려 해도 실제 Network가 필요합니다.</p>
<p>이때 생기는 질문이 있습니다.</p>
<blockquote>
<p>화면 코드가 왜 서버 구현 방법까지 알아야 하지?</p>
</blockquote>
<p>클린 아키텍처는 여기서 시작합니다.</p>
<hr>
<h2 id="2-핵심은-dependency-rule-하나다">2. 핵심은 Dependency Rule 하나다</h2>
<p>클린 아키텍처에서 가장 중요한 규칙은 사실 복잡하지 않습니다.</p>
<p><strong>의존성은 중요한 정책 쪽으로 향해야 합니다.</strong></p>
<p>쉽게 그리면:</p>
<pre><code class="language-text">UI
 ↓
UseCase
 ↓
Domain</code></pre>
<p>그리고 외부 시스템은 반대편에 있습니다.</p>
<pre><code class="language-text">API
Database
Firebase
Framework</code></pre>
<p>Domain이 이런 것들을 직접 알게 만들지 않습니다.</p>
<p>즉:</p>
<pre><code class="language-text">Domain → Firebase</code></pre>
<p>보다</p>
<pre><code class="language-text">Firebase
   ↓
Repository 구현
   ↓
Domain Interface</code></pre>
<p>가 되는 구조입니다.</p>
<p>Robert C. Martin이 설명한 Clean Architecture 역시 UI, Database, Framework와 핵심 Business Rule을 분리하고 Source Code Dependency가 안쪽의 정책을 향하도록 하는 것이 중심입니다.</p>
<hr>
<h2 id="3-처음부터-4개의-거대한-layer를-만들-필요는-없다">3. 처음부터 4개의 거대한 Layer를 만들 필요는 없다</h2>
<p>주니어 개발자가 가장 많이 하는 실수 중 하나입니다.</p>
<p>클린 아키텍처를 배웠다고 바로:</p>
<pre><code class="language-text">Presentation

Domain

Data

Infrastructure

Core

Common

Shared

Network

Repository</code></pre>
<p>를 만듭니다.</p>
<p>그리고 파일 하나를 추가하려고 해도:</p>
<pre><code class="language-text">DTO
Mapper
Entity
Repository
RepositoryImpl
UseCase
Protocol
ViewModel</code></pre>
<p>이 필요해집니다.</p>
<p>이건 Clean한 것이 아니라 <strong>복잡한 것</strong>일 수 있습니다.</p>
<p>클린 아키텍처에서 중요한 것은 Layer 개수가 아닙니다.</p>
<p>실제로 원래 Clean Architecture에서도 정확히 네 개의 원을 반드시 사용해야 한다는 규칙은 없습니다.</p>
<p>중요한 것은:</p>
<pre><code class="language-text">무엇이 자주 바뀌는가?

무엇이 오래 유지되어야 하는가?

어느 쪽이 어느 쪽을 알아야 하는가?</code></pre>
<p>입니다.</p>
<hr>
<h2 id="4-주니어라면-세-덩어리부터-이해하면-된다">4. 주니어라면 세 덩어리부터 이해하면 된다</h2>
<p>앱에서는 처음에 이 정도만 구분해도 충분합니다.</p>
<pre><code class="language-text">Presentation

Domain

Data</code></pre>
<h3 id="presentation">Presentation</h3>
<p>화면과 사용자 Interaction입니다.</p>
<pre><code class="language-text">SwiftUI View
UIKit ViewController
ViewModel
UI State
Navigation</code></pre>
<h3 id="domain">Domain</h3>
<p>앱이 실제로 해야 하는 일입니다.</p>
<pre><code class="language-text">Entity
UseCase
Business Rule
Repository Protocol</code></pre>
<h3 id="data">Data</h3>
<p>데이터를 실제로 가져오는 방법입니다.</p>
<pre><code class="language-text">API
Database
Cache
DTO
Repository Implementation</code></pre>
<p>흐름은:</p>
<pre><code class="language-text">View
 ↓
ViewModel
 ↓
UseCase
 ↓
Repository Protocol
 ↑
Repository Implementation
 ↓
API / DB</code></pre>
<p>정도면 됩니다.</p>
<hr>
<h2 id="5-예제로-보면-훨씬-쉽다">5. 예제로 보면 훨씬 쉽다</h2>
<p>쇼핑 앱에 상품을 가져오는 기능이 있다고 해보겠습니다.</p>
<p>먼저 Domain입니다.</p>
<pre><code class="language-swift">struct Product {
    let id: String
    let name: String
    let price: Int
}</code></pre>
<p>그리고 Repository의 역할만 정의합니다.</p>
<pre><code class="language-swift">protocol ProductRepository {
    func fetchProducts() async throws -&gt; [Product]
}</code></pre>
<p>Domain은 상품이 어디에서 오는지 모릅니다.</p>
<pre><code class="language-text">REST API인지

GraphQL인지

Firebase인지

Local DB인지</code></pre>
<p>알 필요가 없습니다.</p>
<hr>
<h2 id="6-실제-api-구현은-data-layer에-둔다">6. 실제 API 구현은 Data Layer에 둔다</h2>
<pre><code class="language-swift">final class RemoteProductRepository: ProductRepository {

    private let apiClient: APIClient

    init(apiClient: APIClient) {
        self.apiClient = apiClient
    }

    func fetchProducts() async throws -&gt; [Product] {

        let response: ProductResponse =
            try await apiClient.request(&quot;/products&quot;)

        return response.items.map {
            Product(
                id: $0.id,
                name: $0.title,
                price: $0.price
            )
        }
    }
}</code></pre>
<p>여기에는:</p>
<pre><code class="language-text">APIClient

JSON

DTO

Endpoint</code></pre>
<p>가 있어도 됩니다.</p>
<p>왜냐하면 이 영역 자체가 <strong>외부 시스템과 연결하는 영역</strong>이기 때문입니다.</p>
<hr>
<h2 id="7-usecase에는-앱의-의도를-넣는다">7. UseCase에는 앱의 의도를 넣는다</h2>
<pre><code class="language-swift">struct FetchProductsUseCase {

    let repository: ProductRepository

    func execute() async throws -&gt; [Product] {
        try await repository.fetchProducts()
    }
}</code></pre>
<p>지금은 너무 단순해 보입니다.</p>
<p>그래서 이런 생각이 들 수 있습니다.</p>
<blockquote>
<p>Repository를 그냥 ViewModel에서 부르면 안 되나?</p>
</blockquote>
<p>물론 됩니다.</p>
<p>UseCase가 아무 역할도 하지 않는다면 굳이 만들 필요 없습니다.</p>
<p>하지만 나중에 요구사항이 이렇게 바뀐다면 이야기가 달라집니다.</p>
<pre><code class="language-text">판매 중인 상품만 노출

재고 없는 상품 제외

사용자 등급별 가격 계산

차단 상품 제거

추천순 정렬</code></pre>
<p>이건 API의 책임도 아니고 UI의 책임도 아닙니다.</p>
<p><strong>앱이 수행해야 할 Business Rule</strong>입니다.</p>
<p>이때 UseCase의 존재 이유가 생깁니다.</p>
<hr>
<h2 id="8-클린-아키텍처는-코드-정리가-아니라-변경을-관리하는-방법이다">8. 클린 아키텍처는 코드 정리가 아니라 변경을 관리하는 방법이다</h2>
<p>여기서 가장 중요한 부분입니다.</p>
<p>클린 아키텍처를:</p>
<blockquote>
<p>코드를 예쁘게 정리하는 방법</p>
</blockquote>
<p>으로 이해하면 계속 헷갈립니다.</p>
<p>실제로는:</p>
<p><strong>변경의 영향 범위를 제한하는 방법</strong></p>
<p>에 가깝습니다.</p>
<p>예를 들어 서버가:</p>
<pre><code class="language-text">REST
↓
GraphQL</code></pre>
<p>로 변경됐다고 해봅시다.</p>
<p>잘 분리되어 있다면:</p>
<pre><code class="language-text">Data Layer</code></pre>
<p>를 주로 수정하면 됩니다.</p>
<p>UI가:</p>
<pre><code class="language-text">UIKit
↓
SwiftUI</code></pre>
<p>로 바뀌어도 Domain은 대부분 그대로 남을 수 있습니다.</p>
<p>Database가:</p>
<pre><code class="language-text">Core Data
↓
SwiftData</code></pre>
<p>로 바뀌어도 Business Rule까지 같이 뜯어고칠 이유는 없습니다.</p>
<p>좋은 Architecture의 목적은 <strong>변화를 없애는 것이 아니라 변화가 퍼지는 것을 막는 것</strong>입니다.</p>
<hr>
<h1 id="그런데-ai-시대에는-무엇이-달라졌을까">그런데 AI 시대에는 무엇이 달라졌을까</h1>
<p>여기부터가 지금 더 중요한 이야기입니다.</p>
<p>예전에는 개발자가 직접 대부분의 코드를 작성했습니다.</p>
<p>지금은 Codex, Claude Code 같은 Coding Agent에게:</p>
<pre><code class="language-text">로그인 기능 만들어줘.

Repository 추가해줘.

Unit Test 만들어줘.

이 화면 SwiftUI로 바꿔줘.</code></pre>
<p>라고 요청할 수 있습니다.</p>
<p>앞으로 AI가 작성하는 코드의 비율은 더 높아질 가능성이 있습니다.</p>
<p>그런데 여기서 새로운 문제가 발생합니다.</p>
<hr>
<h2 id="9-ai는-코드를-빨리-만들지만-프로젝트의-의도까지-자동으로-알지는-못한다">9. AI는 코드를 빨리 만들지만 프로젝트의 의도까지 자동으로 알지는 못한다</h2>
<p>예를 들어 프로젝트가 이렇게 되어 있다고 합시다.</p>
<pre><code class="language-text">Features/
Domain/
Data/
Core/</code></pre>
<p>개발자에게는 암묵적인 규칙이 있습니다.</p>
<pre><code class="language-text">View에서 Repository 직접 호출 금지

Domain에서 UIKit import 금지

DTO를 Presentation으로 전달 금지

Feature끼리 직접 참조 금지

Network는 Data Layer에서만 사용</code></pre>
<p>그런데 AI에게 아무 설명도 하지 않고:</p>
<blockquote>
<p>상품 상세 화면 추가해줘.</p>
</blockquote>
<p>라고 하면 AI가 가장 빠른 방법으로:</p>
<pre><code class="language-swift">struct ProductDetailView: View {

    func load() async {
        URLSession.shared...
    }
}</code></pre>
<p>를 만들 수도 있습니다.</p>
<p>코드는 동작합니다.</p>
<p>하지만 Architecture는 조금씩 무너지기 시작합니다.</p>
<p>AI 시대에는 이 문제가 더 빠르게 발생할 수 있습니다.</p>
<p>사람이 하루에 300줄을 만들던 프로젝트에서 Agent들이 훨씬 많은 코드를 생성하기 시작하면, <strong>잘못된 설계 역시 더 빠르게 복제될 수 있기 때문입니다.</strong></p>
<hr>
<h2 id="10-그래서-architecture를-사람-머릿속에만-두면-안-된다">10. 그래서 Architecture를 사람 머릿속에만 두면 안 된다</h2>
<p>예전에는 팀의 시니어 개발자가 알고 있으면 어느 정도 운영이 됐습니다.</p>
<pre><code class="language-text">&quot;여기서는 그렇게 만들면 안 돼.&quot;

&quot;Repository 하나 만들어야 해.&quot;

&quot;Domain에서 UIKit 쓰면 안 돼.&quot;</code></pre>
<p>PR Review에서 알려주면 됐습니다.</p>
<p>AI Agent에게는 이 방법이 잘 통하지 않습니다.</p>
<p>그래서 Architecture를 <strong>명시적인 프로젝트 규칙</strong>으로 만들어야 합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">ARCHITECTURE.md</code></pre>
<p>를 만듭니다.</p>
<pre><code class="language-markdown"># Architecture

Presentation
- SwiftUI / UIKit
- ViewModel
- UI State

Domain
- Entity
- UseCase
- Repository Protocol

Data
- Repository Implementation
- API / DB
- DTO

## Dependency Rules

Presentation → Domain 허용

Data → Domain 허용

Domain → Presentation 금지

Domain → Data 금지</code></pre>
<p>사람에게도 좋은 문서지만 AI에게는 더 중요합니다.</p>
<hr>
<h2 id="11-agentsmd와-claudemd는-architecture-문서가-아니다">11. AGENTS.md와 CLAUDE.md는 Architecture 문서가 아니다</h2>
<p>Codex에서는 프로젝트에 <code>AGENTS.md</code>를 둘 수 있고, Claude Code에서는 <code>CLAUDE.md</code> 같은 프로젝트 지침을 사용할 수 있습니다.</p>
<p>여기에 Build, Test, Coding Convention, Repository 규칙 등을 넣어 Agent가 작업을 시작할 때 참고하게 할 수 있습니다.</p>
<p>하지만 중요한 점이 있습니다.</p>
<p><code>AGENTS.md</code>에 Architecture 전체를 복사해 넣는 것이 좋은 방법은 아닙니다.</p>
<p>오히려:</p>
<pre><code class="language-text">AGENTS.md
      ↓
Architecture Map

ARCHITECTURE.md
      ↓
설계 원칙

docs/
      ↓
상세 설계

Tests / Lint
      ↓
규칙 검증</code></pre>
<p>처럼 역할을 나누는 편이 좋습니다.</p>
<p>OpenAI도 현재 Codex 프로젝트 지침에서 <code>AGENTS.md</code>를 간결하게 유지하고 Build/Test/Review 규칙과 Repository별 관습을 명시하는 방식을 권장하며, 더 큰 프로젝트에서는 이를 상세 문서로 연결하는 일종의 목차처럼 사용하는 방식을 소개하고 있습니다.</p>
<p>Claude Code 역시 <code>CLAUDE.md</code>를 매 세션 읽는 Project Instruction으로 사용하고, 특정 작업용 규칙은 Rules나 Skills 등으로 분리할 수 있습니다.</p>
<p>즉 AI 시대의 Architecture는 이제:</p>
<pre><code class="language-text">코드 구조
+
문서
+
AI Instruction
+
자동 검증</code></pre>
<p>까지 같이 봐야 합니다.</p>
<hr>
<h2 id="12-ai에게-가장-먼저-알려줘야-하는-것은-기술-스택이-아니다">12. AI에게 가장 먼저 알려줘야 하는 것은 기술 스택이 아니다</h2>
<p>이런 Instruction은 흔합니다.</p>
<pre><code class="language-text">Swift 6 사용

SwiftUI 사용

async/await 사용

MVVM 사용</code></pre>
<p>물론 필요합니다.</p>
<p>하지만 Architecture를 유지하려면 더 중요한 규칙이 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">## Architecture Rules

1. View는 UseCase만 호출한다.

2. Domain Layer에서는
   SwiftUI, UIKit, URLSession을 import하지 않는다.

3. API Response DTO는
   Presentation Layer까지 전달하지 않는다.

4. Repository Protocol은 Domain에 둔다.

5. Repository 구현은 Data에 둔다.

6. 새로운 Dependency를 추가하기 전에
   기존 구현으로 해결 가능한지 확인한다.

7. 새로운 Layer를 임의로 만들지 않는다.

8. Architecture 변경이 필요하면
   구현 전에 변경 이유를 먼저 설명한다.</code></pre>
<p>이런 내용이 훨씬 중요합니다.</p>
<p>AI에게:</p>
<blockquote>
<p>어떻게 코딩할 것인가</p>
</blockquote>
<p>뿐 아니라</p>
<blockquote>
<p><strong>어디까지 변경해도 되는가</strong></p>
</blockquote>
<p>를 알려주는 것입니다.</p>
<hr>
<h2 id="13-architecture-rule은-가능하면-코드로-검증해야-한다">13. Architecture Rule은 가능하면 코드로 검증해야 한다</h2>
<p>문서만 있다고 Architecture가 유지되는 것은 아닙니다.</p>
<p>사람도 문서를 잊고 AI도 실수합니다.</p>
<p>그래서 가능하면 규칙을 자동화합니다.</p>
<p>예를 들어 Domain Module에:</p>
<pre><code class="language-swift">import UIKit</code></pre>
<p>이 들어가면 Build나 Lint 단계에서 잡도록 만들 수 있습니다.</p>
<p>Module Dependency도:</p>
<pre><code class="language-text">Presentation
    ↓
Domain
    ↑
Data</code></pre>
<p>만 허용하도록 구성할 수 있습니다.</p>
<p>즉:</p>
<pre><code class="language-text">&quot;이렇게 해주세요&quot;</code></pre>
<p>보다</p>
<pre><code class="language-text">&quot;이렇게 하지 않으면 Build가 실패합니다&quot;</code></pre>
<p>가 훨씬 강합니다.</p>
<p>AI 시대에는 특히 그렇습니다.</p>
<p>좋은 구조는 AI가 매번 완벽한 판단을 해야 유지되는 구조가 아니라,</p>
<p><strong>잘못된 코드를 만들어도 시스템이 잡아주는 구조</strong>입니다.</p>
<hr>
<h2 id="14-unit-test의-의미도-조금-달라진다">14. Unit Test의 의미도 조금 달라진다</h2>
<p>예전에는 테스트를:</p>
<blockquote>
<p>사람이 코드를 수정하다 실수하는 것을 막는다.</p>
</blockquote>
<p>정도로 생각했습니다.</p>
<p>Agent가 코드를 직접 수정하는 환경에서는 테스트가 하나의 <strong>작업 경계</strong>가 됩니다.</p>
<pre><code class="language-text">AI 코드 수정
    ↓
Build
    ↓
Unit Test
    ↓
Architecture Test
    ↓
UI Test
    ↓
Review</code></pre>
<p>AI에게:</p>
<blockquote>
<p>로그인 로직 수정해줘.</p>
</blockquote>
<p>라고 말할 때</p>
<p>기대하는 것은 단순히 코드가 생성되는 것이 아닙니다.</p>
<pre><code class="language-text">기존 Test 통과

새 Requirement Test 추가

Architecture Rule 유지

Regression 없음</code></pre>
<p>까지 확인되는 것입니다.</p>
<p>그래서 앞으로는 <strong>테스트가 많은 프로젝트일수록 Agent에게 일을 맡기기 쉬운 프로젝트</strong>가 될 가능성이 큽니다.</p>
<hr>
<h2 id="15-ai에게-큰-기능을-한-번에-맡기지-않는다">15. AI에게 큰 기능을 한 번에 맡기지 않는다</h2>
<p>예를 들어 이런 요청은 위험합니다.</p>
<pre><code class="language-text">쇼핑몰 앱 결제 기능 전체를 구현해줘.</code></pre>
<p>범위가 너무 큽니다.</p>
<p>대신 Architecture Boundary를 기준으로 나눕니다.</p>
<pre><code class="language-text">1. 요구사항 분석

2. Domain Model 제안

3. UseCase 설계

4. Repository Protocol 설계

5. Data 구현

6. Presentation 연결

7. Unit Test

8. Integration Test</code></pre>
<p>그리고 단계마다 확인합니다.</p>
<pre><code class="language-text">Plan
 ↓
Review
 ↓
Implement
 ↓
Test</code></pre>
<p>이 방식의 장점은 AI가 잘못된 방향으로 20개의 파일을 만든 뒤 처음부터 되돌리는 일을 줄일 수 있다는 것입니다.</p>
<hr>
<h2 id="16-ai-시대에는-작은-interface가-더-중요해진다">16. AI 시대에는 작은 Interface가 더 중요해진다</h2>
<p>예를 들어:</p>
<pre><code class="language-swift">protocol PaymentRepository {

    func payment(
        productID: String,
        amount: Int
    ) async throws -&gt; PaymentResult
}</code></pre>
<p>처럼 경계가 명확하면 AI에게:</p>
<blockquote>
<p>PaymentRepository 구현을 Stripe에서 새로운 Payment API로 변경해줘.</p>
</blockquote>
<p>라고 맡기기 쉽습니다.</p>
<p>AI가 수정해야 할 영역이 분명하기 때문입니다.</p>
<p>반대로:</p>
<pre><code class="language-text">Singleton

Global State

Massive ViewModel

거대한 Manager

숨겨진 Side Effect</code></pre>
<p>가 많으면 AI도 전체 영향을 추적하기 어려워집니다.</p>
<p>사람에게 이해하기 어려운 코드는 AI에게도 안전하게 수정하기 어렵습니다.</p>
<p>그래서 AI 시대에 좋은 Architecture는:</p>
<p><strong>Agent가 수정할 수 있는 범위를 명확하게 보여주는 Architecture</strong></p>
<p>라고 볼 수도 있습니다.</p>
<hr>
<h2 id="17-feature-단위-구조도-같이-생각하면-좋다">17. Feature 단위 구조도 같이 생각하면 좋다</h2>
<p>앱이 커지면 단순히:</p>
<pre><code class="language-text">Views/
ViewModels/
Repositories/
UseCases/</code></pre>
<p>처럼 기술 종류별로 나누는 것보다 Feature가 보이는 구조가 관리하기 편할 때가 많습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Features/

├─ Login/
│  ├─ Presentation/
│  ├─ Domain/
│  └─ Data/
│
├─ Product/
│  ├─ Presentation/
│  ├─ Domain/
│  └─ Data/
│
└─ Payment/
   ├─ Presentation/
   ├─ Domain/
   └─ Data/</code></pre>
<p>이렇게 하면 사람도 AI도:</p>
<pre><code class="language-text">결제 수정
→ Payment

로그인 수정
→ Login</code></pre>
<p>처럼 변경 범위를 찾기 쉽습니다.</p>
<p>Architecture의 목적이 잘 드러나는 구조입니다.</p>
<hr>
<h2 id="18-모든-feature에-clean-architecture를-적용할-필요는-없다">18. 모든 Feature에 Clean Architecture를 적용할 필요는 없다</h2>
<p>이것도 중요합니다.</p>
<p>예를 들어 단순한 설정 화면이 있습니다.</p>
<pre><code class="language-text">알림 ON/OFF

Dark Mode ON/OFF</code></pre>
<p>이걸 위해:</p>
<pre><code class="language-text">SettingEntity

UpdateSettingUseCase

SettingRepository

SettingRepositoryImpl

SettingDTO

SettingMapper</code></pre>
<p>를 모두 만들 필요는 없습니다.</p>
<p>Architecture에는 비용이 있습니다.</p>
<p>파일이 늘고 Interface가 늘고 개발자가 이동해야 하는 코드도 늘어납니다.</p>
<p>그래서 기준을 이렇게 잡는 편이 현실적입니다.</p>
<pre><code class="language-text">Business Rule이 복잡하다
→ 분리

외부 Dependency가 자주 바뀐다
→ 분리

Test가 중요하다
→ 분리

여러 화면에서 사용한다
→ 분리

단순 UI 상태다
→ 단순하게 유지</code></pre>
<p><strong>Clean Architecture의 목적은 Layer를 많이 만드는 것이 아니라 변경 비용을 줄이는 것</strong>입니다.</p>
<hr>
<h2 id="19-ai가-만든-코드도-같은-기준으로-review한다">19. AI가 만든 코드도 같은 기준으로 Review한다</h2>
<p>AI 코드라고 별도의 Review 기준이 필요한 것은 아닙니다.</p>
<p>오히려 기존 Architecture 기준을 그대로 적용합니다.</p>
<h3 id="dependency">Dependency</h3>
<pre><code class="language-text">잘못된 Layer를 참조하지 않는가?</code></pre>
<h3 id="responsibility">Responsibility</h3>
<pre><code class="language-text">ViewModel이 너무 많은 일을 하지 않는가?</code></pre>
<h3 id="business-rule">Business Rule</h3>
<pre><code class="language-text">Domain Rule이 UI에 들어가지 않았는가?</code></pre>
<h3 id="boundary">Boundary</h3>
<pre><code class="language-text">DTO가 Domain이나 UI까지 새어 나오지 않는가?</code></pre>
<h3 id="test">Test</h3>
<pre><code class="language-text">중요한 변경에 Test가 추가됐는가?</code></pre>
<h3 id="scope">Scope</h3>
<pre><code class="language-text">요청하지 않은 파일까지 수정하지 않았는가?</code></pre>
<p>마지막 항목은 Agent 환경에서 특히 중요합니다.</p>
<hr>
<h2 id="20-ai가-반복해서-틀리면-프롬프트를-길게-쓰지-말고-규칙을-고친다">20. AI가 반복해서 틀리면 프롬프트를 길게 쓰지 말고 규칙을 고친다</h2>
<p>매번 이렇게 말하고 있다면:</p>
<pre><code class="language-text">Repository Protocol은 Domain에 만들어줘.

DTO를 ViewModel에 넘기지 마.

Test 꼭 추가해줘.</code></pre>
<p>문제가 있습니다.</p>
<p>이건 사람이 AI에게 반복적으로 Code Review를 하고 있는 것입니다.</p>
<p>두 번 이상 반복되는 지적이라면:</p>
<pre><code class="language-text">AGENTS.md

CLAUDE.md

ARCHITECTURE.md

Lint Rule

Test</code></pre>
<p>중 하나로 옮기는 것이 좋습니다.</p>
<p>OpenAI의 Codex 가이드도 반복되는 Review Feedback이나 Agent의 잘못된 가정을 Project Instruction으로 남기고, 가능한 경우 Linter나 Type Check처럼 강제 가능한 시스템과 함께 사용하는 방식을 권장합니다.</p>
<p>즉:</p>
<pre><code class="language-text">AI가 실수
   ↓
사람이 수정</code></pre>
<p>으로 끝내지 않고:</p>
<pre><code class="language-text">AI가 실수
   ↓
원인 파악
   ↓
Architecture Rule 추가
   ↓
다음 작업부터 예방</code></pre>
<p>으로 바꾸는 것입니다.</p>
<p>이것이 AI 시대의 중요한 프로젝트 관리 방식 중 하나입니다.</p>
<hr>
<h2 id="21-readme-하나만으로는-부족하다">21. README 하나만으로는 부족하다</h2>
<p>AI Agent와 같이 개발한다면 프로젝트 문서를 역할별로 나누는 것도 좋습니다.</p>
<p>예를 들면:</p>
<pre><code class="language-text">README.md</code></pre>
<p>프로젝트 소개와 실행 방법.</p>
<pre><code class="language-text">ARCHITECTURE.md</code></pre>
<p>전체 구조와 Dependency Rule.</p>
<pre><code class="language-text">AGENTS.md</code></pre>
<p>Codex가 반드시 알아야 할 작업 규칙.</p>
<pre><code class="language-text">docs/
├─ architecture/
├─ features/
├─ decisions/
└─ migrations/</code></pre>
<p>상세 설계와 변경 기록.</p>
<p>여기에 중요한 Architecture 변경은 간단한 ADR 형식으로 남길 수 있습니다.</p>
<pre><code class="language-text">Decision

왜 변경했는가

어떤 대안을 검토했는가

무엇을 선택했는가

어떤 영향이 있는가</code></pre>
<p>이 문서는 사람을 위한 기록인 동시에 AI가 다음 작업에서 참고할 수 있는 Context가 됩니다.</p>
<hr>
<h2 id="22-결국-중요한-건-context-engineering이다">22. 결국 중요한 건 Context Engineering이다</h2>
<p>AI에게 많은 코드를 보여준다고 좋은 결과가 나오는 것은 아닙니다.</p>
<p>필요한 정보를 정확하게 제공하는 것이 중요합니다.</p>
<p>좋은 프로젝트라면 AI가 작업을 시작했을 때:</p>
<pre><code class="language-text">무슨 앱인지

어떤 Feature인지

Architecture가 무엇인지

Dependency Rule이 무엇인지

어떤 Test를 실행해야 하는지

어디까지 수정해도 되는지</code></pre>
<p>를 빠르게 파악할 수 있어야 합니다.</p>
<p>그래서 앞으로 Architecture 문서는 단순한 개발 문서가 아니라 <strong>AI Agent에게 프로젝트의 Context를 제공하는 Infrastructure</strong> 역할도 하게 됩니다.</p>
<hr>
<h2 id="23-주니어라면-이-정도부터-시작하면-충분하다">23. 주니어라면 이 정도부터 시작하면 충분하다</h2>
<p>처음부터 거대한 Clean Architecture를 만들지 않아도 됩니다.</p>
<h3 id="1단계">1단계</h3>
<pre><code class="language-text">UI와 Network Code 분리</code></pre>
<h3 id="2단계">2단계</h3>
<pre><code class="language-text">Business Logic을 ViewModel 밖으로 이동</code></pre>
<h3 id="3단계">3단계</h3>
<pre><code class="language-text">Repository Protocol 도입</code></pre>
<h3 id="4단계">4단계</h3>
<pre><code class="language-text">Domain이 외부 Framework를 모르도록 구성</code></pre>
<h3 id="5단계">5단계</h3>
<pre><code class="language-text">Unit Test 추가</code></pre>
<h3 id="6단계">6단계</h3>
<pre><code class="language-text">Architecture Rule 문서화</code></pre>
<h3 id="7단계">7단계</h3>
<pre><code class="language-text">AI Agent Instruction 연결</code></pre>
<p>이렇게 조금씩 만들어도 됩니다.</p>
<hr>
<h2 id="24-ai-시대의-clean-architecture를-한-장으로-정리하면">24. AI 시대의 Clean Architecture를 한 장으로 정리하면</h2>
<p>예전에는 이렇게 생각했다면:</p>
<pre><code class="language-text">Presentation
     ↓
Domain
     ↑
Data</code></pre>
<p>지금은 한 단계가 더 필요합니다.</p>
<pre><code class="language-text">          사람 / AI Agent
               ↓
       Project Instructions
               ↓
         Architecture
               ↓
┌────────────────────────────┐
│        Presentation        │
│             ↓              │
│           Domain           │
│             ↑              │
│            Data            │
└────────────────────────────┘
               ↓
     Test / Lint / Build
               ↓
           Verification</code></pre>
<p>여기서 중요한 건 AI가 아닙니다.</p>
<p>가운데 있는 <strong>Architecture와 Verification</strong>입니다.</p>
<p>AI는 이 규칙 안에서 일하는 또 하나의 개발자에 가깝습니다.</p>
<hr>
<h2 id="25-마무리">25. 마무리</h2>
<p>클린 아키텍처를 처음 배우면:</p>
<pre><code class="language-text">Entity

UseCase

Repository

Adapter

Dependency Inversion</code></pre>
<p>같은 용어부터 외우기 쉽습니다.</p>
<p>하지만 가장 먼저 이해해야 할 것은 이것입니다.</p>
<p><strong>중요한 코드를 자주 바뀌는 코드로부터 보호한다.</strong></p>
<p>UI는 바뀝니다.</p>
<p>API도 바뀝니다.</p>
<p>Database도 바뀝니다.</p>
<p>Framework도 바뀝니다.</p>
<p>그리고 이제는 <strong>코드를 작성하는 주체도 바뀌고 있습니다.</strong></p>
<p>사람이 작성하기도 하고 Codex나 Claude Code 같은 Agent가 작성하기도 합니다.</p>
<p>그래도 앱의 Business Rule과 Architecture 원칙은 쉽게 흔들려서는 안 됩니다.</p>
<p>그래서 AI 시대의 Clean Architecture는 단순히:</p>
<pre><code class="language-text">폴더를 잘 나누는 방법</code></pre>
<p>이 아니라,</p>
<pre><code class="language-text">사람과 AI가
같은 규칙 아래에서
안전하게 코드를 변경하는 방법</code></pre>
<p>으로 보는 편이 더 맞습니다.</p>
<p>코드를 만드는 속도가 빨라질수록 더 중요한 것은 코드를 많이 만드는 능력이 아닙니다.</p>
<p><strong>어떤 코드는 어디에 있어야 하고, 무엇에 의존할 수 있으며, 어떤 변경은 허용하지 않을 것인지 명확하게 결정하는 능력입니다.</strong></p>
<p>AI가 구현을 더 많이 맡게 될수록 Architecture의 역할은 줄어드는 것이 아니라 오히려 더 분명해질 가능성이 큽니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/8ef99b72-a20f-41bd-be03-8e0db0f62c84/image.png" alt=""></p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>Robert C. Martin — The Clean Architecture</strong><br>Clean Architecture의 Layer, Dependency Rule, Entity, Use Case, Interface Adapter 개념을 설명한 원문입니다.<br><a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html?utm_source=chatgpt.com">The Clean Architecture 원문</a></p>
</li>
<li><p><strong>Robert C. Martin — Screaming Architecture</strong><br>프로젝트 구조가 Framework보다 실제 Use Case와 Business Domain을 드러내야 한다는 관점을 설명합니다.<br><a href="https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html?utm_source=chatgpt.com">Screaming Architecture 원문</a></p>
</li>
<li><p><strong>OpenAI — AGENTS.md를 활용한 프로젝트 지침</strong><br>Codex에 Build/Test 명령, Review 기준, Repository별 규칙 등을 지속적으로 전달하는 방법을 설명합니다.<br><a href="https://developers.openai.com/ko-KR/docs/agent-configuration/agents-md?utm_source=chatgpt.com">Codex AGENTS.md 공식 문서</a></p>
</li>
<li><p><strong>OpenAI — Harness Engineering</strong><br><code>AGENTS.md</code>를 거대한 설명서가 아니라 프로젝트 지식으로 이동하기 위한 목차처럼 사용하고, Architecture와 Design Document를 별도로 관리하는 실제 Agent-first Repository 운영 방식을 소개합니다.<br><a href="https://openai.com/ko-KR/index/harness-engineering/?utm_source=chatgpt.com">Harness Engineering 공식 글</a></p>
</li>
<li><p><strong>Anthropic — Claude Code 프로젝트 디렉터리</strong><br><code>CLAUDE.md</code>, Rules, Skills, Subagents 등의 역할과 프로젝트 수준에서 Agent Context를 관리하는 방식을 설명합니다.<br><a href="https://code.claude.com/docs/fr/claude-directory?utm_source=chatgpt.com">Claude Code 공식 문서</a></p>
</li>
</ul>
<p>공식 자료와 Clean Architecture의 원래 취지를 같이 보면, AI 시대라고 해서 새로운 Architecture가 갑자기 필요한 것은 아닙니다. 오히려 <strong>기존의 Dependency Rule과 명확한 Boundary에 Project Instructions, 문서, Test, Lint 같은 Agent용 Guardrail을 추가하는 방향</strong>이 현실적입니다.</p>
<p>결국 좋은 AI 개발 환경은 Agent에게 모든 판단을 맡기는 환경이 아니라, <strong>Agent가 잘못된 방향으로 가기 어렵도록 프로젝트 자체에 의도와 규칙이 남아 있는 환경</strong>에 가깝습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[iPhone Duo UI 마이그레이션부터 자동 QA까지]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609202</link>
            <guid>https://velog.io/@kyu_ios_dev/2609202</guid>
            <pubDate>Sun, 20 Sep 2026 06:14:32 GMT</pubDate>
            <description><![CDATA[<h3 id="iphone-duo-ui-마이그레이션부터-자동-qa까지">iPhone Duo UI 마이그레이션부터 자동 QA까지</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/af399ca4-8b23-4fb0-b983-4f179415420a/image.png" alt=""></p>
<h2 id="xcode-271--codex로-화면-수정하고-시뮬레이터에서-다시-검증하기">Xcode 27.1 + Codex로 화면 수정하고 시뮬레이터에서 다시 검증하기</h2>
<p>iPhone Duo 대응에서 처음 눈에 들어오는 것은 화면 크기입니다.</p>
<p>접었을 때와 펼쳤을 때 화면 비율이 달라지고, 가운데 fold가 생기고, 기존 상단이나 하단에 있던 navigation과 toolbar가 세로 방향으로 이동할 수도 있습니다.</p>
<p>하지만 실제 개발에서 더 부담스러운 부분은 따로 있습니다.</p>
<p><strong>수정해야 할 화면보다 확인해야 할 상태가 훨씬 많아진다는 점입니다.</strong></p>
<pre><code class="language-text">Closed
Open
Folded
Rotated

×

Navigation 상태
Modal 상태
Keyboard
Scroll 위치
Dynamic Type
Dark Mode</code></pre>
<p>화면 하나를 고쳐도 여러 상태에서 다시 확인해야 합니다.</p>
<p>그래서 iPhone Duo 대응에서는 UI Migration뿐 아니라 <strong>Simulator Automation과 QA Workflow</strong>가 같이 중요해집니다.</p>
<p>최근 Xcode 27.1의 Duo Simulator와 Codex의 iOS Simulator 제어 Workflow를 조합하면 이 반복작업을 꽤 많이 자동화할 수 있습니다. Apple은 Xcode 27.1에서 Duo를 열고, 닫고, 회전하고, 접은 상태를 Device Hub에서 테스트할 수 있도록 했고, OpenAI는 Codex가 XcodeBuildMCP를 통해 Simulator를 실행하고 UI tree를 읽고 tap·type·swipe하며 screenshot, log, LLDB까지 사용하는 Workflow를 공식적으로 문서화했습니다. </p>
<hr>
<h2 id="1-duo-대응은-단순한-화면-리사이징이-아니다">1. Duo 대응은 단순한 화면 리사이징이 아니다</h2>
<p>기존 iPhone 앱은 보통 세로 화면을 중심으로 만들어졌습니다.</p>
<pre><code class="language-swift">UIScreen.main.bounds.width</code></pre>
<p>같은 값을 기준으로 UI를 계산하거나,</p>
<pre><code class="language-swift">if width &gt; 700 {
    // tablet layout
}</code></pre>
<p>처럼 특정 화면 폭을 기준으로 분기한 코드도 적지 않습니다.</p>
<p>Duo에서는 이런 가정이 훨씬 위험해집니다.</p>
<p>앱이 실행되는 공간이:</p>
<pre><code class="language-text">닫힌 상태
→ 일반적인 iPhone 형태

펼친 상태
→ 넓어진 내부 화면

접은 상태
→ fold가 화면을 분할

회전
→ 또 다른 비율</code></pre>
<p>로 계속 달라지기 때문입니다.</p>
<p>Apple도 Duo 대응에서 화면 크기를 직접 추측하기보다 <strong>Size Class, Trait Collection, 현재 Scene과 실제 Layout Environment를 사용하라</strong>고 권장하고 있습니다. <code>UIScreen.main</code> 같은 main-screen 기반 코드 역시 멀티 디스플레이 환경에서 줄이는 방향입니다. </p>
<p>예를 들어:</p>
<pre><code class="language-swift">let scale = UIScreen.main.scale</code></pre>
<p>보다:</p>
<pre><code class="language-swift">let scale = traitCollection.displayScale</code></pre>
<p>처럼 현재 UI가 실제로 놓여 있는 환경에서 값을 얻는 것이 안전합니다.</p>
<p>Duo Migration의 첫 번째 작업은 의외로 새로운 API를 추가하는 것이 아니라,</p>
<pre><code class="language-text">UIScreen.main

고정 width / height

orientation 기반 분기

device model 기반 분기

absolute frame</code></pre>
<p>같은 기존 가정을 찾아내는 것입니다.</p>
<hr>
<h2 id="2-시스템-navigation을-쓰면-생각보다-많은-것이-자동으로-해결된다">2. 시스템 Navigation을 쓰면 생각보다 많은 것이 자동으로 해결된다</h2>
<p>Duo에서 가장 먼저 다시 볼 부분은 Navigation입니다.</p>
<p>SwiftUI라면:</p>
<pre><code class="language-swift">NavigationStack
NavigationSplitView
TabView</code></pre>
<p>UIKit이라면:</p>
<pre><code class="language-swift">UINavigationController
UISplitViewController
UITabBarController</code></pre>
<p>같은 System Container를 사용하는 것이 중요합니다.</p>
<p>Apple은 Duo에서 표준 navigation container와 presentation이 각 pose에 맞게 적응하도록 설계했습니다.</p>
<p>예를 들어 Tab Bar는 내부 화면에서 상황에 따라 Sidebar 형태로 바뀔 수 있고 Navigation과 Toolbar도 세로 방향으로 이동할 수 있습니다. </p>
<p>그래서 문제가 되는 것은:</p>
<pre><code class="language-text">Custom UI</code></pre>
<p>자체가 아닙니다.</p>
<p>문제는:</p>
<pre><code class="language-text">System Navigation과 완전히 분리된
Custom Navigation</code></pre>
<p>입니다.</p>
<p>예를 들어:</p>
<pre><code class="language-swift">VStack {
    CustomNavigationBar()

    ContentView()

    CustomTabBar()
}</code></pre>
<p>처럼 모든 Navigation UI를 직접 배치했다면 Duo의 Vertical Bar나 새로운 Safe Area 변화가 자동으로 반영되지 않습니다.</p>
<hr>
<h2 id="3-기존-custom-tab-bar를-당장-버릴-필요는-없다">3. 기존 Custom Tab Bar를 당장 버릴 필요는 없다</h2>
<p>기존 서비스에서 Custom Tab Bar와 Custom Navigation을 전부 System Container로 한 번에 교체하는 것은 현실적으로 어렵습니다.</p>
<p>그래서 iOS 27.1에서는 <code>ReservedRegion</code>이 중요합니다.</p>
<p>SwiftUI에서는:</p>
<pre><code class="language-swift">ReservedRegion</code></pre>
<p>UIKit에서는:</p>
<pre><code class="language-swift">UIViewReservedRegion</code></pre>
<p>을 사용할 수 있습니다.</p>
<p>목적은 단순합니다.</p>
<p><strong>Safe Area 밖까지 UI를 사용하면서도 시스템 UI나 하드웨어 영역과 충돌하지 않게 하는 것</strong>입니다. </p>
<p>따라서 마이그레이션은:</p>
<pre><code class="language-text">Custom UI 전부 삭제</code></pre>
<p>보다</p>
<pre><code class="language-text">1. 기존 Custom UI 유지

2. ReservedRegion 대응

3. Navigation State와 UI 분리

4. System Container로 단계적 이동</code></pre>
<p>이 현실적입니다.</p>
<hr>
<h2 id="4-이제-fold-자체를-layout-정보로-읽을-수-있다">4. 이제 fold 자체를 Layout 정보로 읽을 수 있다</h2>
<p>이번 Duo 대응에서 꽤 중요한 변화입니다.</p>
<p>단순히:</p>
<pre><code class="language-text">Safe Area가 달라졌다</code></pre>
<p>정도가 아닙니다.</p>
<p>앱이 <strong>어디에 fold가 있는지 직접 조회할 수 있습니다.</strong></p>
<p>SwiftUI:</p>
<pre><code class="language-swift">GeometryReader { proxy in
    let regions = proxy.reservedRegions(
        kind: .division
    )

    let frames = regions.map(\.frame)

    // layout
}</code></pre>
<p>UIKit:</p>
<pre><code class="language-swift">let regions = view.reservedRegions(
    kind: .division
)

let frames = regions.map(\.frame)</code></pre>
<p>여기서 <code>.division</code>은 화면을 실제로 나누는 영역입니다.</p>
<p>Duo의 fold가 대표적입니다.</p>
<p>또:</p>
<pre><code class="language-swift">.occlusion</code></pre>
<p>도 존재합니다.</p>
<p>이건 카메라처럼 화면 일부를 가리는 영역을 의미합니다. </p>
<p>즉 이제 Layout은 단순히:</p>
<pre><code class="language-text">width = 1000</code></pre>
<p>을 보고 판단하는 것이 아니라,</p>
<pre><code class="language-text">전체 화면
+
division
+
occlusion</code></pre>
<p>을 같이 보고 결정할 수 있습니다.</p>
<hr>
<h2 id="5-fold가-펴져-있어도-미리-알-수-있다">5. fold가 펴져 있어도 미리 알 수 있다</h2>
<p>조금 더 재미있는 API도 있습니다.</p>
<pre><code class="language-swift">let regions = proxy.reservedRegions(
    kind: .division,
    options: .includeInactive
)</code></pre>
<p><code>includeInactive</code>를 사용하면 현재 fold가 활성화돼 있지 않은 상태에서도 해당 Region 정보를 확인할 수 있습니다.</p>
<p>Duo가 완전히 펼쳐져 있으면 fold의 division region은 inactive 상태이고 폭도 0이 될 수 있습니다.</p>
<p>하지만 앱은:</p>
<pre><code class="language-text">이 Device에는 division region이 존재한다</code></pre>
<p>는 사실을 알 수 있습니다. </p>
<p>예를 들어 Grid UI라면:</p>
<pre><code class="language-text">Duo

→ Column을 짝수로 구성
→ 나중에 접혀도 자연스럽게 양쪽으로 분리</code></pre>
<p>같은 선제적인 Layout 설계도 가능합니다.</p>
<hr>
<h2 id="6-arrangementview가-꽤-중요해졌다">6. ArrangementView가 꽤 중요해졌다</h2>
<p>기존 Foldable 대응에서는 직접:</p>
<pre><code class="language-swift">if folded {
    HStack { ... }
} else {
    VStack { ... }
}</code></pre>
<p>같은 코드를 작성하기 쉽습니다.</p>
<p>Apple은 iOS 27.1에서 이 문제를 위해 <code>ArrangementView</code>라는 Layout Container를 제공합니다.</p>
<p>SwiftUI:</p>
<pre><code class="language-swift">NavigationStack {
    ArrangementView {
        PlayerView()
    } secondary: {
        UpNextView()
    }
}</code></pre>
<p>UIKit에서는:</p>
<pre><code class="language-swift">UIArrangementViewController</code></pre>
<p>를 사용할 수 있습니다.</p>
<p>Arrangement는 단순 Split View와 조금 다릅니다.</p>
<pre><code class="language-text">Size Class

Aspect Ratio

Division Region

현재 사용 가능한 공간</code></pre>
<p>등을 기준으로 Primary와 Secondary Content를 배치합니다. </p>
<p>즉 Duo 대응의 핵심은:</p>
<pre><code class="language-text">크기 변경</code></pre>
<p>에서 점점</p>
<pre><code class="language-text">Arrangement 변경</code></pre>
<p>으로 이동합니다.</p>
<hr>
<h2 id="7-center-layout도-다시-생각해야-한다">7. Center Layout도 다시 생각해야 한다</h2>
<p>기존 앱에는 가운데 정렬 UI가 많습니다.</p>
<pre><code class="language-text">[       큰 이미지       ]

        제목

        버튼</code></pre>
<p>Duo를 반쯤 접으면 가운데 fold가 그대로 콘텐츠를 지나갈 수 있습니다.</p>
<p>이때 단순하게 전체 View를 축소하는 것보다:</p>
<pre><code class="language-text">왼쪽
Image

       fold

오른쪽
Title
Button</code></pre>
<p>처럼 콘텐츠를 이동시키는 편이 자연스러울 수 있습니다.</p>
<p>Apple은 이를 <strong>Displacement Pattern</strong>으로 설명하고 있습니다. </p>
<p>그래서 Duo Migration 시 다음 화면을 먼저 찾는 것이 좋습니다.</p>
<pre><code class="language-text">Center aligned Hero

Video Player

Camera Preview

Map

Large Chart

Two-pane editor

Media Player</code></pre>
<p>이런 화면은 fold가 지나갈 가능성이 높습니다.</p>
<hr>
<h2 id="8-vertical-bar-대응도-이제-단순한-tab-bar-문제가-아니다">8. Vertical Bar 대응도 이제 단순한 Tab Bar 문제가 아니다</h2>
<p>Duo 내부 화면에서는 Navigation, Toolbar, Tab Bar가 하나의 Vertical Region을 공유할 수 있습니다.</p>
<p>Apple은 이를 거의:</p>
<pre><code class="language-text">기존 Bar를
90도 돌려 배치한다</code></pre>
<p>는 개념으로 설명합니다.</p>
<p>하지만 Custom Toolbar를 직접 만든 경우에는 자동으로 들어가지 않습니다.</p>
<p>SwiftUI에서는 가능한 한:</p>
<pre><code class="language-swift">NavigationStack {
    ContentView()
        .toolbar {
            ToolbarItem {
                Button(&quot;Edit&quot;) { }
            }
        }
}</code></pre>
<p>처럼 Navigation Container에 Toolbar를 연결하는 것이 좋습니다.</p>
<p>UIKit 역시:</p>
<pre><code class="language-text">UINavigationController
+
ViewController의 toolbarItems</code></pre>
<p>방식이 권장됩니다.</p>
<p>직접 만든:</p>
<pre><code class="language-swift">UIToolbar()
UINavigationBar()
UITabBar()</code></pre>
<p>의 Content는 Duo의 시스템 Vertical Bar 구성에 자동 참여하지 않습니다. </p>
<hr>
<h2 id="9-여기까지가-migration-문제는-qa다">9. 여기까지가 Migration, 문제는 QA다</h2>
<p>여기까지 코드만 고쳤다고 해보겠습니다.</p>
<p>이제 확인해야 합니다.</p>
<pre><code class="language-text">Closed
✓

Open
?

Folded
?

Rotated Open
?

Rotated Folded
?</code></pre>
<p>화면이 30개라면?</p>
<pre><code class="language-text">30 × pose 4</code></pre>
<p>만 해도 120번입니다.</p>
<p>여기에:</p>
<pre><code class="language-text">Navigation

Modal

Keyboard

Scroll

Dynamic Type

Dark Mode</code></pre>
<p>까지 들어갑니다.</p>
<p>그래서 Duo 대응에서는 <strong>시뮬레이터 QA 자동화의 가치가 커집니다.</strong></p>
<hr>
<h2 id="10-xcode-271에는-iphone-duo-simulator가-있다">10. Xcode 27.1에는 iPhone Duo Simulator가 있다</h2>
<p>Xcode 27.1에서 iPhone Duo Simulator를 선택하면 Device Hub에서:</p>
<pre><code class="language-text">Open

Close

Rotate

Fold</code></pre>
<p>상태를 직접 바꿔 테스트할 수 있습니다. </p>
<p>즉 예전처럼:</p>
<pre><code class="language-text">Preview width를 임의로 바꿔보기</code></pre>
<p>가 아니라 실제 Duo 환경에서 UI를 확인할 수 있습니다.</p>
<p>이제 문제는:</p>
<blockquote>
<p>누가 이걸 계속 눌러서 테스트할 것인가?</p>
</blockquote>
<p>입니다.</p>
<p>여기서 Codex를 붙일 수 있습니다.</p>
<hr>
<h2 id="11-codex는-이제-simulator를-직접-조작할-수-있다">11. Codex는 이제 Simulator를 직접 조작할 수 있다</h2>
<p>OpenAI는 Codex의 공식 iOS Use Case로:</p>
<p><strong>Debug in iOS Simulator</strong></p>
<p>를 제공하고 있습니다.</p>
<p>Codex와 <code>XcodeBuildMCP</code>를 연결하면:</p>
<pre><code class="language-text">Xcode Project 탐색
       ↓
Scheme 선택
       ↓
Simulator 선택
       ↓
Build
       ↓
Launch
       ↓
UI hierarchy 확인
       ↓
Tap
Type
Scroll
Swipe
       ↓
Screenshot
       ↓
Log
       ↓
LLDB</code></pre>
<p>까지 진행할 수 있습니다. </p>
<p>즉 Codex가 단순히 Swift 코드를 작성하는 도구에서:</p>
<pre><code class="language-text">코드
+
실행 환경
+
UI
+
Debugger</code></pre>
<p>를 같이 보는 형태로 바뀌고 있습니다.</p>
<hr>
<h2 id="12-좌표를-찍는-매크로와는-조금-다르다">12. 좌표를 찍는 매크로와는 조금 다르다</h2>
<p>UI 자동화에서 흔한 방식은:</p>
<pre><code class="language-text">x: 320
y: 630

tap</code></pre>
<p>입니다.</p>
<p>하지만 Layout이 조금만 바뀌어도 깨집니다.</p>
<p>OpenAI의 Codex Simulator Workflow에서는 가능하면 <strong>Accessibility Label이나 Element ID를 사용하고, 화면이 변경될 때 UI hierarchy를 다시 읽는 방식</strong>을 권장합니다. </p>
<p>예를 들어:</p>
<pre><code class="language-text">&quot;로그인&quot; 버튼 검색
       ↓
Tap
       ↓
화면 변경
       ↓
UI Tree 다시 조회
       ↓
&quot;이메일&quot; 입력창 검색
       ↓
Type</code></pre>
<p>입니다.</p>
<p>Duo처럼 Layout이 pose에 따라 크게 달라지는 환경에서는 이 방식이 특히 중요합니다.</p>
<hr>
<h2 id="13-duo-qa-scenario를-자연어로-만들-수-있다">13. Duo QA Scenario를 자연어로 만들 수 있다</h2>
<p>예를 들어 Codex에게 이런 작업을 줄 수 있습니다.</p>
<pre><code class="language-text">iPhone Duo Simulator에서 앱을 실행한다.

로그인 화면까지 이동한다.

테스트 계정으로 로그인한다.

홈 화면을 확인한다.

홈 → 상세 → 설정 화면까지 이동한다.

각 화면에서 스크린샷을 저장한다.

버튼이 잘리거나 다른 UI와 겹치는지 확인한다.

Navigation이 정상 동작하는지 확인한다.

로그에 constraint warning이나 crash가 있는지 확인한다.

문제가 있으면 원인을 찾고 최소한의 코드만 수정한다.

수정 후 같은 Flow를 다시 실행한다.</code></pre>
<p>Codex가 담당할 수 있는 것은:</p>
<pre><code class="language-text">Reproduce

Observe

Diagnose

Fix

Verify</code></pre>
<p>Loop입니다.</p>
<p>OpenAI도 공식 문서에서 이를 <strong>reproduce-fix-verify loop</strong>라고 설명합니다. </p>
<hr>
<h2 id="14-duo에서는-qa-matrix를-먼저-만들어두는-것이-좋다">14. Duo에서는 QA Matrix를 먼저 만들어두는 것이 좋다</h2>
<p>무작정 Agent에게:</p>
<blockquote>
<p>전체 테스트해줘.</p>
</blockquote>
<p>라고 하면 범위가 너무 큽니다.</p>
<p>Duo용 QA Matrix를 먼저 정의하는 것이 좋습니다.</p>
<p>예를 들어:</p>
<table>
<thead>
<tr>
<th>화면</th>
<th>Closed</th>
<th>Open</th>
<th>Folded</th>
<th>Rotate</th>
</tr>
</thead>
<tbody><tr>
<td>Login</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Home</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Detail</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Settings</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
</tr>
<tr>
<td>Camera</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
<td>✓</td>
</tr>
</tbody></table>
<p>그리고 각 화면에서:</p>
<pre><code class="language-text">Layout

Navigation

Interaction

Safe Area

ReservedRegion

Vertical Bar

Accessibility

Crash / Warning</code></pre>
<p>을 검사합니다.</p>
<p>이렇게 하면 QA가 훨씬 명확해집니다.</p>
<hr>
<h2 id="15-layout-qa에서는-이것부터-찾으면-된다">15. Layout QA에서는 이것부터 찾으면 된다</h2>
<p>Duo Migration에서 특히 잡아야 할 문제는 몇 가지가 반복됩니다.</p>
<h3 id="fixed-width">Fixed Width</h3>
<pre><code class="language-swift">.frame(width: 390)</code></pre>
<h3 id="uiscreenmain">UIScreen.main</h3>
<pre><code class="language-swift">UIScreen.main.bounds</code></pre>
<h3 id="orientation-의존성">Orientation 의존성</h3>
<pre><code class="language-swift">UIDevice.current.orientation</code></pre>
<h3 id="safe-area-무시">Safe Area 무시</h3>
<pre><code class="language-swift">.ignoresSafeArea()</code></pre>
<p>를 foreground control에 무분별하게 사용하는 경우.</p>
<h3 id="custom-navigation">Custom Navigation</h3>
<pre><code class="language-text">Navigation Controller 밖에서
Tab / Toolbar / Navigation Bar 직접 배치</code></pre>
<h3 id="중앙-ui">중앙 UI</h3>
<pre><code class="language-text">fold와 겹치는
centered control</code></pre>
<p>이 항목들을 먼저 Audit하면 전체 수정량을 빠르게 줄일 수 있습니다.</p>
<hr>
<h2 id="16-safe-area-qa는-네-방향을-따로-봐야-한다">16. Safe Area QA는 네 방향을 따로 봐야 한다</h2>
<p>기존 iPhone에서는:</p>
<pre><code class="language-text">left == right</code></pre>
<p>라고 가정한 코드가 생각보다 많습니다.</p>
<p>Duo에서는 safe area나 layout margin이 비대칭일 수 있습니다.</p>
<p>따라서:</p>
<pre><code class="language-swift">let insets = view.safeAreaInsets

print(insets.top)
print(insets.left)
print(insets.bottom)
print(insets.right)</code></pre>
<p>처럼 각각 독립적인 값으로 취급해야 합니다.</p>
<p>Apple도 Duo에서 asymmetric safe area와 layout margin을 반드시 테스트하라고 강조합니다. </p>
<hr>
<h2 id="17-reservedregion-qa도-별도로-만들어야-한다">17. ReservedRegion QA도 별도로 만들어야 한다</h2>
<p>Custom UI가 있다면:</p>
<pre><code class="language-text">Division Region

Occlusion Region</code></pre>
<p>두 가지를 확인합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-swift">let divisions = view.reservedRegions(
    kind: .division
)

let occlusions = view.reservedRegions(
    kind: .occlusion
)</code></pre>
<p>그리고 중요한 버튼이 해당 영역과 겹치는지 확인합니다.</p>
<p>QA 관점에서 보면:</p>
<pre><code class="language-text">Safe Area QA</code></pre>
<p>와</p>
<pre><code class="language-text">Reserved Region QA</code></pre>
<p>는 같은 것이 아닙니다.</p>
<p>Safe Area 안에만 넣으면 되는 일반 control도 있지만, edge-to-edge나 custom bar처럼 Reserved Region을 별도로 고려해야 하는 UI도 있습니다.</p>
<hr>
<h2 id="18-screenshot-qa도-꽤-유용해진다">18. Screenshot QA도 꽤 유용해진다</h2>
<p>Codex는 Simulator에서 screenshot을 캡처할 수 있습니다.</p>
<p>그래서 각 상태에서:</p>
<pre><code class="language-text">Home_Closed.png

Home_Open.png

Home_Folded.png

Home_Rotated.png</code></pre>
<p>처럼 증거를 남길 수 있습니다. </p>
<p>다만 여기서 한 가지 구분해야 합니다.</p>
<p><strong>Codex가 screenshot을 볼 수 있다는 것과 완전한 Visual Regression Test Framework가 있다는 것은 다릅니다.</strong></p>
<p>진짜 픽셀 기반 회귀 테스트가 필요하다면:</p>
<pre><code class="language-text">SnapshotTesting
또는
사내 Snapshot Tool</code></pre>
<p>같은 시스템과 결합하는 것이 더 안정적입니다.</p>
<p>구조는:</p>
<pre><code class="language-text">Codex
 ↓
Simulator Flow 실행
 ↓
Screenshot
 ↓
Snapshot Baseline
 ↓
Diff</code></pre>
<p>형태가 됩니다.</p>
<p>Codex는 여기서 실행과 원인 분석을 담당하게 할 수 있습니다.</p>
<hr>
<h2 id="19-accessibility-qa도-같이-할-수-있다">19. Accessibility QA도 같이 할 수 있다</h2>
<p>Codex가 UI Tree를 읽을 수 있다는 점은 단순 자동 클릭보다 의미가 큽니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Button인데 Label 없음

아이콘만 있고 의미 없음

동일한 Accessibility ID 중복

숨겨져야 할 요소가 노출</code></pre>
<p>같은 문제도 QA 대상이 될 수 있습니다.</p>
<p>Duo에서 Layout이 재배치돼도:</p>
<pre><code class="language-text">화면상 위치</code></pre>
<p>대신</p>
<pre><code class="language-text">Accessibility Identity</code></pre>
<p>가 유지된다면 자동화 Script도 훨씬 안정적으로 동작합니다.</p>
<p>결국 Accessibility를 잘 만드는 것이 QA 자동화 품질도 높여줍니다.</p>
<hr>
<h2 id="20-crash가-발생하면-lldb까지-이어갈-수-있다">20. Crash가 발생하면 LLDB까지 이어갈 수 있다</h2>
<p>UI를 눌러보다 Crash가 발생하면 자동화가 끝나는 것이 아닙니다.</p>
<p>Codex 공식 Workflow는 필요할 경우 LLDB를 붙여:</p>
<pre><code class="language-text">Stack Frame

Variable

Backtrace</code></pre>
<p>등을 확인하는 단계까지 포함합니다. </p>
<p>전체 흐름은:</p>
<pre><code class="language-text">Simulator
 ↓
Crash
 ↓
Log
 ↓
LLDB
 ↓
Root Cause
 ↓
Code 수정
 ↓
Build
 ↓
동일 Flow 재실행</code></pre>
<p>입니다.</p>
<p>이 부분이 단순 XCTest 생성과 가장 큰 차이 중 하나입니다.</p>
<hr>
<h2 id="21-qa-agent에게-코드를-마음대로-고치게-하면-안-된다">21. QA Agent에게 코드를 마음대로 고치게 하면 안 된다</h2>
<p>자동화가 가능하다고:</p>
<blockquote>
<p>문제 있으면 알아서 다 고쳐.</p>
</blockquote>
<p>라고 맡기는 것은 추천하지 않습니다.</p>
<p>오히려 제한을 명확하게 주는 것이 좋습니다.</p>
<pre><code class="language-text">문제를 먼저 재현할 것

수정 전 screenshot과 log를 남길 것

Root Cause를 설명할 것

가장 작은 코드 변경만 할 것

Navigation Architecture는 변경하지 말 것

Public API는 변경하지 말 것

수정 후 동일 Scenario를 다시 실행할 것</code></pre>
<p>같은 조건입니다.</p>
<p>OpenAI의 공식 Simulator 예제도 <strong>smallest code change</strong> 후 동일 Flow를 다시 실행해 검증하도록 안내합니다. </p>
<hr>
<h2 id="22-실제-codex-prompt는-이렇게-시작해볼-수-있다">22. 실제 Codex Prompt는 이렇게 시작해볼 수 있다</h2>
<p>예를 들어:</p>
<pre><code class="language-text">XcodeBuildMCP를 사용해서
현재 프로젝트를 iPhone Duo Simulator에서 QA해줘.

대상 화면:
- Login
- Home
- Detail
- Settings

확인 항목:
- UI clipping
- overlap
- asymmetric safe area
- reserved region 충돌
- navigation
- toolbar / tab bar
- scroll
- accessibility label
- Auto Layout warning
- crash

각 화면에서 screenshot을 남겨.

문제가 발견되면 바로 수정하지 말고
먼저 원인과 수정 계획을 정리해.

승인된 수정은 최소 범위로 적용하고,
수정 후 동일 Flow를 다시 실행해서 검증해.</code></pre>
<p>여기에 Duo 전용 조건을 추가합니다.</p>
<pre><code class="language-text">Closed / Open / Folded / Rotated 상태를
모두 QA 대상으로 본다.

UIScreen.main,
고정 width / height,
orientation 기반 분기를 우선적으로 찾아본다.

Custom Tab Bar와 Custom Navigation은
현재 디자인을 유지하면서
ReservedRegion으로 대응 가능한지 먼저 검토한다.

System Container로의 마이그레이션은
별도 제안으로 분리한다.</code></pre>
<p>이렇게 하면 기존 앱을 전부 갈아엎는 방향으로 흘러가는 것을 막을 수 있습니다.</p>
<hr>
<h2 id="23-pose-변경-자체는-자동화-범위를-구분해서-봐야-한다">23. Pose 변경 자체는 자동화 범위를 구분해서 봐야 한다</h2>
<p>여기서는 한 가지 주의할 점이 있습니다.</p>
<p>Xcode 27.1의 Device Hub가:</p>
<pre><code class="language-text">Open
Close
Rotate
Fold</code></pre>
<p>를 제공하는 것은 Apple이 공식적으로 확인한 기능입니다. </p>
<p>Codex + XcodeBuildMCP가 Simulator 내부의 UI를 자동으로 조작하는 것도 공식 Workflow입니다. </p>
<p>하지만 <strong>Duo의 모든 pose 변경을 XcodeBuildMCP가 자동 API로 제어할 수 있는지는 사용하는 XcodeBuildMCP 버전과 Tool 노출 범위를 확인해야 합니다.</strong></p>
<p>그래서 현재 실무에서는:</p>
<pre><code class="language-text">앱 내부 UI QA
→ Codex 자동화

Pose 변경
→ Tool 지원 시 자동화

미지원 시
→ Device Hub에서 상태 전환</code></pre>
<p>으로 나누는 것이 안전합니다.</p>
<p>이 부분까지 완전히 자동화된 것처럼 보는 것은 아직 이릅니다.</p>
<hr>
<h2 id="24-자동-qa의-현실적인-1단계는-smoke-test다">24. 자동 QA의 현실적인 1단계는 Smoke Test다</h2>
<p>처음부터 모든 화면을 자동화할 필요는 없습니다.</p>
<p>가장 먼저:</p>
<pre><code class="language-text">앱 실행

로그인

홈 진입

핵심 화면 3개 이동

대표적인 Modal 열기

스크롤

주요 CTA Tap</code></pre>
<p>정도를 자동화합니다.</p>
<p>그리고 이를:</p>
<pre><code class="language-text">Closed

Open

Folded</code></pre>
<p>에서 반복합니다.</p>
<p>이것만으로도:</p>
<pre><code class="language-text">Navigation 깨짐

화면 잘림

Button 접근 불가

Modal 이상

Crash</code></pre>
<p>같은 큰 문제를 상당수 잡을 수 있습니다.</p>
<hr>
<h2 id="25-그다음-regression-qa로-확장한다">25. 그다음 Regression QA로 확장한다</h2>
<p>Smoke Test가 안정되면:</p>
<pre><code class="language-text">Critical User Flow</code></pre>
<p>를 추가합니다.</p>
<p>예를 들어 쇼핑 앱이면:</p>
<pre><code class="language-text">Login
 ↓
Product
 ↓
Cart
 ↓
Payment</code></pre>
<p>카메라 앱이면:</p>
<pre><code class="language-text">Camera
 ↓
Zoom
 ↓
Capture
 ↓
Preview
 ↓
Save</code></pre>
<p>업무 앱이면:</p>
<pre><code class="language-text">Login
 ↓
List
 ↓
Detail
 ↓
Edit
 ↓
Submit</code></pre>
<p>정도입니다.</p>
<p>그리고 Duo pose별로 돌립니다.</p>
<pre><code class="language-text">Critical Flow
      ×
Duo Pose</code></pre>
<p>이게 실질적인 Duo Regression Suite가 됩니다.</p>
<hr>
<h2 id="26-qa-결과도-사람이-읽기-쉽게-남겨야-한다">26. QA 결과도 사람이 읽기 쉽게 남겨야 한다</h2>
<p>Agent가:</p>
<blockquote>
<p>테스트 완료했습니다.</p>
</blockquote>
<p>라고 하면 의미가 없습니다.</p>
<p>최종 결과는 최소한 이렇게 받아야 합니다.</p>
<pre><code class="language-text">Simulator
iPhone Duo / iOS 27.1

Scheme
Production-Debug

Tested
12 scenarios

Passed
10

Failed
2</code></pre>
<p>그리고 Failure마다:</p>
<pre><code class="language-text">Home / Folded

문제
Floating button이 division region과 겹침

Evidence
home_folded_before.png

원인
고정 trailing offset

수정
safeArea + reservedRegion 기반 위치 계산

검증
home_folded_after.png</code></pre>
<p>형태로 남기는 것이 좋습니다.</p>
<p>이런 결과라면 개발자뿐 아니라 QA나 기획자도 이해할 수 있습니다.</p>
<hr>
<h2 id="27-xcode의-app-resizability-skill도-같이-활용할-수-있다">27. Xcode의 App Resizability Skill도 같이 활용할 수 있다</h2>
<p>Apple도 이 반복적인 Migration 작업을 AI 활용 영역으로 보고 있습니다.</p>
<p>WWDC26에서 소개됐던 App Modernization Skill은 Xcode 27.1에서 <strong>App Resizability</strong>로 이름이 변경됐고, SwiftUI와 iPhone Duo까지 지원 범위가 확장됐습니다. </p>
<p>즉:</p>
<pre><code class="language-text">Apple App Resizability Skill
→ Layout Migration Audit

Codex + XcodeBuildMCP
→ Simulator 실행 / 문제 재현 / 수정 / 검증</code></pre>
<p>처럼 역할을 나누는 것도 가능합니다.</p>
<hr>
<h2 id="28-앞으로-ios-qa-workflow가-조금-달라질-것-같다">28. 앞으로 iOS QA Workflow가 조금 달라질 것 같다</h2>
<p>기존에는:</p>
<pre><code class="language-text">Developer
 ↓
코드 작성
 ↓
Simulator 확인
 ↓
QA 전달
 ↓
Bug
 ↓
Developer 재현
 ↓
수정</code></pre>
<p>이었다면,</p>
<p>Agent를 끼운 Workflow는:</p>
<pre><code class="language-text">Developer
 ↓
Codex
 ↓
Build
 ↓
Simulator
 ↓
Flow 실행
 ↓
Screenshot / Log
 ↓
문제 발견
 ↓
수정
 ↓
동일 Flow 재검증
 ↓
QA</code></pre>
<p>가 됩니다.</p>
<p>사람 QA가 없어지는 이야기는 아닙니다.</p>
<p>오히려 사람이 반복적으로 확인하던:</p>
<pre><code class="language-text">앱 실행

로그인

버튼 누르기

화면 이동

스크린샷 찍기

로그 수집

수정 확인</code></pre>
<p>을 Agent에게 넘기고,</p>
<p>QA는:</p>
<pre><code class="language-text">UX가 자연스러운가

실제 사용자 시나리오가 맞는가

예상하지 못한 문제가 있는가</code></pre>
<p>에 더 집중하는 방향에 가깝습니다.</p>
<hr>
<h2 id="29-iphone-duo가-이-변화를-더-빠르게-만들-수-있다">29. iPhone Duo가 이 변화를 더 빠르게 만들 수 있다</h2>
<p>일반적인 iPhone 하나만 지원할 때는 직접 Simulator를 몇 번 눌러보는 것으로도 버틸 수 있었습니다.</p>
<p>하지만 Duo에서는:</p>
<pre><code class="language-text">Pose 증가

Resizable Layout

Vertical Navigation

Asymmetric Safe Area

Reserved Region

Multiple Display

Fold</code></pre>
<p>가 동시에 들어옵니다.</p>
<p>검증 Matrix가 커집니다.</p>
<p>그래서 이번 Duo 대응의 중요한 변화는 단순히:</p>
<blockquote>
<p>Foldable iPhone이 나왔다.</p>
</blockquote>
<p>가 아닙니다.</p>
<p>개발 Workflow 관점에서는:</p>
<blockquote>
<p><strong>사람이 모든 UI 상태를 직접 확인하기 어려워지는 시점이 왔다.</strong></p>
</blockquote>
<p>는 쪽이 더 흥미롭습니다.</p>
<hr>
<h2 id="30-정리">30. 정리</h2>
<p>iPhone Duo Migration은 세 단계로 보는 것이 좋습니다.</p>
<h3 id="1단계--architecture">1단계 — Architecture</h3>
<pre><code class="language-text">UIScreen.main 제거

고정 Layout 제거

Size Class / Trait 사용

System Navigation 우선</code></pre>
<h3 id="2단계--duo-layout">2단계 — Duo Layout</h3>
<pre><code class="language-text">Asymmetric Safe Area

ReservedRegion

Division / Occlusion

ArrangementView

Vertical Bar</code></pre>
<h3 id="3단계--automation--qa">3단계 — Automation &amp; QA</h3>
<pre><code class="language-text">Xcode 27.1 Duo Simulator

Codex

XcodeBuildMCP

UI Tree

Tap / Type / Swipe

Screenshot

Logs

LLDB

Regression</code></pre>
<p>결국 중요한 것은 새로운 UI API를 몇 개 적용했느냐가 아닙니다.</p>
<pre><code class="language-text">Migration
      ↓
Run
      ↓
Observe
      ↓
QA
      ↓
Fix
      ↓
Verify</code></pre>
<p>까지 반복할 수 있는 구조를 만드는 것입니다.</p>
<p>Codex의 iOS Simulator Workflow가 흥미로운 것도 이 때문입니다.</p>
<p>예전의 AI 코딩 도구가:</p>
<pre><code class="language-text">코드를 만들어주는 AI</code></pre>
<p>였다면,</p>
<p>현재는 점점:</p>
<pre><code class="language-text">코드를 수정하고

직접 실행하고

화면을 누르고

문제를 재현하고

증거를 수집하고

수정한 뒤

다시 같은 화면을 확인하는 AI</code></pre>
<p>쪽으로 이동하고 있습니다.</p>
<p>iPhone Duo처럼 UI 상태가 빠르게 늘어나는 환경에서는 단순 Code Generation보다 <strong>이 reproduce → fix → verify Loop가 훨씬 중요한 개발 기능</strong>이 될 가능성이 큽니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/4719a501-883a-461f-97a8-e3094ca5a79b/image.png" alt=""></p>
<h2 id="참고자료">참고자료</h2>
<p><strong>Apple Developer — Prepare your app for iPhone Duo</strong><br>iOS 27.1 SDK, Duo Simulator, flexible layout, asymmetric safe area, ReservedRegion, App Resizability를 설명합니다.<br><a href="https://developer.apple.com/videos/play/tech-talks/111461/?utm_source=chatgpt.com">Apple 공식 Tech Talk 보기</a></p>
<p><strong>Apple Developer — Strike a pose with adaptive layouts on iPhone Duo</strong><br>Division/Occlusion Reserved Region, fold 대응, ArrangementView와 UIArrangementViewController를 다룹니다.<br><a href="https://developer.apple.com/videos/play/tech-talks/111463/?utm_source=chatgpt.com">Apple 공식 Tech Talk 보기</a></p>
<p><strong>Apple Developer — Raise the bar with iPhone Duo</strong><br>Vertical Navigation, Toolbar, Tab Bar, Overflow와 Custom Bar 마이그레이션을 설명합니다.<br><a href="https://developer.apple.com/videos/play/tech-talks/111462/?utm_source=chatgpt.com">Apple 공식 Tech Talk 보기</a></p>
<p><strong>OpenAI — Debug in iOS Simulator</strong><br>Codex + XcodeBuildMCP를 이용해 Simulator를 실행하고 UI Tree, Tap/Type/Swipe, Screenshot, Log, LLDB를 활용해 reproduce-fix-verify Loop를 만드는 공식 Workflow입니다.<br><a href="https://learn.chatgpt.com/use-cases/ios-simulator-bug-debugging?utm_source=chatgpt.com">OpenAI 공식 iOS Simulator Workflow 보기</a></p>
<p>공식 자료 기준으로 보면 Duo 대응의 중심은 더 이상 단순한 화면 크기 대응에 머물지 않습니다. Apple은 <code>ReservedRegion</code>, <code>ArrangementView</code>, Vertical Bar와 App Resizability까지 Layout 대응 범위를 넓혔고, 동시에 실제 Duo Simulator를 제공하고 있습니다.</p>
<p>여기에 Codex의 Simulator Automation을 붙이면 <strong>UI Migration → 실행 → 재현 → Screenshot/Log 수집 → 수정 → 재검증</strong>까지 하나의 Workflow로 연결할 수 있습니다.</p>
<p>다만 현재는 Duo Device Hub의 모든 pose 변경까지 Codex나 XcodeBuildMCP가 자동 제어한다고 단정하기보다는, <strong>Simulator 내부 앱 조작 자동화와 Device Pose Automation을 별개의 영역으로 보고 사용하는 Tool 버전에서 지원 여부를 확인하는 것</strong>이 안전합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[문서 작업을 위한 AI 업무 총괄]]></title>
            <link>https://velog.io/@kyu_ios_dev/2608201</link>
            <guid>https://velog.io/@kyu_ios_dev/2608201</guid>
            <pubDate>Sun, 20 Sep 2026 02:02:16 GMT</pubDate>
            <description><![CDATA[<h3 id="문서-작업을-위한-ai-업무-총괄">문서 작업을 위한 AI 업무 총괄</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/88727f8f-4d92-4940-b25a-af45443c5230/image.png" alt=""></p>
<h2 id="자료-수집부터-한국어-보고서·차트·이미지·ppt·pdf·outlook-메일까지">자료 수집부터 한국어 보고서·차트·이미지·PPT·PDF·Outlook 메일까지</h2>
<p>AI 업무 도구를 비교할 때 흔히 모델 성능부터 이야기합니다.</p>
<p>하지만 실제 회사에서 보고서를 만들고 대표이사나 임원에게 발표해야 하는 사람에게 중요한 것은 조금 다릅니다.</p>
<pre><code class="language-text">파일을 쉽게 찾을 수 있는가?

PDF와 Excel 자료를 제대로 읽는가?

한국어 보고서를 자연스럽게 쓰는가?

차트가 보기 좋은가?

설명용 그림을 만들 수 있는가?

PPT가 실제 발표에 쓸 만한가?

수정본과 최종본을 관리하기 쉬운가?

마지막으로 메일까지 보낼 수 있는가?</code></pre>
<p>이 기준으로 보면 비교 대상은 CLI나 Coding Agent가 아닙니다.</p>
<p><strong>ChatGPT Work와 Gemini + Google Workspace</strong>처럼 문서 작업 전체를 맡길 수 있는 환경을 봐야 합니다.</p>
<p>특히 Git이나 Terminal을 모르는 비개발 직군이라면 더욱 그렇습니다.</p>
<p>이번 글에서는 하나의 업무를 처음 시작해서 최종 발표자료와 메일을 보내기까지 어떻게 구성하면 좋은지 정리해보겠습니다.</p>
<hr>
<h2 id="1-먼저-업무-파일-구조부터-단순하게-만든다">1. 먼저 업무 파일 구조부터 단순하게 만든다</h2>
<p>AI를 쓰기 전에 가장 먼저 할 일은 파일을 정리하는 것입니다.</p>
<p>복잡할 필요는 없습니다.</p>
<p>Windows에 이런 폴더 하나만 만들어도 충분합니다.</p>
<pre><code class="language-text">신규사업_검토/
│
├─ 01_원본자료
├─ 02_시장자료
├─ 03_분석자료
├─ 04_보고서
├─ 05_발표자료
├─ 06_이미지
└─ 07_최종본</code></pre>
<p><code>01_원본자료</code>에는 받은 파일을 그대로 넣습니다.</p>
<p>예를 들면:</p>
<pre><code class="language-text">시장조사.pdf

경쟁사자료.pdf

매출자료.xlsx

기존회사소개.pptx

제품사진.jpg</code></pre>
<p>입니다.</p>
<p>중요한 원칙은 <strong>원본을 직접 수정하지 않는 것</strong>입니다.</p>
<p>AI가 만든 자료와 원본자료를 분리하면 나중에 내용을 다시 확인하기 쉽습니다.</p>
<hr>
<h2 id="2-chatgpt-work는-windows-로컬-폴더에서-바로-시작할-수-있다">2. ChatGPT Work는 Windows 로컬 폴더에서 바로 시작할 수 있다</h2>
<p>ChatGPT Work를 데스크톱 앱에서 사용하면 <strong>로컬 폴더나 프로젝트를 열고 필요한 파일에 접근 권한을 줄 수 있습니다.</strong></p>
<p>즉 파일을 하나씩 매번 업로드할 필요 없이:</p>
<pre><code class="language-text">신규사업_검토</code></pre>
<p>폴더를 기준으로 작업할 수 있습니다.</p>
<p>웹이나 모바일 Work가 컴퓨터의 파일에 직접 접근하는 방식은 아니고, 이 로컬 폴더 접근은 데스크톱 앱에서 사용하는 흐름입니다. <a href="https://help.openai.com/ko-kr/articles/20001275?utm_source=chatgpt.com">ChatGPT Work 공식 안내</a></p>
<p>비개발자라면 여기서 Git이나 Repository 같은 것은 신경 쓸 필요가 없습니다.</p>
<p>그냥 Windows 탐색기 폴더라고 생각하면 됩니다.</p>
<p>예를 들어:</p>
<blockquote>
<p>01_원본자료와 02_시장자료에 있는 파일들을 읽고 이번 사업의 시장성, 경쟁사, 리스크를 먼저 정리해줘.</p>
</blockquote>
<p>정도로 시작하면 됩니다.</p>
<hr>
<h2 id="3-중요한-자료는-google-drive도-연결해둔다">3. 중요한 자료는 Google Drive도 연결해둔다</h2>
<p>회사 업무는 로컬 파일만 있는 경우가 드뭅니다.</p>
<p>공유받은 Google Docs나 Sheets, Slides가 있을 수 있고, 팀 전체가 Drive를 사용하는 경우도 많습니다.</p>
<p>ChatGPT에 Google Drive를 연결하면 이미 접근 권한을 가지고 있는 Drive의 Docs, Sheets, Slides와 파일을 찾아 활용할 수 있습니다. <a href="https://help.openai.com/en/articles/10929079-google-drive-app-and-setup-in-chatgpt?utm_source=chatgpt.com">ChatGPT Google Drive 공식 안내</a></p>
<p>구조는 이렇게 생각하면 됩니다.</p>
<pre><code class="language-text">Windows 로컬 폴더
        +
Google Drive
        ↓
   ChatGPT Work</code></pre>
<p>예를 들어:</p>
<pre><code class="language-text">로컬
- 공급사 PDF
- 내부 Excel

Drive
- 기존 사업계획서
- 회사소개 Slides
- 전년도 보고서</code></pre>
<p>를 동시에 참고해서 새 자료를 만드는 식입니다.</p>
<p>이렇게 하면 매번 모든 자료를 다시 첨부하는 수고를 줄일 수 있습니다.</p>
<hr>
<h2 id="4-gemini는-반대로-google-drive에서-시작하는-게-가장-자연스럽다">4. Gemini는 반대로 Google Drive에서 시작하는 게 가장 자연스럽다</h2>
<p>Gemini를 사용할 때는 Windows 폴더보다 <strong>Google Drive 자체를 업무 시작점으로 잡는 편이 편합니다.</strong></p>
<p>예를 들어 Drive에:</p>
<pre><code class="language-text">2026 신규사업/
│
├─ 원본
├─ 시장자료
├─ 분석
├─ 보고서
├─ Slides
└─ 최종본</code></pre>
<p>폴더를 만듭니다.</p>
<p>그리고 Gemini in Drive에서 자료를 찾아 요약하거나 새로운 Docs, Sheets, Slides를 생성합니다.</p>
<p>Google은 현재 Drive에서 Gemini를 이용해 Docs 문서, Sheets, Slides 프레젠테이션과 이미지까지 생성하는 Workflow를 제공하고 있습니다. <a href="https://support.google.com/drive/answer/16685527?hl=ko&amp;utm_source=chatgpt.com">Gemini in Drive 공식 안내</a></p>
<p>따라서 파일관리 측면에서는:</p>
<pre><code class="language-text">Drive
 ↓
Gemini
 ↓
Docs
Sheets
Slides</code></pre>
<p>구조가 상당히 자연스럽습니다.</p>
<hr>
<h2 id="5-첫-번째-결과물은-바로-ppt가-아니라-분석-메모가-좋다">5. 첫 번째 결과물은 바로 PPT가 아니라 ‘분석 메모’가 좋다</h2>
<p>자료를 넣자마자:</p>
<blockquote>
<p>PPT 15장 만들어줘.</p>
</blockquote>
<p>라고 요청하는 것보다 먼저 분석을 시키는 편이 좋습니다.</p>
<p>예를 들어:</p>
<blockquote>
<p>현재 자료를 기준으로  </p>
<ol>
<li>시장 규모  </li>
<li>경쟁사  </li>
<li>회사에 유리한 점  </li>
<li>예상 리스크  </li>
<li>추가 확인이 필요한 데이터<br>를 구분해서 정리해줘.<br>확인되지 않은 내용은 추정하지 말고 별도로 표시해줘.</li>
</ol>
</blockquote>
<p>처럼 요청합니다.</p>
<p>첫 단계에서는 디자인보다 <strong>내용이 맞는지</strong> 확인하는 것이 중요합니다.</p>
<p>구조는:</p>
<pre><code class="language-text">Raw Files
   ↓
AI Analysis
   ↓
Fact Check
   ↓
보고서
   ↓
Presentation</code></pre>
<p>순서가 좋습니다.</p>
<hr>
<h2 id="6-그다음-전문-한국어-보고서를-만든다">6. 그다음 전문 한국어 보고서를 만든다</h2>
<p>분석 내용이 맞으면 보고서로 바꿉니다.</p>
<p>여기서 Prompt를 조금 구체적으로 주는 것이 좋습니다.</p>
<p>예를 들면:</p>
<blockquote>
<p>대표이사가 읽는 사업 검토 보고서로 작성해줘.<br>너무 AI가 쓴 것처럼 과장하지 말고 한국 회사의 실제 보고서처럼 작성해줘.<br>결론을 먼저 보여주고 근거를 뒤에 설명해줘.<br>전문용어는 유지하되 문장은 길지 않게 작성해줘.</p>
</blockquote>
<p>이 정도만 해도 문체가 크게 달라집니다.</p>
<p>좋은 임원 보고서는 보통:</p>
<pre><code class="language-text">Executive Summary

시장 상황

기회

리스크

경제성

실행 방안

의사결정 사항</code></pre>
<p>순서가 읽기 쉽습니다.</p>
<p>중요한 것은 자료를 많이 쓰는 것이 아니라 <strong>의사결정할 내용을 빨리 찾게 만드는 것</strong>입니다.</p>
<hr>
<h2 id="7-숫자가-있으면-보고서보다-먼저-sheets를-만든다">7. 숫자가 있으면 보고서보다 먼저 Sheets를 만든다</h2>
<p>시장규모, 매출, 비용, 성장률 같은 데이터가 있다면 글에 바로 넣기보다 먼저 Spreadsheet로 정리하는 편이 좋습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">회사
시장점유율
매출
성장률
가격
예상비용</code></pre>
<p>을 표로 정리합니다.</p>
<p>그다음 차트를 만듭니다.</p>
<pre><code class="language-text">시장 성장률
→ Line Chart

경쟁사 비교
→ Bar Chart

시장 구성
→ Pie / Stacked Chart

매출 vs 비용
→ Bar / Line</code></pre>
<p>이렇게 해야 PPT의 숫자가 보고서와 다르게 나오는 문제를 줄일 수 있습니다.</p>
<hr>
<h2 id="8-차트는-gemini--sheets가-특히-편하다">8. 차트는 Gemini + Sheets가 특히 편하다</h2>
<p>Gemini in Sheets는 현재 데이터 분석뿐 아니라 <strong>차트와 그래프 생성</strong>을 직접 지원합니다.</p>
<p>예를 들어:</p>
<blockquote>
<p>X축은 연도, Y축은 매출로 해서 성장 추이를 보여주는 차트를 만들어줘.</p>
</blockquote>
<p>라고 요청할 수 있습니다.</p>
<p>또:</p>
<blockquote>
<p>경쟁사별 시장점유율을 비교하기 가장 적합한 차트를 만들어줘.</p>
</blockquote>
<p>처럼 차트 형태까지 맡길 수도 있습니다.</p>
<p>Gemini가 만든 차트는 Sheets에 넣고 다시 수정할 수 있습니다. <a href="https://support.google.com/docs/answer/14356410?hl=ko&amp;utm_source=chatgpt.com">Gemini in Sheets 차트 공식 안내</a></p>
<p>따라서 숫자 중심 보고서라면:</p>
<pre><code class="language-text">Source Data
    ↓
Google Sheets
    ↓
Gemini Analysis
    ↓
Chart
    ↓
Slides</code></pre>
<p>흐름이 상당히 편합니다.</p>
<hr>
<h2 id="9-chatgpt-work는-자료-분석부터-차트와-발표-논리를-같이-묶기-좋다">9. ChatGPT Work는 자료 분석부터 차트와 발표 논리를 같이 묶기 좋다</h2>
<p>ChatGPT Work는 문서, Spreadsheet, Presentation을 하나의 작업 흐름 안에서 만들거나 편집할 수 있습니다.</p>
<p>원본 자료나 기존 회사 PPT를 Reference로 넣고 새 결과물을 만드는 것도 가능합니다. <a href="https://help.openai.com/ko-kr/articles/20001278?utm_source=chatgpt.com">ChatGPT Work 문서·프레젠테이션 공식 안내</a></p>
<p>그래서:</p>
<pre><code class="language-text">시장자료
 ↓
분석
 ↓
차트
 ↓
해석
 ↓
Executive Summary
 ↓
PPT Storyline</code></pre>
<p>를 한 흐름으로 이어가기 쉽습니다.</p>
<p>특히 차트를 만들 때 숫자만 보여주는 것보다:</p>
<blockquote>
<p>이 차트에서 대표가 봐야 하는 핵심 메시지를 한 줄 제목으로 만들어줘.</p>
</blockquote>
<p>처럼 요청하면 발표자료가 훨씬 좋아집니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">2026년 시장규모 15% 성장</code></pre>
<p>보다</p>
<pre><code class="language-text">시장 성장보다 경쟁사 진입 속도가 더 빠르다</code></pre>
<p>처럼 <strong>의미가 있는 제목</strong>을 만들 수 있습니다.</p>
<hr>
<h2 id="10-차트-다음에는-설명용-이미지를-만든다">10. 차트 다음에는 설명용 이미지를 만든다</h2>
<p>PPT에서 모든 내용을 표와 글자로만 설명하면 읽기 힘듭니다.</p>
<p>이럴 때 생성 이미지를 사용합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">사업 구조

공급망

서비스 이용 흐름

고객 Journey

기술 개념

시장 구조</code></pre>
<p>같은 내용입니다.</p>
<p>ChatGPT에서는 필요한 이미지나 설명용 일러스트를 직접 생성해 발표자료의 시각 자료로 활용하기 좋습니다.</p>
<p>구조는:</p>
<pre><code class="language-text">숫자
→ Chart

구조
→ Diagram

추상적인 개념
→ Illustration

제품
→ Product / Reference Image</code></pre>
<p>처럼 나누는 편이 좋습니다.</p>
<p>모든 것을 생성 이미지로 만들 필요는 없습니다.</p>
<hr>
<h2 id="11-gemini도-slides-안에서-이미지를-생성할-수-있다">11. Gemini도 Slides 안에서 이미지를 생성할 수 있다</h2>
<p>Gemini 역시 Google Slides 안에서 Gemini 3 Pro Image를 이용해 이미지를 생성하고 수정할 수 있습니다.</p>
<p>슬라이드를 열고 이미지가 필요한 위치에서 프롬프트를 이용해 이미지를 만드는 방식입니다. <a href="https://support.google.com/docs/answer/16443280?hl=ko&amp;utm_source=chatgpt.com">Gemini Slides 이미지 생성 공식 안내</a></p>
<p>따라서:</p>
<pre><code class="language-text">Google Slides
      ↓
Gemini
      ↓
Image 생성
      ↓
Slide에 바로 삽입</code></pre>
<p>구조가 가능합니다.</p>
<p>Gemini의 장점은 이미지 자체보다 <strong>Slides 안에서 바로 이어서 수정할 수 있다는 것</strong>입니다.</p>
<hr>
<h2 id="12-이제-ppt-storyline을-만든다">12. 이제 PPT Storyline을 만든다</h2>
<p>바로 슬라이드를 만들기 전에 먼저 목차만 만듭니다.</p>
<p>대표이사 보고자료라면 예를 들어:</p>
<pre><code class="language-text">01. 왜 지금 검토해야 하는가

02. 시장은 얼마나 큰가

03. 경쟁사는 어디까지 왔는가

04. 우리에게 어떤 기회가 있는가

05. 예상 수익은 얼마인가

06. 가장 큰 위험은 무엇인가

07. 어떻게 시작할 것인가

08. 오늘 결정해야 할 것은 무엇인가</code></pre>
<p>정도로 잡을 수 있습니다.</p>
<p>이 단계에서 가장 중요한 것은 <strong>슬라이드 개수가 아니라 이야기 순서</strong>입니다.</p>
<hr>
<h2 id="13-ppt는-한-장에-한-메시지를-기본으로-한다">13. PPT는 ‘한 장에 한 메시지’를 기본으로 한다</h2>
<p>AI에게 PPT를 맡기면 흔히 한 장에 글을 너무 많이 넣습니다.</p>
<p>그래서 처음부터 조건을 주는 것이 좋습니다.</p>
<blockquote>
<p>한 슬라이드에는 하나의 핵심 메시지만 넣어줘.<br>본문은 3~5줄 이내로 줄여줘.<br>숫자는 가능하면 차트로 표현하고, 구조는 다이어그램으로 바꿔줘.<br>대표가 5초 안에 핵심을 이해할 수 있게 해줘.</p>
</blockquote>
<p>이런 조건을 줍니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">슬라이드 제목

한국 시장은 성장하고 있지만
경쟁사 진입 속도가 더 빠르다</code></pre>
<p>그리고 아래에는 설명보다 차트 하나를 둡니다.</p>
<p>이런 형태가 발표자료에 더 적합합니다.</p>
<hr>
<h2 id="14-chatgpt-work에서는-기존-회사-ppt를-템플릿으로-활용한다">14. ChatGPT Work에서는 기존 회사 PPT를 템플릿으로 활용한다</h2>
<p>회사에는 대부분 이미 사용하던 PPT가 있습니다.</p>
<pre><code class="language-text">회사소개.pptx

이사회보고.pptx

사업계획서.pptx</code></pre>
<p>중 하나를 Reference나 Template로 넣어:</p>
<blockquote>
<p>이 파일의 제목 위치, 글자 크기, 표 스타일, 차트 분위기, 페이지 구성을 유지하면서 새 사업자료를 만들어줘.</p>
</blockquote>
<p>처럼 요청할 수 있습니다.</p>
<p>ChatGPT Work는 Word, Excel, PowerPoint 또는 Google Workspace 파일을 기반으로 재사용 가능한 Template를 만드는 Workflow를 지원합니다. <a href="https://help.openai.com/ko-kr/articles/20001278?utm_source=chatgpt.com">ChatGPT Work 템플릿 공식 안내</a></p>
<p>시니어 직급에서는 이 기능이 꽤 중요합니다.</p>
<p>매번 예쁜 디자인을 새로 만드는 것보다 <strong>회사에서 이미 사용하는 양식을 유지하는 것이 실제 업무에서는 더 중요</strong>하기 때문입니다.</p>
<hr>
<h2 id="15-단-windows-work에서-powerpoint-직접-편집은-구분해서-봐야-한다">15. 단, Windows Work에서 PowerPoint 직접 편집은 구분해서 봐야 한다</h2>
<p>현재 ChatGPT Work 공식 안내에서 중요한 제한이 하나 있습니다.</p>
<p>ChatGPT Work 전체는 Presentation 생성과 편집을 지원하지만, <strong>Windows/Desktop Work의 직접 Microsoft PowerPoint 통합은 현재 Excel처럼 포함된 형태가 아닙니다.</strong></p>
<p>따라서 Windows 로컬 폴더에서 자료를 분석한 뒤:</p>
<pre><code class="language-text">ChatGPT Work Web에서 Presentation 작성</code></pre>
<p>또는:</p>
<pre><code class="language-text">Google Slides Native 파일 생성</code></pre>
<p>방식을 사용하는 것이 더 자연스럽습니다. <a href="https://help.openai.com/en/articles/20001278-creating-and-editing-documents-spreadsheets-and-presentations-with-chatgpt-work?utm_source=chatgpt.com">ChatGPT Work 공식 안내</a></p>
<p>이 차이는 미리 알아두는 것이 좋습니다.</p>
<hr>
<h2 id="16-gemini는-기존-google-slides의-스타일을-재사용한다">16. Gemini는 기존 Google Slides의 스타일을 재사용한다</h2>
<p>Gemini에서도 기존 Slides를 Reference로 넣어 비슷한 스타일의 새 발표자료를 만들 수 있습니다.</p>
<p>Google Slides의 Gemini는 Drive의 다른 Presentation을 Reference로 추가하고 기존 Presentation Style을 맞추는 기능을 제공합니다. <a href="https://support.google.com/docs/answer/17111393?hl=en&amp;utm_source=chatgpt.com">Gemini Slides 공식 안내</a></p>
<p>따라서 회사 자료가 이미 Google Slides 중심이라면 상당히 편합니다.</p>
<pre><code class="language-text">기존 임원보고 Slides
       ↓
Gemini
       ↓
새 보고자료</code></pre>
<p>로 이어갈 수 있습니다.</p>
<hr>
<h2 id="17-gemini의-한국어-ppt는-기능별-지원-범위를-확인해야-한다">17. Gemini의 한국어 PPT는 기능별 지원 범위를 확인해야 한다</h2>
<p>한국어 자체로 Gemini를 사용하는 것은 문제가 없지만, 현재 Google 공식 문서에서는 <strong>일부 전체 Presentation Generation이나 신규 Slides 생성 기능이 데스크톱 영어 전용으로 표시되는 기능이 남아 있습니다.</strong></p>
<p>따라서 한국어 발표자료를 핵심 Workflow로 사용할 경우 실제 회사 계정에서 해당 기능이 한국어로 어느 범위까지 열려 있는지 확인하는 것이 좋습니다. <a href="https://support.google.com/docs/answer/16961475?hl=ko&amp;utm_source=chatgpt.com">Gemini Slides 언어 지원 안내</a></p>
<p>한국어가 지원되는 범위에서는 기존 Slides 수정, 내용 작성, Drive 자료 참조, 이미지 생성 등을 조합해서 사용할 수 있습니다.</p>
<hr>
<h2 id="18-완성된-ppt는-반드시-pdf로-한-번-확인한다">18. 완성된 PPT는 반드시 PDF로 한 번 확인한다</h2>
<p>AI가 만든 Presentation을 최종본이라고 바로 보내지 않는 것이 좋습니다.</p>
<p>먼저 PDF로 변환해서 확인합니다.</p>
<p>확인할 것은:</p>
<pre><code class="language-text">글자가 잘리지 않았는가

표가 너무 작은가

차트 숫자가 맞는가

이미지가 깨지지 않았는가

페이지마다 제목 톤이 같은가

회사 로고 위치가 일정한가

출처가 빠지지 않았는가</code></pre>
<p>입니다.</p>
<p>Presentation 편집 화면에서는 괜찮아 보여도 PDF에서 줄바꿈이나 레이아웃이 다르게 보일 수 있습니다.</p>
<p>따라서:</p>
<pre><code class="language-text">Presentation
 ↓
PDF
 ↓
최종 검토</code></pre>
<p>를 마지막 Quality Check로 두는 것이 좋습니다.</p>
<hr>
<h2 id="19-발표-대본도-같은-자료에서-같이-만든다">19. 발표 대본도 같은 자료에서 같이 만든다</h2>
<p>PPT가 완성되면 별도로 발표 Script를 만들 필요가 없습니다.</p>
<p>AI에게:</p>
<blockquote>
<p>이 12장 발표자료를 기준으로 7분 발표 대본을 만들어줘.<br>슬라이드 내용을 그대로 읽지 말고, 각 슬라이드에서 말해야 할 핵심만 작성해줘.<br>대표이사 보고이므로 결론을 먼저 말하는 방식으로 작성해줘.</p>
</blockquote>
<p>라고 요청합니다.</p>
<p>형식은:</p>
<pre><code class="language-text">Slide 1
30초

Slide 2
40초

Slide 3
30초</code></pre>
<p>처럼 시간까지 붙이는 것이 좋습니다.</p>
<p>마지막에는 예상 질문도 만듭니다.</p>
<pre><code class="language-text">대표가 물을 질문 10개

재무팀 질문 5개

영업팀 질문 5개

각 질문의 답변</code></pre>
<p>까지 만들어두면 실제 발표 준비가 훨씬 쉬워집니다.</p>
<hr>
<h2 id="20-발표가-끝난-뒤에는-outlook-메일까지-작성한다">20. 발표가 끝난 뒤에는 Outlook 메일까지 작성한다</h2>
<p>최종 자료를 만들었다면 마지막 업무는 공유입니다.</p>
<p>ChatGPT에서는 Outlook Email 연결이 가능하면 Outlook 메일을 검색·읽고, 회신이나 새 메일 초안을 작성하는 Workflow까지 연결할 수 있습니다.</p>
<p>예를 들어:</p>
<blockquote>
<p>오늘 대표이사 보고한 사업검토 자료를 임원들에게 보내는 메일을 작성해줘.<br>너무 딱딱하지 않게 하고, 결정된 내용 3개와 추가 검토사항 2개를 본문에 넣어줘.</p>
</blockquote>
<p>처럼 요청합니다.</p>
<p>그러면:</p>
<pre><code class="language-text">제목

본문

첨부파일 안내

후속 일정

요청사항</code></pre>
<p>까지 구성할 수 있습니다.</p>
<p>Outlook을 실제로 사용하는 환경이라면 위에 표시된 <strong>Outlook Email 연결</strong>을 해두면 이런 작업을 ChatGPT에서 직접 이어가기 편합니다.</p>
<hr>
<h2 id="21-gemini를-쓸-경우-outlook은-한-단계-떨어져-있다">21. Gemini를 쓸 경우 Outlook은 한 단계 떨어져 있다</h2>
<p>Gemini Workspace의 Native Mail 환경은 Gmail입니다.</p>
<p>따라서 회사가 Outlook을 쓴다면:</p>
<pre><code class="language-text">Gemini
 ↓
메일 초안 작성
 ↓
Copy
 ↓
Outlook</code></pre>
<p>방식으로 사용하는 것이 가장 단순합니다.</p>
<p>또는 Outlook 자체의 Copilot을 사용하는 방법도 있습니다.</p>
<p>Microsoft는 Outlook에서 Copilot을 이용해 이메일 Draft를 작성하는 기능을 공식적으로 지원합니다. <a href="https://support.microsoft.com/ko-kr/outlook/copilot-pages/draft-an-email-message-with-copilot-in-outlook?utm_source=chatgpt.com">Outlook Copilot 메일 작성 공식 안내</a></p>
<p>즉 회사 업무환경이:</p>
<pre><code class="language-text">Google Workspace + Gmail</code></pre>
<p>이라면 Gemini가 자연스럽고,</p>
<pre><code class="language-text">Google Drive + Outlook</code></pre>
<p>같은 혼합 환경이라면 ChatGPT Work 쪽이 상대적으로 연결하기 편할 수 있습니다.</p>
<hr>
<h2 id="22-파일과-리소스는-ai-안에만-두지-않는다">22. 파일과 리소스는 AI 안에만 두지 않는다</h2>
<p>AI 채팅만 믿고 파일을 관리하는 것은 추천하지 않습니다.</p>
<p>최종 자료는 반드시 회사 저장소에 보관합니다.</p>
<p>가장 단순한 방법은 Google Drive입니다.</p>
<pre><code class="language-text">2026 신규사업/
│
├─ 01_Source
├─ 02_Data
├─ 03_Report
├─ 04_Charts
├─ 05_Images
├─ 06_Presentation
└─ 07_Final</code></pre>
<p>이 정도면 충분합니다.</p>
<p>Google Docs, Sheets, Slides는 변경 이력을 관리할 수 있고, Drive의 일반 PDF·이미지·기타 파일도 버전을 관리할 수 있습니다. <a href="https://support.google.com/drive/answer/2409045?hl=ko-KR&amp;utm_source=chatgpt.com">Google Drive 파일 버전 관리 공식 안내</a></p>
<p>비개발 직군이라면 Git보다 이 방식이 훨씬 현실적입니다.</p>
<hr>
<h2 id="23-chatgpt-library는-작업-자료를-다시-찾는-용도로-활용한다">23. ChatGPT Library는 작업 자료를 다시 찾는 용도로 활용한다</h2>
<p>ChatGPT도 업로드하거나 생성한 파일을 Library에서 다시 사용할 수 있습니다.</p>
<p>Google Drive 파일이 연결돼 있다면 Drive 원본과 연결된 상태로 활용할 수도 있습니다. <a href="https://help.openai.com/ko-kr/articles/20001052-using-library-to-manage-files-in-chatgpt?utm_source=chatgpt.com">ChatGPT Library 공식 안내</a></p>
<p>다만 회사의 최종 문서관리 체계는:</p>
<pre><code class="language-text">Drive
SharePoint
OneDrive</code></pre>
<p>같은 회사 저장소에 두는 것이 좋습니다.</p>
<p>AI Library는 <strong>작업 공간</strong>, Drive나 회사 문서시스템은 <strong>공식 보관소</strong>라고 생각하면 이해하기 쉽습니다.</p>
<hr>
<h2 id="24-한-번-만든-좋은-자료는-템플릿으로-저장한다">24. 한 번 만든 좋은 자료는 템플릿으로 저장한다</h2>
<p>업무 효율을 가장 크게 높이는 것은 AI에게 매번 처음부터 설명하지 않는 것입니다.</p>
<p>한 번 좋은:</p>
<pre><code class="language-text">대표이사 보고서

신규사업 PPT

시장분석 보고서

주간회의 자료</code></pre>
<p>가 만들어졌다면 그것을 다음 업무의 Template로 사용합니다.</p>
<p>예를 들어:</p>
<blockquote>
<p>지난 신규사업 검토자료와 같은 구조로 이번 중국 제조사 검토자료를 만들어줘.</p>
</blockquote>
<p>라고 요청할 수 있습니다.</p>
<p>그러면:</p>
<pre><code class="language-text">제목 구조

Executive Summary

표 디자인

차트 스타일

슬라이드 구성

문체</code></pre>
<p>를 매번 다시 설명할 필요가 줄어듭니다.</p>
<hr>
<h2 id="25-비개발-시니어에게-추천하는-chatgpt-work-workflow">25. 비개발 시니어에게 추천하는 ChatGPT Work Workflow</h2>
<p>전체를 한 번에 정리하면 이렇습니다.</p>
<pre><code class="language-text">Windows 업무 폴더
        +
Google Drive
        ↓
ChatGPT Work
        ↓
자료 통합 분석
        ↓
한국어 전문 보고서
        ↓
Spreadsheet / Chart
        ↓
이미지 / Diagram
        ↓
PPT Storyline
        ↓
Presentation
        ↓
PDF 검토
        ↓
발표 Script
        ↓
Outlook Draft
        ↓
Google Drive 최종 보관</code></pre>
<p>장점은 <strong>내용을 만들고 해석하고 시각화하는 작업을 하나의 대화 흐름에서 이어가기 쉽다</strong>는 점입니다.</p>
<hr>
<h2 id="26-비개발-시니어에게-추천하는-gemini-workflow">26. 비개발 시니어에게 추천하는 Gemini Workflow</h2>
<p>Gemini는 Drive 자체를 중심으로 시작합니다.</p>
<pre><code class="language-text">Google Drive
     ↓
Gemini
     ↓
Docs 보고서
     ↓
Sheets 분석
     ↓
Chart
     ↓
Slides
     ↓
Image
     ↓
PDF
     ↓
Drive Version History</code></pre>
<p>회사 업무가 Google Workspace 중심이라면 상당히 자연스럽습니다.</p>
<p>특히:</p>
<pre><code class="language-text">자료 공유

공동 편집

댓글

Version History

파일 검색</code></pre>
<p>은 Google Workspace의 강점입니다.</p>
<hr>
<h2 id="27-그래서-무엇을-선택하는-것이-좋을까">27. 그래서 무엇을 선택하는 것이 좋을까</h2>
<p><strong>한국어 전문자료의 내용 완성도, 차트, 이미지, PPT 스토리라인까지 AI에게 많이 맡기고 싶다면 ChatGPT Work를 중심으로 시작하는 편이 좋습니다.</strong></p>
<p>그리고 파일은 Google Drive에 보관합니다.</p>
<pre><code class="language-text">ChatGPT Work
→ 만드는 곳

Google Drive
→ 관리하는 곳</code></pre>
<p>이라고 생각하면 쉽습니다.</p>
<p>반대로:</p>
<p><strong>회사가 Google Workspace를 중심으로 움직이고 있고 공동 편집과 파일관리가 가장 중요하다면 Gemini가 자연스럽습니다.</strong></p>
<pre><code class="language-text">Gemini
+
Docs
+
Sheets
+
Slides
+
Drive</code></pre>
<p>가 하나의 생태계 안에서 움직이기 때문입니다.</p>
<hr>
<h2 id="28-가장-현실적인-방법은-둘-중-하나만-고집하지-않는-것이다">28. 가장 현실적인 방법은 둘 중 하나만 고집하지 않는 것이다</h2>
<p>실제 업무에서는 이렇게 사용해도 됩니다.</p>
<pre><code class="language-text">자료 분석
한국어 보고서
PPT 스토리라인
이미지

→ ChatGPT Work</code></pre>
<p>그리고:</p>
<pre><code class="language-text">Sheets
Slides
공동 편집
Version History
최종 파일 관리

→ Google Workspace</code></pre>
<p>즉:</p>
<pre><code class="language-text">ChatGPT Work
     ↓
콘텐츠 제작
     ↓
Google Workspace
     ↓
회사 업무자산</code></pre>
<p>으로 연결합니다.</p>
<p>현재 두 제품의 장점을 가장 현실적으로 가져가는 방식입니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>비개발 시니어에게 AI 업무도구를 선택할 때 중요한 것은 모델의 Benchmark가 아닙니다.</p>
<p>실제 업무는:</p>
<pre><code class="language-text">자료를 찾고

읽고

판단하고

보고서를 만들고

숫자를 차트로 만들고

개념을 그림으로 설명하고

PPT로 설득하고

PDF로 검토하고

메일로 공유하고

다음 사람이 다시 찾을 수 있게 보관하는 것</code></pre>
<p>까지 이어집니다.</p>
<p>그래서 좋은 AI 업무환경은 문장을 잘 쓰는 AI가 아니라 <strong>업무의 처음과 끝을 연결해주는 환경</strong>이어야 합니다.</p>
<p>현재 기준으로 가장 현실적인 조합은:</p>
<pre><code class="language-text">ChatGPT Work
+
Google Drive / Docs / Sheets / Slides
+
Outlook</code></pre>
<p>입니다.</p>
<p>ChatGPT Work가 자료 분석과 전문 한국어 작성, 차트·이미지·프레젠테이션 제작의 중심 역할을 맡고,</p>
<p>Google Workspace가 파일과 공동작업, Version History를 담당하고,</p>
<p>Outlook이 최종 커뮤니케이션을 담당하는 구조입니다.</p>
<p>Gemini는 Google Workspace 안에서 이 과정을 더욱 자연스럽게 연결할 수 있다는 강점이 있습니다.</p>
<p>결국 선택 기준은 단순합니다.</p>
<p><strong>잘 만드는 것이 가장 중요하면 ChatGPT Work 중심.</strong></p>
<p><strong>잘 관리하고 함께 수정하는 것이 가장 중요하면 Gemini + Workspace 중심.</strong></p>
<p>그리고 둘을 같이 쓸 수 있다면,</p>
<p><strong>ChatGPT Work에서 만들고 Google Workspace에서 관리하는 방식</strong>이 현재 비개발 시니어의 전문자료 업무에는 가장 실용적인 조합 중 하나입니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/e97cf6b8-4687-4afa-8b8c-d8be4298ae69/image.png" alt=""></p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>OpenAI — ChatGPT Work 문서·스프레드시트·프레젠테이션</strong><br>Work에서 문서, Spreadsheet, Presentation을 만들고 기존 PPT·Google Slides 등을 Template로 재사용하는 방법을 확인할 수 있습니다.<br><a href="https://help.openai.com/ko-kr/articles/20001278?utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>OpenAI — ChatGPT Work와 로컬 파일</strong><br>데스크톱 앱에서 로컬 폴더나 프로젝트에 접근 권한을 주고 작업하는 방식과 웹/모바일과의 차이를 확인할 수 있습니다.<br><a href="https://help.openai.com/ko-kr/articles/20001275?utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>OpenAI — Google Drive 연결</strong><br>ChatGPT에서 Drive, Docs, Sheets, Slides 자료를 검색하고 활용하는 방법을 확인할 수 있습니다.<br><a href="https://help.openai.com/en/articles/10929079-google-drive-app-and-setup-in-chatgpt?utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>Google — Gemini in Drive</strong><br>Drive에서 Gemini로 Docs, Sheets, Slides와 이미지를 생성하는 Workflow를 확인할 수 있습니다.<br><a href="https://support.google.com/drive/answer/16685527?hl=ko&amp;utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>Google — Gemini in Sheets</strong><br>Gemini를 이용한 데이터 분석, 차트·그래프 생성과 Spreadsheet 자동화 기능을 확인할 수 있습니다.<br><a href="https://support.google.com/docs/answer/14356410?hl=ko&amp;utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>Google — Gemini in Slides</strong><br>Slides 생성·편집, Drive 자료 참조와 현재 언어별 기능 지원 범위를 확인할 수 있습니다.<br><a href="https://support.google.com/docs/answer/16961475?hl=ko&amp;utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>Google — Slides 이미지 생성</strong><br>Gemini 3 Pro Image를 이용해 Slides 내부에서 이미지를 생성하고 수정하는 기능을 확인할 수 있습니다.<br><a href="https://support.google.com/docs/answer/16443280?hl=ko&amp;utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>Google — Drive 버전 관리</strong><br>Google 파일과 PDF·이미지 등 일반 Drive 파일의 버전 관리 방법을 확인할 수 있습니다.<br><a href="https://support.google.com/drive/answer/2409045?hl=ko-KR&amp;utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
<li><p><strong>Microsoft — Outlook Copilot 메일 작성</strong><br>Outlook에서 AI를 이용해 업무메일 Draft를 작성하는 공식 Workflow를 확인할 수 있습니다.<br><a href="https://support.microsoft.com/ko-kr/outlook/copilot-pages/draft-an-email-message-with-copilot-in-outlook?utm_source=chatgpt.com">공식 자료 보기</a></p>
</li>
</ul>
<p><strong>공식 자료 기준으로 보면</strong>, ChatGPT Work는 Windows 데스크톱에서 로컬 폴더를 직접 활용할 수 있고 Google Drive를 연결하면 Docs·Sheets·Slides의 Native 파일까지 작업에 사용할 수 있습니다. 다만 Windows Work에서 Microsoft PowerPoint 자체를 Excel처럼 직접 조작하는 통합은 현재 별도로 구분되어 있으므로, Presentation 작업은 Work Web이나 Google Slides Workflow로 가져가는 편이 명확합니다.</p>
<p>Gemini는 Drive·Docs·Sheets·Slides가 한 제품군 안에 있기 때문에 파일관리와 공동편집, Version History에서 강점이 있습니다. 특히 Sheets의 Gemini는 차트 생성까지 직접 지원하고 Slides에서는 이미지 생성과 편집이 가능합니다. 다만 일부 신규 Presentation Generation 기능은 현재 공식 문서에서 영어 전용으로 안내되는 영역이 남아 있으므로 한국어 중심 업무에서는 실제 조직 계정에서 제공 범위를 확인하는 것이 좋습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Jev가 뭐냐]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609191</link>
            <guid>https://velog.io/@kyu_ios_dev/2609191</guid>
            <pubDate>Fri, 18 Sep 2026 23:25:12 GMT</pubDate>
            <description><![CDATA[<h3 id="jev가-뭐냐">Jev가 뭐냐</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/2f7b0a83-ee7e-449e-8dc8-61ad3087dfe6/image.png" alt=""></p>
<h2 id="판단만-빠르게-하는-ai가-나온-이유">판단만 빠르게 하는 AI가 나온 이유</h2>
<p>최근 AI 모델은 점점 더 많은 일을 할 수 있게 됐습니다.</p>
<p>코드를 작성하고, 웹을 검색하고, Tool을 호출하고, 여러 단계를 거쳐 문제를 해결합니다.</p>
<p>그런데 실제 서비스를 만들다 보면 모든 문제에 이런 큰 모델이 필요한 것은 아닙니다.</p>
<p>예를 들어 이런 판단이 있습니다.</p>
<pre><code class="language-text">이 문의는 결제 문제인가?

이 요청을 검색으로 보낼까,
DB 조회로 보낼까?

이 메시지는 위험한가?

이 결과를 자동 승인해도 되는가?

이 Agent의 응답을 다시 검토해야 하는가?</code></pre>
<p>각각은 AI가 필요한 문제일 수 있습니다.</p>
<p>하지만 GPT나 Claude 같은 Frontier LLM에게 매번 긴 답변을 생성하게 하는 것은 꽤 비싼 방법이기도 합니다.</p>
<p>TypeSafe AI가 2026년 9월 14일 공개한 <strong>Jev</strong>는 바로 이 지점을 노립니다.</p>
<p>Jev는 대화를 잘하는 모델이 아닙니다.</p>
<p>코드를 길게 작성하는 모델도 아닙니다.</p>
<p>TypeSafe는 Jev를 새로운 <strong>System One Model</strong>이라고 부릅니다.</p>
<p>핵심은 단순합니다.</p>
<p><strong>문장을 생성하는 대신, 소프트웨어가 바로 사용할 수 있는 판단을 빠르게 반환합니다.</strong></p>
<hr>
<h1 id="1-jev는-무엇이-다른가">1. Jev는 무엇이 다른가</h1>
<p>일반적인 LLM은 기본적으로 문자열을 생성합니다.</p>
<pre><code class="language-text">Input
 ↓
LLM
 ↓
Token
 ↓
Token
 ↓
Token
 ↓
Text</code></pre>
<p>결과가 JSON이더라도 기본적으로는 문자열 생성입니다.</p>
<pre><code class="language-json">{
  &quot;category&quot;: &quot;billing&quot;,
  &quot;confidence&quot;: 0.96
}</code></pre>
<p>Structured Output이나 JSON Schema를 사용하면 결과 형태를 강제할 수 있지만, 내부에서는 여전히 Token을 순차적으로 생성하는 Generative Model입니다.</p>
<p>Jev는 이 방향을 처음부터 다르게 잡았습니다.</p>
<pre><code class="language-text">Unstructured State
        ↓
       Jev
        ↓
Typed Probabilistic Decision</code></pre>
<p>예를 들어:</p>
<pre><code class="language-text">사용자 메시지

&quot;카드 결제가 두 번 됐어요.&quot;</code></pre>
<p>를 넣고</p>
<pre><code class="language-text">billing
technical
account
other</code></pre>
<p>중 하나를 판단하도록 하면 Jev는 긴 설명을 생성하는 대신 각 선택지에 대한 판단과 확률을 반환하는 구조입니다.</p>
<p>개념적으로는:</p>
<pre><code class="language-text">billing      0.96
technical    0.02
account      0.01
other        0.01</code></pre>
<p>처럼 사용할 수 있습니다.</p>
<p>그래서 TypeSafe는 Jev를</p>
<p><strong>“frontier-intelligence function call”</strong></p>
<p>에 가깝다고 설명합니다.</p>
<hr>
<h1 id="2-챗봇보다-if문에-가까운-ai다">2. 챗봇보다 <code>if</code>문에 가까운 AI다</h1>
<p>Jev를 이해하기 가장 쉬운 방법은 챗봇보다 <strong>똑똑한 조건문</strong>이라고 생각하는 것입니다.</p>
<p>기존 코드라면 이런 식입니다.</p>
<pre><code class="language-swift">if message.contains(&quot;결제&quot;) {
    route = .billing
} else if message.contains(&quot;비밀번호&quot;) {
    route = .account
}</code></pre>
<p>문제는 현실의 언어가 이렇게 단순하지 않다는 것입니다.</p>
<pre><code class="language-text">&quot;결제가 안 된 것 같은데 돈은 빠져나갔어요.&quot;

&quot;카드는 정상인데 주문이 두 번 잡혔습니다.&quot;

&quot;환불했다고 했는데 아직 입금이 안 됐어요.&quot;</code></pre>
<p>Rule을 계속 늘리기 시작하면 유지하기 어려워집니다.</p>
<p>Jev가 노리는 영역은 이 사이입니다.</p>
<pre><code class="language-text">Hard-coded if

        ↓

Jev

        ↓

Full LLM Agent</code></pre>
<p>규칙만으로 처리하기에는 애매하지만,</p>
<p>GPT나 Claude Agent까지 호출하기에는 과한 판단입니다.</p>
<hr>
<h1 id="3-typesafe는-이것을-system-one-model이라고-부른다">3. TypeSafe는 이것을 System One Model이라고 부른다</h1>
<p>이름은 Daniel Kahneman의 《Thinking, Fast and Slow》에서 가져왔습니다.</p>
<p>Kahneman은 인간의 사고를 크게 두 가지로 설명했습니다.</p>
<pre><code class="language-text">System 1

빠름
직관적
즉각적</code></pre>
<p>그리고</p>
<pre><code class="language-text">System 2

느림
숙고
복잡한 추론</code></pre>
<p>TypeSafe는 이 개념을 AI Model Architecture에 적용했습니다.</p>
<p>기존 Reasoning LLM이 상대적으로:</p>
<pre><code class="language-text">Input
 ↓
Reasoning
 ↓
Generation
 ↓
Answer</code></pre>
<p>에 가깝다면,</p>
<p>Jev는:</p>
<pre><code class="language-text">Input
 ↓
Decision</code></pre>
<p>에 집중합니다.</p>
<p>그래서 모델 이름도 <strong>System One Models</strong>입니다.</p>
<p>Jev라는 이름은 경제학자 William Stanley Jevons에서 가져왔습니다.</p>
<hr>
<h1 id="4-jev는-작은-llm이-아니다">4. Jev는 작은 LLM이 아니다</h1>
<p>여기서 가장 쉽게 오해할 부분입니다.</p>
<p>Jev를 단순히</p>
<pre><code class="language-text">작은 LLM</code></pre>
<p>이라고 보면 정확하지 않습니다.</p>
<p>TypeSafe는 Jev를 기존 Language Model을 줄여 만든 모델이 아니라 <strong>결정이라는 다른 Task를 위해 새로 만든 Architecture</strong>라고 설명합니다.</p>
<p>학습 방식도 RLHF가 아닙니다.</p>
<p>TypeSafe는 자체 학습 방법을:</p>
<pre><code class="language-text">RLCD</code></pre>
<p>라고 부릅니다.</p>
<p><strong>Reinforcement Learning for Calibrated Decisions</strong>입니다.</p>
<p>기존 LLM이 주로:</p>
<pre><code class="language-text">사람이 좋아하는 답변

검증 가능한 정답</code></pre>
<p>을 최적화한다면,</p>
<p>Jev는:</p>
<pre><code class="language-text">정확한 판단
+
그 판단이 얼마나 확실한지</code></pre>
<p>를 함께 학습하는 방향입니다.</p>
<p>즉 목표 함수 자체가 다릅니다.</p>
<hr>
<h1 id="5-가장-중요한-특징은-confidence다">5. 가장 중요한 특징은 Confidence다</h1>
<p>자동화 시스템에서 AI가 어려운 이유 중 하나는 <strong>AI가 틀릴 때 자신이 틀렸다는 사실을 모르는 것</strong>입니다.</p>
<p>예를 들어 실제 정확도가 95%인 모델이 있다고 해보겠습니다.</p>
<p>문제는 나머지 5%입니다.</p>
<p>모델이 모든 결과에:</p>
<pre><code class="language-text">confidence = 0.99</code></pre>
<p>를 내놓는다면 자동화하기 어렵습니다.</p>
<p>반대로 모델의 Confidence가 실제 정확도와 잘 맞는다면 시스템을 이렇게 만들 수 있습니다.</p>
<pre><code class="language-text">Confidence &gt; 0.95
       ↓
자동 처리

0.70 ~ 0.95
       ↓
큰 LLM으로 재검토

&lt; 0.70
       ↓
사람에게 전달</code></pre>
<p>TypeSafe가 Jev에서 특히 강조하는 것이 바로 이 <strong>Calibrated Probability</strong>입니다.</p>
<p>단순히 답을 반환하는 것이 아니라 불확실성도 같이 반환합니다.</p>
<hr>
<h1 id="6-이게-agent-시스템에서는-꽤-중요하다">6. 이게 Agent 시스템에서는 꽤 중요하다</h1>
<p>최근 Agent Architecture에서 가장 자주 반복되는 작업 중 하나가 Routing입니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">User Request
     ↓
Router
     ↓
 ┌───┼─────────┐
Search DB   Coding Agent</code></pre>
<p>Router도 LLM으로 만들 수 있습니다.</p>
<p>하지만 요청이 들어올 때마다 Frontier Model을 호출하면 비용과 Latency가 커집니다.</p>
<p>Jev 같은 모델을 Router로 넣으면 구조가 달라집니다.</p>
<pre><code class="language-text">User Request
       ↓
      Jev
       ↓
┌──────┼─────────┐
Search DB     Agent</code></pre>
<p>그리고 Jev의 Confidence까지 사용합니다.</p>
<pre><code class="language-text">Search Agent     0.87
Database Tool    0.08
Human Review     0.05</code></pre>
<p>가 나오면 Search Agent로 보냅니다.</p>
<p>Confidence가 낮다면:</p>
<pre><code class="language-text">Research Agent    0.42
Database Tool     0.38
Human Review      0.20</code></pre>
<p>바로 실행하지 않고 큰 모델이나 사람에게 판단을 넘길 수 있습니다.</p>
<hr>
<h1 id="7-multi-agent에서도-router-역할로-잘-맞는다">7. Multi-Agent에서도 Router 역할로 잘 맞는다</h1>
<p>멀티에이전트 시스템을 생각해보면 더 이해하기 쉽습니다.</p>
<pre><code class="language-text">                    Main System
                         │
             ┌───────────┼───────────┐
             │           │           │
        Coding Agent  Research   Security
                       Agent      Agent</code></pre>
<p>모든 요청을 Main LLM이 분석하고 적절한 Agent에게 전달할 수도 있습니다.</p>
<p>하지만 요청량이 많다면 Routing 자체가 상당한 비용이 됩니다.</p>
<p>중간에 Jev를 넣을 수 있습니다.</p>
<pre><code class="language-text">Request
   ↓
  Jev
   ↓
Agent Routing
   ↓
선택된 Agent만 호출</code></pre>
<p>즉 Jev가 Agent를 대체하는 것이 아닙니다.</p>
<p><strong>Agent가 필요한지를 먼저 판단하는 앞단의 Decision Layer</strong>가 되는 것입니다.</p>
<hr>
<h1 id="8-skill--mcp-구조와도-잘-맞는다">8. Skill + MCP 구조와도 잘 맞는다</h1>
<p>최근 Agent Architecture는 모든 기능을 Agent로 만들기보다:</p>
<pre><code class="language-text">Skill
+
MCP Tool</code></pre>
<p>을 활용하는 방향으로 가고 있습니다.</p>
<p>예를 들어 사용자의 요청이 들어왔을 때:</p>
<pre><code class="language-text">Swift Migration Skill

Release Skill

GitHub MCP

Research Agent</code></pre>
<p>중 어디로 보낼지 결정해야 합니다.</p>
<p>구조는 이렇게 만들 수 있습니다.</p>
<pre><code class="language-text">Request
   ↓
  Jev
   ↓
 ┌──────┬────────┬────────────┐
Skill   MCP     Research Agent</code></pre>
<p>즉 Jev는 <strong>Agent Orchestrator 전체를 대신하기보다 Orchestrator가 반복적으로 하는 작은 판단을 줄이는 역할</strong>에 가깝습니다.</p>
<hr>
<h1 id="9-moderation과-guardrail도-대표적인-사용처다">9. Moderation과 Guardrail도 대표적인 사용처다</h1>
<p>두 번째로 잘 맞는 영역은 Moderation입니다.</p>
<p>기존 구조는:</p>
<pre><code class="language-text">Input
 ↓
LLM
 ↓
위험 여부 판단</code></pre>
<p>입니다.</p>
<p>하지만 서비스 요청마다 큰 모델을 호출한다면 부담이 됩니다.</p>
<p>Jev는 이런 형태의 판단에 맞게 설계됐습니다.</p>
<pre><code class="language-text">Safe          0.96
Harmful       0.03
Uncertain     0.01</code></pre>
<p>또는:</p>
<pre><code class="language-text">Prompt Injection

Yes   0.91
No    0.09</code></pre>
<p>처럼 사용할 수 있습니다.</p>
<p>특히 Agent 시스템에서는:</p>
<pre><code class="language-text">User Input
    ↓
Guardrail
    ↓
Agent
    ↓
Tool Call</code></pre>
<p>구조에서 매우 낮은 Latency의 판단 모델이 유용할 수 있습니다.</p>
<hr>
<h1 id="10-agent의-출력-검증에도-사용할-수-있다">10. Agent의 출력 검증에도 사용할 수 있다</h1>
<p>Jev는 입력만 분류하는 모델로 볼 필요도 없습니다.</p>
<p>Agent가 생성한 결과를 평가하는 Layer로도 사용할 수 있습니다.</p>
<p>예를 들어 Coding Agent가 수정 결과를 만들었습니다.</p>
<pre><code class="language-text">Coding Agent
      ↓
Code Change
      ↓
Jev Verification</code></pre>
<p>여기서:</p>
<pre><code class="language-text">요청을 충족했는가?

YES 0.94
NO  0.06</code></pre>
<p>또는:</p>
<pre><code class="language-text">Security Risk

Low       0.82
Medium    0.15
High      0.03</code></pre>
<p>같은 판단을 사용할 수 있습니다.</p>
<p>물론 실제 Build와 Test를 대체하는 것은 아닙니다.</p>
<pre><code class="language-text">Compiler
Test
Static Analysis</code></pre>
<p>처럼 결정적인 검증이 가능한 부분은 코드로 검증해야 합니다.</p>
<p>Jev는 그 사이의 애매한 판단을 담당하는 것이 더 적합합니다.</p>
<hr>
<h1 id="11-그래서-검증-가능한-것은-코드로가-중요하다">11. 그래서 <code>검증 가능한 것은 코드로</code>가 중요하다</h1>
<p>Jev를 쓴다고 모든 조건문을 AI로 바꿀 필요는 없습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">HTTP Status == 200</code></pre>
<p>은 코드로 판단하면 됩니다.</p>
<pre><code class="language-text">Build Success</code></pre>
<p>도 Tool 결과를 보면 됩니다.</p>
<pre><code class="language-text">Unit Test Passed</code></pre>
<p>역시 AI가 필요 없습니다.</p>
<p>반면:</p>
<pre><code class="language-text">이 리뷰 의견이 blocking issue인가?

이 고객 문의는 긴급한가?

이 검색 결과가 질문과 관련 있는가?

이 요청은 어느 Agent에게 보내야 하는가?</code></pre>
<p>같은 것은 Rule로 만들기 어렵습니다.</p>
<p>그래서 좋은 구조는:</p>
<pre><code class="language-text">Hard Logic
→ Code

Ambiguous Decision
→ Jev

Deep Reasoning
→ LLM / Agent</code></pre>
<p>입니다.</p>
<hr>
<h1 id="12-일반-llm의-structured-output과는-뭐가-다를까">12. 일반 LLM의 Structured Output과는 뭐가 다를까</h1>
<p>GPT나 Claude도 JSON Schema를 사용할 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-json">{
  &quot;route&quot;: &quot;research&quot;,
  &quot;confidence&quot;: 0.91
}</code></pre>
<p>를 반환하도록 만들 수 있습니다.</p>
<p>그렇다면 굳이 Jev가 필요한가라는 질문이 생깁니다.</p>
<p>차이는 <strong>Structured Output을 지원하느냐가 아니라 모델이 무엇을 위해 설계됐느냐</strong>입니다.</p>
<p>일반 LLM은:</p>
<pre><code class="language-text">Generative Model
        ↓
Schema Constraint
        ↓
Structured Output</code></pre>
<p>입니다.</p>
<p>Jev는:</p>
<pre><code class="language-text">Decision Model
       ↓
Typed Decision</code></pre>
<p>자체가 목적입니다.</p>
<p>그리고 TypeSafe 설명에 따르면 Jev는 모든 결과를 순차 Token Generation이 아니라 <strong>병렬로 계산</strong>합니다.</p>
<p>문장을 생성하지 않기 때문에 Output Generation Cost도 거의 없습니다.</p>
<hr>
<h1 id="13-type-safety라는-이름도-여기에서-나온다">13. Type Safety라는 이름도 여기에서 나온다</h1>
<p>TypeSafe가 특히 강조하는 부분이 Output Type입니다.</p>
<p>일반 LLM에서는 이런 문제가 생길 수 있습니다.</p>
<pre><code class="language-json">{
  &quot;confidence&quot;: &quot;very high&quot;
}</code></pre>
<p>원래 <code>Double</code>을 기대했는데 문자열이 올 수 있습니다.</p>
<p>또는:</p>
<pre><code class="language-json">{
  &quot;route&quot;: &quot;some_new_route&quot;
}</code></pre>
<p>처럼 Schema 밖의 값을 생성할 수도 있습니다.</p>
<p>Structured Output 기능을 사용하면 이런 문제를 상당히 줄일 수 있습니다.</p>
<p>Jev는 처음부터 가능한 Output Domain을 정하고 그 안에서 결정을 반환하도록 설계됐습니다.</p>
<p>TypeSafe는 이 특성 때문에 <strong>type error가 구조적으로 발생하지 않는다</strong>고 설명합니다.</p>
<p>이 부분과 의미적으로 잘못된 판단은 구분해야 합니다.</p>
<pre><code class="language-text">Wrong Type</code></pre>
<p>과</p>
<pre><code class="language-text">Wrong Decision</code></pre>
<p>은 다른 문제입니다.</p>
<p>Jev도 판단 자체는 틀릴 수 있습니다.</p>
<hr>
<h1 id="14-jev는-hallucination이-없다는-표현은-조심해서-봐야-한다">14. “Jev는 Hallucination이 없다”는 표현은 조심해서 봐야 한다</h1>
<p>TypeSafe 공식 자료에는 Jev가 <code>can&#39;t hallucinate</code>, 홈페이지에는 <code>Zero Hallucinations</code>라는 강한 표현이 있습니다.</p>
<p>이건 그대로 받아들이기보다 어떤 의미인지 구분해서 보는 게 좋습니다.</p>
<p>Jev는 자유로운 문자열을 생성하지 않습니다.</p>
<p>따라서:</p>
<pre><code class="language-text">존재하지 않는 API 이름 생성

없는 Tool 이름 생성

Schema 밖 필드 생성</code></pre>
<p>같은 <strong>Generative Hallucination Surface</strong>는 크게 줄어듭니다.</p>
<p>특히 Type Schema를 벗어나는 Output은 구조적으로 막을 수 있습니다.</p>
<p>하지만:</p>
<pre><code class="language-text">billing을 technical로 잘못 분류</code></pre>
<p>하는 것은 여전히 가능합니다.</p>
<p>즉:</p>
<pre><code class="language-text">Type Error ❌</code></pre>
<p>와</p>
<pre><code class="language-text">Decision Error 가능</code></pre>
<p>을 구분해야 합니다.</p>
<p>이 때문에 Confidence Calibration이 중요합니다.</p>
<hr>
<h1 id="15-속도는-jev의-가장-눈에-띄는-부분이다">15. 속도는 Jev의 가장 눈에 띄는 부분이다</h1>
<p>TypeSafe 공식 발표에 따르면 Jev의 End-to-end Response Time은 현재 대략:</p>
<pre><code class="language-text">70ms ~ 500ms</code></pre>
<p>범위입니다.</p>
<p>회사는 같은 수준의 System One 작업에서 Frontier LLM 대비:</p>
<pre><code class="language-text">40x ~ 200x</code></pre>
<p>빠를 수 있다고 설명합니다.</p>
<p>Workflow Evaluation에서는 최대:</p>
<pre><code class="language-text">193.6x faster</code></pre>
<p>라는 수치도 제시합니다.</p>
<p>다만 이 숫자는 반드시 맥락을 같이 봐야 합니다.</p>
<p>TypeSafe도 직접 밝히고 있습니다.</p>
<p>해당 Workflow는 <strong>System One 형태에 적합한 작업</strong>이고, 이 수치가 실제 사용 사례에서 기대할 수 있는 효과 중 높은 편일 가능성이 있다고 설명합니다.</p>
<p>따라서:</p>
<pre><code class="language-text">Jev가 GPT보다 193배 빠르다</code></pre>
<p>라고 일반화하면 안 됩니다.</p>
<p>정확한 표현은:</p>
<p><strong>TypeSafe가 설계한 System One Workflow Evaluation에서는 최대 약 193배 빠른 결과가 나왔다.</strong></p>
<p>정도가 적절합니다.</p>
<hr>
<h1 id="16-비용도-같은-방식으로-봐야-한다">16. 비용도 같은 방식으로 봐야 한다</h1>
<p>현재 공개 가격은:</p>
<pre><code class="language-text">Input

$0.042 / 1M tokens</code></pre>
<p>입니다.</p>
<p>즉:</p>
<pre><code class="language-text">$42 / 1B input tokens</code></pre>
<p>입니다.</p>
<p>TypeSafe는 Output Token은 별도로 과금하지 않는다고 설명합니다.</p>
<p>회사 Workflow Evaluation에서는 Frontier LLM 대비 최대:</p>
<pre><code class="language-text">444.6x cheaper</code></pre>
<p>라는 결과도 공개했습니다.</p>
<p>하지만 이 역시 Jev에 유리한 <strong>Decision-oriented Workflow</strong>에서 측정된 회사 자체 Evaluation입니다.</p>
<p>실제 비용 효과는 자신의 서비스 Workflow에서 직접 측정하는 편이 안전합니다.</p>
<hr>
<h1 id="17-왜-이렇게-빠를까">17. 왜 이렇게 빠를까</h1>
<p>일반 LLM은 Autoregressive Generation을 사용합니다.</p>
<pre><code class="language-text">Token 1
 ↓
Token 2
 ↓
Token 3
 ↓
Token 4</code></pre>
<p>앞 Token이 생성돼야 다음 Token을 만들 수 있습니다.</p>
<p>문장이 길어질수록 Latency도 늘어납니다.</p>
<p>Jev는 문자열을 생성하지 않습니다.</p>
<p>TypeSafe는 <strong>Parallel Sampler</strong>를 이용해 필요한 결정을 한 Query에서 병렬로 출력한다고 설명합니다.</p>
<p>예를 들어 질문이:</p>
<pre><code class="language-text">이 사용자는 이탈할 가능성이 높은가?

이 요청은 사기일 가능성이 있는가?

Human Review가 필요한가?</code></pre>
<p>세 개라면 각각의 답변 문장을 순차적으로 만드는 것이 아니라 여러 판단을 동시에 계산하는 방향입니다.</p>
<p>자동화 시스템에서는 이 차이가 큽니다.</p>
<hr>
<h1 id="18-실시간-서비스에는-꽤-흥미로운-구조다">18. 실시간 서비스에는 꽤 흥미로운 구조다</h1>
<p>100ms 안팎의 판단이 가능해진다면 LLM을 넣기 어려웠던 영역에도 AI를 사용할 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">게임 상태 판단

실시간 추천

광고 Routing

Fraud Risk

Moderation

Search Ranking

Agent Routing</code></pre>
<p>같은 영역입니다.</p>
<p>TypeSafe는 실제 Demo로 Doom 게임 상태를 Jev가 판단하면서 움직이는 사례도 공개했습니다.</p>
<p>이미지 자체를 보는 Vision Model은 아니고, <strong>게임 상태를 구조화된 Text/Data로 전달한 뒤 판단하는 방식</strong>입니다.</p>
<hr>
<h1 id="19-대량-데이터-처리에도-성격이-잘-맞는다">19. 대량 데이터 처리에도 성격이 잘 맞는다</h1>
<p>LLM으로 수백만 개의 Record를 하나씩 처리하면 비용과 시간이 빠르게 커집니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">10,000,000 고객

↓

각 고객의 churn 가능성 평가</code></pre>
<p>를 Frontier LLM으로 처리하면 꽤 큰 작업입니다.</p>
<p>Jev가 노리는 영역은 이런 <strong>Map-style Decision Workload</strong>입니다.</p>
<pre><code class="language-text">Record 1 → Score
Record 2 → Score
Record 3 → Score
...</code></pre>
<p>같은 작업입니다.</p>
<p>문장을 생성할 필요가 없기 때문에 Decision Model의 장점이 크게 나타날 수 있습니다.</p>
<hr>
<h1 id="20-모든-작업에-jev가-좋은-것은-아니다">20. 모든 작업에 Jev가 좋은 것은 아니다</h1>
<p>Jev는 의도적으로 문자열 생성을 포기했습니다.</p>
<p>따라서 다음 작업에는 적합하지 않습니다.</p>
<pre><code class="language-text">코드 작성

문서 작성

이메일 작성

소설 작성

사용자와 긴 대화

복잡한 설명

새로운 설계 생성</code></pre>
<p>이건 GPT, Claude, Gemini 같은 Generative Model이 훨씬 자연스럽습니다.</p>
<p>또:</p>
<pre><code class="language-text">Repository 전체 분석

장애 원인 탐색

Research

Architecture 설계</code></pre>
<p>같이 장시간 Reasoning과 탐색이 필요한 작업도 Jev 하나로 해결하려는 문제는 아닙니다.</p>
<hr>
<h1 id="21-jev와-llm을-경쟁-관계로-볼-필요가-없다">21. Jev와 LLM을 경쟁 관계로 볼 필요가 없다</h1>
<p>실제 Architecture에서는 둘을 같이 쓰는 형태가 더 자연스럽습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">User Request
      ↓
     Jev
      ↓
┌─────┼──────────┐
Tool  Skill     Agent
                ↓
            GPT / Claude</code></pre>
<p>또는:</p>
<pre><code class="language-text">Agent Output
     ↓
    Jev
     ↓
Confidence High?
  │          │
 YES        NO
  ↓          ↓
사용       재검토</code></pre>
<p>입니다.</p>
<p>Jev가 빠른 판단을 담당하고,</p>
<p>큰 LLM은 실제 Reasoning과 Generation을 담당합니다.</p>
<p>이렇게 보면 Jev의 포지션이 훨씬 명확해집니다.</p>
<hr>
<h1 id="22-멀티에이전트-비용을-줄이는-앞단-router로도-볼-수-있다">22. 멀티에이전트 비용을 줄이는 앞단 Router로도 볼 수 있다</h1>
<p>Agent가 많아질수록 Routing 자체도 중요한 문제가 됩니다.</p>
<pre><code class="language-text">Main Agent
 ├─ Coding Agent
 ├─ Security Agent
 ├─ Research Agent
 ├─ Data Agent
 └─ Release Agent</code></pre>
<p>매번 Main LLM에게:</p>
<blockquote>
<p>어느 Agent가 이걸 처리해야 하지?</p>
</blockquote>
<p>라고 물어볼 수도 있습니다.</p>
<p>하지만 이 판단이 충분히 정형화됐다면 Jev가 앞에서 처리할 수 있습니다.</p>
<pre><code class="language-text">Request
 ↓
Jev Router
 ↓
Agent</code></pre>
<p>이렇게 하면 모든 요청에 Main Reasoning Model을 먼저 호출하지 않아도 됩니다.</p>
<p>특히 Agent 요청량이 많아질수록 의미가 커질 수 있습니다.</p>
<hr>
<h1 id="23-confidence-gate가-실무에서-핵심이-될-수-있다">23. Confidence Gate가 실무에서 핵심이 될 수 있다</h1>
<p>Jev에서 가장 개발자다운 부분은 모델보다 <strong>Architecture Pattern</strong>일 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Jev
 ↓
Confidence</code></pre>
<p>결과를 그대로 사용하는 것이 아니라 Threshold를 둡니다.</p>
<pre><code class="language-text">&gt; 0.95

자동 실행</code></pre>
<pre><code class="language-text">0.70 ~ 0.95

Frontier LLM 검토</code></pre>
<pre><code class="language-text">&lt; 0.70

Human Review</code></pre>
<p>이렇게 구성하면 AI를 Binary Decision Maker가 아니라 <strong>Risk-aware Decision Component</strong>로 사용할 수 있습니다.</p>
<p>이 패턴은:</p>
<pre><code class="language-text">Agent Routing

Moderation

Fraud

Approval

Quality Gate</code></pre>
<p>전부에 적용할 수 있습니다.</p>
<hr>
<h1 id="24-jev가-정말-중요한-이유는-모델보다-인터페이스일-수도-있다">24. Jev가 정말 중요한 이유는 모델보다 인터페이스일 수도 있다</h1>
<p>지금까지 AI API의 중심은 대부분 Text였습니다.</p>
<pre><code class="language-text">String In
 ↓
Model
 ↓
String Out</code></pre>
<p>Software에서는 다시 이 문자열을 해석합니다.</p>
<pre><code class="language-text">String
 ↓
Parse
 ↓
Validate
 ↓
Business Logic</code></pre>
<p>Jev가 제안하는 인터페이스는 다릅니다.</p>
<pre><code class="language-text">State
 ↓
Model
 ↓
Typed Decision
 ↓
Code</code></pre>
<p>AI가 사람에게 말을 잘하는 Component가 아니라 <strong>프로그램 내부에서 호출되는 Decision Primitive</strong>에 가까워집니다.</p>
<p>이 방향이 실제로 자리 잡는다면 AI Architecture에도 꽤 큰 변화가 생길 수 있습니다.</p>
<hr>
<h1 id="25-아직은-early-access라는-점도-중요하다">25. 아직은 Early Access라는 점도 중요하다</h1>
<p>현재 Jev는 <strong>Early Access</strong>입니다.</p>
<p>2026년 9월 14일 처음 공개됐고, TypeSafe는 Waitlist 사용자부터 순차적으로 Access를 제공하고 있습니다.</p>
<p>따라서 아직 확인해야 할 것이 많습니다.</p>
<pre><code class="language-text">실제 Production Reliability

Traffic이 늘었을 때 Latency

Pricing 지속 가능성

Domain별 Accuracy

Confidence Calibration

Long-term Stability</code></pre>
<p>등입니다.</p>
<p>특히 현재 공개된 대부분의 성능 자료는 TypeSafe 자체 Evaluation입니다.</p>
<p>회사는 이 점을 상당히 솔직하게 밝히고 있습니다.</p>
<p>Workflow가 내부 Model Capabilities 팀에 의해 만들어졌기 때문에 Bias가 있을 가능성도 인정하고 있습니다.</p>
<hr>
<h1 id="26-benchmark-숫자보다-실제-workflow-평가가-더-중요하다">26. Benchmark 숫자보다 실제 Workflow 평가가 더 중요하다</h1>
<p>TypeSafe는 Standard Benchmark 중심 경쟁에도 비판적인 입장입니다.</p>
<p>공개 Benchmark에 맞춰 반복적으로 Model을 개선하면 결국 Benchmark 자체에 Overfit될 수 있다는 이유입니다.</p>
<p>그래서 Jev는 일반적인 Benchmark Table보다 <strong>실제 Automation Workflow</strong>를 평가 대상으로 삼고 있습니다.</p>
<p>이 접근 자체는 꽤 흥미롭습니다.</p>
<p>개발자 입장에서 중요한 것도 결국:</p>
<pre><code class="language-text">Benchmark Score</code></pre>
<p>보다</p>
<pre><code class="language-text">우리 Workflow에서

얼마나 정확한가?

얼마나 빠른가?

얼마나 싼가?

Confidence가 실제로 믿을 만한가?</code></pre>
<p>이기 때문입니다.</p>
<hr>
<h1 id="27-실제-도입을-검토한다면-이렇게-보는-게-좋다">27. 실제 도입을 검토한다면 이렇게 보는 게 좋다</h1>
<p>Jev를 적용할 후보를 찾을 때는 먼저 현재 시스템에서 Frontier LLM이 이런 작업을 하고 있는지 확인하면 됩니다.</p>
<pre><code class="language-text">분류

점수화

라우팅

검증

Filter

Guardrail</code></pre>
<p>그리고 질문합니다.</p>
<blockquote>
<p>이 작업에서 실제로 긴 Text Generation이 필요한가?</p>
</blockquote>
<p>필요하지 않다면 Jev 같은 Decision Model을 검토할 가치가 있습니다.</p>
<p>반대로:</p>
<pre><code class="language-text">복잡한 추론

코드 생성

대화

문서 생성</code></pre>
<p>이 필요하다면 기존 LLM을 유지하는 편이 맞습니다.</p>
<hr>
<h1 id="28-개발자-입장에서-가장-현실적인-구조">28. 개발자 입장에서 가장 현실적인 구조</h1>
<p>현재 기준으로는 이런 Architecture가 가장 이해하기 쉽습니다.</p>
<pre><code class="language-text">                    Request
                       ↓
                      Jev
                       ↓
             ┌─────────┼─────────┐
             │         │         │
           Tool      Skill     Agent
                                 │
                           GPT / Claude</code></pre>
<p>그리고 마지막에 다시 Jev를 붙일 수도 있습니다.</p>
<pre><code class="language-text">Agent Result
     ↓
    Jev
     ↓
Verification / Score
     ↓
Code</code></pre>
<p>즉:</p>
<pre><code class="language-text">Jev
→ 빠른 판단

LLM
→ 깊은 추론과 생성

Code
→ 확실한 규칙</code></pre>
<p>으로 역할을 나누는 것입니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>Jev가 흥미로운 이유는 GPT나 Claude보다 더 똑똑한 새로운 Frontier Model이 나왔기 때문이 아닙니다.</p>
<p>애초에 목표가 다릅니다.</p>
<p>기존 LLM은:</p>
<pre><code class="language-text">생각하고
말하고
생성한다.</code></pre>
<p>Jev는:</p>
<pre><code class="language-text">판단한다.</code></pre>
<p>에 집중합니다.</p>
<p>TypeSafe가 강조하는 것도 바로 이 차이입니다.</p>
<p>긴 Text를 만들 필요가 없는 Software Decision에 매번 Generative LLM을 사용하는 것이 과한 것은 아닌가라는 질문입니다.</p>
<p>그래서 Jev를 가장 단순하게 표현하면:</p>
<p><strong>빠르고 저렴한 AI 판단 함수</strong></p>
<p>에 가깝습니다.</p>
<p>특히:</p>
<pre><code class="language-text">Routing
Classification
Scoring
Verification
Moderation
Guardrail</code></pre>
<p>같은 영역에서 의미가 있습니다.</p>
<p>반대로:</p>
<pre><code class="language-text">Coding
Research
Writing
Long-running Reasoning</code></pre>
<p>은 여전히 LLM과 Agent의 영역입니다.</p>
<p>결국 앞으로 AI 시스템이 이런 식으로 나뉠 가능성도 있습니다.</p>
<pre><code class="language-text">확실한 규칙
→ Code

애매하지만 빠른 판단
→ Jev

복잡한 추론
→ LLM

장기적인 작업
→ Agent</code></pre>
<p>모든 문제에 가장 큰 LLM을 호출하는 방식에서 벗어나 <strong>문제의 성격에 맞는 Intelligence Layer를 선택하는 구조</strong>입니다.</p>
<p>Jev가 실제 Production 환경에서도 현재 공개된 속도와 Calibration을 유지할 수 있을지는 더 지켜봐야 합니다.</p>
<p>하지만 방향 자체는 꽤 흥미롭습니다.</p>
<p>AI를 더 크게 만드는 경쟁과 별개로,</p>
<p><strong>AI를 더 작은 Software Primitive로 만드는 경쟁도 시작되고 있습니다.</strong></p>
<hr>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>TypeSafe AI — Introducing System One Models and Jev</strong><br>Jev의 Architecture, RLCD, Parallel Sampling, Structured Decision, Confidence, Pricing과 Workflow Evaluation을 설명한 공식 발표입니다.<br>TypeSafe AI 공식 발표</p>
</li>
<li><p><strong>TypeSafe AI — Workflow Evals</strong><br>Jev와 Frontier LLM을 실제 Decision Workflow에 넣어 Accuracy·Latency·Cost를 비교한 평가 방법과 Query를 확인할 수 있습니다.<br>TypeSafe Workflow Evals</p>
</li>
<li><p><strong>TypeSafe AI — System One Models</strong><br>Jev의 현재 가격, Typed Decision, Calibration과 Automation 중심 설계를 정리한 공식 제품 페이지입니다.<br>TypeSafe AI 공식 사이트</p>
</li>
<li><p><strong>TypeSafe AI — Lies, Damned Lies, and Benchmarks</strong><br>TypeSafe가 Standard Benchmark Table보다 Workflow Evaluation을 사용하는 이유와 Benchmark Overfitting에 대한 입장을 설명합니다.<br>TypeSafe AI Benchmark 관련 글</p>
</li>
</ul>
<p><strong>TypeSafe 공식 자료 기준으로 보면</strong>, Jev는 2026년 9월 14일 Early Access로 공개된 첫 System One Model입니다. 일반 LLM처럼 문자열을 생성하지 않고 미리 정의된 타입의 판단과 확률을 반환하도록 설계됐으며, 회사는 이를 위해 RLCD와 Parallel Sampler라는 별도 Training·Inference 방식을 사용한다고 설명합니다.</p>
<p>현재 공개 가격은 입력 100만 Token당 $0.042이며 Output Token은 별도 과금하지 않습니다. TypeSafe는 현재 서비스 Latency를 약 70~500ms라고 밝히고 있으며, 자체 Workflow Evaluation에서는 최대 193.6배 빠르고 444.6배 저렴한 결과를 공개했습니다. 다만 회사 역시 이 수치가 실제 효과 중 높은 편일 가능성이 있고 Evaluation 설계에 내부 Bias가 존재할 수 있다는 점을 명시하고 있습니다.</p>
<p>또 하나 주의할 부분은 TypeSafe가 사용하는 <code>Zero Hallucinations</code> 표현입니다. Jev의 Output Schema가 미리 정해져 있기 때문에 Schema 밖의 값이나 Type Error를 생성하지 않는다는 의미에서는 강한 구조적 보장이 가능합니다. 하지만 Model이 잘못된 선택지를 높은 확률로 고르는 <strong>Decision Error 자체가 불가능하다는 의미로 받아들이면 안 됩니다.</strong> 실제 Production 적용에서는 Calibration과 Confidence Threshold를 반드시 함께 평가하는 것이 중요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[멀티에이전트는 이렇게 시작하면 된다 《3》]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609185</link>
            <guid>https://velog.io/@kyu_ios_dev/2609185</guid>
            <pubDate>Fri, 18 Sep 2026 05:53:16 GMT</pubDate>
            <description><![CDATA[<h3 id="멀티에이전트는-이렇게-시작하면-된다">멀티에이전트는 이렇게 시작하면 된다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/4fdb58b7-088c-4207-80fd-a9ad9cee3a73/image.png" alt=""></p>
<h2 id="codex와-claude-code로-만드는-가장-단순한-구조">Codex와 Claude Code로 만드는 가장 단순한 구조</h2>
<p>멀티에이전트를 처음 적용하려고 하면 구조부터 크게 그리기 쉽습니다.</p>
<pre><code class="language-text">Main Agent
 ├─ Coding Agent
 ├─ Test Agent
 ├─ Review Agent
 ├─ Security Agent
 └─ Research Agent</code></pre>
<p>여기에 MCP Server를 붙이고 Skill을 만들고 Agent마다 Model과 권한까지 따로 설정합니다.</p>
<p>그런데 실제 Codex와 Claude Code에서는 처음부터 이렇게 만들 필요가 없습니다.</p>
<p>두 도구 모두 기본 Agent 자체가 이미</p>
<pre><code class="language-text">Repository 탐색
파일 수정
Shell 실행
Test
Git
Tool 호출</code></pre>
<p>을 처리할 수 있습니다.</p>
<p>멀티에이전트의 시작점은 Agent를 여러 개 만드는 것이 아닙니다.</p>
<p><strong>하나의 Agent로 시작하고, Main Context가 불필요하게 커지거나 독립적으로 처리할 작업이 생길 때만 Subagent를 분리하는 것</strong>이 훨씬 자연스럽습니다.</p>
<p>전체 흐름을 먼저 보면 이렇습니다.</p>
<pre><code class="language-text">Single Agent
     ↓
Project Instructions
     ↓
Skills
     ↓
Subagents
     ↓
MCP
     ↓
독립 Runtime이 필요하면 A2A</code></pre>
<p>Codex와 Claude Code 모두 이 방향으로 구성할 수 있습니다.</p>
<hr>
<h1 id="1-먼저-single-agent로-시작한다">1. 먼저 Single Agent로 시작한다</h1>
<p>Codex라면 Repository에서 Codex를 시작하는 것만으로 기본적인 Agent 환경이 만들어집니다.</p>
<pre><code class="language-text">Codex

├─ 파일 읽기
├─ 코드 검색
├─ 파일 수정
├─ Shell 실행
├─ Build
└─ Test</code></pre>
<p>Claude Code도 비슷합니다.</p>
<pre><code class="language-bash">cd MyProject
claude</code></pre>
<p>기본 구조는 다음과 같습니다.</p>
<pre><code class="language-text">Developer
    ↓
Coding Agent
    ↓
Repository
    ↓
Build / Test / Git</code></pre>
<p>처음부터 Test Agent나 Review Agent를 만들 이유가 없습니다.</p>
<p>우선 Main Agent 하나에게 실제 작업을 맡겨봅니다.</p>
<pre><code class="language-text">이 프로젝트의 인증 구조를 분석하고
로그아웃 시 Token이 제대로 삭제되는지 확인해줘.</code></pre>
<p>또는:</p>
<pre><code class="language-text">Swift 6 Concurrency Error를 확인하고
수정한 뒤 Test까지 실행해줘.</code></pre>
<p>이 상태에서 잘 처리된다면 Agent를 더 추가할 필요가 없습니다.</p>
<hr>
<h1 id="2-프로젝트-공통-규칙부터-agent에게-알려준다">2. 프로젝트 공통 규칙부터 Agent에게 알려준다</h1>
<p>Agent를 추가하기 전에 먼저 해야 할 일이 있습니다.</p>
<p><strong>프로젝트 규칙을 명확하게 만드는 것</strong>입니다.</p>
<p>Codex에서는 <code>AGENTS.md</code>를 사용할 수 있습니다.</p>
<p>예를 들어 Repository Root에:</p>
<pre><code class="language-text">AGENTS.md</code></pre>
<p>를 두고 다음과 같은 규칙을 작성합니다.</p>
<pre><code class="language-markdown"># Project Rules

- Swift 6 strict concurrency를 유지한다.
- UI 변경은 SwiftUI를 우선한다.
- 새로운 Dependency 추가 전 반드시 확인한다.
- 수정 후 관련 Unit Test를 실행한다.
- UIKit 코드는 기존 모듈에서만 유지한다.</code></pre>
<p>Codex는 작업을 시작하면서 이 파일을 읽고 프로젝트 지침으로 사용합니다.</p>
<p>Claude Code에는 같은 역할을 하는 <code>CLAUDE.md</code>가 있습니다.</p>
<pre><code class="language-text">CLAUDE.md</code></pre>
<p>예를 들어:</p>
<pre><code class="language-markdown"># Development Rules

- 새로운 View는 SwiftUI로 작성한다.
- ViewModel은 @MainActor를 기본으로 한다.
- Repository Protocol은 Domain Module에 둔다.
- Test 없이 Business Logic을 변경하지 않는다.</code></pre>
<p>이렇게 하면 Agent에게 매번 긴 Prompt를 반복할 필요가 없습니다.</p>
<pre><code class="language-text">Developer
    ↓
짧은 요청
    ↓
AGENTS.md / CLAUDE.md
    ↓
프로젝트 규칙 반영</code></pre>
<p>멀티에이전트를 만들기 전에 먼저 이 단계부터 정리하는 것이 좋습니다.</p>
<hr>
<h1 id="3-반복되는-작업은-agent가-아니라-skill로-만든다">3. 반복되는 작업은 Agent가 아니라 Skill로 만든다</h1>
<p>개발하다 보면 계속 반복되는 요청이 생깁니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Swift 6 Migration

Feature Module 생성

PR Review

Release 준비

Dependency Update</code></pre>
<p>같은 작업입니다.</p>
<p>매번 Prompt로 절차를 설명할 필요는 없습니다.</p>
<p>Codex와 Claude Code 모두 <code>SKILL.md</code> 기반의 Custom Skill을 지원합니다.</p>
<p>예를 들어 Swift 6 Migration Skill을 만든다고 해보겠습니다.</p>
<pre><code class="language-text">swift6-migration/
 └─ SKILL.md</code></pre>
<p>내용은 다음 정도가 될 수 있습니다.</p>
<pre><code class="language-markdown">---
name: swift6-migration
description: Swift 6 concurrency 오류를 분석하고 수정할 때 사용한다.
---

# Workflow

1. 먼저 프로젝트를 Build한다.
2. Concurrency Diagnostic을 수집한다.
3. Sendable 문제를 분류한다.
4. Actor Isolation을 확인한다.
5. @MainActor 적용 여부를 검토한다.
6. 최소 범위만 수정한다.
7. Build한다.
8. 관련 Test를 실행한다.</code></pre>
<p>이제:</p>
<pre><code class="language-text">Swift 6 오류 고쳐줘.</code></pre>
<p>라고 요청하면 Agent가 해당 Skill을 선택할 수 있습니다.</p>
<p>구조가:</p>
<pre><code class="language-text">Main Agent
     ↓
Swift 6 Migration Skill
     ↓
Build / Search / Edit / Test</code></pre>
<p>이 됩니다.</p>
<p>별도의 <code>SwiftMigrationAgent</code>를 만들 필요가 없습니다.</p>
<hr>
<h1 id="4-codex에서는-skill을-프로젝트에-둘-수-있다">4. Codex에서는 Skill을 프로젝트에 둘 수 있다</h1>
<p>Codex는 Repository에서 Skill을 자동으로 찾을 수 있습니다.</p>
<p>프로젝트 전용 Skill이라면:</p>
<pre><code class="language-text">.agents/
 └─ skills/
     └─ swift6-migration/
         └─ SKILL.md</code></pre>
<p>같은 식으로 둘 수 있습니다.</p>
<p>개인적으로 여러 프로젝트에서 사용하는 Skill이라면 사용자 범위에 둘 수도 있습니다.</p>
<p>Codex는 처음부터 모든 <code>SKILL.md</code> 내용을 Context에 넣지 않습니다.</p>
<p>먼저:</p>
<pre><code class="language-text">Skill Name
+
Description</code></pre>
<p>정도만 확인하고,</p>
<p>실제 작업과 관련 있다고 판단되면 전체 Skill을 읽습니다.</p>
<p>즉:</p>
<pre><code class="language-text">100개의 Skill</code></pre>
<p>이 있다고 해서 100개의 전체 Prompt가 모두 Context에 들어가는 구조는 아닙니다.</p>
<p>이 <strong>Progressive Disclosure</strong>가 Skill이 중요한 이유 중 하나입니다.</p>
<p>OpenAI 공식 문서에서도 Skill을 Codex와 ChatGPT에서 사용하는 재사용 가능한 Workflow 단위로 정의하고 있습니다.</p>
<hr>
<h1 id="5-claude-code에서도-같은-방식으로-skill을-만들-수-있다">5. Claude Code에서도 같은 방식으로 Skill을 만들 수 있다</h1>
<p>Claude Code도 Custom Skill을 지원합니다.</p>
<p>프로젝트에서만 사용할 Skill은:</p>
<pre><code class="language-text">.claude/
 └─ skills/
     └─ ios-release/
         └─ SKILL.md</code></pre>
<p>형태로 둘 수 있습니다.</p>
<p>사용자 전체에서 사용할 Skill은:</p>
<pre><code class="language-text">~/.claude/skills/</code></pre>
<p>에 둘 수 있습니다.</p>
<p>예를 들어 Release Skill이라면:</p>
<pre><code class="language-markdown">---
name: ios-release
description: TestFlight 배포를 준비할 때 사용한다.
---

1. working tree가 clean인지 확인한다.
2. release branch인지 확인한다.
3. test를 실행한다.
4. version과 build number를 확인한다.
5. archive를 생성한다.
6. TestFlight upload 전 사용자 승인을 받는다.</code></pre>
<p>구조는:</p>
<pre><code class="language-text">Claude Code
     ↓
Release Skill
     ↓
Git / Xcodebuild / Fastlane</code></pre>
<p>정도가 됩니다.</p>
<p>여기까지는 아직 멀티에이전트가 아닙니다.</p>
<p>하지만 대부분의 반복적인 개발 업무는 여기까지만으로도 상당 부분 처리할 수 있습니다.</p>
<hr>
<h1 id="6-언제-subagent를-추가해야-할까">6. 언제 Subagent를 추가해야 할까</h1>
<p>Agent를 추가하는 기준은 역할 이름이 아닙니다.</p>
<p><strong>Main Agent의 Context에서 분리했을 때 이득이 있는가</strong>가 더 중요합니다.</p>
<p>예를 들어 이런 요청이 있다고 해보겠습니다.</p>
<pre><code class="language-text">이번 PR을 검토하고
Architecture 문제와
테스트 누락,
최신 Apple API 사용 여부까지 확인해줘.</code></pre>
<p>Main Agent 하나가 전부 하면:</p>
<pre><code class="language-text">Repository 탐색
+
Architecture 분석
+
Test 분석
+
Apple 문서 조사
+
PR Diff</code></pre>
<p>가 모두 하나의 Context에 쌓입니다.</p>
<p>이럴 때 작업을 나누는 것이 좋습니다.</p>
<pre><code class="language-text">Main Agent
   │
   ├─ Explorer
   │    └─ 코드 구조 조사
   │
   ├─ Test Reviewer
   │    └─ 테스트 누락 조사
   │
   └─ Docs Researcher
        └─ 최신 API 확인</code></pre>
<p>각 Subagent는 자기 Context만 사용하고 결과만 Main Agent에게 돌려줍니다.</p>
<hr>
<h1 id="7-codex는-이미-subagent-workflow를-기본-지원한다">7. Codex는 이미 Subagent Workflow를 기본 지원한다</h1>
<p>현재 Codex에서는 Subagent Workflow가 기본적으로 활성화되어 있습니다.</p>
<p>기본 Agent도 제공됩니다.</p>
<p>대표적으로:</p>
<pre><code class="language-text">default
worker
explorer</code></pre>
<p>가 있습니다.</p>
<p><code>explorer</code>는 읽기 중심 탐색에 적합하고,</p>
<p><code>worker</code>는 구현과 수정 작업에 적합합니다.</p>
<p>예를 들어 이런 식으로 요청할 수 있습니다.</p>
<pre><code class="language-text">explorer agent를 사용해서
이 프로젝트의 인증 구조를 먼저 조사해줘.

동시에 다른 agent에게
관련 Unit Test가 어디까지 작성되어 있는지 확인시켜줘.

결과를 합쳐서 수정 계획만 만들어줘.</code></pre>
<p>그러면:</p>
<pre><code class="language-text">Main Codex
   │
   ├─ Explorer #1
   │    └─ Auth Architecture
   │
   └─ Explorer #2
        └─ Tests</code></pre>
<p>형태로 병렬 작업을 수행하고 Main Agent가 결과를 합칩니다.</p>
<hr>
<h1 id="8-codex의-custom-agent도-프로젝트-단위로-만들-수-있다">8. Codex의 Custom Agent도 프로젝트 단위로 만들 수 있다</h1>
<p>자주 사용하는 Specialist가 있다면 직접 정의할 수도 있습니다.</p>
<p>프로젝트 범위에서는:</p>
<pre><code class="language-text">.codex/
 └─ agents/
     └─ security-reviewer.toml</code></pre>
<p>처럼 만듭니다.</p>
<p>개념적으로는:</p>
<pre><code class="language-toml">name = &quot;security_reviewer&quot;
description = &quot;Reviews code changes for security risks.&quot;

developer_instructions = &quot;&quot;&quot;
Focus only on security issues.
Do not modify source files.
Inspect authentication, authorization,
secret handling, and network code.
Return evidence with file paths.
&quot;&quot;&quot;

sandbox_mode = &quot;read-only&quot;</code></pre>
<p>같이 구성할 수 있습니다.</p>
<p>이게 중요한 이유는 단순히 Prompt를 따로 저장할 수 있어서가 아닙니다.</p>
<p>Agent별로:</p>
<pre><code class="language-text">Model

Reasoning Effort

Sandbox

MCP Servers

Skills

Permissions</code></pre>
<p>를 다르게 구성할 수 있기 때문입니다.</p>
<hr>
<h1 id="9-claude-code도-custom-subagent를-만들-수-있다">9. Claude Code도 Custom Subagent를 만들 수 있다</h1>
<p>Claude Code에서도 비슷한 구조를 사용할 수 있습니다.</p>
<p>가장 간단한 방법은:</p>
<pre><code class="language-text">/agents</code></pre>
<p>명령을 사용하는 것입니다.</p>
<p>여기서 Project-level 또는 User-level Custom Agent를 생성할 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">security-reviewer</code></pre>
<p>Agent를 만들어:</p>
<pre><code class="language-text">Security 관련 코드만 분석한다.

Source Code는 수정하지 않는다.

Authentication
Authorization
Secret
Network Security
Dependency 위험만 확인한다.</code></pre>
<p>같은 역할을 줄 수 있습니다.</p>
<p>Claude의 Subagent는 Main Session과 별도의 Context Window를 사용합니다.</p>
<p>즉:</p>
<pre><code class="language-text">Main Context
        │
        ├─ 구현 내용
        ├─ Conversation
        └─ Planning

Security Agent Context
        │
        ├─ Diff
        ├─ Security Files
        └─ Security Rules</code></pre>
<p>처럼 Context를 분리할 수 있습니다.</p>
<p>Anthropic도 Subagent가 특히 유용한 영역으로 <strong>탐색, 코드 조사, 병렬 작업, Context Isolation</strong>을 강조하고 있습니다.</p>
<hr>
<h1 id="10-subagent는-읽기-작업부터-병렬화하는-것이-좋다">10. Subagent는 읽기 작업부터 병렬화하는 것이 좋다</h1>
<p>처음 멀티에이전트를 쓰면서 흔히 하는 실수가 있습니다.</p>
<p>Agent 여러 개에게 동시에 코드를 수정시키는 것입니다.</p>
<pre><code class="language-text">Agent A
→ UserService.swift 수정

Agent B
→ UserService.swift 수정

Agent C
→ UserServiceTests.swift와
   UserService.swift 수정</code></pre>
<p>이렇게 하면:</p>
<pre><code class="language-text">Merge Conflict

Context Mismatch

중복 구현

서로 다른 설계</code></pre>
<p>가 발생하기 쉽습니다.</p>
<p>Codex 공식 문서도 병렬 Subagent는 우선</p>
<pre><code class="language-text">Exploration

Test 분석

Triage

Summary</code></pre>
<p>같은 <strong>read-heavy 작업</strong>부터 사용하는 것을 권장합니다.</p>
<p>좋은 첫 번째 구조는:</p>
<pre><code class="language-text">Main Agent
   │
   ├─ Explorer
   ├─ Test Analyzer
   └─ Dependency Analyzer</code></pre>
<p>입니다.</p>
<p>그 결과를 Main Agent가 받은 뒤 실제 수정은 하나의 Worker가 담당합니다.</p>
<pre><code class="language-text">Explore in Parallel
        ↓
Main Agent Plan
        ↓
Single Writer</code></pre>
<p>구조가 충돌을 줄이기 쉽습니다.</p>
<hr>
<h1 id="11-claude-code에서도-같은-원칙이-적용된다">11. Claude Code에서도 같은 원칙이 적용된다</h1>
<p>Claude Code 역시 Subagent는 독립 Context를 사용합니다.</p>
<p>Anthropic은 큰 작업 중 발생하는 Side Task를 Subagent에게 보내는 방식을 대표적인 사용 사례로 설명합니다.</p>
<p>예를 들어 Main Claude가 Feature를 구현하고 있는데:</p>
<pre><code class="language-text">이 프로젝트에서 기존 OAuth Token Refresh는
어디서 처리하고 있지?</code></pre>
<p>라는 조사가 필요해졌다고 해보겠습니다.</p>
<p>Main Context에서 직접 탐색하면 수십 개 파일을 읽은 내용까지 Context에 쌓입니다.</p>
<p>대신 Explorer Agent에게 맡깁니다.</p>
<pre><code class="language-text">Main Claude
    ↓
Explore Agent

&quot;OAuth Refresh 흐름만 조사해줘.&quot;</code></pre>
<p>Explorer는 독립적으로 파일을 읽고 최종적으로:</p>
<pre><code class="language-text">AuthService.swift
TokenRepository.swift
SessionManager.swift

Refresh 흐름은 ...</code></pre>
<p>정도만 돌려줍니다.</p>
<p>Main Context에는 탐색 과정 전체가 아니라 <strong>결론만 남게 됩니다.</strong></p>
<p>이게 Subagent를 쓰는 가장 큰 장점 중 하나입니다.</p>
<hr>
<h1 id="12-skill과-subagent는-역할이-다르다">12. Skill과 Subagent는 역할이 다르다</h1>
<p>둘을 혼동하기 쉽습니다.</p>
<p>Skill은:</p>
<pre><code class="language-text">이 작업을 어떻게 해야 하는가</code></pre>
<p>를 정의합니다.</p>
<p>Subagent는:</p>
<pre><code class="language-text">이 작업을 누가 독립적으로 처리할 것인가</code></pre>
<p>를 정의합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Swift 6 Migration Skill</code></pre>
<p>은 절차입니다.</p>
<pre><code class="language-text">Swift 6 Migration Reviewer</code></pre>
<p>는 독립적인 Reasoning Worker입니다.</p>
<p>그래서:</p>
<pre><code class="language-text">Main Agent
    ↓
Migration Skill
    ↓
Tools</code></pre>
<p>로 충분하면 Agent를 추가하지 않습니다.</p>
<p>반대로 대규모 Repository를 먼저 분석해야 한다면:</p>
<pre><code class="language-text">Main Agent
    ↓
Migration Explorer Subagent
    ↓
Migration Skill</code></pre>
<p>처럼 둘을 같이 사용할 수도 있습니다.</p>
<hr>
<h1 id="13-codex에서-외부-tool은-mcp로-연결한다">13. Codex에서 외부 Tool은 MCP로 연결한다</h1>
<p>Repository 밖의 시스템을 Agent가 사용하기 시작하면 MCP가 유용합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">GitHub

Linear

Figma

사내 API

문서 검색

Database</code></pre>
<p>같은 시스템입니다.</p>
<p>Codex는 MCP Server를 직접 연결할 수 있습니다.</p>
<p>CLI에서는:</p>
<pre><code class="language-text">codex mcp</code></pre>
<p>를 이용해 관리할 수 있습니다.</p>
<p>개념적인 구조는:</p>
<pre><code class="language-text">Codex
  │
  ├─ Local Tools
  │
  ├─ Skills
  │
  └─ MCP
       │
       ├─ GitHub
       ├─ Figma
       └─ Internal Docs</code></pre>
<p>입니다.</p>
<p>MCP Server는 Tool뿐 아니라 Resource와 Prompt도 제공할 수 있습니다.</p>
<hr>
<h1 id="14-claude-code-역시-mcp를-기본-지원한다">14. Claude Code 역시 MCP를 기본 지원한다</h1>
<p>Claude Code에서도:</p>
<pre><code class="language-text">claude mcp</code></pre>
<p>명령을 통해 MCP Server를 구성할 수 있습니다.</p>
<p>구조는 동일합니다.</p>
<pre><code class="language-text">Claude Code
    ↓
MCP
    ↓
GitHub
Slack
Database
Browser
Internal API</code></pre>
<p>중요한 점은 Agent에게 외부 시스템 접근 권한을 줄 때 권한 범위를 명확하게 나누는 것입니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">GitHub Read
→ 자동 허용

PR Comment
→ 허용

Merge
→ 승인 필요

Production Deploy
→ 승인 필요</code></pre>
<p>같은 방식입니다.</p>
<p>Claude Code는 Tool별 Allow / Deny 규칙과 Permission Mode를 제공합니다.</p>
<p>Codex 역시 Sandbox와 Approval 설정을 통해 작업 범위를 제한할 수 있습니다.</p>
<p>멀티에이전트에서는 Agent마다 이 권한을 다르게 주는 것이 중요합니다.</p>
<hr>
<h1 id="15-agent마다-같은-권한을-줄-필요는-없다">15. Agent마다 같은 권한을 줄 필요는 없다</h1>
<p>예를 들어 다음 구조가 있다고 해보겠습니다.</p>
<pre><code class="language-text">Main Coding Agent

Explorer Agent

Security Reviewer

Implementation Worker</code></pre>
<p>권한은 이렇게 나눌 수 있습니다.</p>
<pre><code class="language-text">Explorer

Read ⭕
Search ⭕
Edit ❌
Shell 제한</code></pre>
<pre><code class="language-text">Security Reviewer

Read ⭕
Scanner ⭕
Edit ❌</code></pre>
<pre><code class="language-text">Implementation Worker

Read ⭕
Edit ⭕
Build ⭕
Test ⭕</code></pre>
<p>Main Agent가 모든 권한을 가진다고 Subagent까지 전부 같은 권한을 가져야 하는 것은 아닙니다.</p>
<p>오히려 <strong>Agent 역할이 좁아질수록 권한도 좁히는 것</strong>이 좋습니다.</p>
<hr>
<h1 id="16-실제-ios-프로젝트라면-이런-구조부터-시작하면-된다">16. 실제 iOS 프로젝트라면 이런 구조부터 시작하면 된다</h1>
<p>예를 들어 Swift 프로젝트가 있다고 해보겠습니다.</p>
<p>처음에는:</p>
<pre><code class="language-text">Codex / Claude Code
       ↓
Repository
       ↓
Build / Test / Git</code></pre>
<p>만 사용합니다.</p>
<p>반복적인 Swift 6 Migration이 생기면:</p>
<pre><code class="language-text">Main Agent
    ↓
Swift 6 Migration Skill</code></pre>
<p>을 추가합니다.</p>
<p>코드베이스 탐색이 Main Context를 너무 많이 사용하기 시작하면:</p>
<pre><code class="language-text">Main Agent
   │
   └─ Explorer Subagent</code></pre>
<p>를 추가합니다.</p>
<p>보안 리뷰를 독립적으로 하고 싶다면:</p>
<pre><code class="language-text">Main Agent
   │
   ├─ Explorer
   └─ Security Reviewer</code></pre>
<p>가 됩니다.</p>
<p>GitHub나 사내 CI가 필요하면:</p>
<pre><code class="language-text">Main Agent
   │
   ├─ Skills
   ├─ Subagents
   └─ MCP
        ├─ GitHub
        └─ CI</code></pre>
<p>까지 확장합니다.</p>
<p>이 정도면 대부분의 개발팀에서 충분히 강력한 Multi-Agent 구조입니다.</p>
<hr>
<h1 id="17-codex와-claude-code에서-추천하는-첫-multi-agent-구조">17. Codex와 Claude Code에서 추천하는 첫 Multi-Agent 구조</h1>
<p>처음부터 Agent를 다섯 개 만들기보다 이 정도가 좋습니다.</p>
<pre><code class="language-text">                Main Coding Agent
                       │
         ┌─────────────┴─────────────┐
         │                           │
     Explorer                  Security Reviewer
    Read Only                     Read Only
         │                           │
         └─────────────┬─────────────┘
                       ↓
                  Main Agent
                       ↓
                 Worker / Edit
                       ↓
                Build + Test</code></pre>
<p>핵심은:</p>
<pre><code class="language-text">탐색
→ 병렬

판단
→ Main

수정
→ 가능한 한 한 곳

검증
→ Build / Test</code></pre>
<p>입니다.</p>
<p>이 구조가 생각보다 중요합니다.</p>
<p>멀티에이전트의 목적은 <strong>동시에 많이 수정하는 것</strong>이 아니라 <strong>Main Context에서 독립적인 사고를 분리하는 것</strong>에 더 가깝기 때문입니다.</p>
<hr>
<h1 id="18-agent를-더-만들기-전에-skill인지-확인한다">18. Agent를 더 만들기 전에 Skill인지 확인한다</h1>
<p>다음과 같은 작업은 대부분 Agent가 필요하지 않습니다.</p>
<pre><code class="language-text">Release 준비

Swift 6 Migration 절차

Dependency Update

Lint Fix

Feature Module 생성

PR Checklist</code></pre>
<p>반복되는 절차가 있다면:</p>
<pre><code class="language-text">SKILL.md</code></pre>
<p>부터 만드는 것이 좋습니다.</p>
<p>반대로:</p>
<pre><code class="language-text">Repository Architecture 분석

대규모 코드 탐색

보안 위험 조사

장애 원인 탐색

기술 조사</code></pre>
<p>처럼 결과에 따라 다음 행동이 달라지는 작업은 Subagent 후보입니다.</p>
<p>기준은 간단합니다.</p>
<pre><code class="language-text">Procedure
    ↓
Skill</code></pre>
<pre><code class="language-text">Independent Reasoning
    ↓
Subagent</code></pre>
<hr>
<h1 id="19-같은-runtime을-넘어서면-그때-a2a를-생각한다">19. 같은 Runtime을 넘어서면 그때 A2A를 생각한다</h1>
<p>Codex 내부 Subagent와 Claude Code Subagent는 기본적으로 같은 Agent 환경 안의 분업입니다.</p>
<p>하지만 이런 구조라면 이야기가 달라집니다.</p>
<pre><code class="language-text">개발팀

Codex Coding Agent
        ↓
       ???
        ↓
보안팀

Claude Security Agent</code></pre>
<p>보안팀 Agent는:</p>
<pre><code class="language-text">별도 Server

별도 Model

별도 Context

별도 Permission

별도 Deployment</code></pre>
<p>를 가지고 있을 수 있습니다.</p>
<p>이 경우 Main Codex의 Subagent로 볼 수 없습니다.</p>
<p><strong>독립된 Agent System</strong>입니다.</p>
<p>여기서 A2A 같은 Agent-to-Agent Protocol이 의미를 갖습니다.</p>
<pre><code class="language-text">Codex Agent
      ↓
     A2A
      ↓
Claude Security Agent</code></pre>
<p>처럼 서로 다른 Agent Runtime을 연결할 수 있습니다.</p>
<p>즉:</p>
<pre><code class="language-text">Codex Subagent
Claude Subagent

→ 같은 Runtime 내부의 분업</code></pre>
<p>과</p>
<pre><code class="language-text">A2A

→ 서로 독립된 Agent System 사이의 통신</code></pre>
<p>은 다른 문제입니다.</p>
<hr>
<h1 id="20-처음부터-a2a까지-넣지-않는-게-좋다">20. 처음부터 A2A까지 넣지 않는 게 좋다</h1>
<p>처음 Agent 시스템을 만들면서:</p>
<pre><code class="language-text">Skills

MCP

Subagents

A2A

Workflow Engine

Vector DB

Long-term Memory</code></pre>
<p>를 모두 세팅하면 Architecture 자체가 개발 대상이 됩니다.</p>
<p>실제 Feature보다 Agent Infrastructure를 관리하는 일이 더 커질 수 있습니다.</p>
<p>그래서 다음 순서가 현실적입니다.</p>
<pre><code class="language-text">STEP 1

Codex / Claude Code
Single Agent</code></pre>
<p>↓</p>
<pre><code class="language-text">STEP 2

AGENTS.md / CLAUDE.md</code></pre>
<p>↓</p>
<pre><code class="language-text">STEP 3

반복 절차
→ Skills</code></pre>
<p>↓</p>
<pre><code class="language-text">STEP 4

Context 분리 필요
→ Subagents</code></pre>
<p>↓</p>
<pre><code class="language-text">STEP 5

외부 시스템
→ MCP</code></pre>
<p>↓</p>
<pre><code class="language-text">STEP 6

독립 Runtime
→ A2A</code></pre>
<p>이 순서면 필요하지 않은 복잡도를 미리 만들지 않아도 됩니다.</p>
<hr>
<h1 id="21-codex와-claude-code를-같이-쓰는-팀이라면-더-재미있어진다">21. Codex와 Claude Code를 같이 쓰는 팀이라면 더 재미있어진다</h1>
<p>실제 개발팀에서는 Codex와 Claude Code를 동시에 사용하는 경우도 있습니다.</p>
<p>예를 들면:</p>
<pre><code class="language-text">Codex

구현
Build
Test</code></pre>
<p>에 강하게 사용하고,</p>
<pre><code class="language-text">Claude Code

Repository 조사
Architecture Review
Documentation</code></pre>
<p>에 사용한다고 해보겠습니다.</p>
<p>처음에는 서로 독립적으로 써도 됩니다.</p>
<pre><code class="language-text">Developer
 ├─ Codex
 └─ Claude Code</code></pre>
<p>굳이 둘을 서로 연결할 필요는 없습니다.</p>
<p>하지만 팀 수준에서 자동화를 만들기 시작하면:</p>
<pre><code class="language-text">Main Coding Workflow
       │
       ├─ Codex Worker
       │
       └─ Claude Reviewer</code></pre>
<p>같은 구조가 생길 수 있습니다.</p>
<p>이 경우 중요한 것은 어떤 모델이 더 좋은가가 아닙니다.</p>
<p><strong>각 Agent에게 어떤 Context와 권한, 역할을 줄 것인가</strong>가 중요합니다.</p>
<hr>
<h1 id="22-멀티에이전트에서-가장-중요한-것은-context-관리다">22. 멀티에이전트에서 가장 중요한 것은 Context 관리다</h1>
<p>Agent가 하나일 때는 Context 문제가 덜 보입니다.</p>
<p>하지만 Subagent가 늘어나면 설계의 중심이 달라집니다.</p>
<p>나쁜 구조는:</p>
<pre><code class="language-text">Main Context

↓

Agent A 전체 전달
Agent B 전체 전달
Agent C 전체 전달</code></pre>
<p>입니다.</p>
<p>좋은 구조는:</p>
<pre><code class="language-text">Main Context
    │
    ├─ Explorer
    │     → 탐색에 필요한 정보만
    │
    ├─ Reviewer
    │     → Diff + 관련 코드만
    │
    └─ Worker
          → 수정 대상 + 계획만</code></pre>
<p>입니다.</p>
<p>그리고 Subagent가 돌아올 때도 전체 작업 로그를 반환하기보다:</p>
<pre><code class="language-text">결론

근거

파일 위치

추천 Action</code></pre>
<p>정도만 Main Agent에 전달하는 편이 좋습니다.</p>
<p>Codex 공식 문서에서도 Subagent가 중간 출력 전체보다 <strong>요약 결과를 Parent에 반환하도록 하는 방식</strong>을 권장합니다.</p>
<hr>
<h1 id="23-멀티에이전트를-쓰면-observability도-필요해진다">23. 멀티에이전트를 쓰면 Observability도 필요해진다</h1>
<p>Agent가 하나일 때는 실패 원인을 찾기 쉽습니다.</p>
<p>Agent가 여러 개가 되면:</p>
<pre><code class="language-text">Main
 ↓
Explorer
 ↓
Main
 ↓
Reviewer
 ↓
Main
 ↓
Worker</code></pre>
<p>중 어디에서 문제가 생겼는지 확인해야 합니다.</p>
<p>최소한 다음 정보는 남기는 것이 좋습니다.</p>
<pre><code class="language-text">Agent

Task

Model

Duration

Tool Calls

Token

Result

Failure</code></pre>
<p>그리고 가능하면 전체 작업을 하나의 Trace로 봅니다.</p>
<pre><code class="language-text">Task #123

├─ Main
├─ Explorer
├─ Docs Research
├─ Worker
└─ Test</code></pre>
<p>Agent 수가 늘어날수록 Model 성능보다 <strong>운영 가능성</strong>이 중요해집니다.</p>
<hr>
<h1 id="24-결국-설치보다-중요한-것은-어디서-나누느냐이다">24. 결국 설치보다 중요한 것은 어디서 나누느냐이다</h1>
<p>Codex에서 Custom Agent를 만드는 것도 어렵지 않고,</p>
<p>Claude Code에서 <code>/agents</code>로 Subagent를 만드는 것도 어렵지 않습니다.</p>
<p>Skill 역시 <code>SKILL.md</code> 파일 하나로 시작할 수 있습니다.</p>
<p>MCP도 CLI에서 연결할 수 있습니다.</p>
<p>기술적인 설치 자체는 점점 쉬워지고 있습니다.</p>
<p>문제는 Architecture입니다.</p>
<pre><code class="language-text">왜 이 Agent가 따로 있어야 하는가?

왜 이 Context를 분리해야 하는가?

왜 이 Tool을 이 Agent만 사용해야 하는가?

왜 이 작업을 병렬로 실행해야 하는가?</code></pre>
<p>에 답할 수 있어야 합니다.</p>
<p>답이 없다면 Agent를 분리하지 않는 편이 나을 가능성이 높습니다.</p>
<hr>
<h1 id="25-처음-구성한다면-이-정도면-충분하다">25. 처음 구성한다면 이 정도면 충분하다</h1>
<p>Codex든 Claude Code든 처음에는 이 구조 정도면 충분합니다.</p>
<pre><code class="language-text">                 Main Coding Agent
                        │
          ┌─────────────┴─────────────┐
          │                           │
      Explorer                    Reviewer
      Read Only                  Read Only
          │                           │
          └─────────────┬─────────────┘
                        ↓
                      Main
                        ↓
                      Edit
                        ↓
                  Build + Test</code></pre>
<p>여기에 프로젝트 규칙:</p>
<pre><code class="language-text">AGENTS.md

or

CLAUDE.md</code></pre>
<p>를 둡니다.</p>
<p>반복 절차는:</p>
<pre><code class="language-text">SKILL.md</code></pre>
<p>로 만듭니다.</p>
<p>외부 시스템이 필요해지면:</p>
<pre><code class="language-text">MCP</code></pre>
<p>를 추가합니다.</p>
<p>Agent 자체가 독립 서비스가 될 때만:</p>
<pre><code class="language-text">A2A</code></pre>
<p>를 고민합니다.</p>
<p>이 정도만 해도 상당히 탄탄한 멀티에이전트 환경을 만들 수 있습니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>멀티에이전트를 시작한다고 해서 새로운 Agent Framework부터 설치할 필요는 없습니다.</p>
<p>이미 Codex나 Claude Code를 사용하고 있다면 그 환경에서 바로 시작할 수 있습니다.</p>
<p>처음에는:</p>
<pre><code class="language-text">1 Agent
+
Project Rules
+
Build / Test</code></pre>
<p>면 충분합니다.</p>
<p>반복되는 작업이 생기면 Skill을 추가합니다.</p>
<pre><code class="language-text">1 Agent
+
Skills</code></pre>
<p>Main Context가 커지기 시작하면 Subagent를 추가합니다.</p>
<pre><code class="language-text">Main
+
Explorer
+
Reviewer</code></pre>
<p>외부 시스템이 필요하면 MCP를 연결합니다.</p>
<pre><code class="language-text">Agent
+
MCP</code></pre>
<p>그리고 서로 다른 팀이나 Runtime의 Agent가 실제로 독립된 서비스가 됐을 때 A2A를 고려합니다.</p>
<pre><code class="language-text">Agent
 ↓
A2A
 ↓
Independent Agent</code></pre>
<p>그래서 멀티에이전트 Architecture를 가장 단순하게 정리하면 다음과 같습니다.</p>
<pre><code class="language-text">Project Rules
      ↓
Single Agent
      ↓
Skills
      ↓
Subagents
      ↓
MCP
      ↓
A2A</code></pre>
<p>복잡도를 한꺼번에 넣는 것이 아니라 <strong>문제가 생기는 순서대로 하나씩 추가하는 것</strong>입니다.</p>
<p>Codex와 Claude Code 모두 이미 이 흐름을 상당 부분 지원하고 있습니다.</p>
<p>결국 좋은 멀티에이전트 환경은 Agent가 많은 환경이 아닙니다.</p>
<p><strong>Main Context에는 중요한 판단만 남기고, 반복 절차는 Skill로, 독립적인 탐색은 Subagent로, 외부 기능은 MCP로 분리한 환경</strong>에 가깝습니다.</p>
<p>그리고 마지막 경계가 생겼을 때 A2A가 들어옵니다.</p>
<p>앞선 두 글까지 연결하면 구조도 깔끔하게 정리됩니다.</p>
<pre><code class="language-text">1편

Agent를 꼭 만들어야 하나?
→ Skill + MCP</code></pre>
<pre><code class="language-text">2편

Agent를 정말 분리해야 할 때는?
→ A2A</code></pre>
<pre><code class="language-text">3편

실제로 어떻게 시작할까?
→ Codex / Claude Code
→ Skill + Subagent + MCP</code></pre>
<p>이 세 편 정도면 멀티에이전트를 처음 구성할 때 필요한 개념부터 실제 운영 방향까지 한 번에 연결할 수 있습니다.</p>
<hr>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>OpenAI — Codex Subagents</strong><br>Codex의 기본 <code>worker</code>, <code>explorer</code> Agent, Custom Agent 설정, 병렬 Subagent Workflow, Agent별 Model·Sandbox·MCP·Skill 설정 방법을 확인할 수 있습니다.<br><a href="https://developers.openai.com/ko-KR/docs/agent-configuration/subagents">Codex Subagents 공식 문서</a></p>
</li>
<li><p><strong>OpenAI — Agent Skills</strong><br>Codex의 <code>SKILL.md</code>, Progressive Disclosure, 프로젝트 및 사용자 범위 Skill 설정 구조를 확인할 수 있습니다.<br><a href="https://developers.openai.com/ko-KR/docs/build-skills">Codex Agent Skills 공식 문서</a></p>
</li>
<li><p><strong>OpenAI — AGENTS.md</strong><br>Repository와 사용자 범위에서 Codex에 지속적인 개발 규칙을 전달하는 방법을 확인할 수 있습니다.<br><a href="https://developers.openai.com/ko-KR/docs/agent-configuration/agents-md">Codex AGENTS.md 공식 문서</a></p>
</li>
<li><p><strong>OpenAI — Codex MCP</strong><br>Codex CLI·IDE·데스크톱에서 STDIO 및 Remote MCP Server를 연결하고 외부 Tool과 Context를 사용하는 방법을 확인할 수 있습니다.<br><a href="https://developers.openai.com/ko-KR/docs/extend/mcp">Codex MCP 공식 문서</a></p>
</li>
<li><p><strong>Anthropic — Claude Code Subagents</strong><br>독립 Context를 사용하는 Claude Code Subagent의 사용 기준과 병렬 탐색, Context Isolation 전략을 확인할 수 있습니다.<br><a href="https://claude.com/blog/subagents-in-claude-code">Claude Code Subagent 공식 가이드</a></p>
</li>
<li><p><strong>Anthropic — Claude Code Skills</strong><br><code>.claude/skills/</code>와 <code>~/.claude/skills/</code>에 Custom Skill을 구성하는 방법을 확인할 수 있습니다.<br><a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview">Claude Agent Skills 공식 문서</a></p>
</li>
<li><p><strong>Anthropic — Claude Code MCP</strong><br>Claude Code와 외부 Tool 및 Data Source를 MCP로 연결하는 공식 구조를 확인할 수 있습니다.<br><a href="https://docs.anthropic.com/en/docs/mcp">Claude MCP 공식 문서</a></p>
</li>
</ul>
<p><strong>OpenAI 공식 문서 기준으로 보면</strong>, 현재 Codex는 Subagent Workflow가 기본 활성화되어 있으며 <code>default</code>, <code>worker</code>, <code>explorer</code> 같은 기본 Agent와 <code>.codex/agents/</code> 기반 Custom Agent를 지원합니다. OpenAI는 특히 코드베이스 탐색, 테스트 분석, triage, summary처럼 읽기 비중이 높은 작업을 병렬 Subagent로 먼저 분리하고, 여러 Agent가 같은 코드를 동시에 수정하는 write-heavy 병렬 작업은 신중하게 사용할 것을 권장하고 있습니다.</p>
<p><strong>Anthropic 역시 비슷한 기준을 제시합니다.</strong> Claude Code의 Subagent는 별도의 Context Window에서 작업하고 결과만 Main Conversation에 반환하기 때문에 코드 탐색이나 독립적인 조사 작업에서 특히 유용합니다. 반대로 단순하거나 Context 공유가 중요한 작업에서는 Subagent 생성 비용이 더 클 수 있습니다.</p>
<p>두 환경 모두 결국 같은 방향을 보여줍니다. <strong>반복 절차는 Skill, 외부 기능은 MCP, 독립적인 Context가 필요한 작업은 Subagent로 분리하고, 서로 다른 Runtime과 조직 경계까지 넘어가는 순간에만 A2A 같은 분산 Agent Protocol을 고려하는 구조</strong>가 현재 가장 현실적인 멀티에이전트 시작점입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MCP 다음은 A2A다 《2》]]></title>
            <link>https://velog.io/@kyu_ios_dev/26091802</link>
            <guid>https://velog.io/@kyu_ios_dev/26091802</guid>
            <pubDate>Fri, 18 Sep 2026 05:36:40 GMT</pubDate>
            <description><![CDATA[<h3 id="mcp-다음은-a2a다">MCP 다음은 A2A다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/abb71a7a-3570-43af-86f9-80cdf6bc90e8/image.png" alt=""></p>
<h2 id="agent끼리-통신하는-아키텍처는-언제-필요한가">Agent끼리 통신하는 아키텍처는 언제 필요한가</h2>
<p>앞선 글에서는 Multi-Agent 구조를 만들 때 모든 전문 기능을 Agent로 분리할 필요는 없다는 이야기를 했습니다.</p>
<pre><code class="language-text">정해진 절차
+
명확한 Tool
        ↓
Skill + MCP</code></pre>
<p>반대로 이런 작업은 조금 다릅니다.</p>
<pre><code class="language-text">탐색
+
가설
+
반복 판단
+
독립적인 Context
        ↓
Agent</code></pre>
<p>그렇다면 실제로 Agent를 분리해야 할 때는 어떻게 연결해야 할까요?</p>
<p>같은 애플리케이션 안의 객체라면 직접 호출하면 됩니다.</p>
<p>하지만 Agent가</p>
<ul>
<li>다른 서버에서 실행되고</li>
<li>다른 팀이 관리하고</li>
<li>다른 언어와 Framework로 만들어졌으며</li>
<li>서로 다른 모델과 Context를 사용하고</li>
<li>몇 분 또는 몇 시간 동안 독립적으로 작업한다면</li>
</ul>
<p>단순한 Function Call로 보기 어려워집니다.</p>
<p>이때 등장하는 것이 <strong>A2A, Agent2Agent Protocol</strong>입니다.</p>
<p>현재 A2A 공식 사양은 <strong>0.3.0</strong>까지 발전했고, JSON-RPC뿐 아니라 HTTP+JSON, gRPC까지 Transport 범위가 확장됐습니다.</p>
<p>그리고 2026년 9월에는 Linux Foundation 산하 <strong>Agentic AI Foundation(AAIF)</strong>의 Hosted Project로 들어가면서 특정 Vendor의 Agent Protocol보다 산업 표준에 가까운 방향으로 움직이고 있습니다.</p>
<p>A2A를 한 문장으로 정리하면 이렇습니다.</p>
<p><strong>MCP가 Agent에게 Tool을 연결하는 표준이라면, A2A는 독립된 Agent에게 일을 맡기는 표준에 가깝습니다.</strong></p>
<hr>
<h1 id="1-mcp와-a2a는-경쟁-관계가-아니다">1. MCP와 A2A는 경쟁 관계가 아니다</h1>
<p>A2A 이야기가 나오면 가장 먼저 생기는 오해가 있습니다.</p>
<pre><code class="language-text">MCP
vs
A2A</code></pre>
<p>둘 중 하나를 선택해야 한다는 생각입니다.</p>
<p>하지만 역할이 다릅니다.</p>
<p>MCP는 Agent가 사용할 Capability를 제공합니다.</p>
<pre><code class="language-text">Agent
   ↓
MCP
   ↓
GitHub
Database
Browser
CI</code></pre>
<p>Agent가 직접 판단하고 Tool을 호출합니다.</p>
<p>반면 A2A는 다른 Agent에게 Task 자체를 위임합니다.</p>
<pre><code class="language-text">Main Agent
     ↓
    A2A
     ↓
Security Agent
     ↓
Security Tools</code></pre>
<p>Main Agent는 Security Agent 내부 Tool을 직접 제어할 필요가 없습니다.</p>
<p>Security Agent가 자신의 Context와 Tool을 이용해 스스로 판단합니다.</p>
<p>정리하면:</p>
<pre><code class="language-text">MCP

&quot;이 기능을 실행해줘.&quot;</code></pre>
<p>에 가깝고,</p>
<pre><code class="language-text">A2A

&quot;이 일을 맡아줘.&quot;</code></pre>
<p>에 가깝습니다.</p>
<hr>
<h1 id="2-tool과-agent의-가장-큰-차이는-독립적인-판단이다">2. Tool과 Agent의 가장 큰 차이는 독립적인 판단이다</h1>
<p>예를 들어 다음 Function이 있다고 해보겠습니다.</p>
<pre><code class="language-text">run_swiftlint()</code></pre>
<p>Input과 Output이 명확합니다.</p>
<pre><code class="language-text">Input
→ Project

Output
→ Findings</code></pre>
<p>이건 Tool입니다.</p>
<p>반면 이런 요청은 다릅니다.</p>
<blockquote>
<p>이번 배포 이후 Crash가 늘어난 원인을 찾아줘.</p>
</blockquote>
<p>이 작업에는 정해진 호출 순서가 없습니다.</p>
<p>Agent는 먼저 Crash 데이터를 확인할 수 있습니다.</p>
<pre><code class="language-text">Crash Rate
 ↓
특정 iOS Version인가?</code></pre>
<p>그다음:</p>
<pre><code class="language-text">최근 Release 확인
 ↓
관련 Commit 검색</code></pre>
<p>또는:</p>
<pre><code class="language-text">API Error 확인
 ↓
Backend 변경 확인</code></pre>
<p>으로 갈 수도 있습니다.</p>
<p>중간 결과를 보고 새로운 가설을 세웁니다.</p>
<pre><code class="language-text">Observe
 ↓
Hypothesis
 ↓
Tool Call
 ↓
Verify
 ↓
Re-plan</code></pre>
<p>이 정도가 되면 Function Call보다는 <strong>독립적인 Agent Task</strong>에 가깝습니다.</p>
<p>A2A는 바로 이런 Agent 사이의 경계를 표준화합니다.</p>
<hr>
<h1 id="3-가장-현실적인-예--coding-agent와-security-agent">3. 가장 현실적인 예 — Coding Agent와 Security Agent</h1>
<p>개발팀에 Coding Agent가 있다고 해보겠습니다.</p>
<pre><code class="language-text">Coding Agent

Repository 분석
코드 생성
Refactoring
Test</code></pre>
<p>보안팀에는 별도의 Security Agent가 있습니다.</p>
<pre><code class="language-text">Security Agent

SAST
Dependency Scan
Secret Scan
Threat Model
Security Policy</code></pre>
<p>Coding Agent가 PR을 만든 뒤 보안 검토가 필요합니다.</p>
<p>여기서 Security Tool을 Coding Agent에게 전부 제공할 수도 있습니다.</p>
<pre><code class="language-text">Coding Agent

+
Security Tools
+
Security Prompt
+
Security Policy</code></pre>
<p>하지만 시스템이 커질수록 문제가 생깁니다.</p>
<p>Coding Agent가 보안팀의 내부 규칙과 Tool까지 알아야 합니다.</p>
<p>Security Tool이 바뀌면 Coding Agent도 영향을 받습니다.</p>
<p>Security Context 역시 Main Agent Context에 들어옵니다.</p>
<p>대신 Security Agent를 독립적으로 두면:</p>
<pre><code class="language-text">Coding Agent
     ↓
    A2A
     ↓
Security Agent
     ↓
Security Tools</code></pre>
<p>구조가 됩니다.</p>
<p>Coding Agent가 해야 할 일은 단순합니다.</p>
<pre><code class="language-text">&quot;이 PR의 보안 위험을 검토해줘.&quot;</code></pre>
<p>입니다.</p>
<p>Security Agent가 내부적으로 어떤 Scanner를 사용하는지는 Coding Agent가 몰라도 됩니다.</p>
<hr>
<h1 id="4-다른-팀이-소유한-agent라면-a2a가-더-자연스럽다">4. 다른 팀이 소유한 Agent라면 A2A가 더 자연스럽다</h1>
<p>A2A가 특히 의미 있는 지점이 <strong>팀 경계</strong>입니다.</p>
<p>예를 들어 회사에 다음 Agent들이 있다고 해보겠습니다.</p>
<pre><code class="language-text">개발팀
Coding Agent

SRE팀
Incident Agent

보안팀
Security Agent

법무팀
Compliance Agent</code></pre>
<p>각 Agent는 서로 다른 팀에서 운영합니다.</p>
<p>각 팀은 자신들의 Agent에 대해</p>
<pre><code class="language-text">Model
Prompt
Knowledge
Tools
Permission
Deploy Cycle</code></pre>
<p>을 독립적으로 관리합니다.</p>
<p>Main Agent가 이 내부 구현까지 알 필요는 없습니다.</p>
<pre><code class="language-text">Coding Agent
     ↓
     A2A
     ↓
Compliance Agent</code></pre>
<p>형태로 Task만 전달합니다.</p>
<p>이 경우 A2A는 단순 Agent 연결 기술이 아니라 <strong>조직의 Ownership Boundary를 유지하는 방법</strong>이 됩니다.</p>
<hr>
<h1 id="5-agent-card는-agent용-api-문서에-가깝다">5. Agent Card는 Agent용 API 문서에 가깝다</h1>
<p>독립적인 Agent끼리 연결하려면 먼저 알아야 할 것이 있습니다.</p>
<blockquote>
<p>저 Agent가 뭘 할 수 있지?</p>
</blockquote>
<p>A2A에서는 이를 <strong>Agent Card</strong>로 표현합니다.</p>
<p>Agent Card는 JSON 형태의 Metadata Document입니다.</p>
<p>대략 이런 정보를 갖습니다.</p>
<pre><code class="language-text">Agent Card

├─ name
├─ description
├─ version
├─ capabilities
├─ skills
├─ endpoint
├─ supported transports
└─ authentication requirements</code></pre>
<p>예를 들어 Security Agent가 다음 Capability를 공개할 수 있습니다.</p>
<pre><code class="language-text">Security Review Agent

Skills

- dependency-security-review
- code-security-review
- secret-detection</code></pre>
<p>Client Agent는 Agent Card를 보고 이 Agent가 자신의 Task를 처리할 수 있는지 판단합니다.</p>
<p>기본적인 Discovery 방식 중 하나는:</p>
<pre><code class="language-text">/.well-known/agent-card.json</code></pre>
<p>입니다.</p>
<p>Enterprise 환경에서는 Agent Registry나 Catalog를 사용할 수도 있습니다.</p>
<p>개념적으로 보면 Agent Card는 <strong>Agent 세계의 OpenAPI Document</strong>와 비슷한 역할을 합니다.</p>
<hr>
<h1 id="6-최신-a2a에서는-transport도-하나로-고정되지-않는다">6. 최신 A2A에서는 Transport도 하나로 고정되지 않는다</h1>
<p>A2A 초기 버전은 JSON-RPC 중심이었습니다.</p>
<p>현재 0.3.0에서는 Core Transport로 다음 방식을 정의합니다.</p>
<pre><code class="language-text">JSON-RPC

gRPC

HTTP+JSON</code></pre>
<p>Agent는 자신이 지원하는 Interface를 Agent Card에 공개할 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Security Agent

JSON-RPC
→ https://security.example.com/a2a

gRPC
→ grpc.security.example.com

HTTP+JSON
→ https://security.example.com/v1</code></pre>
<p>같은 식입니다.</p>
<p>Client는 지원되는 Transport 중 적절한 것을 선택합니다.</p>
<p>이 변화는 A2A가 단순한 Agent SDK 기능에서 <strong>분산 시스템 Protocol</strong>로 발전하고 있다는 신호이기도 합니다.</p>
<hr>
<h1 id="7-a2a의-중심은-message보다-task다">7. A2A의 중심은 Message보다 Task다</h1>
<p>일반적인 Chat 시스템에서는 Message가 중심입니다.</p>
<pre><code class="language-text">User Message
 ↓
Assistant Message</code></pre>
<p>A2A에서는 Agent에게 긴 작업을 맡길 수 있기 때문에 <strong>Task</strong>라는 개념이 중요합니다.</p>
<p>예를 들어 Architecture Review Agent에게:</p>
<pre><code class="language-text">이 Repository 전체의
Architecture 문제를 분석해줘.</code></pre>
<p>라고 요청했다고 해보겠습니다.</p>
<p>몇 초 안에 끝나지 않을 수 있습니다.</p>
<p>Task는 상태를 가집니다.</p>
<pre><code class="language-text">Submitted
   ↓
Working
   ↓
Input Required
   ↓
Working
   ↓
Completed</code></pre>
<p>또는</p>
<pre><code class="language-text">Failed
Canceled
Rejected</code></pre>
<p>로 종료될 수도 있습니다.</p>
<p>즉 A2A는 단순 RPC보다 <strong>비동기 Job Protocol</strong>에 더 가까운 부분이 있습니다.</p>
<hr>
<h1 id="8-결과는-message가-아니라-artifact가-될-수-있다">8. 결과는 Message가 아니라 Artifact가 될 수 있다</h1>
<p>Agent가 만드는 결과도 단순 Text Response만 있는 것이 아닙니다.</p>
<p>A2A에는 <strong>Artifact</strong>라는 개념이 있습니다.</p>
<p>예를 들어 Security Agent가 작업 결과로:</p>
<pre><code class="language-text">security-report.json

security-review.md

dependency-risk.csv</code></pre>
<p>를 만들 수 있습니다.</p>
<p>Architecture Agent라면:</p>
<pre><code class="language-text">architecture-review.md

dependency-graph.json</code></pre>
<p>을 반환할 수 있습니다.</p>
<p>구조는:</p>
<pre><code class="language-text">Task
 │
 ├─ Messages
 │
 └─ Artifacts</code></pre>
<p>입니다.</p>
<p>Message는 Agent끼리 통신하는 내용이고,</p>
<p>Artifact는 실제 작업 결과물입니다.</p>
<p>이 구분은 Long-running Agent를 설계할 때 꽤 중요합니다.</p>
<hr>
<h1 id="9-streaming도-agent-협업에서는-중요하다">9. Streaming도 Agent 협업에서는 중요하다</h1>
<p>Agent 작업이 10분 걸린다고 생각해보겠습니다.</p>
<p>완료될 때까지 아무 응답이 없다면 Client에서는 장애인지 작업 중인지 알기 어렵습니다.</p>
<p>A2A는 Streaming을 지원합니다.</p>
<pre><code class="language-text">Main Agent
    ↓
Architecture Agent

&quot;Repository 분석 시작&quot;
        ↓
&quot;Dependency 분석 완료&quot;
        ↓
&quot;순환 의존성 발견&quot;
        ↓
&quot;Report 생성 중&quot;
        ↓
Artifact</code></pre>
<p>현재 Protocol에서는 SSE를 이용한 Streaming뿐 아니라 Transport에 따라 Streaming 방식을 지원할 수 있습니다.</p>
<p>즉 Client Agent가 Remote Agent의 진행 상태를 실시간으로 받을 수 있습니다.</p>
<hr>
<h1 id="10-몇-시간짜리-작업이라면-push가-더-자연스럽다">10. 몇 시간짜리 작업이라면 Push가 더 자연스럽다</h1>
<p>모든 Agent가 Streaming Connection을 계속 유지할 필요는 없습니다.</p>
<p>예를 들어 Research Agent에게:</p>
<pre><code class="language-text">지난 6개월 경쟁사 기술 변화와
GitHub Release를 조사해서
보고서 만들어줘.</code></pre>
<p>라고 요청했다고 해보겠습니다.</p>
<p>30분이 걸릴 수도 있습니다.</p>
<p>이 경우:</p>
<pre><code class="language-text">Request

↓

Connection 30분 유지</code></pre>
<p>보다:</p>
<pre><code class="language-text">Task 생성
 ↓
Connection 종료
 ↓
Agent Background Processing
 ↓
완료
 ↓
Webhook</code></pre>
<p>이 더 자연스럽습니다.</p>
<p>A2A는 Push Notification 방식도 정의합니다.</p>
<p>Long-running Task와 잘 맞는 이유입니다.</p>
<hr>
<h1 id="11-다른-언어와-framework를-연결할-때-a2a가-빛난다">11. 다른 언어와 Framework를 연결할 때 A2A가 빛난다</h1>
<p>Production 환경에서는 모든 Agent가 같은 Framework로 만들어지지 않습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Coding Agent

Python
LangGraph</code></pre>
<p>보안팀은:</p>
<pre><code class="language-text">Security Agent

Go
Custom Runtime</code></pre>
<p>법무팀은:</p>
<pre><code class="language-text">Compliance Agent

.NET
Microsoft Agent Framework</code></pre>
<p>일 수 있습니다.</p>
<p>이 Agent들을 모두 하나의 Framework로 다시 만드는 것은 현실적이지 않습니다.</p>
<p>A2A에서는 Protocol만 맞으면 됩니다.</p>
<pre><code class="language-text">Python Agent
     ↓
    A2A
     ↓
Go Agent</code></pre>
<p>Google도 2026년 실제 개발 예제로 <strong>Python 기반 Contract Extraction Agent와 Go 기반 Compliance Agent를 A2A로 연결하는 구조</strong>를 공개했습니다.</p>
<p>이게 A2A의 대표적인 장점입니다.</p>
<p>Agent Framework보다 <strong>Protocol Boundary를 기준으로 시스템을 연결할 수 있습니다.</strong></p>
<hr>
<h1 id="12-같은-애플리케이션-안의-subagent라면-a2a는-과할-수-있다">12. 같은 애플리케이션 안의 Subagent라면 A2A는 과할 수 있다</h1>
<p>여기서 중요한 점이 있습니다.</p>
<p>Agent가 두 개라고 무조건 A2A를 쓸 필요는 없습니다.</p>
<p>예를 들어 같은 Process 안에서:</p>
<pre><code class="language-text">Main Agent

├─ Planning Agent
├─ Coding Agent
└─ Test Agent</code></pre>
<p>를 단순히 역할 분리용으로 사용하고 있다고 해보겠습니다.</p>
<p>모든 Agent가</p>
<pre><code class="language-text">같은 Runtime

같은 Deployment

같은 Team

같은 Model Provider</code></pre>
<p>에 있다면 A2A는 오히려 복잡도를 늘릴 수 있습니다.</p>
<pre><code class="language-text">Network
Serialization
Timeout
Retry
Authentication
Versioning
Tracing</code></pre>
<p>문제가 추가됩니다.</p>
<p>이런 경우에는 Framework 내부의</p>
<pre><code class="language-text">Subagent

Agent as Tool

Handoff</code></pre>
<p>정도로 충분할 수 있습니다.</p>
<p><strong>A2A는 Agent가 있다는 이유로 쓰는 것이 아니라 실제 시스템 경계가 있을 때 쓰는 것이 자연스럽습니다.</strong></p>
<hr>
<h1 id="13-a2a를-쓰는-순간-분산-시스템-문제가-생긴다">13. A2A를 쓰는 순간 분산 시스템 문제가 생긴다</h1>
<p>A2A는 Agent Architecture 문제만이 아닙니다.</p>
<p>Network Boundary가 생깁니다.</p>
<p>그래서 기존 Backend와 비슷한 문제가 다시 나타납니다.</p>
<pre><code class="language-text">Timeout

Retry

Partial Failure

Authentication

Authorization

Version Compatibility

Observability</code></pre>
<p>예를 들어 Main Agent가 Security Agent에게 Task를 보냈는데 응답이 없습니다.</p>
<pre><code class="language-text">요청 실패인가?

아직 작업 중인가?

Agent Process가 죽었나?

Network가 끊겼나?</code></pre>
<p>를 구분해야 합니다.</p>
<p>Task ID와 상태가 중요한 이유입니다.</p>
<p>Agent 시스템도 결국 Production에 들어가면 <strong>분산 시스템 Engineering</strong>이 됩니다.</p>
<hr>
<h1 id="14-retry도-단순히-다시-보내면-안-된다">14. Retry도 단순히 다시 보내면 안 된다</h1>
<p>이 부분은 실무에서 특히 중요합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">&quot;Production Deploy 실행해줘.&quot;</code></pre>
<p>라는 Task를 Remote Agent에게 보냈습니다.</p>
<p>응답이 Timeout됐습니다.</p>
<p>Client가 그냥 다시 보내면:</p>
<pre><code class="language-text">Deploy #1

Deploy #2</code></pre>
<p>가 실행될 수도 있습니다.</p>
<p>따라서 실제 Production A2A에서는:</p>
<pre><code class="language-text">Task ID

Operation ID

Idempotency

State Persistence</code></pre>
<p>같은 설계가 필요합니다.</p>
<p>Protocol이 있다고 Distributed System Design이 사라지는 것은 아닙니다.</p>
<p>오히려 Agent가 실제 Action을 수행하기 시작하면 더 중요해집니다.</p>
<hr>
<h1 id="15-authentication과-authorization도-agent-card와-연결된다">15. Authentication과 Authorization도 Agent Card와 연결된다</h1>
<p>A2A Agent Card에는 해당 Agent가 어떤 인증 방식을 요구하는지 선언할 수 있습니다.</p>
<p>하지만:</p>
<pre><code class="language-text">Agent Card에
&quot;OAuth 사용&quot;</code></pre>
<p>이라고 적는 것만으로 보안이 끝나는 것은 아닙니다.</p>
<p>실제 Agent Server에서는 매 요청마다 Authentication과 Authorization을 적용해야 합니다.</p>
<p>예를 들어 Security Agent가:</p>
<pre><code class="language-text">scan_repository

read_security_report

change_security_policy</code></pre>
<p>Skill을 제공한다고 해도 사용자마다 권한은 다를 수 있습니다.</p>
<pre><code class="language-text">Developer

scan_repository ⭕

change_security_policy ❌</code></pre>
<p>처럼 Service Layer에서 검증해야 합니다.</p>
<p>A2A 공식 사양 역시 서버가 각 요청을 인증하고 최소 권한 원칙을 적용하도록 요구합니다.</p>
<hr>
<h1 id="16-agent-card도-공개-정보와-내부-정보를-나눌-수-있다">16. Agent Card도 공개 정보와 내부 정보를 나눌 수 있다</h1>
<p>Agent Card에는 Capability 정보가 들어갑니다.</p>
<p>하지만 Enterprise Agent라면 모든 Capability를 외부에 공개하고 싶지 않을 수 있습니다.</p>
<p>현재 A2A 사양에는 <strong>Authenticated Extended Agent Card</strong> 개념도 있습니다.</p>
<p>처음에는 Public Agent Card만 제공합니다.</p>
<pre><code class="language-text">Public Agent Card

Security Review 가능</code></pre>
<p>인증 이후에는:</p>
<pre><code class="language-text">Extended Agent Card

Dependency Scan
Source Scan
Internal Policy Review
Production Audit</code></pre>
<p>처럼 더 상세한 Capability를 제공할 수 있습니다.</p>
<p>Agent Discovery 자체에도 Security Boundary가 생기는 것입니다.</p>
<hr>
<h1 id="17-mcp--skill--a2a를-같이-쓰면-구조가-이렇게-된다">17. MCP + Skill + A2A를 같이 쓰면 구조가 이렇게 된다</h1>
<p>앞선 글과 연결하면 가장 현실적인 Agent Architecture는 이런 형태입니다.</p>
<pre><code class="language-text">                     Main Coding Agent
                            │
         ┌──────────────────┼──────────────────┐
         │                  │                  │
 Swift Migration       Release Skill      Security Agent
      Skill                 │                  │
         │                  │                 A2A
        MCP                MCP                 │
         │                  │           Security Runtime
   Compiler/Test            CI                  │
                                             MCP
                                              │
                                      Security Tools</code></pre>
<p>여기서:</p>
<pre><code class="language-text">Skill
→ 작업 절차</code></pre>
<pre><code class="language-text">MCP
→ Tool / Capability</code></pre>
<pre><code class="language-text">A2A
→ 독립 Agent에게 Task 위임</code></pre>
<p>을 담당합니다.</p>
<p>셋은 대체 관계가 아닙니다.</p>
<p>각자 다른 Layer입니다.</p>
<hr>
<h1 id="18-실제-개발팀에서는-이런-구조가-가능하다">18. 실제 개발팀에서는 이런 구조가 가능하다</h1>
<p>조금 더 현실적인 예를 만들어보겠습니다.</p>
<pre><code class="language-text">Developer
    ↓
Coding Agent</code></pre>
<p>Coding Agent는 Swift 6 Migration을 수행합니다.</p>
<pre><code class="language-text">Coding Agent
    ↓
Swift 6 Migration Skill
    ↓
Compiler MCP</code></pre>
<p>코드를 수정한 뒤 Security Review가 필요합니다.</p>
<pre><code class="language-text">Coding Agent
    ↓ A2A
Security Agent</code></pre>
<p>Security Agent는 자기 Tool을 사용합니다.</p>
<pre><code class="language-text">Security Agent
    ↓
Security Skill
    ↓
MCP
    ↓
CodeQL
Dependency Scanner
Secret Scanner</code></pre>
<p>그리고 Production에서 장애가 발생하면:</p>
<pre><code class="language-text">Main Agent
    ↓ A2A
Incident Agent</code></pre>
<p>Incident Agent가 독립적으로:</p>
<pre><code class="language-text">Logs
Metrics
Tracing
Deploy History</code></pre>
<p>를 분석합니다.</p>
<p>이 구조에서 Main Agent가 모든 Tool Schema와 Domain Prompt를 가질 필요가 없습니다.</p>
<hr>
<h1 id="19-a2a가-필요한지-판단하는-기준">19. A2A가 필요한지 판단하는 기준</h1>
<p>Agent를 Remote Service로 분리하기 전에 다음 질문을 해보면 됩니다.</p>
<h3 id="다른-팀이-소유하는가">다른 팀이 소유하는가?</h3>
<pre><code class="language-text">YES
→ A2A 후보</code></pre>
<h3 id="별도-deployment-cycle이-필요한가">별도 Deployment Cycle이 필요한가?</h3>
<pre><code class="language-text">YES
→ A2A 후보</code></pre>
<h3 id="다른-언어나-framework로-구현됐는가">다른 언어나 Framework로 구현됐는가?</h3>
<pre><code class="language-text">YES
→ A2A 후보</code></pre>
<h3 id="독립적인-context와-memory가-필요한가">독립적인 Context와 Memory가 필요한가?</h3>
<pre><code class="language-text">YES
→ A2A 후보</code></pre>
<h3 id="몇-분-이상-장시간-작업하는가">몇 분 이상 장시간 작업하는가?</h3>
<pre><code class="language-text">YES
→ A2A 후보</code></pre>
<h3 id="자체적으로-탐색하고-재계획하는가">자체적으로 탐색하고 재계획하는가?</h3>
<pre><code class="language-text">YES
→ A2A 후보</code></pre>
<p>반대로:</p>
<pre><code class="language-text">같은 Process

같은 Team

정해진 Procedure

명확한 Tool</code></pre>
<p>정도라면 A2A까지 갈 필요가 없을 가능성이 높습니다.</p>
<hr>
<h1 id="20-a2a의-최근-흐름도-달라지고-있다">20. A2A의 최근 흐름도 달라지고 있다</h1>
<p>A2A는 2025년 Google이 공개한 Protocol에서 시작했습니다.</p>
<p>하지만 지금은 Google 전용 Protocol로 보는 것도 조금 맞지 않습니다.</p>
<p>현재 A2A는 Linux Foundation의 Agentic AI Foundation에서 운영되는 Open Standard로 이동했고, 150개가 넘는 조직이 참여하는 생태계로 확대되고 있습니다.</p>
<p>공식 A2A 사양도 현재 <strong>0.3.0</strong>까지 발전했습니다.</p>
<p>특히 최근에는:</p>
<pre><code class="language-text">Agent Discovery

Multi Transport

Authentication

Streaming

Push Notification

Long-running Task

Artifact Exchange</code></pre>
<p>처럼 실제 Production Agent를 운영하는 데 필요한 영역들이 구체화되고 있습니다.</p>
<p>즉 A2A가 단순한</p>
<pre><code class="language-text">Agent끼리 Chat한다.</code></pre>
<p>수준에서</p>
<pre><code class="language-text">Distributed Agent Runtime을
어떻게 연결할 것인가.</code></pre>
<p>라는 문제로 이동하고 있습니다.</p>
<hr>
<h1 id="21-결국-a2a는-agent용-http에-가까워질-수-있다">21. 결국 A2A는 Agent용 HTTP에 가까워질 수 있다</h1>
<p>HTTP가 등장했다고 모든 Function Call을 HTTP로 바꾸지는 않습니다.</p>
<p>같은 Process 안에서는 그냥 Function을 호출합니다.</p>
<pre><code class="language-text">function()</code></pre>
<p>서비스 경계가 생겼을 때 HTTP가 의미를 갖습니다.</p>
<pre><code class="language-text">Service A
   ↓ HTTP
Service B</code></pre>
<p>A2A도 비슷하게 볼 수 있습니다.</p>
<pre><code class="language-text">같은 Runtime

→ Subagent / Agent as Tool</code></pre>
<pre><code class="language-text">Capability 호출

→ MCP</code></pre>
<pre><code class="language-text">독립 Agent Runtime

→ A2A</code></pre>
<p>입니다.</p>
<p>그래서 A2A를 Agent끼리 대화하는 새로운 기능 정도로 보기보다 <strong>Agent 시스템 사이의 Network Contract</strong>로 보는 편이 더 정확합니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>앞선 글에서는 모든 전문 기능을 Agent로 만들 필요가 없다는 이야기를 했습니다.</p>
<pre><code class="language-text">정해진 절차
+
명확한 Tool
        ↓
Skill + MCP</code></pre>
<p>가 더 단순한 경우가 많습니다.</p>
<p>하지만 Agent를 정말 분리해야 하는 순간도 있습니다.</p>
<pre><code class="language-text">독립적인 판단

별도 Context

별도 Runtime

별도 Team

장시간 Workflow

다른 언어 / Framework</code></pre>
<p>가 필요하다면 Agent 자체가 하나의 독립 서비스가 됩니다.</p>
<p>그리고 그때 필요한 것이 A2A입니다.</p>
<p>정리하면 세 가지의 역할은 꽤 명확합니다.</p>
<pre><code class="language-text">Skill

&quot;어떻게 일할 것인가&quot;</code></pre>
<pre><code class="language-text">MCP

&quot;무엇을 실행할 수 있는가&quot;</code></pre>
<pre><code class="language-text">A2A

&quot;어떤 Agent에게 일을 맡길 것인가&quot;</code></pre>
<p>이 세 가지를 같이 보면 최근 Agent Architecture의 방향도 조금 더 명확해집니다.</p>
<p>모든 기능을 하나의 거대한 Agent에 넣을 필요도 없고,</p>
<p>모든 기능을 Specialist Agent로 만들 필요도 없습니다.</p>
<pre><code class="language-text">Main Agent
    │
    ├─ Skill
    │    └─ MCP Tool
    │
    ├─ Skill
    │    └─ MCP Tool
    │
    └─ A2A
         ↓
    Independent Agent
         ↓
        MCP</code></pre>
<p>형태의 Hybrid Architecture가 오히려 더 현실적입니다.</p>
<p>결국 Agent Architecture를 설계할 때 중요한 질문은 Agent가 몇 개인지가 아닙니다.</p>
<p><strong>이 기능이 단순 Capability인가, 아니면 독립적으로 일을 맡길 수 있는 시스템인가.</strong></p>
<p>A2A는 후자가 필요해지는 순간부터 의미가 생깁니다.</p>
<hr>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>A2A Protocol — Official Specification 0.3.0</strong><br>Agent Card, Task, Message, Artifact, Streaming, Push Notification과 JSON-RPC·gRPC·HTTP+JSON Transport를 포함한 현재 공식 A2A 사양입니다.<br><a href="https://a2a-protocol.org/v0.3.0/specification/?utm_source=chatgpt.com">A2A 0.3.0 공식 Specification 보기</a></p>
</li>
<li><p><strong>A2A Protocol — Core Concepts</strong><br>Agent Card, Task, Message, Part, Artifact 등 A2A의 핵심 Domain Model을 정리한 공식 문서입니다.<br><a href="https://a2a-protocol.org/latest/topics/key-concepts/?utm_source=chatgpt.com">A2A Core Concepts 보기</a></p>
</li>
<li><p><strong>Google Developers — Build Cross-Language Multi-Agent Team with ADK and A2A</strong><br>Python으로 만든 Contract Extraction Agent와 Go 기반 Compliance Agent를 A2A로 연결하는 실무 예제를 확인할 수 있습니다.<br><a href="https://developers.googleblog.com/build-cross-language-multi-agent-team-with-google-agent-development-kit-and-a2a/?utm_source=chatgpt.com">Google A2A Cross-Language 사례 보기</a></p>
</li>
<li><p><strong>Microsoft Agent Framework — A2A Agent Service</strong><br>Agent Card Discovery, Remote Agent 연결, Streaming, Background Response와 Long-running Task를 Microsoft Agent Framework에서 사용하는 방법을 확인할 수 있습니다.<br><a href="https://learn.microsoft.com/en-us/agent-framework/agents/providers/agent-to-agent?utm_source=chatgpt.com">Microsoft A2A 공식 문서 보기</a></p>
</li>
<li><p><strong>Linux Foundation — A2A / Agentic AI Foundation</strong><br>A2A가 Linux Foundation 산하 Agentic AI Foundation의 Hosted Project로 운영되는 현재 생태계와 표준화 흐름을 확인할 수 있습니다.<br><a href="https://www.linuxfoundation.org/blog/linux-foundation-newsletter-september-2026?utm_source=chatgpt.com">Linux Foundation 공식 자료 보기</a></p>
</li>
</ul>
<p><strong>현재 공식 A2A 사양은 0.3.0이며</strong>, Agent Card를 통한 Discovery, 상태를 가지는 Task, 결과물인 Artifact, Streaming과 Push Notification을 중심으로 독립 Agent 간 장기 작업을 다룰 수 있도록 설계되어 있습니다. 0.3.0에서는 JSON-RPC, gRPC, HTTP+JSON을 핵심 Transport로 정의하고 있습니다.</p>
<p>또한 A2A는 현재 Linux Foundation 산하 AAIF의 Hosted Project로 운영되고 있으며, Linux Foundation은 2026년 9월 기준 150개가 넘는 조직이 A2A 생태계에 참여하고 있다고 설명하고 있습니다. 따라서 현재 흐름은 특정 Agent Framework의 내부 기능보다 <strong>서로 다른 Vendor·Language·Runtime의 Agent를 연결하기 위한 독립적인 Protocol Layer</strong>에 더 가깝습니다.
:::</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[멀티에이전트가 항상 답은 아니다 《1》]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609181</link>
            <guid>https://velog.io/@kyu_ios_dev/2609181</guid>
            <pubDate>Fri, 18 Sep 2026 05:31:59 GMT</pubDate>
            <description><![CDATA[<h3 id="멀티에이전트가-항상-답은-아니다">멀티에이전트가 항상 답은 아니다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/eb34dc51-d617-45d2-be0f-231b1572b62a/image.png" alt=""></p>
<h2 id="agent를-skill로-바꾸는-아키텍처">Agent를 Skill로 바꾸는 아키텍처</h2>
<p>AI Agent 시스템을 만들기 시작하면 구조가 빠르게 커집니다.</p>
<p>처음에는 하나의 Agent가 여러 Tool을 사용합니다.</p>
<pre><code class="language-text">User
 ↓
Main Agent
 ↓
Tools</code></pre>
<p>기능이 늘어나면 역할을 분리하기 시작합니다.</p>
<pre><code class="language-text">Main Agent
   │
   ├─ Release Agent
   ├─ Refactoring Agent
   ├─ Migration Agent
   └─ Research Agent</code></pre>
<p>겉으로 보면 깔끔합니다.</p>
<p>각 Agent가 자기 역할만 담당하니 Microservice처럼 책임도 명확해 보입니다.</p>
<p>그런데 여기서 한 번 생각해볼 필요가 있습니다.</p>
<p><strong>저 기능마다 정말 별도의 LLM Agent가 필요한가?</strong></p>
<p>Microsoft가 9월 16일 공개한 Agent Framework 사례에서도 같은 질문을 던졌습니다.</p>
<p>기존에는 상위 Advisor가 여러 Specialist Agent를 A2A로 호출했지만, 일부 Specialist를 <code>SKILL.md + MCP Tool</code> 구조로 바꿨습니다.</p>
<p>서비스 자체를 합친 것은 아닙니다.</p>
<p>없어진 것은 <strong>Specialist마다 존재하던 별도의 Model Loop</strong>였습니다.</p>
<p>이 차이는 실제 개발 시스템에서 더 중요합니다.</p>
<hr>
<h1 id="1-multi-agent를-만들면-agent-하나만-추가되는-것이-아니다">1. Multi-Agent를 만들면 Agent 하나만 추가되는 것이 아니다</h1>
<p>예를 들어 Release Agent를 하나 만든다고 생각해보겠습니다.</p>
<p>구조는 단순해 보입니다.</p>
<pre><code class="language-text">Main Agent
   ↓
Release Agent
   ↓
CI / Git / App Store</code></pre>
<p>하지만 실제 Release Agent 안에는 이런 것들이 들어갑니다.</p>
<pre><code class="language-text">Release Agent

├─ System Prompt
├─ Model
├─ Context
├─ Tools
├─ Agent Loop
└─ Result Generation</code></pre>
<p>Main Agent가 Release Agent에게 일을 넘기면 Release Agent는 다시 모델을 호출합니다.</p>
<pre><code class="language-text">Main Agent
   ↓
Model 판단
   ↓
Release Agent 호출
   ↓
Release Agent Model 판단
   ↓
Tool 호출
   ↓
Release Agent Model 정리
   ↓
Main Agent
   ↓
최종 응답</code></pre>
<p>단순히 기능 하나가 추가된 것 같지만 실제로는 <strong>Reasoning Layer 하나가 더 생긴 것</strong>입니다.</p>
<p>Agent가 늘어날수록 함께 늘어나는 것도 있습니다.</p>
<pre><code class="language-text">Model Call
Context
Token
Latency
Failure Point
Observability
Permission</code></pre>
<p>그래서 Multi-Agent는 역할을 나누는 좋은 방법이지만, 무조건 가벼운 구조는 아닙니다.</p>
<hr>
<h1 id="2-microsoft는-specialist-agent-일부를-skill로-바꿨다">2. Microsoft는 Specialist Agent 일부를 Skill로 바꿨다</h1>
<p>Microsoft 사례에서는 Weather, Safety, Lift Traffic 같은 Specialist가 각각 독립적인 Agent였습니다.</p>
<p>구조는 이런 형태였습니다.</p>
<pre><code class="language-text">Advisor
   ↓
Specialist Agent
   ↓
Domain Tool
   ↓
Domain Service</code></pre>
<p>이 구조를 다음처럼 바꿨습니다.</p>
<pre><code class="language-text">Advisor
   ↓
Skill
   ↓
MCP Tool
   ↓
Domain Service</code></pre>
<p>여기서 중요한 것은 Domain Service가 그대로 남아 있다는 점입니다.</p>
<pre><code class="language-text">Weather Service
Safety Service
Lift Service</code></pre>
<p>는 계속 독립적으로 배포되고 관리됩니다.</p>
<p>달라진 것은 <strong>어디에서 판단하느냐</strong>입니다.</p>
<p>기존에는:</p>
<pre><code class="language-text">Advisor Reasoning
+
Specialist Reasoning</code></pre>
<p>이었다면,</p>
<p>변경 후에는:</p>
<pre><code class="language-text">Advisor Reasoning</code></pre>
<p>하나가 Domain Operation까지 선택합니다.</p>
<p>Specialist가 가지고 있던 절차와 지식은 <code>SKILL.md</code>로 이동합니다.</p>
<hr>
<h1 id="3-agent를-없앤다고-domain을-없애는-것은-아니다">3. Agent를 없앤다고 Domain을 없애는 것은 아니다</h1>
<p>이 구분이 중요합니다.</p>
<p>Microservice가 네 개 있다고 Agent도 네 개일 필요는 없습니다.</p>
<p>예를 들어 Backend가 이렇게 구성돼 있다고 해보겠습니다.</p>
<pre><code class="language-text">Release Service

Quality Service

Artifact Service

Notification Service</code></pre>
<p>이걸 그대로</p>
<pre><code class="language-text">Release Agent

Quality Agent

Artifact Agent

Notification Agent</code></pre>
<p>로 옮길 이유는 없습니다.</p>
<p>Service Boundary는 주로 이런 것을 위한 것입니다.</p>
<pre><code class="language-text">Business Logic
Data Ownership
Deployment
Scaling
Security
Team Ownership</code></pre>
<p>Agent Boundary는 다릅니다.</p>
<pre><code class="language-text">Independent Reasoning
Private Context
Autonomy
Long-running Workflow
Specialized Model</code></pre>
<p>즉</p>
<p><strong>서비스가 분리돼 있다는 것과 Reasoning을 분리해야 한다는 것은 다른 문제입니다.</strong></p>
<hr>
<h1 id="4-가장-현실적인-예--release-agent가-정말-필요한가">4. 가장 현실적인 예 — Release Agent가 정말 필요한가</h1>
<p>iOS 앱 배포를 자동화한다고 해보겠습니다.</p>
<p>Release Agent를 따로 만들 수도 있습니다.</p>
<pre><code class="language-text">Main Agent
   ↓
Release Agent
   ↓
Git
CI
TestFlight
App Store</code></pre>
<p>하지만 실제 업무를 보면 꽤 정형화돼 있습니다.</p>
<pre><code class="language-text">현재 Branch 확인

↓

변경사항 확인

↓

Version / Build Number 확인

↓

Test 실행

↓

Archive

↓

Upload

↓

Release Note 생성</code></pre>
<p>이 정도라면 별도의 LLM Agent보다 <strong>Release Skill</strong>이 더 자연스러울 수 있습니다.</p>
<pre><code class="language-text">Release Skill

1. release branch를 확인한다.
2. working tree가 clean인지 확인한다.
3. test를 실행한다.
4. build number를 증가시킨다.
5. archive를 생성한다.
6. TestFlight에 업로드한다.</code></pre>
<p>실행 기능은 MCP Tool이나 다른 Tool Interface로 제공합니다.</p>
<pre><code class="language-text">git_status

run_tests

increment_build_number

archive_app

upload_testflight</code></pre>
<p>구조는 단순해집니다.</p>
<pre><code class="language-text">Main Agent
    ↓
Release Skill
    ↓
필요한 Tool 선택
    ↓
CI / App Store</code></pre>
<p>Release를 수행하는 방법은 Skill이 알려주고,</p>
<p>실제 실행은 Tool이 담당합니다.</p>
<hr>
<h1 id="5-그런데-지금-배포해도-되는가라면-이야기가-달라진다">5. 그런데 “지금 배포해도 되는가?”라면 이야기가 달라진다</h1>
<p>같은 Release 영역이라도 질문이 달라질 수 있습니다.</p>
<p>예를 들어:</p>
<blockquote>
<p>지금 이 버전을 배포해도 괜찮을까?</p>
</blockquote>
<p>라면 단순 절차가 아닙니다.</p>
<p>다음 정보를 확인해야 할 수도 있습니다.</p>
<pre><code class="language-text">QA 결과

Crash 증가 여부

최근 Production 장애

Backend 호환성

Feature Flag

Rollout 상태

최근 Commit 위험도</code></pre>
<p>그리고 상황에 따라 추가 정보를 다시 조회할 수도 있습니다.</p>
<pre><code class="language-text">Crash 증가
 ↓
특정 OS인가?
 ↓
해당 Feature 변경 확인
 ↓
최근 Commit 확인
 ↓
Rollout 범위 판단</code></pre>
<p>이 정도가 되면 별도의 Release/Deployment Agent가 의미를 가질 수 있습니다.</p>
<p>즉 같은 Domain이라도 기준은 기능 이름이 아닙니다.</p>
<p><strong>독립적인 Reasoning이 필요한가가 기준입니다.</strong></p>
<hr>
<h1 id="6-코드-품질-작업도-대부분-skill-후보가-될-수-있다">6. 코드 품질 작업도 대부분 Skill 후보가 될 수 있다</h1>
<p>두 번째 예는 Code Quality입니다.</p>
<p>처음에는 이런 구조를 만들기 쉽습니다.</p>
<pre><code class="language-text">Main Coding Agent
        ↓
Refactoring Agent
        ↓
SwiftLint
Tests
CodeQL</code></pre>
<p>하지만 Refactoring Agent가 하는 작업을 자세히 보면:</p>
<pre><code class="language-text">SwiftLint violation 수정

unused code 제거

deprecated API 교체

간단한 중복 제거

test 실행</code></pre>
<p>정도일 수 있습니다.</p>
<p>이런 작업은 대부분 절차가 명확합니다.</p>
<pre><code class="language-text">Code Quality Skill

1. Analyzer를 실행한다.
2. Finding을 Rule별로 분류한다.
3. 작은 Batch로 묶는다.
4. 코드를 수정한다.
5. Build한다.
6. Test한다.
7. Finding이 사라졌는지 확인한다.</code></pre>
<p>Tool은:</p>
<pre><code class="language-text">run_swiftlint

find_usages

apply_patch

run_build

run_tests</code></pre>
<p>만 제공하면 됩니다.</p>
<p>구조는:</p>
<pre><code class="language-text">Coding Agent
     ↓
Code Quality Skill
     ↓
Analyzer / Build / Test</code></pre>
<p>로 충분합니다.</p>
<p>굳이 <code>Refactoring Agent</code>라는 두 번째 Reasoning Loop가 필요하지 않을 수 있습니다.</p>
<hr>
<h1 id="7-swift-6-migration도-agent-여러-개보다-skill이-더-자연스러울-수-있다">7. Swift 6 Migration도 Agent 여러 개보다 Skill이 더 자연스러울 수 있다</h1>
<p>iOS 프로젝트를 Swift 6으로 Migration한다고 해보겠습니다.</p>
<p>Multi-Agent 구조를 과하게 만들면 이런 모습도 가능합니다.</p>
<pre><code class="language-text">Main Agent
   │
   ├─ Concurrency Agent
   ├─ Sendable Agent
   ├─ Actor Agent
   ├─ Build Agent
   └─ Test Agent</code></pre>
<p>기능 이름만 보면 역할이 잘 분리돼 보입니다.</p>
<p>하지만 실제 Migration 절차는 상당 부분 정형화돼 있습니다.</p>
<pre><code class="language-text">Compiler Warning 수집

↓

오류 유형 분류

↓

Sendable 문제 확인

↓

Actor Isolation 확인

↓

@MainActor 적용 여부 확인

↓

코드 수정

↓

Build

↓

Test</code></pre>
<p>이것을 하나의 Skill로 만들 수 있습니다.</p>
<pre><code class="language-text">Swift 6 Migration Skill</code></pre>
<p>그리고 Tool은:</p>
<pre><code class="language-text">run_build

search_symbol

find_concurrency_diagnostics

apply_patch

run_tests</code></pre>
<p>를 제공합니다.</p>
<pre><code class="language-text">Main Coding Agent
        ↓
Swift 6 Migration Skill
        ↓
Compiler / Search / Test</code></pre>
<p>이 정도 구조면 상당수 Migration 작업을 처리할 수 있습니다.</p>
<hr>
<h1 id="8-skill이-좋은-영역의-특징은-꽤-분명하다">8. Skill이 좋은 영역의 특징은 꽤 분명하다</h1>
<p>지금까지 예를 보면 공통점이 있습니다.</p>
<pre><code class="language-text">Release

Code Quality

Swift Migration</code></pre>
<p>모두 일정한 절차가 있습니다.</p>
<p>그리고 사용할 Tool도 명확합니다.</p>
<p>정리하면 이런 특징을 가진 기능은 Skill 후보입니다.</p>
<pre><code class="language-text">Bounded Domain

명확한 Procedure

명확한 Input / Output

Typed Tool

Parent Agent가 판단 가능</code></pre>
<p>이런 업무에 매번 별도의 Agent를 만들면 Reasoning Layer만 불필요하게 늘어날 수 있습니다.</p>
<hr>
<h1 id="9-반대로-장애-대응은-agent로-남기는-편이-자연스럽다">9. 반대로 장애 대응은 Agent로 남기는 편이 자연스럽다</h1>
<p>이번에는 반대 사례를 보겠습니다.</p>
<p>Production 장애가 발생했다고 해보겠습니다.</p>
<pre><code class="language-text">API Error Rate 급증</code></pre>
<p>단순한 절차로 끝나지 않습니다.</p>
<pre><code class="language-text">Error Rate 확인
 ↓
최근 Deploy 확인
 ↓
특정 API인가?
 ↓
DB Latency 확인
 ↓
관련 Trace 확인
 ↓
최근 Commit 확인
 ↓
원인 가설 생성
 ↓
추가 로그 조회
 ↓
가설 수정</code></pre>
<p>이 과정은 계속 달라집니다.</p>
<p>첫 번째 조사 결과에 따라 다음 Tool이 달라집니다.</p>
<pre><code class="language-text">Logs

Metrics

Tracing

Git

Deployment History

Feature Flag</code></pre>
<p>를 어떤 순서로 사용할지도 미리 정하기 어렵습니다.</p>
<p>이런 작업은:</p>
<pre><code class="language-text">Explore
 ↓
Hypothesis
 ↓
Verify
 ↓
Re-plan</code></pre>
<p>이 반복됩니다.</p>
<p>이 경우는 Skill보다 <strong>Incident Agent</strong>가 더 자연스럽습니다.</p>
<hr>
<h1 id="10-research-agent도-같은-이유로-agent로-남는다">10. Research Agent도 같은 이유로 Agent로 남는다</h1>
<p>Microsoft의 실제 사례에서도 모든 Specialist를 Skill로 바꾸지는 않았습니다.</p>
<p>Web Research 기능은 Agent로 유지했습니다.</p>
<p>Research는 보통:</p>
<pre><code class="language-text">검색
 ↓
결과 판단
 ↓
추가 검색
 ↓
출처 비교
 ↓
새로운 질문
 ↓
재검색
 ↓
정리</code></pre>
<p>과정을 반복합니다.</p>
<p>미리 정해진 Tool 호출 순서가 없습니다.</p>
<p>독립적인 Reasoning이 필요합니다.</p>
<p>그래서:</p>
<pre><code class="language-text">Main Agent
   ↓
Research Agent
   ↓
Search Tools</code></pre>
<p>구조가 자연스럽습니다.</p>
<p>이 부분이 중요한 이유는 Microsoft 사례의 메시지가</p>
<p><strong>“Multi-Agent를 없애라”</strong></p>
<p>가 아니기 때문입니다.</p>
<hr>
<h1 id="11-실무에서-구분하는-기준은-생각보다-단순하다">11. 실무에서 구분하는 기준은 생각보다 단순하다</h1>
<p>Agent를 만들기 전에 다음 질문을 해보면 됩니다.</p>
<h3 id="독립적으로-판단해야-하는가">독립적으로 판단해야 하는가?</h3>
<pre><code class="language-text">YES
→ Agent 후보</code></pre>
<h3 id="작업-중-새로운-가설을-만들고-재계획해야-하는가">작업 중 새로운 가설을 만들고 재계획해야 하는가?</h3>
<pre><code class="language-text">YES
→ Agent 후보</code></pre>
<h3 id="자체적으로-긴-workflow를-수행하는가">자체적으로 긴 Workflow를 수행하는가?</h3>
<pre><code class="language-text">YES
→ Agent 후보</code></pre>
<h3 id="다른-모델이나-private-context가-필요한가">다른 모델이나 Private Context가 필요한가?</h3>
<pre><code class="language-text">YES
→ Agent 후보</code></pre>
<p>반대로:</p>
<h3 id="절차가-명확한가">절차가 명확한가?</h3>
<pre><code class="language-text">YES
→ Skill 후보</code></pre>
<h3 id="tool의-input--output이-명확한가">Tool의 Input / Output이 명확한가?</h3>
<pre><code class="language-text">YES
→ Skill 후보</code></pre>
<h3 id="parent-agent가-operation을-선택해도-되는가">Parent Agent가 Operation을 선택해도 되는가?</h3>
<pre><code class="language-text">YES
→ Skill 후보</code></pre>
<p>결국 이렇게 줄일 수 있습니다.</p>
<pre><code class="language-text">정해진 절차
+
명확한 Tool
        ↓
      Skill</code></pre>
<pre><code class="language-text">탐색
+
가설
+
반복 판단
        ↓
      Agent</code></pre>
<hr>
<h1 id="12-skillmd는-agent의-system-prompt를-재사용-가능한-자산으로-만든다">12. <code>SKILL.md</code>는 Agent의 System Prompt를 재사용 가능한 자산으로 만든다</h1>
<p>Specialist Agent를 Skill로 바꿀 때 System Prompt가 사라지는 것은 아닙니다.</p>
<p>예를 들어 Release Agent에 이런 지침이 있었다고 해보겠습니다.</p>
<pre><code class="language-text">release branch에서만 배포한다.

working tree가 dirty면 중단한다.

test 실패 시 archive하지 않는다.

배포 후 build number를 기록한다.</code></pre>
<p>기존에는 Release Agent의 System Prompt 안에 들어가 있습니다.</p>
<pre><code class="language-text">Release Agent
   ↓
System Prompt</code></pre>
<p>Skill 구조에서는:</p>
<pre><code class="language-text">release/SKILL.md</code></pre>
<p>로 이동합니다.</p>
<p>이 변화가 중요한 이유는 해당 지식이 더 이상 특정 Agent Runtime에 묶이지 않기 때문입니다.</p>
<pre><code class="language-text">Agent Prompt</code></pre>
<p>가 아니라</p>
<pre><code class="language-text">Reusable Engineering Procedure</code></pre>
<p>가 됩니다.</p>
<hr>
<h1 id="13-팀의-개발-규칙도-skill이-될-수-있다">13. 팀의 개발 규칙도 Skill이 될 수 있다</h1>
<p>이 구조를 한 단계 더 확장하면 팀 내부 Engineering Rule도 Skill로 만들 수 있습니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">ios-feature-development/SKILL.md</code></pre>
<p>안에:</p>
<pre><code class="language-text">1. Feature Module 생성
2. Domain Interface 정의
3. Repository 연결
4. ViewModel 작성
5. SwiftUI View 작성
6. Unit Test 추가
7. Build 검증</code></pre>
<p>을 정의합니다.</p>
<p>다른 Skill로는:</p>
<pre><code class="language-text">swift6-migration

ios-release

code-quality

dependency-update</code></pre>
<p>를 둘 수 있습니다.</p>
<p>이렇게 되면 팀의 Engineering Knowledge가</p>
<pre><code class="language-text">Wiki
Confluence
README</code></pre>
<p>에만 있는 것이 아니라 Agent가 실행할 수 있는 형태로도 존재하게 됩니다.</p>
<hr>
<h1 id="14-mcp-tool은-skill과-역할이-다르다">14. MCP Tool은 Skill과 역할이 다르다</h1>
<p>여기서 Skill과 MCP를 하나로 생각하면 안 됩니다.</p>
<p>Skill은:</p>
<pre><code class="language-text">무엇을 해야 하는가?

어떤 순서로 해야 하는가?

어떤 기준을 따라야 하는가?</code></pre>
<p>를 알려줍니다.</p>
<p>MCP Tool은:</p>
<pre><code class="language-text">무엇을 실행할 수 있는가?</code></pre>
<p>를 제공합니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Swift 6 Migration Skill</code></pre>
<p>은 이런 절차를 설명합니다.</p>
<pre><code class="language-text">Concurrency Diagnostic을 먼저 분류한다.</code></pre>
<p>MCP Tool은 실제 기능을 제공합니다.</p>
<pre><code class="language-text">run_build()

search_symbol()

apply_patch()

run_tests()</code></pre>
<p>그리고 최종 판단은 Agent가 합니다.</p>
<pre><code class="language-text">Skill
 → Procedure

MCP
 → Capability

Agent
 → Reasoning</code></pre>
<p>으로 나누면 이해하기 쉽습니다.</p>
<hr>
<h1 id="15-tool을-처음부터-전부-context에-넣을-필요도-없다">15. Tool을 처음부터 전부 Context에 넣을 필요도 없다</h1>
<p>Agent 시스템이 커지면 Tool 수가 빠르게 늘어납니다.</p>
<p>예를 들어 개발 Agent에:</p>
<pre><code class="language-text">Git Tools             15개
CI Tools              10개
Xcode Tools           12개
GitHub Tools          20개
Monitoring Tools      18개
Database Tools        15개</code></pre>
<p>가 있다면 이미 90개입니다.</p>
<p>모든 Tool Schema를 매 요청마다 모델에게 보여주는 것은 비효율적입니다.</p>
<p>Microsoft 사례에서는 Skill이 로드된 뒤 해당 Domain의 MCP Tool만 Context에 추가하는 방식을 사용했습니다.</p>
<pre><code class="language-text">처음

Release Skill
Migration Skill
Quality Skill
Incident Agent</code></pre>
<p>정도만 보여줍니다.</p>
<p>사용자가:</p>
<blockquote>
<p>Swift 6 Migration 진행해줘.</p>
</blockquote>
<p>라고 하면:</p>
<pre><code class="language-text">load_skill(&quot;swift6-migration&quot;)</code></pre>
<p>후에 관련 Tool만 추가합니다.</p>
<pre><code class="language-text">run_build
search_symbol
apply_patch
run_tests</code></pre>
<p>나머지는 Context에 들어오지 않습니다.</p>
<p>이게 <strong>Progressive Disclosure</strong>의 핵심입니다.</p>
<hr>
<h1 id="16-skill은-context-engineering-수단이기도-하다">16. Skill은 Context Engineering 수단이기도 하다</h1>
<p>Tool이 많아지는 문제는 단순 UI 문제가 아닙니다.</p>
<p>각 Tool에는:</p>
<pre><code class="language-text">Name
Description
Input Schema
Output Schema</code></pre>
<p>가 있습니다.</p>
<p>전부 Context에 들어가면 Token을 소비합니다.</p>
<p>그래서:</p>
<pre><code class="language-text">100 Tools</code></pre>
<p>전체를 넣는 대신</p>
<pre><code class="language-text">10 Skill Summaries</code></pre>
<p>만 먼저 제공하고,</p>
<p>선택된 Skill의 Tool만 뒤에서 추가하는 구조가 더 유리할 수 있습니다.</p>
<p>즉 Agent Skill은 단순한 Prompt 관리 기법이 아니라 <strong>Context Engineering 전략</strong>이기도 합니다.</p>
<hr>
<h1 id="17-microsoft-사례에서는-model-call이-절반-수준으로-줄었다">17. Microsoft 사례에서는 Model Call이 절반 수준으로 줄었다</h1>
<p>Microsoft는 동일한 Ski Resort 애플리케이션에서 기존 A2A Specialist 구조와 Skill + MCP 구조를 직접 비교했습니다.</p>
<p>A2A 구조에서는 세 번의 실행에서 Model Call이 각각:</p>
<pre><code class="language-text">6회
6회
7회</code></pre>
<p>였습니다.</p>
<p>Skill + MCP 구조는 모두:</p>
<pre><code class="language-text">3회</code></pre>
<p>였습니다.</p>
<p>Skill 방식에서는:</p>
<pre><code class="language-text">Model #1
→ 필요한 Skill 로드

Model #2
→ 필요한 MCP Operation 호출

Model #3
→ 최종 응답</code></pre>
<p>으로 끝났습니다.</p>
<p>Specialist마다 별도의 Model Loop를 돌지 않았기 때문입니다.</p>
<hr>
<h1 id="18-하지만-token은-오히려-증가했다">18. 하지만 Token은 오히려 증가했다</h1>
<p>여기서 중요한 결과가 하나 나옵니다.</p>
<p>Model Call이 줄었으니 Token도 줄었을 것 같지만 그렇지 않았습니다.</p>
<p>세 번의 실행을 합치면:</p>
<pre><code class="language-text">A2A

11,134 tokens</code></pre>
<p>Skill 방식은:</p>
<pre><code class="language-text">13,533 tokens</code></pre>
<p>이었습니다.</p>
<p>약 22% 많았습니다.</p>
<p>이유 중 하나는 Parent Agent의 Context가 계속 커졌기 때문입니다.</p>
<pre><code class="language-text">Skill Instruction
+
Tool Schema
+
Tool Result
+
Conversation Context</code></pre>
<p>가 상위 Agent에 누적됩니다.</p>
<p>따라서</p>
<p><strong>Model Call이 줄었다 = Token이 줄었다</strong></p>
<p>는 공식은 성립하지 않습니다.</p>
<hr>
<h1 id="19-multi-agent의-context-isolation은-여전히-장점이다">19. Multi-Agent의 Context Isolation은 여전히 장점이다</h1>
<p>Specialist Agent를 유지하면 Context를 자연스럽게 분리할 수 있습니다.</p>
<p>예를 들어 Incident Agent는:</p>
<pre><code class="language-text">Logs
Metrics
Tracing</code></pre>
<p>만 보면 됩니다.</p>
<p>Release Agent는:</p>
<pre><code class="language-text">Git
CI
App Store</code></pre>
<p>만 봅니다.</p>
<pre><code class="language-text">Main Agent Context
≠
Incident Context
≠
Release Context</code></pre>
<p>가 됩니다.</p>
<p>Skill 중심 구조에서는 Parent Agent가 더 많은 Domain Instruction과 Tool 정보를 가져가게 됩니다.</p>
<p>그래서 Agent를 줄이는 것이 항상 좋은 것도 아닙니다.</p>
<p>대규모 시스템에서는 Context Isolation 때문에 Agent를 분리하는 것이 더 나은 경우도 있습니다.</p>
<hr>
<h1 id="20-보안-정책은-skill에-맡기면-안-된다">20. 보안 정책은 Skill에 맡기면 안 된다</h1>
<p>예를 들어 Release Skill에:</p>
<pre><code class="language-text">Production 배포는 관리자만 가능하다.</code></pre>
<p>라고 적었다고 해보겠습니다.</p>
<p>이것은 Security Policy가 아닙니다.</p>
<p>LLM Instruction일 뿐입니다.</p>
<p>실제 Tool이나 Service에서는 반드시 다시 검증해야 합니다.</p>
<pre><code class="language-text">Authentication

Authorization

Validation

Audit Log</code></pre>
<p>를 코드에서 강제해야 합니다.</p>
<p>구조는 이렇게 보는 것이 맞습니다.</p>
<pre><code class="language-text">Skill

→ 어떻게 작업할지 설명</code></pre>
<pre><code class="language-text">Tool

→ 실행 가능한 Operation 제공</code></pre>
<pre><code class="language-text">Service

→ 실제 Business Rule과 Security 강제</code></pre>
<p>Agent Architecture에서 이 경계를 흐리면 위험합니다.</p>
<hr>
<h1 id="21-개발팀에서-가장-현실적인-구조는-hybrid다">21. 개발팀에서 가장 현실적인 구조는 Hybrid다</h1>
<p>실제 개발 시스템에서는 다음 형태가 가장 현실적일 수 있습니다.</p>
<pre><code class="language-text">                   Main Coding Agent
                          │
          ┌───────────────┼───────────────┐
          │               │               │
    Release Skill   Migration Skill   Incident Agent
          │               │               │
      MCP Tools        MCP Tools       Agent Loop
          │               │               │
         CI            Compiler       Logs / Metrics</code></pre>
<p>여기에:</p>
<pre><code class="language-text">Code Quality Skill

Dependency Update Skill

SPM Migration Skill</code></pre>
<p>같은 것을 추가할 수 있습니다.</p>
<p>반면:</p>
<pre><code class="language-text">Incident Analysis

Research

Architecture Investigation</code></pre>
<p>처럼 탐색과 판단이 필요한 작업은 Agent로 유지합니다.</p>
<hr>
<h1 id="22-결국-중요한-건-agent의-개수가-아니다">22. 결국 중요한 건 Agent의 개수가 아니다</h1>
<p>멀티에이전트 시스템을 설계하다 보면 Agent가 많을수록 역할이 명확하고 구조가 고도화된 것처럼 보이기도 합니다.</p>
<p>하지만 Agent 하나는 단순한 Class 하나가 아닙니다.</p>
<pre><code class="language-text">Model
Context
Reasoning
Tools
Lifecycle
Failure
Observability
Cost</code></pre>
<p>를 가진 Runtime입니다.</p>
<p>그래서 기능 하나가 추가될 때마다 먼저 물어볼 질문은:</p>
<pre><code class="language-text">어떤 Agent를 만들까?</code></pre>
<p>가 아니라</p>
<pre><code class="language-text">이 기능에
별도의 Reasoning Loop가 필요한가?</code></pre>
<p>가 되어야 합니다.</p>
<p>필요 없다면:</p>
<pre><code class="language-text">Skill
+
Tool</code></pre>
<p>이 더 단순합니다.</p>
<p>필요하다면:</p>
<pre><code class="language-text">Agent</code></pre>
<p>가 맞습니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>Multi-Agent Architecture가 잘못된 것은 아닙니다.</p>
<p>독립적인 판단과 긴 Workflow가 필요한 작업에서는 여전히 강력합니다.</p>
<p>하지만</p>
<pre><code class="language-text">Release

Code Quality

Migration

Dependency Update</code></pre>
<p>처럼 절차가 비교적 명확한 기능까지 각각 Agent로 만드는 것은 과할 수 있습니다.</p>
<p>이런 영역은:</p>
<pre><code class="language-text">SKILL.md
+
MCP Tools</code></pre>
<p>정도로도 충분히 구현할 수 있습니다.</p>
<p>반대로:</p>
<pre><code class="language-text">Incident Response

Research

Architecture Investigation</code></pre>
<p>처럼</p>
<pre><code class="language-text">탐색
 ↓
가설
 ↓
검증
 ↓
재계획</code></pre>
<p>이 반복되는 작업은 별도의 Agent가 자연스럽습니다.</p>
<p>Microsoft의 사례에서도 같은 결론이 나옵니다.</p>
<p>일부 Specialist Agent를 Skill + MCP로 바꾸면서 Model Call은 줄었지만 Token 사용량까지 자동으로 줄지는 않았고, Research처럼 독립성이 필요한 기능은 계속 Agent로 유지했습니다.</p>
<p>결국 기준은 간단합니다.</p>
<p><strong>정해진 절차와 명확한 Tool이 있다면 Skill.</strong></p>
<p><strong>탐색하고 가설을 세우고 다시 판단해야 한다면 Agent.</strong></p>
<p>그리고 Multi-Agent Architecture를 설계할 때는 Agent를 하나 더 만들기 전에 한 번쯤 물어볼 필요가 있습니다.</p>
<p><strong>이 기능에 정말 또 하나의 LLM이 필요한가?</strong></p>
<hr>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>Microsoft Agent Framework — From Specialist Agents to Distributed Skills over MCP</strong><br>Specialist Agent 구조를 Skill + MCP Tool 구조로 변경하고 Model Call, Latency, Token 사용량을 직접 비교한 Microsoft 공식 사례입니다.<br><a href="https://devblogs.microsoft.com/agent-framework/from-specialist-agents-to-distributed-skills-over-mcp/">공식 글 보기</a></p>
</li>
<li><p><strong>Microsoft Agent Framework — Discover Agent Skills from MCP servers in .NET</strong><br>MCP Server에서 Skill을 중앙 배포하고, Agent가 필요한 Skill을 On-demand로 가져오는 구조와 Progressive Disclosure 방식을 확인할 수 있습니다.<br><a href="https://devblogs.microsoft.com/agent-framework/discover-agent-skills-from-mcp-servers-in-net/">공식 글 보기</a></p>
</li>
<li><p><strong>Microsoft Agent Framework — Give Your Agents Domain Expertise with Agent Skills</strong><br><code>SKILL.md</code>를 중심으로 Domain Instruction, Reference, Script 등을 Agent에 필요할 때만 제공하는 기본 Agent Skills 구조를 설명합니다.<br><a href="https://devblogs.microsoft.com/agent-framework/give-your-agents-domain-expertise-with-agent-skills-in-microsoft-agent-framework/">공식 글 보기</a></p>
</li>
<li><p><strong>Microsoft Agent Framework — Agent Skills for .NET Is Now Released</strong><br>Agent Skills for .NET의 Stable API와 Production 환경에서 Skill을 재사용·배포하는 방식을 확인할 수 있습니다.<br><a href="https://devblogs.microsoft.com/agent-framework/agent-skills-for-net-is-now-released/">공식 글 보기</a></p>
</li>
</ul>
<p><strong>Microsoft 공식 사례 기준으로 보면</strong>, 이번 Architecture 변경의 핵심은 Domain Service를 합치는 것이 아닙니다. Service와 Data, Deployment Boundary는 그대로 유지하고 Specialist가 갖고 있던 별도 Model Loop만 제거한 뒤, Domain Instruction은 Skill로, 실행 기능은 MCP Tool로 제공했습니다.</p>
<p>같은 질문을 비교한 세 번의 실행에서 A2A Specialist 방식은 6회·6회·7회의 Model Call이 발생했고 Skill + MCP 방식은 모두 3회였습니다. 반면 전체 Token 사용량은 Skill 방식이 13,533개로 A2A의 11,134개보다 약 22% 많았습니다. Microsoft 역시 이 결과를 통제된 성능 비교로 보지 말아야 한다고 명시하고 있습니다.</p>
<p>또한 Research Agent처럼 독립적인 탐색, 긴 Workflow, 별도 Context나 Specialized Model이 필요한 Component는 Agent로 유지했습니다. 실제 Production Architecture 역시 <strong>Agent 또는 Skill 중 하나를 고르는 구조보다, 둘을 역할에 따라 함께 사용하는 Hybrid 형태</strong>가 더 현실적입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift 6.4, 빌드와 디버깅이 모듈 중심으로 바뀐다]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609151</link>
            <guid>https://velog.io/@kyu_ios_dev/2609151</guid>
            <pubDate>Tue, 15 Sep 2026 09:29:20 GMT</pubDate>
            <description><![CDATA[<h3 id="swift-64-빌드와-디버깅이-모듈-중심으로-바뀐다">Swift 6.4, 빌드와 디버깅이 모듈 중심으로 바뀐다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/679e9762-8b68-4384-bcc4-5b12731e0c3e/image.png" alt=""></p>
<h2 id="lldb부터-dsym-bridging-header-swift-build까지-한-번에-정리">LLDB부터 dSYM, Bridging Header, Swift Build까지 한 번에 정리</h2>
<p>Swift 6.4에서 꽤 큰 변화가 하나 들어옵니다.</p>
<p>새로운 문법이나 SwiftUI API가 아니라 <strong>Compiler, Build System, LLDB가 Swift Module을 다루는 방식</strong>입니다.</p>
<p>Swift.org가 9월 11일 공개한 내용을 보면 Swift 6.3부터 진행되던 Explicit Module Tracking이 Swift 6.4에서 Debugging까지 본격적으로 연결됩니다.</p>
<p>결과적으로 대부분의 Xcode와 SwiftPM 프로젝트에서는 별다른 코드 변경 없이</p>
<ul>
<li>LLDB의 Module Lookup 안정성 개선</li>
<li>일부 Debugging 지연 감소</li>
<li>Bridging Header Import 속도 개선</li>
<li>dSYM 크기 감소</li>
<li>Build System의 Module 처리 단순화</li>
</ul>
<p>효과를 받을 수 있습니다.</p>
<p>겉으로는 LLDB 개선처럼 보이지만 조금 더 넓게 보면 최근 Swift Toolchain이 움직이는 방향이 보입니다.</p>
<pre><code class="language-text">Implicit Dependency
        ↓
Explicit Module
        ↓
Precise Dependency Graph
        ↓
Compiler
Build System
Debugger</code></pre>
<p>각 도구가 Module을 제각각 다시 찾는 구조에서, <strong>Build할 때 만들어진 정확한 Module Dependency를 공유하는 구조</strong>로 옮겨가고 있습니다.</p>
<hr>
<h1 id="1-lldb에서-po가-유난히-느릴-때가-있었던-이유">1. LLDB에서 <code>po</code>가 유난히 느릴 때가 있었던 이유</h1>
<p>Breakpoint에서 단순한 Local Variable을 확인하는 작업은 비교적 간단합니다.</p>
<pre><code class="language-lldb">p user</code></pre>
<p>이 경우 LLDB는 Debug Info와 Reflection Metadata를 이용해서 변수의 위치와 타입을 알아낼 수 있습니다.</p>
<p>하지만 다음은 조금 다릅니다.</p>
<pre><code class="language-lldb">p user.displayName</code></pre>
<p><code>displayName</code>이 Computed Property라면 실제 Function Call이 필요합니다.</p>
<p>LLDB는 내부 Swift Compiler를 이용해 Expression을 JIT Compile하고 실행합니다.</p>
<p>개념적으로는 이런 작업입니다.</p>
<pre><code class="language-swift">import MyFeature

func lldb_expr(...) {
    user.displayName
}</code></pre>
<p>문제는 여기서 발생합니다.</p>
<p>LLDB가 정확한 <code>MyFeature.swiftmodule</code>을 찾아야 하기 때문입니다.</p>
<p>기존에는 Debug Info가 사실상</p>
<pre><code class="language-text">Module Name = MyFeature</code></pre>
<p>정도만 가지고 있는 경우가 있었습니다.</p>
<p>그러면 LLDB는 Module 이름을 기준으로 적절한 파일을 다시 찾아야 합니다.</p>
<p>대형 프로젝트에서는 이것이 생각보다 단순하지 않습니다.</p>
<pre><code class="language-text">MyFeature.swiftmodule

├─ Debug
├─ Release
├─ macOS
├─ Mac Catalyst
├─ Private Module
└─ Public Interface</code></pre>
<p>같은 이름의 서로 다른 Module Variant가 존재할 수 있기 때문입니다.</p>
<hr>
<h1 id="2-기존에는-module-이름을-찾고-없으면-다시-compile하기도-했다">2. 기존에는 Module 이름을 찾고, 없으면 다시 Compile하기도 했다</h1>
<p>과거 LLDB의 Module Import 흐름을 단순화하면 이렇습니다.</p>
<pre><code class="language-text">Breakpoint

↓

현재 Module 이름 확인

↓

Module Cache 검색

↓

정확한 Module이 없으면

↓

Implicit Module Import

↓

Dependency 재Compile 가능</code></pre>
<p>Cold Module Cache에서는 이 비용이 특히 커질 수 있습니다.</p>
<p>그래서 첫 <code>po</code>나 Expression Evaluation이 유난히 느린 경험이 생기기도 했습니다.</p>
<p>특히</p>
<ul>
<li>대형 프로젝트</li>
<li>Objective-C + Swift 혼합 프로젝트</li>
<li>Bridging Header가 큰 프로젝트</li>
<li>SDK Module Dependency가 많은 프로젝트</li>
</ul>
<p>에서 체감될 수 있었습니다.</p>
<p>Swift 6.4가 해결하려는 핵심 문제는 바로 이것입니다.</p>
<p><strong>Module을 이름으로 다시 찾지 말고 Build할 때 사용한 정확한 Module을 기억하자.</strong></p>
<hr>
<h1 id="3-시작점은-explicit-modules다">3. 시작점은 Explicit Modules다</h1>
<p>이 변화는 Swift 6.4에서 갑자기 시작된 것은 아닙니다.</p>
<p>Xcode는 이미 Xcode 16부터 <strong>Explicit Module Dependency</strong>를 적극적으로 사용하고 있습니다.</p>
<p>기존 방식에서는 Source를 Compile하다 필요한 Module을 Compiler가 발견하면 Module Cache에서 찾거나 그 자리에서 Build할 수 있었습니다.</p>
<pre><code class="language-text">Source Compile
     ↓
Import 발견
     ↓
Module 필요
     ↓
Module Cache 검색
     ↓
없으면 Compile</code></pre>
<p>Explicit Module 방식에서는 Build System이 먼저 Dependency를 Scan합니다.</p>
<pre><code class="language-text">Dependency Scan
      ↓
┌───────────────┐
│ Foundation    │
│ MyDomain      │
│ MyNetwork     │
│ FeatureA      │
└───────────────┘
      ↓
Module Build
      ↓
Source Compile</code></pre>
<p>Module Dependency가 Build Graph에 명시적으로 나타납니다.</p>
<p>그러면 Build System은 어떤 Module을 먼저 만들어야 하는지 정확하게 알 수 있습니다.</p>
<p>병렬 Build도 더 효율적으로 Scheduling할 수 있고, Module Build가 실패했을 때 원인도 더 명확하게 확인할 수 있습니다.</p>
<hr>
<h1 id="4-swift-63부터-swift-module끼리-dependency를-직접-기록한다">4. Swift 6.3부터 Swift Module끼리 Dependency를 직접 기록한다</h1>
<p>Explicit Swift Module은 예전부터 Clang Module Dependency를 알고 있었습니다.</p>
<p>하지만 Swift Module끼리의 Dependency Tracking은 충분하지 않았습니다.</p>
<p>Swift 6.3부터 이 부분이 달라졌습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">FeatureModule
     ↓
DomainModule
     ↓
NetworkModule
     ↓
Foundation</code></pre>
<p>구조가 있다면 <code>FeatureModule.swiftmodule</code>이 자신이 어떤 Swift Module에 의존했는지 명시적으로 기록할 수 있습니다.</p>
<p>따라서 LLDB가 <code>FeatureModule</code>을 가져오면 그다음 Dependency를 이름으로 다시 찾아다닐 필요가 줄어듭니다.</p>
<pre><code class="language-text">FeatureModule

→ /path/DomainModule.swiftmodule

→ /path/NetworkModule.swiftmodule</code></pre>
<p>정확한 Module Graph를 따라갈 수 있습니다.</p>
<hr>
<h1 id="5--debug-module-path가-중요한-이유">5. <code>-debug-module-path</code>가 중요한 이유</h1>
<p>LLDB가 Dependency를 정확하게 알고 있어도 시작점이 필요합니다.</p>
<p>Breakpoint가 걸린 Object File이</p>
<blockquote>
<p>어떤 Swift Module에서 만들어진 것인가?</p>
</blockquote>
<p>를 알아야 합니다.</p>
<p>Swift 6.3부터 Compiler는 이를 Debug Info에 저장할 수 있습니다.</p>
<p>이때 사용되는 것이</p>
<pre><code class="language-text">-debug-module-path</code></pre>
<p>입니다.</p>
<p>개념적으로는</p>
<pre><code class="language-text">Foo.o

→ Foo.swiftmodule의 정확한 위치</code></pre>
<p>를 Debug Info에 기록하는 것입니다.</p>
<p>Xcode나 SwiftPM을 사용한다면 직접 신경 쓸 필요가 없습니다.</p>
<p>Swift Driver가 자동으로 처리합니다.</p>
<p>반면</p>
<pre><code class="language-text">Bazel
Buck
CMake
Custom Build System</code></pre>
<p>처럼 Swift Frontend를 직접 호출하는 Build System이라면 이 변화가 중요합니다.</p>
<hr>
<h1 id="6-swift-64에서는-modulewrap과-add_ast_path가-사실상-사라진다">6. Swift 6.4에서는 <code>modulewrap</code>과 <code>add_ast_path</code>가 사실상 사라진다</h1>
<p>기존 Swift Debugging에는 Module을 Binary나 dSYM으로 전달하기 위한 별도의 과정이 있었습니다.</p>
<p>Darwin에서는 Linker에</p>
<pre><code class="language-text">-add_ast_path</code></pre>
<p>를 넘겼습니다.</p>
<p>Linux나 Windows에서는</p>
<pre><code class="language-text">-modulewrap</code></pre>
<p>을 사용했습니다.</p>
<p>예를 들어 Linux에서는</p>
<pre><code class="language-text">Foo.swiftmodule
      ↓
-modulewrap
      ↓
Foo.swiftmodule.o
      ↓
Link</code></pre>
<p>방식으로 Swift Module 자체를 Object File에 집어넣었습니다.</p>
<p>Swift 6.4에서는 Precise Module Tracking 덕분에 이런 과정이 필요 없어집니다.</p>
<p>핵심 변화는 간단합니다.</p>
<pre><code class="language-text">기존

-modulewrap
-add_ast_path</code></pre>
<p>에서</p>
<pre><code class="language-text">Swift 6.4

-debug-module-path</code></pre>
<p>중심으로 바뀝니다.</p>
<p>Xcode나 SwiftPM 사용자는 대부분 자동으로 적용됩니다.</p>
<p>하지만 Bazel이나 자체 Build Infrastructure를 운영한다면 Build Rule을 확인할 필요가 있습니다.</p>
<hr>
<h1 id="7-dsym에서-swift-module도-빠진다">7. dSYM에서 Swift Module도 빠진다</h1>
<p>이번 변화에서 가장 눈에 띄는 부분 중 하나입니다.</p>
<p>기존 dSYM 안에는 Binary Swift Module이 포함될 수 있었습니다.</p>
<pre><code class="language-text">MyApp.dSYM

├─ DWARF
├─ Debug Info
└─ Swift Modules</code></pre>
<p>Swift 6.4부터 <code>dsymutil</code>은 Binary Swift Module을 더 이상 dSYM에 포함하지 않습니다.</p>
<pre><code class="language-text">MyApp.dSYM

├─ DWARF
└─ Debug Info</code></pre>
<p>그 결과 dSYM 크기가 줄어듭니다.</p>
<p>Swift.org에서는 Windows/Linux Binary와 Darwin의 dSYM 모두 <strong>크기가 크게 줄어들 수 있다</strong>고 설명하고 있습니다.</p>
<hr>
<h1 id="8-그런데-swift-module이-없으면-po는-어떻게-동작할까">8. 그런데 Swift Module이 없으면 <code>po</code>는 어떻게 동작할까</h1>
<p>여기서 자연스럽게 궁금해집니다.</p>
<pre><code class="language-text">Swift Module을 dSYM에서 뺐는데
Debugger가 Type을 어떻게 알지?</code></pre>
<p>Swift 5.6 이후 LLDB는 Local Variable의 타입과 Object Description을 확인하는 데 필요한 정보를 Binary의 <strong>Reflection Metadata</strong>에서 읽을 수 있습니다.</p>
<p>따라서 이런 작업은 계속 가능합니다.</p>
<pre><code class="language-lldb">po user</code></pre>
<p>Binary Swift Module이 필요한 것은 조금 더 복잡한 Expression입니다.</p>
<p>예를 들어</p>
<pre><code class="language-lldb">p user.computedProperty</code></pre>
<p>또는 Function Call처럼 실제 Compile이 필요한 Expression입니다.</p>
<p>이 경우 LLDB는 Module을 원래 Build 위치에서 찾습니다.</p>
<p>새로운 Precise Module Tracking 덕분에 예전처럼 이름으로 추측하는 것이 아니라 정확한 Module Path를 따라갈 수 있습니다.</p>
<hr>
<h1 id="9-dsym에-binary-module을-보관하지-않는-게-오히려-자연스럽다">9. dSYM에 Binary Module을 보관하지 않는 게 오히려 자연스럽다</h1>
<p>Binary Swift Module에는 특징이 하나 있습니다.</p>
<p><strong>정확히 같은 Compiler Toolchain에 종속됩니다.</strong></p>
<p>다른 Swift Compiler Version에서 만들어진 Binary Module을 그대로 읽을 수 있다고 보장할 수 없습니다.</p>
<p>반면 dSYM은 Crash Symbolication 등을 위해 장기간 보관하는 Artifact입니다.</p>
<pre><code class="language-text">App Release
   ↓
dSYM 보관
   ↓
6개월 후 Crash 분석</code></pre>
<p>이런 용도입니다.</p>
<p>따라서 Toolchain Version에 강하게 종속되는 Binary Swift Module을 장기 보관용 dSYM 안에 넣는 구조 자체가 조금 어색했습니다.</p>
<p>Swift 6.4에서는 이 역할을 분리합니다.</p>
<pre><code class="language-text">dSYM
→ Long-term Debug Info

Swift Module
→ Build Artifact</code></pre>
<p>Toolchain Architecture 측면에서도 더 깔끔한 구조입니다.</p>
<hr>
<h1 id="10-bridging-header도-드디어-빨라진다">10. Bridging Header도 드디어 빨라진다</h1>
<p>오래된 iOS 프로젝트라면 이번 변화에서 가장 체감할 부분일 수 있습니다.</p>
<p>Swift와 Objective-C가 섞여 있는 프로젝트에서는 Bridging Header가 흔합니다.</p>
<pre><code class="language-text">MyApp-Bridging-Header.h</code></pre>
<p>Swift 6.3까지 LLDB는 Expression Evaluation 과정에서 Bridging Header를 다시 Source부터 Compile할 수 있었습니다.</p>
<pre><code class="language-text">LLDB

↓

Bridging Header

↓

Header Parsing

↓

Clang Compile

↓

Module Import</code></pre>
<p>Header가 크거나 Objective-C Dependency가 많으면 첫 Debug Expression이 느려질 수 있습니다.</p>
<p>Swift 6.4에서는 Explicit Module 정보를 이용해서 <strong>Precompiled Bridging Header와 Dependency를 직접 Import</strong>할 수 있습니다.</p>
<pre><code class="language-text">LLDB
 ↓
Precompiled Bridging Header
 ↓
Explicit Module Dependencies</code></pre>
<p>Fully Modularized Project에 가까운 Debugging 성능을 얻는 것이 목표입니다.</p>
<p>Obj-C와 Swift가 오래 공존한 대형 iOS 프로젝트에서는 상당히 반가운 변화입니다.</p>
<hr>
<h1 id="11-결국-compiler와-debugger가-같은-module-graph를-보게-된다">11. 결국 Compiler와 Debugger가 같은 Module Graph를 보게 된다</h1>
<p>여기까지 정리하면 이번 변화의 핵심이 보입니다.</p>
<p>예전에는 각 단계가 Module을 조금씩 다르게 찾았습니다.</p>
<pre><code class="language-text">Compiler
   ↓
Module Cache

Build System
   ↓
Dependency Scan

Linker
   ↓
add_ast_path

dSYM
   ↓
Swift AST

LLDB
   ↓
Module Name Lookup</code></pre>
<p>점점 이 구조가 단순해지고 있습니다.</p>
<pre><code class="language-text">        Explicit Module Graph
                 │
       ┌─────────┼─────────┐
       │         │         │
    Compiler   Build      LLDB
              System</code></pre>
<p><strong>Build할 때 결정된 Module Graph를 Toolchain 전체가 공유하는 방향</strong>입니다.</p>
<p>이번 Swift 6.4 변화에서 가장 중요한 부분입니다.</p>
<hr>
<h1 id="12-swift가-최근-모듈-중심으로-움직이는-흐름은-이것만이-아니다">12. Swift가 최근 모듈 중심으로 움직이는 흐름은 이것만이 아니다</h1>
<p>여기부터는 Swift 6.4 Debugging 자체와는 조금 다른 이야기지만 같은 방향에서 볼 만한 변화가 있습니다.</p>
<p>Swift 생태계에서는 최근 여러 기능을 보다 명확한 Module과 Toolchain Layer로 정리하는 작업이 계속되고 있습니다.</p>
<p>대표적인 것이 <code>FilePath</code>입니다.</p>
<hr>
<h1 id="13-filepath가-swift-system에서-swift-standard-library로-올라온다">13. <code>FilePath</code>가 swift-system에서 Swift Standard Library로 올라온다</h1>
<p>그동안 Swift에서 File System Path를 제대로 표현하려면 <code>swift-system</code>의 <code>FilePath</code>를 사용하는 방법이 있었습니다.</p>
<pre><code class="language-swift">import SystemPackage

let path: FilePath</code></pre>
<p>문제는 <code>FilePath</code>가 외부 Package에 있다는 것입니다.</p>
<p>Foundation이나 Swift Runtime처럼 더 낮은 계층에서는 외부 Package를 쉽게 Dependency로 사용할 수 없습니다.</p>
<p>SE-0529에서는 <code>FilePath</code>를 Swift Standard Library의 <strong><code>Swift</code> Module</strong>로 이동하는 방향이 승인됐습니다.</p>
<p>앞으로는 개념적으로</p>
<pre><code class="language-swift">let path: FilePath = &quot;/Users/dev/project&quot;</code></pre>
<p>처럼 Swift의 기본 Currency Type으로 사용할 수 있게 됩니다.</p>
<p>구조도</p>
<pre><code class="language-text">swift-system

FilePath</code></pre>
<p>에서</p>
<pre><code class="language-text">Swift Standard Library

Swift.FilePath</code></pre>
<p>로 이동합니다.</p>
<hr>
<h1 id="14-왜-filepath를-swift-module에-넣는-게-중요할까">14. 왜 FilePath를 <code>Swift</code> Module에 넣는 게 중요할까</h1>
<p><code>String</code>이 Path를 표현하는 데 항상 좋은 타입은 아닙니다.</p>
<pre><code class="language-swift">let path: String</code></pre>
<p>은 이것이</p>
<ul>
<li>URL인지</li>
<li>파일 경로인지</li>
<li>일반 Text인지</li>
</ul>
<p>타입만 보고 구분할 수 없습니다.</p>
<p><code>FilePath</code>는 File System Path 자체를 타입으로 표현합니다.</p>
<p>더 중요한 이유는 Dependency Layer입니다.</p>
<pre><code class="language-text">Swift Runtime
Foundation
Swift Testing
Build Tools</code></pre>
<p>같은 Toolchain 구성요소가 공통으로 File Path를 다뤄야 합니다.</p>
<p><code>FilePath</code>가 외부 Package에 있으면 이런 Core Library가 사용하기 어렵습니다.</p>
<p>Standard Library로 올라오면 공통 Currency Type으로 사용할 수 있습니다.</p>
<hr>
<h1 id="15-foundation도-이미-하나의-거대한-framework에서-나뉘고-있다">15. Foundation도 이미 하나의 거대한 Framework에서 나뉘고 있다</h1>
<p>Foundation도 같은 맥락에서 볼 만합니다.</p>
<p>Swift 6에서는 주요 Foundation API의 Swift 구현이 여러 플랫폼에서 통합됐습니다.</p>
<p>그리고 전체 Foundation이 필요하지 않은 경우를 위해</p>
<pre><code class="language-swift">import FoundationEssentials</code></pre>
<p>도 사용할 수 있습니다.</p>
<p><code>FoundationEssentials</code>는 Internationalization과 Localization Data 같은 무거운 부분을 제외하고 핵심 Foundation 기능을 제공합니다.</p>
<p>개념적으로는</p>
<pre><code class="language-text">Foundation

모든 기능</code></pre>
<p>하나만 사용하는 구조에서</p>
<pre><code class="language-text">Foundation

├─ FoundationEssentials
├─ Internationalization
└─ 추가 Foundation 기능</code></pre>
<p>처럼 필요한 Layer를 더 명확하게 가져갈 수 있는 방향입니다.</p>
<p>특히 Server Swift나 Embedded 환경에서는 Binary Size와 Dependency가 중요한 만큼 의미가 큽니다.</p>
<hr>
<h1 id="16-swiftpm도-swift-build로-통합되는-중이다">16. SwiftPM도 Swift Build로 통합되는 중이다</h1>
<p>Build System 쪽에서도 비슷한 변화가 진행되고 있습니다.</p>
<p>Swift 6.3에서는 Swift Package Manager에서 <strong>Swift Build Integration Preview</strong>를 사용할 수 있게 됐습니다.</p>
<p>원래 SwiftPM과 Xcode는 완전히 같은 Build Engine을 사용하지 않았습니다.</p>
<p>Swift 프로젝트가 커질수록</p>
<pre><code class="language-text">Xcode Build

SwiftPM Build

CI Build</code></pre>
<p>환경 차이가 문제가 될 수 있습니다.</p>
<p>Swift 프로젝트는 현재 Swift Build를 공통 Build Infrastructure로 가져오는 방향으로 움직이고 있습니다.</p>
<p>개념적으로는</p>
<pre><code class="language-text">Xcode
   ↓
Swift Build</code></pre>
<p>그리고</p>
<pre><code class="language-text">SwiftPM
   ↓
Swift Build</code></pre>
<p>구조에 가까워집니다.</p>
<p>Swift main branch 역시 Swift Build를 기본 Build System으로 사용하는 방향으로 전환됐습니다.</p>
<hr>
<h1 id="17-결국-하나의-dependency-graph로-수렴하고-있다">17. 결국 하나의 Dependency Graph로 수렴하고 있다</h1>
<p>이 변화들을 하나씩 보면 서로 다른 기능처럼 보입니다.</p>
<pre><code class="language-text">Explicit Modules

LLDB Module Tracking

Smaller dSYM

Bridging Header 개선

Swift Build

FilePath

FoundationEssentials</code></pre>
<p>하지만 Toolchain 관점에서는 공통된 방향이 있습니다.</p>
<p>과거에는</p>
<pre><code class="language-text">Compiler

Build System

Package Manager

Debugger

Core Libraries</code></pre>
<p>각 영역이 어느 정도 독립적으로 Dependency를 관리했습니다.</p>
<p>앞으로는</p>
<pre><code class="language-text">        Module / Dependency Graph
                  │
     ┌────────────┼────────────┐
     │            │            │
 Compiler     Build System    LLDB
     │            │            │
     └────────────┼────────────┘
                  │
               SwiftPM</code></pre>
<p>처럼 명시적인 Dependency를 공유하는 방향으로 움직이고 있습니다.</p>
<p>Swift 6.4의 LLDB 변화가 중요한 이유도 여기에 있습니다.</p>
<p>단순한 Debugger 최적화가 아니라 <strong>Toolchain 전체가 Explicit Module Graph를 신뢰하기 시작했다는 신호</strong>이기 때문입니다.</p>
<hr>
<h1 id="18-일반적인-xcode-프로젝트에서는-무엇을-해야-할까">18. 일반적인 Xcode 프로젝트에서는 무엇을 해야 할까</h1>
<p>대부분은 아무것도 하지 않아도 됩니다.</p>
<p>Xcode와 SwiftPM을 사용하고 있다면 Swift Driver와 Build System이 대부분 자동으로 처리합니다.</p>
<p>오히려 확인해볼 부분은 오래된 프로젝트입니다.</p>
<pre><code class="language-text">Objective-C + Swift 혼합

대형 Bridging Header

Custom Build Script

Static Library

Bazel / Buck / CMake

오래된 Module Setting</code></pre>
<p>같은 환경입니다.</p>
<p>특히 자체 Build System을 운영한다면</p>
<pre><code class="language-text">-modulewrap

-add_ast_path</code></pre>
<p>를 사용하는 Build Rule이 있는지 확인할 필요가 있습니다.</p>
<p>Swift 6.4에서는 이런 처리를 제거하고 <code>-debug-module-path</code> 방식으로 이동할 수 있습니다.</p>
<hr>
<h1 id="19-ios-프로젝트에서-확인해볼-것">19. iOS 프로젝트에서 확인해볼 것</h1>
<p>Swift 6.4 전환을 준비한다면 다음 정도는 확인할 만합니다.</p>
<pre><code class="language-text">□ Bridging Header가 지나치게 커져 있지 않은가?

□ Objective-C Header가 Module화되지 않은 채 남아 있지 않은가?

□ Static Library Debugging에서 별도 Swift Module 처리를 하고 있는가?

□ Bazel/Buck/CMake Build Rule에 -modulewrap이 남아 있는가?

□ Linker Option에 -add_ast_path를 직접 추가하고 있는가?

□ CI에서 dSYM 크기나 Upload 시간이 큰 편인가?

□ 첫 LLDB Expression Evaluation이 유난히 느린 프로젝트인가?

□ Explicit Modules가 비활성화된 오래된 Target이 있는가?</code></pre>
<p>일반적인 앱에서는 코드 Migration보다 <strong>Build Infrastructure 점검</strong>에 가까운 변화입니다.</p>
<hr>
<h1 id="20-swift-64의-변화가-중요한-이유">20. Swift 6.4의 변화가 중요한 이유</h1>
<p>Swift 개발에서 Module은 예전부터 존재했습니다.</p>
<p>새로운 개념은 아닙니다.</p>
<p>달라지는 것은 Module이 Toolchain에서 갖는 역할입니다.</p>
<p>예전에는</p>
<pre><code class="language-text">import Foundation</code></pre>
<p>처럼 Source Code의 Namespace와 Dependency 정도로 생각하기 쉬웠습니다.</p>
<p>지금은</p>
<pre><code class="language-text">Compilation Unit

Dependency Graph

Build Scheduling

Caching

Debugging

Symbol Resolution</code></pre>
<p>까지 Module 정보가 관여합니다.</p>
<p>즉 Module은 단순한 코드 분리 단위가 아니라 <strong>Swift Toolchain을 연결하는 공통 단위</strong>가 되고 있습니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>Swift 6.4에서 가장 눈에 띄는 변화 중 하나는 Debugger가 Module을 찾는 방식입니다.</p>
<p>예전에는 LLDB가 Module 이름을 보고 적절한 Module을 찾아야 했습니다.</p>
<p>이제는 Build할 때 사용한 정확한 Module Path와 Dependency Graph를 따라갈 수 있습니다.</p>
<p>그 결과</p>
<pre><code class="language-text">LLDB Import 안정성 ↑

Bridging Header Import 속도 ↑

dSYM 크기 ↓

불필요한 Module Compile ↓

Custom Build 단계 ↓</code></pre>
<p>같은 변화가 가능해집니다.</p>
<p>그리고 이 흐름을 조금 넓게 보면 최근 Swift Toolchain의 방향도 보입니다.</p>
<pre><code class="language-text">Implicit
    ↓
Explicit

Name Lookup
    ↓
Precise Path

Hidden Dependency
    ↓
Dependency Graph

Tool별 Build 정보
    ↓
공유되는 Module 정보</code></pre>
<p><code>FilePath</code>가 Standard Library로 이동하고, Foundation이 세분화되고, SwiftPM이 Swift Build를 받아들이는 변화까지 같은 시기에 진행되고 있습니다.</p>
<p>모두 똑같은 프로젝트는 아니지만 방향은 비슷합니다.</p>
<p><strong>Swift의 Compiler, Build System, Package Manager, Debugger가 명확한 Module과 Dependency를 중심으로 정리되고 있습니다.</strong></p>
<p>Swift 6.4의 Module Tracking은 그중에서도 일반 iOS 개발자가 직접 체감할 가능성이 높은 변화입니다.</p>
<p>새로운 문법 하나보다 눈에 덜 띌 수 있지만 대형 프로젝트에서는 Build와 Debugging 경험을 꽤 크게 바꿀 수 있는 변화입니다.</p>
<hr>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>Swift.org — Module Tracking in Swift Debug Info</strong><br>Swift 6.3부터 시작된 Precise Module Tracking과 Swift 6.4의 <code>modulewrap</code>, <code>add_ast_path</code>, dSYM, Bridging Header 변화를 설명한 공식 자료입니다.<br><a href="https://www.swift.org/blog/module-tracking-in-debug-info/?utm_source=chatgpt.com">Swift.org 공식 글 보기</a></p>
</li>
<li><p><strong>Apple Developer — Building your project with explicit module dependencies</strong><br>Xcode의 Explicit Module Dependency Scan과 Module Build Scheduling 구조를 확인할 수 있습니다.<br><a href="https://developer.apple.com/documentation/xcode/building-your-project-with-explicit-module-dependencies?utm_source=chatgpt.com">Apple Explicit Module 공식 문서</a></p>
</li>
<li><p><strong>Swift Evolution — SE-0529 Add FilePath to the Standard Library</strong><br><code>swift-system</code>의 <code>FilePath</code>를 <code>Swift</code> Module의 기본 타입으로 이동하는 배경과 Migration 방향을 확인할 수 있습니다.<br><a href="https://github.com/swiftlang/swift-evolution/blob/main/proposals/0529-filepath-in-stdlib.md?utm_source=chatgpt.com">SE-0529 공식 Proposal</a></p>
</li>
<li><p><strong>Swift.org — What&#39;s new in Swift: March 2026</strong><br>Swift 6.3의 SwiftPM + Swift Build Integration과 Build Infrastructure 통합 방향을 확인할 수 있습니다.<br><a href="https://www.swift.org/blog/whats-new-in-swift-march-2026/?utm_source=chatgpt.com">Swift Build 공식 업데이트</a></p>
</li>
<li><p><strong>Swift.org — Swift Core Libraries</strong><br>Swift Foundation의 통합 구현과 <code>FoundationEssentials</code>의 역할을 확인할 수 있습니다.<br><a href="https://www.swift.org/documentation/core-libraries/?utm_source=chatgpt.com">Swift Core Libraries 공식 문서</a></p>
</li>
</ul>
<p><strong>Swift 공식 자료 기준으로 보면</strong>, Swift 6.4의 핵심 변화는 LLDB가 Swift Module을 이름으로 추측해서 찾는 대신 Build 시점에 기록된 정확한 Module Path와 Explicit Dependency를 사용할 수 있게 되는 것입니다. 이에 따라 <code>-modulewrap</code>과 <code>-add_ast_path</code>를 제거할 수 있고, Binary Swift Module을 dSYM에 포함하지 않아도 되면서 Debug Artifact 크기도 줄어듭니다.</p>
<p>또 Swift 6.4에서는 LLDB가 Bridging Header를 Source부터 다시 Compile하는 대신 Precompiled Bridging Header와 Explicit Module Dependency를 직접 사용할 수 있게 됩니다. 일반적인 Xcode/SwiftPM 프로젝트는 별도 대응이 필요하지 않지만 Bazel·Buck·CMake 등 Custom Build System은 <code>-debug-module-path</code> 처리 여부를 확인할 필요가 있습니다.</p>
<p>현실적으로 이번 변화를 <strong>“새로운 Module 기능”이라기보다 <code>Compiler → Build System → LLDB</code>가 하나의 Explicit Module Graph를 공유하도록 정리되는 변화</strong>로 보는 것이 가장 정확합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[기술부채도 이제 AI에게 티켓처럼 던진다]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609124</link>
            <guid>https://velog.io/@kyu_ios_dev/2609124</guid>
            <pubDate>Sat, 12 Sep 2026 09:30:51 GMT</pubDate>
            <description><![CDATA[<h3 id="기술부채도-이제-ai에게-티켓처럼-던진다">기술부채도 이제 AI에게 티켓처럼 던진다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/faa48c18-c83d-43cd-9e29-fc3015f74014/image.png" alt=""></p>
<h2 id="github-agentic-autofix가-바꾸는-기술부채-처리-방식">GitHub Agentic Autofix가 바꾸는 기술부채 처리 방식</h2>
<p>프로젝트를 오래 운영하다 보면 이상하게 없어지지 않는 목록이 하나 있습니다.</p>
<p><strong>Code Quality backlog입니다.</strong></p>
<p>당장 장애를 만드는 버그는 아니지만 언젠가는 고쳐야 하는 코드들입니다.</p>
<pre><code class="language-text">중복 코드
불필요한 조건문
사용되지 않는 표현식
복잡도가 높은 함수
유지보수성이 떨어지는 코드
신뢰성 문제</code></pre>
<p>CodeQL이나 각종 정적 분석 도구가 계속 문제를 찾아내지만 실제 프로젝트에서는 이런 finding이 빠르게 쌓입니다.</p>
<p>이유는 간단합니다.</p>
<p>급하지 않기 때문입니다.</p>
<pre><code class="language-text">신규 기능
   ↓
버그 수정
   ↓
긴급 배포
   ↓
성능 문제
   ↓
기술부채</code></pre>
<p>항상 기술부채가 마지막으로 밀립니다.</p>
<p>그런데 GitHub가 9월 9일 공개한 <strong>Agentic Autofix</strong>는 이 오래된 흐름을 조금 다른 방식으로 바꾸기 시작했습니다.</p>
<p>이제 Code Quality 화면에서 최대 <strong>25개의 finding을 한꺼번에 선택해서 Copilot에게 작업으로 넘길 수 있습니다.</strong></p>
<p>그리고 Copilot은 단순히 수정 코드를 제안하는 데서 끝나지 않습니다.</p>
<pre><code class="language-text">Finding 선택
     ↓
Assign to Copilot
     ↓
Branch 생성
     ↓
코드 탐색
     ↓
수정
     ↓
검증
     ↓
Pull Request 생성
     ↓
Developer Review</code></pre>
<p>기술부채를 하나씩 직접 처리하는 것이 아니라,</p>
<p><strong>backlog 자체를 Agent의 작업 큐처럼 사용하는 방식</strong>입니다.</p>
<hr>
<h1 id="기존-autofix와-뭐가-다른가">기존 Autofix와 뭐가 다른가</h1>
<p>GitHub에는 이미 Copilot Autofix가 있었습니다.</p>
<p>Code Quality나 Code Scanning에서 문제가 발견되면 수정안을 생성해주는 기능입니다.</p>
<p>흐름은 대략 이런 형태였습니다.</p>
<pre><code class="language-text">Finding
   ↓
Generate Fix
   ↓
Suggested Change
   ↓
Developer 확인
   ↓
Commit</code></pre>
<p>개발자 입장에서는 꽤 편하지만 본질적으로는 <strong>코드 수정 제안 기능</strong>에 가깝습니다.</p>
<p>Finding 하나를 보고 수정안을 생성하고, 개발자가 그 결과를 확인해서 적용합니다.</p>
<p>이번 Agentic Autofix는 작업 단위가 조금 다릅니다.</p>
<pre><code class="language-text">Finding
   ↓
Fix suggestion</code></pre>
<p>이 아니라</p>
<pre><code class="language-text">Finding 묶음
   ↓
Agent Task</code></pre>
<p>이 됩니다.</p>
<p>GitHub Code Quality 화면에서 최대 25개의 standard finding을 선택하고 <code>Assign to Copilot</code>을 누르면 하나의 remediation 작업으로 넘길 수 있습니다.</p>
<p>예를 들어 프로젝트에 이런 finding이 있다고 해보겠습니다.</p>
<pre><code class="language-text">Overwritten property     12
Expression has no effect  8
Redundant condition       5</code></pre>
<p>총 25개를 선택해서 Agent에게 넘깁니다.</p>
<p>그다음부터는 Copilot이 작업을 진행합니다.</p>
<hr>
<h1 id="중요한-차이는-agent가-코드베이스를-본다는-것">중요한 차이는 Agent가 코드베이스를 본다는 것</h1>
<p>기존 Autofix는 문제가 발생한 코드 주변에서 수정안을 만드는 방식에 가까웠습니다.</p>
<p>Agentic Autofix는 Copilot Cloud Agent를 사용합니다.</p>
<p>따라서 필요한 경우 해당 파일 하나만 보는 것이 아니라 <strong>관련된 코드까지 탐색할 수 있습니다.</strong></p>
<p>예를 들어 이런 코드가 있다고 해보겠습니다.</p>
<pre><code class="language-swift">final class UserRepository {

    private let apiClient: APIClient

    init(apiClient: APIClient) {
        self.apiClient = apiClient
    }

    func fetchUser() async throws -&gt; User {
        let result = try await apiClient.fetchUser()
        return result
    }
}</code></pre>
<p>정적 분석에서는 단순한 코드 하나가 문제로 잡혔더라도 실제 수정에는 다른 요소가 영향을 줄 수 있습니다.</p>
<pre><code class="language-text">Protocol
Dependency
Test
Caller
Configuration</code></pre>
<p>기존의 단순 fix generator라면 finding 주변 코드만 수정하기 쉽습니다.</p>
<p>Agent는 필요하면 Repository를 탐색하면서</p>
<pre><code class="language-text">이 코드는 어디에서 호출되는가?
이 타입을 사용하는 테스트가 있는가?
수정하면 다른 코드가 깨지는가?
같은 패턴이 다른 파일에도 존재하는가?</code></pre>
<p>를 확인할 수 있습니다.</p>
<p>이 차이가 <code>Autofix</code>와 <code>Agentic Autofix</code>를 구분하는 핵심입니다.</p>
<hr>
<h1 id="수정한-다음에는-스스로-검증한다">수정한 다음에는 스스로 검증한다</h1>
<p>Agentic Autofix에서 더 중요한 부분은 <strong>Validation</strong>입니다.</p>
<p>코드 생성 AI의 가장 큰 문제는 코드를 만드는 것 자체가 아니었습니다.</p>
<p>그 코드가 정말 맞는지 확인해야 한다는 것이 문제였습니다.</p>
<p>예전 AI Coding Workflow는 흔히 이랬습니다.</p>
<pre><code class="language-text">Developer
   ↓
AI에게 수정 요청
   ↓
코드 생성
   ↓
Developer가 Build
   ↓
Error
   ↓
다시 AI</code></pre>
<p>Agentic Workflow에서는 이 반복 일부를 Agent가 가져갑니다.</p>
<pre><code class="language-text">Agent
 ↓
Analyze
 ↓
Modify
 ↓
Validate
 ↓
Problem?
 ├─ Yes → 다시 수정
 │
 └─ No → Pull Request</code></pre>
<p>GitHub의 Agentic Autofix는 변경한 내용을 검증한 뒤 Pull Request를 생성합니다.</p>
<p>Code scanning alert의 경우에는 원래 문제를 찾았던 분석을 다시 실행해서 실제로 alert가 사라졌는지 확인하는 방식도 사용됩니다.</p>
<p>즉 목표가</p>
<p><strong>“코드를 수정했다.”</strong></p>
<p>가 아니라</p>
<p><strong>“finding을 해결했다.”</strong></p>
<p>로 달라집니다.</p>
<p>이 차이는 생각보다 큽니다.</p>
<hr>
<h1 id="이제-finding-하나와-finding-25개의-workflow가-같다">이제 finding 하나와 finding 25개의 Workflow가 같다</h1>
<p>이번 변경에서 눈에 띄는 UI 변화도 있습니다.</p>
<p>기존의 개별 finding용 <code>Generate fix</code> 흐름이 <code>Assign to Copilot</code>으로 통합됐습니다.</p>
<p>따라서 하나의 finding을 처리하든 25개를 처리하든 기본 흐름은 같습니다.</p>
<pre><code class="language-text">1 Finding
    ↓
Assign to Copilot</code></pre>
<p>또는</p>
<pre><code class="language-text">25 Findings
     ↓
Assign to Copilot</code></pre>
<p>입니다.</p>
<p>이런 구조가 중요한 이유는 AI 기능을 별도의 도구처럼 사용하지 않아도 되기 때문입니다.</p>
<p>기존에는</p>
<pre><code class="language-text">Code Quality
      ↓
Finding 확인
      ↓
IDE 이동
      ↓
코드 찾기
      ↓
AI에게 설명
      ↓
수정</code></pre>
<p>과정이 필요했다면,</p>
<p>이제 Finding 자체가 Agent Task가 됩니다.</p>
<pre><code class="language-text">Code Quality Finding
        =
   Agent Ticket</code></pre>
<p>에 가까워지는 것입니다.</p>
<hr>
<h1 id="기술부채-관리에서-가장-비싼-것은-수정-코드가-아니다">기술부채 관리에서 가장 비싼 것은 수정 코드가 아니다</h1>
<p>기술부채를 직접 수정해보면 실제로 시간을 많이 쓰는 곳은 몇 줄의 코드를 변경하는 부분이 아닙니다.</p>
<p>오히려 이런 과정에서 시간이 많이 듭니다.</p>
<pre><code class="language-text">어떤 finding부터 고칠지 찾기

↓

관련 코드 확인

↓

영향 범위 파악

↓

수정

↓

테스트

↓

PR 작성

↓

리뷰</code></pre>
<p>특히 오래된 Repository에서는 첫 번째와 두 번째 단계가 훨씬 어렵습니다.</p>
<p>몇 년 전에 작성된 코드의 warning 하나를 수정하려고 파일을 열었는데,</p>
<pre><code class="language-text">왜 이렇게 작성했지?</code></pre>
<p>부터 시작하는 경우도 많습니다.</p>
<p>그리고 결국</p>
<pre><code class="language-text">나중에 하자</code></pre>
<p>가 됩니다.</p>
<p>Agentic Autofix가 줄이려는 부분은 바로 이 작업 비용입니다.</p>
<p>Developer가 직접 finding마다 Context를 다시 만드는 대신,</p>
<pre><code class="language-text">Finding
+
Repository Context
+
Analysis Result</code></pre>
<p>를 Agent에게 넘깁니다.</p>
<p>이게 반복되면 기술부채 처리 방식 자체가 달라질 수 있습니다.</p>
<hr>
<h1 id="technical-debt-backlog가-agent-queue로-바뀐다">Technical Debt Backlog가 Agent Queue로 바뀐다</h1>
<p>기존 기술부채 관리 방식은 보통 이렇습니다.</p>
<pre><code class="language-text">Static Analysis
      ↓
Finding
      ↓
Jira Ticket
      ↓
Backlog
      ↓
Sprint 여유?
      ↓
Developer Assign
      ↓
Fix</code></pre>
<p>문제는 <code>Sprint 여유?</code>에서 대부분 멈춘다는 것입니다.</p>
<p>Agent가 이 과정에 들어오면 흐름이 달라집니다.</p>
<pre><code class="language-text">Code Quality
     ↓
Finding
     ↓
Select
     ↓
Assign to Copilot
     ↓
Agent Fix
     ↓
Pull Request
     ↓
Human Review</code></pre>
<p>즉 개발자의 시작점이</p>
<pre><code class="language-text">Issue</code></pre>
<p>에서</p>
<pre><code class="language-text">Pull Request</code></pre>
<p>쪽으로 이동합니다.</p>
<p>사람이 문제를 직접 수정하는 것이 아니라,</p>
<p><strong>Agent가 만든 해결안을 검토하는 것부터 업무가 시작되는 구조</strong>입니다.</p>
<hr>
<h1 id="그렇다고-25개를-무조건-한꺼번에-넘기면-될까">그렇다고 25개를 무조건 한꺼번에 넘기면 될까</h1>
<p>여기서 실무적으로 중요한 부분이 있습니다.</p>
<p>25개를 처리할 수 있다고 해서 항상 25개를 한 번에 넘기는 것이 좋은 것은 아닙니다.</p>
<p>예를 들어 이런 두 묶음은 성격이 다릅니다.</p>
<pre><code class="language-text">Batch A

Expression has no effect
Redundant condition
Unused assignment</code></pre>
<p>서로 비교적 독립적입니다.</p>
<p>반면</p>
<pre><code class="language-text">Batch B

Authentication
Session management
Database transaction
Concurrency</code></pre>
<p>처럼 서로 다른 영역에 걸쳐 있는 finding은 하나의 PR로 묶으면 오히려 리뷰하기 어려워질 수 있습니다.</p>
<p>Agent가 많은 코드를 수정할수록 중요한 것은 결국 <strong>Reviewability</strong>입니다.</p>
<p>따라서 실제 팀에서는 finding을</p>
<pre><code class="language-text">Rule
Module
Feature
Risk</code></pre>
<p>단위로 묶는 방식이 더 현실적일 수 있습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">Networking 관련 12개</code></pre>
<p>또는</p>
<pre><code class="language-text">동일한 CodeQL Rule 20개</code></pre>
<p>처럼 만드는 방식입니다.</p>
<p>AI가 많은 코드를 수정할 수 있게 될수록 PR을 작게 유지하는 원칙은 오히려 더 중요해질 수 있습니다.</p>
<hr>
<h1 id="이제-사람의-역할은-fix보다-policy-쪽으로-이동한다">이제 사람의 역할은 Fix보다 Policy 쪽으로 이동한다</h1>
<p>Agentic Autofix가 흥미로운 이유는 단순히 개발 시간을 줄여주기 때문만은 아닙니다.</p>
<p>개발자의 역할이 조금 달라지기 때문입니다.</p>
<p>기존에는</p>
<pre><code class="language-text">Developer

Finding 확인
코드 분석
수정
테스트
PR 작성</code></pre>
<p>을 했다면 Agent가 들어온 뒤에는</p>
<pre><code class="language-text">Agent

코드 분석
수정
검증
PR 작성</code></pre>
<p>을 맡을 수 있습니다.</p>
<p>그렇다면 Developer가 더 많이 봐야 하는 것은 이런 부분입니다.</p>
<pre><code class="language-text">이 finding은 실제 문제인가?

이 수정 범위가 적절한가?

Architecture를 훼손하지 않았는가?

테스트가 충분한가?

이 PR을 Merge해도 되는가?</code></pre>
<p>즉</p>
<p><strong>Implementation</strong></p>
<p>비중이 줄고</p>
<p><strong>Review + Policy</strong></p>
<p>비중이 올라갑니다.</p>
<hr>
<h1 id="quality-gate가-더-중요해지는-이유">Quality Gate가 더 중요해지는 이유</h1>
<p>Agent가 많은 코드를 자동으로 수정하는 환경에서는 CI가 더욱 중요해집니다.</p>
<p>사람이 직접 작성한 코드라면 개발자가 어느 정도 변경 의도를 알고 있습니다.</p>
<p>하지만 Agent가 만든 PR은 다릅니다.</p>
<p>따라서 Merge 조건을 더 명확하게 만들어야 합니다.</p>
<pre><code class="language-text">Agent PR
   ↓
Build
   ↓
Unit Test
   ↓
Integration Test
   ↓
CodeQL
   ↓
Code Coverage
   ↓
Review
   ↓
Merge</code></pre>
<p>앞으로 좋은 Agent Workflow를 만드는 핵심은 Agent에게</p>
<p><strong>“코드를 잘 만들어.”</strong></p>
<p>라고 하는 것이 아니라</p>
<p><strong>“이 조건을 통과해야 작업이 완료된 것이다.”</strong></p>
<p>라고 정의하는 데 있을 가능성이 큽니다.</p>
<p>AI Coding에서도 결국 중요한 것은 <strong>Done의 정의</strong>입니다.</p>
<hr>
<h1 id="agent가-기술부채를-만들고-agent가-기술부채를-갚는-구조">Agent가 기술부채를 만들고 Agent가 기술부채를 갚는 구조</h1>
<p>여기서 조금 재미있는 상황도 생깁니다.</p>
<p>AI Coding Agent가 빠르게 코드를 생성하면서 개발 속도가 올라가고 있습니다.</p>
<p>하지만 코드 생산량이 늘어나면 Quality Issue도 같이 증가할 가능성이 있습니다.</p>
<pre><code class="language-text">AI Code Generation ↑
        ↓
Code Volume ↑
        ↓
Quality Finding ↑</code></pre>
<p>그러면 다시 AI가 이를 수정합니다.</p>
<pre><code class="language-text">AI가 코드 생성
      ↓
Code Quality 분석
      ↓
Finding 발생
      ↓
AI Agent가 수정</code></pre>
<p>결국 이런 Loop가 만들어질 수 있습니다.</p>
<pre><code class="language-text">          ┌─────────────┐
          │ Coding Agent│
          └──────┬──────┘
                 ↓
               Code
                 ↓
        ┌────────────────┐
        │ Quality Analysis│
        └───────┬────────┘
                ↓
             Finding
                ↓
        ┌────────────────┐
        │ Remediation Agent│
        └───────┬────────┘
                ↓
               PR</code></pre>
<p>그래서 앞으로 중요한 것은 AI가 코드를 얼마나 많이 작성하는지가 아닐 수 있습니다.</p>
<p><strong>AI가 생성한 코드를 어떤 시스템으로 통제하느냐</strong>가 더 중요해집니다.</p>
<hr>
<h1 id="지금-당장-모든-프로젝트에서-쓸-수-있는-것은-아니다">지금 당장 모든 프로젝트에서 쓸 수 있는 것은 아니다</h1>
<p>이번 기능에는 몇 가지 조건이 있습니다.</p>
<p>GitHub Code Quality가 활성화된 Repository에서 사용할 수 있고, 현재 GitHub Team과 GitHub Enterprise Cloud 환경을 대상으로 제공됩니다.</p>
<p>또 Agentic Autofix로 Copilot에게 작업을 할당하면 <strong>AI Credit을 사용합니다.</strong></p>
<p>현재 Code Quality backlog의 Agentic Autofix는 Public Preview이기 때문에 Workflow나 세부 동작은 이후 변경될 가능성도 있습니다.</p>
<p>따라서 당장 기존 정적 분석 시스템을 전부 대체한다고 보기보다는,</p>
<p><strong>GitHub가 Code Quality와 Copilot Agent를 어떤 방향으로 결합하려는지 보여주는 기능</strong></p>
<p>으로 보는 편이 맞습니다.</p>
<hr>
<h1 id="sonarqube-같은-기존-품질-도구가-없어지는-것은-아니다">SonarQube 같은 기존 품질 도구가 없어지는 것은 아니다</h1>
<p>이 기능을 보고</p>
<pre><code class="language-text">이제 SonarQube나 기존 정적 분석이 필요 없어지는 건가?</code></pre>
<p>라고 생각할 수도 있습니다.</p>
<p>하지만 역할은 다릅니다.</p>
<p>정적 분석기의 역할은 계속 중요합니다.</p>
<pre><code class="language-text">Analyzer
    ↓
Problem Detection</code></pre>
<p>Agent가 담당하는 것은 그다음입니다.</p>
<pre><code class="language-text">Problem
   ↓
Remediation</code></pre>
<p>즉 경쟁 관계보다는 이런 구조에 가깝습니다.</p>
<pre><code class="language-text">Static Analysis
CodeQL
Quality Rule
      ↓
   Finding
      ↓
AI Remediation Agent
      ↓
 Pull Request</code></pre>
<p>앞으로 중요한 변화는 <strong>Detection의 자동화보다 Remediation의 자동화</strong>일 가능성이 큽니다.</p>
<hr>
<h1 id="기술부채도-이제-사람이-직접-잡으러-다니지-않는다">기술부채도 이제 사람이 직접 잡으러 다니지 않는다</h1>
<p>지금까지 AI Coding 도구는 대부분 새 코드를 만드는 곳에 집중했습니다.</p>
<pre><code class="language-text">Feature 생성
Test 생성
Refactoring
Documentation</code></pre>
<p>하지만 실제 프로젝트에서는 새 코드를 만드는 것만큼 오래된 코드를 관리하는 일이 중요합니다.</p>
<p>이번 Agentic Autofix는 AI Agent의 역할이</p>
<pre><code class="language-text">Create Code</code></pre>
<p>에서</p>
<pre><code class="language-text">Maintain Code</code></pre>
<p>로 확장되고 있다는 점에서 의미가 있습니다.</p>
<p>그리고 이 변화가 계속된다면 기술부채 관리도 지금과 상당히 다른 모습이 될 수 있습니다.</p>
<p>예전에는 backlog를 열고 개발자가 하나씩 가져갔습니다.</p>
<p>앞으로는</p>
<pre><code class="language-text">25 Findings 선택
        ↓
Assign to Copilot
        ↓
잠시 후 Pull Request</code></pre>
<p>가 자연스러운 Workflow가 될 수도 있습니다.</p>
<p>그때 개발자가 해야 할 일은 코드를 한 줄씩 수정하는 것보다,</p>
<p><strong>어떤 작업을 Agent에게 맡기고 어떤 기준을 통과해야 Merge할 것인지 결정하는 일</strong>에 더 가까워질 겁니다.</p>
<p>결국 Agentic Autofix에서 눈여겨볼 부분은 <code>25개를 한꺼번에 고쳐준다</code>는 기능 자체가 아닙니다.</p>
<p>더 큰 변화는 이것입니다.</p>
<p><strong>기술부채가 개발자의 작업 목록에서 Agent의 작업 큐로 이동하기 시작했다.</strong></p>
<p>AI Coding Agent가 코드 생성을 넘어 유지보수 영역까지 들어오기 시작했다는 신호로 볼 만합니다.</p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>GitHub Changelog — Remediate Code Quality findings with agentic autofix</strong><br>2026년 9월 9일 공개된 Agentic Autofix 공식 발표입니다. Code Quality에서 최대 25개의 finding을 한 번에 Copilot에 할당하고, 별도 branch에서 수정·검증한 뒤 Pull Request를 생성하는 전체 흐름을 확인할 수 있습니다.<br><a href="https://github.blog/changelog/2026-09-09-remediate-code-quality-findings-with-agentic-autofix/?utm_source=chatgpt.com">GitHub Agentic Autofix 공식 발표</a></p>
</li>
<li><p><strong>GitHub Docs — Code Quality</strong><br>Code Quality finding과 remediation workflow, Copilot을 이용한 수정 흐름을 확인할 수 있습니다.<br><a href="https://docs.github.com/en/code-security/code-quality?utm_source=chatgpt.com">GitHub Code Quality 공식 문서</a></p>
</li>
<li><p><strong>GitHub Docs — Autofix for Code Scanning</strong><br>Code Scanning Alert에서 Copilot Autofix와 Agentic Autofix가 어떻게 동작하는지 확인할 수 있습니다.<br><a href="https://docs.github.com/en/code-security/concepts/code-scanning/autofix-for-code-scanning?utm_source=chatgpt.com">GitHub Code Scanning Autofix 공식 문서</a></p>
</li>
</ul>
<p><strong>공식 자료 기준으로 보면</strong>, 이번 변화의 핵심은 단순히 AI가 수정 코드를 추천하는 것이 아니라 <strong>finding 자체를 Copilot Agent의 작업으로 넘길 수 있게 됐다는 점</strong>입니다.</p>
<p>Code Quality에서는 최대 25개의 finding을 하나의 작업으로 묶어 Copilot에 할당할 수 있고, Agent가 별도 branch에서 수정과 검증을 수행한 뒤 사람이 검토할 Pull Request를 생성합니다.</p>
<p>기술부채 관리도 점점</p>
<pre><code class="language-text">Finding
   ↓
Developer Fix</code></pre>
<p>에서</p>
<pre><code class="language-text">Finding
   ↓
Agent Remediation
   ↓
Pull Request
   ↓
Human Review</code></pre>
<p>구조로 이동하고 있습니다.</p>
<p>따라서 실제 팀에서는 Agent에게 얼마나 많은 코드를 맡길 수 있는가보다 <strong>CI, Test, Review, Quality Gate를 어떻게 정의할 것인가</strong>가 더 중요해질 가능성이 큽니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin이 Swift 쪽으로 한 발 더 들어왔다]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609123</link>
            <guid>https://velog.io/@kyu_ios_dev/2609123</guid>
            <pubDate>Sat, 12 Sep 2026 09:28:13 GMT</pubDate>
            <description><![CDATA[<h3 id="kotlin이-swift-쪽으로-한-발-더-들어왔다">Kotlin이 Swift 쪽으로 한 발 더 들어왔다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/43b1279c-7fd6-45e7-a6ed-ab88c21776a4/image.png" alt=""></p>
<h2 id="kotlin-2420의-swift-export-그리고-iphone-duo-시대의-kmp">Kotlin 2.4.20의 Swift Export, 그리고 iPhone Duo 시대의 KMP</h2>
<p>Kotlin 2.4.20이 9월 7일 정식 출시됐습니다.</p>
<p>전체 변경사항을 보면 Standard Library, Kotlin/Wasm, Kotlin/JS, Gradle 등 여러 영역이 업데이트됐지만 iOS 개발자라면 <strong>Kotlin/Native 쪽 변화</strong>를 눈여겨볼 만합니다.</p>
<p>이번 버전에서 특히 볼 부분은 세 가지입니다.</p>
<ul>
<li>Swift Export 기능 확대</li>
<li>SwiftPM 연동을 위한 <code>Package.swift</code> 생성 지원</li>
<li>Kotlin/Native Incremental Compilation 개선</li>
</ul>
<p>각각만 보면 작은 개선처럼 보일 수도 있습니다.</p>
<p>하지만 방향은 꽤 명확합니다.</p>
<p>기존 KMP의 iOS 연동은 대체로</p>
<pre><code class="language-text">Kotlin
   ↓
Kotlin/Native
   ↓
Objective-C Interop
   ↓
Swift</code></pre>
<p>구조였습니다.</p>
<p>Kotlin 2.4.20에서 계속 진행되고 있는 방향은 이 중간 단계를 줄여</p>
<pre><code class="language-text">Kotlin
   ↓
Swift</code></pre>
<p>에 더 가까운 개발 경험을 만드는 것입니다.</p>
<p>그리고 최근 발표된 <strong>iPhone Duo</strong>까지 같이 보면 이 변화가 더 흥미로워집니다.</p>
<p>앞으로 KMP에서 중요한 질문은 단순히</p>
<blockquote>
<p>얼마나 많은 코드를 공유할 수 있는가?</p>
</blockquote>
<p>가 아니라</p>
<blockquote>
<p><strong>어디까지 공유하는 것이 Apple 플랫폼 변화에 가장 자연스럽게 대응할 수 있는가?</strong></p>
</blockquote>
<p>가 될 가능성이 높습니다.</p>
<hr>
<h1 id="kmp에서-항상-애매했던-ios-쪽-경계">KMP에서 항상 애매했던 iOS 쪽 경계</h1>
<p>Kotlin Multiplatform을 사용하는 가장 현실적인 방식은 UI 전체를 공유하는 것보다 비즈니스 로직을 공유하는 구조입니다.</p>
<p>예를 들면 이런 형태입니다.</p>
<pre><code class="language-text">Android
   │
   ├─ Compose
   │
   └─────────┐
             │
        Shared KMP
             │
   ┌─────────┘
   │
iOS
   │
   └─ SwiftUI</code></pre>
<p>공유 영역에는 보통</p>
<pre><code class="language-text">Network
Repository
Domain
Validation
Business Logic</code></pre>
<p>이 들어갑니다.</p>
<p>iOS UI는 SwiftUI,</p>
<p>Android UI는 Compose로 만드는 방식입니다.</p>
<p>구조 자체는 상당히 자연스럽습니다.</p>
<p>문제는 Shared Module이 Swift와 만나는 지점이었습니다.</p>
<p>Kotlin/Native는 오랫동안 Objective-C compatibility를 기반으로 Swift에 API를 노출했습니다.</p>
<p>그래서 Kotlin에서는 자연스러운 타입도 Swift에 넘어오는 순간 조금 다른 모습이 됩니다.</p>
<p>대표적으로</p>
<pre><code class="language-text">Package
Nullable
Generic
Coroutine
Flow
Sealed Class</code></pre>
<p>같은 부분입니다.</p>
<p>결국 Shared Logic을 만들고도 iOS 쪽에 Adapter나 Wrapper가 다시 생기는 경우가 많았습니다.</p>
<pre><code class="language-text">Kotlin Model
     ↓
Interop
     ↓
Swift Adapter
     ↓
SwiftUI</code></pre>
<p>KMP를 사용하면서도 iOS 개발자가 계속 Interop 구조를 의식해야 했던 이유입니다.</p>
<hr>
<h1 id="swift-export가-줄이려는-것이-바로-이-경계다">Swift Export가 줄이려는 것이 바로 이 경계다</h1>
<p>Swift Export의 목표는 단순합니다.</p>
<p><strong>Kotlin API를 Swift에서 보다 Swift다운 형태로 사용할 수 있게 만드는 것.</strong></p>
<p>기존 구조가</p>
<pre><code class="language-text">Kotlin
 ↓
Objective-C
 ↓
Swift</code></pre>
<p>였다면,</p>
<p>Swift Export는</p>
<pre><code class="language-text">Kotlin
 ↓
Swift Module
 ↓
Swift</code></pre>
<p>에 가까운 구조를 만듭니다.</p>
<p>Kotlin package 구조도 더 자연스럽게 Swift 쪽으로 전달할 수 있고, 여러 Kotlin Module을 각각 Swift Module 형태로 Export하는 것도 가능합니다.</p>
<p>예를 들어 KMP 프로젝트가</p>
<pre><code class="language-text">shared-domain
shared-network
shared-database</code></pre>
<p>처럼 구성돼 있다면 Swift에서도 Module 경계를 더 명확하게 유지할 수 있습니다.</p>
<p>결국 목표는 하나입니다.</p>
<p><strong>iOS 개발자가 KMP를 사용하면서 Kotlin/Native의 내부 사정을 최대한 덜 신경 쓰게 만드는 것.</strong></p>
<hr>
<h1 id="2420에서는-sealed-class가-swift에서-훨씬-자연스러워졌다">2.4.20에서는 sealed class가 Swift에서 훨씬 자연스러워졌다</h1>
<p>이번 버전에서 iOS 개발자가 체감하기 좋은 변화 중 하나가 <strong>sealed class와 sealed interface 지원</strong>입니다.</p>
<p>Kotlin에서는 상태를 표현할 때 sealed hierarchy를 자주 사용합니다.</p>
<pre><code class="language-kotlin">sealed interface LoginState

data object Loading : LoginState

data class Success(
    val userName: String
) : LoginState

data class Failure(
    val message: String
) : LoginState</code></pre>
<p>Kotlin에서는 <code>when</code>으로 모든 상태를 안전하게 처리할 수 있습니다.</p>
<pre><code class="language-kotlin">when (state) {
    Loading -&gt; showLoading()
    is Success -&gt; showUser(state.userName)
    is Failure -&gt; showError(state.message)
}</code></pre>
<p>새로운 subtype이 추가되면 Compiler가 누락된 case를 알려줍니다.</p>
<p>Swift의 enum을 <code>switch</code>하는 것과 비슷합니다.</p>
<p>문제는 기존 Swift Interop이었습니다.</p>
<p>Swift에서는 Kotlin sealed hierarchy를 처리할 때 결국</p>
<pre><code class="language-swift">default:
    break</code></pre>
<p>같은 case를 넣어야 하는 경우가 있었습니다.</p>
<p>이렇게 되면 Kotlin에 새로운 상태가 추가돼도 Swift Compiler가 누락을 잡아주지 못할 수 있습니다.</p>
<hr>
<h1 id="이제-swift에서도-exhaustive-switch가-가능하다">이제 Swift에서도 exhaustive switch가 가능하다</h1>
<p>Kotlin 2.4.20의 Swift Export에서는 sealed hierarchy를 Swift enum 형태로 연결할 수 있습니다.</p>
<p><code>sealedType()</code>을 통해 Swift에서 exhaustive switch가 가능합니다.</p>
<p>예를 들어 Kotlin에</p>
<pre><code class="language-kotlin">sealed interface Shape

class Circle : Shape
class Rectangle : Shape</code></pre>
<p>가 있다면 Swift에서는 개념적으로 이런 식입니다.</p>
<pre><code class="language-swift">switch shape.sealedType() {
case .circle(let circle):
    print(circle.value)

case .rectangle(let rectangle):
    print(rectangle.value)
}</code></pre>
<p><code>default</code>가 필요 없습니다.</p>
<p>Kotlin에 새로운 subtype이 추가되면 Swift Compiler도 처리되지 않은 case가 있다는 것을 알려줄 수 있습니다.</p>
<p>KMP에서 UI State를 공유한다면 꽤 의미가 큽니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">Loading
Success
Empty
Failure
Expired</code></pre>
<p>같은 상태를 Kotlin에서 정의하고 SwiftUI에서 그대로 처리하기가 훨씬 자연스러워집니다.</p>
<hr>
<h1 id="swiftui와-kmp-사이에-만들던-adapter도-줄일-수-있다">SwiftUI와 KMP 사이에 만들던 Adapter도 줄일 수 있다</h1>
<p>기존 KMP + SwiftUI 프로젝트에서는 이런 구조가 자주 생깁니다.</p>
<pre><code class="language-text">Kotlin State
    ↓
Swift Adapter
    ↓
Swift Enum
    ↓
SwiftUI</code></pre>
<p>Shared Logic을 만들었는데 iOS에서 다시 한번 Model 변환을 하는 셈입니다.</p>
<p>Swift Export가 발전하면 목표 구조는 훨씬 단순합니다.</p>
<pre><code class="language-text">Kotlin State
     ↓
Swift Export
     ↓
SwiftUI</code></pre>
<p>실제 프로젝트에서 KMP 도입 비용을 높이는 것은 Kotlin 코드 자체보다 이런 <strong>Glue Code</strong>인 경우가 많습니다.</p>
<p>따라서 Swift Export 개선은 단순한 문법 편의보다 Architecture 관점에서 의미가 있습니다.</p>
<hr>
<h1 id="swift가-kotlin-interface를-직접-구현할-수도-있다">Swift가 Kotlin interface를 직접 구현할 수도 있다</h1>
<p>2.4.20에서 또 하나 중요한 변화가 <strong>Cross-language inheritance</strong>입니다.</p>
<p>Kotlin에서 Contract를 정의하고 실제 구현을 Swift에서 제공할 수 있습니다.</p>
<p>예를 들어 Shared Module에서</p>
<pre><code class="language-kotlin">interface SecureStorage {
    fun save(
        key: String,
        value: String
    )
}</code></pre>
<p>라는 Interface를 정의했다고 해보겠습니다.</p>
<p>iOS에서는 실제 구현에 Keychain을 사용하고 싶습니다.</p>
<p>이 로직을 Kotlin으로 억지로 옮길 필요가 없습니다.</p>
<p>Swift가 구현하면 됩니다.</p>
<pre><code class="language-text">Shared Kotlin

SecureStorage
     ↑
     │
Swift Implementation
     │
  Keychain</code></pre>
<p>CryptoKit처럼 Apple 전용 Framework를 사용하는 것도 같은 방식으로 생각할 수 있습니다.</p>
<p>이건 KMP Architecture에서 상당히 중요한 변화입니다.</p>
<hr>
<h1 id="kmp라고-해서-모든-코드를-공유할-필요는-없다">KMP라고 해서 모든 코드를 공유할 필요는 없다</h1>
<p>KMP를 처음 적용할 때 흔히 나오는 고민이 있습니다.</p>
<pre><code class="language-text">어디까지 Kotlin으로 만들 것인가?</code></pre>
<p>공유할 수 있다는 이유로 모든 영역을 Shared Module로 올릴 필요는 없습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">Keychain
CryptoKit
LocalAuthentication
AVFoundation
HealthKit
StoreKit</code></pre>
<p>같은 기능은 Apple Framework를 Native에서 직접 사용하는 편이 더 자연스러운 경우가 많습니다.</p>
<p>Shared Module에서는 Contract만 정의합니다.</p>
<pre><code class="language-text">Shared Kotlin

AuthenticationProvider
SecureStorage
CryptoProvider</code></pre>
<p>그리고 각 플랫폼에서 구현합니다.</p>
<pre><code class="language-text">Android
 └─ Android implementation

iOS
 └─ Swift implementation</code></pre>
<p>Cross-language inheritance가 좋아질수록 이런 구조의 비용이 줄어듭니다.</p>
<p>KMP의 방향도</p>
<pre><code class="language-text">모든 것을 Kotlin으로 만든다</code></pre>
<p>보다</p>
<pre><code class="language-text">공유할 가치가 있는 것만 Kotlin으로 만든다</code></pre>
<p>쪽이 더 현실적입니다.</p>
<hr>
<h1 id="swiftpm-연결도-계속-자연스러워지고-있다">SwiftPM 연결도 계속 자연스러워지고 있다</h1>
<p>iOS 개발자 입장에서 또 중요한 부분이 <strong>Swift Package Manager</strong>입니다.</p>
<p>KMP Library를 iOS에서 사용하려면 일반적으로 XCFramework를 사용합니다.</p>
<pre><code class="language-text">Kotlin
   ↓
Kotlin/Native
   ↓
XCFramework
   ↓
iOS</code></pre>
<p>SwiftPM으로 배포한다면 <code>Package.swift</code> 관리가 추가됩니다.</p>
<p>특히 해당 XCFramework가 다른 Swift Package에 의존하면 배포 과정이 더 복잡해집니다.</p>
<p>Kotlin 2.4.20에서는 SwiftPM dependency가 있는 XCFramework를 만들 때 <code>assembleSharedXCFramework</code> 작업이 필요한 <strong><code>Package.swift</code> 파일을 자동 생성</strong>할 수 있게 됐습니다.</p>
<pre><code class="language-text">KMP
 ↓
Gradle
 ↓
XCFramework
 +
Package.swift
 ↓
SwiftPM
 ↓
Xcode</code></pre>
<p>여기서 주의할 점도 있습니다.</p>
<p>모든 KMP 프로젝트에서 <code>Package.swift</code>가 자동으로 만들어진다는 의미는 아닙니다.</p>
<p>이번 기능은 특히 <strong>SwiftPM dependency가 포함된 XCFramework를 Swift Package 형태로 배포하는 과정</strong>을 단순화하는 변화입니다.</p>
<hr>
<h1 id="native-build도-계속-줄이려-한다">Native Build도 계속 줄이려 한다</h1>
<p>KMP 프로젝트에서 실제 개발 경험을 좌우하는 부분 중 하나가 Build Time입니다.</p>
<p>순수 iOS 프로젝트와 다르게</p>
<pre><code class="language-text">Gradle
+
Kotlin Compiler
+
Kotlin/Native
+
Xcode</code></pre>
<p>가 함께 움직입니다.</p>
<p>Shared Module이 커지면 Kotlin/Native Compile Time도 체감됩니다.</p>
<p>2.4.20에서는 <code>.klib</code> artifact를 대상으로 한 Incremental Compilation도 개선됐습니다.</p>
<p>현재는 Beta 기능이며</p>
<pre><code class="language-properties">kotlin.incremental.native=true</code></pre>
<p>를 통해 사용할 수 있습니다.</p>
<p>목표는 단순합니다.</p>
<pre><code class="language-text">작은 코드 변경
       ↓
Native 전체 재빌드</code></pre>
<p>가 아니라</p>
<pre><code class="language-text">작은 코드 변경
       ↓
변경된 부분 중심 Compile</code></pre>
<p>로 가는 것입니다.</p>
<p>Interop이 아무리 좋아져도 Build가 느리면 실제 개발 경험은 좋기 어렵습니다.</p>
<p>JetBrains가 Swift Export와 Native Build를 동시에 개선하고 있는 이유입니다.</p>
<hr>
<h1 id="그런데-iphone-duo가-나오면서-새로운-질문이-생겼다">그런데 iPhone Duo가 나오면서 새로운 질문이 생겼다</h1>
<p>여기까지는 Kotlin 2.4.20 자체의 이야기입니다.</p>
<p>그런데 최근 발표된 <strong>iPhone Duo</strong>를 같이 보면 KMP UI 전략에도 재미있는 문제가 하나 생깁니다.</p>
<p>Apple은 Duo의 접힌 화면과 펼쳐진 내부 화면에서 표준 Navigation Container가 자동으로 적응하도록 설계했습니다.</p>
<p>대표적으로</p>
<pre><code class="language-text">TabView
NavigationSplitView

UITabBarController
UISplitViewController</code></pre>
<p>입니다.</p>
<p>접힌 상태에서는 Compact한 Navigation으로 동작하고,</p>
<p>내부의 넓은 화면에서는 Sidebar나 Split 구조를 사용할 수 있습니다.</p>
<p>즉 같은 iPhone 앱이</p>
<pre><code class="language-text">Compact
   ↓
Tab Bar</code></pre>
<p>에서</p>
<pre><code class="language-text">Expanded
   ↓
Sidebar</code></pre>
<p>로 바뀔 수 있습니다.</p>
<p>여기서 KMP를 사용하는 앱도 UI를 어떻게 구성했느냐에 따라 차이가 생깁니다.</p>
<hr>
<h1 id="kmp--swiftui라면-사실-큰-문제가-없다">KMP + SwiftUI라면 사실 큰 문제가 없다</h1>
<p>KMP로 비즈니스 로직만 공유하고 UI를 SwiftUI로 만든 앱이라면 Duo 대응 때문에 KMP 자체를 크게 걱정할 이유는 없습니다.</p>
<p>구조가 이런 식이기 때문입니다.</p>
<pre><code class="language-text">┌────────────────────────────┐
│            iOS             │
│                            │
│ SwiftUI                    │
│ TabView                    │
│ NavigationSplitView        │
│ Native Sidebar             │
│ Safe Area                  │
│ iPhone Duo Adaptivity      │
└─────────────┬──────────────┘
              │
         Swift Export
              │
┌─────────────▼──────────────┐
│         Shared KMP         │
│                            │
│ Domain                     │
│ Repository                 │
│ Network                    │
│ Validation                 │
│ Business Logic             │
└────────────────────────────┘</code></pre>
<p>iOS Navigation은 Apple Framework가 담당합니다.</p>
<p>따라서 Apple이 새로운 Sidebar나 Window Adaptivity를 추가하면 SwiftUI 쪽에서 대응하면 됩니다.</p>
<p>KMP는 그 아래의 Business Logic을 계속 제공합니다.</p>
<p>이 구조에서는 KMP가 오히려 거의 보이지 않습니다.</p>
<hr>
<h1 id="uikit-시스템-navigation을-사용해도-마찬가지다">UIKit 시스템 Navigation을 사용해도 마찬가지다</h1>
<p>꼭 SwiftUI여야 하는 것도 아닙니다.</p>
<p>UIKit에서도</p>
<pre><code class="language-text">UITabBarController
UINavigationController
UISplitViewController</code></pre>
<p>같은 시스템 Navigation을 사용한다면 Apple이 제공하는 Adaptivity를 활용할 수 있습니다.</p>
<p>Compose Multiplatform 화면을 사용하더라도 <code>ComposeUIViewController</code>를 Native Navigation 아래에 넣는 구조가 가능합니다.</p>
<p>예를 들면</p>
<pre><code class="language-text">UITabBarController
        ↓
UINavigationController
        ↓
ComposeUIViewController
        ↓
Compose Screen</code></pre>
<p>입니다.</p>
<p>JetBrains 공식 가이드에서도 이와 비슷하게 SwiftUI 또는 UIKit이 Navigation을 담당하고 Compose는 Screen Content를 그리는 Hybrid 구조를 안내하고 있습니다.</p>
<p>즉 중요한 것은</p>
<pre><code class="language-text">SwiftUI인가?
Compose인가?</code></pre>
<p>만이 아닙니다.</p>
<p>더 중요한 것은</p>
<p><strong>누가 Navigation을 소유하고 있느냐</strong>입니다.</p>
<hr>
<h1 id="진짜-문제가-될-수-있는-건-오래된-custom-navigation이다">진짜 문제가 될 수 있는 건 오래된 Custom Navigation이다</h1>
<p>iPhone Duo에서 더 신경 써야 할 쪽은 KMP가 아니라 오히려 이런 코드입니다.</p>
<pre><code class="language-text">Custom Tab Bar
Custom Navigation Bar
Custom Sidebar
Fixed Width Layout
Orientation 기반 Layout
UIScreen.main 기반 계산</code></pre>
<p>예를 들어 SwiftUI에서 시스템 <code>TabView</code> 대신 이런 식으로 Tab Bar를 직접 만들었다고 해보겠습니다.</p>
<pre><code class="language-swift">ZStack(alignment: .bottom) {
    content

    CustomTabBar()
        .frame(height: 64)
}</code></pre>
<p>여기에</p>
<pre><code class="language-swift">let width = UIScreen.main.bounds.width</code></pre>
<p>같은 계산까지 들어가 있다면 Duo에서는 확인해야 할 부분이 많아집니다.</p>
<p>Apple의 표준 Navigation은 Duo에서</p>
<pre><code class="language-text">접힘
펼침
Sidebar
Split
Safe Area
Camera 영역</code></pre>
<p>등을 시스템이 알고 처리합니다.</p>
<p>Custom Navigation은 그 정보를 직접 반영해야 합니다.</p>
<hr>
<h1 id="duo에서는-safe-area조차-좌우가-같다는-보장이-없다">Duo에서는 Safe Area조차 좌우가 같다는 보장이 없다</h1>
<p>이 부분도 중요합니다.</p>
<p>Apple은 iPhone Duo에서 Safe Area와 Layout Margin이 <strong>비대칭일 수 있다</strong>고 안내하고 있습니다.</p>
<p>따라서 이런 가정도 위험해집니다.</p>
<pre><code class="language-text">left inset == right inset</code></pre>
<p>Custom Tab Bar나 Custom Navigation Bar에서 Safe Area를 직접 계산했다면 반드시 다시 확인해야 합니다.</p>
<p>특히</p>
<pre><code class="language-swift">UIScreen.main.bounds</code></pre>
<p>처럼 Main Screen을 직접 참조하는 방식도 Duo 같은 Multi-display Device에서는 모호해집니다.</p>
<p>Apple은 Layout 판단에</p>
<pre><code class="language-text">Environment
Trait Collection
Scene Bounds
Size Class</code></pre>
<p>를 사용하는 방향을 권장하고 있습니다.</p>
<hr>
<h1 id="orientation-기준-layout도-다시-봐야-한다">Orientation 기준 Layout도 다시 봐야 한다</h1>
<p>오래된 iOS 앱에는 이런 코드도 많습니다.</p>
<pre><code class="language-swift">if orientation.isLandscape {
    showExpandedLayout()
}</code></pre>
<p>하지만 Duo 내부 Display에서는 기존 Orientation 가정을 그대로 사용할 수 없습니다.</p>
<p>따라서</p>
<pre><code class="language-text">Portrait
Landscape</code></pre>
<p>보다</p>
<pre><code class="language-text">Compact
Regular
Available Width
Scene Bounds</code></pre>
<p>를 기준으로 Layout을 판단하는 것이 중요해집니다.</p>
<p>이 문제 역시 KMP와 직접적인 관계가 없습니다.</p>
<p>Swift로 만들었더라도 Custom Layout을 오래된 방식으로 구성했다면 똑같이 문제가 됩니다.</p>
<hr>
<h1 id="compose-multiplatform으로-ui-전체를-공유했다면">Compose Multiplatform으로 UI 전체를 공유했다면?</h1>
<p>여기에서는 조금 이야기가 달라집니다.</p>
<p>Compose Multiplatform 자체도 Adaptive Layout을 지원합니다.</p>
<p><code>WindowSizeClass</code>나 Material 3 Adaptive API 등을 활용해서</p>
<pre><code class="language-text">Compact
Medium
Expanded</code></pre>
<p>환경에 따라 다른 Layout을 만들 수 있습니다.</p>
<p>따라서</p>
<pre><code class="language-text">Duo 외부 화면

Bottom Navigation</code></pre>
<pre><code class="language-text">Duo 내부 화면

Navigation Rail
또는
Sidebar 형태 UI</code></pre>
<p>를 직접 구현하는 것은 가능합니다.</p>
<p>문제는 이게 <strong>Apple의 Native Sidebar와 동일한 것은 아니라는 점</strong>입니다.</p>
<p>Compose에서 직접 만든 Sidebar는 Compose Component입니다.</p>
<p>Apple의</p>
<pre><code class="language-text">TabView
NavigationSplitView
UITabBarController
UISplitViewController</code></pre>
<p>가 제공하는 시스템 Navigation과는 다릅니다.</p>
<hr>
<h1 id="이미-liquid-glass에서-같은-문제가-한번-드러났다">이미 Liquid Glass에서 같은 문제가 한번 드러났다</h1>
<p>이 부분은 Duo만의 새로운 문제가 아닙니다.</p>
<p>iOS 26의 Liquid Glass에서도 같은 일이 있었습니다.</p>
<p>Compose Multiplatform으로 Tab Bar와 Navigation 전체를 직접 그리면 Apple의 Native Tab Bar에 자동으로 적용되는 Liquid Glass 효과를 그대로 받을 수 없습니다.</p>
<p>그래서 JetBrains 공식 가이드에서도 한 가지 현실적인 Architecture를 제시합니다.</p>
<pre><code class="language-text">SwiftUI

TabView
NavigationStack
      ↓
Compose
Screen Content</code></pre>
<p>즉 Navigation은 Apple의 Native Component가 담당하고,</p>
<p>화면 Content는 Compose가 담당하는 방식입니다.</p>
<p>UIKit에서도 같은 구조가 가능합니다.</p>
<pre><code class="language-text">UITabBarController
UINavigationController
        ↓
ComposeUIViewController</code></pre>
<p>Liquid Glass에서 나온 이 문제가 iPhone Duo에서도 똑같은 Architecture 질문으로 이어집니다.</p>
<hr>
<h1 id="duo에서는-이-차이가-더-커질-수-있다">Duo에서는 이 차이가 더 커질 수 있다</h1>
<p>Liquid Glass는 주로 Visual Style의 문제였습니다.</p>
<p>하지만 Duo는 조금 다릅니다.</p>
<p>이번에는 <strong>Navigation 구조 자체가 바뀝니다.</strong></p>
<pre><code class="language-text">Compact
   ↓
Tab Bar</code></pre>
<p>에서</p>
<pre><code class="language-text">Expanded
   ↓
Sidebar
   ↓
Split Content</code></pre>
<p>로 전환될 수 있습니다.</p>
<p>시스템 Navigation을 사용하면 이 변화에 Apple Framework가 적극적으로 참여합니다.</p>
<p>반면 Custom Navigation이나 Compose에서 직접 만든 Navigation이라면 이 Adaptive Behavior를 직접 구현해야 합니다.</p>
<p>그래서 앞으로 KMP UI를 설계할 때도 질문이 달라집니다.</p>
<pre><code class="language-text">Compose로 만들 수 있는가?</code></pre>
<p>보다</p>
<pre><code class="language-text">Compose로 직접 만들어야 하는가?</code></pre>
<p>가 더 중요해집니다.</p>
<hr>
<h1 id="결국-kmp보다-custom-ui가-더-큰-변수다">결국 KMP보다 Custom UI가 더 큰 변수다</h1>
<p>정리하면 iPhone Duo 대응에서 문제를 단순히</p>
<pre><code class="language-text">Native SwiftUI = 안전

KMP = 위험</code></pre>
<p>으로 볼 수는 없습니다.</p>
<p>실제로는 이렇게 보는 편이 더 정확합니다.</p>
<pre><code class="language-text">KMP + SwiftUI Navigation
        ↓
대응 수월

KMP + UIKit System Navigation
        ↓
대응 수월

Compose Content
+ Native Navigation
        ↓
대응 수월</code></pre>
<p>반면</p>
<pre><code class="language-text">Swift + Custom Tab Bar
        ↓
직접 대응 필요

Compose + Custom Navigation
        ↓
직접 대응 필요

UIScreen / Orientation
기반 Layout
        ↓
직접 대응 필요</code></pre>
<p>입니다.</p>
<p>즉 문제의 기준은 언어가 아닙니다.</p>
<p><strong>얼마나 시스템 UI와 Navigation을 활용하고 있는가</strong>가 더 중요합니다.</p>
<hr>
<h1 id="swift-export가-좋아지는-것이-여기에서도-의미가-있다">Swift Export가 좋아지는 것이 여기에서도 의미가 있다</h1>
<p>이 지점에서 다시 Kotlin 2.4.20의 Swift Export로 돌아오면 이야기가 연결됩니다.</p>
<p>Swift Export가 좋아질수록</p>
<pre><code class="language-text">Business Logic
     ↓
Kotlin</code></pre>
<p>과</p>
<pre><code class="language-text">Platform UI
     ↓
SwiftUI / UIKit</code></pre>
<p>를 분리하는 비용이 낮아집니다.</p>
<p>예전에는 이 경계에서 Objective-C Interop과 Wrapper Code가 많이 필요했습니다.</p>
<p>그 비용이 줄어든다면 굳이 Apple 플랫폼 UI까지 Kotlin으로 공유할 이유도 줄어들 수 있습니다.</p>
<pre><code class="language-text">Shared

Domain
Repository
Network
Business Logic

──────────────

Native iOS

Tab Bar
Sidebar
Navigation
Safe Area
Liquid Glass
Duo Adaptivity</code></pre>
<p>이런 구조가 더 매력적으로 보이는 이유입니다.</p>
<hr>
<h1 id="그렇다고-compose-ui-공유가-의미-없다는-것은-아니다">그렇다고 Compose UI 공유가 의미 없다는 것은 아니다</h1>
<p>Compose Multiplatform UI를 공유하는 것도 분명 장점이 있습니다.</p>
<p>화면이 많은 앱에서 Android와 iOS UI를 동시에 개발해야 한다면 공유 효과가 큽니다.</p>
<p>다만 플랫폼 변화가 빠르게 들어오는 영역은 판단이 필요합니다.</p>
<p>대표적으로</p>
<pre><code class="language-text">Navigation
System Bar
Window Behavior
Platform Animation
Safe Area
New Form Factor</code></pre>
<p>같은 부분입니다.</p>
<p>이 영역까지 Custom UI로 가져가면 공유 코드는 늘어납니다.</p>
<p>대신 Apple의 새로운 UI 변화에 대응해야 하는 책임도 App 쪽으로 넘어옵니다.</p>
<p>따라서 좋은 KMP Architecture는 공유율 자체를 최대화하는 것이 아니라</p>
<p><strong>공유했을 때 이득이 큰 영역과 Native로 남겼을 때 이득이 큰 영역을 구분하는 것</strong></p>
<p>에 가깝습니다.</p>
<hr>
<h1 id="kotlin-2420과-iphone-duo를-같이-보면-이런-구조가-보인다">Kotlin 2.4.20과 iPhone Duo를 같이 보면 이런 구조가 보인다</h1>
<p>앞으로 상당히 현실적인 KMP Architecture는 이런 형태일 수 있습니다.</p>
<pre><code class="language-text">┌───────────────────────────────┐
│             iOS               │
│                               │
│ SwiftUI / UIKit               │
│                               │
│ TabView / UITabBarController  │
│ Sidebar                       │
│ NavigationSplitView           │
│ Safe Area                     │
│ Liquid Glass                  │
│ iPhone Duo                    │
└───────────────┬───────────────┘
                │
          Swift Export
                │
┌───────────────▼───────────────┐
│          Shared KMP           │
│                               │
│ Domain                        │
│ Repository                    │
│ Network                       │
│ Validation                    │
│ Business Rules                │
└───────────────┬───────────────┘
                │
┌───────────────▼───────────────┐
│           Android             │
│                               │
│ Compose                       │
└───────────────────────────────┘</code></pre>
<p>여기서 중요한 것은 SwiftUI를 많이 사용한다는 것이 아닙니다.</p>
<p><strong>플랫폼의 책임과 Shared Logic의 책임을 명확하게 나눈다는 것</strong>입니다.</p>
<hr>
<h1 id="swift-export는-아직-alpha다">Swift Export는 아직 Alpha다</h1>
<p>물론 지금 바로 모든 KMP 프로젝트를 이 구조로 바꿔야 한다는 의미는 아닙니다.</p>
<p>Swift Export는 여전히 <strong>Alpha</strong> 단계입니다.</p>
<p>현재도 몇 가지 제한이 있습니다.</p>
<ul>
<li>일부 Kotlin 타입 Export 제한</li>
<li>Generic Type Parameter의 Type Erasure</li>
<li>기존 Objective-C Interop 프로젝트 자동 Migration 부재</li>
<li>일부 기능에 별도 설정 필요</li>
<li>API와 동작이 변경될 가능성</li>
</ul>
<p>따라서 Production Project에서는 전면 전환보다는 작은 Module부터 검증하는 방식이 현실적입니다.</p>
<p>다만 JetBrains가</p>
<pre><code class="language-text">Swift Export
SwiftPM
Cross-language inheritance
Incremental Compilation</code></pre>
<p>을 계속 동시에 개선하고 있다는 것은 방향을 보여줍니다.</p>
<hr>
<h1 id="ios-개발자가-kmp를-볼-때-질문도-달라져야-한다">iOS 개발자가 KMP를 볼 때 질문도 달라져야 한다</h1>
<p>예전에는 KMP를 검토할 때 주로 이런 질문을 했습니다.</p>
<pre><code class="language-text">몇 %까지 코드를 공유할 수 있는가?</code></pre>
<p>하지만 앞으로는 이 질문이 더 중요할 수 있습니다.</p>
<pre><code class="language-text">어떤 코드를 공유해야
두 플랫폼 모두 자연스러운가?</code></pre>
<p>예를 들어</p>
<pre><code class="language-text">Domain
Repository
API
Validation
Business Rule</code></pre>
<p>은 공유 효과가 큽니다.</p>
<p>반면</p>
<pre><code class="language-text">Tab Bar
Navigation
Sidebar
Safe Area
Platform Interaction</code></pre>
<p>은 플랫폼 변화의 영향을 직접 받습니다.</p>
<p>iPhone Duo처럼 새로운 Form Factor가 등장할수록 이 차이는 더 분명해집니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>Kotlin 2.4.20의 Swift Export는 겉으로 보면 KMP의 Interop 개선입니다.</p>
<p>하지만 조금 넓게 보면 더 흥미로운 방향이 보입니다.</p>
<p>KMP가 iOS UI를 더 많이 가져가는 것이 아니라,</p>
<p><strong>Kotlin과 Swift가 서로 잘하는 영역을 유지하면서 경계를 더 얇게 만드는 방향</strong>입니다.</p>
<p>그리고 iPhone Duo는 이 Architecture가 왜 중요한지를 보여주는 좋은 사례가 됐습니다.</p>
<p>Duo 대응에서 가장 걱정해야 할 것은 KMP 자체가 아닙니다.</p>
<p>오히려</p>
<pre><code class="language-text">Custom Tab Bar
Custom Navigation
UIScreen.main
Orientation 분기
고정 Width
Safe Area 수동 계산</code></pre>
<p>같은 오래된 UI 코드가 더 큰 변수입니다.</p>
<p>Apple의 시스템 <code>TabView</code>, <code>NavigationSplitView</code>, <code>UITabBarController</code>, <code>UISplitViewController</code>를 사용하고 있다면 새로운 화면 형태와 Sidebar에 대응하기가 훨씬 수월합니다.</p>
<p>KMP 역시 마찬가지입니다.</p>
<p>Business Logic은 Kotlin으로 공유하고,</p>
<p>Navigation과 Apple 고유 UI는 SwiftUI나 UIKit에 맡길 수 있습니다.</p>
<p>Compose를 사용하더라도 Native Navigation 안에 Compose Screen을 넣는 Hybrid 구조가 가능합니다.</p>
<p>결국 Kotlin 2.4.20과 iPhone Duo를 같이 보면 하나의 결론으로 이어집니다.</p>
<p><strong>KMP의 경쟁력은 UI까지 얼마나 많이 공유하느냐보다, 공유할 가치가 있는 로직을 얼마나 자연스럽게 Swift에 전달할 수 있느냐에 있다.</strong></p>
<p>Swift Export가 발전하는 이유도 결국 그 경계를 줄이기 위해서입니다.</p>
<p>그리고 새로운 Apple Hardware가 등장할수록,</p>
<p><strong>공유 코드와 플랫폼 코드의 경계를 어디에 둘 것인가</strong></p>
<p>라는 질문은 더 중요해질 것 같습니다.</p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>Kotlin Documentation — What&#39;s new in Kotlin 2.4.20</strong><br>Swift Export의 sealed class/interface 지원, cross-language inheritance, SwiftPM dependency용 <code>Package.swift</code> 생성, Kotlin/Native Incremental Compilation 개선을 확인할 수 있습니다.<br><a href="https://kotlinlang.org/docs/whatsnew2420.html?utm_source=chatgpt.com">Kotlin 2.4.20 공식 변경사항</a></p>
</li>
<li><p><strong>Kotlin Documentation — Interoperability with Swift using Swift Export</strong><br>Swift Export의 현재 지원 범위와 Alpha 상태, multi-module, package preservation 등 Swift와 Kotlin 사이의 새로운 Interop 방향을 확인할 수 있습니다.<br><a href="https://kotlinlang.org/docs/native-swift-export.html?utm_source=chatgpt.com">Kotlin Swift Export 공식 문서</a></p>
</li>
<li><p><strong>Kotlin Documentation — SwiftPM Export</strong><br>Kotlin Multiplatform에서 XCFramework와 Swift Package Manager를 연결하는 방식을 확인할 수 있습니다.<br><a href="https://kotlinlang.org/docs/native-spm.html?utm_source=chatgpt.com">Kotlin SwiftPM 공식 문서</a></p>
</li>
<li><p><strong>Apple Developer — Prepare your app for iPhone Duo</strong><br>iPhone Duo 내부 화면의 Size Class, Sidebar, Adaptive Layout, Safe Area와 시스템 Navigation의 동작을 확인할 수 있습니다.<br><a href="https://developer.apple.com/kr/videos/play/tech-talks/111461/?utm_source=chatgpt.com">Apple iPhone Duo 대응 공식 Tech Talk</a></p>
</li>
</ul>
<p><strong>공식 자료 기준으로 보면</strong>, Kotlin 2.4.20의 Swift Export는 Kotlin과 Swift 사이에서 필요했던 Objective-C 기반 Interop을 점점 줄이는 방향으로 발전하고 있습니다.</p>
<p>이번 버전에서는 sealed hierarchy를 Swift에서 더 자연스럽게 처리할 수 있고, Swift에서 Kotlin Interface를 구현하는 cross-language inheritance도 추가됐습니다. SwiftPM dependency가 포함된 XCFramework 배포 과정도 조금 더 단순해졌습니다.</p>
<p>다만 Swift Export 자체는 아직 <strong>Alpha</strong>이므로 기존 Production 프로젝트를 바로 전면 전환하기보다는 작은 Module부터 검증하는 방식이 현실적입니다.</p>
<p>iPhone Duo까지 연결해서 보면 더 중요한 기준은 KMP 자체가 아닙니다.</p>
<pre><code class="language-text">Shared KMP
Domain / Repository / Network
        ↓
Swift Export
        ↓
SwiftUI / UIKit
        ↓
TabView
NavigationSplitView
Sidebar
        ↓
iPhone Duo</code></pre>
<p>이 구조라면 Apple의 새로운 Navigation과 Adaptive Layout을 그대로 활용할 수 있습니다.</p>
<p>반대로 KMP 여부와 관계없이 Custom Tab Bar, Custom Navigation, 고정 Width, <code>UIScreen.main</code>, Orientation 기반 Layout을 많이 사용했다면 Duo 대응을 직접 해야 하는 영역이 늘어납니다.</p>
<p>따라서 KMP의 현실적인 방향은 <strong>Business Logic은 공유하고 Apple 플랫폼의 Navigation과 System UI는 Native Framework에 맡기는 구조</strong>로 보는 것이 자연스럽습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS 27.1 커스텀 탭바를 당장 버릴 필요는 없다  ]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609122</link>
            <guid>https://velog.io/@kyu_ios_dev/2609122</guid>
            <pubDate>Sat, 12 Sep 2026 09:22:36 GMT</pubDate>
            <description><![CDATA[<h3 id="ios-271-커스텀-탭바를-당장-버릴-필요는-없다">iOS 27.1 커스텀 탭바를 당장 버릴 필요는 없다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/2477e0ae-bb97-4037-bae9-f9f8bea24fe1/image.png" alt=""></p>
<h2 id="ios-271과-iphone-duo-시대-오래된-navigation을-어떻게-가져갈-것인가">iOS 27.1과 iPhone Duo 시대, 오래된 Navigation을 어떻게 가져갈 것인가</h2>
<p>iPhone Duo가 공개되면서 오래 운영한 iOS 프로젝트라면 한 번쯤 확인해야 할 코드가 생겼습니다.</p>
<p>대표적인 것이 이런 UI입니다.</p>
<pre><code class="language-text">Custom Tab Bar
Custom Navigation Bar
Custom Toolbar
UIScreen.main 기반 레이아웃
Orientation 기반 분기
고정 Width / Height
Safe Area 직접 계산</code></pre>
<p>최근 SwiftUI 프로젝트라면 <code>TabView</code>, <code>NavigationStack</code>, <code>NavigationSplitView</code>를 사용하는 경우가 많아 상대적으로 대응이 쉽습니다.</p>
<p>반면 몇 년 이상 운영한 UIKit 프로젝트나 디자인 요구가 강했던 앱에서는 Tab Bar와 Navigation Bar를 직접 만든 경우가 적지 않습니다.</p>
<p>예를 들면 이런 구조입니다.</p>
<pre><code class="language-swift">final class MainViewController: UIViewController {

    private let contentView = UIView()
    private let customTabBar = CustomTabBar()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(contentView)
        view.addSubview(customTabBar)
    }
}</code></pre>
<p>SwiftUI에서도 마찬가지입니다.</p>
<pre><code class="language-swift">ZStack(alignment: .bottom) {
    currentContent

    CustomTabBar()
        .frame(height: 64)
}</code></pre>
<p>이 코드들이 iOS 27.1에서 갑자기 사용할 수 없게 되는 것은 아닙니다.</p>
<p><strong>커스텀 Tab Bar와 Navigation은 여전히 사용할 수 있습니다.</strong></p>
<p>다만 iPhone Duo가 들어오면서 한 가지 차이가 커졌습니다.</p>
<p>시스템 Navigation을 사용하면 Apple이 새로운 화면 형태에 맞춰 상당 부분을 처리해주지만,</p>
<p>Custom Navigation은 그 책임이 앱으로 넘어옵니다.</p>
<hr>
<h1 id="먼저-결론부터-보면">먼저 결론부터 보면</h1>
<p>앞으로의 대응은 크게 세 가지로 나눌 수 있습니다.</p>
<pre><code class="language-text">현재

Custom Tab / Navigation
        ↓

1단계
Custom UI 유지
+ Safe Area
+ Reserved Region
+ Adaptive Layout
        ↓

2단계
Navigation State와
UI 표현 분리
        ↓

3단계
UITabBarController / TabView
NavigationSplitView
System Toolbar
        ↓

Duo / Sidebar / Vertical Bar
자동 대응 범위 확대</code></pre>
<p>즉 오래된 프로젝트를 한 번에 전부 다시 만들 필요는 없습니다.</p>
<p><strong>Custom UI를 먼저 안전하게 만든 뒤, Navigation Container부터 단계적으로 시스템 쪽으로 이동하는 방식</strong>이 현실적입니다.</p>
<hr>
<h1 id="왜-이번에는-system-navigation이-더-중요해졌을까">왜 이번에는 System Navigation이 더 중요해졌을까</h1>
<p>기존 iPhone은 화면 형태가 비교적 예측 가능했습니다.</p>
<p>물론 기기 크기는 계속 달라졌지만 기본적인 구조는 비슷했습니다.</p>
<pre><code class="language-text">┌──────────────────┐
│ Navigation Bar   │
│                  │
│                  │
│     Content      │
│                  │
│                  │
│ Tab Bar          │
└──────────────────┘</code></pre>
<p>그래서 앱에서 Tab Bar를 직접 그려도 큰 문제가 없었습니다.</p>
<p>하지만 Duo에서는 화면이 펼쳐지면 이야기가 달라집니다.</p>
<pre><code class="language-text">Closed

┌──────────────┐
│              │
│   Content    │
│              │
│              │
│   Tab Bar    │
└──────────────┘</code></pre>
<p>펼친 내부 화면에서는 사용 가능한 공간 자체가 크게 달라집니다.</p>
<pre><code class="language-text">Opened

┌───────────┬────────────────────┐
│           │                    │
│ Sidebar   │      Content       │
│           │                    │
│           │                    │
└───────────┴────────────────────┘</code></pre>
<p>여기에 화면의 pose와 방향에 따라 System Bar가 아래쪽이 아니라 <strong>옆으로 이동할 수도 있습니다.</strong></p>
<p>Apple은 Duo에서 Navigation, Toolbar, Tab Bar를 Vertical Axis로 배치할 수 있도록 시스템 UI를 바꿨습니다.</p>
<p>이제 화면 아래에 있던 컨트롤이 옆으로 이동할 수 있습니다.</p>
<pre><code class="language-text">기존

Navigation
────────────

Content

────────────
Tab Bar</code></pre>
<p>에서</p>
<pre><code class="language-text">Duo

┌────┬───────────────────────┐
│Nav │                       │
│    │                       │
│Tool│       Content         │
│    │                       │
│Tab │                       │
└────┴───────────────────────┘</code></pre>
<p>같은 형태가 가능해집니다.</p>
<p>시스템 Navigation을 사용한다면 이 이동을 Framework가 처리합니다.</p>
<p>하지만 직접 만든 Tab Bar라면 시스템이 그 내부 구조를 알지 못합니다.</p>
<hr>
<h1 id="custom-uitabbar를-만들었다고-시스템-tab-bar가-되는-것은-아니다">Custom UITabBar를 만들었다고 시스템 Tab Bar가 되는 것은 아니다</h1>
<p>UIKit에서 특히 주의할 부분입니다.</p>
<p>예를 들어 직접</p>
<pre><code class="language-swift">let tabBar = UITabBar()</code></pre>
<p>를 만들었다고 해서 Duo의 새로운 Adaptive Navigation이 자동 적용되는 것은 아닙니다.</p>
<p>Apple은 Duo의 Vertical Bar 대응에서 <code>UINavigationController</code>와 <code>UITabBarController</code> 같은 <strong>Navigation Container가 관리하는 Bar를 사용할 것을 권장</strong>하고 있습니다.</p>
<p>즉</p>
<pre><code class="language-text">UITabBar
UINavigationBar
UIToolbar</code></pre>
<p>인스턴스를 직접 배치한 것과</p>
<pre><code class="language-text">UITabBarController
UINavigationController</code></pre>
<p>가 관리하는 Bar는 다르게 봐야 합니다.</p>
<p>전자는 Custom UI에 가깝습니다.</p>
<p>후자는 시스템 Navigation 구조입니다.</p>
<hr>
<h1 id="그렇다고-custom-tab-bar를-바로-없앨-필요는-없다">그렇다고 Custom Tab Bar를 바로 없앨 필요는 없다</h1>
<p>오래된 앱에서 Tab Bar를 시스템 Tab Bar로 교체하는 것은 생각보다 큰 작업일 수 있습니다.</p>
<p>커스텀 Tab Bar 안에</p>
<pre><code class="language-text">Animation
Badge
Floating Button
Custom Transition
Analytics
Deep Link
Selection State
Authentication Check
Special Gesture</code></pre>
<p>같은 로직이 들어가 있기 때문입니다.</p>
<p>그래서 첫 단계는 교체가 아니라 <strong>Custom UI를 Adaptive하게 만드는 것</strong>입니다.</p>
<p>iOS 27.1에서는 이 작업을 위한 새로운 개념이 추가됐습니다.</p>
<h2 id="reserved-region">Reserved Region</h2>
<p>SwiftUI에서는 <code>ReservedRegion</code>,</p>
<p>UIKit에서는 <code>UIViewReservedRegion</code>을 사용할 수 있습니다.</p>
<p>Reserved Region은 쉽게 말하면</p>
<blockquote>
<p>이 영역에는 앱의 Custom UI가 있으니 시스템 UI와 충돌하지 않도록 서로 공간을 조정하자.</p>
</blockquote>
<p>라는 정보를 Layout System에 전달하는 방식입니다.</p>
<p>특히</p>
<pre><code class="language-text">Custom Tab Bar
Custom Floating Controls
Edge-to-edge UI
Custom Navigation</code></pre>
<p>같은 화면에서 유용합니다.</p>
<p>예전에는 직접</p>
<pre><code class="language-text">Safe Area
+
Magic Number
+
Tab Bar Height
+
Device별 보정값</code></pre>
<p>을 계산했다면,</p>
<p>iOS 27.1에서는 시스템이 알고 있는 Reserved Region 정보를 이용할 수 있습니다.</p>
<p>Custom UI를 당장 제거하기 어려운 앱이라면 <strong>첫 번째 마이그레이션 포인트가 여기</strong>입니다.</p>
<hr>
<h1 id="safe-area-계산부터-다시-확인해야-한다">Safe Area 계산부터 다시 확인해야 한다</h1>
<p>Duo에서 가장 쉽게 문제가 생길 수 있는 코드 중 하나가 이겁니다.</p>
<pre><code class="language-swift">let width =
    view.bounds.width
    - view.safeAreaInsets.left * 2</code></pre>
<p>이 코드는 암묵적으로</p>
<pre><code class="language-text">left == right</code></pre>
<p>라고 가정하고 있습니다.</p>
<p>기존 iPhone에서는 우연히 잘 동작했을 수 있습니다.</p>
<p>Duo에서는 Safe Area와 Layout Margin이 <strong>좌우 대칭이라는 보장이 없습니다.</strong></p>
<p>따라서 이렇게 계산하는 편이 안전합니다.</p>
<pre><code class="language-swift">let availableBounds =
    view.bounds.inset(by: view.safeAreaInsets)

let width = availableBounds.width</code></pre>
<p>이 차이는 작아 보이지만 앞으로 중요합니다.</p>
<pre><code class="language-text">❌ left inset × 2

⭕ left / right 각각 사용</code></pre>
<p>Duo에서는 Camera와 Vertical System Controls, Split View 상태 등에 따라 사용 가능한 영역이 달라질 수 있기 때문입니다.</p>
<hr>
<h1 id="uiscreenmain도-이제-정말-줄여야-한다">UIScreen.main도 이제 정말 줄여야 한다</h1>
<p>오래된 프로젝트를 검색하면 이런 코드가 상당히 많이 나옵니다.</p>
<pre><code class="language-swift">UIScreen.main.bounds.width</code></pre>
<pre><code class="language-swift">UIScreen.main.bounds.height</code></pre>
<pre><code class="language-swift">UIScreen.main.scale</code></pre>
<p>Duo는 Display가 하나라는 가정을 깨는 기기입니다.</p>
<p>Apple 역시 Two-display Device에서는 <code>main screen</code>이라는 개념이 모호해지기 때문에 화면 정보를 Layout 판단에 직접 사용하는 방식을 피하도록 안내하고 있습니다.</p>
<p>예를 들어 Scale만 필요하다면</p>
<pre><code class="language-swift">let scale = traitCollection.displayScale</code></pre>
<p>처럼 현재 환경에서 가져오는 편이 낫습니다.</p>
<p>Layout은</p>
<pre><code class="language-text">UIScreen</code></pre>
<p>보다</p>
<pre><code class="language-text">Environment
Trait Collection
Scene Bounds
Window</code></pre>
<p>를 기준으로 판단해야 합니다.</p>
<hr>
<h1 id="orientation-분기도-다시-봐야-한다">Orientation 분기도 다시 봐야 한다</h1>
<p>다음 코드 역시 오래된 프로젝트에서 흔합니다.</p>
<pre><code class="language-swift">if orientation.isLandscape {
    showWideLayout()
} else {
    showCompactLayout()
}</code></pre>
<p>Duo 내부 화면에서는 이런 접근이 더 이상 좋은 기준이 아닙니다.</p>
<p>Apple은 Duo 내부 Display가 기존 <code>supportedInterfaceOrientations</code>의 가정을 그대로 따르지 않기 때문에 Layout 결정에는 <strong>Size Class를 사용하라고 안내</strong>합니다.</p>
<p>SwiftUI라면</p>
<pre><code class="language-swift">@Environment(\.horizontalSizeClass)
private var horizontalSizeClass</code></pre>
<p>UIKit이라면</p>
<pre><code class="language-swift">traitCollection.horizontalSizeClass</code></pre>
<p>를 사용합니다.</p>
<p>즉</p>
<pre><code class="language-text">Portrait / Landscape</code></pre>
<p>보다</p>
<pre><code class="language-text">Compact / Regular</code></pre>
<p>그리고 궁극적으로는</p>
<pre><code class="language-text">현재 사용할 수 있는 공간</code></pre>
<p>이 중요해집니다.</p>
<hr>
<h1 id="duo-내부-화면은-sidebar를-쓰기-좋은-환경이다">Duo 내부 화면은 Sidebar를 쓰기 좋은 환경이다</h1>
<p>iPhone Duo 내부 화면은 horizontal과 vertical 모두 Regular Size Class를 제공합니다.</p>
<p>그래서 iPhone에서도 Sidebar Navigation을 본격적으로 사용할 수 있습니다.</p>
<p>SwiftUI에서는</p>
<pre><code class="language-swift">TabView {
    Tab(&quot;Home&quot;, systemImage: &quot;house&quot;) {
        HomeView()
    }

    Tab(&quot;Search&quot;, systemImage: &quot;magnifyingglass&quot;) {
        SearchView()
    }

    Tab(&quot;Settings&quot;, systemImage: &quot;gear&quot;) {
        SettingsView()
    }
}
.defaultTabBarPlacement(.sidebar)</code></pre>
<p>처럼 Sidebar 배치를 선택할 수 있습니다.</p>
<p>UIKit에서는</p>
<pre><code class="language-swift">tabBarController
    .sidebar
    .preferredPlacement = .sidebar</code></pre>
<p>를 사용할 수 있습니다.</p>
<p>다만 Sidebar를 요청했다고 항상 Sidebar가 나타나는 것은 아닙니다.</p>
<p>현재 환경에서 Sidebar를 보여줄 공간이 있는지는 시스템이 판단합니다.</p>
<p>UIKit에서는</p>
<pre><code class="language-swift">let available =
    tabBarController.sidebar.isAvailable</code></pre>
<p>로 확인할 수 있습니다.</p>
<hr>
<h1 id="결국-같은-navigation이-화면에-따라-달라질-수-있다">결국 같은 Navigation이 화면에 따라 달라질 수 있다</h1>
<p>이제 하나의 앱에서</p>
<pre><code class="language-text">Compact

┌──────────────────┐
│                  │
│     Content      │
│                  │
├──────────────────┤
│ Home Search Me   │
└──────────────────┘</code></pre>
<p>가</p>
<pre><code class="language-text">Regular

┌─────────┬─────────────────────┐
│ Home    │                     │
│ Search  │      Content        │
│ Profile │                     │
│ Setting │                     │
└─────────┴─────────────────────┘</code></pre>
<p>로 바뀔 수 있습니다.</p>
<p>중요한 것은 Tab의 역할이 달라지는 것이 아니라 <strong>표현 방식만 달라진다는 점</strong>입니다.</p>
<p>그래서 앞으로 Navigation Architecture에서 중요한 것은</p>
<pre><code class="language-text">Tab Bar View</code></pre>
<p>자체가 아니라</p>
<pre><code class="language-text">Navigation State</code></pre>
<p>입니다.</p>
<hr>
<h1 id="커스텀-탭바-마이그레이션은-state부터-분리하면-쉽다">커스텀 탭바 마이그레이션은 State부터 분리하면 쉽다</h1>
<p>기존 Custom Tab Bar가 이런 식으로 돼 있다고 해보겠습니다.</p>
<pre><code class="language-swift">struct CustomTabBar: View {

    @State
    private var selectedIndex = 0

    // UI + Navigation Logic
}</code></pre>
<p>이 구조에서는 Tab Bar UI와 Navigation State가 붙어 있습니다.</p>
<p>시스템 <code>TabView</code>로 바꾸려면 전체 구조를 같이 건드려야 합니다.</p>
<p>먼저 Selection을 외부로 빼는 것이 좋습니다.</p>
<pre><code class="language-swift">enum MainTab: Hashable {
    case home
    case search
    case profile
    case settings
}</code></pre>
<p>그리고 상태를 별도로 관리합니다.</p>
<pre><code class="language-swift">@Observable
final class MainNavigationState {

    var selectedTab: MainTab = .home
}</code></pre>
<p>Custom Tab Bar에서는</p>
<pre><code class="language-text">MainNavigationState
        ↓
CustomTabBar</code></pre>
<p>를 사용하고,</p>
<p>나중에는 같은 State를</p>
<pre><code class="language-text">MainNavigationState
        ↓
TabView</code></pre>
<p>가 사용하도록 바꿉니다.</p>
<p>즉</p>
<pre><code class="language-text">Before

Custom Tab
   │
   ├─ UI
   └─ Navigation State</code></pre>
<p>를</p>
<pre><code class="language-text">After

Navigation State
      │
 ┌────┴─────┐
 │          │
Custom    System
Tab       TabView</code></pre>
<p>로 바꾸는 것입니다.</p>
<p>이렇게 하면 한 번에 UI 전체를 교체하지 않아도 됩니다.</p>
<hr>
<h1 id="첫-번째-마이그레이션은-navigation-container부터">첫 번째 마이그레이션은 Navigation Container부터</h1>
<p>오래된 UIKit 프로젝트라면 가장 현실적인 순서는 이렇습니다.</p>
<p>현재 구조가</p>
<pre><code class="language-text">RootViewController

├─ Content
└─ CustomTabBar</code></pre>
<p>라면,</p>
<p>먼저</p>
<pre><code class="language-text">UITabBarController
        ↓
각 화면의 UINavigationController</code></pre>
<p>구조로 Navigation Container를 바꿉니다.</p>
<p>디자인 때문에 Custom UI가 필요하다면 처음에는 일부 Appearance나 Content를 유지해도 됩니다.</p>
<p>핵심은 <strong>Navigation Ownership을 시스템에 돌려주는 것</strong>입니다.</p>
<p>이렇게 해두면 이후 Duo의</p>
<pre><code class="language-text">Vertical Bar
Sidebar
Overflow
Adaptive Navigation</code></pre>
<p>같은 기능을 단계적으로 사용할 수 있습니다.</p>
<hr>
<h1 id="navigation-bar도-view가-아니라-item-중심으로-옮긴다">Navigation Bar도 View가 아니라 Item 중심으로 옮긴다</h1>
<p>커스텀 Navigation Bar가 이런 구조라면</p>
<pre><code class="language-swift">HStack {
    BackButton()
    Spacer()
    Text(title)
    Spacer()
    MoreButton()
}</code></pre>
<p>장기적으로는 Action을 시스템 Toolbar Item으로 옮기는 것이 좋습니다.</p>
<p>SwiftUI에서는</p>
<pre><code class="language-swift">.toolbar {
    ToolbarItem(placement: .cancellationAction) {
        Button(&quot;Back&quot;) {
            dismiss()
        }
    }

    ToolbarItem(placement: .topBarTrailing) {
        Button(&quot;More&quot;, systemImage: &quot;ellipsis&quot;) {
            showMenu()
        }
    }
}</code></pre>
<p>같은 구조입니다.</p>
<p>UIKit에서도</p>
<pre><code class="language-text">navigationItem
UIBarButtonItem</code></pre>
<p>쪽으로 Action을 이동합니다.</p>
<p>이렇게 해야 시스템이</p>
<pre><code class="language-text">Horizontal Bar

↓

Vertical Bar</code></pre>
<p>로 이동할 때 각 Action의 의미를 알 수 있습니다.</p>
<hr>
<h1 id="duo에서는-toolbar가-정말-세로가-된다">Duo에서는 Toolbar가 정말 세로가 된다</h1>
<p>이 부분은 단순 Sidebar보다 더 중요한 변화일 수 있습니다.</p>
<p>Duo의 넓은 화면에서는 Navigation과 Toolbar Item이 옆쪽 Shared Bar Region에 배치될 수 있습니다.</p>
<p>대략 이런 느낌입니다.</p>
<pre><code class="language-text">┌──────┬───────────────────────┐
│  ←   │                       │
│      │                       │
│ Done │                       │
│      │       Content         │
│  +   │                       │
│      │                       │
│ ...  │                       │
└──────┴───────────────────────┘</code></pre>
<p>그래서 Toolbar Item도 세로 배치를 고려해야 합니다.</p>
<p>Apple은 가능한 경우 <strong>Symbol 중심의 Toolbar Item</strong>을 권장합니다.</p>
<p>긴 텍스트 버튼은 Vertical Bar와 잘 맞지 않기 때문입니다.</p>
<hr>
<h1 id="custom-toolbar-item도-버릴-필요는-없다">Custom Toolbar Item도 버릴 필요는 없다</h1>
<p>System Toolbar 안에 Custom View를 넣는 것도 여전히 가능합니다.</p>
<p>예를 들어</p>
<pre><code class="language-swift">.toolbar {
    ToolbarItem {
        ProfileView()
            .axisBehavior(.verticalPreferred)
    }
}</code></pre>
<p>처럼 Vertical Representation을 지원한다고 알려줄 수 있습니다.</p>
<p>반대로 세로 UI로 만들기 어려운 컨트롤은</p>
<pre><code class="language-swift">.axisBehavior(.horizontalOnly)</code></pre>
<p>로 유지할 수 있습니다.</p>
<p>UIKit의 <code>UIBarButtonItem</code>에도 같은 방향의 <code>axisBehavior</code>가 제공됩니다.</p>
<p>즉 선택지가</p>
<pre><code class="language-text">System UI
or
Custom UI</code></pre>
<p>두 개뿐인 것이 아닙니다.</p>
<p>가장 현실적인 형태는</p>
<pre><code class="language-text">System Container
       +
Custom Content</code></pre>
<p>입니다.</p>
<hr>
<h1 id="이것이-기존-custom-ui의-좋은-마이그레이션-지점이다">이것이 기존 Custom UI의 좋은 마이그레이션 지점이다</h1>
<p>예전에는</p>
<pre><code class="language-text">Custom Navigation Bar
    ├─ Back
    ├─ Title
    ├─ Profile View
    └─ Custom Action</code></pre>
<p>전체를 직접 만들었다면,</p>
<p>앞으로는</p>
<pre><code class="language-text">UINavigationController
        │
        ├─ System Back
        ├─ System Toolbar Item
        ├─ Custom Profile View
        └─ Custom Action View</code></pre>
<p>처럼 바꿀 수 있습니다.</p>
<p>디자인은 상당 부분 유지하면서도 Navigation Context를 시스템에 돌려주는 방식입니다.</p>
<p>이렇게 해야 Apple이 새로운 Form Factor를 만들 때 대응 비용이 줄어듭니다.</p>
<hr>
<h1 id="toolbar가-세로로-갔는지도-확인할-수-있다">Toolbar가 세로로 갔는지도 확인할 수 있다</h1>
<p>Custom Content가 Vertical Bar에서 Layout을 바꿔야 한다면 현재 Bar 위치를 확인할 수도 있습니다.</p>
<p>SwiftUI에서는</p>
<pre><code class="language-swift">@Environment(\.toolbarVerticalEdge)
private var verticalEdge</code></pre>
<p>UIKit에서는</p>
<pre><code class="language-swift">traitCollection.verticalBarEdge</code></pre>
<p>를 사용할 수 있습니다.</p>
<p>예를 들어 같은 Profile UI라도</p>
<pre><code class="language-text">Horizontal

[ Photo  Name ]</code></pre>
<p>에서</p>
<pre><code class="language-text">Vertical

[Photo]</code></pre>
<p>처럼 바꿀 수 있습니다.</p>
<p>시스템 Container 안에서 Custom View를 사용하면서도 새로운 Duo UI에 적응할 수 있는 방법입니다.</p>
<hr>
<h1 id="overflow도-직접-만들지-않는-쪽이-좋아진다">Overflow도 직접 만들지 않는 쪽이 좋아진다</h1>
<p>오래된 Custom Toolbar를 보면 흔히</p>
<pre><code class="language-text">⋯</code></pre>
<p>버튼을 직접 만들고 Menu를 띄우는 코드가 있습니다.</p>
<p>Duo에서는 Bar 공간이 화면 상태에 따라 계속 달라질 수 있습니다.</p>
<p>따라서 어떤 Action이 Overflow로 이동해야 하는지를 직접 계산하기보다 시스템에 맡기는 편이 낫습니다.</p>
<p>SwiftUI에는</p>
<pre><code class="language-swift">ToolbarOverflowMenu {
    Button(&quot;Scan&quot;) {
        scan()
    }

    Button(&quot;Connect&quot;) {
        connect()
    }
}</code></pre>
<p>같은 방식이 있습니다.</p>
<p>중요한 Action에는</p>
<pre><code class="language-swift">.visibilityPriority(.high)</code></pre>
<p>를 줄 수도 있습니다.</p>
<p>즉 앞으로 Toolbar 설계는</p>
<pre><code class="language-text">어디에 놓을 것인가</code></pre>
<p>보다</p>
<pre><code class="language-text">무엇이 반드시 보여야 하는가</code></pre>
<p>를 시스템에 알려주는 방향으로 바뀝니다.</p>
<hr>
<h1 id="그래도-vertical-bar가-맞지-않는-앱도-있다">그래도 Vertical Bar가 맞지 않는 앱도 있다</h1>
<p>모든 앱이 Sidebar나 Vertical Toolbar를 사용해야 하는 것은 아닙니다.</p>
<p>예를 들어 Calculator처럼</p>
<pre><code class="language-text">화면 전체가 하나의 작업 공간
+
하단 Control이 중요한 앱</code></pre>
<p>이라면 Vertical Bar가 오히려 Layout을 방해할 수도 있습니다.</p>
<p>SwiftUI에서는</p>
<pre><code class="language-swift">.toolbarVerticalBehavior(.disabled)</code></pre>
<p>로 Vertical Bar를 끌 수 있습니다.</p>
<p>UIKit에서도 View Controller의</p>
<pre><code class="language-swift">override var preferredVerticalBarBehavior:
    UIVerticalBarBehavior {
    .disabled
}</code></pre>
<p>처럼 Opt-out이 가능합니다.</p>
<p>중요한 것은 새 UI를 무조건 사용하는 것이 아닙니다.</p>
<p><strong>시스템의 Adaptive Behavior를 이해한 뒤 앱에 맞게 선택하는 것</strong>입니다.</p>
<hr>
<h1 id="resizable-대응은-duo만-위한-작업이-아니다">Resizable 대응은 Duo만 위한 작업이 아니다</h1>
<p>Duo 때문에 Resizable이라는 단어가 더 눈에 띄지만 사실 이 문제는 이미 시작됐습니다.</p>
<p>iPhone 앱이</p>
<pre><code class="language-text">iPhone

iPhone Mirroring

iPad에서 실행

Duo

Split View</code></pre>
<p>등 다양한 공간에서 실행될 수 있기 때문입니다.</p>
<p>그래서 이제</p>
<pre><code class="language-swift">if UIDevice.current.userInterfaceIdiom == .phone</code></pre>
<p>만으로 Layout을 판단하는 것은 부족합니다.</p>
<p>같은 <code>.phone</code> 환경에서도 사용 가능한 Width는 크게 달라질 수 있습니다.</p>
<p>앞으로는</p>
<pre><code class="language-text">Device Type</code></pre>
<p>이 아니라</p>
<pre><code class="language-text">Available Space</code></pre>
<p>를 봐야 합니다.</p>
<hr>
<h1 id="resizable-대응에서-가장-먼저-없앨-코드">Resizable 대응에서 가장 먼저 없앨 코드</h1>
<p>기존 프로젝트에서 아래 코드를 검색해보면 좋습니다.</p>
<pre><code class="language-swift">UIScreen.main</code></pre>
<pre><code class="language-swift">UIDevice.current.userInterfaceIdiom</code></pre>
<pre><code class="language-swift">interfaceOrientation</code></pre>
<p>그리고</p>
<pre><code class="language-swift">.frame(width: 390)</code></pre>
<p>같은 고정 Layout도 확인해야 합니다.</p>
<p>물론 모두 잘못된 코드는 아닙니다.</p>
<p>문제는 <strong>Layout 결정의 핵심 기준으로 사용했을 때</strong>입니다.</p>
<p>대신</p>
<pre><code class="language-text">Size Class
Container Size
Safe Area
Trait Collection
Scene</code></pre>
<p>를 사용하도록 조금씩 옮기는 편이 좋습니다.</p>
<hr>
<h1 id="navigationsplitview도-이제-ipad-전용-api처럼-보면-안-된다">NavigationSplitView도 이제 iPad 전용 API처럼 보면 안 된다</h1>
<p>예전에는</p>
<pre><code class="language-swift">NavigationSplitView</code></pre>
<p>를 보면 사실상</p>
<pre><code class="language-text">iPad / macOS</code></pre>
<p>용이라고 생각하기 쉬웠습니다.</p>
<p>Duo에서는 상황이 달라졌습니다.</p>
<p>내부 화면은 충분한 공간을 제공하기 때문에</p>
<pre><code class="language-text">Sidebar
+
Detail</code></pre>
<p>구조가 자연스럽습니다.</p>
<p>SwiftUI라면</p>
<pre><code class="language-swift">NavigationSplitView {
    List {
        NavigationLink(
            &quot;Home&quot;,
            value: Destination.home
        )

        NavigationLink(
            &quot;Projects&quot;,
            value: Destination.projects
        )
    }
} detail: {
    DetailView()
}</code></pre>
<p>같은 구조를 iPhone에서도 고려할 수 있습니다.</p>
<p>외부 화면에서는 Single Column으로 Collapse되고,</p>
<p>넓은 환경에서는 Split Navigation으로 확장됩니다.</p>
<hr>
<h1 id="결국-ui가-아니라-information-architecture까지-바뀐다">결국 UI가 아니라 Information Architecture까지 바뀐다</h1>
<p>Duo 대응을 단순히</p>
<pre><code class="language-text">390pt 화면

↓

큰 화면</code></pre>
<p>으로 보면 부족합니다.</p>
<p>기존 iPhone에서는 화면 하단에</p>
<pre><code class="language-text">Home
Search
Profile
Settings</code></pre>
<p>정도만 보여줬다면,</p>
<p>Sidebar에서는</p>
<pre><code class="language-text">Home

Projects
 ├─ Active
 ├─ Recent
 └─ Archived

Favorites

Team
 ├─ Members
 └─ Shared

Settings</code></pre>
<p>같이 더 많은 Navigation Hierarchy를 보여줄 수 있습니다.</p>
<p>즉 문제는 Layout Resize만이 아닙니다.</p>
<p><strong>화면이 넓어졌을 때 Information Architecture 자체를 확장할 것인지</strong>를 생각해야 합니다.</p>
<hr>
<h1 id="기존-앱이라면-이렇게-마이그레이션하는-게-현실적이다">기존 앱이라면 이렇게 마이그레이션하는 게 현실적이다</h1>
<p>한 번에 SwiftUI로 다시 만드는 방식은 대부분 현실적이지 않습니다.</p>
<p>다음 정도의 순서가 안전합니다.</p>
<h3 id="1단계--custom-ui를-duo에서도-깨지지-않게-만든다">1단계 — Custom UI를 Duo에서도 깨지지 않게 만든다</h3>
<pre><code class="language-text">UIScreen.main 제거
Orientation 의존 제거
Safe Area 좌우 독립 처리
고정 Width 제거
Reserved Region 대응</code></pre>
<p>이 단계에서는 기존 디자인을 유지합니다.</p>
<hr>
<h3 id="2단계--navigation-state를-ui에서-분리한다">2단계 — Navigation State를 UI에서 분리한다</h3>
<pre><code class="language-text">Selected Tab
Navigation Path
Deep Link
Presentation State</code></pre>
<p>를 Custom View 내부에서 빼냅니다.</p>
<pre><code class="language-text">Navigation State
        ↓
Custom UI</code></pre>
<p>구조로 만듭니다.</p>
<hr>
<h3 id="3단계--system-container로-이동한다">3단계 — System Container로 이동한다</h3>
<p>UIKit이라면</p>
<pre><code class="language-text">UITabBarController
UINavigationController
UISplitViewController</code></pre>
<p>SwiftUI라면</p>
<pre><code class="language-text">TabView
NavigationStack
NavigationSplitView</code></pre>
<p>로 Container부터 교체합니다.</p>
<hr>
<h3 id="4단계--custom-control은-toolbar-item으로-옮긴다">4단계 — Custom Control은 Toolbar Item으로 옮긴다</h3>
<p>전체 Custom Navigation Bar를 유지하기보다 필요한 Custom UI만 남깁니다.</p>
<pre><code class="language-text">System Navigation
       +
Custom ToolbarItem</code></pre>
<p>구조입니다.</p>
<hr>
<h3 id="5단계--sidebar와-vertical-bar를-활성화한다">5단계 — Sidebar와 Vertical Bar를 활성화한다</h3>
<p>Duo나 Regular Width 환경에서</p>
<pre><code class="language-swift">.defaultTabBarPlacement(.sidebar)</code></pre>
<p>또는</p>
<pre><code class="language-swift">tabBarController
    .sidebar
    .preferredPlacement = .sidebar</code></pre>
<p>를 적용합니다.</p>
<p>Toolbar Item도 Vertical Axis에서 정상적으로 보이는지 확인합니다.</p>
<hr>
<h1 id="xcode-271에서는-devicehub로-반드시-확인하는-게-좋다">Xcode 27.1에서는 DeviceHub로 반드시 확인하는 게 좋다</h1>
<p>Duo는 Simulator를 한 번 띄우는 것으로 테스트가 끝나지 않습니다.</p>
<p>확인해야 할 상태가 많습니다.</p>
<pre><code class="language-text">Outer Display

Inner Display

Fully Open

Partially Folded

Portrait

Landscape

Split View</code></pre>
<p>Xcode 27.1의 DeviceHub에서는 Duo를 열고 닫고, 회전하고, Fold 상태를 바꾸면서 Layout을 확인할 수 있습니다.</p>
<p>Apple은 기존 App Modernization Skill도 Xcode 27.1에서 <strong>App Resizability</strong>라는 이름으로 확장했습니다.</p>
<p>SwiftUI와 iPhone Duo까지 분석 대상으로 포함됩니다.</p>
<p>오래된 프로젝트라면 이런 자동 분석을 이용해</p>
<pre><code class="language-text">Fixed Layout
Screen Assumption
Adaptive Layout 문제</code></pre>
<p>를 먼저 찾는 것도 좋은 시작점입니다.</p>
<hr>
<h1 id="지금-프로젝트에서-체크할-것">지금 프로젝트에서 체크할 것</h1>
<p>Duo 대응을 준비한다면 최소한 다음은 확인할 필요가 있습니다.</p>
<pre><code class="language-text">□ UIScreen.main으로 Layout을 계산하는가?

□ interfaceOrientation으로 UI 구조를 결정하는가?

□ Safe Area의 left/right가 같다고 가정하는가?

□ Custom Tab Bar가 화면 아래에 고정되어 있는가?

□ Custom Navigation Bar가 Safe Area를 직접 계산하는가?

□ Tab 선택 State가 Custom Tab Bar 내부에 묶여 있는가?

□ NavigationStack / UINavigationController로 옮길 수 있는가?

□ Regular Width에서 Sidebar가 더 자연스럽지 않은가?

□ Toolbar Custom View가 Vertical Axis에서도 사용할 수 있는가?

□ Overflow Menu를 직접 구현하고 있는가?

□ Duo Split View에서도 UI가 깨지지 않는가?</code></pre>
<p>여기에서 많이 걸린다고 해서 앱을 전부 다시 만들어야 한다는 의미는 아닙니다.</p>
<p>오히려 <strong>마이그레이션 우선순위를 잡을 수 있다는 의미</strong>입니다.</p>
<hr>
<h1 id="커스텀-ui가-문제라기보다-시스템과-단절된-ui가-문제다">커스텀 UI가 문제라기보다 시스템과 단절된 UI가 문제다</h1>
<p>이번 변화에서 가장 중요한 부분은 이것입니다.</p>
<p>Custom UI 자체가 나쁜 것은 아닙니다.</p>
<p>브랜드 경험이나 복잡한 Interaction 때문에 Custom Control이 반드시 필요한 앱도 있습니다.</p>
<p>문제가 되는 것은</p>
<pre><code class="language-text">Custom UI
+
Device 가정
+
Magic Number
+
직접 Safe Area 계산
+
Navigation State까지 결합</code></pre>
<p>된 구조입니다.</p>
<p>반대로</p>
<pre><code class="language-text">System Navigation Container
        +
Adaptive Layout
        +
Custom Content</code></pre>
<p>구조라면 Custom UI를 상당히 많이 유지하면서도 새로운 플랫폼 변화에 대응할 수 있습니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>iOS 27.1과 iPhone Duo가 나왔다고 해서 오래된 Custom Tab Bar와 Navigation을 당장 전부 버릴 필요는 없습니다.</p>
<p>Apple도 <code>ReservedRegion</code>과 <code>UIViewReservedRegion</code>을 추가하면서 <strong>Custom UI가 새로운 화면 환경에서 시스템 UI와 공존할 수 있는 방법</strong>을 제공하고 있습니다.</p>
<p>다만 앞으로의 방향은 분명합니다.</p>
<p>예전에는 앱이</p>
<pre><code class="language-text">화면 크기
Tab Bar 위치
Navigation 위치
Safe Area</code></pre>
<p>를 상당 부분 직접 결정할 수 있었습니다.</p>
<p>앞으로는</p>
<pre><code class="language-text">System Container
       ↓
Adaptive Navigation
       ↓
현재 사용 가능한 공간
       ↓
App Content</code></pre>
<p>구조가 훨씬 유리해집니다.</p>
<p>특히 Duo에서는</p>
<pre><code class="language-text">Bottom Tab Bar
        ↓
Sidebar

Horizontal Toolbar
        ↓
Vertical Toolbar

Single Column
        ↓
Split View</code></pre>
<p>처럼 같은 앱의 Navigation 표현 자체가 바뀔 수 있습니다.</p>
<p>이걸 Custom UI로 전부 직접 구현하는 것도 가능합니다.</p>
<p>하지만 계속 직접 따라가는 비용은 점점 커집니다.</p>
<p>그래서 오래된 프로젝트라면 가장 현실적인 전략은 하나입니다.</p>
<p><strong>디자인을 전부 버리는 것이 아니라 Navigation의 책임부터 시스템에 조금씩 돌려주는 것.</strong></p>
<p>Custom Tab Bar를 유지해야 한다면 먼저 Resizable과 Reserved Region에 대응하고,</p>
<p>그다음 Navigation State를 분리하고,</p>
<p>마지막으로 <code>TabView</code>, <code>UITabBarController</code>, <code>NavigationSplitView</code> 같은 System Container로 이동하면 됩니다.</p>
<p>iPhone Duo가 던지는 질문도 결국 폴더블 대응 하나로 끝나지 않습니다.</p>
<p><strong>다음에 또 다른 화면 형태가 나와도 지금의 Navigation 구조가 그대로 살아남을 수 있는가.</strong></p>
<p>이번 iOS 27.1은 오래된 Navigation 코드를 한 번 점검하기 좋은 시점입니다.</p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>Apple Developer — Prepare your app for iPhone Duo</strong><br>iPhone Duo의 Resizable Layout, Size Class, Safe Area, <code>UIScreen.main</code> 의존 문제, Sidebar와 표준 Navigation의 Adaptive 동작, Xcode 27.1 DeviceHub 테스트 방법 등을 확인할 수 있습니다.<br><a href="https://developer.apple.com/kr/videos/play/tech-talks/111461/?utm_source=chatgpt.com">Prepare your app for iPhone Duo</a></p>
</li>
<li><p><strong>Apple Developer — Raise the bar with iPhone Duo</strong><br>Duo의 Vertical Bar, Toolbar Item, Custom View, <code>axisBehavior</code>, Overflow, Visibility Priority 등 새로운 Navigation Bar 동작을 확인할 수 있습니다.<br><a href="https://developer.apple.com/kr/videos/play/tech-talks/111462/?utm_source=chatgpt.com">Raise the bar with iPhone Duo</a></p>
</li>
</ul>
<p><strong>Apple 공식 자료 기준으로 보면</strong>, iOS 27.1 SDK에서는 표준 Navigation과 Toolbar가 iPhone Duo의 새로운 화면 구조에 맞춰 더 적극적으로 적응합니다.</p>
<p><code>NavigationSplitView</code>, <code>UISplitViewController</code>, <code>TabView</code>, <code>UITabBarController</code> 같은 System Navigation Container를 사용하면 Duo의 화면 상태와 사용할 수 있는 공간에 따라 Navigation 표현을 변경하기가 훨씬 수월합니다.</p>
<p>내부 화면은 horizontal·vertical Size Class가 모두 <code>regular</code>이기 때문에 Sidebar를 사용할 수 있는 공간도 확보됩니다.</p>
<p>반대로 기존 앱에서 직접 만든</p>
<pre><code class="language-text">Custom Tab Bar
Custom Navigation Bar
Custom Toolbar</code></pre>
<p>는 같은 Adaptive Behavior를 자동으로 받을 수 있다고 가정하면 안 됩니다.</p>
<p>특히 다음 코드는 다시 확인할 필요가 있습니다.</p>
<pre><code class="language-swift">UIScreen.main</code></pre>
<pre><code class="language-swift">interfaceOrientation</code></pre>
<pre><code class="language-swift">.frame(width: 390)</code></pre>
<p>그리고</p>
<pre><code class="language-text">left Safe Area == right Safe Area</code></pre>
<p>같은 가정도 Duo에서는 안전하지 않습니다.</p>
<p>iOS 27.1의 <code>ReservedRegion</code>과 <code>UIViewReservedRegion</code>은 Custom Bar나 edge-to-edge UI를 당장 제거하기 어려운 앱에서 시스템 UI와 충돌하지 않도록 만드는 중요한 중간 대응책입니다.</p>
<p>또한 Apple은 Vertical Bar 내부에서도 Custom View를 사용할 수 있도록 <code>axisBehavior</code>, Vertical Bar 환경 정보, Overflow와 Visibility Priority 관련 기능을 제공하고 있습니다.</p>
<p>따라서 현실적인 Migration 방향은</p>
<pre><code class="language-text">Custom UI 전부 제거</code></pre>
<p>가 아니라</p>
<pre><code class="language-text">System Container
       +
필요한 Custom Content</code></pre>
<p>에 가깝습니다.</p>
<p>기존 Custom Tab Bar와 Navigation을 유지하면서 먼저 Resizable과 Safe Area에 대응하고, Navigation State를 UI에서 분리한 뒤 <code>TabView</code>, <code>UITabBarController</code>, <code>NavigationSplitView</code> 같은 시스템 Container로 단계적으로 옮기는 것이 가장 현실적인 접근입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI Agent의 UI는 채팅창이 아닐지도 모른다  ]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609121</link>
            <guid>https://velog.io/@kyu_ios_dev/2609121</guid>
            <pubDate>Sat, 12 Sep 2026 09:17:13 GMT</pubDate>
            <description><![CDATA[<h3 id="ai-agent의-ui는-채팅창이-아닐지도-모른다">AI Agent의 UI는 채팅창이 아닐지도 모른다</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/5d9c4f98-b0cc-4e90-b41c-f44d06ead867/image.png" alt=""></p>
<h2 id="aws-pizza-bot이-보여주는-long-running-agent의-새로운-ux">AWS Pizza Bot이 보여주는 Long-running Agent의 새로운 UX</h2>
<p>요즘 AI 앱을 열면 대부분 비슷한 화면이 나옵니다.</p>
<p>입력창이 있고, 메시지를 보내면 AI가 답합니다.</p>
<pre><code class="language-text">User
 ↓
Prompt
 ↓
AI
 ↓
Response</code></pre>
<p>ChatGPT 이후 너무 익숙해진 구조입니다.</p>
<p>짧은 질문을 하고 바로 답을 받는다면 이 방식이 잘 맞습니다.</p>
<p>문제는 Agent가 실제 일을 하기 시작하면서 생깁니다.</p>
<p>예를 들어 이런 요청입니다.</p>
<pre><code class="language-text">오늘 중요한 메일을 확인하고
관련 Slack 메시지도 찾아서
해야 할 일을 정리한 다음
필요한 후속 메일까지 작성해줘.</code></pre>
<p>Agent가 해야 할 일이 많습니다.</p>
<pre><code class="language-text">Email 확인
   ↓
Slack 확인
   ↓
Task 확인
   ↓
자료 분석
   ↓
결과 정리
   ↓
후속 작업 생성</code></pre>
<p>몇 초가 아니라 몇 분이 걸릴 수도 있습니다.</p>
<p>중간에 이런 상황도 생깁니다.</p>
<pre><code class="language-text">Agent

&quot;이 메일을 실제로 보내도 될까요?&quot;</code></pre>
<p>사용자의 승인이 필요합니다.</p>
<p>그동안 사람은 뭘 해야 할까요?</p>
<p>채팅창을 계속 보고 있어야 할까요?</p>
<p>AWS가 9월 10일 공개한 오픈소스 프로젝트 <strong>Pizza Bot</strong>은 바로 여기에서 시작합니다.</p>
<p>핵심 아이디어는 단순합니다.</p>
<blockquote>
<p>Agent가 오래 일한다면 사용자가 채팅창에서 기다릴 이유가 없다.</p>
</blockquote>
<p>그래서 Pizza Bot은 Agent UI를 Chat이 아니라 <strong>Email Inbox처럼 만들었습니다.</strong></p>
<hr>
<h1 id="지금의-ai-ui는-사람이-agent를-기다리게-만든다">지금의 AI UI는 사람이 Agent를 기다리게 만든다</h1>
<p>현재 대부분의 AI Agent UI는 기본적으로 synchronous interaction을 가정합니다.</p>
<pre><code class="language-text">User
 ↓
Request
 ↓
Wait
 ↓
Agent
 ↓
Response</code></pre>
<p>개발 도구에서도 크게 다르지 않습니다.</p>
<p>Terminal에서 Agent를 실행하면 로그가 계속 올라옵니다.</p>
<pre><code class="language-text">Reading files...
Searching repository...
Running tests...
Fixing error...
Running tests again...</code></pre>
<p>처음에는 재미있습니다.</p>
<p>AI가 실제로 일하는 모습이 보이기 때문입니다.</p>
<p>하지만 작업 시간이 길어질수록 문제가 생깁니다.</p>
<pre><code class="language-text">3초
10초
30초
2분
10분
30분</code></pre>
<p>Agent가 정말 일을 대신해주는 것인지,</p>
<p>사람이 Agent가 일하는 모습을 지켜보는 것인지 애매해집니다.</p>
<p>AWS는 Pizza Bot 발표에서 이 상황을 상당히 직설적으로 표현했습니다.</p>
<p><strong>이건 collaboration보다 babysitting에 가깝다는 것입니다.</strong></p>
<p>Agent에게 일을 맡겼는데 계속 화면을 보고 있어야 한다면 자동화의 의미가 줄어듭니다.</p>
<hr>
<h1 id="email에서는-답장이-올-때까지-outbox를-보고-있지-않는다">Email에서는 답장이 올 때까지 Outbox를 보고 있지 않는다</h1>
<p>Pizza Bot의 아이디어가 재미있는 이유는 새로운 UI를 발명하지 않았기 때문입니다.</p>
<p>이미 수십 년 동안 사용해온 <strong>Email의 작업 방식</strong>을 가져왔습니다.</p>
<p>메일을 보낼 때 이런 행동을 하지는 않습니다.</p>
<pre><code class="language-text">Send
 ↓
Outbox 열기
 ↓
계속 새로고침
 ↓
답장 기다리기</code></pre>
<p>메일을 보낸 다음 다른 일을 합니다.</p>
<p>답장이 오면 알림을 받고 다시 확인합니다.</p>
<p>Pizza Bot은 Agent도 그렇게 사용해야 한다고 봅니다.</p>
<pre><code class="language-text">Task 전달
   ↓
Agent 작업 시작
   ↓
사용자는 다른 일
   ↓
완료 또는 승인 필요
   ↓
Inbox에 도착</code></pre>
<p>즉 핵심 변화는 이것입니다.</p>
<pre><code class="language-text">Chat

Stay here</code></pre>
<p>에서</p>
<pre><code class="language-text">Inbox

Come back later</code></pre>
<p>로 바뀝니다.</p>
<hr>
<h1 id="conversation-대신-thread가-작업의-단위가-된다">Conversation 대신 Thread가 작업의 단위가 된다</h1>
<p>일반적인 AI Chat에서는 Session이 중요합니다.</p>
<pre><code class="language-text">Chat Session

Message
Message
Message
Message</code></pre>
<p>브라우저를 닫거나 Session이 끝나면 작업도 사실상 끝난다고 생각하기 쉽습니다.</p>
<p>Pizza Bot에서는 <strong>Thread 자체가 지속되는 작업 공간</strong>입니다.</p>
<p>Thread 안에는 단순 대화 내용만 있는 것이 아닙니다.</p>
<pre><code class="language-text">Thread

├─ Messages
├─ Agent State
├─ Tool Activity
├─ Checkpoints
├─ Attachments
└─ Approval State</code></pre>
<p>가 함께 저장됩니다.</p>
<p>Agent가 중간까지 작업하다가 사람의 승인을 기다리는 상황도 Thread 상태에 포함됩니다.</p>
<pre><code class="language-text">Running
   ↓
Need Approval
   ↓
Paused
   ↓
User Approves
   ↓
Resume
   ↓
Completed</code></pre>
<p>이 상태가 메모리에만 존재하지 않습니다.</p>
<p>Disk에 checkpoint가 저장됩니다.</p>
<p>그래서 한 시간 뒤 다시 돌아와도 작업을 이어갈 수 있습니다.</p>
<hr>
<h1 id="pizza-bot의-inbox는-세-가지-queue로-나뉜다">Pizza Bot의 Inbox는 세 가지 Queue로 나뉜다</h1>
<p>Pizza Bot의 UI는 Email Client와 비슷합니다.</p>
<p>중심에는 세 가지 Queue가 있습니다.</p>
<pre><code class="language-text">All

전체 Thread</code></pre>
<pre><code class="language-text">Unread

완료됐지만
아직 확인하지 않은 작업</code></pre>
<pre><code class="language-text">Action

사람의 결정이나
승인을 기다리는 작업</code></pre>
<p>여기서 가장 흥미로운 것은 <strong>Action</strong>입니다.</p>
<p>보통 Agent UI에서는 승인을 요청하면 현재 대화 중간에 이런 메시지가 나옵니다.</p>
<pre><code class="language-text">Agent:

메일을 보내려고 합니다.

Approve?</code></pre>
<p>문제는 사람이 그 순간 자리에 없을 수도 있다는 것입니다.</p>
<p>Pizza Bot에서는 Agent가 멈춘 뒤 Action Queue로 들어갑니다.</p>
<pre><code class="language-text">Agent
 ↓
Tool 실행 필요
 ↓
Approval Required
 ↓
Action Queue</code></pre>
<p>사용자는 나중에 Action Queue를 열어서 판단합니다.</p>
<pre><code class="language-text">Approve
Edit
Reject</code></pre>
<p>그리고 Agent는 그 지점부터 다시 작업을 이어갑니다.</p>
<hr>
<h1 id="agent-ux에서는-waiting도-정상적인-상태다">Agent UX에서는 Waiting도 정상적인 상태다</h1>
<p>기존 Software에서는 작업이 멈추면 보통 문제라고 생각합니다.</p>
<pre><code class="language-text">Running
 ↓
Success

or

Running
 ↓
Failure</code></pre>
<p>하지만 Agent 시스템에서는 상태가 하나 더 필요합니다.</p>
<pre><code class="language-text">Running
 ↓
Waiting for Human
 ↓
Running
 ↓
Completed</code></pre>
<p>이게 중요합니다.</p>
<p>AI Agent에게 모든 권한을 주면 위험하고,</p>
<p>모든 작업마다 승인을 요구하면 자동화가 의미 없습니다.</p>
<p>그래서 Agent Workflow에서는 <strong>Human-in-the-loop가 어디에 들어갈지</strong>가 중요합니다.</p>
<p>예를 들어 이런 식입니다.</p>
<pre><code class="language-text">메일 읽기
   ↓
자동 허용

문서 요약
   ↓
자동 허용

CRM 정보 조회
   ↓
자동 허용

CRM 수정
   ↓
승인 필요

외부 메일 발송
   ↓
승인 필요</code></pre>
<p>Pizza Bot의 Skill에서는 Tool별로 이런 Approval Policy를 지정할 수 있습니다.</p>
<p>Agent UX가 단순 Chat UX보다 Workflow Engine에 가까워지는 이유입니다.</p>
<hr>
<h1 id="거절만-있는-것이-아니라-edit도-있다">거절만 있는 것이 아니라 Edit도 있다</h1>
<p>Approval UX에서 눈여겨볼 부분이 하나 더 있습니다.</p>
<p>보통 Agent 승인 UI는 이렇습니다.</p>
<pre><code class="language-text">Approve

Reject</code></pre>
<p>하지만 실제 업무에서는 둘 사이가 필요합니다.</p>
<p>예를 들어 Agent가 이런 메일을 보내려고 합니다.</p>
<pre><code class="language-text">To: client@example.com

Meeting confirmed for 3 PM.</code></pre>
<p>시간만 4시로 바꾸고 싶다고 해보겠습니다.</p>
<p>기존 방식이라면</p>
<pre><code class="language-text">Reject
 ↓
Agent에게 다시 설명
 ↓
새 결과 생성
 ↓
다시 승인</code></pre>
<p>해야 합니다.</p>
<p>Pizza Bot은 <code>edit</code> 결정을 지원합니다.</p>
<pre><code class="language-text">Approve
Edit
Reject</code></pre>
<p>즉 Agent가 제안한 Action 자체를 사람이 수정해서 실행할 수 있습니다.</p>
<p>Long-running Agent에서 꽤 중요한 UX입니다.</p>
<p>사람은 Agent의 결과를 처음부터 다시 만들 필요 없이 <strong>마지막 판단만 수정</strong>하면 됩니다.</p>
<hr>
<h1 id="agent는-background에서-계속-실행된다">Agent는 Background에서 계속 실행된다</h1>
<p>Pizza Bot은 Client와 Agent Runtime을 분리합니다.</p>
<p>구조는 대략 이렇습니다.</p>
<pre><code class="language-text">Electron App ─┐
Browser      ──┤
Mobile Web   ──┼── HTTP ── Pizza Bot Server
Terminal     ──┘
                        │
                        ↓
                 Agent Runtime
                        │
            ┌───────────┼───────────┐
            ↓           ↓           ↓
         SQLite       Files       MCP</code></pre>
<p>Server가 Agent의 상태를 가지고 있습니다.</p>
<p>따라서 Browser를 닫거나 다른 Device로 이동해도 Server가 살아 있다면 Agent 작업은 계속됩니다.</p>
<pre><code class="language-text">Laptop

Task 시작
   ↓

Laptop 닫음
   ↓

Agent 계속 작업
   ↓

Phone

결과 확인</code></pre>
<p>이런 구조가 가능합니다.</p>
<p>Agent가 UI 안에서 실행되는 것이 아니라 <strong>독립적인 Background Worker처럼 실행</strong>되는 것입니다.</p>
<hr>
<h1 id="모바일-앱에서는-이-구조가-더-자연스럽다">모바일 앱에서는 이 구조가 더 자연스럽다</h1>
<p>이 부분은 모바일 앱 개발자에게 특히 흥미롭습니다.</p>
<p>모바일에서는 사용자가 하나의 화면을 몇 분씩 보고 있는 경우가 많지 않습니다.</p>
<p>예를 들어 AI 여행 앱에서 이런 작업을 요청했다고 해보겠습니다.</p>
<pre><code class="language-text">서울에서 오사카로
다음 주말 여행할 건데

항공편 찾아보고
호텔 비교하고
동선까지 정리해줘.</code></pre>
<p>현재 Chat 방식이라면</p>
<pre><code class="language-text">Prompt
 ↓
Loading
 ↓
Agent working...
 ↓
Agent working...
 ↓
Result</code></pre>
<p>입니다.</p>
<p>하지만 모바일에 더 자연스러운 구조는 이럴 수 있습니다.</p>
<pre><code class="language-text">Task 생성
   ↓
앱 닫기
   ↓
Agent Background Processing
   ↓
Push Notification

&quot;여행 계획이 준비됐습니다.&quot;
   ↓
결과 확인</code></pre>
<p>중간에 승인이 필요하다면</p>
<pre><code class="language-text">Push Notification

&quot;호텔 예약 전에 확인이 필요합니다.&quot;</code></pre>
<p>이 옵니다.</p>
<p>그리고 앱을 열면</p>
<pre><code class="language-text">Action Required</code></pre>
<p>화면으로 바로 이동합니다.</p>
<p>Pizza Bot의 Inbox 구조와 거의 같습니다.</p>
<hr>
<h1 id="agent-앱은-chat-app보다-task-manager에-가까워질-수-있다">Agent 앱은 Chat App보다 Task Manager에 가까워질 수 있다</h1>
<p>지금 AI App 디자인을 보면 대부분 ChatGPT를 참고합니다.</p>
<pre><code class="language-text">Sidebar
Conversation
Input Field
Send Button</code></pre>
<p>하지만 Agent가 실제 업무를 수행하기 시작하면 더 자연스러운 UI는 이런 형태일 수 있습니다.</p>
<pre><code class="language-text">Tasks

────────────────────

● 코드 리뷰 완료
  3분 전

● 여행 계획 완료
  12분 전

! 계약서 전송 승인 필요
  Action Required

○ 경쟁사 조사 중
  Running

○ 매일 오전 뉴스 요약
  Scheduled</code></pre>
<p>Chat이라기보다</p>
<pre><code class="language-text">Inbox
+
Task Manager
+
Notification Center</code></pre>
<p>에 가깝습니다.</p>
<p>여기에 Agent 상태가 붙습니다.</p>
<pre><code class="language-text">Queued
Running
Waiting
Completed
Failed</code></pre>
<p>실제로 Agent 앱을 만든다면 <code>Message</code>보다 <code>Task</code>가 Domain Model의 중심이 될 수 있습니다.</p>
<hr>
<h1 id="앱-architecture도-달라진다">앱 Architecture도 달라진다</h1>
<p>Chat 기반 AI 앱의 상태는 비교적 단순합니다.</p>
<pre><code class="language-swift">enum ChatState {
    case idle
    case generating
    case completed
    case failed
}</code></pre>
<p>하지만 Long-running Agent를 앱에 넣는다면 상태가 훨씬 많아집니다.</p>
<p>개념적으로는 이런 모델이 필요할 수 있습니다.</p>
<pre><code class="language-swift">enum AgentTaskState {
    case queued
    case running
    case waitingForApproval
    case completed
    case failed
}</code></pre>
<p>그리고 Task 자체가 지속돼야 합니다.</p>
<pre><code class="language-swift">struct AgentTask: Identifiable {
    let id: UUID
    let title: String
    let state: AgentTaskState
    let createdAt: Date
}</code></pre>
<p>UI도 상태별로 달라집니다.</p>
<pre><code class="language-text">.running

Progress UI</code></pre>
<pre><code class="language-text">.waitingForApproval

Approve / Edit / Reject</code></pre>
<pre><code class="language-text">.completed

Result</code></pre>
<p>이렇게 보면 Agent App은 Chat UI보다 <strong>State Machine UI</strong>에 더 가깝습니다.</p>
<hr>
<h1 id="background-agent에는-persistence가-필수다">Background Agent에는 Persistence가 필수다</h1>
<p>Long-running Agent에서 중요한 것은 모델 성능만이 아닙니다.</p>
<p>Agent가 30분 동안 작업한다고 생각해보겠습니다.</p>
<pre><code class="language-text">Step 1 완료
Step 2 완료
Step 3 완료
Step 4 실행 중</code></pre>
<p>여기서 Process가 죽으면 어떻게 될까요?</p>
<p>처음부터 다시 실행한다면 실용성이 떨어집니다.</p>
<p>그래서 Agent Runtime에는 <strong>Checkpoint</strong>가 필요합니다.</p>
<p>Pizza Bot도 이 부분을 중요하게 다룹니다.</p>
<p>내부적으로 DeepAgents와 LangGraph 기반의 stateful agent runtime을 사용하며 작업 과정이 계속 checkpoint됩니다.</p>
<pre><code class="language-text">Task

Step 1
 ↓
Checkpoint

Step 2
 ↓
Checkpoint

Approval
 ↓
Checkpoint

Step 3</code></pre>
<p>Agent가 멈춰도 이전 상태부터 이어갈 수 있습니다.</p>
<p>이제 Agent Backend를 설계할 때 Database에 저장해야 하는 것이 단순 Chat History만은 아닙니다.</p>
<pre><code class="language-text">Conversation

+

Task State

+

Tool Calls

+

Checkpoint

+

Approval

+

Artifact</code></pre>
<p>까지 포함됩니다.</p>
<hr>
<h1 id="scheduled-agent가-되면-chat-ui는-더-어색해진다">Scheduled Agent가 되면 Chat UI는 더 어색해진다</h1>
<p>Pizza Bot은 Task를 직접 만드는 것뿐 아니라 Schedule이나 Webhook으로 시작할 수 있습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">매일 08:00

메일 확인
 ↓
Slack 확인
 ↓
오늘 중요한 일 정리</code></pre>
<p>를 실행할 수 있습니다.</p>
<p>사용자가 Prompt를 보내지 않았습니다.</p>
<p>그래도 Agent는 작업합니다.</p>
<pre><code class="language-text">Cron
 ↓
Agent
 ↓
Result
 ↓
Inbox</code></pre>
<p>Webhook도 비슷합니다.</p>
<pre><code class="language-text">GitHub PR 생성
 ↓
Webhook
 ↓
Agent Code Review
 ↓
Inbox</code></pre>
<p>이쯤 되면 Chat이라는 UI가 더 이상 중심이 아닙니다.</p>
<p>Agent를 시작하는 Trigger가</p>
<pre><code class="language-text">User Prompt
Schedule
Webhook
Event</code></pre>
<p>로 늘어나기 때문입니다.</p>
<p>결과를 보여주는 곳도 자연스럽게 <strong>Inbox</strong>가 됩니다.</p>
<hr>
<h1 id="notification이-agent-ux의-핵심이-될-수-있다">Notification이 Agent UX의 핵심이 될 수 있다</h1>
<p>Background Agent가 일반화되면 Notification의 의미도 바뀝니다.</p>
<p>지금 Notification은 주로</p>
<pre><code class="language-text">새 메시지
새 댓글
배송 상태</code></pre>
<p>를 알려줍니다.</p>
<p>Agent App에서는</p>
<pre><code class="language-text">작업 완료</code></pre>
<p>뿐 아니라</p>
<pre><code class="language-text">사람의 판단 필요</code></pre>
<p>도 알려줘야 합니다.</p>
<p>예를 들면 이런 Push가 가능합니다.</p>
<pre><code class="language-text">AI Assistant

경쟁사 분석이 완료됐습니다.</code></pre>
<p>또는</p>
<pre><code class="language-text">AI Assistant

고객에게 메일을 보내기 전에
승인이 필요합니다.</code></pre>
<p>Notification을 누르면 해당 Task의 정확한 상태로 Deep Link됩니다.</p>
<pre><code class="language-text">Push
 ↓
Task ID
 ↓
Action Screen</code></pre>
<p>Agent 앱에서 Notification은 부가 기능이 아니라 <strong>주요 Interaction Channel</strong>이 될 가능성이 큽니다.</p>
<hr>
<h1 id="pizza-bot도-main-agent와-specialist를-나눈다">Pizza Bot도 Main Agent와 Specialist를 나눈다</h1>
<p>Pizza Bot에서는 사용자가 이야기하는 Main Agent가 Generalist 역할을 합니다.</p>
<p>그리고 특정 작업은 Skill 기반 Specialist Worker에게 넘길 수 있습니다.</p>
<pre><code class="language-text">Main Agent
    │
    ├─ Meeting Specialist
    │
    ├─ Browser Specialist
    │
    └─ Research Specialist</code></pre>
<p>각 Specialist는 별도 Instruction과 제한된 Tool 목록을 갖습니다.</p>
<p>예를 들어 Browser Automation Agent에는 Browser Tool만 주는 식입니다.</p>
<pre><code class="language-text">Browser Specialist

Allowed Tools

├─ navigate
├─ click
├─ type
└─ screenshot</code></pre>
<p>CRM Agent라면</p>
<pre><code class="language-text">CRM Specialist

Allowed Tools

├─ readCustomer
├─ readDeal
└─ updateDeal</code></pre>
<p>처럼 구성할 수 있습니다.</p>
<p>Agent마다 사용할 수 있는 Tool 범위를 줄이면 두 가지 장점이 있습니다.</p>
<pre><code class="language-text">Context ↓

Permission Surface ↓</code></pre>
<p>Agent가 무엇을 할 수 있는지도 확인하기 쉬워집니다.</p>
<hr>
<h1 id="mcp와-skill을-그대로-활용한다">MCP와 Skill을 그대로 활용한다</h1>
<p>Pizza Bot은 새로운 Tool Extension 규격을 따로 만들지 않았습니다.</p>
<p>외부 Tool은 <strong>MCP</strong>로 연결합니다.</p>
<pre><code class="language-text">Pizza Bot
    ↓
MCP
    ↓
Calendar
Slack
CRM
Browser
GitHub</code></pre>
<p>Specialist의 동작 방식은 <code>SKILL.md</code>로 정의할 수 있습니다.</p>
<p>개념적으로 보면 이런 구조입니다.</p>
<pre><code class="language-text">skill
 ├─ instructions
 ├─ tools
 └─ approval policy</code></pre>
<p>Agent가 새로운 기능을 필요로 할 때 Core Application을 계속 수정하는 방식보다,</p>
<pre><code class="language-text">Skill
+
MCP Server</code></pre>
<p>를 추가하는 구조입니다.</p>
<p>최근 Agent 생태계에서 Plugin Architecture가 어느 방향으로 정리되고 있는지도 볼 수 있는 부분입니다.</p>
<hr>
<h1 id="tool-permission도-agent-ux와-연결된다">Tool Permission도 Agent UX와 연결된다</h1>
<p>Agent가 실제 업무를 하면 결국 권한 문제가 생깁니다.</p>
<p>Pizza Bot에서는 기본적으로 사용자의 Disk 전체에 바로 접근할 수 없습니다.</p>
<p>Folder 접근도 사용자가 직접 허용해야 합니다.</p>
<pre><code class="language-text">Folder

Read Only

or

Read + Write</code></pre>
<p>MCP Tool도 마찬가지입니다.</p>
<p>특정 Skill에서 어떤 Tool을 사용할 수 있는지 제한할 수 있습니다.</p>
<p>그리고 위험한 작업에는 Approval을 붙일 수 있습니다.</p>
<pre><code class="language-text">Read

Auto</code></pre>
<pre><code class="language-text">Write

Approval</code></pre>
<pre><code class="language-text">Delete

Approval</code></pre>
<p>즉 Agent Security와 Agent UX가 따로 존재하지 않습니다.</p>
<p><strong>권한 정책이 UI에 그대로 나타납니다.</strong></p>
<p>Action Queue가 그 대표적인 결과입니다.</p>
<hr>
<h1 id="self-hosted라는-점도-의미가-있다">Self-hosted라는 점도 의미가 있다</h1>
<p>Pizza Bot은 AWS의 Hosted Service가 아닙니다.</p>
<p>오픈소스 Community Project이고 Self-hosted 방식입니다.</p>
<p>Telemetry도 없으며 데이터는 기본적으로 사용자가 관리하는 환경에 저장됩니다.</p>
<p>Model Provider도 선택할 수 있습니다.</p>
<pre><code class="language-text">Anthropic
Amazon Bedrock
Google Gemini
OpenAI
OpenRouter
Ollama</code></pre>
<p>Local Model도 가능합니다.</p>
<p>구조적으로 보면 Agent Runtime과 Model Provider가 분리돼 있습니다.</p>
<pre><code class="language-text">Pizza Bot
     ↓
Agent Runtime
     ↓
Provider Interface
     ↓
┌────────┬────────┬────────┐
Claude  Gemini  OpenAI  Local</code></pre>
<p>Agent Application이 특정 모델 하나에 종속될 필요가 없다는 의미입니다.</p>
<p>최근 Agent Architecture에서 계속 보이는 흐름이기도 합니다.</p>
<p><strong>Model보다 Runtime과 Workflow가 위에 놓이기 시작하고 있습니다.</strong></p>
<hr>
<h1 id="amazon-내부에서는-이미-2000명-이상이-사용했다">Amazon 내부에서는 이미 2,000명 이상이 사용했다</h1>
<p>Pizza Bot은 갑자기 만들어진 실험 프로젝트는 아닙니다.</p>
<p>이전 버전은 Amazon 내부에서 사용됐고, AWS에 따르면 <strong>2,000명 이상</strong>이 사용했습니다.</p>
<p>활용 사례도 개발 업무에만 한정되지 않았습니다.</p>
<pre><code class="language-text">Meeting 준비

Follow-up

Email 작성

Slack 요약

CRM 기록

하루 업무 우선순위 정리

Web Research</code></pre>
<p>같은 작업에 사용됐습니다.</p>
<p>즉 Pizza Bot이 해결하려는 문제는 Coding Agent만의 문제가 아닙니다.</p>
<p><strong>시간이 오래 걸리는 모든 Agent Task의 Interaction 방식</strong>에 대한 실험에 가깝습니다.</p>
<hr>
<h1 id="모든-ai-앱에-inbox가-필요한-것은-아니다">모든 AI 앱에 Inbox가 필요한 것은 아니다</h1>
<p>그렇다고 Chat UI가 잘못됐다는 이야기는 아닙니다.</p>
<p>질문의 성격에 따라 다릅니다.</p>
<p>짧은 Interaction이라면 Chat이 훨씬 좋습니다.</p>
<pre><code class="language-text">이 코드 설명해줘.

이 문장 번역해줘.

Swift Actor가 뭐야?</code></pre>
<p>이런 요청은</p>
<pre><code class="language-text">Prompt
 ↓
Immediate Response</code></pre>
<p>가 자연스럽습니다.</p>
<p>반면 이런 요청은 다릅니다.</p>
<pre><code class="language-text">Repository 전체를 분석해서
Architecture 문제를 찾아줘.</code></pre>
<pre><code class="language-text">이번 주 경쟁사 뉴스를 조사하고
보고서 만들어줘.</code></pre>
<pre><code class="language-text">메일과 Slack을 확인해서
오늘 해야 할 일을 정리해줘.</code></pre>
<p>이런 작업은</p>
<pre><code class="language-text">Task
 ↓
Background Work
 ↓
Notification
 ↓
Result</code></pre>
<p>구조가 더 자연스럽습니다.</p>
<p>결국 Agent App에서는 두 가지 UI가 같이 존재할 가능성이 큽니다.</p>
<pre><code class="language-text">Quick Interaction

Chat</code></pre>
<pre><code class="language-text">Long-running Work

Inbox / Task</code></pre>
<hr>
<h1 id="ai-앱을-만들-때-먼저-물어봐야-할-질문">AI 앱을 만들 때 먼저 물어봐야 할 질문</h1>
<p>최근 AI 기능을 앱에 넣을 때 가장 먼저 만드는 화면은 흔히 Chat입니다.</p>
<p>하지만 앞으로는 먼저 다른 질문을 해볼 필요가 있습니다.</p>
<pre><code class="language-text">이 작업은 몇 초 안에 끝나는가?</code></pre>
<p>몇 초라면 Chat이 좋습니다.</p>
<pre><code class="language-text">사용자의 승인이 중간에 필요한가?</code></pre>
<p>필요하다면 Task 상태 관리가 필요합니다.</p>
<pre><code class="language-text">앱을 닫아도 계속 실행돼야 하는가?</code></pre>
<p>그렇다면 Backend Agent Runtime이 필요합니다.</p>
<pre><code class="language-text">Schedule이나 Event로 자동 실행되는가?</code></pre>
<p>그렇다면 Chat보다 Inbox가 더 중요해집니다.</p>
<p>즉 UI를 결정하기 전에 <strong>Agent의 실행 모델부터 결정해야 합니다.</strong></p>
<hr>
<h1 id="long-running-agent의-구조는-이런-모습에-가까워진다">Long-running Agent의 구조는 이런 모습에 가까워진다</h1>
<p>Pizza Bot의 아이디어를 일반적인 Agent 앱 Architecture로 바꿔보면 이런 형태입니다.</p>
<pre><code class="language-text">                 Trigger
                    │
        ┌───────────┼───────────┐
        │           │           │
      User       Schedule    Webhook
        │           │           │
        └───────────┼───────────┘
                    ↓
               Agent Task
                    ↓
               Agent Runtime
                    ↓
           ┌────────┴────────┐
           │                 │
       Tool Calls        Specialist
           │                 │
           └────────┬────────┘
                    ↓
                 State
                    ↓
       ┌────────────┼────────────┐
       │            │            │
    Running       Action      Completed
                     │            │
                     ↓            ↓
                 Approval       Unread</code></pre>
<p>여기에서 Chat은 전체 시스템의 일부일 뿐입니다.</p>
<p>Agent Application의 중심은</p>
<pre><code class="language-text">Task
State
Trigger
Tool
Approval
Notification</code></pre>
<p>입니다.</p>
<p>이 변화가 중요한 이유입니다.</p>
<hr>
<h1 id="모바일-agent-앱이라면-더-고민해볼-만하다">모바일 Agent 앱이라면 더 고민해볼 만하다</h1>
<p>iOS 앱으로 생각하면 구조가 더 명확해집니다.</p>
<p>사용자가 Agent Task를 생성합니다.</p>
<pre><code class="language-swift">struct AgentTask: Identifiable, Codable {
    let id: UUID
    let title: String
    var state: State

    enum State: String, Codable {
        case queued
        case running
        case waitingForApproval
        case completed
        case failed
    }
}</code></pre>
<p>Server에서는 Agent가 계속 작업합니다.</p>
<p>상태가 바뀌면 Push Notification을 보냅니다.</p>
<pre><code class="language-text">Server
 ↓
Task State Changed
 ↓
APNs
 ↓
iPhone</code></pre>
<p>앱에서는 상태에 따라 다른 화면을 보여줍니다.</p>
<pre><code class="language-swift">switch task.state {
case .running:
    ProgressView()

case .waitingForApproval:
    ApprovalView(task: task)

case .completed:
    ResultView(task: task)

default:
    EmptyView()
}</code></pre>
<p>이렇게 보면 AI Agent 앱은 기존 Chat App보다 오히려</p>
<p><strong>Background Job Management App</strong></p>
<p>에 더 가까워집니다.</p>
<hr>
<h1 id="결국-agent의-ux는-대화보다-위임에-가까워지고-있다">결국 Agent의 UX는 ‘대화’보다 ‘위임’에 가까워지고 있다</h1>
<p>지금까지 AI는 주로 대화 상대였습니다.</p>
<pre><code class="language-text">Ask
 ↓
Answer</code></pre>
<p>Agent는 조금 다릅니다.</p>
<pre><code class="language-text">Delegate
 ↓
Work
 ↓
Report</code></pre>
<p>사람 사이에서도 이 두 방식은 다릅니다.</p>
<p>옆자리 동료에게 간단히 질문할 때는 바로 대화합니다.</p>
<p>하지만 몇 시간 걸리는 일을 맡길 때는 계속 옆에서 지켜보지 않습니다.</p>
<pre><code class="language-text">이거 조사해줘.

↓

다 되면 알려줘.</code></pre>
<p>Agent도 실제 업무를 맡기기 시작하면 같은 UX가 필요해집니다.</p>
<p>그래서 Pizza Bot에서 가장 흥미로운 것은 어떤 모델을 사용하는지도, 새로운 Agent Algorithm도 아닙니다.</p>
<p><strong>사용자가 Agent를 계속 보고 있지 않는다는 것을 처음부터 전제로 UI를 설계했다는 점</strong>입니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>Chat은 AI 시대의 첫 번째 Interface였습니다.</p>
<p>빠르게 질문하고 빠르게 답을 받는 데는 여전히 가장 좋은 방식입니다.</p>
<p>하지만 Agent가</p>
<pre><code class="language-text">검색하고

파일을 읽고

여러 Tool을 호출하고

다른 Agent에게 일을 나누고

사람의 승인을 기다리고

몇 분 또는 몇 시간 동안 작업하고

Schedule에 따라 다시 실행되는</code></pre>
<p>단계까지 오면 이야기가 달라집니다.</p>
<p>그런 작업을 작은 채팅창 안에서 계속 지켜보는 것은 자연스럽지 않습니다.</p>
<p>Pizza Bot이 제안하는 방식은 훨씬 단순합니다.</p>
<pre><code class="language-text">일을 맡긴다.

↓

다른 일을 한다.

↓

끝났거나
내 판단이 필요할 때
Agent가 다시 찾아온다.</code></pre>
<p>결국 Long-running Agent에서 중요한 UI는 입력창이 아니라</p>
<p><strong>Inbox, Task State, Approval, Notification</strong></p>
<p>일 수 있습니다.</p>
<p>앞으로 AI 앱을 만들 때도</p>
<blockquote>
<p>Chat 화면을 어떻게 만들까?</p>
</blockquote>
<p>보다 먼저 물어볼 질문이 하나 생겼습니다.</p>
<p><strong>이 작업을 사용자가 끝날 때까지 보고 있어야 할 이유가 있는가?</strong></p>
<p>답이 <code>아니오</code>라면, 그 앱은 Chat보다 Inbox에 가까워지는 편이 더 자연스러울 수 있습니다.</p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><p><strong>AWS Open Source Blog — Introducing Pizza Bot, an open source inbox for AI agents that work in the background</strong><br>Pizza Bot의 Inbox 중심 UI, Background Agent, Unread/Action Queue, Schedule, Webhook, Self-hosted 구조를 설명한 공식 발표입니다.<br><a href="https://aws.amazon.com/blogs/opensource/introducing-pizza-bot-an-open-source-inbox-for-ai-agents-that-work-in-the-background/?utm_source=chatgpt.com">AWS Pizza Bot 공식 발표</a></p>
</li>
<li><p><strong>AWS Open Source Blog</strong><br>Pizza Bot을 포함해 AWS가 공개하는 Agent, MCP, Open Source 관련 후속 자료를 확인할 수 있습니다.<br><a href="https://aws.amazon.com/blogs/opensource/?utm_source=chatgpt.com">AWS Open Source Blog</a></p>
</li>
</ul>
<p><strong>AWS 공식 자료 기준으로 보면</strong>, Pizza Bot에서 가장 중요한 것은 새로운 AI 모델이 아니라 <strong>Agent와 사용자가 상호작용하는 방법을 바꿨다는 점</strong>입니다.</p>
<p>사용자가 Agent에게 작업을 맡긴 뒤 Chat 화면에서 계속 기다리는 대신 Agent는 Background에서 작업합니다.</p>
<pre><code class="language-text">Task 생성
   ↓
Background Agent
   ↓
작업 완료
   ↓
Unread</code></pre>
<p>사람의 판단이 필요하면</p>
<pre><code class="language-text">Agent
   ↓
Approval Required
   ↓
Action</code></pre>
<p>으로 이동합니다.</p>
<p>또한 작업은 사용자가 직접 시작하는 것뿐 아니라 Schedule이나 Webhook으로 시작할 수 있습니다.</p>
<p>그래서 Agent Application의 중심도</p>
<pre><code class="language-text">Conversation</code></pre>
<p>보다</p>
<pre><code class="language-text">Task
State
Approval
Notification
Trigger</code></pre>
<p>에 가까워집니다.</p>
<p>Long-running Agent를 모바일 앱이나 업무 도구에 넣는다면 Chat UI를 그대로 복제하기보다 <strong>Inbox + Task Manager + Notification</strong> 구조가 더 자연스러운 경우가 많다는 것을 보여주는 사례입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Apple 2026 이벤트 총정리]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609103</link>
            <guid>https://velog.io/@kyu_ios_dev/2609103</guid>
            <pubDate>Wed, 09 Sep 2026 22:29:27 GMT</pubDate>
            <description><![CDATA[<h3 id="apple-2026-이벤트-총정리">Apple 2026 이벤트 총정리</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/92f5f950-e1a4-4183-bb46-94f1c892771f/image.png" alt=""></p>
<h2 id="iphone-duo부터-siri-ai까지-그리고-개발자가-봐야-할-변화">iPhone Duo부터 Siri AI까지, 그리고 개발자가 봐야 할 변화</h2>
<p>Apple의 2026년 9월 이벤트가 끝났습니다.</p>
<p>이번 발표는 최근 몇 년의 iPhone 행사 중에서도 변화 폭이 꽤 큰 편입니다.</p>
<p>가장 큰 이유는 단연 <strong>Apple 최초의 폴더블 iPhone, iPhone Duo</strong>입니다.</p>
<p>여기에</p>
<ul>
<li>iPhone 18 Pro / Pro Max</li>
<li>Apple Watch Series 12</li>
<li>Apple Watch Ultra 4</li>
<li>AirPods 5</li>
<li>새로운 Siri AI</li>
<li>Apple Intelligence 기반 Health 기능</li>
</ul>
<p>까지 한꺼번에 공개됐습니다.</p>
<p>이번 발표를 한 문장으로 정리하면 이렇습니다.</p>
<blockquote>
<p><strong>하드웨어의 형태는 더 다양해지고, 그 위에서 Apple Intelligence가 사용자의 Context를 이해하기 시작했다.</strong></p>
</blockquote>
<p>먼저 이번 Apple Event에서 발표된 내용부터 정리해보겠습니다.</p>
<hr>
<h1 id="1-가장-큰-발표--apple-최초의-폴더블-iphone-iphone-duo">1. 가장 큰 발표 — Apple 최초의 폴더블 iPhone, iPhone Duo</h1>
<p>이번 이벤트의 주인공은 사실상 <strong>iPhone Duo</strong>였습니다.</p>
<p>Apple 최초의 폴더블 iPhone입니다.</p>
<p>접었을 때는 <strong>5.4인치 외부 디스플레이</strong>, 펼쳤을 때는 <strong>7.6인치 내부 디스플레이</strong>를 사용합니다.</p>
<p>특히 내부 디스플레이는 Apple이 지금까지 만든 iPhone 중 가장 큰 화면입니다.</p>
<p>접었을 때는 비교적 작은 iPhone처럼 사용할 수 있고, 펼치면 콘텐츠 감상이나 게임, 멀티태스킹에 훨씬 넓은 화면을 제공합니다.</p>
<p>흥미로운 점은 두 디스플레이가 <strong>같은 화면 비율</strong>을 사용한다는 것입니다.</p>
<p>그래서 앱을 접힌 화면에서 사용하다가 펼쳐도 콘텐츠가 자연스럽게 확장됩니다.</p>
<p>단순히 화면 두 개가 붙어 있는 폴더블이 아니라, Apple답게 Hardware와 Software를 같이 설계한 형태입니다.</p>
<hr>
<h2 id="iphone-duo의-핵심-사양">iPhone Duo의 핵심 사양</h2>
<p>iPhone Duo는 새로운 <strong>A20 Pro</strong>를 사용합니다.</p>
<p>A20 Pro는 2nm 공정 기반이며,</p>
<ul>
<li>6-core CPU</li>
<li>7-core GPU</li>
<li>Dual 16-core Neural Engine</li>
<li>향상된 Unified Memory Bandwidth</li>
</ul>
<p>를 제공합니다.</p>
<p>특히 AI 처리 성능이 크게 강화됐습니다.</p>
<p>폴더블 구조에서 가장 걱정되는 부분인 발열도 별도로 대응했습니다.</p>
<p>iPhone Duo에는</p>
<p><strong>Custom Vapor Chamber + Dual Battery Architecture</strong></p>
<p>가 들어갑니다.</p>
<p>Apple은 이를 통해 멀티태스킹이나 게임, AI 연산 같은 지속적인 고성능 작업에서도 안정적인 성능을 유지하도록 설계했습니다.</p>
<hr>
<h1 id="2-폴더블-구조를-활용한-새로운-camera-경험">2. 폴더블 구조를 활용한 새로운 Camera 경험</h1>
<p>iPhone Duo는 폴더블 구조 자체를 Camera 기능에도 활용합니다.</p>
<p>기기를 펼치거나 접은 상태에 따라 상대방에게 Preview를 보여주거나, 기존 iPhone에서는 만들기 어려웠던 촬영 구도를 만들 수 있습니다.</p>
<p>그리고 <strong>Siri Camera Mode</strong>도 새롭게 등장합니다.</p>
<p>Camera Control을 통해 Siri Camera를 실행하면 Siri가 사용자가 보고 있는 장면을 이해하고 질문에 답하거나 관련 작업을 수행할 수 있습니다.</p>
<p>지금까지 Camera가</p>
<pre><code class="language-text">Camera
 ↓
Capture
 ↓
Photo</code></pre>
<p>였다면 앞으로는</p>
<pre><code class="language-text">Camera
 ↓
Scene Understanding
 ↓
Siri AI
 ↓
Action</code></pre>
<p>이라는 새로운 사용 방식이 추가되는 셈입니다.</p>
<hr>
<h1 id="3-iphone-duo는-apple-pencil도-지원한다">3. iPhone Duo는 Apple Pencil도 지원한다</h1>
<p>조금 의외였던 기능도 있습니다.</p>
<p><strong>iPhone Duo가 Apple Pencil USB-C를 지원합니다.</strong></p>
<p>Apple Pencil은 외부 화면과 내부 화면 모두에서 사용할 수 있습니다.</p>
<p>7.6인치 내부 화면을 펼치면 사실상 작은 iPad에 가까운 작업 공간이 만들어집니다.</p>
<p>따라서</p>
<ul>
<li>메모</li>
<li>문서 Annotation</li>
<li>Sketch</li>
<li>PDF Markup</li>
</ul>
<p>같은 작업이 가능해집니다.</p>
<p>iPhone과 iPad 사이의 경계가 점점 흐려지고 있다는 느낌을 주는 부분입니다.</p>
<hr>
<h1 id="4-iphone-18-pro--이번에는-camera가-많이-바뀌었다">4. iPhone 18 Pro — 이번에는 Camera가 많이 바뀌었다</h1>
<p>iPhone 18 Pro와 Pro Max 역시 상당한 변화가 있습니다.</p>
<p>이번 Pro 모델의 핵심은</p>
<p><strong>Camera + Performance + AI</strong></p>
<p>세 가지입니다.</p>
<p>가장 눈에 띄는 변화는 메인 Camera입니다.</p>
<p>48MP Fusion Main Camera에 <strong>Variable Aperture</strong>, 즉 가변 조리개가 들어갔습니다.</p>
<p>기존 iPhone Camera는 Computational Photography를 통해 대부분의 결과를 자동으로 처리했습니다.</p>
<p>하지만 이번에는 Professional User를 위한 수동 제어 기능이 더 강화됐습니다.</p>
<p>새로운 Pro Control에서는</p>
<ul>
<li>Aperture</li>
<li>Shutter Speed</li>
<li>White Balance</li>
<li>Histogram</li>
</ul>
<p>등을 직접 제어할 수 있습니다.</p>
<p>iPhone이 점점 Mirrorless Camera에 가까운 촬영 경험을 제공하는 방향으로 가고 있습니다.</p>
<hr>
<h1 id="5-dynamic-island도-다시-바뀐다">5. Dynamic Island도 다시 바뀐다</h1>
<p>iPhone 18 Pro에서는 Dynamic Island가 더 작아졌습니다.</p>
<p>그런데 표시할 수 있는 정보는 오히려 늘어났습니다.</p>
<p>새로운 Dynamic Island에서는 최대 <strong>3개의 Live Activity를 동시에 표시</strong>할 수 있습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">Taxi 도착 시간
+
스포츠 경기 점수
+
음악 재생</code></pre>
<p>같은 정보를 동시에 보여줄 수 있습니다.</p>
<p>Dynamic Island가 단순 Notification 영역이 아니라 점점 <strong>실시간 앱 상태를 보여주는 작은 Dashboard</strong>에 가까워지고 있습니다.</p>
<hr>
<h1 id="6-a20-pro--ai를-위한-칩이라는-느낌이-더-강해졌다">6. A20 Pro — AI를 위한 칩이라는 느낌이 더 강해졌다</h1>
<p>iPhone 18 Pro와 iPhone Duo 모두 <strong>A20 Pro</strong>를 사용합니다.</p>
<p>CPU나 GPU 성능도 올라갔지만 이번 Apple의 설명을 보면 특히 AI에 상당히 많은 비중을 두고 있습니다.</p>
<p>구조는</p>
<pre><code class="language-text">6-core CPU
7-core GPU
Dual 16-core Neural Engine</code></pre>
<p>입니다.</p>
<p>새로운 N1 Networking Chip을 통해</p>
<ul>
<li>Wi-Fi 7</li>
<li>Bluetooth 6</li>
<li>Thread</li>
</ul>
<p>를 지원합니다.</p>
<p>Cellular Modem 역시 Apple 자체 설계의 <strong>C2 Modem</strong>으로 변경됐습니다.</p>
<p>Apple이 iPhone의 핵심 Silicon을 점점 자체 설계로 가져오는 흐름이 더 명확해졌습니다.</p>
<hr>
<h1 id="7-siri-ai--이번-이벤트에서-하드웨어만큼-중요한-변화">7. Siri AI — 이번 이벤트에서 하드웨어만큼 중요한 변화</h1>
<p>이번 발표에서 제품만큼 중요한 것이 새로운 <strong>Siri AI</strong>입니다.</p>
<p>기존 Siri와 가장 큰 차이는 사용자의 <strong>Personal Context</strong>를 이해한다는 점입니다.</p>
<p>예를 들어 Siri가</p>
<ul>
<li>Messages</li>
<li>Mail</li>
<li>Photos</li>
<li>현재 화면</li>
</ul>
<p>등의 정보를 바탕으로 사용자의 요청을 이해할 수 있습니다.</p>
<p>예전 Siri는</p>
<pre><code class="language-text">Command
 ↓
Action</code></pre>
<p>에 가까웠습니다.</p>
<p>앞으로는</p>
<pre><code class="language-text">Context
 ↓
Understanding
 ↓
Reasoning
 ↓
Action</code></pre>
<p>에 가까워집니다.</p>
<p>그리고 중요한 기능이 <strong>On-screen Awareness</strong>입니다.</p>
<p>사용자가 현재 화면에서 보고 있는 콘텐츠를 Siri가 이해할 수 있습니다.</p>
<p>예를 들어 화면에 어떤 장소 정보가 있다면</p>
<blockquote>
<p>여기 일정에 추가해줘.</p>
</blockquote>
<p>같은 식의 요청이 가능해집니다.</p>
<p>Siri가 단순 Voice Assistant가 아니라 OS 전체를 연결하는 AI Layer가 되어가는 모습입니다.</p>
<hr>
<h1 id="8-siri-ai는-단계적으로-제공된다">8. Siri AI는 단계적으로 제공된다</h1>
<p>여기서 중요한 점도 있습니다.</p>
<p>이번에 공개된 Siri AI 전체 기능이 모든 국가와 언어에서 동시에 제공되는 것은 아닙니다.</p>
<p>초기에는 일부 언어와 지역부터 제공되고 이후 지원 범위가 확대됩니다.</p>
<p>따라서 Apple Intelligence와 Siri 기능을 사용하는 앱이라면 지역과 언어별 지원 범위를 별도로 확인할 필요가 있습니다.</p>
<hr>
<h1 id="9-apple-watch-series-12--이번에는-health가-중심">9. Apple Watch Series 12 — 이번에는 Health가 중심</h1>
<p>Apple Watch Series 12는 디자인보다 <strong>Health Sensing</strong>이 핵심입니다.</p>
<p>새로운 Health Sensing System과 S11 Chip을 중심으로 사용자의 상태를 더 자주, 더 정밀하게 측정합니다.</p>
<p>Apple Watch는 단순히 심박수나 활동량을 기록하는 기기에서</p>
<pre><code class="language-text">Sensor
 ↓
Data
 ↓
Interpretation</code></pre>
<p>을 수행하는 방향으로 계속 확장되고 있습니다.</p>
<hr>
<h1 id="10-readiness-score">10. Readiness Score</h1>
<p>Apple Watch Series 12에 새롭게 추가되는 대표 기능은 <strong>Readiness</strong>입니다.</p>
<p>Readiness는</p>
<ul>
<li>최근 운동량</li>
<li>Training Load</li>
<li>Sleep</li>
<li>HRV</li>
<li>Vitals</li>
</ul>
<p>등을 종합해서 사용자의 하루 컨디션을 계산합니다.</p>
<p>결과는</p>
<pre><code class="language-text">Recover
Pace Yourself
Ready
Go For It</code></pre>
<p>같은 식으로 보여줍니다.</p>
<p>단순히 건강 데이터를 보여주는 것이 아니라</p>
<p><strong>지금 운동을 해도 되는지, 쉬는 것이 좋은지</strong></p>
<p>까지 해석해서 알려주는 방향입니다.</p>
<hr>
<h1 id="11-health-앱도-데이터보다-insight가-중심이-된다">11. Health 앱도 데이터보다 Insight가 중심이 된다</h1>
<p>iPhone의 Health 앱도 크게 바뀝니다.</p>
<p>새로운 Health 관련 화면에서는 사용자의 장기적인 건강 데이터와 여러 지표를 함께 분석합니다.</p>
<p>중요한 변화는 Health 앱이 점점</p>
<pre><code class="language-text">Heart Rate
Sleep
HRV
Exercise
Vitals</code></pre>
<p>같은 숫자를 보여주는 앱에서</p>
<pre><code class="language-text">Data
 ↓
Pattern
 ↓
Insight
 ↓
Recommendation</code></pre>
<p>을 제공하는 앱으로 바뀌고 있다는 점입니다.</p>
<p>Apple Intelligence가 Chat이나 Image Generation에만 사용되는 것이 아니라 Health Data Interpretation으로 확장되는 모습입니다.</p>
<hr>
<h1 id="12-apple-watch-ultra-4">12. Apple Watch Ultra 4</h1>
<p>Apple Watch Ultra 4 역시 새로운 Health Sensing System과 S11을 사용합니다.</p>
<p>다만 Ultra답게 Outdoor와 Battery 사용 시간이 더 강화됐습니다.</p>
<p>일반 사용뿐 아니라 장시간 GPS Tracking이 필요한</p>
<ul>
<li>Ultra Marathon</li>
<li>Hiking</li>
<li>Trail Running</li>
<li>Expedition</li>
</ul>
<p>같은 환경을 더욱 적극적으로 고려하고 있습니다.</p>
<hr>
<h1 id="13-apple-watch에도-audio-intelligence가-들어간다">13. Apple Watch에도 Audio Intelligence가 들어간다</h1>
<p>이번 Watch 발표에서 의외로 흥미로운 부분이 <strong>Audio Intelligence</strong>입니다.</p>
<p>주변 Sound를 감지하고, 사용자가 들었던 내용을 기반으로 정보를 제공하거나 Siri와 연결할 수 있는 기능이 확대됩니다.</p>
<p>Apple Watch가 단순 Health Sensor가 아니라</p>
<p><strong>사용자 주변의 Context를 이해하는 AI Device</strong></p>
<p>로 확장되는 모습입니다.</p>
<hr>
<h1 id="14-airpods-5--open-ear-anc와-ai">14. AirPods 5 — Open-ear ANC와 AI</h1>
<p>AirPods 5도 새롭게 발표됐습니다.</p>
<p>이번 AirPods의 핵심은</p>
<p><strong>Open-ear ANC + Adaptive EQ + Siri AI</strong></p>
<p>입니다.</p>
<p>ANC 성능이 더 강화됐고 새로운 Acoustic Architecture와 Adaptive EQ가 적용됐습니다.</p>
<p>하지만 개발 관점에서 더 흥미로운 부분은 AI입니다.</p>
<hr>
<h1 id="15-airpods에서-live-translation">15. AirPods에서 Live Translation</h1>
<p>AI 관련 기능 중 가장 눈에 띄는 것이 <strong>Live Translation</strong>입니다.</p>
<p>AirPods를 착용한 상태에서 서로 다른 언어로 대화하면 Apple Intelligence가 실시간 Translation을 지원합니다.</p>
<p>AirPods는 점점</p>
<pre><code class="language-text">Audio Device</code></pre>
<p>에서</p>
<pre><code class="language-text">Microphone
+
Speaker
+
Voice Interface
+
AI Interface</code></pre>
<p>로 변하고 있습니다.</p>
<p>화면을 보지 않고 AI를 사용하는 경험이 점점 중요해지고 있다는 의미입니다.</p>
<hr>
<h1 id="이번-apple-event를-한눈에-정리하면">이번 Apple Event를 한눈에 정리하면</h1>
<p>이번 발표의 핵심은 크게 네 가지입니다.</p>
<h2 id="①-iphone의-새로운-form-factor">① iPhone의 새로운 Form Factor</h2>
<pre><code class="language-text">Phone
 ↓
Foldable
 ↓
Large Canvas</code></pre>
<p>iPhone Duo가 등장하면서 iPhone과 iPad 사이에 새로운 영역이 생겼습니다.</p>
<hr>
<h2 id="②-pro-camera의-확장">② Pro Camera의 확장</h2>
<pre><code class="language-text">Auto
+
Manual Control
+
Computational Photography</code></pre>
<p>iPhone Camera가 단순 자동 촬영에서 더 전문적인 촬영 도구로 확장됩니다.</p>
<hr>
<h2 id="③-apple-intelligence의-device-확장">③ Apple Intelligence의 Device 확장</h2>
<pre><code class="language-text">iPhone
Watch
AirPods
Camera
Health
Siri</code></pre>
<p>AI가 하나의 앱이나 Siri 안에만 존재하지 않고 Apple Device 전체로 퍼지고 있습니다.</p>
<hr>
<h2 id="④-sensor-data를-ai가-해석하기-시작">④ Sensor Data를 AI가 해석하기 시작</h2>
<pre><code class="language-text">Sensor
 ↓
History
 ↓
Personal Baseline
 ↓
AI Interpretation
 ↓
Recommendation</code></pre>
<p>Apple Watch와 Health 앱의 방향이 가장 대표적입니다.</p>
<hr>
<h1 id="여기부터는-개발자가-봐야-할-부분">여기부터는 개발자가 봐야 할 부분</h1>
<p>여기까지가 이번 <strong>Apple Event 자체의 핵심 내용</strong>입니다.</p>
<p>그런데 iOS 개발자라면 이번 발표에서 몇 가지를 조금 다르게 봐야 합니다.</p>
<hr>
<h1 id="1-iphone-duo--adaptive-layout이-이제-iphone의-문제다">1. iPhone Duo — Adaptive Layout이 이제 iPhone의 문제다</h1>
<p>폴더블 iPhone이 등장하면서 Adaptive Layout은 더 이상 iPad 개발에서만 중요한 문제가 아닙니다.</p>
<p>하나의 앱이 좁은 화면과 넓은 화면을 오갈 수 있기 때문입니다.</p>
<p>따라서 기존의</p>
<pre><code class="language-swift">UIScreen.main.bounds.width</code></pre>
<p>기반 분기나</p>
<pre><code class="language-swift">UIDevice.current.userInterfaceIdiom</code></pre>
<p>기반 Layout 결정은 점점 위험해질 수 있습니다.</p>
<p>앞으로 중요한 것은</p>
<pre><code class="language-text">Device</code></pre>
<p>가 아니라</p>
<pre><code class="language-text">Available Space</code></pre>
<p>입니다.</p>
<p>SwiftUI라면</p>
<pre><code class="language-swift">@Environment(\.horizontalSizeClass)
private var horizontalSizeClass</code></pre>
<p>또는</p>
<pre><code class="language-swift">ViewThatFits {
    ExpandedView()
    CompactView()
}</code></pre>
<p>같은 방식이 더 자연스러워집니다.</p>
<hr>
<h1 id="2-더-중요한-변화--iphone에서도-sidebar가-1급-navigation-패턴이-된다">2. 더 중요한 변화 — iPhone에서도 Sidebar가 1급 Navigation 패턴이 된다</h1>
<p>Resizable보다 개인적으로 더 흥미로운 변화는 <strong>iPhone에서도 Sidebar Navigation을 공식적으로 사용할 수 있게 됐다는 점</strong>입니다.</p>
<p>지금까지 iPhone의 대표적인 Navigation은 거의</p>
<pre><code class="language-text">Tab Bar</code></pre>
<p>였습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">Home
Search
Favorites
Profile
Settings</code></pre>
<p>를 화면 아래쪽에 두는 구조입니다.</p>
<p>하지만 iOS 27에서는 iPhone 앱도 Sidebar 표현을 선택할 수 있습니다.</p>
<p>UIKit에서는 다음과 같이 설정할 수 있습니다.</p>
<pre><code class="language-swift">tabBarController.sidebar.preferredPlacement = .sidebar</code></pre>
<p>그러면 앱이 Sidebar 표현을 선호한다는 것을 시스템에 알려줍니다.</p>
<p>다만 항상 Sidebar가 표시되는 것은 아닙니다.</p>
<p>실제로 Sidebar를 보여줄 만큼 공간이 있는지는 <strong>시스템이 판단합니다.</strong></p>
<p>현재 환경에서 Sidebar가 사용 가능한지는 다음처럼 확인할 수 있습니다.</p>
<pre><code class="language-swift">let available = tabBarController.sidebar.isAvailable</code></pre>
<p>즉 구조는 이런 식입니다.</p>
<pre><code class="language-text">Compact Width
      ↓
   Tab Bar

Regular Width
      ↓
   Sidebar</code></pre>
<p>iPhone Duo처럼 화면이 넓어지는 Device에서는 이 변화가 특히 중요합니다.</p>
<hr>
<h1 id="3-iphone-sidebar는-ipad-sidebar와-조금-다르다">3. iPhone Sidebar는 iPad Sidebar와 조금 다르다</h1>
<p>여기서 중요한 차이가 하나 있습니다.</p>
<p>iPad에서는 Tab Bar와 Sidebar가 환경에 따라 자연스럽게 전환되거나 사용자가 UI를 통해 전환할 수 있습니다.</p>
<p>하지만 iPhone에서는 <strong>Sidebar를 사용할지 앱이 선택합니다.</strong></p>
<pre><code class="language-swift">tabBarController.sidebar.preferredPlacement = .sidebar</code></pre>
<p>를 설정했다면 시스템은 현재 공간이 충분할 때 Sidebar를 표시합니다.</p>
<p>사용자가 직접</p>
<pre><code class="language-text">Tab Bar ↔ Sidebar</code></pre>
<p>를 토글하는 구조는 아닙니다.</p>
<p>즉 iPhone에서 Sidebar는 단순히 iPad UI를 가져온 것이 아니라 <strong>iPhone 환경에 맞게 다시 정의된 Navigation Pattern</strong>이라고 볼 수 있습니다.</p>
<hr>
<h1 id="4-sidebar가-중요한-이유는-화면을-넓게-쓰는-것만이-아니다">4. Sidebar가 중요한 이유는 화면을 넓게 쓰는 것만이 아니다</h1>
<p>Sidebar의 장점은 단순히 Menu 위치가 왼쪽으로 이동한다는 것이 아닙니다.</p>
<p>Navigation Hierarchy 자체가 더 풍부해질 수 있습니다.</p>
<p>기존 Tab Bar에서는 보통 Root Navigation이 제한적입니다.</p>
<pre><code class="language-text">Home
Search
Profile
Settings</code></pre>
<p>하지만 Sidebar에서는</p>
<pre><code class="language-text">Home

Library
 ├─ Recent
 ├─ Favorites
 └─ Downloads

Projects
 ├─ Project A
 ├─ Project B
 └─ Project C

Settings</code></pre>
<p>처럼 더 깊은 구조를 한 번에 보여줄 수 있습니다.</p>
<p>즉 iPhone Duo의 큰 화면을 단순히</p>
<p><strong>기존 UI를 확대해서 보여주는 것</strong></p>
<p>이 아니라</p>
<p><strong>Information Architecture 자체를 바꾸는 것</strong></p>
<p>까지 고려할 수 있습니다.</p>
<p>이 부분이 Adaptive Layout보다 한 단계 더 중요한 변화라고 생각합니다.</p>
<hr>
<h1 id="5-navigationsplitview도-이제-iphone에서-더-중요해진다">5. NavigationSplitView도 이제 iPhone에서 더 중요해진다</h1>
<p>SwiftUI에서는 <code>NavigationSplitView</code>를 다시 볼 필요가 있습니다.</p>
<p>예전에는 사실상</p>
<pre><code class="language-text">iPad
macOS</code></pre>
<p>중심 API라는 인식이 강했습니다.</p>
<p>하지만 넓은 iPhone 환경이 생기면서 이야기가 달라집니다.</p>
<p>예를 들어</p>
<pre><code class="language-swift">NavigationSplitView {
    List {
        NavigationLink(&quot;Home&quot;, value: Destination.home)
        NavigationLink(&quot;Search&quot;, value: Destination.search)
        NavigationLink(&quot;Settings&quot;, value: Destination.settings)
    }
} detail: {
    DetailView()
}</code></pre>
<p>같은 구조가 iPhone에서도 충분히 의미 있는 Layout이 될 수 있습니다.</p>
<p>즉 앞으로 Navigation을 설계할 때</p>
<pre><code class="language-text">iPhone = NavigationStack
iPad = NavigationSplitView</code></pre>
<p>처럼 기기별로 구분하기보다는</p>
<pre><code class="language-text">Compact Space
   ↓
NavigationStack

Expanded Space
   ↓
NavigationSplitView</code></pre>
<p>처럼 <strong>공간을 기준으로 설계하는 방식</strong>이 더 자연스럽습니다.</p>
<hr>
<h1 id="6-중요한-tab은-계속-살아남게-할-수-있다">6. 중요한 Tab은 계속 살아남게 할 수 있다</h1>
<p>iOS 27에서는 <code>UITabBarController</code>에 <strong>prominentTabIdentifier</strong>도 추가됐습니다.</p>
<p>예를 들어 쇼핑 앱의 Cart처럼 항상 중요한 Tab이 있다고 가정해봅시다.</p>
<pre><code class="language-swift">tabBarController.prominentTabIdentifier = &quot;cart&quot;</code></pre>
<p>처럼 지정할 수 있습니다.</p>
<p>이렇게 하면 지원되는 Layout에서 해당 Tab을 더 중요한 항목으로 표시할 수 있습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">Home
Search
Favorites
Cart ★
Profile</code></pre>
<p>처럼 특정 기능을 Navigation 구조에서 강조할 수 있습니다.</p>
<p>검색 중심 앱이라면 Search,</p>
<p>음악 앱이라면 Now Playing,</p>
<p>쇼핑 앱이라면 Cart</p>
<p>같은 기능을 생각해볼 수 있습니다.</p>
<hr>
<h1 id="7-dynamic-island--live-activity도-다시-테스트해야-한다">7. Dynamic Island / Live Activity도 다시 테스트해야 한다</h1>
<p>iPhone 18 Pro에서는 여러 개의 Live Activity가 동시에 표시될 수 있습니다.</p>
<p>따라서 개발자는 자신의 Live Activity가 항상 넓은 공간을 사용할 수 있다고 가정하면 안 됩니다.</p>
<pre><code class="language-text">My Activity
+
Other Activity
+
Other Activity</code></pre>
<p>환경에서도 핵심 정보가 살아남아야 합니다.</p>
<p>즉 Live Activity UI도</p>
<pre><code class="language-text">Full Space</code></pre>
<p>가 아니라</p>
<pre><code class="language-text">Limited Space</code></pre>
<p>를 기준으로 다시 테스트할 필요가 있습니다.</p>
<hr>
<h1 id="8-camera-앱-개발자는-iphone-18-pro를-눈여겨볼-필요가-있다">8. Camera 앱 개발자는 iPhone 18 Pro를 눈여겨볼 필요가 있다</h1>
<p>가변 조리개와 새로운 Pro Control은 Apple Camera 앱의 기능처럼 보이지만, Camera 관련 앱을 만드는 개발자에게도 의미가 있습니다.</p>
<p>Camera Pipeline은 점점</p>
<pre><code class="language-text">AVCaptureSession
      ↓
Camera Frame
      ↓
Vision / Core ML
      ↓
On-device AI
      ↓
Real-time Result</code></pre>
<p>구조로 발전하고 있습니다.</p>
<p>A20 Pro의 Neural Engine과 Memory Bandwidth 향상은</p>
<ul>
<li>Real-time Filter</li>
<li>Object Detection</li>
<li>Video Analysis</li>
<li>OCR</li>
<li>Generative Camera</li>
</ul>
<p>같은 기능에서 실제 의미가 있습니다.</p>
<hr>
<h1 id="9-siri-ai에서-개발자가-봐야-할-것은-app-intents다">9. Siri AI에서 개발자가 봐야 할 것은 App Intents다</h1>
<p>이번 이벤트에서 Siri AI가 강조됐지만 개발자는 그 뒤에 있는 <strong>App Intents</strong>를 봐야 합니다.</p>
<p>서버 AI의 Tool Calling을 생각하면 이해하기 쉽습니다.</p>
<p>일반적인 AI Agent는</p>
<pre><code class="language-text">LLM
 ↓
Tool
 ↓
Function</code></pre>
<p>구조입니다.</p>
<p>Apple 플랫폼에서는</p>
<pre><code class="language-text">Siri / Apple Intelligence
        ↓
App Intent
        ↓
App Feature</code></pre>
<p>가 됩니다.</p>
<p>예를 들어</p>
<pre><code class="language-swift">struct AddInventoryIntent: AppIntent {
    // ...
}</code></pre>
<p>같은 Intent를 제공하면 AI가</p>
<blockquote>
<p>우유 하나 재고에 추가해줘.</p>
</blockquote>
<p>같은 자연어 요청을 실제 앱 기능으로 연결할 수 있습니다.</p>
<p>앞으로 App Intents는 단순 Shortcut API가 아니라</p>
<p><strong>Apple Intelligence가 앱 기능을 호출하기 위한 Interface</strong></p>
<p>에 가까워질 가능성이 큽니다.</p>
<hr>
<h1 id="10-on-device-ai를-더-적극적으로-생각할-시점">10. On-device AI를 더 적극적으로 생각할 시점</h1>
<p>A20 Pro가 Neural Engine을 강조하는 이유도 중요합니다.</p>
<p>앞으로 모든 AI 작업을 Server로 보내기보다는</p>
<pre><code class="language-text">On-device AI
+
Cloud AI</code></pre>
<p>Hybrid 구조를 고민할 필요가 있습니다.</p>
<p>예를 들어</p>
<pre><code class="language-text">OCR
Barcode
Image Classification
Simple Text Processing</code></pre>
<p>같은 작업은 Device에서 처리하고,</p>
<p>복잡한 Reasoning만 Cloud Model로 보내는 방식입니다.</p>
<pre><code class="language-text">Camera
 ↓
Vision / Local Model
 ↓
Simple?
 ├─ YES → Local Result
 │
 └─ NO → Cloud AI</code></pre>
<p>이런 Architecture는</p>
<ul>
<li>Latency</li>
<li>Privacy</li>
<li>Server Cost</li>
</ul>
<p>를 동시에 줄일 수 있습니다.</p>
<hr>
<h1 id="11-healthkit-앱도-데이터-표시에서-해석으로-넘어간다">11. HealthKit 앱도 데이터 표시에서 해석으로 넘어간다</h1>
<p>이번 Apple Watch 발표에서 중요한 것은 Sensor 자체보다 <strong>Apple이 데이터를 해석하기 시작했다는 점</strong>입니다.</p>
<p>기존 HealthKit 앱은 대부분</p>
<pre><code class="language-text">HealthKit
 ↓
Data
 ↓
Chart</code></pre>
<p>구조였습니다.</p>
<p>하지만 앞으로 사용자는</p>
<blockquote>
<p>그래서 이 데이터가 무슨 의미인가?</p>
</blockquote>
<p>까지 기대하게 됩니다.</p>
<p>따라서</p>
<pre><code class="language-text">HealthKit
 ↓
Historical Data
 ↓
Personal Baseline
 ↓
Analysis
 ↓
Insight</code></pre>
<p>구조가 더 중요해질 가능성이 높습니다.</p>
<hr>
<h1 id="이번-발표-이후-기존-프로젝트에서-먼저-검색해볼-코드">이번 발표 이후 기존 프로젝트에서 먼저 검색해볼 코드</h1>
<p>기존 프로젝트가 있다면 개인적으로 아래부터 검색해볼 것 같습니다.</p>
<pre><code class="language-swift">UIScreen.main</code></pre>
<pre><code class="language-swift">UIDevice.current.userInterfaceIdiom</code></pre>
<pre><code class="language-swift">interfaceOrientation</code></pre>
<p>그리고</p>
<pre><code class="language-swift">.frame(width:)</code></pre>
<p>같은 고정 Width 코드도 확인해볼 필요가 있습니다.</p>
<p>Navigation에서는</p>
<pre><code class="language-text">Tab Bar가 항상 최선인가?

넓은 환경에서 Sidebar가 더 적합하지 않은가?

NavigationSplitView로 확장할 수 없는가?

중요한 Tab을 prominentTabIdentifier로 지정할 필요는 없는가?</code></pre>
<p>를 검토해볼 수 있습니다.</p>
<hr>
<h1 id="마치며">마치며</h1>
<p>이번 Apple Event의 가장 화려한 제품은 분명 <strong>iPhone Duo</strong>입니다.</p>
<p>하지만 개발자 입장에서 iPhone Duo의 의미는 단순히</p>
<p><strong>“Apple도 폴더블을 만들었다.”</strong></p>
<p>가 아닙니다.</p>
<p>진짜 변화는 iPhone 앱의 UI 구조 자체가 달라질 수 있다는 것입니다.</p>
<p>예전에는</p>
<pre><code class="language-text">iPhone
 ↓
Tab Bar
 ↓
NavigationStack</code></pre>
<p>정도가 가장 일반적인 구조였다면,</p>
<p>앞으로는</p>
<pre><code class="language-text">Compact
   ↓
Tab Bar
   ↓
NavigationStack</code></pre>
<p>과</p>
<pre><code class="language-text">Expanded
   ↓
Sidebar
   ↓
Split Navigation</code></pre>
<p>을 하나의 앱 안에서 함께 생각해야 합니다.</p>
<p>즉 iPhone Duo의 핵심 개발자 변화는</p>
<p><strong>화면이 커졌다는 것이 아니라, iPhone에서도 Sidebar와 Split Navigation이 본격적인 선택지가 됐다는 것</strong></p>
<p>이라고 볼 수 있습니다.</p>
<p>그리고 여기에</p>
<pre><code class="language-text">Adaptive UI
App Intents
On-device AI
Live Activity
Health Data Interpretation</code></pre>
<p>이 연결됩니다.</p>
<p>이번 Apple Event는 하드웨어 발표처럼 보이지만,</p>
<p>개발자 입장에서는 결국 한 가지 질문으로 이어집니다.</p>
<blockquote>
<p><strong>이제 우리 앱도 화면 크기만 바꾸는 것이 아니라, 화면이 넓어졌을 때 Navigation과 Information Architecture 자체를 바꿀 준비가 되어 있는가?</strong></p>
</blockquote>
<p>2026년 iOS 개발에서 꽤 중요한 체크포인트가 될 것 같습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[PR도 Agent가 끝낸다: Agent Merge 이후의 개발 워크플로우]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609092</link>
            <guid>https://velog.io/@kyu_ios_dev/2609092</guid>
            <pubDate>Tue, 08 Sep 2026 21:32:01 GMT</pubDate>
            <description><![CDATA[<h3 id="pr도-agent가-끝낸다-agent-merge-이후의-개발-워크플로우">PR도 Agent가 끝낸다: Agent Merge 이후의 개발 워크플로우</h3>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/eab8d4e1-1af8-4100-be3a-027343670304/image.png" alt=""></p>
<p>AI Coding Agent의 역할은 지금까지 주로 <strong>Pull Request를 만드는 것</strong>에 집중돼 있었다.</p>
<pre><code class="language-text">Issue
  ↓
Agent
  ↓
Repository 조사
  ↓
구현
  ↓
Test
  ↓
Pull Request
  ↓
Human Review</code></pre>
<p>그런데 실제 개발에서는 PR을 만드는 순간 일이 끝나지 않는다.</p>
<p>오히려 그다음부터 일이 시작되는 경우가 많다.</p>
<pre><code class="language-text">Reviewer Comment 7개

CI 2개 실패

base branch 변경

Merge Conflict 발생

수정 후 다시 CI

새로운 Review Comment

또 수정</code></pre>
<p>작은 기능 하나라도 PR이 Merge되기까지 몇 시간에서 며칠이 걸린다.</p>
<p>2026년 9월 2일 공개된 VS Code 1.136에는 이 마지막 구간을 Agent에게 맡기는 <strong>Agent Merge Preview</strong>가 추가됐다. VS Code는 Agent Merge를 “PR을 merge-ready 상태까지 가져가는 기능”으로 설명한다. Agent가 Review Feedback을 처리하고, Required CI 실패를 수정하고, Base Branch와 충돌하면 최신 상태로 맞추고 Merge Conflict를 해결한 뒤 필요한 Workflow를 다시 실행한다. 이 과정을 PR이 Merge 가능한 상태가 될 때까지 반복한다. </p>
<p>이건 생각보다 큰 변화다.</p>
<p>Coding Agent가:</p>
<pre><code class="language-text">코드를 만드는 Agent</code></pre>
<p>에서:</p>
<pre><code class="language-text">Software Change를 끝내는 Agent</code></pre>
<p>로 이동하고 있기 때문이다.</p>
<hr>
<h2 id="1-개발에서-가장-긴-시간은-코딩이-아닐-수도-있다">1. 개발에서 가장 긴 시간은 코딩이 아닐 수도 있다</h2>
<p>예를 들어 Feature 구현 자체는 Agent가 20분 만에 끝냈다고 하자.</p>
<p>하지만 실제 흐름은 이렇게 된다.</p>
<pre><code class="language-text">20분
구현

↓

15분
CI

↓

2시간
Reviewer 확인 대기

↓

Review Comment

↓

20분
수정

↓

15분
CI

↓

Base Branch 변경

↓

Conflict

↓

다시 수정

↓

다시 Review</code></pre>
<p>코드 작성 시간은 전체 Lead Time의 일부일 뿐이다.</p>
<p>AI Coding Agent가 구현 속도를 크게 올리면 오히려 새로운 병목이 생긴다.</p>
<pre><code class="language-text">Coding Throughput
↑↑↑

PR Merge Throughput
→</code></pre>
<p>Agent는 PR을 빠르게 만들어내는데 사람이 Review하고 CI 실패를 정리하고 Conflict를 처리하는 속도는 그대로인 것이다.</p>
<p>Agent Merge는 정확히 이 지점을 노린다.</p>
<hr>
<h1 id="2-agent-merge가-실제로-하는-일">2. Agent Merge가 실제로 하는 일</h1>
<p>현재 VS Code Agent Merge가 처리할 수 있는 영역은 크게 네 가지다.</p>
<pre><code class="language-text">Review Feedback

Failed Required Checks

Merge Conflicts

Final Merge / Merge Queue</code></pre>
<p>구체적으로는 PR에서 해결되지 않은 Review Thread, <code>changes requested</code> Review, Repository Maintainer나 Copilot Reviewer가 남긴 새로운 Comment를 Agent가 읽고 대응할 수 있다. Required CI Check가 실패하면 원인을 조사해 수정하고 Workflow를 다시 실행할 수 있으며, Branch가 Base Branch보다 뒤처지면 업데이트하고 Conflict를 해결할 수도 있다. 설정에 따라 마지막 Merge 또는 Merge Queue 등록까지 가능하다. </p>
<p>즉 기존 구조:</p>
<pre><code class="language-text">Agent
  ↓
PR
  ↓
사람
  ↓
Review 대응
  ↓
CI 대응
  ↓
Conflict 해결
  ↓
Merge</code></pre>
<p>가:</p>
<pre><code class="language-text">Agent
  ↓
PR
  ↓
Agent Merge
  │
  ├─ Review 대응
  ├─ CI 수정
  ├─ Conflict 해결
  ├─ Workflow 재실행
  └─ Merge-ready 확인
  ↓
Human Gate
  ↓
Merge</code></pre>
<p>로 바뀐다.</p>
<hr>
<h1 id="3-사실-완전히-새로운-기능-하나가-갑자기-생긴-것은-아니다">3. 사실 완전히 새로운 기능 하나가 갑자기 생긴 것은 아니다</h1>
<p>VS Code에서는 이전부터 PR의 Failed CI를 확인하고 Agent에게 <code>Fix Checks</code>를 요청하거나 새 Review Comment를 <code>Address Comments</code>로 넘기는 흐름이 발전해왔다.</p>
<p>1.136의 Agent Merge는 이 각각의 작업을 <strong>지속적인 Loop</strong>로 묶었다는 점이 중요하다. </p>
<p>예전:</p>
<pre><code class="language-text">CI 실패
→ 사람이 Fix Checks 클릭

Comment 도착
→ 사람이 Address Comments 클릭

Conflict 발생
→ 사람이 다시 Agent 호출</code></pre>
<p>지금:</p>
<pre><code class="language-text">Agent Merge ON
       ↓
PR 상태 감시
       ↓
Blocker 발생
       ↓
Agent 실행
       ↓
수정
       ↓
Push
       ↓
Check
       ↓
새 Blocker?
       │
      YES
       ↓
다시 처리</code></pre>
<p>Agent가 <strong>PR 상태를 지속적으로 관리하는 Worker</strong>가 된 것이다.</p>
<hr>
<h1 id="4-pr-자체가-하나의-장기-실행-task가-된다">4. PR 자체가 하나의 장기 실행 Task가 된다</h1>
<p>기존 Agent Task:</p>
<pre><code class="language-text">&quot;로그인 버그 수정해.&quot;</code></pre>
<p>Agent Merge 이후에는 실제 Task Boundary가 더 길어진다.</p>
<pre><code class="language-text">로그인 버그 수정

↓

PR 생성

↓

Reviewer 요청 반영

↓

CI 안정화

↓

Base Branch 최신화

↓

Conflict 해결

↓

최종 Required Checks 통과</code></pre>
<p>이 전체가 하나의 작업이 된다.</p>
<p>즉 Agent가 다루는 단위가:</p>
<pre><code class="language-text">Code Change</code></pre>
<p>에서:</p>
<pre><code class="language-text">Pull Request Lifecycle</code></pre>
<p>로 올라간다.</p>
<p>그리고 이 변화는 상당히 중요하다.</p>
<hr>
<h1 id="5-실제로-vs-code에서-사용하는-방법">5. 실제로 VS Code에서 사용하는 방법</h1>
<p>현재 Agent Merge는 Preview 기능이다.</p>
<p>먼저 설정에서 활성화한다.</p>
<pre><code class="language-json">{
  &quot;chat.agentMerge.enabled&quot;: true
}</code></pre>
<p>PR과 연결된 Agent Session을 연 뒤 Agents Window에서 <code>Agent Merge</code>를 활성화한다.</p>
<p>Command Palette에서는:</p>
<pre><code class="language-text">Enable Agent Merge for Active Session</code></pre>
<p>또는:</p>
<pre><code class="language-text">Configure Agent Merge for Active Session</code></pre>
<p>을 사용할 수 있다. </p>
<p>Agent Merge 메뉴에서는 어느 작업까지 Agent에게 허용할지도 정할 수 있다.</p>
<hr>
<h1 id="6-설정을-보면-agent-merge의-설계가-더-잘-보인다">6. 설정을 보면 Agent Merge의 설계가 더 잘 보인다</h1>
<p>현재 관련 주요 설정은 다음과 같다. </p>
<pre><code class="language-json">{
  &quot;chat.agentMerge.enabled&quot;: true,

  &quot;chat.agentMerge.addressReviews&quot;: true,

  &quot;chat.agentMerge.fixCI&quot;: true,

  &quot;chat.agentMerge.resolveConflicts&quot;: true,

  &quot;chat.agentMerge.mergePullRequest&quot;: &quot;never&quot;,

  &quot;chat.agentMerge.mergeMethod&quot;: &quot;auto&quot;,

  &quot;chat.agentMerge.replyAttribution&quot;: true
}</code></pre>
<p>여기서 특히 중요한 것이:</p>
<pre><code class="language-text">mergePullRequest</code></pre>
<p>다.</p>
<p>현재 선택지는:</p>
<pre><code class="language-text">always

ifUnchanged

never</code></pre>
<p>다. </p>
<p>개발팀에서 처음 도입한다면 <code>never</code>부터 시작하는 편이 좋다.</p>
<pre><code class="language-text">Agent
→ Merge-ready까지

Human
→ 실제 Merge</code></pre>
<p>경계를 유지하는 것이다.</p>
<hr>
<h1 id="7-왜-처음부터-자동-merge까지-켜지-않는-게-좋을까">7. 왜 처음부터 자동 Merge까지 켜지 않는 게 좋을까</h1>
<p>Agent가 다음을 해결했다고 하자.</p>
<pre><code class="language-text">Review Comment
PASS

CI
PASS

Merge Conflict
해결

Required Checks
PASS</code></pre>
<p>그러면 안전할까?</p>
<p>반드시 그렇지는 않다.</p>
<p>예를 들어 CI를 고친 방법이:</p>
<pre><code class="language-text">깨지는 테스트의 assertion 수정</code></pre>
<p>일 수도 있다.</p>
<p>Reviewer의 Comment를 해결한 방법이:</p>
<pre><code class="language-text">원래 의도와 다른 우회 구현</code></pre>
<p>일 수도 있다.</p>
<p>Conflict를 해결하면서:</p>
<pre><code class="language-text">Base Branch의 중요한 변경 삭제</code></pre>
<p>가 발생할 수도 있다.</p>
<p>기계적으로는 모두 <code>PASS</code>인데 제품은 틀릴 수 있다.</p>
<hr>
<h1 id="8-agent-merge에서-가장-위험한-것은-green-만들기다">8. Agent Merge에서 가장 위험한 것은 ‘Green 만들기’다</h1>
<p>Agent에게:</p>
<pre><code class="language-text">PR을 Merge 가능한 상태로 만들어.</code></pre>
<p>라는 Goal을 주면 모델은 자연스럽게:</p>
<pre><code class="language-text">Green CI</code></pre>
<p>를 목표로 삼는다.</p>
<p>그런데:</p>
<pre><code class="language-text">Green CI
=
Correct Software</code></pre>
<p>는 아니다.</p>
<p>대표적으로 이런 문제가 있다.</p>
<pre><code class="language-text">Test FAIL

↓

Agent

↓

Product Code 수정</code></pre>
<p>이면 괜찮을 수 있다.</p>
<p>하지만:</p>
<pre><code class="language-text">Test FAIL

↓

Agent

↓

Test Expectation 수정

↓

PASS</code></pre>
<p>라면 반드시 확인해야 한다.</p>
<hr>
<h1 id="9-테스트-코드는-specification이-될-수-있다">9. 테스트 코드는 Specification이 될 수 있다</h1>
<p>예를 들어 원래 요구사항이:</p>
<pre><code class="language-text">인증되지 않은 사용자는
HTTP 401을 받아야 한다.</code></pre>
<p>라고 하자.</p>
<p>Test:</p>
<pre><code class="language-ts">expect(response.status).toBe(401)</code></pre>
<p>그런데 실제 구현이 403을 반환한다.</p>
<p>Agent Merge가 CI를 통과시키기 위해:</p>
<pre><code class="language-ts">expect(response.status).toBe(403)</code></pre>
<p>으로 바꿨다.</p>
<p>CI는 Green이다.</p>
<p>하지만 요구사항은 깨졌다.</p>
<p>이런 변경은:</p>
<pre><code class="language-text">CI Repair</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">Specification Change</code></pre>
<p>다.</p>
<p>둘을 반드시 분리해야 한다.</p>
<hr>
<h1 id="10-그래서-agent-merge에도-권한-경계가-필요하다">10. 그래서 Agent Merge에도 권한 경계가 필요하다</h1>
<p>추천하는 정책은 이렇다.</p>
<h3 id="자동-허용">자동 허용</h3>
<pre><code class="language-text">Formatting

Lint 수정

명백한 Compile Error

단순 Import

Reviewer가 구체적으로 요구한 작은 수정

Mechanical Merge Conflict</code></pre>
<h3 id="확인-후-진행">확인 후 진행</h3>
<pre><code class="language-text">Test Assertion 변경

Public API 변경

새 Dependency

Database Schema

Architecture 변경

Security 관련 코드

Auth / Payment</code></pre>
<h3 id="사람이-결정">사람이 결정</h3>
<pre><code class="language-text">요구사항 변경

보안 정책 변경

Production Migration

Test 삭제

Required Check 제거

Branch Protection 변경</code></pre>
<p>즉 Agent Merge를 켠다고 <strong>Agent에게 PR에 관한 모든 결정 권한을 넘기는 것은 아니다.</strong></p>
<hr>
<h1 id="11-merge-conflict도-생각보다-위험하다">11. Merge Conflict도 생각보다 위험하다</h1>
<p>Conflict 해결은 Agent에게 굉장히 잘 맞는 작업처럼 보인다.</p>
<p>예:</p>
<pre><code class="language-text">&lt;&lt;&lt;&lt;&lt;&lt;&lt; feature

새 구현

=======

main의 새 구현

&gt;&gt;&gt;&gt;&gt;&gt;&gt; main</code></pre>
<p>하지만 Conflict는 단순 문자열 충돌이 아니다.</p>
<p>두 Branch 모두 올바른 변경일 수 있다.</p>
<p>예:</p>
<pre><code class="language-text">feature
→ 새로운 Cache

main
→ Race Condition 수정</code></pre>
<p>Agent가:</p>
<pre><code class="language-text">feature쪽 선택</code></pre>
<p>해서 Conflict Marker를 없애면 Git은 정상이다.</p>
<p>하지만 main의 Race Condition 수정이 사라질 수 있다.</p>
<hr>
<h1 id="12-좋은-conflict-resolution은-둘-다-이해해야-한다">12. 좋은 Conflict Resolution은 ‘둘 다 이해’해야 한다</h1>
<p>따라서 Agent에게:</p>
<pre><code class="language-text">Conflict marker 없애.</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">Base branch의 변경 목적과
feature branch의 변경 목적을 모두 확인하고
두 요구사항을 보존하는 방향으로 해결해.</code></pre>
<p>라고 해야 한다.</p>
<p>특히 다음 파일은 Conflict 자동 해결 Risk를 높게 보는 편이 좋다.</p>
<pre><code class="language-text">Authentication

Database

Concurrency

Build Configuration

Dependency Lock

Infrastructure

Security Policy</code></pre>
<hr>
<h1 id="13-agent-merge를-pr-유지보수-agent로-보는-게-가장-정확하다">13. Agent Merge를 ‘PR 유지보수 Agent’로 보는 게 가장 정확하다</h1>
<p>Agent Merge를:</p>
<pre><code class="language-text">Automatic Merger</code></pre>
<p>라고 생각하는 것보다:</p>
<pre><code class="language-text">PR Maintenance Agent</code></pre>
<p>라고 생각하면 이해하기 쉽다.</p>
<p>주요 역할:</p>
<pre><code class="language-text">Review Follow-up

CI Repair

Branch Sync

Conflict Resolution

Workflow Retry</code></pre>
<p>이다.</p>
<p>즉 사람이 PR을 만든 뒤 매번 들어가서 관리하던 <strong>잔업</strong>을 Agent가 맡는다.</p>
<hr>
<h1 id="14-개발자가-가장-자주-하는-pr-잔업이-사라질-수-있다">14. 개발자가 가장 자주 하는 PR 잔업이 사라질 수 있다</h1>
<p>실제로 이런 상황이 많다.</p>
<p>Reviewer:</p>
<pre><code class="language-text">여기 optional 처리해주세요.</code></pre>
<p>개발자:</p>
<pre><code class="language-text">수정
commit
push</code></pre>
<p>30분 뒤 CI:</p>
<pre><code class="language-text">lint failure</code></pre>
<p>개발자:</p>
<pre><code class="language-text">다시 수정
push</code></pre>
<p>그 사이 main 변경:</p>
<pre><code class="language-text">branch behind</code></pre>
<p>개발자:</p>
<pre><code class="language-text">pull
resolve
push</code></pre>
<p>새 Review:</p>
<pre><code class="language-text">이 Test도 추가해주세요.</code></pre>
<p>다시 개발자가 들어간다.</p>
<p>이 과정 하나하나는 어렵지 않다.</p>
<p>문제는 <strong>Attention을 계속 끊는다는 것</strong>이다.</p>
<hr>
<h1 id="15-agent-merge의-진짜-가치는-context-switching-감소다">15. Agent Merge의 진짜 가치는 Context Switching 감소다</h1>
<p>개발자에게 PR 하나는 끝난 작업처럼 보여도 머릿속에는 계속 남는다.</p>
<pre><code class="language-text">PR #128
CI 기다리는 중

PR #131
Reviewer 답변 기다림

PR #133
Conflict 발생

PR #135
새 Comment</code></pre>
<p>그러면 개발자는 다음 Feature를 개발하면서도 계속 Notification을 확인한다.</p>
<p>Agent Merge가 제대로 동작하면:</p>
<pre><code class="language-text">PR #128
Agent가 CI 처리

PR #131
Agent가 Comment 대응

PR #133
Agent가 Conflict 조사</code></pre>
<p>가 된다.</p>
<p>사람은:</p>
<pre><code class="language-text">Decision Needed

Risk High

Merge Ready</code></pre>
<p>일 때만 돌아오면 된다.</p>
<p>이게 훨씬 큰 생산성 변화일 수 있다.</p>
<hr>
<h1 id="16-좋은-agent는-모든-comment를-무조건-받아들이면-안-된다">16. 좋은 Agent는 모든 Comment를 무조건 받아들이면 안 된다</h1>
<p>Reviewer가:</p>
<pre><code class="language-text">이거 Singleton으로 바꾸는 게 좋겠습니다.</code></pre>
<p>라고 Comment를 남겼다고 하자.</p>
<p>Agent가 곧바로:</p>
<pre><code class="language-text">Singleton으로 변경</code></pre>
<p>하면 안 될 수도 있다.</p>
<p>왜냐하면 Repository Architecture에서는 Singleton을 금지하고 있을 수 있기 때문이다.</p>
<p>좋은 Agent의 행동은:</p>
<pre><code class="language-text">Review Comment
      ↓
Repository Rule
      ↓
Architecture Context
      ↓
충돌?
   │       │
  NO      YES
   │       │
   ▼       ▼
수정    Decision Needed</code></pre>
<p>이다.</p>
<p>즉 Comment는 명령이 아니라 <strong>입력</strong>이다.</p>
<hr>
<h1 id="17-그래서-agentsmd와-review-skill이-더-중요해진다">17. 그래서 AGENTS.md와 Review Skill이 더 중요해진다</h1>
<p>예를 들어 Repository에:</p>
<pre><code class="language-markdown"># Review Rules

- Singleton 추가 금지
- Public API 변경은 확인 필요
- 새로운 외부 Dependency는 자동 추가하지 않는다
- Test assertion 변경은 요구사항을 확인한다
- 기존 Security validation을 제거하지 않는다</code></pre>
<p>가 있다면 Agent Merge도 이 기준을 따라야 한다.</p>
<p>Agent가 강해질수록 Repository의 규칙이 더 중요해진다.</p>
<hr>
<h1 id="18-pr-description도-agent의-context가-된다">18. PR Description도 Agent의 Context가 된다</h1>
<p>좋은 PR에는 단순 변경 목록만 있는 것이 아니라:</p>
<pre><code class="language-text">왜 바꿨는가

무엇을 바꿨는가

무엇은 바꾸지 않았는가

어떻게 검증했는가</code></pre>
<p>가 있어야 한다.</p>
<p>예:</p>
<pre><code class="language-markdown">## 목표

로그인 중 중복 요청 문제 해결.

## 원인

Loading 상태 반영 전에
버튼을 다시 누를 수 있었음.

## 변경

요청 시작 즉시 버튼을 disabled 처리.

## 변경하지 않은 것

Authentication API
Retry Policy

## 검증

Unit Test
E2E Login Flow</code></pre>
<p>이 정보가 있으면 이후 Agent가 Reviewer Comment나 CI Failure를 처리할 때 원래 Goal을 잃을 가능성이 줄어든다.</p>
<hr>
<h1 id="19-agent-merge는-원래-goal을-계속-보존해야-한다">19. Agent Merge는 ‘원래 Goal’을 계속 보존해야 한다</h1>
<p>PR Lifecycle이 길어질수록 Agent가 원래 문제를 잊을 가능성이 있다.</p>
<p>예:</p>
<pre><code class="language-text">Goal
중복 Login Request 방지</code></pre>
<p>그런데 세 번 수정하고 Conflict까지 해결한 뒤:</p>
<pre><code class="language-text">현재 코드
Login Button 항상 disabled</code></pre>
<p>가 되어버릴 수도 있다.</p>
<p>CI만 보면 통과할 수 있다.</p>
<p>따라서 각 Repair Cycle마다:</p>
<pre><code class="language-text">Original Goal

Acceptance Criteria

Current Diff

New Blocker</code></pre>
<p>를 같이 봐야 한다.</p>
<hr>
<h1 id="20-review-feedback도-등급을-나누는-게-좋다">20. Review Feedback도 등급을 나누는 게 좋다</h1>
<p>모든 Comment가 동일하지 않다.</p>
<p>예:</p>
<pre><code class="language-text">CRITICAL

Security
Data Loss
Incorrect Authorization</code></pre>
<pre><code class="language-text">MAJOR

Logic Bug
Concurrency
Architecture
Regression</code></pre>
<pre><code class="language-text">MINOR

Naming
Formatting
Small Refactor</code></pre>
<p>Agent Merge가 처리할 때도:</p>
<pre><code class="language-text">MINOR
→ 자동

MAJOR
→ 수정 후 재검증

CRITICAL
→ Human Notify</code></pre>
<p>처럼 다르게 가져갈 수 있다.</p>
<hr>
<h1 id="21-github의-기존-보호장치를-없애면-안-된다">21. GitHub의 기존 보호장치를 없애면 안 된다</h1>
<p>Agent Merge가 강해져도 GitHub Ruleset이나 Branch Protection이 더 중요해진다.</p>
<p>GitHub는 Protected Branch에서:</p>
<ul>
<li>Pull Request Review</li>
<li>Required Status Checks</li>
<li>Conversation Resolution</li>
<li>Merge Queue</li>
<li>성공한 Deployment</li>
<li>Signed Commit</li>
<li>Force Push 제한</li>
</ul>
<p>같은 조건을 강제할 수 있다. </p>
<p>즉:</p>
<pre><code class="language-text">Agent</code></pre>
<p>를 신뢰하는 것이 아니라:</p>
<pre><code class="language-text">Agent
+
Repository Policy</code></pre>
<p>를 신뢰하는 것이다.</p>
<hr>
<h1 id="22-추천-architecture는-이렇다">22. 추천 Architecture는 이렇다</h1>
<pre><code class="language-text">                    Feature / Bug
                         │
                         ▼
                    Coding Agent
                         │
                         ▼
                     Pull Request
                         │
                         ▼
                  Independent Review
                         │
                         ▼
                    Agent Merge
                         │
            ┌────────────┼────────────┐
            ▼            ▼            ▼
        Comments       CI Fail      Conflict
            │            │            │
            └────────────┼────────────┘
                         ▼
                     Agent Fix
                         │
                         ▼
                   Build / Tests
                         │
                         ▼
                    Re-review
                         │
                         ▼
                  GitHub Ruleset
                         │
                         ▼
                    Merge Queue
                         │
                         ▼
                     Human Gate
                         │
                         ▼
                       main</code></pre>
<p>핵심은 Agent Merge가 <strong>GitHub Ruleset보다 위에 있지 않다는 것</strong>이다.</p>
<hr>
<h1 id="23-ci는-agent의-상사가-되어야-한다">23. CI는 Agent의 상사가 되어야 한다</h1>
<p>Agent가:</p>
<pre><code class="language-text">완료했습니다.</code></pre>
<p>라고 해도 CI가 실패하면 완료가 아니다.</p>
<pre><code class="language-text">Agent Opinion
    ↓

상관없음

CI Result
    ↓

실제 Gate</code></pre>
<p>라는 구조가 좋다.</p>
<p>Required Status Check를 Protected Branch에 설정하면 해당 Check가 통과해야 Merge할 수 있다. </p>
<p>Agent Merge 역시 Required Check가 Pending이면 기다리고, 실제 Merge 직전에 PR이 Ready 상태인지 다시 확인한다. </p>
<hr>
<h1 id="24-security-check-역시-required로-만드는-편이-좋다">24. Security Check 역시 Required로 만드는 편이 좋다</h1>
<p>예:</p>
<pre><code class="language-text">Unit Test

Integration Test

Lint

CodeQL

Dependency Review

Secret Scan</code></pre>
<p>등을 Required Check로 둔다.</p>
<p>GitHub Ruleset은 Status Check뿐 아니라 Code Scanning 결과 등도 Merge 조건으로 사용할 수 있다. </p>
<p>그러면 Agent가:</p>
<pre><code class="language-text">Security Warning 무시하고 Merge</code></pre>
<p>하기 어렵다.</p>
<hr>
<h1 id="25-code-owner도-여전히-중요하다">25. Code Owner도 여전히 중요하다</h1>
<p>예를 들어:</p>
<pre><code class="language-text">/auth/**
→ Security Team

/payment/**
→ Payment Team

/database/**
→ Backend Lead</code></pre>
<p>처럼 특정 영역을 CODEOWNERS로 관리할 수 있다.</p>
<p>Agent가 Review Comment를 전부 해결하더라도:</p>
<pre><code class="language-text">Security Code Owner Approval</code></pre>
<p>이 없으면 Merge되지 않게 할 수 있다.</p>
<p>Agent가 강해질수록 <strong>권한 경계가 더 중요해진다.</strong></p>
<hr>
<h1 id="26-copilot-review까지-완전히-자동화할-수도-있지만-주의가-필요하다">26. Copilot Review까지 완전히 자동화할 수도 있지만 주의가 필요하다</h1>
<p>GitHub Copilot은 현재 PR Code Review를 수행하고 Severity 기반 Comment를 남길 수 있다. 기본적으로 Copilot Review는 Required Approval로 계산되지 않지만, 현재 Public Preview인 Copilot Approvals를 별도로 활성화하면 Repository의 Required Approval을 만족시키도록 구성할 수도 있다. </p>
<p>기술적으로는:</p>
<pre><code class="language-text">Coding Agent
     ↓
Copilot Review
     ↓
Agent Merge
     ↓
Copilot Approval
     ↓
Merge</code></pre>
<p>처럼 거의 사람 없는 Flow도 가능해지고 있다.</p>
<p>하지만 모든 Repository에서 이걸 기본값으로 두는 것은 권하지 않는다.</p>
<hr>
<h1 id="27-작성-agent와-reviewer가-같은-실패를-공유할-수-있기-때문이다">27. 작성 Agent와 Reviewer가 같은 실패를 공유할 수 있기 때문이다</h1>
<p>예를 들어 요구사항을 Agent가 잘못 이해했다.</p>
<pre><code class="language-text">Requirement
A

Agent 이해
B</code></pre>
<p>Agent는 B를 구현한다.</p>
<p>AI Reviewer도 B라는 구현 자체는 훌륭하다고 평가한다.</p>
<pre><code class="language-text">Implementation
PASS

Architecture
PASS

Tests
PASS</code></pre>
<p>하지만 실제 Product Requirement는 A다.</p>
<p>즉:</p>
<pre><code class="language-text">Wrong Requirement Interpretation
+
Good Implementation
+
Good AI Review
=
Wrong Software</code></pre>
<p>가 가능하다.</p>
<p>그래서 고위험 변경에서는 사람의 Product/Architecture 판단이 여전히 필요하다.</p>
<hr>
<h1 id="28-추천하는-도입-단계는-네-단계다">28. 추천하는 도입 단계는 네 단계다</h1>
<h3 id="1단계--agent-merge는-관찰만">1단계 — Agent Merge는 관찰만</h3>
<pre><code class="language-text">Review Feedback
CI Failure
Conflict</code></pre>
<p>를 보고 어떤 행동을 할지 확인한다.</p>
<p>실제 Merge는 사람.</p>
<hr>
<h3 id="2단계--유지보수-자동화">2단계 — 유지보수 자동화</h3>
<pre><code class="language-text">addressReviews = true
fixCI = true
resolveConflicts = true

mergePullRequest = never</code></pre>
<p>로 사용한다.</p>
<p>개인 프로젝트에서도 가장 현실적인 시작점이다.</p>
<hr>
<h3 id="3단계--low-risk-pr-자동-merge">3단계 — Low Risk PR 자동 Merge</h3>
<p>예:</p>
<pre><code class="language-text">Documentation

Tests

Formatting

Dependency Patch

Internal Refactor</code></pre>
<p>같은 변경만 자동 Merge 후보로 둔다.</p>
<hr>
<h3 id="4단계--risk-based-merge">4단계 — Risk-based Merge</h3>
<pre><code class="language-text">LOW
→ Agent Merge 가능

MEDIUM
→ AI Review + Required Checks

HIGH
→ Code Owner + Human

CRITICAL
→ 자동 Merge 금지</code></pre>
<p>로 발전시킨다.</p>
<hr>
<h1 id="29-ifunchanged-옵션이-흥미로운-이유">29. <code>ifUnchanged</code> 옵션이 흥미로운 이유</h1>
<p>Agent Merge 설정에는:</p>
<pre><code class="language-text">always

ifUnchanged

never</code></pre>
<p>가 있다. </p>
<p>특히 <code>ifUnchanged</code>는 꽤 좋은 안전 장치다.</p>
<p>의미를 단순화하면:</p>
<pre><code class="language-text">Agent가 Repair를 위해
PR을 실제로 변경하지 않았다면

→ Merge 가능</code></pre>
<p>하지만 Agent가 Repair Turn에서 코드를 변경했다면:</p>
<pre><code class="language-text">→ 자동 Merge하지 않음</code></pre>
<p>으로 운영할 수 있다.</p>
<p>즉:</p>
<pre><code class="language-text">기존 PR 그대로 모든 Check PASS</code></pre>
<p>와:</p>
<pre><code class="language-text">Agent가 방금 새 코드를 수정한 PR</code></pre>
<p>을 동일하게 취급하지 않는 것이다.</p>
<p>실무적으로 꽤 합리적인 구분이다.</p>
<hr>
<h1 id="30-pr-수정-후-독립-re-review를-넣는-게-좋다">30. PR 수정 후 독립 Re-review를 넣는 게 좋다</h1>
<p>가장 추천하는 구조는:</p>
<pre><code class="language-text">Human / AI Review
       ↓
Finding
       ↓
Agent Merge Fix
       ↓
새 Commit
       ↓
Independent Re-review</code></pre>
<p>다.</p>
<p>특히:</p>
<pre><code class="language-text">Auth

Payment

Data

Concurrency

Infrastructure</code></pre>
<p>같은 변경이라면 필수에 가깝다.</p>
<p>왜냐하면 Review Comment 하나를 해결하면서 다른 Bug를 만들 수 있기 때문이다.</p>
<hr>
<h1 id="31-claude를-독립-reviewer로-넣는-구조도-가능하다">31. Claude를 독립 Reviewer로 넣는 구조도 가능하다</h1>
<p>최근 다뤘던 멀티에이전트 구조를 응용하면:</p>
<pre><code class="language-text">Codex
→ 구현

Claude
→ Review

Agent Merge
→ CI / Comment / Conflict 처리

Claude
→ Re-review

Runtime QA
→ 실제 검증</code></pre>
<p>처럼 가져갈 수 있다.</p>
<p>중요한 것은 특정 모델 조합이 아니다.</p>
<pre><code class="language-text">작성

검토

수정

재검토</code></pre>
<p>의 Context를 분리하는 것이다.</p>
<hr>
<h1 id="32-qa는-merge-전에-한-번-더-필요하다">32. QA는 Merge 전에 한 번 더 필요하다</h1>
<p>CI가 모두 Green이어도 UX가 깨질 수 있다.</p>
<p>Web이라면:</p>
<pre><code class="language-text">Playwright

Browser

Screenshot

Video

Console

Network</code></pre>
<p>으로 Runtime QA를 할 수 있다.</p>
<p>iOS:</p>
<pre><code class="language-text">Simulator

Accessibility

Recording

Runtime Log</code></pre>
<p>Android:</p>
<pre><code class="language-text">Emulator

Semantics

Logcat</code></pre>
<p>같은 검증을 추가할 수 있다.</p>
<p>즉:</p>
<pre><code class="language-text">PR Ready</code></pre>
<p>와:</p>
<pre><code class="language-text">Product Ready</code></pre>
<p>를 구분한다.</p>
<hr>
<h1 id="33-merge-queue와-agent-merge는-상당히-잘-맞는다">33. Merge Queue와 Agent Merge는 상당히 잘 맞는다</h1>
<p>GitHub Merge Queue는 여러 PR이 동시에 main으로 들어가는 환경에서 각 PR을 최신 Base 상태와 함께 검사하고 순서대로 Merge하도록 설계돼 있다. </p>
<p>Agent Merge가:</p>
<pre><code class="language-text">PR을 Merge-ready 상태까지 유지</code></pre>
<p>하고,</p>
<p>Merge Queue가:</p>
<pre><code class="language-text">최신 main과 함께 최종 검증</code></pre>
<p>을 하는 구조다.</p>
<pre><code class="language-text">Agent Merge
     ↓
Merge-ready
     ↓
Merge Queue
     ↓
Latest Base Integration
     ↓
Required Checks
     ↓
Merge</code></pre>
<p>Agent가 많아져 PR 생성량이 늘수록 이런 구조의 가치가 커진다.</p>
<hr>
<h1 id="34-결국-agent-merge는-self-healing-pr에-가깝다">34. 결국 Agent Merge는 ‘Self-healing PR’에 가깝다</h1>
<p>앞으로 PR은 정적인 변경 묶음이 아니라 조금 다른 형태가 될 수 있다.</p>
<pre><code class="language-text">PR 생성
  ↓
환경 변화
  ↓
스스로 수정
  ↓
Feedback 반영
  ↓
CI 복구
  ↓
Base Branch 동기화
  ↓
다시 검증</code></pre>
<p>일종의:</p>
<pre><code class="language-text">Self-maintaining Change</code></pre>
<p>다.</p>
<p>이건 상당히 큰 변화다.</p>
<hr>
<h1 id="35-하지만-self-healing과-self-correcting은-다르다">35. 하지만 Self-healing과 Self-correcting은 다르다</h1>
<p>Agent가:</p>
<pre><code class="language-text">Test를 Green으로 만들었다.</code></pre>
<p>고 해서:</p>
<pre><code class="language-text">제품을 올바르게 만들었다.</code></pre>
<p>는 뜻은 아니다.</p>
<p>Agent Merge는:</p>
<pre><code class="language-text">Operational Blocker</code></pre>
<p>를 잘 처리할 수 있다.</p>
<p>그러나:</p>
<pre><code class="language-text">Product Intent
Architecture Trade-off
Security Risk Acceptance</code></pre>
<p>까지 자동으로 결정하는 것은 다른 문제다.</p>
<p>여기에는 여전히 사람의 판단이 필요하다.</p>
<hr>
<h1 id="36-그래서-가장-중요한-것은-merge-policy다">36. 그래서 가장 중요한 것은 Merge Policy다</h1>
<p>Agent가 얼마나 똑똑한지보다:</p>
<pre><code class="language-text">무엇을 Agent에게 맡길 것인가?</code></pre>
<p>를 정하는 것이 중요하다.</p>
<p>예를 들어:</p>
<pre><code class="language-yaml">agent_merge:

  review_feedback:
    auto: true

  ci_failure:
    auto: true

  merge_conflict:
    auto: true

  test_expectation_change:
    approval: required

  dependency_addition:
    approval: required

  auth_change:
    human_review: required

  production_config:
    auto_merge: false</code></pre>
<p>이런 Policy가 있으면 Agent가 바뀌어도 Workflow는 유지된다.</p>
<hr>
<h1 id="37-개인-개발자에게도-꽤-유용하다">37. 개인 개발자에게도 꽤 유용하다</h1>
<p>혼자 개발하면 이런 일이 많다.</p>
<pre><code class="language-text">PR 만들었는데

CI 하나 깨짐

↓

나중에 고쳐야지</code></pre>
<p>다른 작업 시작.</p>
<p>몇 시간 뒤:</p>
<pre><code class="language-text">아 맞다.</code></pre>
<p>다시 돌아온다.</p>
<p>Agent Merge가 있으면:</p>
<pre><code class="language-text">PR
↓
CI Fail
↓
Agent Fix
↓
CI
↓
Merge Ready</code></pre>
<p>까지 뒤에서 진행시킬 수 있다.</p>
<p>개인 개발자에게도 <strong>Attention 절약</strong> 효과가 꽤 클 수 있다.</p>
<hr>
<h1 id="38-여러-agent를-쓰면-더-중요해진다">38. 여러 Agent를 쓰면 더 중요해진다</h1>
<p>Agent 1:</p>
<pre><code class="language-text">Feature A PR</code></pre>
<p>Agent 2:</p>
<pre><code class="language-text">Bug Fix PR</code></pre>
<p>Agent 3:</p>
<pre><code class="language-text">Refactor PR</code></pre>
<p>가 동시에 생겼다고 하자.</p>
<p>이제 사람에게:</p>
<pre><code class="language-text">PR 3개 관리</code></pre>
<p>업무가 생긴다.</p>
<p>그런데 각 PR마다 Agent Merge가 붙으면:</p>
<pre><code class="language-text">PR A → Agent 유지관리

PR B → Agent 유지관리

PR C → Agent 유지관리</code></pre>
<p>를 할 수 있다.</p>
<p>사람은:</p>
<pre><code class="language-text">Needs Decision

Security Risk

Merge Ready</code></pre>
<p>만 보는 방향으로 갈 수 있다.</p>
<hr>
<h1 id="39-multi-agent의-진짜-병목을-건드리는-기능이다">39. Multi-Agent의 진짜 병목을 건드리는 기능이다</h1>
<p>멀티에이전트가 발전하면서 가장 먼저 발생하는 문제가 있다.</p>
<pre><code class="language-text">Agent 생성 속도
&gt;
Human 처리 속도</code></pre>
<p>이다.</p>
<p>Agent Merge는 이것을:</p>
<pre><code class="language-text">Agent 생성

+

Agent 유지관리</code></pre>
<p>로 확장한다.</p>
<p>즉 Agent가 만들어낸 PR을 <strong>다른 단계의 Agent가 끝까지 돌보는 구조</strong>다.</p>
<p>이게 Engineering Agent 시스템에 가까워지는 이유다.</p>
<hr>
<h1 id="40-앞으로-issue부터-merge까지-하나의-agent-graph가-될-수-있다">40. 앞으로 Issue부터 Merge까지 하나의 Agent Graph가 될 수 있다</h1>
<p>결국 이런 형태가 자연스럽다.</p>
<pre><code class="language-text">                        Issue
                          │
                          ▼
                     Planning Agent
                          │
                          ▼
                  Implementation Agent
                          │
                          ▼
                         PR
                          │
               ┌──────────┴──────────┐
               ▼                     ▼
          Review Agent             CI
               │                     │
               └──────────┬──────────┘
                          ▼
                     Agent Merge
                          │
             ┌────────────┼────────────┐
             ▼            ▼            ▼
        Feedback Fix   CI Recovery   Conflict
             │            │            │
             └────────────┼────────────┘
                          ▼
                      Re-review
                          │
                          ▼
                      Runtime QA
                          │
                          ▼
                     Merge Queue
                          │
                          ▼
                       Human Gate
                          │
                          ▼
                         main</code></pre>
<p>이제 Agent의 작업 경계가:</p>
<pre><code class="language-text">Issue → Code</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">Issue → Verified Merge</code></pre>
<p>까지 늘어난다.</p>
<hr>
<h1 id="41-개발자의-역할-역시-한-단계-올라간다">41. 개발자의 역할 역시 한 단계 올라간다</h1>
<p>예전 개발자는:</p>
<pre><code class="language-text">코드를 작성하고

CI를 보고

Review Comment를 수정하고

Conflict를 해결하고

Merge했다.</code></pre>
<p>Agent 환경에서는 점점:</p>
<pre><code class="language-text">Goal 설정

Architecture 결정

Risk 판단

Agent Policy 설정

Exception 승인

최종 결과 Review</code></pre>
<p>를 맡게 된다.</p>
<p>구현의 세부 작업보다 <strong>Software Change 전체의 품질을 관리하는 역할</strong>로 이동하는 것이다.</p>
<hr>
<h1 id="42-agent-merge를-쓰면서-측정해볼-지표">42. Agent Merge를 쓰면서 측정해볼 지표</h1>
<p>실제 도입했다면 단순:</p>
<pre><code class="language-text">Agent Merge 사용 횟수</code></pre>
<p>를 볼 필요는 없다.</p>
<p>다음이 더 중요하다.</p>
<pre><code class="language-text">PR Lead Time

Review → Fix Time

CI Recovery Time

Conflict Resolution Time

Human Intervention Count

Agent Repair Count

Re-review Rejection Rate

Regression Rate</code></pre>
<p>특히:</p>
<pre><code class="language-text">Human Intervention Count</code></pre>
<p>가 재미있다.</p>
<p>Agent Merge를 넣었는데 사람이 여전히 PR마다 열 번씩 개입해야 한다면 큰 효과가 없는 것이다.</p>
<hr>
<h1 id="43-좋은-agent-merge는-사람을-많이-부르지-않는다">43. 좋은 Agent Merge는 사람을 많이 부르지 않는다</h1>
<p>예:</p>
<pre><code class="language-text">PR 시작

Agent Review 대응

CI 수정

Conflict 해결

CI 재실행

↓

Human

&quot;Merge 가능&quot;</code></pre>
<p>이면 성공적이다.</p>
<p>반대로:</p>
<pre><code class="language-text">Comment 1
→ 질문

CI
→ 질문

Conflict
→ 질문

Workflow
→ 질문</code></pre>
<p>이라면 단순 Automation을 복잡하게 만든 것에 가깝다.</p>
<p>목표는:</p>
<pre><code class="language-text">Agent Activity ↑</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">Human Attention ↓</code></pre>
<p>이어야 한다.</p>
<hr>
<h1 id="44-agent가-직접-merge했다면-provenance도-남겨야-한다">44. Agent가 직접 Merge했다면 Provenance도 남겨야 한다</h1>
<p>앞으로는:</p>
<pre><code class="language-text">누가 Merge했는가?</code></pre>
<p>만으로 부족할 수 있다.</p>
<pre><code class="language-text">어떤 Agent가

어떤 Review Comment를 해결했고

어떤 CI를 고쳤고

어떤 Conflict를 해결했으며

마지막 변경 후 어떤 Test를 실행했는가</code></pre>
<p>도 중요하다.</p>
<p>즉 Agent Merge가 발전할수록:</p>
<pre><code class="language-text">Agent Provenance</code></pre>
<p>의 중요성도 커진다.</p>
<p>PR Timeline이 일종의 Agent 작업 감사 로그가 되는 것이다.</p>
<hr>
<h1 id="45-github의-기존-reviewruleset이-사라지는-게-아니다">45. GitHub의 기존 Review/Ruleset이 사라지는 게 아니다</h1>
<p>오히려 반대다.</p>
<p>Agent가 더 많은 변경을 만들수록:</p>
<pre><code class="language-text">Protected Branch

Required Review

Required Checks

Ruleset

Code Owner

Merge Queue</code></pre>
<p>같은 기존 Engineering Control이 더 중요해진다.</p>
<p>GitHub도 Ruleset을 이용해 PR Review, Status Check, Code Scanning 같은 조건을 병합 전에 강제할 수 있도록 제공하고 있다. </p>
<p>Agent는 그 조건을 <strong>통과하도록 일하는 Worker</strong>다.</p>
<p>조건 자체를 결정하는 존재가 아니다.</p>
<hr>
<h1 id="46-제가-처음-적용한다면-이렇게-시작한다">46. 제가 처음 적용한다면 이렇게 시작한다</h1>
<p>개인 프로젝트:</p>
<pre><code class="language-json">{
  &quot;chat.agentMerge.enabled&quot;: true,
  &quot;chat.agentMerge.addressReviews&quot;: true,
  &quot;chat.agentMerge.fixCI&quot;: true,
  &quot;chat.agentMerge.resolveConflicts&quot;: true,
  &quot;chat.agentMerge.mergePullRequest&quot;: &quot;never&quot;
}</code></pre>
<p>그리고 GitHub에서는:</p>
<pre><code class="language-text">Required Tests

Required Build

Code Scanning

Conversation Resolution</code></pre>
<p>정도만 먼저 둔다.</p>
<p>Agent에게는 Merge-ready까지만 맡긴다.</p>
<p>실제 Merge는 직접 한다.</p>
<hr>
<h1 id="47-익숙해지면-low-risk만-자동화한다">47. 익숙해지면 Low Risk만 자동화한다</h1>
<p>예:</p>
<pre><code class="language-text">docs/**

tests/**

internal tooling

formatting

dependency patch</code></pre>
<p>등은 자동화 범위를 늘린다.</p>
<p>반면:</p>
<pre><code class="language-text">auth/**

payment/**

database/**

infra/**

security/**</code></pre>
<p>는 계속 Human Gate를 둔다.</p>
<p>즉 Repository Path 자체를 Risk Signal로 사용할 수도 있다.</p>
<hr>
<h1 id="48-agent-merge가-의미하는-더-큰-변화">48. Agent Merge가 의미하는 더 큰 변화</h1>
<p>지금까지 AI Coding 경쟁은 대부분:</p>
<pre><code class="language-text">누가 코드를 더 잘 만드는가?</code></pre>
<p>였다.</p>
<p>그런데 개발자가 실제 원하는 것은 코드가 아니다.</p>
<p>원하는 것은:</p>
<pre><code class="language-text">Issue 해결</code></pre>
<p>이다.</p>
<p>그래서 Agent의 작업 범위는 자연스럽게:</p>
<pre><code class="language-text">Code Generation
        ↓
Repository Modification
        ↓
Build / Test
        ↓
Pull Request
        ↓
Review Response
        ↓
CI Recovery
        ↓
Merge</code></pre>
<p>로 계속 확장된다.</p>
<p>Agent Merge는 이 흐름에서 꽤 상징적인 기능이다.</p>
<hr>
<h1 id="마무리">마무리</h1>
<p>VS Code 1.136의 Agent Merge는 표면적으로 보면 작은 기능처럼 보인다.</p>
<pre><code class="language-text">Review Comment 처리

CI 수정

Conflict 해결

자동 Merge</code></pre>
<p>정도다.</p>
<p>하지만 개발 Workflow 관점에서는 의미가 훨씬 크다.</p>
<p>Coding Agent의 완료 지점이:</p>
<pre><code class="language-text">&quot;PR 만들었습니다.&quot;</code></pre>
<p>에서:</p>
<pre><code class="language-text">&quot;PR이 Merge 가능한 상태입니다.&quot;</code></pre>
<p>로 이동하기 때문이다.</p>
<p>VS Code의 현재 Agent Merge는 PR을 지속적으로 감시하면서 unresolved review feedback, required CI failure, base branch update와 merge conflict 같은 Blocker를 처리하고, 설정에 따라 Merge 또는 Merge Queue까지 이어갈 수 있다. 기능은 아직 Preview이고 Agent Merge를 활성화하면 Session이 Autopilot + Assisted permissions로 바뀌며 모델 요청도 소비하므로 자동화 범위를 확인한 뒤 켜야 한다. </p>
<p>그리고 여기서 가장 중요한 것은:</p>
<pre><code class="language-text">AI가 Merge할 수 있다.</code></pre>
<p>가 아니다.</p>
<p>더 중요한 것은:</p>
<pre><code class="language-text">AI에게 무엇까지 Merge 과정에서
스스로 판단하도록 허용할 것인가?</code></pre>
<p>다.</p>
<p>Test가 깨졌다고 Test를 바꿔도 되는가.</p>
<p>Reviewer 의견이 Architecture Rule과 충돌하면 무엇을 따라야 하는가.</p>
<p>Merge Conflict를 해결하면서 Base Branch의 중요한 수정이 사라지지 않았는가.</p>
<p>새 Commit이 들어온 뒤 기존 Approval은 여전히 유효한가.</p>
<p>이런 문제는 단순 Automation으로 해결되지 않는다.</p>
<p>그래서 앞으로 좋은 PR Workflow는:</p>
<pre><code class="language-text">Agent
+
Repository Rules
+
Independent Review
+
CI
+
Runtime QA
+
Human Gate</code></pre>
<p>의 조합이 될 가능성이 높다.</p>
<p>Agent Merge를 도입한다고 Branch Protection이나 Required Check가 필요 없어지는 게 아니다.</p>
<p>오히려 GitHub는 Protected Branch와 Ruleset을 이용해 Required Review, Required Status Check, Conversation Resolution, Merge Queue, Code Scanning 등의 조건을 강제할 수 있다. Agent가 강해질수록 이런 <strong>Agent가 임의로 우회할 수 없는 결정적 규칙</strong>이 더 중요해진다. </p>
<p>결국 Coding Agent 시대의 PR은 정적인 코드 묶음에서 조금씩 바뀌고 있다.</p>
<pre><code class="language-text">PR
=
변경된 코드</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">PR
=
계속 관찰하고
피드백을 받고
실패를 복구하고
최신 Branch와 맞추고
검증을 반복하는
살아 있는 Software Change</code></pre>
<p>에 가까워진다.</p>
<p>그리고 앞으로 Agent 경쟁의 중요한 기준도 바뀔 것이다.</p>
<blockquote>
<p><strong>누가 PR을 가장 빨리 만드는가가 아니라, 누가 개발자의 Attention을 가장 적게 사용하면서 PR을 안전하게 Merge-ready 상태까지 가져가는가.</strong></p>
</blockquote>
<p>Agent Merge가 흥미로운 이유가 바로 여기에 있다.</p>
<p>AI가 코드를 쓰기 시작한 다음 단계는 <strong>AI가 자신이 만든 Software Change의 생명주기를 관리하기 시작하는 것</strong>이다.</p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<p><strong>Visual Studio Code 1.136 — September 2, 2026</strong><br>VS Code 1.136에서 Agent Merge Preview가 공개됐다. Review Feedback, Failed Checks, Merge Conflict를 Agent가 반복 처리해 PR을 Merge-ready 상태까지 가져가는 기능과 Multi-root Agent Session 등이 함께 추가됐다. </p>
<p><strong>Visual Studio Code — Agents Window / Agent Merge</strong><br>Agent Merge의 실제 동작, 활성화 방법, Review·CI·Conflict 처리와 Merge Queue/자동 Merge 옵션, Autopilot 및 Permission 관련 주의사항이 설명돼 있다. </p>
<p><strong>Visual Studio Code — AI Settings Reference</strong><br><code>addressReviews</code>, <code>fixCI</code>, <code>resolveConflicts</code>, <code>mergePullRequest</code>, <code>mergeMethod</code>, <code>replyAttribution</code> 등 Agent Merge의 세부 설정을 확인할 수 있다. </p>
<p><strong>GitHub — Protected Branches / Rulesets</strong><br>Required Review, Required Status Check, Conversation Resolution, Merge Queue, Code Scanning 같은 Repository 수준의 병합 조건을 강제할 수 있다. </p>
<p><strong>GitHub — Copilot Code Review</strong><br>Copilot을 PR Reviewer로 활용하고 Review Comment를 Agent에게 다시 구현시키는 Workflow를 제공한다. Copilot Approval은 별도 설정 시 Required Approval에 포함할 수 있지만 현재 Public Preview다. </p>
<h3 id="핵심-참고-포인트">핵심 참고 포인트</h3>
<p>Agent Merge의 핵심은 단순한 자동 Merge가 아니다. <strong>PR 생성 이후의 Review 대응 → CI 복구 → Branch 동기화 → Conflict 해결 → 재검증이라는 반복적인 유지보수 업무를 Agent가 지속적으로 맡는 것</strong>이다. </p>
<p>실무에서는 처음부터 <code>mergePullRequest: always</code>로 두기보다 Review·CI·Conflict 처리는 Agent에게 맡기고 실제 Merge는 사람이 수행하는 <code>never</code> 구성부터 시작하는 것이 안전하다. 이후 Low Risk 변경에 한해 <code>ifUnchanged</code>나 Merge Queue를 단계적으로 도입할 수 있다. </p>
<p>그리고 Agent가 강해질수록 <code>CI Green</code>을 <code>Software Correct</code>로 착각하지 않는 것이 중요하다. Agent Merge는 PR의 운영적 Blocker를 제거하는 데 강하지만 Product Intent와 Architecture·Security 판단까지 대체하는 시스템은 아니다. <strong>Agent는 PR을 고치고, Repository Policy와 Test가 검증하며, 중요한 결정은 사람에게 남기는 구조</strong>가 가장 현실적이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MCP 다음은 MHS다: AI Agent가 실제 기계를 움직이는 시대]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609091</link>
            <guid>https://velog.io/@kyu_ios_dev/2609091</guid>
            <pubDate>Tue, 08 Sep 2026 21:29:41 GMT</pubDate>
            <description><![CDATA[<h4 id="mcp-다음은-mhs다-ai-agent가-실제-기계를-움직이는-시대">MCP 다음은 MHS다: AI Agent가 실제 기계를 움직이는 시대</h4>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/7f4b6809-c136-4feb-b08f-54ad1e71cb0f/image.png" alt=""></p>
<p>AI Agent가 지금까지 주로 다뤄온 세계는 소프트웨어였다.</p>
<pre><code class="language-text">Repository
Browser
Database
Slack
GitHub
Cloud
API</code></pre>
<p>Agent는 MCP나 각종 Tool API를 통해 이 소프트웨어 세계를 점점 자유롭게 움직이기 시작했다.</p>
<p>그런데 다음 단계는 화면 안에 있지 않다.</p>
<pre><code class="language-text">현미경

로봇팔

카메라

액체 처리 장비

센서

레이저

공장 장비</code></pre>
<p>같은 <strong>실제 물리 장비</strong>다.</p>
<p>2026년 8월 27일 Anthropic은 HHMI Janelia Research Campus와 함께 개발해온 <strong>Model Hardware Standard(MHS)</strong>의 Research Preview를 공개했다.</p>
<p>Anthropic의 설명을 단순화하면 MHS는:</p>
<blockquote>
<p>AI Agent가 서로 다른 물리 장비를 발견하고, 상태를 읽고, 조작하고, 안전 한계를 이해할 수 있도록 만드는 공통 Hardware Interface</p>
</blockquote>
<p>에 가깝다.</p>
<p>현재는 일부 과학 연구소와 첨단 제조사에 제공되는 제한된 Research Preview이며, 안전성 평가와 운영 Best Practice를 먼저 만든 뒤 향후 Open Source할 계획이다. </p>
<p>흥미로운 건 이것이 단순한 “로봇용 MCP”가 아니라는 점이다.</p>
<p><strong>MCP와 MHS는 서로 경쟁하는 표준이라기보다 다른 Layer에 있다.</strong></p>
<hr>
<h2 id="1-mcp가-software-tool을-열었다면-mhs는-physical-tool을-연다">1. MCP가 Software Tool을 열었다면 MHS는 Physical Tool을 연다</h2>
<p>MCP가 등장하면서 Agent는 다양한 Software Tool을 표준화된 방식으로 사용할 수 있게 됐다.</p>
<pre><code class="language-text">AI Agent

   ↓ MCP

GitHub
Database
Browser
Filesystem
Slack
Cloud</code></pre>
<p>Hardware에서도 비슷한 문제가 존재한다.</p>
<p>예를 들어 연구실에 다음 장비가 있다고 해보자.</p>
<pre><code class="language-text">Microscope
Liquid Handler
Robot Arm
Plate Reader
Camera
Temperature Controller</code></pre>
<p>문제는 대부분 서로 다른 제조사 제품이라는 것이다.</p>
<p>각 장비마다:</p>
<pre><code class="language-text">Vendor SDK

독자 API

전용 프로그램

자체 Protocol

전용 Driver

별도 GUI</code></pre>
<p>가 존재한다.</p>
<p>결국 연구실이나 공장에서 여러 장비를 연결하려면 이런 코드를 만들어야 했다.</p>
<pre><code class="language-text">Microscope ↔ Custom Integration

Robot Arm ↔ Custom Integration

Camera ↔ Custom Integration

Liquid Handler ↔ Custom Integration</code></pre>
<p>장비가 하나 늘어날 때마다 또 연결해야 한다.</p>
<p>Anthropic은 이런 통합에 일반적으로 <strong>몇 주에서 몇 달까지 걸릴 수 있다</strong>고 설명한다. MHS의 목표는 장비 하나를 공통 Driver 형태로 한 번 정의하고 여러 Agent와 Workflow가 다시 사용할 수 있게 만드는 것이다. 초기 적용에서는 이런 통합 작업을 시간 또는 분 단위까지 단축한 사례가 소개됐다. </p>
<hr>
<h1 id="2-mhs가-해결하려는-핵심-문제는-hardware-api가-아니다">2. MHS가 해결하려는 핵심 문제는 Hardware API가 아니다</h1>
<p>장비에 API가 있는 것만으로 Agent가 장비를 안전하게 사용할 수 있는 것은 아니다.</p>
<p>예를 들어 로봇팔 API가 있다고 하자.</p>
<pre><code class="language-text">move(x, y, z)</code></pre>
<p>Agent 입장에서는 호출 방법은 알 수 있다.</p>
<p>하지만 중요한 정보가 빠져 있다.</p>
<pre><code class="language-text">이 로봇의 최대 Payload는?

Arm 자체 무게는?

현재 Gripper에 무엇이 잡혀 있나?

이 좌표에 사람이 있는가?

어디까지 움직여도 되는가?

최대 속도는?

비상 정지 상태인가?</code></pre>
<p>소프트웨어에서는 호출 실패가:</p>
<pre><code class="language-text">Exception</code></pre>
<p>정도로 끝날 수 있다.</p>
<p>Physical Agent에서는 잘못된 호출이:</p>
<pre><code class="language-text">장비 파손

샘플 손실

실험 오염

충돌

사람의 부상</code></pre>
<p>으로 이어질 수 있다.</p>
<p>따라서 Physical AI에는 단순 API보다 훨씬 많은 Context가 필요하다.</p>
<hr>
<h1 id="3-mhs-driver는-장비를-agent가-이해할-수-있는-형태로-바꾼다">3. MHS Driver는 장비를 Agent가 이해할 수 있는 형태로 바꾼다</h1>
<p>Anthropic이 공개한 MHS 구조의 중심에는 <strong>표준 Driver</strong>가 있다.</p>
<p>Driver는 장비 고유의 API와 Agent 사이에 위치한다.</p>
<pre><code class="language-text">                AI Agent
                   │
                   ▼
               MHS Driver
                   │
          ┌────────┼────────┐
          ▼        ▼        ▼
        read     write    metadata
          │        │
          ▼        ▼
              Vendor API
                   │
                   ▼
                Hardware</code></pre>
<p>기본 Primitive는 상당히 단순하다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">read</code></pre>
<p>는:</p>
<pre><code class="language-text">현재 온도 읽기
현재 위치 읽기
센서 값 읽기
카메라 상태 읽기</code></pre>
<p>같은 동작이다.</p>
<pre><code class="language-text">write</code></pre>
<p>는:</p>
<pre><code class="language-text">온도 설정
로봇 위치 변경
레이저 출력 변경
밸브 열기</code></pre>
<p>같은 제어다. </p>
<p>단순한 Primitive를 두는 이유는 여러 장비를 하나의 Agent Workflow 안에서 연결하기 쉽기 때문이다.</p>
<hr>
<h1 id="4-하지만-readwrite보다-더-중요한-것이-device-description이다">4. 하지만 read/write보다 더 중요한 것이 Device Description이다</h1>
<p>Agent에게:</p>
<pre><code class="language-text">set_temperature(50)</code></pre>
<p>라는 Tool만 보여주는 것은 위험하다.</p>
<p>50이:</p>
<pre><code class="language-text">섭씨 50도인가?

화씨 50도인가?

이 장비가 허용하는 범위인가?

샘플이 견딜 수 있는 값인가?</code></pre>
<p>알 수 없기 때문이다.</p>
<p>그래서 MHS Driver에는 장비의 물리적 특성을 설명하는 Tag가 들어간다.</p>
<p>Anthropic 설명에 따르면 사용자는 자연어로 장비 정보를 작성할 수도 있고, Agent가 사용자에게 장비에 대해 질문하면서 필요한 정보를 수집할 수도 있다.</p>
<p>그 결과 Reference File이 만들어진다.</p>
<p>여기에는 대략:</p>
<pre><code class="language-text">무엇을 측정할 수 있는가

무엇을 조절할 수 있는가

장비의 일반 특성

어떤 Safety Limit이 적용되는가</code></pre>
<p>같은 정보가 들어간다. </p>
<p>개념적으로 표현하면 이런 모습이다.</p>
<pre><code class="language-yaml">device:
  type: temperature_controller

capabilities:
  read:
    - temperature

  write:
    - target_temperature

limits:
  target_temperature:
    min: 4
    max: 40

safety:
  emergency_stop: true</code></pre>
<p>이건 MHS 공식 공개 Schema가 아니라 <strong>구조를 설명하기 위한 예시</strong>다. 현재 핵심 Specification은 아직 제한된 Research Preview 단계다.</p>
<hr>
<h1 id="5-agent에게-hardware-manual을-읽히는-것과는-다르다">5. Agent에게 Hardware Manual을 읽히는 것과는 다르다</h1>
<p>그렇다면 그냥 PDF Manual을 Agent에게 읽히면 되지 않을까?</p>
<p>문제는 Manual이:</p>
<pre><code class="language-text">비정형

장비마다 다름

버전이 다름

현재 상태를 알 수 없음</code></pre>
<p>이라는 것이다.</p>
<p>MHS가 하려는 것은 Manual을 AI에게 검색시키는 게 아니다.</p>
<p>장비의:</p>
<pre><code class="language-text">Capabilities

State

Control

Physical Properties

Safety Limits</code></pre>
<p>를 <strong>Machine-readable Interface</strong>로 만드는 것이다.</p>
<p>즉:</p>
<pre><code class="language-text">Manual
→ 사람 중심 설명</code></pre>
<p>에서:</p>
<pre><code class="language-text">MHS Driver
→ Agent가 동작할 수 있는 Hardware Contract</code></pre>
<p>로 바뀐다.</p>
<hr>
<h1 id="6-mhs에서-상당히-재미있는-부분이-shared-state다">6. MHS에서 상당히 재미있는 부분이 Shared State다</h1>
<p>여러 장비가 같이 일하려면 Agent만 장비 상태를 알아서는 부족하다.</p>
<p>장비끼리 상태를 공유해야 한다.</p>
<p>Anthropic이 소개한 구현에서는 각 장비의:</p>
<pre><code class="language-text">Variables

Controls

Sensor Values</code></pre>
<p>를 하나의 공유 Dictionary에 기록한다.</p>
<p>이 Dictionary가 Shared Memory에 존재하고 여러 프로그램이나 장비가 접근할 수 있다. </p>
<p>구조를 단순화하면:</p>
<pre><code class="language-text">Microscope ───┐
Camera ───────┤
Robot Arm ────┤
Laser ────────┼─→ Shared State
Sensor ───────┤
              │
              ▼
           AI Agent</code></pre>
<p>이게 중요한 이유가 있다.</p>
<hr>
<h1 id="7-agent가-모든-상태를-직접-polling할-필요가-없어진다">7. Agent가 모든 상태를 직접 Polling할 필요가 없어진다</h1>
<p>예를 들어 Camera가 Laser 위치를 측정한다.</p>
<pre><code class="language-text">Camera
→ beam_x = 128
→ beam_y = 245</code></pre>
<p>Mirror Controller는 이 값을 보고 거울을 움직인다.</p>
<p>기존에는:</p>
<pre><code class="language-text">Camera API
↓
Custom Adapter
↓
Controller Program
↓
Mirror API</code></pre>
<p>를 별도로 만들어야 했다.</p>
<p>공유 상태를 이용하면:</p>
<pre><code class="language-text">Camera
     ↓
Shared State
     ↓
Agent / Controller
     ↓
Mirror</code></pre>
<p>형태가 된다.</p>
<p>새 장비가 들어와도 다른 장비와 Point-to-point Integration을 계속 만들 필요가 줄어든다.</p>
<hr>
<h1 id="8-hardware-integration-비용의-구조-자체를-바꾸려는-것이다">8. Hardware Integration 비용의 구조 자체를 바꾸려는 것이다</h1>
<p>장비가 세 개라면 연결 수가 적다.</p>
<p>하지만 장비가 계속 늘어나면 문제가 커진다.</p>
<pre><code class="language-text">A ↔ B
A ↔ C
A ↔ D
B ↔ C
B ↔ D
C ↔ D
...</code></pre>
<p>MHS의 방향은:</p>
<pre><code class="language-text">Device A ─┐
Device B ─┤
Device C ─┼─→ Standard Interface
Device D ─┤
Device E ─┘</code></pre>
<p>다.</p>
<p>즉 장비 하나를 추가할 때 전체 시스템을 다시 연결하는 대신 <strong>그 장비를 한 번 MHS에 연결하는 것</strong>에 집중한다.</p>
<p>Anthropic이 Hardware Integration 시간이 몇 주에서 시간·분 단위로 줄 수 있다고 강조하는 이유도 이 구조 때문이다. </p>
<hr>
<h1 id="9-그렇다면-mcp와-mhs는-정확히-어떻게-연결될까">9. 그렇다면 MCP와 MHS는 정확히 어떻게 연결될까</h1>
<p>가장 헷갈리기 쉬운 부분이다.</p>
<pre><code class="language-text">MCP
vs
MHS</code></pre>
<p>가 아니다.</p>
<p>MHS가 Physical Hardware를 표준화하고,</p>
<p>MCP는 Agent가 그것을 사용하는 <strong>접근 방식 중 하나</strong>가 될 수 있다.</p>
<p>Anthropic이 현재 공개한 MHS Control Mechanism은 세 가지다.</p>
<pre><code class="language-text">MCP

CLI

Code Files / API</code></pre>
<p>즉:</p>
<pre><code class="language-text">Claude / GPT / 다른 Agent
             │
             ▼
            MCP
             │
             ▼
         MHS Driver
             │
             ▼
        Physical Device</code></pre>
<p>도 가능하고,</p>
<pre><code class="language-text">Agent
  │
  ▼
CLI
  │
  ▼
MHS Driver</code></pre>
<p>도 가능하다.</p>
<hr>
<h1 id="10-그래서-mhs는-model-agnostic이다">10. 그래서 MHS는 Model-agnostic이다</h1>
<p>이름 때문에:</p>
<pre><code class="language-text">Claude 전용 Hardware Protocol</code></pre>
<p>처럼 느껴질 수 있지만 그렇지 않다.</p>
<p>Anthropic은 MHS가 <strong>model-agnostic</strong>이고 일반적인 Agent Harness가 MCP 같은 표준 Protocol을 통해 접근할 수 있다고 설명한다. </p>
<p>즉 구조적으로는:</p>
<pre><code class="language-text">Claude
GPT
Gemini
Local Model
Other Agent
       │
       ▼
     MHS
       │
       ▼
   Hardware</code></pre>
<p>를 목표로 한다.</p>
<p>이 점에서는 MCP가 가져온 방향과 꽤 비슷하다.</p>
<hr>
<h1 id="11-그런데-physical-agent에서는-mcp-호출만-반복하면-느릴-수도-있다">11. 그런데 Physical Agent에서는 MCP 호출만 반복하면 느릴 수도 있다</h1>
<p>여기서 재미있는 문제가 하나 생긴다.</p>
<p>예를 들어 Laser를 미세 조정해야 한다.</p>
<pre><code class="language-text">값 읽기
↓
생각
↓
조금 이동
↓
값 읽기
↓
생각
↓
조금 이동
↓
값 읽기</code></pre>
<p>이 작업을 LLM이 매번 추론하면서 수행하면 느리다.</p>
<p>Hardware는 밀리초 단위의 제어가 필요할 수도 있다.</p>
<p>그래서 MHS에는 Code File이라는 방식이 중요해진다.</p>
<hr>
<h1 id="12-agent는-생각을-code로-압축할-수-있다">12. Agent는 ‘생각’을 Code로 압축할 수 있다</h1>
<p>Anthropic이 공개한 Laser Alignment 사례가 아주 재미있다.</p>
<p>처음 Claude는 사람처럼 탐색했다.</p>
<pre><code class="language-text">Laser 조절
↓
Camera 확인
↓
Beam 위치 관찰
↓
다시 조절
↓
다시 관찰</code></pre>
<p>여러 번 반복하면서 관계를 파악했다.</p>
<p>그런데 충분히 이해한 뒤에는 그 행동을 <strong>Deterministic Script로 만들었다.</strong></p>
<p>즉:</p>
<pre><code class="language-text">Agent Reasoning
        ↓
패턴 학습
        ↓
Code 생성
        ↓
Deterministic Controller</code></pre>
<p>로 바뀐다. </p>
<p>이게 상당히 중요한 패턴이다.</p>
<hr>
<h1 id="13-ai는-모든-순간-생각할-필요가-없다">13. AI는 모든 순간 생각할 필요가 없다</h1>
<p>예를 들어 로봇팔의 반복 작업을 생각해보자.</p>
<p>나쁜 구조:</p>
<pre><code class="language-text">LLM
↓
Move 1
↓
LLM
↓
Move 2
↓
LLM
↓
Move 3</code></pre>
<p>좋은 구조는:</p>
<pre><code class="language-text">LLM

Goal 이해
↓
작업 계획
↓
Controller Script 생성

          ↓

Deterministic Runtime

Move
Move
Move
Sensor
Adjust</code></pre>
<p>일 수 있다.</p>
<p>Agent는 고수준의 판단을 하고 빠르고 반복적인 Physical Control은 코드가 수행한다.</p>
<hr>
<h1 id="14-이것은-software-agent에서도-이미-보던-패턴이다">14. 이것은 Software Agent에서도 이미 보던 패턴이다</h1>
<p>Coding Agent에서도 비슷하다.</p>
<p>처음에는 Agent가:</p>
<pre><code class="language-text">파일 찾기
grep
검색
Test
Log</code></pre>
<p>를 하나씩 호출한다.</p>
<p>같은 작업이 반복되면:</p>
<pre><code class="language-text">Script
Skill
Tool</code></pre>
<p>로 만든다.</p>
<p>Physical Agent에서도:</p>
<pre><code class="language-text">Exploration
↓
Understanding
↓
Automation</code></pre>
<p>이 반복된다.</p>
<p>AI Agent가 새로운 Hardware를 사용하면서 <strong>자신의 Tool을 스스로 만들어내는 구조</strong>다.</p>
<hr>
<h1 id="15-quera-사례가-이-구조를-잘-보여준다">15. QuEra 사례가 이 구조를 잘 보여준다</h1>
<p>Anthropic이 공개한 MHS 적용 사례 중 하나가 QuEra Computing의 Quantum Computer Laser System이다.</p>
<p>중성 원자를 이용하는 Quantum Computer에서는 Laser Frequency를 극도로 정밀하게 유지해야 한다.</p>
<p>문제가 생기면 숙련된 Engineer가 여러 계측 장비를 보면서 Laser Lock을 복구해야 한다.</p>
<p>기존에는 사람의 복구에 약 <strong>5~10분</strong>이 걸릴 수 있었다.</p>
<p>QuEra는 과거에도 이 작업을 자동화하려고 했고, Laser Engineer·Software Engineer·Algorithm Specialist·Tester가 몇 달 동안 만든 Bespoke Script가 있었다.</p>
<p>그 Script의 성공률은 약 <strong>58퍼센트</strong>였다고 Anthropic은 설명한다. </p>
<hr>
<h1 id="16-mhs를-통해-claude에게-같은-문제를-맡겼다">16. MHS를 통해 Claude에게 같은 문제를 맡겼다</h1>
<p>QuEra는 Agent에게:</p>
<pre><code class="language-text">Goal:
Laser를 다시 Lock한다.

Success:
첫 시도에 Lock하고
30초 동안 유지한다.</code></pre>
<p>라는 목표를 줬다.</p>
<p>그리고 의도적으로:</p>
<pre><code class="language-text">Beam Block

Instrument Power Cut

Frequency Disturbance</code></pre>
<p>같은 장애를 만들었다.</p>
<p>MHS가 Claude에게 장비를 읽고 조절할 수 있는 Interface를 제공했다.</p>
<p>Anthropic이 공개한 결과에서는 Agent가 만든 Controller가 Laser Lock을 <strong>99.3퍼센트의 경우 사람 개입 없이 복구</strong>했다. </p>
<p>상당히 인상적인 숫자다.</p>
<p>다만 이 결과는 Anthropic이 발표한 특정 QuEra 환경의 사례이지, MHS를 적용하면 어떤 Hardware에서든 99퍼센트 자동복구가 된다는 의미는 아니다.</p>
<hr>
<h1 id="17-중요한-것은-58-→-993이라는-숫자보다-recovery-방식이다">17. 중요한 것은 58 → 99.3이라는 숫자보다 Recovery 방식이다</h1>
<p>기존 Script는 Linear Workflow에 가까웠다.</p>
<pre><code class="language-text">Step A
↓
Step B
↓
Step C
↓
Step D</code></pre>
<p>그런데 중간에 온도나 압력 같은 환경 변화가 발생하면 이전 Step이 무효가 될 수 있었다.</p>
<p>그러면 처음부터 다시 해야 했다.</p>
<p>Agent는 조금 다르게 움직일 수 있다.</p>
<pre><code class="language-text">현재 Sensor State 확인
↓
어디가 틀어졌는지 판단
↓
필요한 Step만 다시 실행
↓
결과 관찰
↓
다시 조정</code></pre>
<p>즉 <strong>State-aware Recovery</strong>다.</p>
<p>Software Agent에서 최근 중요해지고 있는:</p>
<pre><code class="language-text">실패
→ 동일 Retry</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">실패
→ Re-observe
→ Re-plan
→ Recovery</code></pre>
<p>구조가 Physical World에서도 똑같이 등장한다.</p>
<hr>
<h1 id="18-mhs가-진짜-흥미로운-이유는-hardware-agentic-loop-때문이다">18. MHS가 진짜 흥미로운 이유는 ‘Hardware Agentic Loop’ 때문이다</h1>
<p>소프트웨어 Agent Loop:</p>
<pre><code class="language-text">Observe

↓

Reason

↓

Act

↓

Observe

↓

Recover</code></pre>
<p>Hardware에서도 그대로 적용된다.</p>
<pre><code class="language-text">Sensor

↓

AI

↓

Actuator

↓

Physical World 변화

↓

Sensor

↓

AI</code></pre>
<p>이제 Agent가 다루는 State가 파일이나 Browser DOM이 아니라 <strong>현실 세계의 상태</strong>다.</p>
<p>이 차이는 엄청나게 크다.</p>
<hr>
<h1 id="19-software에서는-retry-비용이-비교적-낮다">19. Software에서는 Retry 비용이 비교적 낮다</h1>
<p>예:</p>
<pre><code class="language-text">Build 실패

↓

다시 Build</code></pre>
<p>큰 문제가 아닐 수 있다.</p>
<p>Hardware에서는:</p>
<pre><code class="language-text">액체 50ml 투입

↓

잘못됨

↓

다시 해볼게</code></pre>
<p>가 불가능할 수도 있다.</p>
<p>샘플은 이미 오염됐다.</p>
<p>또:</p>
<pre><code class="language-text">Robot Arm 이동

↓

충돌

↓

Retry</code></pre>
<p>도 말이 안 된다.</p>
<p>따라서 Physical Agent에서는 <strong>Irreversible Action</strong>이라는 개념이 훨씬 중요하다.</p>
<hr>
<h1 id="20-그래서-physical-agent의-권한은-단계적으로-나누는-게-좋다">20. 그래서 Physical Agent의 권한은 단계적으로 나누는 게 좋다</h1>
<p>개발환경에서 Agent Permission을:</p>
<pre><code class="language-text">AUTO
CONFIRM
DENY</code></pre>
<p>로 나누듯 Hardware도 비슷하게 설계할 수 있다.</p>
<p>예를 들어:</p>
<h3 id="auto">AUTO</h3>
<pre><code class="language-text">Sensor 읽기

Camera 촬영

장비 상태 확인

낮은 위험도의 미세 조정</code></pre>
<h3 id="confirm">CONFIRM</h3>
<pre><code class="language-text">Sample 이동

고출력 Laser 변경

Robot Arm 큰 이동

실험 조건 변경</code></pre>
<h3 id="deny">DENY</h3>
<pre><code class="language-text">Safety Limit 해제

Emergency Stop 비활성화

위험 구역 진입

허가되지 않은 장비 제어</code></pre>
<p>이다.</p>
<p>이것은 MHS 공식 권한 Schema를 의미하는 것이 아니라, <strong>Physical Agent 시스템을 설계할 때 필요한 현실적인 Control Layer</strong>의 예다.</p>
<hr>
<h1 id="21-safety-limit은-prompt에만-넣으면-안-된다">21. Safety Limit은 Prompt에만 넣으면 안 된다</h1>
<p>가장 위험한 구조:</p>
<pre><code class="language-text">System Prompt:

&quot;로봇팔을 너무 빠르게 움직이지 마.&quot;</code></pre>
<p>이다.</p>
<p>Agent가 잘못 판단하면 끝이다.</p>
<p>더 좋은 구조:</p>
<pre><code class="language-text">Agent

↓

move(speed = 200)

↓

Hardware Safety Layer

max_speed = 80

↓

DENY</code></pre>
<p>즉 안전 규칙은 Agent 바깥에서 강제되어야 한다.</p>
<p>Anthropic도 MHS Reference 정보에 장비의 Safety Limit이 포함되고 Driver가 Agent가 장비를 안전하게 사용할 수 있도록 물리적 Context를 제공하는 구조를 설명한다. </p>
<hr>
<h1 id="22-physical-ai에서는-defense-in-depth가-더-중요하다">22. Physical AI에서는 Defense in Depth가 더 중요하다</h1>
<p>추천 구조:</p>
<pre><code class="language-text">                    AI Agent
                       │
                       ▼
                   MHS Layer
                       │
                       ▼
                  Policy Layer
                       │
             ┌─────────┼─────────┐
             ▼         ▼         ▼
          Limits   Permissions  Interlock
             │         │         │
             └─────────┼─────────┘
                       ▼
                  Device Driver
                       │
                       ▼
                  Safety PLC
                       │
                       ▼
                    Hardware</code></pre>
<p>Agent가 마지막 안전장치가 되어서는 안 된다.</p>
<hr>
<h1 id="23-emergency-stop은-ai가-판단하면-안-된다">23. Emergency Stop은 AI가 판단하면 안 된다</h1>
<p>예를 들어 로봇이 사람에게 접근한다.</p>
<p>이때:</p>
<pre><code class="language-text">Camera
↓
LLM
↓
사람인지 판단
↓
멈출까?</code></pre>
<p>같은 구조는 위험하다.</p>
<p>E-Stop이나 Collision Safety는:</p>
<pre><code class="language-text">Hardware

PLC

Safety Controller</code></pre>
<p>같은 결정적 시스템이 담당해야 한다.</p>
<p>AI는 그보다 위 Layer에 있는 것이 좋다.</p>
<hr>
<h1 id="24-physical-agent에는-digital-twin이-거의-필수에-가까워질-수-있다">24. Physical Agent에는 Digital Twin이 거의 필수에 가까워질 수 있다</h1>
<p>새로운 행동을 실제 기계에서 바로 실행할 필요는 없다.</p>
<p>추천 Workflow:</p>
<pre><code class="language-text">Goal

↓

Agent Plan

↓

Simulation / Digital Twin

↓

Safety Check

↓

Shadow Mode

↓

Human Approval

↓

Physical Execution</code></pre>
<p>이다.</p>
<p>예를 들어 Agent가 로봇팔 경로를 만든다.</p>
<p>먼저 Simulation에서:</p>
<pre><code class="language-text">충돌

Joint Limit

작업 시간

위험 Zone</code></pre>
<p>을 검증한다.</p>
<p>문제가 없을 때 실제 Hardware에서 실행한다.</p>
<hr>
<h1 id="25-shadow-mode도-굉장히-유용하다">25. Shadow Mode도 굉장히 유용하다</h1>
<p>Agent에게 실제 Control 권한을 주지 않는다.</p>
<p>대신:</p>
<pre><code class="language-text">현재 상태라면
무엇을 할 것인가?</code></pre>
<p>만 기록한다.</p>
<pre><code class="language-text">Physical Hardware
      │
      ▼
   Sensor Data
      │
      ▼
     Agent
      │
      ▼
Proposed Actions</code></pre>
<p>실제 작업자는 기존 Controller가 한다.</p>
<p>그리고:</p>
<pre><code class="language-text">Agent 선택

vs

Human 선택</code></pre>
<p>을 비교한다.</p>
<p>충분히 안정적이면 권한을 단계적으로 올린다.</p>
<hr>
<h1 id="26-처음부터-autonomous-factory를-만들-필요는-없다">26. 처음부터 Autonomous Factory를 만들 필요는 없다</h1>
<p>Physical AI 이야기가 나오면 금방:</p>
<pre><code class="language-text">무인 공장</code></pre>
<p>으로 가기 쉽다.</p>
<p>현실적인 도입 순서는 오히려:</p>
<pre><code class="language-text">Level 0
관찰

↓

Level 1
추천

↓

Level 2
사람 승인 후 실행

↓

Level 3
저위험 작업 자동 실행

↓

Level 4
고수준 Goal 기반 Workflow</code></pre>
<p>처럼 가는 편이 안전하다.</p>
<hr>
<h1 id="27-mhs가-제조업에서-흥미로운-이유도-여기에-있다">27. MHS가 제조업에서 흥미로운 이유도 여기에 있다</h1>
<p>공장에는 이미 수많은 자동화 Protocol이 있다.</p>
<pre><code class="language-text">PLC

OPC UA

ROS

Vendor SDK

Industrial Ethernet</code></pre>
<p>MHS가 이 모든 것을 없애는 것은 아니다.</p>
<p>오히려 위에 Agent Layer를 만들려는 접근에 가깝다.</p>
<pre><code class="language-text">                  AI Agent
                     │
                    MHS
                     │
        ┌────────────┼─────────────┐
        ▼            ▼             ▼
      ROS 2        OPC UA       Vendor SDK
        │            │             │
        ▼            ▼             ▼
      Robot       Machine        Sensor</code></pre>
<p>기존 산업제어 Protocol을 대체하기보다 Agent가 그것들을 일관된 방식으로 사용할 수 있게 하는 쪽이다.</p>
<hr>
<h1 id="28-즉-mhs는-hardware-os가-아니다">28. 즉 MHS는 Hardware OS가 아니다</h1>
<p>MHS가:</p>
<pre><code class="language-text">Robot Operating System 대체</code></pre>
<p>도 아니고:</p>
<pre><code class="language-text">PLC 대체</code></pre>
<p>도 아니다.</p>
<p>정확히는:</p>
<blockquote>
<p><strong>Agent가 여러 종류의 Programmable Hardware를 발견하고 이해하고 안전하게 사용하는 데 필요한 공통 Interface Layer</strong></p>
</blockquote>
<p>에 가깝다.</p>
<p>현재 Anthropic도 MHS가 <strong>programmable interface를 가진 장비</strong>를 대상으로 한다고 설명한다. </p>
<hr>
<h1 id="29-그럼-일반-개발자가-지금-mhs를-사용할-수-있을까">29. 그럼 일반 개발자가 지금 MHS를 사용할 수 있을까?</h1>
<p>현재는 제한적이다.</p>
<p>2026년 9월 기준 MHS는:</p>
<pre><code class="language-text">Research Preview</code></pre>
<p>단계다.</p>
<p>공식 사이트에서 신청을 받고 있으며 초기 파트너와 과학·로봇·전자·제조 분야 조직을 대상으로 테스트가 진행되고 있다. </p>
<p>핵심 Specification도 아직 일반 Open Source 상태는 아니다.</p>
<p>Anthropic은 Safety Evaluation과 Best Practice를 더 만든 뒤 Open Source할 계획이라고 밝혔다. </p>
<p>따라서 지금 GitHub에서:</p>
<pre><code class="language-bash">npm install mhs</code></pre>
<p>하고 시작하는 일반 개발자용 표준이라고 생각하면 아직 이르다.</p>
<hr>
<h1 id="30-하지만-지금-준비할-수-있는-것은-많다">30. 하지만 지금 준비할 수 있는 것은 많다</h1>
<p>MHS 자체를 사용하지 않더라도 Physical Agent Architecture를 비슷하게 설계해볼 수 있다.</p>
<p>예를 들어 Raspberry Pi + Camera + Motor가 있다고 하자.</p>
<p>기존:</p>
<pre><code class="language-text">Python Script
→ GPIO</code></pre>
<p>대신:</p>
<pre><code class="language-text">Device Adapter

read_state()
read_camera()
move_motor()
stop_motor()</code></pre>
<p>처럼 Capability를 분리한다.</p>
<p>그리고 별도로:</p>
<pre><code class="language-text">limits

permissions

device_state

safety</code></pre>
<p>를 정의한다.</p>
<hr>
<h1 id="31-작은-physical-agent를-만든다면-이런-구조가-좋다">31. 작은 Physical Agent를 만든다면 이런 구조가 좋다</h1>
<pre><code class="language-text">physical-agent/

├── devices/
│   ├── camera/
│   ├── motor/
│   └── temperature/
│
├── manifests/
│   ├── camera.yaml
│   ├── motor.yaml
│   └── temperature.yaml
│
├── policies/
│   └── safety.yaml
│
├── simulation/
│
├── logs/
│
└── agent/</code></pre>
<p>Device Manifest:</p>
<pre><code class="language-yaml">device: motor

capabilities:
  - read_position
  - move
  - stop

limits:
  position:
    min: 0
    max: 100

  speed:
    max: 20</code></pre>
<p>다시 말하지만 이것은 <strong>MHS 공식 Schema가 아니라 MHS의 설계 방향을 이해하기 위한 예시</strong>다.</p>
<hr>
<h1 id="32-중요한-것은-tool-이름보다-capability다">32. 중요한 것은 Tool 이름보다 Capability다</h1>
<p>Agent에게:</p>
<pre><code class="language-text">motor_move_x_140()</code></pre>
<p>같은 저수준 Tool을 무수히 노출하기보다:</p>
<pre><code class="language-text">readPosition
move
stop</code></pre>
<p>같은 안정된 Primitive를 제공한다.</p>
<p>그리고 Hardware별 차이는 Adapter가 처리한다.</p>
<pre><code class="language-text">                  Agent
                    │
            ┌───────┼───────┐
            ▼       ▼       ▼
           read    move    stop
                    │
                    ▼
                 Adapter
                    │
        ┌───────────┼────────────┐
        ▼           ▼            ▼
      Brand A     Brand B      Brand C</code></pre>
<p>장비가 바뀌어도 Agent Workflow는 크게 바뀌지 않는다.</p>
<hr>
<h1 id="33-physical-agent에서도-skill-개념이-중요해질-수-있다">33. Physical Agent에서도 Skill 개념이 중요해질 수 있다</h1>
<p>예를 들어:</p>
<pre><code class="language-text">laser-alignment</code></pre>
<p>이라는 Skill이 있다고 하자.</p>
<p>처음에는 Agent가 여러 번 탐색해 알아낸다.</p>
<p>그리고:</p>
<pre><code class="language-text">1. Camera 상태 확인
2. Laser Power 확인
3. Beam 위치 측정
4. Mirror 조정
5. 다시 측정
6. 오차 이하까지 반복</code></pre>
<p>같은 Workflow로 정리한다.</p>
<p>다음부터 Agent는 처음부터 다시 추론하지 않는다.</p>
<pre><code class="language-text">Agent
↓
Skill
↓
Deterministic Controller</code></pre>
<p>형태가 된다.</p>
<p>Software Agent에서 발전한 Skill 개념과 매우 비슷하다.</p>
<hr>
<h1 id="34-physical-agent의-로그는-더-중요하다">34. Physical Agent의 로그는 더 중요하다</h1>
<p>Coding Agent가 잘못된 코드를 만들었다면 Git Diff를 보면 된다.</p>
<p>Physical Agent는 작업이 지나가면 상태가 사라질 수도 있다.</p>
<p>따라서:</p>
<pre><code class="language-text">Timestamp

Device

Previous State

Command

Requested Value

Applied Value

Sensor Result

Agent Reason

Safety Decision</code></pre>
<p>같은 기록이 중요하다.</p>
<p>예:</p>
<pre><code class="language-json">{
  &quot;time&quot;: &quot;14:21:03&quot;,
  &quot;device&quot;: &quot;motor-02&quot;,
  &quot;action&quot;: &quot;move&quot;,
  &quot;requested&quot;: 18,
  &quot;applied&quot;: 18,
  &quot;position_before&quot;: 41,
  &quot;position_after&quot;: 59,
  &quot;result&quot;: &quot;success&quot;
}</code></pre>
<p>이런 Event Log가 있어야 사고가 발생했을 때 무엇이 일어났는지 확인할 수 있다.</p>
<hr>
<h1 id="35-agent-provenance가-hardware에서도-중요해진다">35. Agent Provenance가 Hardware에서도 중요해진다</h1>
<p>앞으로 질문은:</p>
<pre><code class="language-text">누가 Robot Arm을 움직였는가?</code></pre>
<p>만으로 끝나지 않을 수 있다.</p>
<pre><code class="language-text">어떤 Agent가

어떤 Goal을 받고

어떤 Sensor Data를 보고

어떤 Policy Version으로

어떤 Command를 실행했고

사람이 승인했는가?</code></pre>
<p>까지 필요할 수 있다.</p>
<p>특히:</p>
<pre><code class="language-text">Manufacturing

Medical

Laboratory

Warehouse

Energy</code></pre>
<p>같은 환경에서는 더욱 그렇다.</p>
<hr>
<h1 id="36-그래서-physical-agent-control-plane이-필요해진다">36. 그래서 Physical Agent Control Plane이 필요해진다</h1>
<p>앞으로 이런 시스템을 상상할 수 있다.</p>
<pre><code class="language-text">                    Agent Control Plane
                           │
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
       Identity         Permission        Tasks
          │                │                │
          └────────────────┼────────────────┘
                           ▼
                          MHS
                           │
             ┌─────────────┼─────────────┐
             ▼             ▼             ▼
          Robot         Camera        Machine</code></pre>
<p>여기에서:</p>
<pre><code class="language-text">Agent Identity

Device Permission

Action Budget

Safety Policy

Runtime Monitoring

Human Approval

Audit Log</code></pre>
<p>를 관리한다.</p>
<hr>
<h1 id="37-agent에게도-작업-예산이-필요하다">37. Agent에게도 ‘작업 예산’이 필요하다</h1>
<p>Software Agent에서:</p>
<pre><code class="language-text">Token Budget

Retry Budget</code></pre>
<p>를 두는 것처럼,</p>
<p>Physical Agent에는:</p>
<pre><code class="language-text">Motion Budget

Time Budget

Energy Budget

Sample Budget

Retry Budget</code></pre>
<p>같은 것도 필요할 수 있다.</p>
<p>예:</p>
<pre><code class="language-text">같은 Hardware Action
2회 실패

↓

STOP

↓

현재 상태 다시 읽기

↓

Human Notify</code></pre>
<p>같은 정책이다.</p>
<p>앞서 Software QA Agent에서도 중요한 원칙이었던:</p>
<pre><code class="language-text">Retry</code></pre>
<p>보다:</p>
<pre><code class="language-text">Re-observation</code></pre>
<p>이 Hardware에서는 훨씬 더 중요하다.</p>
<hr>
<h1 id="38-hardware-error-recovery는-ai-agent가-잘할-가능성이-있는-영역이다">38. Hardware Error Recovery는 AI Agent가 잘할 가능성이 있는 영역이다</h1>
<p>전통 Automation은:</p>
<pre><code class="language-text">Error Code 103
→ Procedure 103 실행</code></pre>
<p>형태가 많다.</p>
<p>하지만 실제 Hardware Failure는 복합적이다.</p>
<pre><code class="language-text">Sensor 변화

Temperature 변화

Motor 상태

Camera 결과

Power 상태</code></pre>
<p>를 함께 봐야 할 수 있다.</p>
<p>Agent가 여러 상태를 종합해서:</p>
<pre><code class="language-text">가능성 A

가능성 B

가능성 C</code></pre>
<p>를 판단하고 안전 범위 안에서 실험적으로 확인할 수 있다.</p>
<p>QuEra의 Laser 사례도 이 가능성을 보여준다. </p>
<hr>
<h1 id="39-하지만-llm의-physical-intuition은-아직-제한적이다">39. 하지만 LLM의 Physical Intuition은 아직 제한적이다</h1>
<p>이 부분은 반드시 같이 봐야 한다.</p>
<p>Anthropic도 이번 Research Preview를 바로 공개 표준으로 내놓지 않는 이유 중 하나로 <strong>AI Model이 실제 물리 세계를 충분히 이해하지 못한다는 점</strong>을 언급하고 있다.</p>
<p>텍스트와 이미지로 학습한 모델에게:</p>
<pre><code class="language-text">물체 질량

마찰

관성

기계 Backlash

Sensor Noise

온도 지연

Material Failure</code></pre>
<p>같은 실제 물리현상은 매우 어렵다.</p>
<p>그래서 먼저 제한된 파트너 환경에서 Safety Evaluation과 Best Practice를 만들겠다는 것이다. </p>
<hr>
<h1 id="40-physical-ai에서는-모델이-똑똑해질-때까지-기다린다도-답은-아니다">40. Physical AI에서는 ‘모델이 똑똑해질 때까지 기다린다’도 답은 아니다</h1>
<p>모델이 모든 물리 현상을 이해하게 만드는 것만 기다릴 필요는 없다.</p>
<p>더 좋은 Architecture는:</p>
<pre><code class="language-text">AI

+

Sensors

+

Deterministic Controller

+

Physical Constraints

+

Safety Interlock

+

Simulation

+

Human</code></pre>
<p>이다.</p>
<p>모델의 약점을 시스템으로 보완한다.</p>
<p>이건 최근 Software Agent Architecture와도 같은 방향이다.</p>
<hr>
<h1 id="41-mcp에서-배운-가장-중요한-교훈도-같다">41. MCP에서 배운 가장 중요한 교훈도 같다</h1>
<p>MCP가 성공적으로 확산된 이유 중 하나는:</p>
<pre><code class="language-text">모든 Tool을 모델에 직접 구현</code></pre>
<p>하지 않고:</p>
<pre><code class="language-text">Agent

↕

Standard Interface

↕

Tool</code></pre>
<p>로 분리했기 때문이다.</p>
<p>MHS도 비슷한 질문을 Hardware에 던지고 있다.</p>
<pre><code class="language-text">Agent마다

Robot Driver를 만들 것인가?</code></pre>
<p>아니면:</p>
<pre><code class="language-text">Hardware를 한 번 표준화해서

여러 Agent가 사용할 것인가?</code></pre>
<p>이다.</p>
<hr>
<h1 id="42-그래서-mcp-다음은-mhs라는-표현은-절반만-맞다">42. 그래서 ‘MCP 다음은 MHS’라는 표현은 절반만 맞다</h1>
<p>시간 순서상으로는 자연스럽다.</p>
<p>하지만 기술적으로:</p>
<pre><code class="language-text">MCP → MHS로 교체</code></pre>
<p>되는 것은 아니다.</p>
<p>더 정확하게는:</p>
<pre><code class="language-text">                    AI Agent
                       │
              ┌────────┴────────┐
              ▼                 ▼
             MCP               CLI
              │                 │
              └────────┬────────┘
                       ▼
                      MHS
                       │
                       ▼
                    Hardware</code></pre>
<p>같은 구조가 가능하다.</p>
<p><strong>MHS는 MCP를 밀어내는 것이 아니라 Physical Hardware를 MCP가 접근할 수 있는 새로운 Layer로 만드는 쪽에 가깝다.</strong></p>
<hr>
<h1 id="43-mhs가-열리면-개발자의-범위도-넓어질-수-있다">43. MHS가 열리면 개발자의 범위도 넓어질 수 있다</h1>
<p>지금 Agent 개발이라고 하면:</p>
<pre><code class="language-text">Web

Backend

Cloud

Coding Agent</code></pre>
<p>가 중심이다.</p>
<p>앞으로는:</p>
<pre><code class="language-text">Robotics

Smart Factory

Smart Home

Lab Automation

Warehouse

Agriculture

Energy

Medical Devices</code></pre>
<p>쪽에서도 Agent Application이 크게 늘 수 있다.</p>
<p>특히 Software Developer가 과거에는 접근하기 어려웠던 Hardware System에 들어갈 진입 장벽을 줄일 가능성이 있다.</p>
<hr>
<h1 id="44-개인-개발자에게-가장-가까운-분야는-smart-home과-robotics일-수-있다">44. 개인 개발자에게 가장 가까운 분야는 Smart Home과 Robotics일 수 있다</h1>
<p>예:</p>
<pre><code class="language-text">Agent

↓

Camera

Temperature Sensor

Robot

Matter Device

Home Assistant</code></pre>
<p>를 연결한다.</p>
<p>다만 소비자 IoT와 MHS가 직접 연결된다고 발표된 것은 아니다.</p>
<p>여기서 중요한 것은 <strong>MHS가 제시하는 Architecture Pattern</strong>이다.</p>
<pre><code class="language-text">Hardware Capability Description

Standard Driver

Shared State

Agent

Safety Boundary</code></pre>
<p>이 구조는 다양한 Physical Agent 시스템에서 참고할 만하다.</p>
<hr>
<h1 id="45-결국-agent의-세상이-화면-밖으로-나온다">45. 결국 Agent의 세상이 화면 밖으로 나온다</h1>
<p>최근 몇 년간 Agent는 빠르게 확장됐다.</p>
<pre><code class="language-text">Chat

↓

Code

↓

Browser

↓

Computer

↓

Cloud</code></pre>
<p>그리고 이제:</p>
<pre><code class="language-text">Physical Hardware</code></pre>
<p>까지 들어오기 시작했다.</p>
<p>Anthropic의 MHS Research Preview는 이 변화를 꽤 명확하게 보여준다.</p>
<hr>
<h1 id="46-앞으로-개발자가-고민해야-할-질문도-달라진다">46. 앞으로 개발자가 고민해야 할 질문도 달라진다</h1>
<p>Software Agent에서는:</p>
<pre><code class="language-text">이 Agent에게 Git Write를 허용할까?</code></pre>
<p>를 고민했다.</p>
<p>Physical Agent에서는:</p>
<pre><code class="language-text">이 Agent에게 Robot Arm을 얼마나 빠르게 움직일 권한을 줄까?

Sample을 폐기할 수 있게 할까?

몇 번까지 Retry하게 할까?

어떤 작업은 반드시 사람이 승인해야 할까?</code></pre>
<p>를 고민해야 한다.</p>
<p>Agent Permission이 곧 <strong>물리적 권한</strong>이 된다.</p>
<hr>
<h1 id="47-physical-agent에서-가장-중요한-것은-intelligence보다-boundaries일-수-있다">47. Physical Agent에서 가장 중요한 것은 Intelligence보다 Boundaries일 수 있다</h1>
<p>엄청나게 똑똑한 Agent보다:</p>
<pre><code class="language-text">무엇을 할 수 있고

무엇을 할 수 없으며

언제 멈춰야 하는지</code></pre>
<p>가 명확한 Agent가 더 안전할 수 있다.</p>
<p>따라서 MHS 이후의 핵심은:</p>
<pre><code class="language-text">Agent Intelligence</code></pre>
<p>만이 아니다.</p>
<pre><code class="language-text">Agent
+
Hardware Contract
+
Safety Boundary
+
Runtime Verification</code></pre>
<p>이다.</p>
<hr>
<h1 id="48-개발자가-지금-준비할-만한-architecture">48. 개발자가 지금 준비할 만한 Architecture</h1>
<p>지금부터 Physical AI를 공부한다면 다음 구조를 추천할 수 있다.</p>
<pre><code class="language-text">                   Goal
                    │
                    ▼
                AI Agent
                    │
                    ▼
               Planner
                    │
                    ▼
                Simulator
                    │
                    ▼
              Safety Policy
                    │
                    ▼
              Device Adapter
                    │
                    ▼
                 Hardware
                    │
                    ▼
                  Sensor
                    │
                    └──────────→ Agent</code></pre>
<p>그리고 모든 Action을 Log한다.</p>
<pre><code class="language-text">Observe
→ Plan
→ Validate
→ Act
→ Observe
→ Verify</code></pre>
<p>이 Loop가 기본이 된다.</p>
<hr>
<h1 id="49-mhs가-open-source되면-가장-먼저-보고-싶은-부분">49. MHS가 Open Source되면 가장 먼저 보고 싶은 부분</h1>
<p>현재 공개 자료만으로는 실제 Specification 전체를 볼 수 없다.</p>
<p>그래서 정식 Open Source 이후 특히 확인할 부분은:</p>
<pre><code class="language-text">Device Manifest Schema

Discovery

Authentication

Permission Model

Safety Limit 표현

Unit 표현

Failure / Recovery

State Synchronization

Network Protocol

Driver Conformance

Simulation Interface

Audit / Provenance</code></pre>
<p>이다.</p>
<p>특히 <strong>Safety가 Prompt 수준인지 Driver 수준에서 얼마나 강하게 강제되는지</strong>가 중요하다.</p>
<hr>
<h1 id="50-지금-단계에서-mhs를-과대평가해서도-안-된다">50. 지금 단계에서 MHS를 과대평가해서도 안 된다</h1>
<p>현재 MHS는:</p>
<pre><code class="language-text">Research Preview</code></pre>
<p>다.</p>
<p>아직:</p>
<pre><code class="language-text">업계 표준으로 확정</code></pre>
<p>된 것도 아니고,</p>
<pre><code class="language-text">모든 Robot 업체가 채택</code></pre>
<p>한 것도 아니다.</p>
<p>또:</p>
<pre><code class="language-text">AI가 공장을 완전히 자율 운영</code></pre>
<p>한다는 의미도 아니다.</p>
<p>Anthropic과 초기 파트너들이 <strong>AI Agent와 Physical Hardware를 연결하기 위한 공통 규격을 실험하기 시작했다</strong>고 보는 것이 정확하다. </p>
<hr>
<h1 id="마무리">마무리</h1>
<p>MCP가 중요한 이유는 AI에게 새로운 지능을 준 것이 아니었다.</p>
<p>AI가 사용할 수 있는 <strong>Software Tool의 세계를 표준화된 방식으로 넓혔기 때문</strong>이다.</p>
<p>MHS가 흥미로운 이유도 같다.</p>
<p>단순히 Claude가 Robot Arm을 움직였다는 이야기가 아니다.</p>
<p>더 중요한 질문은:</p>
<pre><code class="language-text">AI Agent가
서로 다른 물리 장비를
어떻게 발견하고,

무엇을 할 수 있는지 이해하고,

현재 상태를 읽고,

안전한 범위 안에서 조작하고,

여러 장비를 하나의 Workflow로 묶을 것인가?</code></pre>
<p>이다.</p>
<p>Anthropic이 공개한 구조에서는 MHS Driver가 장비별 API 차이를 표준화하고, Device Reference가 측정 가능 값·조절 가능한 값·물리적 특성과 안전 한계를 Agent에게 알려준다. MCP·CLI·Code File을 통해 Agent가 장비를 제어할 수 있고, 반복적이거나 빠른 작업은 Agent가 직접 매 순간 추론하지 않고 Deterministic Code로 내려보낼 수도 있다. </p>
<p>이 구조가 중요한 이유는 결국 <strong>Agent가 사용하는 Tool의 정의가 바뀌기 때문</strong>이다.</p>
<p>지금까지:</p>
<pre><code class="language-text">Tool
=
API
Database
Browser
Git</code></pre>
<p>였다면,</p>
<p>앞으로는:</p>
<pre><code class="language-text">Tool
=
Robot
Microscope
Camera
Laser
Machine
Sensor</code></pre>
<p>도 된다.</p>
<p>하지만 Software와 Physical World 사이에는 결정적인 차이가 있다.</p>
<p>Software는 잘못되면 Rollback할 수 있는 경우가 많다.</p>
<p>Physical World에는:</p>
<pre><code class="language-text">Undo</code></pre>
<p>가 없는 작업이 많다.</p>
<p>그래서 Physical Agent 시대에는 모델의 Intelligence만큼이나:</p>
<pre><code class="language-text">Safety Limits

Permissions

Deterministic Controllers

Simulation

Retry Budget

Emergency Stop

Audit Log

Human Approval</code></pre>
<p>이 중요해진다.</p>
<p>한 문장으로 정리하면:</p>
<blockquote>
<p><strong>MHS의 진짜 의미는 AI에게 기계를 움직일 권한을 주는 것이 아니라, AI가 실제 기계를 사용할 때 필요한 공통 언어와 안전 경계를 만들기 시작했다는 데 있다.</strong></p>
</blockquote>
<p>그리고 이 방향이 자리 잡는다면 Agent 개발의 범위도 크게 달라질 수 있다.</p>
<pre><code class="language-text">Software Agent</code></pre>
<p>에서:</p>
<pre><code class="language-text">Physical Agent</code></pre>
<p>로.</p>
<pre><code class="language-text">Coding Automation</code></pre>
<p>에서:</p>
<pre><code class="language-text">Experiment Automation
Manufacturing Automation
Robotics Automation</code></pre>
<p>으로.</p>
<p>AI Agent가 화면 밖으로 나오기 시작한 셈이다.</p>
<p>MCP가 Agent에게 Software World의 문을 열었다면,</p>
<p><strong>MHS는 Physical World의 문을 열려는 첫 시도 중 하나다.</strong></p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<p><strong>Anthropic — Previewing the Model Hardware Standard, 2026-08-27</strong><br>MHS Research Preview의 공식 발표. MHS는 HHMI Janelia Research Campus와의 협력에서 시작됐으며 현미경·Liquid Handler·Robot Arm·Quantum Laser 등 Programmable Hardware를 AI Agent가 공통 Interface를 통해 제어하는 방향을 제시한다. Standardized Driver, read/write Primitive, Device Discovery, Natural-language Hardware Context, Safety Limits, MCP·CLI·Code File 기반 제어 구조를 설명한다. </p>
<p><strong>Model Hardware Standard 공식 사이트</strong><br>현재 MHS는 Limited Research Preview이며 과학·로봇·전자·제조 분야 파트너를 대상으로 신청을 받고 있다. Safety Evaluation과 Best Practice 개발 이후 Open Source할 계획이다. </p>
<p><strong>Anthropic / QuEra MHS 사례</strong><br>Quantum Computer Laser System의 Lock Recovery에 MHS 기반 Agent를 적용한 사례에서 기존 수작업·Bespoke Automation과 다른 Adaptive Recovery 접근을 보여준다. 공개 결과에서 MHS 기반 Controller는 실험 환경에서 99.3퍼센트의 Lock Recovery 성공률을 기록했다. </p>
<p><strong>HHMI Janelia Research Campus</strong><br>MHS는 Janelia의 연구 장비 통합 문제를 해결하려는 작업에서 출발했다. Janelia는 다양한 Custom Microscope와 연구용 Hardware를 개발·운영하는 연구기관으로, Open Science와 Hardware/Software 도구 공개도 지속하고 있다. </p>
<h3 id="핵심-참고-포인트">핵심 참고 포인트</h3>
<p>MHS는 MCP의 대체물이 아니다. <strong>MHS가 Hardware를 공통 Driver와 Device Description으로 표준화하고 MCP는 Agent가 그 Hardware에 접근하는 방법 중 하나가 될 수 있다.</strong> Anthropic은 MCP 외에도 CLI와 Code File/API를 MHS 제어 방식으로 설명하고 있다. </p>
<p>또한 현재 MHS는 일반 개발자가 바로 설치해서 사용하는 완성형 Open Source 표준이 아니라 제한된 Research Preview다. 따라서 공개된 구조를 기반으로 Physical Agent Architecture를 연구할 수는 있지만, 실제 MHS 공식 Schema나 구현 세부사항을 임의로 가정해서는 안 된다. </p>
<p>가장 흥미로운 기술적 패턴은 <strong>Agent가 처음에는 Hardware를 탐색적으로 조작하고, 반복 가능한 관계를 학습한 뒤 그 행동을 Deterministic Code로 변환하는 방식</strong>이다. AI가 모든 제어 순간마다 추론하는 것이 아니라 <code>AI Reasoning → Controller 생성 → 빠른 Runtime 실행</code>으로 역할을 분리한다. Physical Agent가 실제 산업 환경으로 확장될수록 이 구조와 함께 Safety Boundary·Simulation·Hardware Interlock·Audit가 핵심이 될 가능성이 높다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GPT-6 Astra 이후, Coding Agent는 Engineering Agent가 된다]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609051</link>
            <guid>https://velog.io/@kyu_ios_dev/2609051</guid>
            <pubDate>Sat, 05 Sep 2026 07:56:45 GMT</pubDate>
            <description><![CDATA[<h4 id="gpt-6-astra-이후-coding-agent는-engineering-agent가-된다">GPT-6 Astra 이후, Coding Agent는 Engineering Agent가 된다</h4>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/748c904f-c4c4-49a8-9246-0b9b385c366d/image.png" alt=""></p>
<p>GPT-6 Astra가 나온 지금, 개발자 입장에서 가장 중요한 변화는 모델 점수 하나가 더 올라갔다는 사실이 아니다.</p>
<p>OpenAI는 Astra를 단순한 코딩 모델이 아니라 <strong>복잡한 추론·코딩·브라우징·컴퓨터 사용·전문 업무를 하나의 멀티스텝 작업으로 수행하는 모델</strong>로 소개하고 있다. 특히 코드, 브라우저, 전문 소프트웨어를 오가며 end-to-end 작업을 수행하는 능력을 전면에 내세웠다. </p>
<p>이 변화는 Coding Agent라는 말의 의미를 바꾼다.</p>
<p>지금까지의 Coding Agent가 대략 이런 역할이었다면,</p>
<pre><code class="language-text">요구사항
  ↓
Repository 조사
  ↓
코드 수정
  ↓
Build / Test</code></pre>
<p>Astra 이후의 Agent는 점점 이런 형태에 가까워진다.</p>
<pre><code class="language-text">Goal
  ↓
Repository 조사
  ↓
관련 문서 조사
  ↓
Browser 사용
  ↓
전문 도구 실행
  ↓
구현
  ↓
Build / Test
  ↓
실패 원인 분석
  ↓
다른 방법으로 복구
  ↓
Runtime 확인
  ↓
결과물 생성
  ↓
Human Review</code></pre>
<p>즉 <strong>Coding Agent에서 Engineering Agent로 이동하고 있다.</strong></p>
<hr>
<h2 id="1-astra의-핵심은-코드를-더-잘-쓰는-것이-아니다">1. Astra의 핵심은 코드를 더 잘 쓰는 것이 아니다</h2>
<p>GPT-6 Astra는 2026년 9월 3일 발표됐다.</p>
<p>OpenAI는 Astra를 “가장 어려운 end-to-end work”를 위한 모델이라고 설명하고 있으며, software engineering뿐 아니라 computer use, browsing, science, research, 문서·스프레드시트·프레젠테이션 제작까지 하나의 작업 흐름에서 다룰 수 있도록 설계했다고 밝히고 있다. </p>
<p>이 설명에서 중요한 단어는 <code>coding</code>보다 <strong>end-to-end</strong>다.</p>
<p>기존 Coding Agent의 성공 기준은 보통:</p>
<pre><code class="language-text">코드를 수정했는가?</code></pre>
<p>였다.</p>
<p>Engineering Agent의 성공 기준은 다르다.</p>
<pre><code class="language-text">요청된 업무가
실제로 완료됐는가?</code></pre>
<p>다.</p>
<p>예를 들어:</p>
<blockquote>
<p>신규 결제 Flow를 만들고 실제 브라우저에서 검증한 뒤 QA 결과까지 정리해.</p>
</blockquote>
<p>라는 Goal이 있다고 하자.</p>
<p>Coding Agent라면:</p>
<pre><code class="language-text">React 코드 작성
API 연결
Test 작성</code></pre>
<p>정도까지 갈 수 있다.</p>
<p>Engineering Agent는:</p>
<pre><code class="language-text">기존 결제 구조 조사
        ↓
Backend API 확인
        ↓
Frontend 구현
        ↓
브라우저 실행
        ↓
결제 Flow 사용
        ↓
Console / Network 확인
        ↓
실패 발견
        ↓
코드 수정
        ↓
재검증
        ↓
결과 정리</code></pre>
<p>까지가 하나의 Task다.</p>
<p>개발 단위 자체가 달라지는 것이다.</p>
<hr>
<h1 id="2-코드가-아니라-업무를-맡기기-시작한다">2. 코드가 아니라 ‘업무’를 맡기기 시작한다</h1>
<p>예전 Prompt는 이런 식이었다.</p>
<pre><code class="language-text">이 함수 리팩터링해줘.</code></pre>
<p>조금 지나서는:</p>
<pre><code class="language-text">이 Feature 구현하고 테스트까지 해줘.</code></pre>
<p>였다.</p>
<p>앞으로는 점점 이렇게 바뀔 가능성이 크다.</p>
<pre><code class="language-text">회원가입 전환율이 떨어지는 원인을 조사하고,
관련 Frontend 문제를 수정한 뒤
실제 Browser에서 Flow를 검증해.</code></pre>
<p>이 요청에는:</p>
<pre><code class="language-text">Data 조사
UI 분석
코드 탐색
구현
브라우저 조작
QA
결과 보고</code></pre>
<p>가 동시에 들어 있다.</p>
<p>Astra가 강조하는 것도 이런 멀티스텝 Workflow다. OpenAI 공식 문서는 Astra가 코드, 브라우저, 전문 소프트웨어 사이를 오가며 복합적인 작업을 수행하도록 설계됐다고 설명한다. </p>
<p>이제 AI에게 맡기는 단위가:</p>
<pre><code class="language-text">Function</code></pre>
<p>에서:</p>
<pre><code class="language-text">Feature</code></pre>
<p>를 거쳐:</p>
<pre><code class="language-text">Engineering Goal</code></pre>
<p>로 커지고 있다.</p>
<hr>
<h1 id="3-async-tool-calling이-이-변화에서-상당히-중요하다">3. Async Tool Calling이 이 변화에서 상당히 중요하다</h1>
<p>Astra에는 눈에 띄는 기능이 하나 있다.</p>
<p><strong>Async Tool Calling</strong>이다.</p>
<p>기존 Agent Workflow는 흔히:</p>
<pre><code class="language-text">Agent
  ↓
Tool 호출
  ↓
기다림
  ↓
Tool 결과
  ↓
다음 작업</code></pre>
<p>형태였다.</p>
<p>Build가 3분 걸리면 Agent도 사실상 기다렸다.</p>
<p>Astra에서는 Tool을 비동기로 호출한 상태에서도 다른 작업을 계속 수행할 수 있다. Application이 실제 Tool 실행과 Pending 상태를 관리하고, 결과가 준비되면 기존 <code>call_id</code>를 이용해 다시 전달하는 구조다. </p>
<p>개발 Workflow에 적용하면:</p>
<pre><code class="language-text">Agent
 ├─ Backend Test 실행 ───────────┐
 │                              │
 ├─ 기다리지 않고 Frontend 조사 │
 │                              │
 ├─ Docs 확인                    │
 │                              │
 └─ Test 결과 수신 ◀────────────┘</code></pre>
<p>이런 형태가 가능해진다.</p>
<p>사람 개발자와 비슷하다.</p>
<p>개발자가:</p>
<pre><code class="language-text">빌드 돌려놓고

↓

다른 파일 확인하고

↓

문서 읽고

↓

빌드 끝나면 결과 확인</code></pre>
<p>하는 것처럼 Agent도 Tool Waiting Time을 다른 작업에 사용할 수 있다.</p>
<p>이건 단순한 속도 개선 이상의 변화다.</p>
<p><strong>Agent가 작업 Scheduler처럼 행동하기 시작한다.</strong></p>
<hr>
<h1 id="4-mid-turn-steering도-개발환경에서는-큰-변화다">4. Mid-turn Steering도 개발환경에서는 큰 변화다</h1>
<p>Astra의 또 다른 새 기능은 <strong>Mid-turn Steering</strong>이다.</p>
<p>Agent가 긴 작업을 수행하는 도중 추가 지시를 넣을 수 있다. </p>
<p>예를 들어 Agent가 작업 중이다.</p>
<pre><code class="language-text">Repository 조사
↓
Architecture 분석
↓
Implementation 진행 중...</code></pre>
<p>그때 개발자가:</p>
<pre><code class="language-text">잠깐.
기존 Public API는 절대 변경하지 마.</code></pre>
<p>라고 추가한다.</p>
<p>예전에는 작업을 중단하고 다시 Prompt를 만들어야 하는 경우가 많았다.</p>
<p>Mid-turn Steering에서는:</p>
<pre><code class="language-text">기존 Goal
+
현재 Context
+
추가 Constraint</code></pre>
<p>를 유지한 상태에서 방향을 바꿀 수 있다.</p>
<p>실제 개발팀에서 Tech Lead가:</p>
<blockquote>
<p>그 방향 말고 기존 Interface 유지하면서 해주세요.</p>
</blockquote>
<p>라고 중간에 이야기하는 것과 비슷하다.</p>
<p>Agent가 단순 명령 실행기가 아니라 <strong>계속 협업 중인 Worker</strong>에 가까워진다.</p>
<hr>
<h1 id="5-그러면-개발자의-역할도-바뀐다">5. 그러면 개발자의 역할도 바뀐다</h1>
<p>AI가 코드를 더 많이 작성한다고 개발자의 역할이 사라지는 것은 아니다.</p>
<p>오히려 개발자가 다뤄야 하는 추상화 수준이 올라간다.</p>
<p>기존:</p>
<pre><code class="language-text">Developer

코드 작성</code></pre>
<p>Agent 시대:</p>
<pre><code class="language-text">Developer

Goal 정의
Constraint 정의
Architecture 판단
Agent 작업 분할
결과 검증</code></pre>
<p>즉 개발자는:</p>
<pre><code class="language-text">어떻게 구현할까?</code></pre>
<p>를 고민하는 시간 일부를 줄이고,</p>
<pre><code class="language-text">무엇을 맡길까?

어디까지 맡길까?

어떤 결과면 성공인가?

어떤 판단은 사람이 해야 하나?</code></pre>
<p>를 더 많이 고민하게 된다.</p>
<p>최근 Coding Agent에서 이미 보이던 변화인데 Astra 같은 모델에서는 훨씬 명확해질 가능성이 크다.</p>
<hr>
<h1 id="6-가장-중요한-것은-goal을-제대로-만드는-능력이다">6. 가장 중요한 것은 Goal을 제대로 만드는 능력이다</h1>
<p>Engineering Agent에게:</p>
<pre><code class="language-text">이 앱 개선해줘.</code></pre>
<p>라고 하면 너무 넓다.</p>
<p>반대로:</p>
<pre><code class="language-text">Button padding을 8에서 12로 바꿔.</code></pre>
<p>라고 하면 Engineering Agent를 사용하는 의미가 줄어든다.</p>
<p>좋은 Goal은 이 중간이다.</p>
<p>예:</p>
<pre><code class="language-text">Goal:
신규 사용자의 가입 완료율을 떨어뜨리는
Frontend UX 문제를 조사하고 수정한다.

Scope:
signup 관련 React components만 수정 가능.

Constraints:
Backend API 변경 금지.
새 Dependency 추가 금지.

Validation:
Desktop + Mobile Browser에서
회원가입 Flow를 실제 수행한다.

Completion:
- Build PASS
- E2E PASS
- Console Error 없음
- 변경 내용과 발견된 UX 문제 보고</code></pre>
<p>이 정도가 Engineering Agent에게 적절하다.</p>
<p>즉 Prompt Engineering보다 앞으로 더 중요한 것은 <strong>Goal Engineering</strong>일 수 있다.</p>
<hr>
<h1 id="7-agentsmd와-skills가-오히려-더-중요해진다">7. AGENTS.md와 Skills가 오히려 더 중요해진다</h1>
<p>모델이 강해질수록:</p>
<pre><code class="language-text">이제 세부 규칙 안 적어도 알아서 잘하겠지.</code></pre>
<p>라고 생각하기 쉽다.</p>
<p>그런데 OpenAI의 Astra 가이드는 오히려 반대 방향을 주의시킨다.</p>
<p>Astra는 이전 모델보다 instruction following이 강하고, <code>AGENTS.md</code>나 Skills처럼 접근 가능한 파일의 지침에도 더 민감하게 반응할 수 있다. OpenAI는 여러 Skills와 instruction file을 사용하는 환경에서는 서로 충돌하거나 조용히 영향을 주는 지침을 감사할 것을 권장하고 있다. </p>
<p>즉 모델이 강할수록:</p>
<pre><code class="language-text">AGENTS.md
Skills
Architecture Docs
Security Policy
Testing Rules</code></pre>
<p>의 품질이 더 중요해질 수 있다.</p>
<p>강한 Agent는 잘못된 지시도 더 충실히 수행할 가능성이 있기 때문이다.</p>
<hr>
<h1 id="8-agentsmd는-설명서보다-경계선이어야-한다">8. AGENTS.md는 ‘설명서’보다 경계선이어야 한다</h1>
<p>좋은 <code>AGENTS.md</code>는 모든 Architecture를 설명하는 2만 줄짜리 문서가 아니다.</p>
<p>예:</p>
<pre><code class="language-markdown"># Project Rules

- Public API 변경 전 확인한다.
- 새 Dependency를 임의로 추가하지 않는다.
- Production Credential을 읽지 않는다.
- 관련 테스트 없이 완료 처리하지 않는다.
- 테스트하지 못한 부분은 Not Verified로 보고한다.
- Architecture 변경은 먼저 계획을 제시한다.</code></pre>
<p>이런 규칙이 더 중요하다.</p>
<p>Agent 입장에서:</p>
<pre><code class="language-text">무엇을 할 수 있는가?</code></pre>
<p>보다:</p>
<pre><code class="language-text">무엇은 하면 안 되는가?</code></pre>
<p>를 명확하게 만드는 것이다.</p>
<p>Engineering Agent의 자율성이 높아질수록 Boundaries가 중요해진다.</p>
<hr>
<h1 id="9-skill은-작업-방법을-고정한다">9. Skill은 ‘작업 방법’을 고정한다</h1>
<p>예를 들어 iOS Bug Fix Skill을 만들 수 있다.</p>
<pre><code class="language-text">Goal 확인
↓
관련 코드 조사
↓
재현
↓
가설 작성
↓
수정
↓
Build
↓
관련 Test
↓
Simulator 확인
↓
완료 보고</code></pre>
<p>Web QA Skill:</p>
<pre><code class="language-text">Scenario 확인
↓
Browser 실행
↓
실제 사용자 Flow 수행
↓
Console 확인
↓
Network 확인
↓
Screenshot / Trace
↓
UX Finding</code></pre>
<p>Security Skill:</p>
<pre><code class="language-text">Git Diff
↓
Secret
↓
Auth
↓
Authorization
↓
PII
↓
Cloud Permission
↓
Dependency
↓
Risk 등급</code></pre>
<p>Astra가 강해졌다고 Workflow가 사라지는 것이 아니다.</p>
<p>오히려 <strong>좋은 Workflow를 훨씬 더 안정적으로 수행할 수 있게 되는 것</strong>에 가깝다.</p>
<hr>
<h1 id="10-engineering-agent에게-모든-권한을-주면-안-된다">10. Engineering Agent에게 모든 권한을 주면 안 된다</h1>
<p>여기서 중요한 문제가 발생한다.</p>
<p>Astra는 OpenAI가 지금까지 광범위하게 배포한 모델 가운데 처음으로 사이버보안 능력이 Preparedness Framework의 <code>Critical</code> 기준에 도달한 모델이다. OpenAI는 Astra가 적절한 도구와 접근권한이 있을 경우 새로운 보안 취약점을 찾고 활용하는 작업까지 매우 강해졌다고 설명한다. </p>
<p>이건 개발자에게도 중요한 신호다.</p>
<p>모델이 강해질수록:</p>
<pre><code class="language-text">Shell
Git
AWS
Production
Database
Browser
Credential</code></pre>
<p>에 대한 접근을 더 신중하게 관리해야 한다.</p>
<p>Agent Capability가 올라갈수록 Permission 설계가 더 중요해진다.</p>
<hr>
<h1 id="11-그래서-auto--confirm--deny가-필요하다">11. 그래서 AUTO / CONFIRM / DENY가 필요하다</h1>
<p>예를 들어:</p>
<h3 id="auto">AUTO</h3>
<pre><code class="language-text">파일 검색
코드 수정
Unit Test 실행
Local Build
Formatting
Lint</code></pre>
<h3 id="confirm">CONFIRM</h3>
<pre><code class="language-text">새 Dependency 추가
Public API 변경
Database Migration
새 Cloud Resource
외부 서비스 연결</code></pre>
<h3 id="deny">DENY</h3>
<pre><code class="language-text">Production Secret 읽기
Production DB 직접 수정
main 강제 Push
Security Policy 해제
Credential Export</code></pre>
<p>이런 식으로 나눈다.</p>
<p>강한 Agent에게:</p>
<pre><code class="language-text">알아서 해.</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">여기까지는 알아서 해.
그 이상은 물어봐.
여기는 절대 건드리지 마.</code></pre>
<p>를 정의한다.</p>
<hr>
<h1 id="12-openai가-astra에-추가-safety-monitoring을-넣은-이유도-여기-있다">12. OpenAI가 Astra에 추가 Safety Monitoring을 넣은 이유도 여기 있다</h1>
<p>OpenAI는 Astra가 사용자의 지시를 잘못 해석했을 가능성을 탐지하는 추가 Safety Monitoring을 도입했다고 밝혔다.</p>
<p>잠재적인 문제가 감지되면 Conversation이나 작업을 일시 중지하거나 종료하고 사용자가 검토하도록 할 수 있다. </p>
<p>이건 앞으로 Agent Runtime에 중요한 개념이 될 수 있다.</p>
<pre><code class="language-text">Agent
   ↓
Action
   ↓
Runtime Monitor
   ↓
Expected Boundary?
     │
 YES │ NO
     │
     ▼
 Continue   Pause
               ↓
            Human</code></pre>
<p>즉 AI Model 자체만 강해지는 것이 아니라:</p>
<pre><code class="language-text">AI
+
Monitor
+
Policy
+
Human Gate</code></pre>
<p>형태의 시스템이 중요해진다.</p>
<hr>
<h1 id="13-coding-agent-하나가-모든-걸-할-필요도-없다">13. Coding Agent 하나가 모든 걸 할 필요도 없다</h1>
<p>Astra가 매우 강한 모델이라고 해서 모든 작업을 Astra 하나에게 맡기는 것이 반드시 좋은 Architecture는 아니다.</p>
<p>오히려 역할을 나눌 수 있다.</p>
<pre><code class="language-text">Astra
= Planner / Complex Engineering

Codex Worker
= Implementation

Claude
= Independent Review

Playwright
= Web Runtime Verification

CI
= Deterministic Gate</code></pre>
<p>또는 OpenAI 모델 안에서도:</p>
<pre><code class="language-text">Astra
= 어려운 판단

Sol
= 일반 구현

Terra
= 반복 작업

Luna
= 대량 저비용 작업</code></pre>
<p>처럼 Routing할 수 있다.</p>
<p>OpenAI의 현재 모델 가이드에서도 Astra는 가장 어려운 end-to-end work를 위한 모델로, Terra는 intelligence와 cost의 균형, Luna는 비용 민감한 대량 작업에 적합한 모델로 분류하고 있다. </p>
<p>즉 Engineering Agent 시대에는 <strong>모델 하나보다 팀 구성</strong>이 중요해진다.</p>
<hr>
<h1 id="14-개인-개발자도-작은-ai-개발팀을-만들-수-있다">14. 개인 개발자도 작은 AI 개발팀을 만들 수 있다</h1>
<p>예를 들어 Workspace가:</p>
<pre><code class="language-text">workspace/

├── ios-app/
├── android-app/
├── web/
└── backend/</code></pre>
<p>처럼 여러 Git Repository로 나뉘어 있다고 하자.</p>
<p>상위 Orchestrator:</p>
<pre><code class="language-text">Codex / Astra</code></pre>
<p>하위 작업:</p>
<pre><code class="language-text">ios-app
→ 구현 Agent

android-app
→ 조사 Agent

web
→ Browser QA Agent

backend
→ Test Agent</code></pre>
<p>그리고 독립 Reviewer:</p>
<pre><code class="language-text">Claude Review</code></pre>
<p>를 붙인다.</p>
<p>구조는:</p>
<pre><code class="language-text">                    Human
                      │
                      ▼
                Astra / Codex
                  Orchestrator
                      │
       ┌──────────────┼──────────────┐
       ▼              ▼              ▼
     iOS Agent    Android Agent   Web Agent
       │              │              │
       └──────────────┼──────────────┘
                      ▼
                 Build / Tests
                      │
                      ▼
                Claude Review
                      │
                      ▼
                  Runtime QA
                      │
                      ▼
                    Human</code></pre>
<p>한 명의 개발자가 작은 개발조직을 운영하는 구조다.</p>
<hr>
<h1 id="15-여기서-astra는-최고의-코더보다-상위-오케스트레이터에-더-어울릴-수-있다">15. 여기서 Astra는 ‘최고의 코더’보다 ‘상위 오케스트레이터’에 더 어울릴 수 있다</h1>
<p>Astra는 API 기준 input 100만 토큰당 10달러, output 50달러다.</p>
<p>GPT-5.6 Sol은 input 4달러, output 20달러다. 두 모델 모두 1,050,000 token context와 최대 128,000 output token을 지원한다. </p>
<p>Astra는 Sol보다 토큰 단가가 2.5배 높다.</p>
<p>따라서 모든 작은 작업을 Astra에 맡기는 것은 비용 면에서 비효율적일 수 있다.</p>
<p>예:</p>
<pre><code class="language-text">Import 정리
→ Astra

Naming 수정
→ Astra

Unit Test Fixture
→ Astra</code></pre>
<p>보다:</p>
<pre><code class="language-text">복잡한 Goal 분해
→ Astra

Repository-wide 설계 판단
→ Astra

일반 구현
→ Sol / Terra

반복적인 작업
→ Luna</code></pre>
<p>가 훨씬 현실적이다.</p>
<hr>
<h1 id="16-하지만-단순-token-가격만-보면-안-된다">16. 하지만 단순 Token 가격만 보면 안 된다</h1>
<p>OpenAI는 Astra가 일부 평가에서 이전 모델보다 훨씬 적은 출력 토큰으로 더 높은 성능을 달성해, 높은 토큰 단가에도 불구하고 Task 단위 예상 비용을 낮출 수 있다고 설명한다. </p>
<p>이건 Coding Agent에서도 중요하다.</p>
<p>예:</p>
<pre><code class="language-text">Sol

3번 시도
+
긴 Log
+
Human Intervention</code></pre>
<p>대:</p>
<pre><code class="language-text">Astra

1번 시도
+
완료</code></pre>
<p>라면 Astra가 비싸더라도 전체 비용은 낮을 수 있다.</p>
<p>그래서 봐야 하는 것은:</p>
<pre><code class="language-text">Cost per Token</code></pre>
<p>보다:</p>
<pre><code class="language-text">Cost per Successful Task</code></pre>
<p>다.</p>
<hr>
<h1 id="17-engineering-agent-시대의-진짜-kpi">17. Engineering Agent 시대의 진짜 KPI</h1>
<p>이제 Agent 성능을:</p>
<pre><code class="language-text">Generated LOC

Token

PR Count</code></pre>
<p>로 보면 안 된다.</p>
<p>더 중요한 지표는:</p>
<pre><code class="language-text">Successful Task Rate

Human Intervention Count

Retry Count

Recovery Success Rate

Review Time

Regression Rate

Cost per Successful Task</code></pre>
<p>이다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Agent A

작업 성공 95%
사람 개입 1회
Review 10분</code></pre>
<pre><code class="language-text">Agent B

작업 성공 95%
사람 개입 9회
Review 40분</code></pre>
<p>같은 성공률이라도 실제 생산성은 완전히 다르다.</p>
<hr>
<h1 id="18-특히-human-attention이-핵심-자원이-된다">18. 특히 Human Attention이 핵심 자원이 된다</h1>
<p>Agent는 동시에 여러 개 돌릴 수 있다.</p>
<p>사람은 그렇지 않다.</p>
<pre><code class="language-text">Agent 1
Agent 2
Agent 3
Agent 4</code></pre>
<p>가 동시에 작업을 끝내면:</p>
<pre><code class="language-text">Review Queue</code></pre>
<p>가 생긴다.</p>
<p>그래서 좋은 Engineering Agent는:</p>
<pre><code class="language-text">많은 일을 하는 Agent</code></pre>
<p>보다:</p>
<pre><code class="language-text">사람이 쉽게 검토할 수 있는
완료된 결과를 가져오는 Agent</code></pre>
<p>가 되어야 한다.</p>
<hr>
<h1 id="19-그래서-완료-보고-형식도-바꿔야-한다">19. 그래서 완료 보고 형식도 바꿔야 한다</h1>
<p>Agent가:</p>
<pre><code class="language-text">완료했습니다.</code></pre>
<p>라고 하면 부족하다.</p>
<p>추천하는 완료 Report:</p>
<pre><code class="language-text">## 변경

관련 파일 4개 수정

## 이유

원인은 Task cancellation 이후
state update가 계속 발생한 것.

## 실제 검증

Build PASS
Unit Test 42/42 PASS

## Runtime

Simulator 정상

## 미검증

Physical Device

## Human Decision

없음</code></pre>
<p>이런 결과가 훨씬 Review하기 쉽다.</p>
<p>Engineering Agent의 생산성을 높이려면 <strong>출력량이 아니라 Review 비용을 줄여야 한다.</strong></p>
<hr>
<h1 id="20-agent가-강해질수록-test는-더-중요하다">20. Agent가 강해질수록 Test는 더 중요하다</h1>
<p>역설적으로 AI가 더 똑똑해질수록 테스트가 덜 필요해지는 게 아니다.</p>
<p>오히려 더 중요해진다.</p>
<p>강한 Agent는 더 많은 코드를 더 빠르게 수정할 수 있기 때문이다.</p>
<pre><code class="language-text">Agent Capability ↑

↓

Change Surface ↑</code></pre>
<p>좋은 방향이면 생산성이 빠르게 올라간다.</p>
<p>틀린 방향이면 잘못된 변경도 빠르게 확산된다.</p>
<p>그래서:</p>
<pre><code class="language-text">Agent Opinion</code></pre>
<p>보다:</p>
<pre><code class="language-text">Compiler
Test
Runtime</code></pre>
<p>를 우선해야 한다.</p>
<hr>
<h1 id="21-agent가-만든-test도-그대로-믿으면-안-된다">21. Agent가 만든 Test도 그대로 믿으면 안 된다</h1>
<p>Agent가:</p>
<pre><code class="language-text">구현
+
Test</code></pre>
<p>를 같이 작성했다.</p>
<p>그리고 Test가 통과했다.</p>
<p>끝일까?</p>
<p>아니다.</p>
<p>Agent가 요구사항을 잘못 이해했다면:</p>
<pre><code class="language-text">틀린 구현
+
틀린 테스트
=
PASS</code></pre>
<p>가 가능하다.</p>
<p>그래서 중요한 기능에서는:</p>
<pre><code class="language-text">Acceptance Criteria

↓

독립 Reviewer

↓

Runtime Verification</code></pre>
<p>을 분리해야 한다.</p>
<hr>
<h1 id="22-review-agent와-coding-agent를-분리하는-이유">22. Review Agent와 Coding Agent를 분리하는 이유</h1>
<p>예를 들어 Codex가 구현했다고 하자.</p>
<p>Claude에게 별도로 Review를 맡긴다.</p>
<pre><code class="language-text">Codex
→ Implementation

Claude
→ Review</code></pre>
<p>서로 다른 모델을 반드시 써야 한다는 의미는 아니다.</p>
<p>중요한 것은 Context를 분리하는 것이다.</p>
<pre><code class="language-text">작성 과정의 가정</code></pre>
<p>을 가진 Agent가 자기 코드를 평가하는 것보다:</p>
<pre><code class="language-text">Task
Diff
Architecture
Tests</code></pre>
<p>만 받은 Reviewer가 독립적으로 보는 편이 좋다.</p>
<hr>
<h1 id="23-qa도-또-다른-agent로-분리한다">23. QA도 또 다른 Agent로 분리한다</h1>
<p>Review:</p>
<pre><code class="language-text">Source
Diff
Architecture</code></pre>
<p>QA:</p>
<pre><code class="language-text">Running Product
User Goal
Runtime</code></pre>
<p>를 본다.</p>
<p>예:</p>
<pre><code class="language-text">Implementation
      ↓
Build/Test
      ↓
Code Review
      ↓
Runtime QA
      ↓
Human Gate</code></pre>
<p>이 구조가 Engineering Agent 시대에 더 자연스럽다.</p>
<hr>
<h1 id="24-web에서는-이미-상당-부분-가능하다">24. Web에서는 이미 상당 부분 가능하다</h1>
<p>Web Frontend라면:</p>
<pre><code class="language-text">Goal
  ↓
Agent 구현
  ↓
Browser
  ↓
Playwright
  ↓
DOM / ARIA
  ↓
Click / Type / Scroll
  ↓
Console
  ↓
Network
  ↓
Screenshot / Video / Trace</code></pre>
<p>까지 하나의 Workflow로 묶을 수 있다.</p>
<p>Astra가 Computer Use와 Browser Use에서 강해지는 방향은 결국 이런 <strong>Runtime Engineering</strong>을 더 자연스럽게 만들 가능성이 높다. OpenAI는 Astra를 browser와 computer use에서 새로운 frontier를 세운 모델로 소개하고 있다. </p>
<hr>
<h1 id="25-모바일도-결국-같은-방향으로-갈-가능성이-높다">25. 모바일도 결국 같은 방향으로 갈 가능성이 높다</h1>
<p>iOS:</p>
<pre><code class="language-text">Source
↓
Build
↓
Simulator
↓
Accessibility
↓
Interaction
↓
Recording
↓
Runtime Log</code></pre>
<p>Android:</p>
<pre><code class="language-text">Source
↓
Gradle
↓
Emulator
↓
Semantics
↓
Interaction
↓
Logcat</code></pre>
<p>현재는 Browser보다 연결이 복잡하다.</p>
<p>하지만 개발도구가 Agent에게 Semantic UI와 Runtime 상태를 더 많이 제공할수록 Web과 비슷한 구조가 될 가능성이 높다.</p>
<hr>
<h1 id="26-engineering-agent는-코딩만-하는-개발자가-아니다">26. Engineering Agent는 코딩만 하는 개발자가 아니다</h1>
<p>앞으로 Agent 역할을 개발팀 역할에 대응시키면 이렇게 볼 수 있다.</p>
<pre><code class="language-text">Research Agent
= 코드 조사

Architecture Agent
= 설계 검토

Implementation Agent
= 구현

Review Agent
= 코드 리뷰

QA Agent
= Runtime QA

Security Agent
= 보안 검토</code></pre>
<p>그리고 상위에는:</p>
<pre><code class="language-text">Orchestrator</code></pre>
<p>가 있다.</p>
<p>Astra가 흥미로운 이유는 이 상위 역할과 여러 역할 사이를 한 모델이 오갈 수 있는 능력이 크게 올라갔다는 점이다.</p>
<hr>
<h1 id="27-하지만-ai-개발자-한-명보다는-ai-개발팀이-더-현실적이다">27. 하지만 ‘AI 개발자 한 명’보다는 ‘AI 개발팀’이 더 현실적이다</h1>
<p>Astra 하나에게:</p>
<pre><code class="language-text">조사하고
설계하고
코딩하고
리뷰하고
QA하고
배포해.</code></pre>
<p>라고 하는 것도 가능해질 수 있다.</p>
<p>하지만 좋은 개발 조직은 역할을 분리한다.</p>
<p>AI도 마찬가지다.</p>
<pre><code class="language-text">Astra
→ Goal / Planning

Sol
→ Implementation

Claude
→ Review

Playwright
→ QA

CI
→ Gate</code></pre>
<p>처럼 구성할 수 있다.</p>
<p>중요한 것은 어떤 모델을 쓰느냐보다:</p>
<pre><code class="language-text">역할

권한

검증

완료 조건</code></pre>
<p>이다.</p>
<hr>
<h1 id="28-앞으로-개발-architecture에는-ai-control-plane이-들어간다">28. 앞으로 개발 Architecture에는 AI Control Plane이 들어간다</h1>
<p>지금까지 개발팀 Architecture를 생각하면:</p>
<pre><code class="language-text">GitHub
CI
Issue Tracker
Monitoring</code></pre>
<p>정도가 중심이었다.</p>
<p>앞으로는:</p>
<pre><code class="language-text">Agent Tasks
Agent Permissions
Skills
Worktrees
Model Routing
Tool Access
Agent Logs
Human Gates</code></pre>
<p>같은 것도 관리해야 한다.</p>
<p>즉:</p>
<pre><code class="language-text">Developer Control Plane</code></pre>
<p>이 필요해진다.</p>
<p>Astra 같은 모델은 이 필요성을 더 빠르게 만든다.</p>
<hr>
<h1 id="29-멀티에이전트의-목표는-agent-숫자가-아니다">29. 멀티에이전트의 목표는 Agent 숫자가 아니다</h1>
<p>Agent가 강해지면:</p>
<pre><code class="language-text">10 Agent
20 Agent
50 Agent</code></pre>
<p>를 돌리고 싶어질 수 있다.</p>
<p>하지만 Agent 숫자가 많을수록 좋은 것이 아니다.</p>
<p>중요한 건:</p>
<pre><code class="language-text">Human Cognitive Load ↓

Software Throughput ↑</code></pre>
<p>이다.</p>
<p>Agent 20개가 동시에 질문을 던진다면 실패한 오케스트레이션이다.</p>
<p>좋은 Agent Team은:</p>
<pre><code class="language-text">조사
구현
검증</code></pre>
<p>을 알아서 수행하고,</p>
<p>사람에게는:</p>
<pre><code class="language-text">Decision Needed</code></pre>
<p>만 올린다.</p>
<hr>
<h1 id="30-결국-좋은-engineering-agent는-잠시-잊을-수-있는-agent다">30. 결국 좋은 Engineering Agent는 잠시 잊을 수 있는 Agent다</h1>
<p>개발자가 Agent에게 작업을 맡긴다.</p>
<p>그리고 다른 일을 한다.</p>
<p>30분 뒤 돌아왔을 때:</p>
<pre><code class="language-text">Finding
Evidence
Result
Decision Needed</code></pre>
<p>가 정리돼 있다.</p>
<p>이게 이상적인 형태다.</p>
<p>반대로:</p>
<pre><code class="language-text">3분마다 질문

5분마다 승인

같은 실패 반복

긴 설명</code></pre>
<p>을 하면 Agent Capability가 높아도 실제 생산성은 낮다.</p>
<hr>
<h1 id="31-astra가-보여주는-미래는-더-좋은-copilot이-아니다">31. Astra가 보여주는 미래는 ‘더 좋은 Copilot’이 아니다</h1>
<p>Copilot이라는 이름에는 기본적으로:</p>
<pre><code class="language-text">사람이 운전

AI가 보조</code></pre>
<p>라는 의미가 있다.</p>
<p>Engineering Agent는 조금 다르다.</p>
<pre><code class="language-text">사람
→ 목적과 경계 결정

Agent
→ 실제 업무 수행

사람
→ 결과 판단</code></pre>
<p>형태다.</p>
<p>즉 개발자는 항상 키보드를 잡고 있을 필요가 없다.</p>
<p>더 높은 수준에서:</p>
<pre><code class="language-text">Goal

Architecture

Trade-off

Risk

Approval</code></pre>
<p>을 담당한다.</p>
<hr>
<h1 id="32-그렇다면-개발자는-코딩을-덜-배워도-될까">32. 그렇다면 개발자는 코딩을 덜 배워도 될까?</h1>
<p>오히려 반대일 수 있다.</p>
<p>Agent 결과를 제대로 검증하려면:</p>
<pre><code class="language-text">Architecture

Concurrency

Networking

Database

Security

Runtime

Performance</code></pre>
<p>를 이해해야 한다.</p>
<p>직접 작성하는 코드량이 줄어들어도 <strong>판단의 난도는 올라갈 수 있다.</strong></p>
<p>특히 Senior Developer 역할은:</p>
<pre><code class="language-text">코드를 많이 쓰는 사람</code></pre>
<p>에서:</p>
<pre><code class="language-text">좋은 변경인지 판단할 수 있는 사람</code></pre>
<p>으로 더 이동할 가능성이 높다.</p>
<hr>
<h1 id="33-junior-개발자에게는-다른-문제가-생긴다">33. Junior 개발자에게는 다른 문제가 생긴다</h1>
<p>기존 학습:</p>
<pre><code class="language-text">직접 구현
↓
실수
↓
Debug
↓
Review
↓
이해</code></pre>
<p>Agent 시대:</p>
<pre><code class="language-text">Prompt
↓
Agent
↓
Merge</code></pre>
<p>가 되면 중간 학습 단계가 줄어든다.</p>
<p>따라서 Junior에게는 일부 Task를:</p>
<pre><code class="language-text">Human Implementation
+
AI Review</code></pre>
<p>로 남기는 방식도 필요하다.</p>
<p>모든 것을 Agent에게 위임하는 것이 반드시 좋은 Engineering 교육은 아니다.</p>
<hr>
<h1 id="34-astra를-당장-모든-곳에-적용할-필요도-없다">34. Astra를 당장 모든 곳에 적용할 필요도 없다</h1>
<p>Astra는 현재 가격과 토큰 소비량이 Sol보다 2.5배 가량 높다.</p>
<p>따라서 현실적인 도입은:</p>
<pre><code class="language-text">Hard Task
→ Astra

Normal Coding
→ Sol / Terra

High-volume
→ Luna</code></pre>
<p>같은 구조가 낫다.</p>
<p>OpenAI도 현재 모델 선택 가이드에서 Astra는 가장 복잡한 reasoning과 coding용, Terra는 비용과 intelligence의 균형, Luna는 비용 민감한 대량 작업용으로 구분하고 있다. </p>
<hr>
<h1 id="35-개발팀이-지금-준비해야-할-것은-astra-prompt가-아니다">35. 개발팀이 지금 준비해야 할 것은 Astra Prompt가 아니다</h1>
<p>신규 모델이 나오면 흔히:</p>
<pre><code class="language-text">Astra용 Prompt Best Practice</code></pre>
<p>부터 찾는다.</p>
<p>물론 필요하다.</p>
<p>하지만 더 중요한 것은:</p>
<pre><code class="language-text">Repository Structure

AGENTS.md

Skills

Tests

CI

Permissions

Security Policy

Runtime Evidence

Review Rules</code></pre>
<p>다.</p>
<p>모델은 계속 바뀐다.</p>
<p>개발 시스템은 남는다.</p>
<hr>
<h1 id="36-가장-좋은-구조는-model-independent하다">36. 가장 좋은 구조는 Model-independent하다</h1>
<p>오늘:</p>
<pre><code class="language-text">GPT-6 Astra</code></pre>
<p>가 가장 강할 수 있다.</p>
<p>몇 달 뒤:</p>
<pre><code class="language-text">다음 GPT
다음 Claude
다른 Frontier Model</code></pre>
<p>이 더 좋아질 수 있다.</p>
<p>그러므로:</p>
<pre><code class="language-text">Task
  ↓
Agent Runtime
  ↓
Model</code></pre>
<p>을 분리한다.</p>
<p>Model은 교체 가능한 Worker다.</p>
<pre><code class="language-text">Astra
Fable
Sol
다음 모델</code></pre>
<p>무엇이 들어와도:</p>
<pre><code class="language-text">Goal
→ Implementation
→ Validation
→ Review
→ QA
→ Human</code></pre>
<p>Workflow는 유지한다.</p>
<hr>
<h1 id="37-개인-개발자에게-가장-현실적인-구조">37. 개인 개발자에게 가장 현실적인 구조</h1>
<p>앞으로 개인 개발 환경은 이런 모습이 될 가능성이 높다.</p>
<pre><code class="language-text">                    Developer
                        │
                        ▼
                  Goal / Policy
                        │
                        ▼
                   Orchestrator
                        │
           ┌────────────┼────────────┐
           ▼            ▼            ▼
        Research     Implement       Test
         Agent         Agent         Agent
           │            │            │
           └────────────┼────────────┘
                        ▼
                  Automated Checks
                        │
                        ▼
                  Independent Review
                        │
                        ▼
                    Runtime QA
                        │
                        ▼
                      Human</code></pre>
<p>그리고 Astra 같은 모델은 이 구조의:</p>
<pre><code class="language-text">Orchestrator

또는

가장 어려운 Worker</code></pre>
<p>역할을 맡을 가능성이 크다.</p>
<hr>
<h1 id="38-완료-기준도-바뀌어야-한다">38. 완료 기준도 바뀌어야 한다</h1>
<p>예전 Coding Agent:</p>
<pre><code class="language-text">Code Generated</code></pre>
<p>이 완료였다.</p>
<p>앞으로는:</p>
<pre><code class="language-text">Goal Achieved
+
Build PASS
+
Tests PASS
+
Runtime Verified
+
Critical Review 0
+
Not Verified 명시</code></pre>
<p>정도가 되어야 한다.</p>
<p><strong>Code Complete가 아니라 Engineering Complete</strong>다.</p>
<hr>
<h1 id="마무리">마무리</h1>
<p>GPT-6 Astra의 가장 중요한 변화는 코드를 조금 더 잘 작성하게 된 것이 아니다.</p>
<p>OpenAI가 Astra를 설명할 때 반복해서 강조하는 것은:</p>
<pre><code class="language-text">Coding

Browsing

Computer Use

Professional Tools

Complex Multistep Work</code></pre>
<p>를 하나의 end-to-end Workflow 안에서 수행하는 능력이다. </p>
<p>이건 Coding Agent의 역할을 근본적으로 바꾼다.</p>
<p>예전에는:</p>
<pre><code class="language-text">Developer
→ Agent
→ Code</code></pre>
<p>였다.</p>
<p>앞으로는:</p>
<pre><code class="language-text">Developer
        ↓
Goal + Constraints
        ↓
Engineering Agent
        ↓
Research
        ↓
Implementation
        ↓
Tool Use
        ↓
Build / Test
        ↓
Recovery
        ↓
Runtime Verification
        ↓
Review-ready Result
        ↓
Developer</code></pre>
<p>에 가까워진다.</p>
<p>그리고 이 변화가 커질수록 개발팀에서 가장 중요한 것은 모델 자체가 아닐 가능성이 높다.</p>
<p>오히려:</p>
<pre><code class="language-text">AGENTS.md

Skills

Permissions

Tests

CI

Runtime Evidence

Review Policy

Security Guardrails</code></pre>
<p>같은 <strong>Agent가 일할 수 있는 Engineering Environment</strong>가 중요해진다.</p>
<p>Astra가 똑똑하다고 모든 권한을 넘겨주는 것도 좋은 설계가 아니다.</p>
<p>OpenAI가 Astra에 추가적인 안전 모니터링을 넣고, Astra가 최초로 Critical 수준의 사이버보안 Capability에 도달했다고 별도로 강조한 이유도 결국 같은 문제를 보여준다. Agent Capability가 높아질수록 <strong>Control Plane과 Permission Boundary가 더 중요해진다.</strong> </p>
<p>그래서 GPT-6 Astra 이후 개발팀이 준비해야 하는 질문은:</p>
<pre><code class="language-text">Astra로 코드를 얼마나 많이 만들 수 있을까?</code></pre>
<p>가 아니다.</p>
<p>더 중요한 질문은:</p>
<blockquote>
<p><strong>이제 AI에게 어디까지 Engineering Goal을 맡길 수 있고, 그 결과를 어떤 시스템으로 검증할 것인가?</strong></p>
</blockquote>
<p>이다.</p>
<p>Coding Agent의 다음 단계는 더 좋은 자동완성이 아니다.</p>
<p><strong>Engineering Agent다.</strong></p>
<p>그리고 Engineering Agent 시대의 개발자는 코드를 가장 많이 작성하는 사람이 아니라, <strong>AI에게 올바른 목표와 경계를 주고, 결과가 실제 Software Change로 신뢰할 만한지 판단할 수 있는 사람</strong>에 더 가까워질 가능성이 크다.</p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<p>OpenAI는 2026년 9월 3일 GPT-6 Astra를 발표하고 coding, research, computer use 및 복잡한 multi-step work가 크게 향상된 모델이라고 설명했다. Astra는 현재 제한된 조직부터 배포 중이며 API 및 Plus·Pro·Business·Enterprise 사용자로 확대될 예정이다. </p>
<p>OpenAI의 공식 개발자 가이드에서는 Astra를 코드·브라우저·전문 소프트웨어 사이를 오가는 복잡한 Workflow에 적합한 모델로 소개하며, Async Tool Calling과 Mid-turn Steering을 새 기능으로 제공한다. 또한 <code>AGENTS.md</code>와 Skills 등 외부 지침에 대한 instruction following이 더 강해졌기 때문에 접근 가능한 지침 파일을 점검할 것을 권장한다. </p>
<p>GPT-6 Astra API 모델은 1,050,000 token context, 최대 128,000 output token과 low·medium·high·xhigh·max reasoning effort를 지원한다. API 가격은 100만 input token당 10달러, output token당 50달러다. </p>
<p>OpenAI는 Astra가 Preparedness Framework에서 Critical 수준의 cybersecurity capability에 도달한 첫 모델이라고 밝히고 있으며, 이에 따라 추가적인 모니터링과 격리·안전 조치를 강화했다. </p>
<h3 id="핵심-참고-포인트">핵심 참고 포인트</h3>
<p>GPT-6 Astra를 단순히 GPT-5.6 Sol보다 더 높은 성능의 Coding Model로 보는 것은 변화의 일부만 보는 것이다. OpenAI가 Astra에서 강조하는 핵심은 <strong>코딩과 Browser·Computer Use·Professional Tool을 하나의 긴 Workflow로 묶어 실제 업무 결과까지 도달하는 능력</strong>이다. </p>
<p>특히 Async Tool Calling은 Build나 Test처럼 오래 걸리는 작업 동안 Agent가 다른 일을 진행할 수 있게 하고, Mid-turn Steering은 긴 작업 중에도 사람이 새로운 요구사항이나 Constraint를 추가할 수 있게 한다. 이것은 Agent를 단발성 코드 생성기보다 <strong>지속적으로 일하는 Engineering Worker</strong>에 가깝게 만든다. </p>
<p>따라서 앞으로 개발환경의 핵심 경쟁력은 특정 Frontier Model 하나보다 <code>Goal 설계 → Agent 작업 → 자동 검증 → 독립 Review → Runtime QA → Human Gate</code>를 얼마나 안정적으로 운영할 수 있느냐에 있을 가능성이 높다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI Security Guardrail 설계: 개발팀의 보안 실수를 시스템으로 막는 법]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609031</link>
            <guid>https://velog.io/@kyu_ios_dev/2609031</guid>
            <pubDate>Thu, 03 Sep 2026 13:36:39 GMT</pubDate>
            <description><![CDATA[<h4 id="ai-security-guardrail-설계-개발팀의-보안-실수를-시스템으로-막는-법">AI Security Guardrail 설계: 개발팀의 보안 실수를 시스템으로 막는 법</h4>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/624622b9-b9b6-4b15-8d00-272bd80ed21c/image.png" alt=""></p>
<p>2026년 9월 3일 공개된 티빙 침해사고 민관합동조사 결과는 개발자 입장에서 꽤 불편하게 읽힌다.</p>
<p>공격 기법이 특별히 새로운 것도 아니었기 때문이다.</p>
<p>조사 결과 공격자는 개발환경 접속키를 탈취해 내부 개발환경에 들어왔고, 이후 개발 프로젝트에서 운영환경 접속키를 추가 확보해 AWS 운영환경까지 침투했다. 소스코드를 포함한 기술자산은 361건, 약 30.35GB가 외부로 유출됐으며, 중복을 포함한 이용자 계정 약 3,954만 개가 영향을 받은 것으로 조사됐다. </p>
<p>더 충격적인 부분은 공격보다 그 전후다.</p>
<p>개발·운영환경 접속키가 소스코드에 노출되거나 사내 메신저로 공유됐고, 모든 개발자에게 전체 개발 프로젝트 접근 권한이 부여돼 있었다. 키의 발급·사용·변경·폐기와 정기점검 절차도 제대로 갖춰져 있지 않았다는 것이 조사 결과다. 2024년 모의해킹에서는 이미 소스코드 안 접속키 노출 문제가 발견됐지만 개선되지 않았다. </p>
<p>그리고 공격이 시작된 뒤에도 문제가 이어졌다.</p>
<p>실시간 네트워크·데이터 흐름을 탐지하고 차단하는 정보보호 체계 대신 CPU 부하 같은 시스템 모니터링에 주로 의존했고, 이상징후가 발생한 뒤 정보보호 조직에 공유되기까지 약 14시간이 걸렸다. 일부 접속기록은 약 6일만 보관됐으며, KISA 신고 역시 법정 시한을 넘긴 것으로 조사됐다. </p>
<p>이 사건을 단순히:</p>
<blockquote>
<p>개발자가 키를 소스코드에 넣어서 사고가 났다.</p>
</blockquote>
<p>정도로 정리하면 중요한 부분을 놓친다.</p>
<p>진짜 문제는 <strong>한 사람이 실수했을 때 그 실수가 Production 침해까지 그대로 이어질 수 있었던 시스템</strong>이다.</p>
<p>그리고 AI Coding Agent를 사용하는 지금은 이 문제를 조금 다르게 볼 필요가 있다.</p>
<p>사람이 보안을 놓칠 수 있다면 이제는 AI라도 한 번 더 보게 만들 수 있다.</p>
<p>다만 AI에게 보안을 “맡기는” 것이 아니다.</p>
<p><strong>사람 → AI → 자동 보안 도구 → 권한 시스템 → Runtime 감시가 서로를 막아주는 구조</strong>를 만들어야 한다.</p>
<hr>
<h2 id="1-이번-사고에서-가장-위험했던-건-key-하나가-아니다">1. 이번 사고에서 가장 위험했던 건 Key 하나가 아니다</h2>
<p>조사 결과를 개발 시스템 관점으로 단순화하면 이런 형태다.</p>
<pre><code class="language-text">개발자 Access Key 탈취
        ↓
개발환경 접근
        ↓
다수 프로젝트 접근
        ↓
Source Code 확보
        ↓
Source 안의 운영환경 Credential 확보
        ↓
Production 접근
        ↓
DB 접근
        ↓
데이터 대량 추출</code></pre>
<p>문제는 첫 번째 Key가 탈취됐다는 사실만이 아니다.</p>
<p>첫 Credential이:</p>
<pre><code class="language-text">Developer
→ Development</code></pre>
<p>에서 끝나지 않고,</p>
<pre><code class="language-text">Developer
→ Development
→ Source
→ Production Credential
→ Production
→ Database</code></pre>
<p>까지 이어졌다는 것이 더 위험하다.</p>
<p>좋은 보안 Architecture라면 중간마다 끊겨야 한다.</p>
<pre><code class="language-text">Developer Credential 탈취

        ↓

Development 일부 접근

        X</code></pre>
<p>또는:</p>
<pre><code class="language-text">Source 탈취

        ↓

Production Credential 없음

        X</code></pre>
<p>또는:</p>
<pre><code class="language-text">Production 접근 시도

        ↓

권한 부족 / MFA / 단기 Credential

        X</code></pre>
<p>또는:</p>
<pre><code class="language-text">DB 대량 조회

        ↓

Anomaly Detection

        ↓

Session Kill + Alert

        X</code></pre>
<p>공격자는 여러 방어선을 연속으로 통과해야 한다.</p>
<p>이를 <strong>Defense in Depth</strong>라고 한다.</p>
<p>이번 조사 결과에서 드러난 가장 큰 문제도 각각의 방어선이 충분히 독립적으로 작동하지 않았다는 점이다.</p>
<hr>
<h1 id="2-보안은-개발자의-기억에-맡기면-안-된다">2. 보안은 개발자의 기억에 맡기면 안 된다</h1>
<p>현실적인 개발팀에서 이런 대화는 꽤 흔하다.</p>
<pre><code class="language-text">&quot;이 Key는 나중에 Secrets Manager로 옮기죠.&quot;

&quot;일단 개발 서버니까 넣어둘게요.&quot;

&quot;테스트 끝나면 지우겠습니다.&quot;

&quot;이 Repository private인데 괜찮지 않나요?&quot;</code></pre>
<p>문제는 대부분 악의가 없다는 것이다.</p>
<p>편해서 그렇게 한다.</p>
<p>일정이 급해서 그렇게 한다.</p>
<p>그리고 몇 달 뒤 아무도 기억하지 못한다.</p>
<p>그래서 보안 정책은:</p>
<pre><code class="language-text">개발자가 잘 지켜야 한다.</code></pre>
<p>에서 끝나면 안 된다.</p>
<p>더 좋은 시스템은:</p>
<pre><code class="language-text">개발자가 실수해도
실수가 Repository에 들어가지 못한다.</code></pre>
<p>여야 한다.</p>
<p>GitHub Push Protection이 대표적인 예다.</p>
<p>GitHub는 Push 과정에서 API Key나 Token 같은 Secret을 발견하면 Repository에 들어가기 전에 Push 자체를 차단할 수 있다. Secret Scanning은 Git History 전체에서도 Credential을 탐지할 수 있다. </p>
<p>즉:</p>
<pre><code class="language-text">개발자가 기억한다</code></pre>
<p>보다:</p>
<pre><code class="language-text">Git이 막는다</code></pre>
<p>가 강하다.</p>
<hr>
<h1 id="3-이제-여기에-ai-security-reviewer를-하나-더-넣을-수-있다">3. 이제 여기에 AI Security Reviewer를 하나 더 넣을 수 있다</h1>
<p>2026년의 개발 환경에서는 한 단계 더 갈 수 있다.</p>
<pre><code class="language-text">Developer / Coding Agent
        ↓
Security Agent
        ↓
Deterministic Security Checks
        ↓
CI
        ↓
Runtime Security</code></pre>
<p>예를 들어 Codex가 Feature를 구현했다고 하자.</p>
<p>바로 PR을 올리지 않는다.</p>
<p>먼저 별도의 Claude나 다른 Agent가 <strong>Security Reviewer</strong> 역할을 맡는다.</p>
<pre><code class="language-text">Codex
→ 구현

Claude Security Review
→ 보안 관점 검토

CodeQL / Secret Scanner
→ 기계적 검증

CI
→ 최종 Gate</code></pre>
<p>중요한 것은 Claude가 작성한 코드를 Claude가 다시 고치는 구조가 아니라는 것이다.</p>
<pre><code class="language-text">Coding Agent
= 생산

Security Agent
= 의심

Security Tool
= 검출

Policy
= 차단</code></pre>
<p>각자의 역할을 나눈다.</p>
<hr>
<h1 id="4-ai-security-agent에게-보안-확인해줘라고-하면-안-된다">4. AI Security Agent에게 “보안 확인해줘”라고 하면 안 된다</h1>
<p>나쁜 요청:</p>
<pre><code class="language-text">보안 문제 없는지 확인해줘.</code></pre>
<p>이렇게 하면 결과가 모호하다.</p>
<p>대신 보안 계약을 고정한다.</p>
<pre><code class="language-text">이번 변경을 Security Reviewer 관점에서 검토한다.

반드시 확인:

Credential / Secret 노출
Authentication
Authorization
Privilege escalation
PII 접근
Logging
Network exposure
Dependency 변경
Encryption
Input validation
Production access
Cloud IAM
Data export 가능성

결과는:

CRITICAL
HIGH
MEDIUM
LOW
NOT VERIFIED

로 분리한다.

근거 없는 가능성은 취약점으로 단정하지 않는다.

코드를 수정하지 말고 Finding만 반환한다.</code></pre>
<p>이 Prompt 자체를 매번 작성할 필요도 없다.</p>
<p><code>security-review</code> Skill로 만들어 두면 된다.</p>
<hr>
<h1 id="5-하지만-ai가-secret-scanner를-대체하면-안-된다">5. 하지만 AI가 Secret Scanner를 대체하면 안 된다</h1>
<p>이 부분이 중요하다.</p>
<p>LLM이:</p>
<pre><code class="language-text">AKIA...</code></pre>
<p>같은 AWS Key를 발견할 수도 있다.</p>
<p>하지만 이런 건 AI가 할 일이 아니다.</p>
<p>GitHub Secret Scanning, Gitleaks, TruffleHog 같은 도구가 훨씬 적합하다.</p>
<p>현재 GitHub Secret Scanning은 알려진 Token뿐 아니라 Generic Secret 탐지에도 AI 기반 Detection을 일부 사용하며, Push Protection은 Credential이 Repository에 들어오기 전에 차단할 수 있다. GitHub MCP를 사용하는 AI 작업에서도 지원되는 환경에서는 Secret 노출을 차단하는 보호 기능이 적용된다. </p>
<p>따라서 역할은 이렇게 나누는 것이 좋다.</p>
<pre><code class="language-text">Secret Scanner
→ Secret 자체를 찾음

CodeQL / SAST
→ 알려진 코드 취약점 패턴 탐지

AI Security Reviewer
→ 여러 파일과 Architecture를 연결해 위험 판단

Human
→ 중요한 Architecture와 예외 승인</code></pre>
<p>AI는 <strong>보안 Tool 위의 reasoning layer</strong>로 사용하는 것이 좋다.</p>
<hr>
<h1 id="6-repository에-secret이-존재할-이유부터-없앤다">6. Repository에 Secret이 존재할 이유부터 없앤다</h1>
<p>가장 먼저 해야 할 것은:</p>
<pre><code class="language-text">secret = &quot;...&quot;</code></pre>
<p>을 금지하는 것이다.</p>
<p>AWS도 Access Key를 Source Code나 Configuration에 넣는 방식을 명시적인 Anti-pattern으로 보고, 가능하면 IAM Role을 통한 Temporary Credential을 사용하고 장기간 보관해야 하는 Secret은 Secrets Manager 같은 전용 시스템에서 관리하도록 권장한다. </p>
<p>구조는:</p>
<pre><code class="language-text">Source Code
   │
   │ Secret 이름만 참조
   ▼
Runtime Identity
   │
   ▼
Secrets Manager
   │
   ▼
필요한 순간 Credential 획득</code></pre>
<p>이런 형태가 되어야 한다.</p>
<p>반대로:</p>
<pre><code class="language-text">Git
↓
API_KEY
↓
Production</code></pre>
<p>같은 연결이 존재하면 안 된다.</p>
<hr>
<h1 id="7-가능하면-장기-key-자체를-없앤다">7. 가능하면 장기 Key 자체를 없앤다</h1>
<p>더 좋은 방식은 Secret을 잘 숨기는 것이 아니라 <strong>없애는 것</strong>이다.</p>
<p>예를 들어 AWS 환경이라면:</p>
<pre><code class="language-text">Access Key
Secret Access Key</code></pre>
<p>를 개발자 PC나 Repository에 저장하는 대신:</p>
<pre><code class="language-text">IAM Role

STS

Temporary Credentials

OIDC</code></pre>
<p>같은 구조를 사용한다.</p>
<p>즉:</p>
<pre><code class="language-text">Permanent Credential</code></pre>
<p>보다:</p>
<pre><code class="language-text">Short-lived Credential</code></pre>
<p>이다.</p>
<p>만료 시간이 짧은 Credential은 탈취돼도 공격자의 활동 가능 시간을 줄인다.</p>
<p>AWS 역시 IAM Access Key가 필요할 때 가능하면 EC2·Lambda 등의 IAM Role과 단기 Credential을 사용하도록 권장한다. </p>
<hr>
<h1 id="8-모든-개발자가-모든-repository를-볼-필요도-없다">8. 모든 개발자가 모든 Repository를 볼 필요도 없다</h1>
<p>이번 티빙 조사 결과에서 상당히 눈에 띄는 부분이 모든 개발자에게 전체 개발 프로젝트 접근 권한이 부여돼 있었다는 것이다. </p>
<p>이건 공격자 입장에서 굉장히 좋다.</p>
<p>한 명만 뚫으면 된다.</p>
<pre><code class="language-text">Developer A Credential
        ↓
ALL PROJECTS</code></pre>
<p>좋은 구조는 다르다.</p>
<pre><code class="language-text">Developer A
→ iOS

Developer B
→ Backend Payment

Developer C
→ Recommendation

Security Team
→ Security Project</code></pre>
<p>그리고 필요할 때만 일시적으로 추가 권한을 준다.</p>
<p>이것이 <strong>Least Privilege</strong>다.</p>
<p>OWASP 역시 CI/CD와 개발 환경에서 개발자에게 필요한 기능만 허용하고 Project 관리 권한이나 불필요하게 높은 권한을 주지 않는 것을 권장한다. </p>
<hr>
<h1 id="9-여기에서도-ai를-사용할-수-있다">9. 여기에서도 AI를 사용할 수 있다</h1>
<p>재미있는 시스템을 하나 만들 수 있다.</p>
<p><strong>Permission Review Agent</strong>다.</p>
<p>예를 들어 매일 새벽:</p>
<pre><code class="language-text">Security Agent

GitHub
AWS IAM
Secrets Manager
CI
Kubernetes</code></pre>
<p>의 Metadata를 읽는다.</p>
<p>그리고:</p>
<pre><code class="language-text">Developer A

최근 60일:
ios-app만 작업

현재 권한:
ios-app
backend
billing
infra
data-pipeline</code></pre>
<p>를 발견한다.</p>
<p>Agent가:</p>
<pre><code class="language-text">권한 과다 가능성</code></pre>
<p>을 Security Queue에 올린다.</p>
<p>다만 AI가 직접 Permission을 제거하면 위험하다.</p>
<p>따라서:</p>
<pre><code class="language-text">AI
→ 과도한 권한 후보 탐지

Policy Engine
→ 규칙 확인

Security/Human
→ 승인

IAM
→ 실제 변경</code></pre>
<p>형태가 적절하다.</p>
<hr>
<h1 id="10-security-agent가-매-pr마다-보는-architecture">10. Security Agent가 매 PR마다 보는 Architecture</h1>
<p>추천 구조는 이렇다.</p>
<pre><code class="language-text">Developer / Coding Agent
          │
          ▼
       Git Diff
          │
          ▼
   ┌───────────────┐
   │ Security Agent│
   └───────────────┘
          │
   ┌──────┼───────┐
   ▼      ▼       ▼
 Secret  Auth   Data Flow
 Review  Review  Review
   │      │       │
   └──────┼───────┘
          ▼
     Risk Report
          │
          ▼
Deterministic Checks
          │
   ┌──────┼────────┐
   ▼      ▼        ▼
Secret  CodeQL  Dependency
Scan             Review
          │
          ▼
       CI Gate</code></pre>
<p>여기서 AI는:</p>
<pre><code class="language-text">&quot;이 API가 새로 admin 권한을 요청하는데 정말 필요한가?&quot;

&quot;이 Repository에서 처음으로 production DB 접근 코드가 추가됐다.&quot;

&quot;개인정보를 로그에 기록할 가능성이 있다.&quot;

&quot;새 S3 bucket이 public access를 허용한다.&quot;

&quot;API Response에 필요하지 않은 PII가 추가됐다.&quot;</code></pre>
<p>같은 <strong>Context-dependent 문제</strong>를 본다.</p>
<hr>
<h1 id="11-security-agent는-diff만-보면-안-된다">11. Security Agent는 Diff만 보면 안 된다</h1>
<p>예를 들어 PR에 이런 코드가 추가됐다고 하자.</p>
<pre><code class="language-swift">logger.info(&quot;login user: \(user)&quot;)</code></pre>
<p>컴파일도 된다.</p>
<p>Test도 통과한다.</p>
<p>Secret Scanner도 아무것도 못 찾는다.</p>
<p>하지만 <code>user</code> 안에:</p>
<pre><code class="language-text">email
phone
CI
birthDate</code></pre>
<p>같은 개인정보가 들어 있다면 문제가 될 수 있다.</p>
<p>AI Reviewer가 Repository의 <code>User</code> 모델과 Logging 코드를 함께 보면:</p>
<pre><code class="language-text">PII Logging Risk</code></pre>
<p>를 발견할 가능성이 있다.</p>
<p>이게 AI Security Review가 일반 정적 분석 위에서 할 수 있는 일이다.</p>
<hr>
<h1 id="12-pr에-새로운-권한이-생기면-security-review를-자동-승격한다">12. PR에 새로운 권한이 생기면 Security Review를 자동 승격한다</h1>
<p>모든 PR을 최고 수준으로 Review할 필요는 없다.</p>
<p>Risk를 분류한다.</p>
<pre><code class="language-text">LOW

UI
String
Layout
Test</code></pre>
<pre><code class="language-text">MEDIUM

Network API
Local Storage
Dependency</code></pre>
<pre><code class="language-text">HIGH

Authentication
Authorization
User Data
Encryption
Cloud IAM
Payment</code></pre>
<pre><code class="language-text">CRITICAL

Production Credential
DB Migration
Admin Permission
Secret Management
Public Network Exposure</code></pre>
<p>그리고:</p>
<pre><code class="language-text">LOW
→ 일반 CI

MEDIUM
→ AI Security Review

HIGH
→ AI + Security Tool + Human

CRITICAL
→ Human Approval 필수</code></pre>
<p>로 간다.</p>
<hr>
<h1 id="13-github-branch-protection과-결합한다">13. GitHub Branch Protection과 결합한다</h1>
<p>AI가 보안 경고를 했는데 개발자가:</p>
<pre><code class="language-text">일단 Merge하고 다음 Sprint에서 고치죠.</code></pre>
<p>라고 할 수 있다.</p>
<p>그래서 Policy가 필요하다.</p>
<p>예:</p>
<pre><code class="language-text">CRITICAL
→ Merge Block

HIGH
→ Security Approval Required

MEDIUM
→ Warning

LOW
→ Advisory</code></pre>
<p>CodeQL 역시 Repository 설정에 따라 Code Scanning Check를 Required Check로 만들어 문제가 해결되기 전 Merge를 막을 수 있다. </p>
<p>즉 중요한 것은:</p>
<pre><code class="language-text">AI가 말했다.</code></pre>
<p>가 아니다.</p>
<pre><code class="language-text">Policy가 Merge를 막았다.</code></pre>
<p>이다.</p>
<hr>
<h1 id="14-이번-사고를-기준으로-가장-먼저-막아야-할-것은-secret이다">14. 이번 사고를 기준으로 가장 먼저 막아야 할 것은 Secret이다</h1>
<p>추천 Pipeline의 첫 번째 Gate는 아주 단순하다.</p>
<pre><code class="language-text">Developer
   ↓
Local Commit
   ↓
Secret Scan
   ↓
Git Push
   ↓
Push Protection</code></pre>
<p>Secret이 발견되면:</p>
<pre><code class="language-text">STOP</code></pre>
<p>이다.</p>
<p>“다음에 고치기”가 없다.</p>
<p>GitHub Push Protection에서는 예외적으로 Bypass할 수도 있지만, 조직에서는 Delegated Bypass를 통해 별도 Reviewer 승인 절차를 둘 수 있다. </p>
<p>즉:</p>
<pre><code class="language-text">개발자가 스스로 우회</code></pre>
<p>보다:</p>
<pre><code class="language-text">Security Reviewer 승인 필요</code></pre>
<p>가 훨씬 안전하다.</p>
<hr>
<h1 id="15-secret이-유출됐으면-삭제보다-rotation이-먼저다">15. Secret이 유출됐으면 삭제보다 Rotation이 먼저다</h1>
<p>개발팀에서 의외로 자주 나오는 오해가 있다.</p>
<pre><code class="language-text">Git에서 Key 지웠습니다.</code></pre>
<p>그러면 끝난 게 아니다.</p>
<p>이미 Commit History에 존재할 수도 있고 외부로 복제됐을 수도 있다.</p>
<p>Credential이 노출됐다고 판단되면:</p>
<pre><code class="language-text">Revoke

↓

Rotate

↓

사용처 변경

↓

Git History 정리

↓

Access Log 확인</code></pre>
<p>순서가 더 중요하다.</p>
<p>AWS Secrets Manager도 Secret Rotation을 자동화할 수 있다. </p>
<p>AI Security Agent가 Secret 발견 시 바로 이런 Runbook을 생성하도록 할 수 있다.</p>
<hr>
<h1 id="16-ai에게-incident-runbook도-맡길-수-있다">16. AI에게 Incident Runbook도 맡길 수 있다</h1>
<p>예를 들어 Security Agent가 Production Credential 노출을 발견했다.</p>
<p>그러면:</p>
<pre><code class="language-text">CRITICAL: AWS Credential exposed</code></pre>
<p>만 남기지 않는다.</p>
<p>자동으로:</p>
<pre><code class="language-text">1. Credential revoke 후보
2. 영향을 받는 Service
3. 최근 사용 기록
4. 접근 가능한 Resource
5. Rotation 대상
6. 관련 Repository
7. 관련 Deployment</code></pre>
<p>를 정리한다.</p>
<p>그리고 Security 담당자가:</p>
<pre><code class="language-text">EXECUTE</code></pre>
<p>를 승인한다.</p>
<p>이런 것이 AI의 좋은 사용 방식이다.</p>
<hr>
<h1 id="17-runtime까지-가면-ai의-역할이-더-커진다">17. Runtime까지 가면 AI의 역할이 더 커진다</h1>
<p>티빙 사고에서는 공격자가 5월 30일 1차 데이터 유출을 시도했고 DB Server 과부하로 이상징후가 감지돼 차단됐지만, 다음 날 가상서버를 생성해 이용자 정보 약 24GB를 저장한 뒤 외부로 유출하고 가상서버를 삭제한 것으로 조사됐다. </p>
<p>여기에서 중요한 질문이 생긴다.</p>
<pre><code class="language-text">왜 CPU가 올라갔는지는 봤는데

누가

어떤 Credential로

어떤 DB에서

얼마나 많은 데이터를 읽어

어디로 전송했는지는

즉시 연결되지 않았는가?</code></pre>
<p>Runtime Security는 CPU 그래프만 봐서는 부족하다.</p>
<hr>
<h1 id="18-ai-security-agent는-runtime-event를-연결하는-데-유용하다">18. AI Security Agent는 Runtime Event를 연결하는 데 유용하다</h1>
<p>예를 들어 이런 Event가 동시에 발생한다.</p>
<pre><code class="language-text">03:11
새 VM 생성

03:14
DB SELECT 급증

03:16
Data Transfer 증가

03:18
평소 사용하지 않던 Credential 사용

03:21
해외 IP 연결

03:25
VM 삭제</code></pre>
<p>각 이벤트 하나만 보면 정상일 수도 있다.</p>
<p>하지만 연결하면:</p>
<pre><code class="language-text">Possible Data Exfiltration</code></pre>
<p>이다.</p>
<p>이런 <strong>Cross-system Correlation</strong>이 AI가 잘할 수 있는 영역이다.</p>
<pre><code class="language-text">CloudTrail
+
VPC Flow Log
+
DB Audit Log
+
IAM
+
Git Deployment
+
SIEM</code></pre>
<p>을 연결해 설명한다.</p>
<hr>
<h1 id="19-그렇다고-ai에게-실시간-차단권을-바로-주면-안-된다">19. 그렇다고 AI에게 실시간 차단권을 바로 주면 안 된다</h1>
<p>예를 들어 AI가:</p>
<pre><code class="language-text">공격 같습니다.</code></pre>
<p>라고 판단했다고 Production DB 전체를 끊으면 장애가 발생할 수 있다.</p>
<p>그래서 자동화 수준을 나눈다.</p>
<pre><code class="language-text">OBSERVE
→ 로그 분석

ALERT
→ Security Team 호출

CONTAIN
→ Session Kill / Key Disable 후보 제시

AUTO-CONTAIN
→ 명확한 규칙일 때만 자동 차단</code></pre>
<p>예를 들어:</p>
<pre><code class="language-text">Retired Credential 사용

Revoked Key 사용

Impossible Travel

금지된 국가에서 Admin Token 사용</code></pre>
<p>같은 명백한 상황은 자동 대응 가능성이 높다.</p>
<p>반면:</p>
<pre><code class="language-text">데이터 조회량이 조금 많음</code></pre>
<p>같은 것은 Human Review가 필요하다.</p>
<hr>
<h1 id="20-결국-ai보다-먼저-필요한-건-로그다">20. 결국 AI보다 먼저 필요한 건 로그다</h1>
<p>AI가 아무리 강해도 Logging이 없으면 못 본다.</p>
<p>이번 조사에서도 일부 시스템 기록이 약 6일만 보관됐고 신규 장비에 로그관리 정책이 제대로 적용되지 않은 문제가 확인됐다. </p>
<p>AI Security Agent에게:</p>
<pre><code class="language-text">지난달 공격자가 무엇을 했지?</code></pre>
<p>라고 물어도 Log가 없으면 답할 수 없다.</p>
<p>따라서 먼저:</p>
<pre><code class="language-text">누가

언제

어떤 Credential로

어떤 Resource에

어떤 Action을 했고

얼마나 데이터를 읽었는가</code></pre>
<p>가 남아야 한다.</p>
<p>AI는 그 위에 올라간다.</p>
<hr>
<h1 id="21-security-agent가-매일-새벽에-자동-점검하게-한다">21. Security Agent가 매일 새벽에 자동 점검하게 한다</h1>
<p>개발자가 Security Dashboard를 매일 확인하지 않을 수 있다.</p>
<p>AI는 할 수 있다.</p>
<p>예를 들어 매일 새벽:</p>
<pre><code class="language-text">Security Agent

01. Git Secret Alert 확인
02. IAM 신규 권한 확인
03. Admin 권한 증가 확인
04. 오래된 Access Key 확인
05. Rotation 안 된 Secret 확인
06. 새로운 Public Endpoint 확인
07. 새로운 Dependency 확인
08. 최근 Critical Code Scan 확인
09. 비정상 Production Access 확인
10. 미해결 Security Finding 확인</code></pre>
<p>을 수행한다.</p>
<p>결과가 없으면 아무것도 하지 않는다.</p>
<p>문제가 있으면:</p>
<pre><code class="language-text">Security Inbox</code></pre>
<p>에 올린다.</p>
<hr>
<h1 id="22-특히-발견됐지만-안-고친-문제를-ai가-추적하게-한다">22. 특히 “발견됐지만 안 고친 문제”를 AI가 추적하게 한다</h1>
<p>이번 조사 결과에서 가장 아픈 부분 중 하나는 2024년 모의해킹에서 접속키 노출 문제가 발견됐지만 개선되지 않았다는 것이다. </p>
<p>보안에서는 발견보다 <strong>Closure</strong>가 중요하다.</p>
<p>그래서 Security Finding에 상태를 둔다.</p>
<pre><code class="language-text">OPEN
↓
ASSIGNED
↓
FIXED
↓
VERIFIED
↓
CLOSED</code></pre>
<p>그리고:</p>
<pre><code class="language-text">OPEN → 7일
HIGH

OPEN → 30일
CRITICAL ESCALATION</code></pre>
<p>같은 규칙을 둔다.</p>
<p>AI가 매일:</p>
<pre><code class="language-text">90일째 열린 HIGH Finding 3건</code></pre>
<p>을 찾아 Security Lead와 개발 책임자에게 올린다.</p>
<hr>
<h1 id="23-모의해킹-보고서도-pdf로-끝나면-안-된다">23. 모의해킹 보고서도 PDF로 끝나면 안 된다</h1>
<p>흔한 구조:</p>
<pre><code class="language-text">Pentest
↓
PDF
↓
메일
↓
회의
↓
보관</code></pre>
<p>좋은 구조:</p>
<pre><code class="language-text">Pentest
↓
Findings DB
↓
Owner
↓
Deadline
↓
Fix
↓
Automated Verification
↓
Retest
↓
Close</code></pre>
<p>이다.</p>
<p>AI는 여기서 Pentest 보고서를 읽고 Finding을 Issue로 구조화하는 데 매우 유용하다.</p>
<hr>
<h1 id="24-보안-전담인력이-적을수록-ai가-더-의미-있을-수-있다">24. 보안 전담인력이 적을수록 AI가 더 의미 있을 수 있다</h1>
<p>이번 조사에서 티빙 임직원 265명 가운데 개발인력은 149명, 정보보호 전담인력은 약 4명 수준으로 조사됐다. 조사단은 이런 인력 규모로 상시 관제·취약점 점검·이상행위 모니터링 등에 한계가 있었다고 판단했다. </p>
<p>개발자 149명의:</p>
<pre><code class="language-text">PR

Dependency

IAM

Secret

Cloud

API

Database

Log</code></pre>
<p>를 4명이 모두 수동으로 보는 것은 현실적으로 어렵다.</p>
<p>여기서 AI가 의미가 있다.</p>
<p>AI는 보안 전문가를 없애는 것이 아니라:</p>
<pre><code class="language-text">149명 개발자
       ↓
AI Security Layer
       ↓
중요한 20건
       ↓
Security Team</code></pre>
<p>으로 Noise를 줄인다.</p>
<hr>
<h1 id="25-추천하는-전체-architecture">25. 추천하는 전체 Architecture</h1>
<p>실제 개발팀이라면 이 구조가 가장 현실적이다.</p>
<pre><code class="language-text">                       Developer
                           │
                           ▼
                    Coding Agent
                           │
                           ▼
                       Git Commit
                           │
                           ▼
                Secret / Credential Scan
                           │
                     Secret 발견?
                    YES ───────→ BLOCK
                           │
                           ▼
                     Pull Request
                           │
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
       CodeQL         Dependency        AI Security
        SAST            Review            Review
          │                │                │
          └────────────────┼────────────────┘
                           ▼
                     Security Score
                           │
                ┌──────────┼──────────┐
                ▼          ▼          ▼
               LOW       HIGH      CRITICAL
                │          │          │
                ▼          ▼          ▼
               CI       Security    Human
                          Review    Approval
                           │
                           ▼
                        Deploy
                           │
                           ▼
                       Runtime
                           │
           ┌───────────────┼────────────────┐
           ▼               ▼                ▼
         IAM Log        DB Audit        Network Flow
           │               │                │
           └───────────────┼────────────────┘
                           ▼
                   AI Security Monitor
                           │
                이상 행동 Correlation
                           │
               ┌───────────┴───────────┐
               ▼                       ▼
             ALERT                 AUTO-CONTAIN
               │                 명확한 Rule만
               ▼
          Security Team</code></pre>
<p>AI 하나가 모든 것을 지키는 구조가 아니다.</p>
<p>AI가 여러 기존 보안 시스템 사이에서 <strong>놓친 연결을 찾는 구조</strong>다.</p>
<hr>
<h1 id="26-repository는-이렇게-구성할-수-있다">26. Repository는 이렇게 구성할 수 있다</h1>
<pre><code class="language-text">project/
├── AGENTS.md
├── SECURITY.md
│
├── .security/
│   ├── policy.yaml
│   ├── data-classification.yaml
│   ├── permissions.yaml
│   └── exceptions.yaml
│
├── skills/
│   ├── security-review/
│   ├── dependency-review/
│   └── incident-triage/
│
├── src/
└── tests/</code></pre>
<p><code>SECURITY.md</code>에는 인간이 읽을 원칙을 두고,</p>
<p><code>.security/policy.yaml</code>에는 기계가 읽을 규칙을 둔다.</p>
<hr>
<h1 id="27-예를-들어-security-policy">27. 예를 들어 Security Policy</h1>
<pre><code class="language-yaml">secret:
  hardcoded: deny
  production_key_in_repo: deny

permissions:
  new_admin_permission: human_approval
  wildcard_resource: security_review

data:
  pii_logging: deny
  bulk_export: security_review

network:
  new_public_endpoint: security_review

dependencies:
  critical_vulnerability: deny

production:
  direct_developer_access: deny</code></pre>
<p>이렇게 만들어 두면 AI Security Agent 역시 이 Policy를 기준으로 판단할 수 있다.</p>
<hr>
<h1 id="28-coding-agent도-같은-규칙을-먼저-읽게-한다">28. Coding Agent도 같은 규칙을 먼저 읽게 한다</h1>
<p>이제 Codex나 Claude Code에게 기능을 구현시키기 전에:</p>
<pre><code class="language-text">AGENTS.md
SECURITY.md
.security/policy.yaml</code></pre>
<p>을 읽게 한다.</p>
<p>그러면 구현 단계부터:</p>
<pre><code class="language-text">Secret을 어디에 둘 것인가

새 Permission이 필요한가

PII를 다루는가

Public Endpoint인가

Logging에 개인정보가 들어가는가</code></pre>
<p>를 확인한다.</p>
<p>즉 Security Review가 PR 마지막에서만 발생하지 않는다.</p>
<pre><code class="language-text">Design
→ Implementation
→ Review
→ Runtime</code></pre>
<p>전체에 들어간다.</p>
<hr>
<h1 id="29-ai가-개발자의-보안-습관까지-조금씩-바꿀-수-있다">29. AI가 개발자의 보안 습관까지 조금씩 바꿀 수 있다</h1>
<p>예를 들어 Agent가 매번:</p>
<pre><code class="language-text">이 변경은 Production IAM 권한이 추가되므로
Security Review가 필요합니다.</code></pre>
<p>라고 알려준다.</p>
<p>또:</p>
<pre><code class="language-text">이 Credential은 장기 Access Key 대신
Role 기반 Temporary Credential을 사용할 수 있습니다.</code></pre>
<p>라고 제안한다.</p>
<p>이게 반복되면 개발자도 자연스럽게:</p>
<pre><code class="language-text">Credential
→ Secrets Manager

Permission
→ Least Privilege

Production
→ Temporary Role

PII
→ Redaction</code></pre>
<p>을 기본값으로 생각하기 시작한다.</p>
<hr>
<h1 id="30-하지만-ai가-보안-책임자가-되어서는-안-된다">30. 하지만 AI가 보안 책임자가 되어서는 안 된다</h1>
<p>이 글에서 가장 중요한 선이다.</p>
<pre><code class="language-text">AI가 있으니
보안팀이 없어도 된다.</code></pre>
<p>가 아니다.</p>
<p>오히려 반대다.</p>
<p>AI가 필요한 이유는:</p>
<pre><code class="language-text">Security Team의 시간을
정말 중요한 판단에 사용하기 위해서</code></pre>
<p>다.</p>
<p>AI Security Agent는:</p>
<pre><code class="language-text">찾기

분류

연결

요약

추적</code></pre>
<p>을 잘한다.</p>
<p>사람은:</p>
<pre><code class="language-text">위험 수용

Architecture 결정

Incident 대응

법적 판단

Production 차단 결정</code></pre>
<p>을 맡는다.</p>
<hr>
<h1 id="31-티빙-사고에서-배울-가장-중요한-것은-한-번의-실수가-아니다">31. 티빙 사고에서 배울 가장 중요한 것은 “한 번의 실수”가 아니다</h1>
<p>이번 사고는 개발자의 Credential 하나가 탈취된 것에서 시작했지만 조사 결과를 보면 그 뒤로 여러 방어선이 연속해서 제대로 작동하지 않았다.</p>
<pre><code class="language-text">Access Key 관리

Repository Secret

Project Permission

Production Credential

Network Access Control

DB Monitoring

Data Flow Detection

Log Retention

Incident Escalation

Vulnerability Closure</code></pre>
<p>이 중 몇 개만 제대로 작동했어도 피해 규모는 달라졌을 가능성이 있다.</p>
<p>따라서 문제를:</p>
<pre><code class="language-text">개발자가 Key를 잘못 관리했다.</code></pre>
<p>로 끝내면 다시 비슷한 사고가 난다.</p>
<p>보안에서 인간의 실수를 없앨 수는 없다.</p>
<p>대신 <strong>한 번의 인간 실수가 대규모 사고가 되지 못하도록 설계</strong>할 수 있다.</p>
<hr>
<h1 id="마무리">마무리</h1>
<p>티빙 침해사고는 최신 Zero-day 하나 때문에 모든 것이 무너진 사건으로 보기는 어렵다.</p>
<p>2026년 9월 3일 공개된 민관합동조사 결과에서는 개발환경 접속키 관리, 전체 프로젝트 접근권한, 소스 내 운영환경 Credential, 미조치된 기존 취약점, 부족한 이상징후 탐지, 짧은 로그 보관, 사고 보고 지연까지 여러 문제가 함께 확인됐다. </p>
<p>그래서 개발팀이 얻어야 할 결론도:</p>
<blockquote>
<p>개발자들에게 보안 교육을 더 하자.</p>
</blockquote>
<p>에서 끝나면 부족하다.</p>
<p>교육은 필요하다.</p>
<p>하지만 사람은 다시 실수한다.</p>
<p>더 강한 구조는 이렇다.</p>
<pre><code class="language-text">Developer
   ↓
Coding Agent
   ↓
Secret Guard
   ↓
AI Security Review
   ↓
CodeQL / Dependency Scan
   ↓
Policy Gate
   ↓
CI
   ↓
Runtime Monitoring
   ↓
AI Correlation
   ↓
Security Team</code></pre>
<p>즉 보안을:</p>
<pre><code class="language-text">사람이 잘 기억해야 하는 규칙</code></pre>
<p>에서:</p>
<pre><code class="language-text">어기기 어려운 시스템의 기본값</code></pre>
<p>으로 바꾸는 것이다.</p>
<p>그리고 AI가 들어가면서 한 가지 새로운 선택지가 생겼다.</p>
<p>기존 보안 Tool이:</p>
<pre><code class="language-text">Secret 발견

취약점 발견

Dependency 문제 발견</code></pre>
<p>을 한다면 AI Security Agent는 그 위에서:</p>
<pre><code class="language-text">왜 위험한가

무엇과 연결되는가

어디까지 영향을 주는가

다음에 무엇을 해야 하는가

아직 해결되지 않은 문제는 무엇인가</code></pre>
<p>를 계속 추적할 수 있다.</p>
<p>특히 보안 전담인력이 개발조직에 비해 작은 회사라면 의미가 크다.</p>
<p>AI가 보안 전문가를 대신하는 것이 아니다.</p>
<blockquote>
<p><strong>보안 전문가가 모든 PR과 모든 IAM 변경과 모든 로그를 직접 보지 않아도 되도록, AI가 먼저 의심하고 자동화된 시스템이 먼저 막게 만드는 것이다.</strong></p>
</blockquote>
<p>궁극적인 목표는:</p>
<pre><code class="language-text">AI가 보안을 잘한다.</code></pre>
<p>가 아니다.</p>
<p>더 좋은 시스템은:</p>
<pre><code class="language-text">개발자가 실수하고

AI가 놓치고

Security Reviewer도 놓쳐도

마지막 Policy와 Runtime Control이
사고를 막는다.</code></pre>
<p>이다.</p>
<p><strong>보안은 사람의 주의력에 의존할수록 약해지고, 여러 독립된 시스템이 서로를 검증할수록 강해진다.</strong></p>
<p>AI는 그 방어선 중 하나가 될 수 있다.</p>
<p>그리고 2026년의 개발환경이라면 이제는 그 방어선을 굳이 빼둘 이유도 없다.</p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<p>2026년 9월 3일 과학기술정보통신부 민관합동조사 결과를 인용한 연합뉴스 보도에 따르면 티빙 사고에서는 약 3,954만 계정과 소스코드를 포함한 기술자산 361건이 유출됐으며, 개발·운영환경 Credential 관리, 프로젝트 접근권한, 이상징후 탐지·보고, 취약점 개선 등 여러 보안 통제가 함께 미흡했던 것으로 조사됐다. 개인정보보호위원회는 개인정보 유출 규모와 관련 법 위반 여부 등을 별도로 조사하고 있다. </p>
<p>GitHub의 Secret Scanning과 Push Protection은 Source와 Git History에서 Credential을 탐지하고, 지원되는 Secret이 Repository에 들어가기 전에 Push 자체를 차단할 수 있다. CodeQL과 Code Scanning은 Pull Request 단계에서 보안 취약점을 탐지하고 Required Check로 활용할 수 있다. </p>
<p>AWS Well-Architected Security guidance는 장기간 Access Key를 Source Code나 설정 파일에 넣는 방식을 피하고, 가능한 경우 IAM Role 기반의 단기 Credential을 사용하며 필요한 Secret은 전용 Secret 관리 시스템에서 관리·회전하도록 권고한다. </p>
<h3 id="핵심-참고-포인트">핵심 참고 포인트</h3>
<p>이번 사고에서 가장 중요한 교훈은 특정 개발자의 실수 하나가 아니라 <strong>Credential → Repository → Production → Database로 이어지는 공격 경로를 중간에서 차단할 독립적인 보안 통제가 충분히 작동하지 않았다는 점</strong>이다. </p>
<p>따라서 AI Security Agent 역시 단독 방어책으로 두면 안 된다. 가장 현실적인 구조는 <code>Secret 차단 → 최소권한 → AI Security Review → 정적 분석 → CI Policy → Runtime Monitoring → Incident Response</code>를 겹쳐 놓고, AI는 그 사이에서 Context 분석·우선순위·미해결 Finding 추적을 담당하게 만드는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Codex 멀티에이전트 구현 + Claude Review·QA 개발 환경]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609022</link>
            <guid>https://velog.io/@kyu_ios_dev/2609022</guid>
            <pubDate>Wed, 02 Sep 2026 03:11:45 GMT</pubDate>
            <description><![CDATA[<h4 id="codex-멀티에이전트-구현--claude-review·qa-개발-환경">Codex 멀티에이전트 구현 + Claude Review·QA 개발 환경</h4>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/3398d676-5847-4cae-9e46-b926a11e57ca/image.png" alt=""></p>
<p>AI Coding Agent를 처음 사용할 때는 대부분 한 명의 개발자를 하나의 Agent로 대체하는 형태에서 시작한다.</p>
<pre><code class="language-text">Developer
   ↓
Coding Agent
   ↓
Code</code></pre>
<p>하지만 최근 Coding Agent가 긴 작업을 처리하고, 여러 Repository를 동시에 다루며, Build와 Test까지 수행하기 시작하면서 구조가 조금씩 달라지고 있다.</p>
<p>이제 개인 개발자도 이런 환경을 만들 수 있다.</p>
<pre><code class="language-text">                     나
                     │
                     ▼
              Codex Orchestrator
                     │
          ┌──────────┼──────────┐
          ▼          ▼          ▼
      조사 Agent   구현 Agent   테스트 Agent
          │          │          │
          └──────────┼──────────┘
                     ▼
                  변경 코드
                     │
                     ▼
               Claude Review
                     │
                     ▼
                 Codex 수정
                     │
                     ▼
                 Claude QA
                     │
                     ▼
              Runtime Evidence
                     │
                     ▼
                  Human Gate</code></pre>
<p>여기서 핵심은 단순히 Agent를 여러 개 실행하는 것이 아니다.</p>
<p><strong>Codex가 구현 조직을 관리하고 Claude를 독립적인 검증 계층으로 분리하는 것</strong>이다.</p>
<p>OpenAI는 현재 Codex를 여러 Agent를 동시에 관리하는 command center로 설명하고 있으며, 프로젝트별 Thread와 Git worktree를 이용해 여러 Agent가 같은 Repository에서도 서로 충돌하지 않고 병렬 작업할 수 있도록 지원한다. Skills를 이용해 팀이나 개인의 반복적인 작업 방식도 Codex에 정의할 수 있다. </p>
<p>이 기능들을 잘 조합하면 별도의 복잡한 Agent 플랫폼 없이도 꽤 강력한 개인용 AI 개발 조직을 만들 수 있다.</p>
<hr>
<h2 id="1-개인-workspace-자체를-하나의-작은-개발-조직으로-본다">1. 개인 Workspace 자체를 하나의 작은 개발 조직으로 본다</h2>
<p>예를 들어 개인 Workspace가 이렇게 되어 있다고 하자.</p>
<pre><code class="language-text">~/workspace/

├── ios-camera/
├── ios-pantry/
├── android-app/
├── web-dashboard/
├── backend/
├── automation/
└── novel-tools/</code></pre>
<p>각 폴더는 독립된 Git Repository다.</p>
<p>기존에는 개발자가 직접 프로젝트를 옮겨 다녔다.</p>
<pre><code class="language-text">ios-camera
→ 작업

web-dashboard
→ 작업

backend
→ 작업</code></pre>
<p>Agent 환경에서는 조금 다르게 생각할 수 있다.</p>
<pre><code class="language-text">                    Workspace
                        │
                        ▼
                     Codex
                        │
        ┌───────────────┼───────────────┐
        ▼               ▼               ▼
    ios-camera      web-dashboard     backend
        │               │               │
      Agent A          Agent B          Agent C</code></pre>
<p>각 Agent는 자신의 Repository에서 독립적으로 작업한다.</p>
<p>그리고 각 프로젝트 안에는 해당 프로젝트만의 규칙을 둔다.</p>
<hr>
<h1 id="2-프로젝트마다-agentsmd를-따로-둔다">2. 프로젝트마다 AGENTS.md를 따로 둔다</h1>
<p>예를 들어 iOS 프로젝트라면:</p>
<pre><code class="language-text">ios-camera/
├── .git/
├── AGENTS.md
├── Package.swift
├── Sources/
└── Tests/</code></pre>
<p><code>AGENTS.md</code>:</p>
<pre><code class="language-markdown"># 프로젝트 규칙

- Swift 6 기준
- iOS 18 이상
- Swift Concurrency 우선
- UI 상태 변경은 MainActor에서 수행
- 새 외부 라이브러리는 사용자 확인 없이 추가하지 않는다
- 기존 Public API 변경은 확인 후 진행한다
- 구현 후 반드시 Build한다
- 관련 Unit Test가 있으면 실행한다
- 테스트하지 않은 항목은 완료했다고 말하지 않는다</code></pre>
<p>Android라면 전혀 다른 규칙을 둘 수 있다.</p>
<pre><code class="language-markdown"># 프로젝트 규칙

- Kotlin
- Jetpack Compose
- Coroutine Structured Concurrency 준수
- StateFlow 사용
- Gradle build 확인
- lint 실행
- 기존 Convention Plugin 규칙 유지</code></pre>
<p>Web:</p>
<pre><code class="language-markdown"># 프로젝트 규칙

- Next.js
- TypeScript strict 유지
- 접근성 확인
- Playwright E2E 사용
- Console Error 확인
- Responsive Layout 검증</code></pre>
<p>상위 Codex는 이 모든 세부 규칙을 기억할 필요가 없다.</p>
<pre><code class="language-text">Workspace Codex
= 어디에서 누가 일할지 결정

각 Repository
= 어떻게 일할지 결정</code></pre>
<p>역할을 분리한다.</p>
<hr>
<h1 id="3-codex-멀티에이전트는-모두-코딩하게-하지-않는다">3. Codex 멀티에이전트는 ‘모두 코딩’하게 하지 않는다</h1>
<p>멀티에이전트를 처음 쓰면 쉽게 이런 구조를 만들게 된다.</p>
<pre><code class="language-text">Agent A → 구현
Agent B → 구현
Agent C → 구현
Agent D → 구현</code></pre>
<p>하지만 같은 Feature를 여러 Agent가 동시에 수정하면 오히려 관리가 어려워진다.</p>
<p>더 안정적인 구조는 역할을 나누는 것이다.</p>
<pre><code class="language-text">Research Agent
READ ONLY

Architecture Agent
READ ONLY

Implementation Agent
WRITE

Test Agent
READ + EXECUTE</code></pre>
<p>즉:</p>
<pre><code class="language-text">병렬 조사
   ↓
결과 취합
   ↓
한 Agent가 구현</code></pre>
<p>방식이다.</p>
<p>독립적인 작업만 병렬화한다.</p>
<hr>
<h1 id="4-예를-들어-ios-camera-버그-하나를-맡긴다면">4. 예를 들어 iOS Camera 버그 하나를 맡긴다면</h1>
<p>Goal:</p>
<pre><code class="language-text">동영상 촬영 중 간헐적으로
AVAssetWriter append가 실패하는 원인을 찾아 수정한다.</code></pre>
<p>상위 Codex가 바로 코드부터 수정하지 않는다.</p>
<p>먼저 작업을 나눈다.</p>
<pre><code class="language-text">Research Agent A
→ CaptureSession / Frame Pipeline 조사

Research Agent B
→ AVAssetWriter 사용 구조 조사

Research Agent C
→ 관련 Test / Log / Error Path 조사</code></pre>
<p>세 Agent는 동시에 조사할 수 있다.</p>
<pre><code class="language-text">                 Codex
                   │
       ┌───────────┼───────────┐
       ▼           ▼           ▼
 Frame 조사    Writer 조사    Log 조사
       │           │           │
       └───────────┼───────────┘
                   ▼
              조사 결과 취합</code></pre>
<p>그다음 Implementation Agent 하나가 실제 수정한다.</p>
<hr>
<h1 id="5-같은-repository에서는-worktree를-이용한다">5. 같은 Repository에서는 Worktree를 이용한다</h1>
<p>여러 Agent가 동일 Repository에서 작업할 때 가장 중요한 것이 Git 격리다.</p>
<p>Codex 앱은 Worktree를 기본 지원한다.</p>
<p>각 Agent가:</p>
<pre><code class="language-text">main repository

├── worktree-research-a
├── worktree-research-b
├── worktree-implementation
└── worktree-test</code></pre>
<p>처럼 독립된 코드 복사본에서 작업할 수 있다.</p>
<p>OpenAI도 Codex 앱에서 여러 Agent가 동일 Repository를 동시에 작업할 때 각 Agent가 별도의 Worktree를 이용하기 때문에 로컬 Git 상태를 건드리지 않고 다양한 접근을 병렬로 시도할 수 있다고 설명한다. </p>
<p>이게 멀티에이전트에서 굉장히 중요하다.</p>
<hr>
<h1 id="6-codex를-코더가-아니라-tech-lead로-사용한다">6. Codex를 ‘코더’가 아니라 Tech Lead로 사용한다</h1>
<p>상위 Codex 역할은 직접 모든 코드를 작성하는 것이 아니다.</p>
<p>다음에 더 가깝다.</p>
<pre><code class="language-text">Goal 분석

↓

작업 분해

↓

Agent 배치

↓

결과 수집

↓

구현 방향 선택

↓

Build / Test

↓

검증 Agent에게 전달</code></pre>
<p>즉:</p>
<pre><code class="language-text">Codex Orchestrator
=
PM
+
Tech Lead</code></pre>
<p>처럼 사용한다.</p>
<p>실제 수정은 하위 Agent가 담당한다.</p>
<hr>
<h1 id="7-skills로-오케스트레이션-규칙을-고정한다">7. Skills로 오케스트레이션 규칙을 고정한다</h1>
<p>매번 Codex에게:</p>
<pre><code class="language-text">먼저 조사하고
병렬 Agent를 띄우고
한 Agent만 수정하고
테스트하고
Claude Review하고...</code></pre>
<p>라고 설명할 필요는 없다.</p>
<p>Skill로 만든다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">engineering-orchestrator</code></pre>
<p>Skill의 핵심 Goal:</p>
<pre><code class="language-markdown"># 목표

독립적인 조사 작업은 Codex subagent로 병렬 수행한다.

실제 Repository 수정은 명확한 소유권을 가진
하나의 Implementation Agent가 담당한다.

구현 완료 후 자동 검증을 수행한다.

그 후 Claude를 독립 Reviewer로 사용한다.

Critical 또는 Major 문제가 발견되면
Codex가 수정하고 다시 Review한다.

Review를 통과한 뒤 Claude QA를 실행한다.

QA에서 문제가 발견되면 다시 Codex로 반환한다.

Critical / Major가 모두 해결되고
필수 Runtime 검증이 끝났을 때만 완료한다.</code></pre>
<p>실행 순서:</p>
<pre><code class="language-text">1. Goal 확인
2. Repository 규칙 확인
3. 작업 분해
4. 조사 Agent 병렬 실행
5. 결과 취합
6. 구현
7. Build/Test
8. Claude Review
9. 수정
10. Re-review
11. Claude QA
12. 수정
13. Re-QA
14. 결과 보고</code></pre>
<p>OpenAI는 Skills를 반복 가능한 작업 방법, 팀의 표준, 도구 사용 방법 등을 Codex에 제공하는 방식으로 설명하고 있다. </p>
<hr>
<h1 id="8-codex만으로-구현과-테스트까지-처리한다">8. Codex만으로 구현과 테스트까지 처리한다</h1>
<p>첫 번째 검증 계층은 AI Reviewer가 아니다.</p>
<pre><code class="language-text">Compiler
Test
Lint
Runtime</code></pre>
<p>다.</p>
<p>예를 들어 iOS라면:</p>
<pre><code class="language-text">Implementation
      ↓
xcodebuild
      ↓
Unit Test
      ↓
필요한 Simulator 검증</code></pre>
<p>Android:</p>
<pre><code class="language-text">Implementation
      ↓
Gradle
      ↓
Unit Test
      ↓
Lint
      ↓
Emulator</code></pre>
<p>Web:</p>
<pre><code class="language-text">Implementation
      ↓
Type Check
      ↓
Unit Test
      ↓
Build
      ↓
Playwright</code></pre>
<p>Agent가:</p>
<pre><code class="language-text">수정했습니다.
문제 없습니다.</code></pre>
<p>라고 말하는 건 검증이 아니다.</p>
<hr>
<h1 id="9-그다음에-claude를-독립-reviewer로-붙인다">9. 그다음에 Claude를 독립 Reviewer로 붙인다</h1>
<p>여기서 Claude가 들어간다.</p>
<p>Codex가 구현했다면 Claude는 코드를 수정하지 않는다.</p>
<pre><code class="language-text">Codex
= 작성자

Claude
= Reviewer</code></pre>
<p>로 분리한다.</p>
<p>Claude에게 전달할 것은:</p>
<pre><code class="language-text">Task 목표

Acceptance Criteria

Git Diff

관련 Architecture

관련 Test

프로젝트 규칙</code></pre>
<p>정도다.</p>
<p>그리고 Reviewer Prompt를 고정한다.</p>
<pre><code class="language-text">이 변경을 독립 Reviewer 관점에서 검토해.

구현을 수정하지 마.

다음 항목에 대해서만
실제 근거가 있는 문제를 보고해.

- Correctness
- Concurrency
- State
- Architecture
- Error handling
- Regression 가능성
- Missing Test
- Security
- Accessibility

결과는:

Critical
Major
Minor
Missing Tests
Not Verified

로 분류해.</code></pre>
<hr>
<h1 id="10-claude에게-전체-작업-history를-주지-않는-것도-중요하다">10. Claude에게 전체 작업 History를 주지 않는 것도 중요하다</h1>
<p>Codex가 구현 과정에서:</p>
<pre><code class="language-text">왜 이 구조를 선택했는지
어떤 시행착오가 있었는지</code></pre>
<p>를 모두 Claude에게 알려주면 Reviewer도 영향을 받을 수 있다.</p>
<p>독립 Review라면 오히려:</p>
<pre><code class="language-text">Task

Diff

현재 코드

검증 결과</code></pre>
<p>중심으로 주는 것이 좋다.</p>
<p>그러면:</p>
<pre><code class="language-text">Codex
→ 구현 당시의 가정

Claude
→ 결과물 자체 평가</code></pre>
<p>가 분리된다.</p>
<hr>
<h1 id="11-review-결과는-다시-codex로-반환한다">11. Review 결과는 다시 Codex로 반환한다</h1>
<p>예:</p>
<pre><code class="language-text">Claude Review

CRITICAL
없음

MAJOR

1.
Task cancellation 이후에도
state mutation이 발생할 가능성이 있음.

2.
Error path에서 기존 retry state가 초기화되지 않음.

MINOR

Naming 1건.</code></pre>
<p>상위 Codex는 이걸 받는다.</p>
<pre><code class="language-text">Claude Findings
       ↓
Codex 판단
       ↓
Implementation Agent 수정
       ↓
Build
       ↓
Tests</code></pre>
<p>그리고 다시 Claude에게 보낸다.</p>
<hr>
<h1 id="12-re-review를-반드시-한다">12. Re-review를 반드시 한다</h1>
<p>Workflow:</p>
<pre><code class="language-text">Claude Review
     ↓
문제 발견
     ↓
Codex Fix
     ↓
Claude Re-review</code></pre>
<p>완료 조건:</p>
<pre><code class="language-text">Critical = 0
Major = 0</code></pre>
<p>로 정할 수 있다.</p>
<p>Minor는 필요에 따라 처리한다.</p>
<p>이렇게 하면 Review Agent가 단순히 참고 의견만 주고 사라지는 구조가 아니다.</p>
<hr>
<h1 id="13-review와-qa는-같은-claude-session으로-하지-않는다">13. Review와 QA는 같은 Claude Session으로 하지 않는다</h1>
<p>여기서 역할을 한 번 더 분리한다.</p>
<pre><code class="language-text">Claude Review Agent

Source
Diff
Architecture
Tests</code></pre>
<p>를 본다.</p>
<p>반면:</p>
<pre><code class="language-text">Claude QA Agent

실행된 앱
User Goal
UI
Runtime
Recording
Logs</code></pre>
<p>를 본다.</p>
<p>즉:</p>
<pre><code class="language-text">Review
= 코드에서 문제를 예측

QA
= 실제 실행해서 문제를 발견</code></pre>
<p>이다.</p>
<hr>
<h1 id="14-ios-qa라면">14. iOS QA라면</h1>
<p>현재 사용 가능한 도구를 기준으로 구성한다.</p>
<pre><code class="language-text">Claude QA
    │
    ▼
iOS Simulator
    │
    ├── UI Interaction
    ├── Accessibility
    ├── Screenshot
    ├── Screen Recording
    └── Runtime Log</code></pre>
<p>예를 들어:</p>
<pre><code class="language-text">처음 사용하는 사용자가

1. 카메라 화면 진입
2. 필터 선택
3. 동영상 촬영
4. 촬영 종료
5. 저장

까지 수행한다.</code></pre>
<p>단순히 기능이 되는지만 보는 것이 아니다.</p>
<pre><code class="language-text">Tap 실패

버튼 발견 시간

Retry

Backtrack

반응 지연

Keyboard/Overlay

잘못된 Navigation</code></pre>
<p>도 확인한다.</p>
<hr>
<h1 id="15-android-qa도-같은-원칙이다">15. Android QA도 같은 원칙이다</h1>
<pre><code class="language-text">Claude QA
    │
    ▼
Android Emulator
    │
    ├── Semantics
    ├── UIAutomator
    ├── Screenshot
    ├── Recording
    └── Logcat</code></pre>
<p>Element를 찾을 때도:</p>
<pre><code class="language-text">Semantic
↓
Accessibility
↓
Text
↓
Identifier
↓
Visual
↓
Coordinate</code></pre>
<p>순서로 접근한다.</p>
<p>좌표 Tap부터 시작하지 않는다.</p>
<hr>
<h1 id="16-web에서는-playwright를-붙이기가-가장-좋다">16. Web에서는 Playwright를 붙이기가 가장 좋다</h1>
<p>현재 Web이 Agentic QA를 만들기 가장 좋은 환경이다.</p>
<pre><code class="language-text">Claude QA
   │
   ▼
Playwright
   │
   ├── DOM
   ├── ARIA
   ├── Browser Interaction
   ├── Video
   ├── Trace
   ├── Console
   └── Network</code></pre>
<p>Playwright는 현재 공식적으로 Planner, Generator, Healer 형태의 Test Agent Workflow도 제공하고 있어 Agent가 앱을 탐색하고 테스트 계획을 만들거나 실패한 테스트를 다시 조사하는 구조를 만들 수 있다.</p>
<p>Claude QA와 결합하면:</p>
<pre><code class="language-text">User Scenario
     ↓
Browser 사용
     ↓
Problem
     ↓
Screenshot / Video / Trace
     ↓
Finding</code></pre>
<p>형태가 된다.</p>
<hr>
<h1 id="17-qa에서-동일-실패를-반복하게-두지-않는다">17. QA에서 동일 실패를 반복하게 두지 않는다</h1>
<p>Agent QA를 실제 돌리면 자주 발생하는 문제가 있다.</p>
<pre><code class="language-text">버튼 Tap
   ↓
실패
   ↓
같은 버튼 Tap
   ↓
실패
   ↓
다시 Tap</code></pre>
<p>이건 좋은 QA가 아니다.</p>
<p>QA Skill에 규칙을 넣는다.</p>
<pre><code class="language-text">동일한 목표에서
동일하거나 실질적으로 동일한 행동이
2회 실패하면

세 번째 동일 행동을 실행하지 않는다.</code></pre>
<p>대신:</p>
<pre><code class="language-text">STOP

↓

현재 화면 다시 관찰

↓

Semantic Tree 재확인

↓

Keyboard / Modal / Overlay 확인

↓

Navigation State 확인

↓

다른 탐색 전략</code></pre>
<p>으로 간다.</p>
<hr>
<h1 id="18-agent-실패와-product-실패도-분리한다">18. Agent 실패와 Product 실패도 분리한다</h1>
<p>Claude가 버튼을 못 찾았다고:</p>
<pre><code class="language-text">UX가 나쁘다.</code></pre>
<p>고 바로 결론내리면 안 된다.</p>
<p>원인은 적어도 네 종류다.</p>
<pre><code class="language-text">PERCEPTION
화면을 잘못 이해

LOCALIZATION
Element 위치를 잘못 찾음

AUTOMATION
Tap 자체 실패

PRODUCT
실제 앱 문제</code></pre>
<p>QA 결과에는 이 분류를 같이 남기게 한다.</p>
<hr>
<h1 id="19-qa-evidence를-남긴다">19. QA Evidence를 남긴다</h1>
<p>QA Agent의 결과가:</p>
<pre><code class="language-text">테스트했습니다.
정상입니다.</code></pre>
<p>이면 부족하다.</p>
<p>예:</p>
<pre><code class="language-text">Scenario
영상 촬영 후 저장

Functional
PASS

Expected Actions
5

Actual Actions
6

Retry
1

Backtrack
0

Runtime
Crash 0

UX Finding
저장 처리 시작까지 약간의 피드백 지연 존재

Evidence
recording.mov
actions.jsonl
screenshots/005.png

Not Verified
Physical Device</code></pre>
<p>정도가 되어야 한다.</p>
<hr>
<h1 id="20-qa-finding도-다시-codex로-돌아간다">20. QA Finding도 다시 Codex로 돌아간다</h1>
<p>예를 들어 Claude QA가:</p>
<pre><code class="language-text">MAJOR

저장 버튼 Tap 후
약 2초간 Feedback이 없어
사용자가 다시 Tap할 가능성이 있음.</code></pre>
<p>을 찾았다.</p>
<p>그럼:</p>
<pre><code class="language-text">Claude QA Finding
       ↓
Codex
       ↓
관련 State 조사
       ↓
Loading 표시 수정
       ↓
Build/Test
       ↓
Claude QA 2</code></pre>
<p>를 돌린다.</p>
<hr>
<h1 id="21-결국-전체-개발-loop는-이렇게-된다">21. 결국 전체 개발 Loop는 이렇게 된다</h1>
<pre><code class="language-text">                         HUMAN
                           │
                           ▼
                   Codex Orchestrator
                           │
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
      Research         Architecture      Test Analysis
       Codex              Codex              Codex
          │                │                 │
          └────────────────┼─────────────────┘
                           ▼
                    Implementation
                         Codex
                           │
                           ▼
                   Build / Test / Lint
                           │
                           ▼
                    Claude Review
                           │
                    문제 발견?
                    │           │
                   YES         NO
                    │           │
                    ▼           ▼
                Codex Fix    Claude QA
                    │           │
                    ▼           ▼
               Build/Test   Runtime Test
                    │           │
                    └─────┐     │
                          ▼     ▼
                       Re-review
                           │
                           ▼
                        Re-QA
                           │
                           ▼
                    Final Evidence
                           │
                           ▼
                         HUMAN</code></pre>
<p>개인 개발 환경에서도 충분히 현실적인 구조다.</p>
<hr>
<h1 id="22-여러-프로젝트를-동시에-돌리면-더-재미있어진다">22. 여러 프로젝트를 동시에 돌리면 더 재미있어진다</h1>
<p>Workspace가:</p>
<pre><code class="language-text">workspace/

├── ios-camera/
├── ios-pantry/
├── android/
├── web/
└── backend/</code></pre>
<p>라고 하자.</p>
<p>Codex에서는 서로 다른 Project Thread를 동시에 실행할 수 있다. OpenAI는 현재 Codex를 여러 Agent가 프로젝트를 넘나들며 병렬 작업하는 command center로 설명한다. </p>
<p>예:</p>
<pre><code class="language-text">                   Codex Workspace
                          │
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
    ios-camera           web             backend
        │                 │                 │
  Codex Agent Team   Codex Agent Team  Codex Agent
        │                 │                 │
   Claude Review      Claude Review     Tests
        │                 │
    Claude QA          Claude QA</code></pre>
<p>한 프로젝트가 Build되는 동안 다른 프로젝트 Agent는 Repository 조사를 할 수 있다.</p>
<hr>
<h1 id="23-상위-workspace에는-얇은-규칙만-둔다">23. 상위 Workspace에는 얇은 규칙만 둔다</h1>
<p>예:</p>
<pre><code class="language-markdown"># Workspace 운영 규칙

- 각 Agent는 지정된 Repository 안에서만 작업한다.
- Repository의 AGENTS.md를 최우선한다.
- 독립적인 조사 작업은 병렬화한다.
- 동일 파일을 수정하는 Agent를 동시에 실행하지 않는다.
- 구현 Agent와 Review Agent 역할을 분리한다.
- Build/Test 없이 완료 처리하지 않는다.
- Claude Review의 Critical/Major가 0일 때만 QA로 진행한다.
- QA의 주요 문제를 해결하지 않은 상태로 DONE 처리하지 않는다.</code></pre>
<p>프로젝트 세부 규칙은 각 Repository에 둔다.</p>
<hr>
<h1 id="24-workspace에는-task-board-하나를-두면-편하다">24. Workspace에는 Task Board 하나를 두면 편하다</h1>
<p>예:</p>
<pre><code class="language-text">TASKS.md</code></pre>
<p>내용:</p>
<pre><code class="language-text">RUNNING

IOS-114
동영상 저장 실패 조사

WEB-081
결제 Flow 개선


REVIEW

ANDROID-044
로그인 상태 처리


QA

IOS-110
필터 촬영 Flow


DONE

WEB-080
프로필 UI</code></pre>
<p>상위 Codex는 이걸 보고 다음 작업을 선택한다.</p>
<p>개인 개발자에게도 상당히 유용하다.</p>
<hr>
<h1 id="25-codex가-모든-결정을-하게-하지는-않는다">25. Codex가 모든 결정을 하게 하지는 않는다</h1>
<p>자동으로 처리해도 되는 것:</p>
<pre><code class="language-text">Formatting

작은 Refactor

Test 작성

Build 오류 수정

명확한 Bug Fix</code></pre>
<p>확인이 필요한 것:</p>
<pre><code class="language-text">Public API 변경

Architecture 변경

새 Dependency

Database Schema

Auth 구조</code></pre>
<p>사람에게 남길 것:</p>
<pre><code class="language-text">Production Deploy

Security Policy

중요 Product 결정

대규모 데이터 Migration</code></pre>
<p>즉:</p>
<pre><code class="language-text">AUTO

CONFIRM

HUMAN ONLY</code></pre>
<p>세 단계로 나눈다.</p>
<hr>
<h1 id="26-최종-완료-조건도-명확하게-만든다">26. 최종 완료 조건도 명확하게 만든다</h1>
<p>Agent가:</p>
<pre><code class="language-text">작업 완료했습니다.</code></pre>
<p>라고 말한다고 완료가 아니다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Implementation 완료

Build PASS

Tests PASS

Claude Review
Critical 0
Major 0

Claude QA
Functional PASS

확인하지 못한 항목 명시

Git Diff 확인 가능</code></pre>
<p>정도가 완료 조건이다.</p>
<hr>
<h1 id="27-가장-중요한-목표는-agent-숫자를-늘리는-게-아니다">27. 가장 중요한 목표는 Agent 숫자를 늘리는 게 아니다</h1>
<p>멀티에이전트를 구축하다 보면 쉽게:</p>
<pre><code class="language-text">Agent 10개

Agent 20개</code></pre>
<p>가 목표가 된다.</p>
<p>하지만 실제 병목은 사람이다.</p>
<pre><code class="language-text">Agent Throughput
↑↑↑

Human Review
→</code></pre>
<p>Agent가 하루에 PR을 20개 만들어도 사람이 검토하지 못하면 아무 의미가 없다.</p>
<p>그래서 오케스트레이션의 목표는:</p>
<pre><code class="language-text">더 많은 Agent</code></pre>
<p>가 아니라:</p>
<pre><code class="language-text">더 적은 Human Attention으로
더 신뢰할 수 있는 Change</code></pre>
<p>를 만드는 것이다.</p>
<hr>
<h1 id="28-codex--claude-구조의-장점">28. Codex + Claude 구조의 장점</h1>
<p>이 구조에서 역할이 매우 명확하다.</p>
<pre><code class="language-text">Codex
= 생산

Claude
= 독립 검증

Build/Test/Runtime
= 증거

Human
= 최종 판단</code></pre>
<p>특정 모델 하나의 자기 검증에 의존하지 않는다.</p>
<p>그리고 모델이 바뀌어도 Workflow 자체는 유지할 수 있다.</p>
<p>나중에:</p>
<pre><code class="language-text">Codex → 다른 구현 Agent

Claude → 다른 Review Agent</code></pre>
<p>로 교체해도:</p>
<pre><code class="language-text">Goal
→ 구현
→ 검증
→ QA
→ Human</code></pre>
<p>구조는 그대로 남는다.</p>
<hr>
<h1 id="29-결국-개인-개발자도-작은-ai-개발팀을-운영하게-된다">29. 결국 개인 개발자도 작은 AI 개발팀을 운영하게 된다</h1>
<p>예전 개인 개발:</p>
<pre><code class="language-text">나

기획
설계
개발
테스트
QA
Review</code></pre>
<p>Agent 환경:</p>
<pre><code class="language-text">                  나
                  │
                  ▼
             Goal / 판단
                  │
                  ▼
               Codex
       ┌──────────┼──────────┐
       ▼          ▼          ▼
     조사        구현       테스트
                  │
                  ▼
                Claude
             Review / QA
                  │
                  ▼
              Evidence
                  │
                  ▼
                  나</code></pre>
<p>개발자가 직접 모든 작업을 수행하는 것에서 <strong>AI 팀의 작업 경계를 설계하고 최종 결과를 판단하는 역할</strong>로 조금씩 이동한다.</p>
<hr>
<h1 id="30-그렇다면-orca는-필요-없을까">30. 그렇다면 Orca는 필요 없을까?</h1>
<p>꼭 그렇지는 않다.</p>
<p>Codex 안에서만 이런 환경을 구성하면 가장 단순하다는 장점이 있다.</p>
<p>Codex 자체가 이미:</p>
<ul>
<li>Multi-agent</li>
<li>프로젝트별 Thread</li>
<li>Git Worktree</li>
<li>Skills</li>
<li>Background Work</li>
</ul>
<p>를 지원하기 때문이다. </p>
<p>하지만 Agent 종류를 더 자유롭게 섞거나, Agent 실행 상태 자체를 별도 시스템에서 관리하고 싶다면 <strong>외부 오케스트레이션 계층</strong>이 의미가 있다.</p>
<p>대표적인 예가 Orca 계열이다.</p>
<hr>
<h1 id="31-orca를-넣으면-구조는-이렇게-바뀐다">31. Orca를 넣으면 구조는 이렇게 바뀐다</h1>
<pre><code class="language-text">                    Human
                      │
                      ▼
                Orchestrator
                      │
                      ▼
                    Orca
        ┌─────────────┼─────────────┐
        ▼             ▼             ▼
      Codex       Claude Code     Cursor
        │             │             │
        └─────────────┼─────────────┘
                      ▼
              Isolated Worktrees</code></pre>
<p>Orca 프로젝트들은 일반적으로 Agent마다 독립 Git worktree를 만들고 여러 Worker를 병렬 실행한 뒤 상태와 결과를 오케스트레이터에 전달하는 방식을 사용한다.</p>
<p>예를 들어 <code>araa47/orca</code>는 각 Worker를 독립 Git worktree와 tmux 환경에 실행하고 background daemon이 Worker 완료·막힘 상태 등을 감시해 상위 오케스트레이터에게 전달한다. Codex·Claude Code·Cursor를 Worker로 사용할 수 있다. 다만 해당 프로젝트 자체가 개인/Hobby 프로젝트라는 점은 감안해야 한다. </p>
<p>다른 <code>orca-cli/orca</code> 구현은 SQLite에 Run 상태를 저장하고, 각 Agent를 Worktree로 격리하며, MCP를 통해 Codex·Claude Code·Cursor·OpenCode 등의 Agent가 Orca를 제어할 수 있도록 설계돼 있다. 작업 의존성을 DAG로 구성하는 Pod 구조도 제공한다. </p>
<hr>
<h1 id="32-orca가-codex-native-방식보다-좋은-경우">32. Orca가 Codex Native 방식보다 좋은 경우</h1>
<p>다음 같은 상황이다.</p>
<pre><code class="language-text">Codex만 사용</code></pre>
<p>이 아니라:</p>
<pre><code class="language-text">Codex

Claude Code

Cursor

OpenCode

다른 Agent</code></pre>
<p>를 동시에 Worker로 사용하고 싶다.</p>
<p>또는:</p>
<pre><code class="language-text">Agent 상태

Run History

작업 DAG

완료 이벤트

Retry

Worker 교체</code></pre>
<p>를 모델과 분리된 시스템에서 관리하고 싶을 수도 있다.</p>
<p>이런 경우 Orca 같은 별도 Orchestration Layer가 더 자연스럽다.</p>
<hr>
<h1 id="33-반대로-개인-개발자라면-codex-native부터-시작하는-게-좋다">33. 반대로 개인 개발자라면 Codex Native부터 시작하는 게 좋다</h1>
<p>처음부터:</p>
<pre><code class="language-text">Codex
+
Claude
+
Orca
+
MCP
+
tmux
+
Task DB</code></pre>
<p>를 모두 구성할 필요는 없다.</p>
<p>관리해야 하는 시스템만 늘어난다.</p>
<p>현재 Codex가 제공하는 기능으로 먼저:</p>
<pre><code class="language-text">Codex Multi-Agent

+

Worktree

+

Skills

+

Claude Review/QA</code></pre>
<p>를 구성해보는 편이 좋다.</p>
<p>필요한 순간이 오면 Orca를 추가한다.</p>
<hr>
<h1 id="34-비슷한-효과를-내는-다른-방식도-있다">34. 비슷한 효과를 내는 다른 방식도 있다</h1>
<p>Orca만 유일한 방법은 아니다.</p>
<p>예를 들어 <strong>Orka Agents</strong> 계열 프로젝트는 Codex CLI·Claude Code CLI·GitHub Copilot CLI·OpenCode 같은 Repository 기반 Coding Agent Runtime을 하나의 Coordinator 아래에서 실행하고, 장시간 Goal Loop와 Multi-Agent Coordination을 제공하는 방향으로 개발되고 있다. </p>
<p>또 다른 Orca 계열 데스크톱 환경들은 여러 Codex·Claude Code·OpenCode Agent를 각각 Worktree에서 병렬 실행하고 결과를 한 화면에서 비교하는 구조를 제공한다. </p>
<p>그리고 꼭 별도 오케스트레이터를 사용할 필요도 없다.</p>
<p>Claude Code의 Subagent, Codex Multi-Agent, CI Workflow, Git Worktree와 간단한 Task Ledger를 조합해서 직접 작은 오케스트레이션 환경을 만들 수도 있다.</p>
<hr>
<h1 id="마무리">마무리</h1>
<p>현재 개인 개발자에게 꽤 현실적인 시작점은 이 구조라고 생각한다.</p>
<pre><code class="language-text">                    HUMAN
                      │
                      ▼
              Codex Orchestrator
                      │
          ┌───────────┼───────────┐
          ▼           ▼           ▼
       Research    Architecture   Test
        Codex        Codex        Codex
          │           │           │
          └───────────┼───────────┘
                      ▼
               Codex Implementation
                      │
                      ▼
                Build / Test
                      │
                      ▼
                Claude Review
                      │
                 Codex Fix
                      │
                 Re-review
                      │
                      ▼
                  Claude QA
                      │
                Runtime Evidence
                      │
                      ▼
                    HUMAN</code></pre>
<p>이 구조에서 Codex는 단순한 Coding Agent가 아니다.</p>
<p><strong>여러 작업과 Agent를 관리하는 Engineering Orchestrator</strong>가 된다.</p>
<p>Claude도 두 번째 Coding Agent로 사용하지 않는다.</p>
<pre><code class="language-text">Claude Review
Claude Runtime QA</code></pre>
<p>라는 독립 검증 계층으로 사용한다.</p>
<p>그리고 가장 중요한 판단은 AI가 아니라:</p>
<pre><code class="language-text">Compiler
Tests
Runtime
Git Diff
Human</code></pre>
<p>에 남긴다.</p>
<p>OpenAI가 Codex를 여러 Agent를 병렬로 관리하는 command center로 확장하고 Worktree와 Skills를 기본 기능으로 넣은 것도 결국 개발 Workflow가 이런 방향으로 이동하고 있기 때문이다. </p>
<p>중요한 것은 Agent를 몇 명 띄웠느냐가 아니다.</p>
<blockquote>
<p><strong>개발자의 개입을 얼마나 줄이면서도 검증 가능한 Software Change를 만들어낼 수 있느냐</strong>다.</p>
</blockquote>
<p>그래서 개인 Workspace가 이미 여러 Git Repository로 잘 나뉘어 있다면 굳이 거대한 Agent Platform부터 구축할 필요가 없다.</p>
<p>먼저:</p>
<pre><code class="language-text">Workspace
+
Codex Multi-Agent
+
프로젝트별 AGENTS.md
+
Skills
+
Git Worktree
+
Claude Review
+
Claude QA</code></pre>
<p>로 시작해도 상당히 강력한 개인 AI 개발팀을 만들 수 있다.</p>
<p>그리고 프로젝트 수가 늘어나거나 서로 다른 Coding Agent를 동시에 운영하고 싶어질 때는 그 위에 <strong>Orca 같은 Agent Orchestrator, Orka Agents 계열, 또는 다른 Multi-Agent Runtime</strong>을 얹어 비슷한 구조를 더 명시적인 실행·상태 관리 시스템으로 확장할 수 있다. </p>
<p>즉 선택은 두 가지다.</p>
<pre><code class="language-text">가볍게 시작

Codex Native
+ Claude Review/QA</code></pre>
<p>또는:</p>
<pre><code class="language-text">Agent 종류와 규모 확대

Orchestration Layer
+ Codex
+ Claude Code
+ 기타 Agent</code></pre>
<p>어느 쪽이든 핵심 Architecture는 같다.</p>
<p><strong>구현하는 Agent와 검증하는 Agent를 분리하고, Agent보다 Evidence를 신뢰하며, 사람은 가장 비싼 판단에만 개입하는 것.</strong></p>
<p>앞으로 개인 개발 환경도 점점 IDE 하나를 사용하는 방식에서 <strong>작은 AI 개발 조직을 운영하는 방식</strong>으로 바뀔 가능성이 크다.</p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<p>OpenAI는 Codex를 여러 Agent를 동시에 관리하고 프로젝트별로 병렬 작업을 수행하는 command center로 제공하고 있으며, 같은 Repository에서도 Git worktree를 통해 Agent 작업을 격리할 수 있다고 설명한다. Skills를 통해 반복적인 개발 Workflow와 팀 규칙을 Codex에 제공할 수도 있다. </p>
<p>Orca 계열 오픈소스 프로젝트들은 Codex·Claude Code·Cursor 같은 Coding Agent를 독립 Git worktree에 실행하고, Worker의 상태·완료·Retry·작업 의존성을 오케스트레이션 계층에서 관리하는 접근을 보여준다. 구현마다 기능과 성숙도는 다르므로 실제 도입 전 프로젝트 상태와 유지보수 수준을 확인할 필요가 있다. </p>
<h3 id="핵심-참고-포인트">핵심 참고 포인트</h3>
<p>처음부터 외부 Orchestrator를 추가해야 하는 것은 아니다. 현재 Codex 자체가 <strong>Multi-Agent + Worktree + Skills + 프로젝트 단위 작업</strong>을 제공하기 때문에 개인 개발 환경에서는 먼저 Codex를 상위 오케스트레이터로 두고 Claude를 Review·QA 계층으로 분리하는 방식이 비교적 단순하다. </p>
<p>프로젝트와 Agent 수가 늘어나거나 Codex·Claude Code·Cursor 등 여러 Agent Runtime을 한 시스템에서 운영하고 싶어진다면 Orca나 Orka 같은 별도의 오케스트레이션 도구를 추가할 수 있다. 중요한 것은 특정 도구가 아니라 <code>Goal → 병렬 조사 → 구현 → 자동 검증 → 독립 Review → Runtime QA → Human Gate</code>라는 Workflow 자체다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Claude Fable 5.1이 바꾼 Coding Agent 판도: GPT-5.6 Sol을 앞선 건 무엇인가]]></title>
            <link>https://velog.io/@kyu_ios_dev/2609021</link>
            <guid>https://velog.io/@kyu_ios_dev/2609021</guid>
            <pubDate>Wed, 02 Sep 2026 02:41:33 GMT</pubDate>
            <description><![CDATA[<h4 id="claude-fable-51이-바꾼-coding-agent-판도-gpt-56-sol을-앞선-건-무엇인가">Claude Fable 5.1이 바꾼 Coding Agent 판도: GPT-5.6 Sol을 앞선 건 무엇인가</h4>
<p><img src="https://velog.velcdn.com/images/kyu_ios_dev/post/1eccff05-7fa4-43cd-b78a-049c109923b7/image.png" alt=""></p>
<p>불과 두 달 전만 해도 Coding Agent 경쟁에서는 GPT-5.6 Sol의 존재감이 상당히 강했다.</p>
<p>OpenAI가 2026년 7월 GPT-5.6을 정식 공개했을 당시 Sol은 Artificial Analysis Coding Agent Index에서 <strong>80점</strong>을 기록했다. 당시 Claude Fable 5는 77.2점이었다. OpenAI는 Terminal-Bench 2.1과 DeepSWE에서도 Sol의 장기 Coding Agent 성능을 강조했다. </p>
<p>그런데 2026년 9월 1일 Anthropic이 <strong>Claude Fable 5.1</strong>을 공개하면서 분위기가 다시 달라졌다. Anthropic은 Fable 5.1을 현재 자사의 가장 강력한 Coding·Knowledge Work 모델로 소개하고 있다. </p>
<p>이번 변화에서 중요한 건 단순히 새로운 모델이 벤치마크 몇 개에서 GPT를 앞섰다는 사실이 아니다.</p>
<p>더 중요한 변화는 <strong>Coding Model 경쟁의 중심이 코드 생성 능력에서 실제 Engineering Task를 끝까지 수행하는 Agent 능력으로 이동하고 있다는 점</strong>이다.</p>
<hr>
<h2 id="1-몇-달-만에-순위가-다시-뒤집혔다">1. 몇 달 만에 순위가 다시 뒤집혔다</h2>
<p>GPT-5.6 Sol이 공개됐을 당시 OpenAI가 강조했던 지표 중 하나가 Artificial Analysis Coding Agent Index였다.</p>
<pre><code class="language-text">GPT-5.6 Sol     80.0
Claude Fable 5  77.2</code></pre>
<p>Sol은 당시 Fable 5보다 2.8점 높았다. </p>
<p>특히 OpenAI가 강조한 것은 단순한 점수뿐만 아니었다.</p>
<p>Sol은 Fable 5와 비교했을 때 더 적은 출력 토큰과 더 짧은 작업 시간, 더 낮은 예상 비용으로 높은 Coding Agent 성능을 냈다는 것이 OpenAI의 설명이었다. </p>
<p>그런데 Fable 5.1이 나오면서 비교 대상 자체가 달라졌다.</p>
<p>Artificial Analysis의 출시 직후 비교에서는 <strong>Fable 5.1의 Adaptive Reasoning·Max Effort 구성이 GPT-5.6 Sol medium보다 Intelligence Index에서 상당히 높은 결과</strong>를 보이고 있다.</p>
<pre><code class="language-text">Artificial Analysis Intelligence Index

Claude Fable 5.1 Max    66
GPT-5.6 Sol Medium      56</code></pre>
<p>다만 이 비교는 추론 설정이 동일하지 않다.</p>
<p>Fable은 Max Effort이고 Sol은 Medium이므로 이것만 보고 “10점 차이로 완전히 이겼다”고 말하면 안 된다. 반대로 현재 Fable 5.1이 이전 Fable 5보다 상당히 강해졌다는 신호로 보는 것은 충분히 가능하다. </p>
<hr>
<h1 id="2-이번-변화는-일반-coding보다-agentic-coding에서-더-크게-보인다">2. 이번 변화는 일반 Coding보다 Agentic Coding에서 더 크게 보인다</h1>
<p>요즘 Coding Agent가 수행하는 일은 예전의 코드 생성과 많이 다르다.</p>
<p>예전에는:</p>
<pre><code class="language-text">요구사항
  ↓
함수 작성
  ↓
결과</code></pre>
<p>정도였다.</p>
<p>지금은 오히려 이런 형태다.</p>
<pre><code class="language-text">Repository 탐색
        ↓
관련 Architecture 파악
        ↓
문제 재현
        ↓
수정 계획
        ↓
여러 파일 수정
        ↓
Build
        ↓
Test
        ↓
실패
        ↓
원인 재분석
        ↓
수정
        ↓
재검증
        ↓
Review-ready 결과</code></pre>
<p>이 흐름에서는 모델의 순수 Coding 능력만으로는 부족하다.</p>
<p>필요한 능력이 달라진다.</p>
<pre><code class="language-text">Repository Understanding

Planning

Tool Use

Long-horizon Reasoning

Failure Recovery

Verification

Context 유지</code></pre>
<p>이번 Fable 5.1이 특히 노리는 부분이 이 영역이다.</p>
<p>Anthropic은 Fable 5.1을 대규모 코드베이스 작업, Code Review, 장시간 진행되는 Agent 작업, Tool 사용과 복잡한 Knowledge Work를 위한 모델로 소개하고 있다. </p>
<hr>
<h1 id="3-좋은-coding-agent는-코드를-잘-만드는-agent가-아니다">3. 좋은 Coding Agent는 코드를 잘 만드는 Agent가 아니다</h1>
<p>실제 개발에서 더 중요한 질문은 이것이다.</p>
<pre><code class="language-text">한 번에 정답 코드를 만들었는가?</code></pre>
<p>보다:</p>
<pre><code class="language-text">문제가 생겨도
사람을 계속 부르지 않고
끝까지 해결할 수 있는가?</code></pre>
<p>다.</p>
<p>예를 들어 Agent에게 Build Error 하나를 맡긴다.</p>
<p>좋지 않은 Agent:</p>
<pre><code class="language-text">Build 실패
   ↓
A 수정
   ↓
Build 실패
   ↓
A&#39; 수정
   ↓
Build 실패
   ↓
A&#39;&#39; 수정</code></pre>
<p>겉으로 보면 계속 일하고 있다.</p>
<p>하지만 실제로는 같은 가설 안에서 빙빙 돌고 있다.</p>
<p>좋은 Agent는 두 번째 실패쯤에서 이렇게 움직여야 한다.</p>
<pre><code class="language-text">Build 실패
   ↓
기존 가설 폐기
   ↓
관련 코드 다시 조사
   ↓
새 가설 수립
   ↓
다른 증거 확인
   ↓
수정</code></pre>
<p>이게 <strong>Recovery 능력</strong>이다.</p>
<p>장시간 Coding Agent에서는 이 차이가 굉장히 크다.</p>
<hr>
<h1 id="4-gpt-56-sol-역시-바로-이-영역을-겨냥한-모델이다">4. GPT-5.6 Sol 역시 바로 이 영역을 겨냥한 모델이다</h1>
<p>그래서 Fable 5.1이 좋아졌다고 해서 Sol이 갑자기 구형 Coding Model이 된 것은 아니다.</p>
<p>OpenAI가 GPT-5.6 Sol을 출시하면서 가장 강하게 강조했던 것도 long-horizon agentic work였다.</p>
<p>Sol은 Terminal-Bench 2.1에서 88.8퍼센트, DeepSWE v1.1에서 72.7퍼센트를 기록했고, <code>max</code> 추론과 여러 하위 Agent를 병렬로 사용하는 <code>ultra</code> 구성까지 도입했다. </p>
<p>즉 두 회사 모두 같은 곳을 보고 있다.</p>
<pre><code class="language-text">Claude Fable 5.1
          ↘

        Long-running
        Engineering Agent

          ↗
GPT-5.6 Sol</code></pre>
<p>경쟁은 더 이상 “누가 Python 함수를 더 잘 만드는가”가 아니다.</p>
<hr>
<h1 id="5-벤치마크-숫자를-직접-비교할-때는-주의해야-한다">5. 벤치마크 숫자를 직접 비교할 때는 주의해야 한다</h1>
<p>여기서 자주 발생하는 오류가 있다.</p>
<p>예를 들어 GPT-5.6 Sol 발표 자료에는:</p>
<pre><code class="language-text">Terminal-Bench 2.1
88.8%</code></pre>
<p>이 나온다. </p>
<p>반면 최신 Claude 자료나 새로운 비교에서는 다른 버전의 Terminal-Bench나 다른 Harness를 사용하는 경우가 있다.</p>
<p>그래서:</p>
<pre><code class="language-text">88.8 vs 55.x</code></pre>
<p>처럼 숫자만 직접 놓고:</p>
<pre><code class="language-text">Sol이 훨씬 강하다.</code></pre>
<p>라고 결론 내리면 안 된다.</p>
<p>Benchmark 버전이 다르면 문제 집합도 다르고, Agent Harness나 Tool 환경도 달라질 수 있다.</p>
<p>Coding Agent에서는 특히:</p>
<pre><code class="language-text">Model
+
Harness
+
Tool
+
Reasoning 설정
+
Context</code></pre>
<p>전체가 결과에 영향을 준다.</p>
<hr>
<h1 id="6-이제-모델-이름보다-harness가-더-중요해진다">6. 이제 모델 이름보다 Harness가 더 중요해진다</h1>
<p>같은 Fable 5.1이라도:</p>
<pre><code class="language-text">Claude App</code></pre>
<p>에서 사용하는 것과:</p>
<pre><code class="language-text">Claude Code</code></pre>
<p>로 Repository를 직접 수정하게 하는 것은 완전히 다른 경험이다.</p>
<p>Sol도 마찬가지다.</p>
<pre><code class="language-text">ChatGPT</code></pre>
<p>와:</p>
<pre><code class="language-text">Codex</code></pre>
<p>에서 동일한 모델을 사용해도 Agent의 행동 방식은 달라진다.</p>
<p>이제 실제 Coding Agent 성능은 대략 이런 식으로 보는 것이 맞다.</p>
<pre><code class="language-text">Agent 성능
=
Model
+
Harness
+
Repository Context
+
Tool Access
+
Project Rules
+
Validation</code></pre>
<p>모델 하나의 IQ 점수만으로 설명하기 어렵다.</p>
<hr>
<h1 id="7-fable-51에서-눈여겨볼-부분은-code-review다">7. Fable 5.1에서 눈여겨볼 부분은 Code Review다</h1>
<p>Coding Agent가 좋아지면서 새로운 병목이 하나 생겼다.</p>
<p><strong>Review다.</strong></p>
<p>Agent가 몇 분 만에 20개 파일을 수정할 수 있어도 사람은 그 20개 파일을 다시 읽어야 한다.</p>
<p>그래서 앞으로 강한 Coding Agent에게 필요한 능력은:</p>
<pre><code class="language-text">Code Generation</code></pre>
<p>뿐만 아니다.</p>
<pre><code class="language-text">Code Review

Impact Analysis

Missing Test 발견

Architecture 위반 탐지

Risk 분류</code></pre>
<p>가 점점 중요해진다.</p>
<p>Fable 5.1도 Anthropic이 Coding과 Knowledge Work를 핵심 용도로 내세우면서 이런 장시간 Repository 작업을 중심에 두고 있다. </p>
<hr>
<h1 id="8-좋은-reviewer는-diff만-보면-안-된다">8. 좋은 Reviewer는 Diff만 보면 안 된다</h1>
<p>예를 들어 이런 변경이 있다고 하자.</p>
<pre><code class="language-swift">func loadUser() async {
    user = try? await repository.load()
}</code></pre>
<p>단순히 문법만 보면 이상하지 않을 수 있다.</p>
<p>하지만 실제 Review에서는:</p>
<pre><code class="language-text">이 메서드는 MainActor인가?

View가 사라졌을 때 Task는 취소되는가?

실패를 왜 무시하는가?

Repository 구현은 Actor-safe한가?

기존 Error State는 어떻게 되는가?

테스트는 있는가?</code></pre>
<p>까지 봐야 한다.</p>
<p>즉:</p>
<pre><code class="language-text">Diff
↓
Call Graph
↓
State
↓
Architecture
↓
Runtime
↓
Test</code></pre>
<p>를 연결해야 한다.</p>
<p>이런 작업은 작은 코드 생성 문제보다 훨씬 긴 Context와 추론을 필요로 한다.</p>
<hr>
<h1 id="9-그래서-이번-경쟁은-누가-더-똑똑하냐보다-누가-덜-귀찮게-하느냐에-가깝다">9. 그래서 이번 경쟁은 ‘누가 더 똑똑하냐’보다 ‘누가 덜 귀찮게 하느냐’에 가깝다</h1>
<p>Agent를 실제 사용하는 개발자 입장에서는 꽤 단순하다.</p>
<p>A Agent:</p>
<pre><code class="language-text">질문
질문
질문
승인
질문
실패
재시도</code></pre>
<p>B Agent:</p>
<pre><code class="language-text">Task 시작

↓

조사

↓

구현

↓

Build

↓

실패

↓

스스로 복구

↓

Test

↓

결과 보고</code></pre>
<p>두 모델의 Benchmark가 비슷하다면 실제로는 B가 훨씬 생산적이다.</p>
<p>그래서 앞으로 Coding Agent 지표에는 이런 것도 들어가야 한다.</p>
<pre><code class="language-text">Successful Task Rate

Human Intervention Count

Retry Count

Recovery Success Rate

Review Time

Unnecessary Diff</code></pre>
<hr>
<h1 id="10-sol과-fable-51의-차이는-이제-성능만으로-보기-어렵다">10. Sol과 Fable 5.1의 차이는 이제 성능만으로 보기 어렵다</h1>
<p>현재 분위기를 단순화하면 대략 이런 식이다.</p>
<h3 id="gpt-56-sol">GPT-5.6 Sol</h3>
<p>강점은 여전히 뚜렷하다.</p>
<pre><code class="language-text">강한 일반 추론

Agentic Coding

Codex 통합

Programmatic Tool Calling

큰 Context

빠른 처리

상대적으로 낮은 API 비용</code></pre>
<p>OpenAI는 GPT-5.6이 Tool을 연결하고 중간 결과를 처리하며 다음 Action까지 결정하는 Programmatic Tool Calling을 지원하도록 설계했다고 설명한다. </p>
<hr>
<h3 id="claude-fable-51">Claude Fable 5.1</h3>
<p>이번 세대에서 눈에 띄는 방향은:</p>
<pre><code class="language-text">장시간 Repository 작업

복잡한 Coding

Code Review

긴 Knowledge Work

Tool 기반 Agent 작업</code></pre>
<p>이다.</p>
<p>특히 최신 독립 평가 초기 결과에서도 Fable 5.1의 추론 성능 상승이 확인되기 시작했다. </p>
<hr>
<h1 id="11-가격은-sol이-여전히-중요한-강점을-가진다">11. 가격은 Sol이 여전히 중요한 강점을 가진다</h1>
<p>Coding Agent에서는 성능이 전부가 아니다.</p>
<p>Agent는 많은 Token을 소비한다.</p>
<p>Repository가 크다면:</p>
<pre><code class="language-text">Architecture 문서

Source

Tests

Build Log

Git Diff

Error Log</code></pre>
<p>를 계속 읽는다.</p>
<p>그래서 가격 차이가 장시간 작업에서 크게 누적된다.</p>
<p>Artificial Analysis의 현재 비교에서도 Fable 5.1 Max 구성이 GPT-5.6 Sol medium보다 지능 점수는 높지만 Token 비용은 더 높은 것으로 나타난다. </p>
<p>즉:</p>
<pre><code class="language-text">가장 강한 모델</code></pre>
<p>과:</p>
<pre><code class="language-text">가장 경제적인 Agent</code></pre>
<p>는 반드시 같은 모델이 아니다.</p>
<hr>
<h1 id="12-진짜-비교해야-할-것은-cost-per-successful-task다">12. 진짜 비교해야 할 것은 Cost per Successful Task다</h1>
<p>예를 들어:</p>
<pre><code class="language-text">Fable 5.1

Task 성공
1회 실행
비용 6달러</code></pre>
<p>와:</p>
<pre><code class="language-text">Sol

첫 번째 실패
두 번째 Retry
세 번째 성공
총 비용 4달러</code></pre>
<p>라면 Sol이 더 저렴하다.</p>
<p>반대로:</p>
<pre><code class="language-text">Fable
1회 성공</code></pre>
<pre><code class="language-text">Sol
4회 실패 후 Human Intervention</code></pre>
<p>이라면 Fable이 비싸더라도 전체 비용은 더 낮을 수 있다.</p>
<p>실제 비용은:</p>
<pre><code class="language-text">Model Cost

+

Retry Cost

+

CI Cost

+

Human Review Time

+

Rework</code></pre>
<p>이다.</p>
<p>그래서 결국 중요한 지표는:</p>
<pre><code class="language-text">Cost per Successful Task</code></pre>
<p>가 된다.</p>
<hr>
<h1 id="13-개발자가-직접-비교하려면-벤치마크보다-자기-repository가-낫다">13. 개발자가 직접 비교하려면 벤치마크보다 자기 Repository가 낫다</h1>
<p>새 모델이 나왔을 때 LeetCode 같은 문제를 하나 던지는 것보다 실제 Repository에서 같은 일을 맡겨 보는 게 훨씬 낫다.</p>
<p>예를 들어 다섯 가지 정도면 충분하다.</p>
<h3 id="오래된-버그">오래된 버그</h3>
<pre><code class="language-text">재현
↓
원인
↓
수정
↓
Regression Test</code></pre>
<hr>
<h3 id="repository-전체-refactoring">Repository 전체 Refactoring</h3>
<pre><code class="language-text">영향 범위 조사
↓
계획
↓
수정
↓
Build
↓
Test</code></pre>
<hr>
<h3 id="code-review">Code Review</h3>
<pre><code class="language-text">PR Diff
↓
Critical/Major 문제
↓
Missing Test
↓
실제 영향</code></pre>
<hr>
<h3 id="실패-recovery">실패 Recovery</h3>
<p>일부러 깨진 Test를 준다.</p>
<p>그리고:</p>
<pre><code class="language-text">같은 시도를 반복하는지

가설을 바꾸는지

다른 Evidence를 찾는지</code></pre>
<p>본다.</p>
<hr>
<h3 id="장시간-작업">장시간 작업</h3>
<p>30분 이상 걸릴 일을 맡긴다.</p>
<p>그리고 결과를 이렇게 기록한다.</p>
<pre><code class="language-text">Task Success

Human Intervention

Retry

Runtime

Review Time

Unnecessary Changes</code></pre>
<p>이게 실제 개발자에게는 훨씬 정확한 Benchmark다.</p>
<hr>
<h1 id="14-모델을-하나로-고정할-이유도-점점-줄어들고-있다">14. 모델을 하나로 고정할 이유도 점점 줄어들고 있다</h1>
<p>불과 몇 달 사이에도 순위가 뒤집힌다.</p>
<p>GPT-5.6 Sol이 공개됐을 때는 Fable 5보다 강한 Coding Agent 성능을 강조했다. </p>
<p>그리고 두 달 뒤 Fable 5.1이 나왔다.</p>
<p>이 속도라면 특정 모델 하나를:</p>
<pre><code class="language-text">우리 팀의 영구 표준</code></pre>
<p>으로 만드는 것은 점점 어려워진다.</p>
<p>오히려 Agent Workflow를 모델과 분리하는 게 낫다.</p>
<pre><code class="language-text">Task
  ↓
Agent
  ↓
Repository
  ↓
Build
  ↓
Test
  ↓
Review</code></pre>
<p>그리고 Agent 자리에:</p>
<pre><code class="language-text">Fable 5.1

GPT-5.6 Sol

다음 세대 모델</code></pre>
<p>을 교체할 수 있도록 한다.</p>
<hr>
<h1 id="15-중요한-규칙은-모델-내부가-아니라-repository에-남긴다">15. 중요한 규칙은 모델 내부가 아니라 Repository에 남긴다</h1>
<p>모델이 바뀌어도 유지돼야 할 것이 있다.</p>
<pre><code class="language-text">Architecture

Coding Rule

Build Command

Test Policy

Security Rule

Review Rule</code></pre>
<p>이런 것들이다.</p>
<p>따라서:</p>
<pre><code class="language-text">AGENTS.md

CLAUDE.md

Skills

Architecture Docs

Tests

CI</code></pre>
<p>같은 Repository 자산이 중요해진다.</p>
<p>좋은 Agent Workflow는 특정 모델의 기억에 의존하지 않는다.</p>
<hr>
<h1 id="16-모델-routing도-더-현실적인-선택이-된다">16. 모델 Routing도 더 현실적인 선택이 된다</h1>
<p>모든 작업에 Fable 5.1이나 Sol Max를 사용할 필요도 없다.</p>
<p>예:</p>
<pre><code class="language-text">단순 코드 조사
→ 빠른 모델

Boilerplate
→ 저렴한 모델

일반 Feature
→ 중간급 모델

복잡한 Debugging
→ Fable 5.1 / Sol

Architecture 변경
→ 최고 reasoning 구성</code></pre>
<p>이렇게 Task별로 나누는 편이 전체 비용은 훨씬 낮아진다.</p>
<hr>
<h1 id="17-특히-xhigh·max를-항상-켜놓는-시대도-끝나갈-수-있다">17. 특히 XHigh·Max를 항상 켜놓는 시대도 끝나갈 수 있다</h1>
<p>강한 모델을 쓰는 것과 모든 Task에서 최대 추론을 사용하는 것은 다르다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">파일 이름 변경

Import 수정

테스트 Fixture 생성</code></pre>
<p>에 최고 Reasoning이 필요하지는 않다.</p>
<p>반대로:</p>
<pre><code class="language-text">Deadlock

Memory Corruption

Architecture Migration

희귀 Production Crash</code></pre>
<p>같은 문제에는 강한 추론이 필요하다.</p>
<p>그래서:</p>
<pre><code class="language-text">Medium
↓
High
↓
XHigh / Max</code></pre>
<p>처럼 필요한 경우에만 올리는 것이 효율적이다.</p>
<p>모델의 평균 성능이 올라갈수록 오히려 이런 <strong>Reasoning Routing</strong>이 더 중요해진다.</p>
<hr>
<h1 id="18-coding-agent의-새로운-병목은-사람의-review다">18. Coding Agent의 새로운 병목은 사람의 Review다</h1>
<p>Agent 성능이 높아질수록 이상한 현상이 생긴다.</p>
<pre><code class="language-text">Agent Throughput
↑↑↑

Human Review Throughput
→</code></pre>
<p>Agent 세 개를 동시에 돌리면 세 개의 PR이 나온다.</p>
<p>하지만 Developer 한 명은 세 개를 동시에 Review할 수 없다.</p>
<p>그래서 이제 중요한 Agent 능력은:</p>
<pre><code class="language-text">많이 수정</code></pre>
<p>가 아니다.</p>
<pre><code class="language-text">Review하기 좋은 변경</code></pre>
<p>이다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">작은 Diff

명확한 변경 이유

실제 실행한 Test

검증하지 못한 부분

Risk 높은 파일</code></pre>
<p>을 짧게 제공하는 Agent가 실무에서는 더 유용하다.</p>
<hr>
<h1 id="19-결국-fable-51에서-봐야-하는-건-attention-efficiency다">19. 결국 Fable 5.1에서 봐야 하는 건 ‘Attention Efficiency’다</h1>
<p>앞으로 Coding Agent 경쟁에서 꽤 중요한 개념이 될 수 있다.</p>
<pre><code class="language-text">Token Efficiency</code></pre>
<p>만이 아니다.</p>
<pre><code class="language-text">Human Attention Efficiency</code></pre>
<p>다.</p>
<p>예를 들어:</p>
<pre><code class="language-text">Agent A

10달러
사람 개입 1회
Review 10분</code></pre>
<pre><code class="language-text">Agent B

3달러
사람 개입 12회
Review 45분</code></pre>
<p>어느 쪽이 실제로 더 싼지는 명확하지 않다.</p>
<p>Senior Developer의 35분이 API 비용 7달러보다 훨씬 비쌀 수도 있다.</p>
<hr>
<h1 id="20-그래서-fable-51의-진짜-경쟁-상대는-sol의-benchmark-점수가-아니다">20. 그래서 Fable 5.1의 진짜 경쟁 상대는 Sol의 Benchmark 점수가 아니다</h1>
<p>더 근본적인 질문은 이것이다.</p>
<pre><code class="language-text">누가 더 높은 점수를 받았나?</code></pre>
<p>보다는:</p>
<pre><code class="language-text">어떤 Agent에게 일을 맡겼을 때

개발자가 가장 적게 개입하고

가장 작은 Review 비용으로

신뢰할 수 있는 변경을 받는가?</code></pre>
<p>이다.</p>
<p>이게 앞으로 실무 Agent 경쟁의 핵심에 더 가깝다.</p>
<hr>
<h1 id="21-gpt-56-sol이-당장-밀려났다고-보기도-어렵다">21. GPT-5.6 Sol이 당장 밀려났다고 보기도 어렵다</h1>
<p>이번 발표만 보고 Sol을 내려놓을 필요도 없다.</p>
<p>OpenAI의 Sol은 여전히:</p>
<pre><code class="language-text">Terminal 작업

Programmatic Tool Calling

긴 Context

Codex

Multi-Agent Ultra</code></pre>
<p>라는 상당히 강한 Agent 환경을 가지고 있다. </p>
<p>특히 Sol은 모델 하나만이 아니라 Codex Harness와 함께 평가해야 한다.</p>
<p>Fable 5.1도 Claude Code와 함께 봐야 한다.</p>
<p>따라서 앞으로 비교는 사실:</p>
<pre><code class="language-text">Fable 5.1
vs
Sol</code></pre>
<p>보다:</p>
<pre><code class="language-text">Claude Code + Fable 5.1

vs

Codex + GPT-5.6 Sol</code></pre>
<p>쪽이 실제 개발자 경험에 더 가깝다.</p>
<hr>
<h1 id="22-이번-발표가-보여준-가장-중요한-변화">22. 이번 발표가 보여준 가장 중요한 변화</h1>
<p>Fable 5.1의 점수가 Sol보다 몇 점 높은지는 몇 달 뒤 다시 바뀔 수도 있다.</p>
<p>그보다 중요한 건 Frontier Model 경쟁의 속도다.</p>
<p>7월:</p>
<pre><code class="language-text">GPT-5.6 Sol 등장

→ Fable 5보다 높은 Coding Agent 지표</code></pre>
<p>9월:</p>
<pre><code class="language-text">Fable 5.1 등장

→ 다시 Claude 쪽 성능 크게 상승</code></pre>
<p>앞으로도 이런 식일 가능성이 높다.</p>
<p>즉 이제 모델 경쟁은 연 단위가 아니다.</p>
<p><strong>몇 주, 몇 달 단위다.</strong></p>
<hr>
<h1 id="23-그래서-개발팀이-준비해야-할-것은-최고-모델-선택이-아니다">23. 그래서 개발팀이 준비해야 할 것은 ‘최고 모델 선택’이 아니다</h1>
<p>지금 최고인 모델을 찾아 영구적으로 고정하는 것보다:</p>
<pre><code class="language-text">모델을 쉽게 교체할 수 있는 Agent Workflow</code></pre>
<p>가 더 중요하다.</p>
<p>예:</p>
<pre><code class="language-text">Task Specification
       ↓
Coding Agent
       ↓
Build
       ↓
Tests
       ↓
Static Checks
       ↓
Runtime Verification
       ↓
Human Review</code></pre>
<p>여기서 Coding Agent만 교체하면 된다.</p>
<p>그러면 Fable이 좋아지면 Fable을 쓰고,</p>
<p>Sol이 다음 업데이트에서 다시 올라오면 Sol을 쓸 수 있다.</p>
<hr>
<h1 id="24-앞으로-좋은-coding-agent를-판단할-때-볼-숫자">24. 앞으로 좋은 Coding Agent를 판단할 때 볼 숫자</h1>
<p>개발팀이라면 다음 정도면 충분하다.</p>
<pre><code class="language-text">작업 성공률

평균 Retry 횟수

사람 개입 횟수

Build/Test 성공률

Review 시간

재작업 비율

불필요한 변경량

성공 작업당 비용</code></pre>
<p>특히:</p>
<pre><code class="language-text">Benchmark Score</code></pre>
<p>보다:</p>
<pre><code class="language-text">Successful Task Rate</code></pre>
<p>를 보는 편이 좋다.</p>
<hr>
<h1 id="25-개인-개발자도-아주-간단하게-비교할-수-있다">25. 개인 개발자도 아주 간단하게 비교할 수 있다</h1>
<p>실제 사용하는 Repository 하나를 정한다.</p>
<p>같은 Task 다섯 개를 준비한다.</p>
<pre><code class="language-text">버그 수정

기능 추가

Refactoring

Code Review

Test 작성</code></pre>
<p>Fable 5.1과 Sol에 각각 똑같이 맡긴다.</p>
<p>그리고 결과를 이렇게 적는다.</p>
<table>
<thead>
<tr>
<th>항목</th>
<th align="right">Fable 5.1</th>
<th align="right">GPT-5.6 Sol</th>
</tr>
</thead>
<tbody><tr>
<td>완료 여부</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>사람 개입</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>Retry</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>Build</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>Test</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>Review 시간</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>불필요한 수정</td>
<td align="right"></td>
<td align="right"></td>
</tr>
<tr>
<td>비용</td>
<td align="right"></td>
<td align="right"></td>
</tr>
</tbody></table>
<p>5개만 해도 자신의 실제 개발 환경에서는 어느 쪽이 맞는지 꽤 잘 보인다.</p>
<p>인터넷 Benchmark보다 훨씬 유용하다.</p>
<hr>
<h1 id="마무리">마무리</h1>
<p>Claude Fable 5.1의 등장은 Coding Agent 경쟁이 얼마나 빠르게 움직이고 있는지를 다시 보여준다.</p>
<p>불과 두 달 전 GPT-5.6 Sol은 Artificial Analysis Coding Agent Index에서 80점을 기록하며 Fable 5를 앞섰고, Terminal-Bench 2.1과 DeepSWE 같은 장시간 Engineering Benchmark에서도 강한 결과를 보여줬다. </p>
<p>그리고 이제 Fable 5.1이 등장했다.</p>
<p>출시 직후 Artificial Analysis 평가에서도 Fable 5.1의 강한 추론 구성은 Sol의 일반적인 reasoning 구성보다 높은 Intelligence Index를 기록하기 시작했다. 다만 서로 reasoning 설정이 다르므로 이 수치를 그대로 모델 전체의 절대 순위로 해석해서는 안 된다. </p>
<p>이번 변화의 핵심은:</p>
<pre><code class="language-text">Claude가 GPT를 이겼다.</code></pre>
<p>가 아니다.</p>
<p>더 중요한 변화는 이것이다.</p>
<pre><code class="language-text">Coding Model 경쟁
        ↓
Coding Agent 경쟁
        ↓
Engineering Agent 경쟁</code></pre>
<p>코드를 생성하는 능력에서 Repository를 이해하고,</p>
<p>Tool을 사용하고,</p>
<p>실패하면 다시 조사하고,</p>
<p>Build와 Test를 거쳐,</p>
<p>사람이 Review할 수 있는 변경을 만들어내는 능력으로 경쟁의 중심이 이동하고 있다.</p>
<p>그래서 앞으로 모델을 평가할 때도 질문을 바꿔야 한다.</p>
<pre><code class="language-text">누가 코드를 더 잘 쓰는가?</code></pre>
<p>보다:</p>
<blockquote>
<p><strong>누가 개발자의 Attention을 가장 적게 사용하면서 신뢰할 수 있는 Software Change를 끝까지 만들어주는가?</strong></p>
</blockquote>
<p>Fable 5.1과 GPT-5.6 Sol의 진짜 승부도 결국 여기서 갈릴 가능성이 크다.</p>
<p>그리고 이 속도라면 지금의 1등 모델이 몇 달 뒤에도 1등일 거라는 보장은 없다.</p>
<p>그래서 개발자에게 가장 중요한 자산은 특정 모델이 아니다.</p>
<pre><code class="language-text">AGENTS.md

Skills

Architecture

Tests

Build

CI

Review Policy</code></pre>
<p>처럼 <strong>어떤 Frontier Model이 들어와도 그대로 사용할 수 있는 Engineering System</strong>이다.</p>
<p>모델은 계속 바뀐다.</p>
<p>좋은 개발 Workflow는 남는다.</p>
<hr>
<h2 id="참고-자료">참고 자료</h2>
<ul>
<li><p><strong>Anthropic — Claude Fable</strong><br>Anthropic은 2026년 9월 1일 Claude Fable 5.1을 발표하고 Coding과 Knowledge Work를 위한 자사의 가장 강력한 모델로 소개했다. </p>
</li>
<li><p><strong>OpenAI — GPT-5.6</strong><br>GPT-5.6 Sol은 Artificial Analysis Coding Agent Index 80점, Terminal-Bench 2.1 88.8퍼센트, DeepSWE v1.1 72.7퍼센트를 기록했으며 OpenAI는 긴 Coding·Tool Workflow를 핵심 역량으로 설명한다. </p>
</li>
<li><p><strong>OpenAI — GPT-5.6 Engineering</strong><br>OpenAI는 GPT-5.6에서 Context 관리, Prompt Caching, Agent Harness, Programmatic Tool Calling 등을 통해 긴 Agent 작업의 효율을 높이는 방향을 설명하고 있다. </p>
</li>
<li><p><strong>Artificial Analysis — Claude Fable 5.1 vs GPT-5.6 Sol</strong><br>출시 직후 비교에서 Fable 5.1의 강한 reasoning 설정이 Sol medium보다 높은 Intelligence Index를 기록하고 있지만 가격과 응답 지연에서는 Sol이 유리한 결과도 나타난다. 서로 reasoning 설정이 다르다는 점을 함께 봐야 한다. </p>
</li>
</ul>
<h3 id="핵심-참고-포인트">핵심 참고 포인트</h3>
<p>Fable 5.1이 나오면서 <strong>GPT-5.6 Sol이 모든 Coding 영역에서 명확히 패배했다고 단정할 단계는 아니다.</strong> 벤치마크 버전, Reasoning Effort, Harness가 서로 다르기 때문이다.</p>
<p>다만 Fable 5.1 출시 직후의 평가와 Anthropic의 제품 방향을 보면 Claude의 Coding·Long-running Agent 성능이 다시 크게 올라온 것은 분명하다. </p>
<p>따라서 이번 발표를 가장 정확하게 해석하면 <strong>“Coding Model의 새로운 절대 1등이 결정됐다”보다는 “Fable 5.1이 Agentic Coding 경쟁을 다시 매우 팽팽하게 만들었고, 이제 모델 비교는 단발 Benchmark보다 실제 Engineering Task 성공률과 사람의 개입 비용을 기준으로 해야 한다”</strong>에 가깝다.</p>
]]></description>
        </item>
    </channel>
</rss>