<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <author>
    <name>어썸블로그</name>
  </author>
  <id>국내의 좋은 블로그 글들을 매일 배달해줍니다.</id>
  <title>개발자 어썸블로그</title>
  <updated>2026-06-15T00:00:45+09:00</updated>
  <entry>
    <author>
      <name>류광</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;p&gt;코드 작성 비용이 극도로 낮아지는 AI 시대에 소프트웨어 공학의 고전들을 다시 생각해 보는 글입니다.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://occamsrazr.net/tt/447</id>
    <link href="https://occamsrazr.net/tt/447"/>
    <summary type="html">코드 작성 비용이 극도로 낮아지는 AI 시대에 소프트웨어 공학의 고전들을 다시 생각해 보는 글입니다.</summary>
    <title>AI 시대에 다시 보는 소프트웨어 공학의 고전들 </title>
    <updated>2026-06-13T15:06:00+09:00</updated>
    <dc:date>2026-06-13T15:06:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>김재호</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;blockquote&gt;
  &lt;p&gt;그쯤 되면 ‘커피한잔’ 이 아니라 ‘커피한잔 홀딩스’ 아니에요?&lt;br&gt;
그냥 여러 사업을 가진 지주회사 같은데?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;맞는 말이라 엄청 웃었습니다.&lt;/p&gt;

&lt;p&gt;저도 회사 이름을 ‘커피한잔’으로 지은 걸 후회한 적이 있습니다.&lt;br&gt;
이렇게 여러 서비스를 하게 될줄은 몰랐지.&lt;br&gt;
그냥 벤자민 스튜디오 같은 걸로 지을걸.&lt;/p&gt;

&lt;p&gt;사실 &lt;a href="https://withcoffee.app"&gt;커피한잔이라는 소개팅 서비스&lt;/a&gt; 하나만 해도 혼자 운영하는 것이 쉬운 일은 아닙니다.&lt;br&gt;
그런데 커피한잔 외 &lt;a href="https://mykoreamap.com"&gt;마이코리아맵&lt;/a&gt;도 운영하고… 이제는 &lt;a href="https://activeholders.com"&gt;액티브홀더스&lt;/a&gt;까지.&lt;br&gt;
그 외 &lt;a href="https://jeho.page/about"&gt;자잘한 서비스들&lt;/a&gt;은 덤이고요.&lt;/p&gt;

&lt;p&gt;AI 가 아니면 이렇게 하지는 못했을 겁니다.&lt;/p&gt;

&lt;p&gt;하지만 아무리 AI가 도와준다 하더라도 혼자 여러 프로젝트를 하는 건 힘듭니다.&lt;br&gt;
프로젝트가 늘어날 때마다 점점 어려워짐을 느끼네요.&lt;br&gt;
하고 싶은 프로젝트가 아직 두 가지 더 있는데, 해낼 수 있을지 모르겠습니다.&lt;/p&gt;

&lt;p&gt;3일 혹은 일주일 정도 한 프로젝트만 집중해서 일하고, 또 다른 프로젝트를 하는 식으로 지내고 있습니다.&lt;br&gt;
여러 프로젝트를 하니깐 재미가 있으면서도… 이렇게 하는 게 맞나 싶은 생각도 드네요.&lt;/p&gt;

&lt;div class="section-divider"&gt;&lt;span class="ornament"&gt;✔️&lt;/span&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;함께 읽으면 좋은 글:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://jeho.page/essay/2025/07/23/context-swiching.html"&gt;컨텍스트 스위칭 - AI 코딩 부작용&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://jeho.page/essay/2026/06/09/coffee-holdings.html</id>
    <link href="https://jeho.page/essay/2026/06/09/coffee-holdings.html"/>
    <summary type="html">그쯤 되면 ‘커피한잔’ 이 아니라 ‘커피한잔 홀딩스’ 아니에요? 그냥 여러 사업을 가진 지주회사 같은데?</summary>
    <title>커피한잔 홀딩스</title>
    <updated>2026-06-09T02:25:00+09:00</updated>
    <dc:date>2026-06-09T02:25:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Pluu</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;div class="youtube"&gt;
    &lt;iframe width="560" height="315" src="https://www.youtube.com/embed/8PxuWdjESfg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;!--more--&gt;

&lt;hr&gt;

&lt;h1 id="compose-first"&gt;Compose First&lt;/h1&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/develop/ui/compose/images/compose-first.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compose는 Android UI 개발의 표준으로 성숙&lt;/li&gt;
  &lt;li&gt;모든 안드로이드 UI를 &lt;code class="language-plaintext highlighter-rouge"&gt;Jetpack Compose&lt;/code&gt;로 구축하는 &lt;code class="language-plaintext highlighter-rouge"&gt;Compose First&lt;/code&gt; 원칙을 발표&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;goo.gle/compose-first&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;이후 모든 API, 라이브러리, Tool, 가이드는 Compose로 제공된다. 기존 &lt;code class="language-plaintext highlighter-rouge"&gt;View 컴포넌트(Fragment, RecyclerView, Material View 컴포넌트 등)는 유지 보수 모드로 전환&lt;/code&gt;되며, 앞으로 새로운 기능 추가 없이 버그 수정만 제공된다고 한다.
    &lt;ul&gt;
      &lt;li&gt;당장 View 컴포넌트를 지원 중단(Deprecated)하거나 제거할 계획은 없음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose로-마이그레이션"&gt;Compose로 마이그레이션&lt;/h2&gt;

&lt;p&gt;XML을 Compose로 변환을 돕는 Skill외에도 Android Studio에 기능을 준비 중이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;프로젝트 정보를 기반으로 AI 에이전트로 UI 변화가 이루어짐&lt;/li&gt;
  &lt;li&gt;레이아웃이 참조하는 스타일, 리소스를 확인한 후 마이그레이션 전후를 비교할 수 있는 스크린샷 데스트를 생성해 줌&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose-111"&gt;Compose 1.11&lt;/h2&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/01.png"&gt;&lt;/p&gt;

&lt;p&gt;Compose 1.10 및 1.11에서 Retain, 테스트 API, SharedTransitionLayout, 새로운 TextField 기능이 추가되었다.&lt;/p&gt;

&lt;h2 id="new-styles-api"&gt;New Styles API&lt;/h2&gt;

&lt;p&gt;컴포넌트의 스타일 특성을 표준화된 세트로 정의해 컴포넌트의 동작과 외관을 분리되었다. 컴포넌트 스타일을 쉽게 커스텀 할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/02.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;상태 지원&lt;/li&gt;
  &lt;li&gt;상태 변경 애니메이션&lt;/li&gt;
  &lt;li&gt;성능 최적화가 적용되어 Recomposition을 최소화&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;향후 Material 컴포넌트에도 Style 지원 계획이다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Styles in Compose : https://developer.android.com/develop/ui/compose/styles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/03.png"&gt;&lt;/p&gt;

&lt;h3 id="hero-benchmarks"&gt;Hero benchmarks&lt;/h3&gt;

&lt;p&gt;최신 Compose 1.11에서는 스크롤 버벅임(Jank), Startup, View와 Compose가 공존하는 하이브리드 UI 성능이 향상되었다.&lt;/p&gt;

&lt;p&gt;실제 앱 성능을 비교하는 새로운 벤치마크 제품을 오픈소스로 출시&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hero benchmarks: http://goo.gle/hero-benchmark&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="성능-최적화-및-디버깅-도구"&gt;성능 최적화 및 디버깅 도구&lt;/h1&gt;

&lt;h2 id="r8-configuration-analyzer"&gt;R8 configuration analyzer&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;새로운 R8 인사이트 도구를 Play console에 순차적으로 출시 예정&lt;/li&gt;
  &lt;li&gt;Android Studio에서도 확인할 수 있는 R8 configuration analyzer를 출시함. 최적화, 난독화, 리소스 축소의 효율성을 점수로 노출&lt;/li&gt;
  &lt;li&gt;AI Agent가 R8과 연동할 수 있는 새로운 Skill도 출시할 계획&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/04.png"&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Use R8 Configuration Analyzer : http://goo.gle/r8-analyzer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="안드로이드-17의-메모리-관리-강화"&gt;안드로이드 17의 메모리 관리 강화&lt;/h1&gt;

&lt;h2 id="메모리-제한memory-limits"&gt;메모리 제한(Memory limits)&lt;/h2&gt;

&lt;p&gt;안드로이드 17은 메모리 누수 등으로 리소스를 과도하게 사용하는 앱에 영향을 주는 메모리 제한(Memory limits)을 도입합니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/05.png"&gt;&lt;/p&gt;

&lt;p&gt;실제로 앱이 메모리 제한에 영향을 받은 경우, 애플리케이션 종료 정보(exitinfo)에 메모리 제한에 대한 문자열이 포함된다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/06.png"&gt;&lt;/p&gt;

&lt;p&gt;ProfilingManager API에 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_anomaly"&gt;TRIGGER_TYPE_ANOMALY&lt;/a&gt;또는 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_oom"&gt;TRIGGER_TYPE_OOM&lt;/a&gt; 타입의 프로파일링 트리거가 있다. Heapdump를 얻어 메모리 문제를 진단하고 해결할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Trigger-based profiling : https://developer.android.com/topic/performance/tracing/profiling-manager/trigger-based-capture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-studio"&gt;Android Studio&lt;/h2&gt;

&lt;p&gt;안드로이드 스튜디오의 프로파일러에 LeakCanary가 통합되어 Gemini AI를 통해 메모리 누수 원인과 수정 제안을 받을 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/studio/preview/features/images/leakcanary-task.png"&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;이미지 출처 : https://developer.android.com/studio/preview/features#leakcanary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-17"&gt;Android 17&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;CustomView가 포함된 알림의 이미지 크기를 제한하여, 특정 크기를 초과하면 이미지를 제거한다.&lt;/li&gt;
  &lt;li&gt;ART에서 Young Generation GC를 더 자주 도입한다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/07.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Target Android 17로 지정 시 Reflection을 이용한 Static final field 수정은 불가능해진다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/08.png"&gt;&lt;/p&gt;

&lt;p&gt;고성능과 전력 효율을 위해 Vulkan이 자체 GPU API로 지원하고 있으며, 기존 OpenGL/WebGPU API는 Vulkan 위에 계층적으로 추가된다. 앱/게임에서 OpenGL을 사용 중이라면 ANGLE이 Vulkan으로 변환해준다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/09.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱이 GPU 성능을 활용할 수 있도록&lt;/li&gt;
  &lt;li&gt;Jetpack WebGPU 종속성을 추가하면 된다&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;AndroidX webgpu : https://developer.android.com/jetpack/androidx/releases/webgpu&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/10.png"&gt;&lt;/p&gt;

&lt;p&gt;새로운 Performance Analyzer는 하나의 툴체인으로 통합하여 디버깅을 획기적으로 간소화한다. 트레이스를 로드 및 렌더링하는 속도가 기존 대비 최대 26배 빨라졌다. 독립적인 실행하거나 Studio Profiler 내에서 실행될 수 있다.&lt;/p&gt;

&lt;h1 id="intelligence"&gt;Intelligence&lt;/h1&gt;

&lt;p&gt;Gemini와 같은 Agnet는 여러 앱에 걸쳐 오케스트레이터(Orchestrator) 역할을 할 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini는 앱 화면을 분석/탐색&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="appfunctions"&gt;AppFunctions&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/11.png"&gt;&lt;/p&gt;

&lt;p&gt;AppFunctions은 Android MCP 통합 구축을 간소화하는 Jetpack 라이브러리의 Android 플랫폼 API이다. 이를 통해 앱은 기기 내 MCP 서버처럼 작동할 수 있으며, Gemini와 같은 Client Agent 및 어시스턴트가 사용할 수 있는 도구 역할을 하는 기능을 제공한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini를 통해서 AppFunctions 구현을 쉽게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="language-kotlin highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AppFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDescribedByKDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;searchEmails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EmailSummary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;코드 출처 : https://developer.android.com/ai/appfunctions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="on-device"&gt;On device&lt;/h3&gt;

&lt;p&gt;Gemini Nano와 같은 On Device 모델을 사용하면, 사용자 데이터를 로컬에 보관하고 인터넷 연결 없이 작동하면 거래당 비용도 발생하지 않는다.&lt;/p&gt;

&lt;p&gt;올해 말 Gemma 4를 탐재한 Gemini Nano 4를 사용할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ML Kit GenAI Prompt API : https://developers.google.com/ml-kit/genai/prompt/android&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/12.png"&gt;&lt;/p&gt;

&lt;p&gt;Gemini Cloud 모델은 고급 기능을 갖추고 있으며, &lt;a href="https://firebase.google.com/docs/ai-logic"&gt;Firebase AI Logic&lt;/a&gt;을 통해 Android 앱에서 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/13.png"&gt;&lt;/p&gt;

&lt;p&gt;Cloud 기반 에이전트를 구축하려는 경우, A2UI 프로토콜을 사용하면 클라이언트에 UI를 표시할 수 있다.&lt;/p&gt;

&lt;p&gt;안드로이드용 A2UI를 표시하는 Jetpack Compose Renderer가 곧 출시 예정&lt;/p&gt;

&lt;h1 id="accessibility"&gt;Accessibility&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Compose에서 제스처를 사용해 앱 콘텐츠 크기를 조절하는 가이드가 새로 배포 (Pinch to zoom)&lt;/li&gt;
  &lt;li&gt;사용자가 생성한 콘텐츠 등에서 설명이 누락된 경우, AI를 활용해 이미지 설명을 자동으로 생성&lt;/li&gt;
  &lt;li&gt;새로운 Accessibility Scanner는 명암비가 낮거나 터치 타겟이 너무 작은 일반적인 문제들을 더욱 잘 잡아낸다&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="개인정보-보호-및-보안"&gt;개인정보 보호 및 보안&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/14.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱에서 네이티브 라이브러리를 동적으로 로드할 때 읽기 전용으로 처리&lt;/li&gt;
  &lt;li&gt;OTP가 포함된 메시지에 접근하는 것을 방지하기 위해 3시간 동안 읽기 접근을 지연&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="credential-manager"&gt;Credential Manager&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/15.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;이메일과 전화번호 인증을 제공하며, 기존 비밀번호 사용자를 위해 패스키(Passkeys)를 자동으로 생성해 주어 보안성을 높인다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="access_local_network"&gt;ACCESS_LOCAL_NETWORK&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/16.png"&gt;&lt;/p&gt;

&lt;p&gt;Android 17을 Target으로하는 앱은 스마트 홈 장치 등 로컬 네트워크 장치를 찾으려면 &lt;code class="language-plaintext highlighter-rouge"&gt;ACCESS_LOCAL_NETWORK&lt;/code&gt; 권한이 runtime으로 요구됩니다.&lt;/p&gt;

&lt;h3 id="privacy-preserving-pickers"&gt;Privacy Preserving Pickers&lt;/h3&gt;

&lt;p&gt;앱이 광범위한 전체 권한을 요청하지 않아도 되도록 Picker를 제공합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Output Switcher : 특정 장치에 연결&lt;/li&gt;
  &lt;li&gt;EyeDropper API : 화면의 특정 색상을 선택&lt;/li&gt;
  &lt;li&gt;Contacts Picker : 연락처 내 특정 필드와 특정 연락처에 접근&lt;/li&gt;
  &lt;li&gt;Photo Picker : 그리드 뷰를 지원&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="os-experiences"&gt;OS Experiences&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/17.png"&gt;&lt;/p&gt;

&lt;p&gt;Live Update Notification&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;건강 및 피트니스, 앱, 타이머, 여행 앱에서 사용할 수 있는 미터법 스타일 템플릿을 추가&lt;/li&gt;
  &lt;li&gt;Sementic color API를 사용하여 실시간으로 상태를 전달할 수 있다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/18.png"&gt;&lt;/p&gt;

&lt;p&gt;올해 말 다양한 이모티콘을 업데이트할 예정이다.&lt;/p&gt;

&lt;h1 id="camera--media"&gt;Camera &amp;amp; Media&lt;/h1&gt;

&lt;h3 id="on-device-이미지비디오-강화"&gt;On device 이미지/비디오 강화&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/19.png"&gt;&lt;/p&gt;

&lt;p&gt;기기 내부에서 실행되는 AI를 사용해 오프라인 상태에서도 서버 비용 없이 사진의 화질 개선, 초점 보정(Deblur), 노이즈 제거(Denoise), 업스케일링 등을 처리할 수 있는 라이브러리가 제공됩니다.&lt;/p&gt;

&lt;h3 id="백그라운드-오디오-제한"&gt;백그라운드 오디오 제한&lt;/h3&gt;

&lt;p&gt;사용자가 의도하지 않은 배경 음악이나 소음이 갑자기 재생되는 것을 막기 위해 Android 17은 백그라운드 앱의 오디오 API 사용을 엄격히 제한합니다. (정확한 알람 제외)&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/20.png"&gt;&lt;/p&gt;

&lt;p&gt;새로운 이미지 포맷 지원&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RAW14&lt;/li&gt;
  &lt;li&gt;H.266 VVC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;스트리밍 개선&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;HE-AAC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;카메라 강화&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;제조사별 확장 기능 등&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;차세대 Eclipsa 비디오 포맷이 공식 출시&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;고품질 HDR 재생을 지원&lt;/li&gt;
  &lt;li&gt;ExoPlayer는 추가 설정 없이 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="adaptive"&gt;Adaptive&lt;/h1&gt;

&lt;h3 id="ignored-api"&gt;Ignored API&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/21.png"&gt;&lt;/p&gt;

&lt;p&gt;안드로이드 17부터는 기기의 전체 화면 비율이나 가로/세로 방향을 앱이 임의로 제한(opt-out)할 수 없습니다.&lt;/p&gt;

&lt;p&gt;무시되는 옵션&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;screenOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿resizableActivity&lt;/li&gt;
  &lt;li&gt;﻿﻿minAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿maxAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿setRequestedOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿getRequestedOrientation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="mediaquery-flexbox-grid"&gt;MediaQuery, FlexBox, Grid&lt;/h3&gt;

&lt;p&gt;Compose 1.11에서는 기기 상태를 쿼리하는 MediaQuery와 유연한 요소 배치를 위한 FlexBox, Grid 레이아웃 API가 실험적으로 제공&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MediaQuery : https://developer.android.com/develop/adaptive-apps/guides/mediaquery&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;FlexBox : https://developer.android.com/develop/ui/compose/layouts/adaptive/flexbox&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Grid : https://developer.android.com/develop/ui/compose/layouts/adaptive/grid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/22.png"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/23.png"&gt;&lt;/p&gt;

&lt;h3 id="continue-on"&gt;Continue On&lt;/h3&gt;

&lt;p&gt;한 기기에서 시작한 작업을 다른 기기로 전환하여 작업을 계속할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Continue On : goo.gle/continue-on&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="bubbles"&gt;Bubbles&lt;/h3&gt;

&lt;p&gt;모든 앱에서 화면을 띄울 수 있는 Bubbles 기능이 확대되었으며, 대화면 전용 Bubble bar가 도입되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bubbles : https://developer.android.com/develop/ui/compose/layouts/adaptive/support-bubbles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="widget"&gt;Widget&lt;/h3&gt;

&lt;p&gt;Jetpack Glance를 활용해 위젯을 여러 생태계로 손쉽게 확장할 수 있습니다. 특히 올해는 자동차에 위젯을 제공할 준비를 하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/24.png"&gt;&lt;/p&gt;

&lt;p&gt;Snap scroll API를 사용하여 위젯 애니메이션을 구현할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;SnapScrollMatchHeight : https://developer.android.com/reference/kotlin/androidx/glance/appwidget/lazy/VerticalScrollMode.SnapScrollMatchHeight&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="wear-os-7"&gt;Wear OS 7&lt;/h1&gt;

&lt;p&gt;시스템 플랫폼 개선으로 배터리 수명이 최대 10% 길어집니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/25.png"&gt;&lt;/p&gt;

&lt;p&gt;사용자가 스마트폰에서 미디어를 재생하면 워치에 자동으로 제어 컨트롤이 나타나며, 휴대폰의 실시간 알림이 시계로 브리지 연동됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/26.png"&gt;&lt;/p&gt;

&lt;p&gt;스마트 워치는 연결된 스마트폰의 미디어 출력을 제어하여 스피커에서 헤드폰으로 전환 등을 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/27.png"&gt;&lt;/p&gt;

&lt;p&gt;시계 제조 업체는 스마트폰에서 시계로 실시간 업데이트 알림을 전송하는 기능을 제공할 수 있습니다.&lt;/p&gt;

&lt;h3 id="wear-os-appfunctions"&gt;Wear OS AppFunctions&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Wear OS 6.1 이상&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;제미나이(Gemini)와 같은 AI 에이전트와 연동되는 AppFunctions를 생성할 수 있습니다. 이를 활용하면 에이전트가 사용자를 대신하여 앱 내의 특정 작업 흐름(in-app flows)을 직접 호출하고 실행할 수 있습니다.&lt;/p&gt;

&lt;h3 id="추가-업데이트"&gt;추가 업데이트&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;올해 말 Wear Workout Tracker 앱을 출시 예정&lt;/li&gt;
  &lt;li&gt;Wear OS 1.6용 Compose는 Navigation 3를 지원하며, LocalAmbientModeManager를 통해 기기가 절전모드일 때 컨텐츠를 관리할 수 있다&lt;/li&gt;
  &lt;li&gt;Wear OS 7 Canary Emulator가 Android Studio에서 제공&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="andorid-xr"&gt;Andorid XR&lt;/h1&gt;

&lt;p&gt;몰입형 가상현실과 증강현실(AR) 안경을 지원하는 Android XR SDK Developer Preview 4가 출시됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Updates to the Android XR SDK: Introducing Developer Preview 4 : https://developer.android.com/blog/posts/updates-to-the-android-xr-sdk-introducing-developer-preview-4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jetpack XR SDK 라이브러리가 베타 버전으로 출시될 예정&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/28.png"&gt;&lt;/p&gt;

&lt;p&gt;개선 사항&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;대용량 3D 모델을 앱에 포함하는 대신 실시간으로 지오메트리를 생성해 앱 크기를 줄임&lt;/li&gt;
  &lt;li&gt;XR Glasses에 Geospatial API를 도입해 공간 길 찾기를 돕는다&lt;/li&gt;
  &lt;li&gt;GODOT 및 언리얼 엔진에 대한 지원을 확장&lt;/li&gt;
  &lt;li&gt;시각적 및 상호 작용 제약 조건에 맞춰 디자인하는데 사용할 수 있는 컴포넌트 Jetpack Compose Glimmer 개선
    &lt;ul&gt;
      &lt;li&gt;Jetpack Compose Glimmer는 디스플레이 글라스에 최적화된 증강 Android XR 환경을 빌드하기 위한 Compose UI 툴킷&lt;/li&gt;
      &lt;li&gt;Glimmer를 쉽게 추가할 수 있는 Skill도 제공&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Build UI for display glasses with Jetpack Compose Glimmer : https://developer.android.com/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="cars"&gt;Cars&lt;/h1&gt;

&lt;p&gt;Android Auto와 구글이 내장된 차량용 앱간의 호환성을 높여 차량용 앱 개발을 간소화했다.&lt;/p&gt;

&lt;p&gt;단일 코드로 양쪽 플랫폼에 Media Apps Templates를 모두 사용할 수 있으며, 두 플랫폼 모두에서 콘텐츠가 포함된 지도 템플릿과 함께 Google Maps SDK를 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;Car App Library 1.9에서는 두 플랫폼에서 사용할 수 있는 새로운 컴포넌트와 레이아웃을 추가한다.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>http://pluu.github.io/blog/android/io26/2026/06/08/io26-What's_new_in_Android/</id>
    <link href="http://pluu.github.io/blog/android/io26/2026/06/08/io26-What's_new_in_Android/"/>
    <summary type="html">&lt;div class="youtube"&gt;
    &lt;iframe width="560" height="315" src="https://www.youtube.com/embed/8PxuWdjESfg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;!--more--&gt;

&lt;hr /&gt;

&lt;h1 id="compose-first"&gt;Compose First&lt;/h1&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/develop/ui/compose/images/compose-first.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compose는 Android UI 개발의 표준으로 성숙&lt;/li&gt;
  &lt;li&gt;모든 안드로이드 UI를 &lt;code class="language-plaintext highlighter-rouge"&gt;Jetpack Compose&lt;/code&gt;로 구축하는 &lt;code class="language-plaintext highlighter-rouge"&gt;Compose First&lt;/code&gt; 원칙을 발표&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;goo.gle/compose-first&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;이후 모든 API, 라이브러리, Tool, 가이드는 Compose로 제공된다. 기존 &lt;code class="language-plaintext highlighter-rouge"&gt;View 컴포넌트(Fragment, RecyclerView, Material View 컴포넌트 등)는 유지 보수 모드로 전환&lt;/code&gt;되며, 앞으로 새로운 기능 추가 없이 버그 수정만 제공된다고 한다.
    &lt;ul&gt;
      &lt;li&gt;당장 View 컴포넌트를 지원 중단(Deprecated)하거나 제거할 계획은 없음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose로-마이그레이션"&gt;Compose로 마이그레이션&lt;/h2&gt;

&lt;p&gt;XML을 Compose로 변환을 돕는 Skill외에도 Android Studio에 기능을 준비 중이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;프로젝트 정보를 기반으로 AI 에이전트로 UI 변화가 이루어짐&lt;/li&gt;
  &lt;li&gt;레이아웃이 참조하는 스타일, 리소스를 확인한 후 마이그레이션 전후를 비교할 수 있는 스크린샷 데스트를 생성해 줌&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose-111"&gt;Compose 1.11&lt;/h2&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/01.png" /&gt;&lt;/p&gt;

&lt;p&gt;Compose 1.10 및 1.11에서 Retain, 테스트 API, SharedTransitionLayout, 새로운 TextField 기능이 추가되었다.&lt;/p&gt;

&lt;h2 id="new-styles-api"&gt;New Styles API&lt;/h2&gt;

&lt;p&gt;컴포넌트의 스타일 특성을 표준화된 세트로 정의해 컴포넌트의 동작과 외관을 분리되었다. 컴포넌트 스타일을 쉽게 커스텀 할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/02.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;상태 지원&lt;/li&gt;
  &lt;li&gt;상태 변경 애니메이션&lt;/li&gt;
  &lt;li&gt;성능 최적화가 적용되어 Recomposition을 최소화&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;향후 Material 컴포넌트에도 Style 지원 계획이다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Styles in Compose : https://developer.android.com/develop/ui/compose/styles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/03.png" /&gt;&lt;/p&gt;

&lt;h3 id="hero-benchmarks"&gt;Hero benchmarks&lt;/h3&gt;

&lt;p&gt;최신 Compose 1.11에서는 스크롤 버벅임(Jank), Startup, View와 Compose가 공존하는 하이브리드 UI 성능이 향상되었다.&lt;/p&gt;

&lt;p&gt;실제 앱 성능을 비교하는 새로운 벤치마크 제품을 오픈소스로 출시&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hero benchmarks: http://goo.gle/hero-benchmark&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="성능-최적화-및-디버깅-도구"&gt;성능 최적화 및 디버깅 도구&lt;/h1&gt;

&lt;h2 id="r8-configuration-analyzer"&gt;R8 configuration analyzer&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;새로운 R8 인사이트 도구를 Play console에 순차적으로 출시 예정&lt;/li&gt;
  &lt;li&gt;Android Studio에서도 확인할 수 있는 R8 configuration analyzer를 출시함. 최적화, 난독화, 리소스 축소의 효율성을 점수로 노출&lt;/li&gt;
  &lt;li&gt;AI Agent가 R8과 연동할 수 있는 새로운 Skill도 출시할 계획&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/04.png" /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Use R8 Configuration Analyzer : http://goo.gle/r8-analyzer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="안드로이드-17의-메모리-관리-강화"&gt;안드로이드 17의 메모리 관리 강화&lt;/h1&gt;

&lt;h2 id="메모리-제한memory-limits"&gt;메모리 제한(Memory limits)&lt;/h2&gt;

&lt;p&gt;안드로이드 17은 메모리 누수 등으로 리소스를 과도하게 사용하는 앱에 영향을 주는 메모리 제한(Memory limits)을 도입합니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/05.png" /&gt;&lt;/p&gt;

&lt;p&gt;실제로 앱이 메모리 제한에 영향을 받은 경우, 애플리케이션 종료 정보(exitinfo)에 메모리 제한에 대한 문자열이 포함된다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/06.png" /&gt;&lt;/p&gt;

&lt;p&gt;ProfilingManager API에 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_anomaly"&gt;TRIGGER_TYPE_ANOMALY&lt;/a&gt;또는 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_oom"&gt;TRIGGER_TYPE_OOM&lt;/a&gt; 타입의 프로파일링 트리거가 있다. Heapdump를 얻어 메모리 문제를 진단하고 해결할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Trigger-based profiling : https://developer.android.com/topic/performance/tracing/profiling-manager/trigger-based-capture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-studio"&gt;Android Studio&lt;/h2&gt;

&lt;p&gt;안드로이드 스튜디오의 프로파일러에 LeakCanary가 통합되어 Gemini AI를 통해 메모리 누수 원인과 수정 제안을 받을 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/studio/preview/features/images/leakcanary-task.png" /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;이미지 출처 : https://developer.android.com/studio/preview/features#leakcanary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-17"&gt;Android 17&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;CustomView가 포함된 알림의 이미지 크기를 제한하여, 특정 크기를 초과하면 이미지를 제거한다.&lt;/li&gt;
  &lt;li&gt;ART에서 Young Generation GC를 더 자주 도입한다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/07.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Target Android 17로 지정 시 Reflection을 이용한 Static final field 수정은 불가능해진다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/08.png" /&gt;&lt;/p&gt;

&lt;p&gt;고성능과 전력 효율을 위해 Vulkan이 자체 GPU API로 지원하고 있으며, 기존 OpenGL/WebGPU API는 Vulkan 위에 계층적으로 추가된다. 앱/게임에서 OpenGL을 사용 중이라면 ANGLE이 Vulkan으로 변환해준다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/09.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱이 GPU 성능을 활용할 수 있도록&lt;/li&gt;
  &lt;li&gt;Jetpack WebGPU 종속성을 추가하면 된다&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;AndroidX webgpu : https://developer.android.com/jetpack/androidx/releases/webgpu&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/10.png" /&gt;&lt;/p&gt;

&lt;p&gt;새로운 Performance Analyzer는 하나의 툴체인으로 통합하여 디버깅을 획기적으로 간소화한다. 트레이스를 로드 및 렌더링하는 속도가 기존 대비 최대 26배 빨라졌다. 독립적인 실행하거나 Studio Profiler 내에서 실행될 수 있다.&lt;/p&gt;

&lt;h1 id="intelligence"&gt;Intelligence&lt;/h1&gt;

&lt;p&gt;Gemini와 같은 Agnet는 여러 앱에 걸쳐 오케스트레이터(Orchestrator) 역할을 할 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini는 앱 화면을 분석/탐색&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="appfunctions"&gt;AppFunctions&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/11.png" /&gt;&lt;/p&gt;

&lt;p&gt;AppFunctions은 Android MCP 통합 구축을 간소화하는 Jetpack 라이브러리의 Android 플랫폼 API이다. 이를 통해 앱은 기기 내 MCP 서버처럼 작동할 수 있으며, Gemini와 같은 Client Agent 및 어시스턴트가 사용할 수 있는 도구 역할을 하는 기능을 제공한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini를 통해서 AppFunctions 구현을 쉽게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="language-kotlin highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AppFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDescribedByKDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;searchEmails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EmailSummary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;코드 출처 : https://developer.android.com/ai/appfunctions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="on-device"&gt;On device&lt;/h3&gt;

&lt;p&gt;Gemini Nano와 같은 On Device 모델을 사용하면, 사용자 데이터를 로컬에 보관하고 인터넷 연결 없이 작동하면 거래당 비용도 발생하지 않는다.&lt;/p&gt;

&lt;p&gt;올해 말 Gemma 4를 탐재한 Gemini Nano 4를 사용할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ML Kit GenAI Prompt API : https://developers.google.com/ml-kit/genai/prompt/android&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/12.png" /&gt;&lt;/p&gt;

&lt;p&gt;Gemini Cloud 모델은 고급 기능을 갖추고 있으며, &lt;a href="https://firebase.google.com/docs/ai-logic"&gt;Firebase AI Logic&lt;/a&gt;을 통해 Android 앱에서 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/13.png" /&gt;&lt;/p&gt;

&lt;p&gt;Cloud 기반 에이전트를 구축하려는 경우, A2UI 프로토콜을 사용하면 클라이언트에 UI를 표시할 수 있다.&lt;/p&gt;

&lt;p&gt;안드로이드용 A2UI를 표시하는 Jetpack Compose Renderer가 곧 출시 예정&lt;/p&gt;

&lt;h1 id="accessibility"&gt;Accessibility&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Compose에서 제스처를 사용해 앱 콘텐츠 크기를 조절하는 가이드가 새로 배포 (Pinch to zoom)&lt;/li&gt;
  &lt;li&gt;사용자가 생성한 콘텐츠 등에서 설명이 누락된 경우, AI를 활용해 이미지 설명을 자동으로 생성&lt;/li&gt;
  &lt;li&gt;새로운 Accessibility Scanner는 명암비가 낮거나 터치 타겟이 너무 작은 일반적인 문제들을 더욱 잘 잡아낸다&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="개인정보-보호-및-보안"&gt;개인정보 보호 및 보안&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/14.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱에서 네이티브 라이브러리를 동적으로 로드할 때 읽기 전용으로 처리&lt;/li&gt;
  &lt;li&gt;OTP가 포함된 메시지에 접근하는 것을 방지하기 위해 3시간 동안 읽기 접근을 지연&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="credential-manager"&gt;Credential Manager&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/15.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;이메일과 전화번호 인증을 제공하며, 기존 비밀번호 사용자를 위해 패스키(Passkeys)를 자동으로 생성해 주어 보안성을 높인다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="access_local_network"&gt;ACCESS_LOCAL_NETWORK&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/16.png" /&gt;&lt;/p&gt;

&lt;p&gt;Android 17을 Target으로하는 앱은 스마트 홈 장치 등 로컬 네트워크 장치를 찾으려면 &lt;code class="language-plaintext highlighter-rouge"&gt;ACCESS_LOCAL_NETWORK&lt;/code&gt; 권한이 runtime으로 요구됩니다.&lt;/p&gt;

&lt;h3 id="privacy-preserving-pickers"&gt;Privacy Preserving Pickers&lt;/h3&gt;

&lt;p&gt;앱이 광범위한 전체 권한을 요청하지 않아도 되도록 Picker를 제공합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Output Switcher : 특정 장치에 연결&lt;/li&gt;
  &lt;li&gt;EyeDropper API : 화면의 특정 색상을 선택&lt;/li&gt;
  &lt;li&gt;Contacts Picker : 연락처 내 특정 필드와 특정 연락처에 접근&lt;/li&gt;
  &lt;li&gt;Photo Picker : 그리드 뷰를 지원&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="os-experiences"&gt;OS Experiences&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/17.png" /&gt;&lt;/p&gt;

&lt;p&gt;Live Update Notification&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;건강 및 피트니스, 앱, 타이머, 여행 앱에서 사용할 수 있는 미터법 스타일 템플릿을 추가&lt;/li&gt;
  &lt;li&gt;Sementic color API를 사용하여 실시간으로 상태를 전달할 수 있다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/18.png" /&gt;&lt;/p&gt;

&lt;p&gt;올해 말 다양한 이모티콘을 업데이트할 예정이다.&lt;/p&gt;

&lt;h1 id="camera--media"&gt;Camera &amp;amp; Media&lt;/h1&gt;

&lt;h3 id="on-device-이미지비디오-강화"&gt;On device 이미지/비디오 강화&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/19.png" /&gt;&lt;/p&gt;

&lt;p&gt;기기 내부에서 실행되는 AI를 사용해 오프라인 상태에서도 서버 비용 없이 사진의 화질 개선, 초점 보정(Deblur), 노이즈 제거(Denoise), 업스케일링 등을 처리할 수 있는 라이브러리가 제공됩니다.&lt;/p&gt;

&lt;h3 id="백그라운드-오디오-제한"&gt;백그라운드 오디오 제한&lt;/h3&gt;

&lt;p&gt;사용자가 의도하지 않은 배경 음악이나 소음이 갑자기 재생되는 것을 막기 위해 Android 17은 백그라운드 앱의 오디오 API 사용을 엄격히 제한합니다. (정확한 알람 제외)&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/20.png" /&gt;&lt;/p&gt;

&lt;p&gt;새로운 이미지 포맷 지원&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RAW14&lt;/li&gt;
  &lt;li&gt;H.266 VVC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;스트리밍 개선&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;HE-AAC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;카메라 강화&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;제조사별 확장 기능 등&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;차세대 Eclipsa 비디오 포맷이 공식 출시&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;고품질 HDR 재생을 지원&lt;/li&gt;
  &lt;li&gt;ExoPlayer는 추가 설정 없이 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="adaptive"&gt;Adaptive&lt;/h1&gt;

&lt;h3 id="ignored-api"&gt;Ignored API&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/21.png" /&gt;&lt;/p&gt;

&lt;p&gt;안드로이드 17부터는 기기의 전체 화면 비율이나 가로/세로 방향을 앱이 임의로 제한(opt-out)할 수 없습니다.&lt;/p&gt;

&lt;p&gt;무시되는 옵션&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;screenOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿resizableActivity&lt;/li&gt;
  &lt;li&gt;﻿﻿minAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿maxAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿setRequestedOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿getRequestedOrientation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="mediaquery-flexbox-grid"&gt;MediaQuery, FlexBox, Grid&lt;/h3&gt;

&lt;p&gt;Compose 1.11에서는 기기 상태를 쿼리하는 MediaQuery와 유연한 요소 배치를 위한 FlexBox, Grid 레이아웃 API가 실험적으로 제공&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MediaQuery : https://developer.android.com/develop/adaptive-apps/guides/mediaquery&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;FlexBox : https://developer.android.com/develop/ui/compose/layouts/adaptive/flexbox&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Grid : https://developer.android.com/develop/ui/compose/layouts/adaptive/grid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/22.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/23.png" /&gt;&lt;/p&gt;

&lt;h3 id="continue-on"&gt;Continue On&lt;/h3&gt;

&lt;p&gt;한 기기에서 시작한 작업을 다른 기기로 전환하여 작업을 계속할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Continue On : goo.gle/continue-on&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="bubbles"&gt;Bubbles&lt;/h3&gt;

&lt;p&gt;모든 앱에서 화면을 띄울 수 있는 Bubbles 기능이 확대되었으며, 대화면 전용 Bubble bar가 도입되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bubbles : https://developer.android.com/develop/ui/compose/layouts/adaptive/support-bubbles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="widget"&gt;Widget&lt;/h3&gt;

&lt;p&gt;Jetpack Glance를 활용해 위젯을 여러 생태계로 손쉽게 확장할 수 있습니다. 특히 올해는 자동차에 위젯을 제공할 준비를 하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/24.png" /&gt;&lt;/p&gt;

&lt;p&gt;Snap scroll API를 사용하여 위젯 애니메이션을 구현할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;SnapScrollMatchHeight : https://developer.android.com/reference/kotlin/androidx/glance/appwidget/lazy/VerticalScrollMode.SnapScrollMatchHeight&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="wear-os-7"&gt;Wear OS 7&lt;/h1&gt;

&lt;p&gt;시스템 플랫폼 개선으로 배터리 수명이 최대 10% 길어집니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/25.png" /&gt;&lt;/p&gt;

&lt;p&gt;사용자가 스마트폰에서 미디어를 재생하면 워치에 자동으로 제어 컨트롤이 나타나며, 휴대폰의 실시간 알림이 시계로 브리지 연동됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/26.png" /&gt;&lt;/p&gt;

&lt;p&gt;스마트 워치는 연결된 스마트폰의 미디어 출력을 제어하여 스피커에서 헤드폰으로 전환 등을 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/27.png" /&gt;&lt;/p&gt;

&lt;p&gt;시계 제조 업체는 스마트폰에서 시계로 실시간 업데이트 알림을 전송하는 기능을 제공할 수 있습니다.&lt;/p&gt;

&lt;h3 id="wear-os-appfunctions"&gt;Wear OS AppFunctions&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Wear OS 6.1 이상&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;제미나이(Gemini)와 같은 AI 에이전트와 연동되는 AppFunctions를 생성할 수 있습니다. 이를 활용하면 에이전트가 사용자를 대신하여 앱 내의 특정 작업 흐름(in-app flows)을 직접 호출하고 실행할 수 있습니다.&lt;/p&gt;

&lt;h3 id="추가-업데이트"&gt;추가 업데이트&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;올해 말 Wear Workout Tracker 앱을 출시 예정&lt;/li&gt;
  &lt;li&gt;Wear OS 1.6용 Compose는 Navigation 3를 지원하며, LocalAmbientModeManager를 통해 기기가 절전모드일 때 컨텐츠를 관리할 수 있다&lt;/li&gt;
  &lt;li&gt;Wear OS 7 Canary Emulator가 Android Studio에서 제공&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="andorid-xr"&gt;Andorid XR&lt;/h1&gt;

&lt;p&gt;몰입형 가상현실과 증강현실(AR) 안경을 지원하는 Android XR SDK Developer Preview 4가 출시됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Updates to the Android XR SDK: Introducing Developer Preview 4 : https://developer.android.com/blog/posts/updates-to-the-android-xr-sdk-introducing-developer-preview-4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jetpack XR SDK 라이브러리가 베타 버전으로 출시될 예정&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/28.png" /&gt;&lt;/p&gt;

&lt;p&gt;개선 사항&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;대용량 3D 모델을 앱에 포함하는 대신 실시간으로 지오메트리를 생성해 앱 크기를 줄임&lt;/li&gt;
  &lt;li&gt;XR Glasses에 Geospatial API를 도입해 공간 길 찾기를 돕는다&lt;/li&gt;
  &lt;li&gt;GODOT 및 언리얼 엔진에 대한 지원을 확장&lt;/li&gt;
  &lt;li&gt;시각적 및 상호 작용 제약 조건에 맞춰 디자인하는데 사용할 수 있는 컴포넌트 Jetpack Compose Glimmer 개선
    &lt;ul&gt;
      &lt;li&gt;Jetpack Compose Glimmer는 디스플레이 글라스에 최적화된 증강 Android XR 환경을 빌드하기 위한 Compose UI 툴킷&lt;/li&gt;
      &lt;li&gt;Glimmer를 쉽게 추가할 수 있는 Skill도 제공&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Build UI for display glasses with Jetpack Compose Glimmer : https://developer.android.com/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="cars"&gt;Cars&lt;/h1&gt;

&lt;p&gt;Android Auto와 구글이 내장된 차량용 앱간의 호환성을 높여 차량용 앱 개발을 간소화했다.&lt;/p&gt;

&lt;p&gt;단일 코드로 양쪽 플랫폼에 Media Apps Templates를 모두 사용할 수 있으며, 두 플랫폼 모두에서 콘텐츠가 포함된 지도 템플릿과 함께 Google Maps SDK를 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;Car App Library 1.9에서는 두 플랫폼에서 사용할 수 있는 새로운 컴포넌트와 레이아웃을 추가한다.&lt;/p&gt;
</summary>
    <title>Blog: [요약] What's new in Android (Google I/O '26)</title>
    <updated>2026-06-08T23:00:00+09:00</updated>
    <dc:date>2026-06-08T23:00:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Outsider</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;p&gt;최근 몇 년 사이 보안에 관심이 많아졌다. 완벽한 보안이란 없지만, 여러 환경 중 의외로 보안이 취약한 곳은 로컬 환경이다. 아무래도 개인 장비라 외부 접근이 기본적으로 차단되는 데다가 자주 사용해서 편의성도 중요하다 보니 로컬에는 많은 시크릿이 평문으로 저장되어 있다.&lt;/p&gt;
&lt;p&gt;로컬에서 관리되는 시크릿은 다양하지만, 그중 정말 중요하면서도 평문으로 관리되는 것 중 하나가 SSH 키다. 비밀키는 보안의 핵심이지만 현실에서는 평문으로 관리되고 있어서 개인 장비를 분실하거나 해킹당하면 쉽게 유출될 수 있다.&lt;/p&gt;
&lt;h2&gt;1Password SSH 에이전트 설정&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;는 비밀번호를 관리해 주는 게 핵심 기능이지만 몇 년 전부터 개발자를 위한 기능을 강화하고 있다. &lt;a href="https://1password.com/blog/1password-ssh-agent"&gt;SSH 에이전트 기능은 나온 지 수년이 되었지만&lt;/a&gt; 생각만 하다가 이제야 제대로 설정했다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/07de70fafc74_3x.png" alt="1Password의 개발자 화면에서 SSH 에이전트, 개발자 환경, CLI, Watchtower 기능 카드가 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;의 개발자 메뉴에 들어가면 SSH 에이전트라는 메뉴가 보인다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/fe98ef5e5727_3x.png" alt="1Password 설정의 개발자 탭이 열려 있으며, 개발자 경험 표시와 활동 기록 옵션이 체크되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;혹시 개발자 메뉴가 안 보인다면 설정에서 개발자 기능을 켜야 한다.&lt;/p&gt;
&lt;p&gt;SSH 에이전트 설정을 누르면 다음과 같은 안내가 나온다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/f83cf547aa32_3x.png" alt="1Password가 디스크에 SSH 키 이름 저장을 허용할지 묻는 알림 창. ‘키 지문만 사용’과 ‘키 이름 사용’ 버튼이 보인다."&gt;&lt;/p&gt;
&lt;p&gt;설명을 완전히 이해는 못했지만 키 지문으로는 키를 구분하기 어려우므로 키 이름을 사용하기로 했다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/ad860e633fee_3x.jpg" alt="1Password의 SSH 에이전트 설정 창에 ~/.ssh/config에 추가할 IdentityAgent 스니펫과 자동 편집 버튼이 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;이는 &lt;code&gt;~/.ssh/config&lt;/code&gt; 설정인데, 해본 사람은 알겠지만 모든 SSH 호스트에 1Password SSH 에이전트를 사용하도록 하는 설정이다. 그래서 다른 호스트에서는 기존의 키 파일을 써야 한다면 호스트를 지정한 설정을 추가하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/5a75ec5ee546_3x.png" alt="1Password SSH 에이전트 설정 화면으로, 실행 중 상태와 사용 가능한 SSH 키가 없다는 안내가 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;SSH config에 설정을 넣으면 에이전트가 실행 중으로 바뀐다.&lt;/p&gt;
&lt;h2&gt;SSH 접속에 1Password SSH 에이전트 사용하기&lt;/h2&gt;
&lt;p&gt;먼저 SSH에 사용할 키를 등록해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/d8ff05963f8e_3x.png" alt="비밀번호 관리 앱의 새 항목 창에서 SSH 키 항목을 만들고 있다. 개인 키 파일 드래그 영역과 추가 옵션, 저장 버튼이 보인다."&gt;&lt;/p&gt;
&lt;p&gt;인식할 수 있는 이름을 주고 기존의 키를 드래그하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/0a4f5fa815bf_3x.png" alt="개인 키 파일을 드래그해 가져오는 영역과 개인 키 추가 버튼이 보이며, 키 유형은 Ed25519로 선택되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;에서 바로 키를 생성할 수도 있는데 &lt;a href="https://en.wikipedia.org/wiki/Ed25519"&gt;Ed25519&lt;/a&gt;와 &lt;a href="https://en.wikipedia.org/wiki/RSA_cryptosystem"&gt;RSA&lt;/a&gt;로 만들 수 있다. 특별한 이유가 없다면 지금은 &lt;a href="https://en.wikipedia.org/wiki/Ed25519"&gt;Ed25519&lt;/a&gt;로 만들면 된다. 키 크기도 훨씬 작고 검증 속도도 훨씬 빠르다. 나 같은 경우는 기본으로 쓰던 키가 너무 오래되어서 그런지 &lt;a href="https://www.1password.dev/ssh/manage-keys#key-import-errors"&gt;지원하지 않는 형식&lt;/a&gt;이라고 나와서 이 기회에 새로 키를 생성했다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/b188631ec9fb_3x.png" alt="Git 커밋에 SSH 서명을 설정하라는 안내와 함께 Test key의 공개 키, 지문, 개인 키 상태, 키 유형이 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;생성된 키의 공개키와 지문도 바로 볼 수 있다. GitHub를 사용하는 경우 &lt;strong&gt;GitHub 계정의 &lt;a href="https://github.com/settings/keys"&gt;SSH and GPG keys 설정&lt;/a&gt;에서 공개 키를 SSH Authentication Key로 등록하면 된다&lt;/strong&gt;. &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;에서 Git 커밋 서명에도 사용하라고 안내하는데, 나 같은 경우는 GPG로 서명하고 있어서 따로 설정하진 않았다. 간단히 설명하면 Authentication Key는 &lt;code&gt;git clone&lt;/code&gt;이나 &lt;code&gt;git pull&lt;/code&gt; 등 Git 저장소를 SSH로 접속할 때 쓰는 키이고 Signing Key는 커밋할 때 서명을 추가해서 해당 커밋을 본인이 했음을 증명할 때 사용하는 키다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/251d1184a1ba_3x.jpg" alt="터미널에서 GitHub 저장소를 클론하는 중 Ghostty가 1Password에 SSH 키 접근 권한을 요청하는 인증 창이 떠 있다."&gt;&lt;/p&gt;
&lt;p&gt;이제 터미널에서 Git 저장소에 접근하면 1Password 화면이 나오고, 여기서 인증하면 정상적으로 클론할 수 있다. 이렇게 구성하면 로컬에 비밀키를 평문으로 보관하지 않고서 안전하게 비밀키를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/64178dd211d3_3x.png" alt="1Password 설정의 개발자 메뉴가 열려 있고, 고급 옵션에서 승인 요청, 키 승인 기억, SSH 설정 항목을 조정할 수 있다."&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt; 설정에서 키 승인에 대한 유효기간을 얼마나 유지할지 등을 설정할 수 있다.&lt;/p&gt;
&lt;h2&gt;북마크 관리&lt;/h2&gt;
&lt;p&gt;Git이 아니어도 서버 접속에 사용하는 SSH 키는 당연히 1Password에서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/f781468bd0ad_3x.jpg" alt="macOS에서 Ghostty가 SSH 키 사용을 위해 1Password 접근 권한을 요청하는 확인 창이 떠 있다."&gt;&lt;/p&gt;
&lt;p&gt;스크린샷에서는 해당 서버에 접속하는 화면을 보여줬지만, 앞서 &lt;code&gt;~/.ssh/config&lt;/code&gt;의 설정을 기억한다면 호스트를 &lt;code&gt;*&lt;/code&gt;로만 설정했고 호스트별로 키를 식별하는 설정은 없었다는 것을 알 것이다. 실제로 어떤 기준인지는 모르지만 &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;에 등록한 SSH 키가 순서대로 하나씩 뜬다. 그래서 이름을 보고 해당 키가 아니면 거부하고, 사용할 키가 나오면 승인하면 된다. SSH의 구조 때문인지 키를 골라서 선택하는 게 아니라 이렇게만 동작한다. 이로 인해서 일반적으로 SSH 서버가 인증 시도를 6회로 제한하기 때문에 SSH 에이전트도 &lt;a href="https://www.1password.dev/ssh/agent/advanced#ssh-server-six-key-limit"&gt;SSH 키가 6개 초과로 있으면 제대로 사용할 수 없는 문제가 생긴다&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;그래서 한번 승인해서 사용하고 나면 아래처럼 활동 탭에서 그 기록을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/f7074db86b77_3x.jpg" alt="1Password SSH 에이전트의 활동 탭에 Ghostty에서 사용한 SSH 키와 최근 작업 시간이 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;여기서 우측에 북마크 버튼이 있는데, 이걸 누르면 북마크로 저장된다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/501adeac502c_3x.jpg" alt="SSH 키 관리 화면의 북마크 탭이 선택되어 있으며, 등록된 호스트와 SSH 키 항목에 연결 버튼이 표시된다."&gt;&lt;/p&gt;
&lt;p&gt;이 &lt;a href="https://www.1password.dev/ssh/bookmarks"&gt;북마크&lt;/a&gt; 저장해 두면 해당 호스트를 사용할 때는 &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;가 알아서 해당 키를 띄워주므로 자주 사용하는 키는 북마크로 등록해놔야 편하게 쓸 수 있다.&lt;/p&gt;
&lt;h2&gt;GitHub 멀티 계정을 사용하는 경우&lt;/h2&gt;
&lt;p&gt;앞에서 활동 탭을 보면 SSH 접속은 &lt;a href="https://www.1password.dev/ssh/bookmarks"&gt;북마크&lt;/a&gt; 버튼이 있는데 Git 명령어에서는 &lt;a href="https://www.1password.dev/ssh/bookmarks"&gt;북마크&lt;/a&gt; 버튼이 없는걸 볼 수 있다.&lt;/p&gt;
&lt;p&gt;나는 &lt;a href="https://blog.outsider.ne.kr/1448"&gt;업무용 GitHub과 개인용 GitHub을 따로 운영&lt;/a&gt;하고 있는데 경험상 이런 사람이 많지는 않지만 회사 사정 등 여러 이유로 내부 Git 저장소를 쓰는 등 여러 Git 호스팅 서비스에 인증을 해야 하는 경우가 있다. 여러 Git 호스팅을 쓰는 경우 &lt;code&gt;~/.gitconfig&lt;/code&gt;와 &lt;code&gt;~/.ssh/config&lt;/code&gt; 설정이 둘다 필요한데 여기서는 사실상 &lt;code&gt;~/.ssh/config&lt;/code&gt;만 관련있다.&lt;/p&gt;
&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# ~/.ssh/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# work account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;company.github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/work-private-key&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# personal account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/personal-github-key&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 설정은 두 개의 키를 각 호스트에 쓰는 가장 일반적인 경우의 설정이다. 취향에 따라 약간씩 다를 수 있지만 기본 구조는 똑같다. SSH가 호스트만으로 구분할 수 있기 때문에 호스트를 이용해서 다른 키를 사용하게 하는데 호스트가 아예 다르면 오히려 편하지만 여기서는 둘다 GitHub인 예시이므로 &lt;code&gt;company.github.com&lt;/code&gt;이라는건 임의로 만들어 낸 주소다. 그래서 둘 다 GitHub이지만 회사 저장소를 사용할 때는 &lt;code&gt;git remote add&lt;/code&gt;에서 &lt;code&gt;github.com&lt;/code&gt; 대신 &lt;code&gt;company.github.com&lt;/code&gt;으로 등록하면 실제로는 &lt;code&gt;github.com&lt;/code&gt;으로 연결되면서 다른 키를 사용하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;도 이 방식을 이용해서 &lt;a href="https://www.1password.dev/ssh/agent/advanced#use-multiple-github-accounts"&gt;멀티 계정을 사용하는 방법을 안내&lt;/a&gt;하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.outsider.ne.kr/uploads/2026/06/20fb66528a2f_3x.png" alt="github auth 화면에 공개 키, 지문, 개인 키, 키 유형 Ed25519 항목이 표시되어 있고 메뉴에서 다운로드가 선택되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;사용하는 키의 공개 키를 다운로드해서 &lt;code&gt;~/.ssh/&lt;/code&gt; 아래에 저장한다.&lt;/p&gt;
&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# ~/.ssh/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"~/Library/Group Containers/2AAA333A2C.com.1password/t/agent.sock"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# work account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;company.github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/company-github.pub&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentitiesOnly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# personal account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/personal-github.pub&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentitiesOnly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 위처럼 설정하면 공개키를 인식하고 해당키로 사용할 비밀키를 식별해서 정확히 원하는 키만 인증으로 뜨게 된다.&lt;/p&gt;
&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;$ git clone git@github.com:outsideris/project.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;Cloning into &lt;span class="s1"&gt;'project'&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;remote: Enumerating objects: 199, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;199/199&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;120/120&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;remote: Total &lt;span class="m"&gt;199&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 87&lt;span class="o"&gt;)&lt;/span&gt;, reused &lt;span class="m"&gt;162&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 57&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;from 0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;199/199&lt;span class="o"&gt;)&lt;/span&gt;, 60.76 KiB &lt;span class="p"&gt;|&lt;/span&gt; 467.00 KiB/s, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;87/87&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;$  git clone git@company.github.com:outsider-biz/test.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;Cloning into &lt;span class="s1"&gt;'test'&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;remote: Enumerating objects: 13, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;13/13&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;6/6&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;remote: Total &lt;span class="m"&gt;13&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;, reused &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;from 0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;13/13&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;1/1&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;호스트만 제대로 지정해주면 동시에 사용하는데 문제가 없다. 그리고 이는 1Password SSH 에이전트의 문제는 아니고 원래 SSH 키로만 사용할 때도 똑같다.&lt;/p&gt;
&lt;p&gt;이로써 키가 유출될 걱정은 덜었고 새로운 장비를 사거나 할때도 키를 복사하는 과정이 필요했는데 이제는 &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;만 설치하면 바로 사용할 수 있게 되었다.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://blog.outsider.ne.kr/1799</id>
    <link href="https://blog.outsider.ne.kr/1799"/>
    <summary type="html">&lt;p&gt;최근 몇 년 사이 보안에 관심이 많아졌다. 완벽한 보안이란 없지만, 여러 환경 중 의외로 보안이 취약한 곳은 로컬 환경이다. 아무래도 개인 장비라 외부 접근이 기본적으로 차단되는 데다가 자주 사용해서 편의성도 중요하다 보니 로컬에는 많은 시크릿이 평문으로 저장되어 있다.&lt;/p&gt;
&lt;p&gt;로컬에서 관리되는 시크릿은 다양하지만, 그중 정말 중요하면서도 평문으로 관리되는 것 중 하나가 SSH 키다. 비밀키는 보안의 핵심이지만 현실에서는 평문으로 관리되고 있어서 개인 장비를 분실하거나 해킹당하면 쉽게 유출될 수 있다.&lt;/p&gt;
&lt;h2&gt;1Password SSH 에이전트 설정&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;는 비밀번호를 관리해 주는 게 핵심 기능이지만 몇 년 전부터 개발자를 위한 기능을 강화하고 있다. &lt;a href="https://1password.com/blog/1password-ssh-agent"&gt;SSH 에이전트 기능은 나온 지 수년이 되었지만&lt;/a&gt; 생각만 하다가 이제야 제대로 설정했다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/07de70fafc74_3x.png" alt="1Password의 개발자 화면에서 SSH 에이전트, 개발자 환경, CLI, Watchtower 기능 카드가 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;의 개발자 메뉴에 들어가면 SSH 에이전트라는 메뉴가 보인다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/fe98ef5e5727_3x.png" alt="1Password 설정의 개발자 탭이 열려 있으며, 개발자 경험 표시와 활동 기록 옵션이 체크되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;혹시 개발자 메뉴가 안 보인다면 설정에서 개발자 기능을 켜야 한다.&lt;/p&gt;
&lt;p&gt;SSH 에이전트 설정을 누르면 다음과 같은 안내가 나온다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/f83cf547aa32_3x.png" alt="1Password가 디스크에 SSH 키 이름 저장을 허용할지 묻는 알림 창. ‘키 지문만 사용’과 ‘키 이름 사용’ 버튼이 보인다."&gt;&lt;/p&gt;
&lt;p&gt;설명을 완전히 이해는 못했지만 키 지문으로는 키를 구분하기 어려우므로 키 이름을 사용하기로 했다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/ad860e633fee_3x.jpg" alt="1Password의 SSH 에이전트 설정 창에 ~/.ssh/config에 추가할 IdentityAgent 스니펫과 자동 편집 버튼이 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;이는 &lt;code&gt;~/.ssh/config&lt;/code&gt; 설정인데, 해본 사람은 알겠지만 모든 SSH 호스트에 1Password SSH 에이전트를 사용하도록 하는 설정이다. 그래서 다른 호스트에서는 기존의 키 파일을 써야 한다면 호스트를 지정한 설정을 추가하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/5a75ec5ee546_3x.png" alt="1Password SSH 에이전트 설정 화면으로, 실행 중 상태와 사용 가능한 SSH 키가 없다는 안내가 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;SSH config에 설정을 넣으면 에이전트가 실행 중으로 바뀐다.&lt;/p&gt;
&lt;h2&gt;SSH 접속에 1Password SSH 에이전트 사용하기&lt;/h2&gt;
&lt;p&gt;먼저 SSH에 사용할 키를 등록해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/d8ff05963f8e_3x.png" alt="비밀번호 관리 앱의 새 항목 창에서 SSH 키 항목을 만들고 있다. 개인 키 파일 드래그 영역과 추가 옵션, 저장 버튼이 보인다."&gt;&lt;/p&gt;
&lt;p&gt;인식할 수 있는 이름을 주고 기존의 키를 드래그하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/0a4f5fa815bf_3x.png" alt="개인 키 파일을 드래그해 가져오는 영역과 개인 키 추가 버튼이 보이며, 키 유형은 Ed25519로 선택되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;에서 바로 키를 생성할 수도 있는데 &lt;a href="https://en.wikipedia.org/wiki/Ed25519"&gt;Ed25519&lt;/a&gt;와 &lt;a href="https://en.wikipedia.org/wiki/RSA_cryptosystem"&gt;RSA&lt;/a&gt;로 만들 수 있다. 특별한 이유가 없다면 지금은 &lt;a href="https://en.wikipedia.org/wiki/Ed25519"&gt;Ed25519&lt;/a&gt;로 만들면 된다. 키 크기도 훨씬 작고 검증 속도도 훨씬 빠르다. 나 같은 경우는 기본으로 쓰던 키가 너무 오래되어서 그런지 &lt;a href="https://www.1password.dev/ssh/manage-keys#key-import-errors"&gt;지원하지 않는 형식&lt;/a&gt;이라고 나와서 이 기회에 새로 키를 생성했다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/b188631ec9fb_3x.png" alt="Git 커밋에 SSH 서명을 설정하라는 안내와 함께 Test key의 공개 키, 지문, 개인 키 상태, 키 유형이 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;생성된 키의 공개키와 지문도 바로 볼 수 있다. GitHub를 사용하는 경우 &lt;strong&gt;GitHub 계정의 &lt;a href="https://github.com/settings/keys"&gt;SSH and GPG keys 설정&lt;/a&gt;에서 공개 키를 SSH Authentication Key로 등록하면 된다&lt;/strong&gt;. &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;에서 Git 커밋 서명에도 사용하라고 안내하는데, 나 같은 경우는 GPG로 서명하고 있어서 따로 설정하진 않았다. 간단히 설명하면 Authentication Key는 &lt;code&gt;git clone&lt;/code&gt;이나 &lt;code&gt;git pull&lt;/code&gt; 등 Git 저장소를 SSH로 접속할 때 쓰는 키이고 Signing Key는 커밋할 때 서명을 추가해서 해당 커밋을 본인이 했음을 증명할 때 사용하는 키다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/251d1184a1ba_3x.jpg" alt="터미널에서 GitHub 저장소를 클론하는 중 Ghostty가 1Password에 SSH 키 접근 권한을 요청하는 인증 창이 떠 있다."&gt;&lt;/p&gt;
&lt;p&gt;이제 터미널에서 Git 저장소에 접근하면 1Password 화면이 나오고, 여기서 인증하면 정상적으로 클론할 수 있다. 이렇게 구성하면 로컬에 비밀키를 평문으로 보관하지 않고서 안전하게 비밀키를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/64178dd211d3_3x.png" alt="1Password 설정의 개발자 메뉴가 열려 있고, 고급 옵션에서 승인 요청, 키 승인 기억, SSH 설정 항목을 조정할 수 있다."&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt; 설정에서 키 승인에 대한 유효기간을 얼마나 유지할지 등을 설정할 수 있다.&lt;/p&gt;
&lt;h2&gt;북마크 관리&lt;/h2&gt;
&lt;p&gt;Git이 아니어도 서버 접속에 사용하는 SSH 키는 당연히 1Password에서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/f781468bd0ad_3x.jpg" alt="macOS에서 Ghostty가 SSH 키 사용을 위해 1Password 접근 권한을 요청하는 확인 창이 떠 있다."&gt;&lt;/p&gt;
&lt;p&gt;스크린샷에서는 해당 서버에 접속하는 화면을 보여줬지만, 앞서 &lt;code&gt;~/.ssh/config&lt;/code&gt;의 설정을 기억한다면 호스트를 &lt;code&gt;*&lt;/code&gt;로만 설정했고 호스트별로 키를 식별하는 설정은 없었다는 것을 알 것이다. 실제로 어떤 기준인지는 모르지만 &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;에 등록한 SSH 키가 순서대로 하나씩 뜬다. 그래서 이름을 보고 해당 키가 아니면 거부하고, 사용할 키가 나오면 승인하면 된다. SSH의 구조 때문인지 키를 골라서 선택하는 게 아니라 이렇게만 동작한다. 이로 인해서 일반적으로 SSH 서버가 인증 시도를 6회로 제한하기 때문에 SSH 에이전트도 &lt;a href="https://www.1password.dev/ssh/agent/advanced#ssh-server-six-key-limit"&gt;SSH 키가 6개 초과로 있으면 제대로 사용할 수 없는 문제가 생긴다&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;그래서 한번 승인해서 사용하고 나면 아래처럼 활동 탭에서 그 기록을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/f7074db86b77_3x.jpg" alt="1Password SSH 에이전트의 활동 탭에 Ghostty에서 사용한 SSH 키와 최근 작업 시간이 표시되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;여기서 우측에 북마크 버튼이 있는데, 이걸 누르면 북마크로 저장된다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/501adeac502c_3x.jpg" alt="SSH 키 관리 화면의 북마크 탭이 선택되어 있으며, 등록된 호스트와 SSH 키 항목에 연결 버튼이 표시된다."&gt;&lt;/p&gt;
&lt;p&gt;이 &lt;a href="https://www.1password.dev/ssh/bookmarks"&gt;북마크&lt;/a&gt; 저장해 두면 해당 호스트를 사용할 때는 &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;가 알아서 해당 키를 띄워주므로 자주 사용하는 키는 북마크로 등록해놔야 편하게 쓸 수 있다.&lt;/p&gt;
&lt;h2&gt;GitHub 멀티 계정을 사용하는 경우&lt;/h2&gt;
&lt;p&gt;앞에서 활동 탭을 보면 SSH 접속은 &lt;a href="https://www.1password.dev/ssh/bookmarks"&gt;북마크&lt;/a&gt; 버튼이 있는데 Git 명령어에서는 &lt;a href="https://www.1password.dev/ssh/bookmarks"&gt;북마크&lt;/a&gt; 버튼이 없는걸 볼 수 있다.&lt;/p&gt;
&lt;p&gt;나는 &lt;a href="https://blog.outsider.ne.kr/1448"&gt;업무용 GitHub과 개인용 GitHub을 따로 운영&lt;/a&gt;하고 있는데 경험상 이런 사람이 많지는 않지만 회사 사정 등 여러 이유로 내부 Git 저장소를 쓰는 등 여러 Git 호스팅 서비스에 인증을 해야 하는 경우가 있다. 여러 Git 호스팅을 쓰는 경우 &lt;code&gt;~/.gitconfig&lt;/code&gt;와 &lt;code&gt;~/.ssh/config&lt;/code&gt; 설정이 둘다 필요한데 여기서는 사실상 &lt;code&gt;~/.ssh/config&lt;/code&gt;만 관련있다.&lt;/p&gt;
&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# ~/.ssh/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# work account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;company.github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/work-private-key&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# personal account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/personal-github-key&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;위 설정은 두 개의 키를 각 호스트에 쓰는 가장 일반적인 경우의 설정이다. 취향에 따라 약간씩 다를 수 있지만 기본 구조는 똑같다. SSH가 호스트만으로 구분할 수 있기 때문에 호스트를 이용해서 다른 키를 사용하게 하는데 호스트가 아예 다르면 오히려 편하지만 여기서는 둘다 GitHub인 예시이므로 &lt;code&gt;company.github.com&lt;/code&gt;이라는건 임의로 만들어 낸 주소다. 그래서 둘 다 GitHub이지만 회사 저장소를 사용할 때는 &lt;code&gt;git remote add&lt;/code&gt;에서 &lt;code&gt;github.com&lt;/code&gt; 대신 &lt;code&gt;company.github.com&lt;/code&gt;으로 등록하면 실제로는 &lt;code&gt;github.com&lt;/code&gt;으로 연결되면서 다른 키를 사용하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;도 이 방식을 이용해서 &lt;a href="https://www.1password.dev/ssh/agent/advanced#use-multiple-github-accounts"&gt;멀티 계정을 사용하는 방법을 안내&lt;/a&gt;하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;img src="/uploads/2026/06/20fb66528a2f_3x.png" alt="github auth 화면에 공개 키, 지문, 개인 키, 키 유형 Ed25519 항목이 표시되어 있고 메뉴에서 다운로드가 선택되어 있다."&gt;&lt;/p&gt;
&lt;p&gt;사용하는 키의 공개 키를 다운로드해서 &lt;code&gt;~/.ssh/&lt;/code&gt; 아래에 저장한다.&lt;/p&gt;
&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# ~/.ssh/config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityAgent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;~/Library/Group Containers/2AAA333A2C.com.1password/t/agent.sock&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# work account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;company.github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/company-github.pub&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentitiesOnly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# personal account&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;HostName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentityFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;~/.ssh/personal-github.pub&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;IdentitiesOnly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;그리고 위처럼 설정하면 공개키를 인식하고 해당키로 사용할 비밀키를 식별해서 정확히 원하는 키만 인증으로 뜨게 된다.&lt;/p&gt;
&lt;pre class="chroma"&gt;&lt;code&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;$ git clone git@github.com:outsideris/project.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;Cloning into &lt;span class="s1"&gt;&amp;#39;project&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;remote: Enumerating objects: 199, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;199/199&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;120/120&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;remote: Total &lt;span class="m"&gt;199&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 87&lt;span class="o"&gt;)&lt;/span&gt;, reused &lt;span class="m"&gt;162&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 57&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;from 0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;199/199&lt;span class="o"&gt;)&lt;/span&gt;, 60.76 KiB &lt;span class="p"&gt;|&lt;/span&gt; 467.00 KiB/s, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;87/87&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;$  git clone git@company.github.com:outsider-biz/test.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;Cloning into &lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;remote: Enumerating objects: 13, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;13/13&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;6/6&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;remote: Total &lt;span class="m"&gt;13&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;, reused &lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;delta 1&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;from 0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;13/13&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;1/1&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;호스트만 제대로 지정해주면 동시에 사용하는데 문제가 없다. 그리고 이는 1Password SSH 에이전트의 문제는 아니고 원래 SSH 키로만 사용할 때도 똑같다.&lt;/p&gt;
&lt;p&gt;이로써 키가 유출될 걱정은 덜었고 새로운 장비를 사거나 할때도 키를 복사하는 과정이 필요했는데 이제는 &lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;만 설치하면 바로 사용할 수 있게 되었다.&lt;/p&gt;
</summary>
    <title>1Password SSH 에이전트로 로컬 SSH 키 안전하게 관리하기</title>
    <updated>2026-06-12T20:29:42+09:00</updated>
    <dc:date>2026-06-12T20:29:42+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>joosing</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;p&gt;최근에 주변에서 “AI가 그러던데” 라는 말을 자주 듣습니다. 대부분 AI가 준 결과를 아무런 검증 없이 그대로 인용하는 말입니다. 이런 말을 일의 영역에서 들으면 마음이 조금 불편해집니다.&lt;/p&gt;
&lt;p&gt;우리는 AI의 도움을 받지만 AI를 통한 결과는 우리 스스로 보증해야 합니다. AI가 준 결과는 사실을 찾는 중간 과정일 뿐입니다. 우리는 AI가 준 정보가 합리적인지 스스로 판단해 보아야 합니다. 모호한 사실이라면 공식 기술 문서를 이중으로 찾아봐야 하고, 결과물이 코드라면 직접 테스트 코드를 돌려 결과를 확인하는 노력도 필요합니다. 물론 테스트 코드를 작성하는 일도 AI의 도움을 받을 수 있지만, 테스트가 검증하는 입력과 출력 그리고 조건들이 합리적인지는 스스로 검증해야 합니다. &lt;/p&gt;
&lt;p&gt;불과 몇 년 전만해도 습관적으로 잘 알려진 개발자 이름을 대며 “OOO (사람 이름)이 그러던데”라는 말로 어떤 기술적 주장을 하는 사람들이 있었는데, 시대가 바뀌면서 이런 표현들도 바뀌어 가는구나 싶습니다.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://velog.io/@joosing/AI%EA%B0%80-%EA%B7%B8%EB%9F%AC%EB%8D%98%EB%8D%B0</id>
    <link href="https://velog.io/@joosing/AI%EA%B0%80-%EA%B7%B8%EB%9F%AC%EB%8D%98%EB%8D%B0"/>
    <summary type="html">&lt;p&gt;최근에 주변에서 “AI가 그러던데” 라는 말을 자주 듣습니다. 대부분 AI가 준 결과를 아무런 검증 없이 그대로 인용하는 말입니다. 이런 말을 일의 영역에서 들으면 마음이 조금 불편해집니다.&lt;/p&gt;
&lt;p&gt;우리는 AI의 도움을 받지만 AI를 통한 결과는 우리 스스로 보증해야 합니다. AI가 준 결과는 사실을 찾는 중간 과정일 뿐입니다. 우리는 AI가 준 정보가 합리적인지 스스로 판단해 보아야 합니다. 모호한 사실이라면 공식 기술 문서를 이중으로 찾아봐야 하고, 결과물이 코드라면 직접 테스트 코드를 돌려 결과를 확인하는 노력도 필요합니다. 물론 테스트 코드를 작성하는 일도 AI의 도움을 받을 수 있지만, 테스트가 검증하는 입력과 출력 그리고 조건들이 합리적인지는 스스로 검증해야 합니다. &lt;/p&gt;
&lt;p&gt;불과 몇 년 전만해도 습관적으로 잘 알려진 개발자 이름을 대며 “OOO (사람 이름)이 그러던데”라는 말로 어떤 기술적 주장을 하는 사람들이 있었는데, 시대가 바뀌면서 이런 표현들도 바뀌어 가는구나 싶습니다.&lt;/p&gt;
</summary>
    <title>AI가 그러던데?  </title>
    <updated>2026-06-13T19:20:54+09:00</updated>
    <dc:date>2026-06-13T19:20:54+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>joosing</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;p&gt;&lt;img src="https://velog.velcdn.com/images/joosing/post/1826791d-627d-4abf-bb0d-c06a5fd673d0/image.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;문제를 해결하는 리더들에게는 공통적인 특징들이 있다.&lt;/p&gt;
&lt;h3 id="1-get-to-the-point"&gt;1. Get to the Point&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들의 언어는 간결하고 문제의 핵심을 찔러 쪼갠다. 그들의 언어는 문제를 꿰뚫은 뒤에 즉시 행동 가능한 방향을 가리키고 많은 사람들이 같은 생각을 가지게 한다. 반면에 문제를 해결하지 못하는 리더의 언어는 장황하다. A를 말하면 A부터 Z까지의 설명이 돌아오고 왠만한 문해력으로는 이해하기 힘든 길고 복잡한 의견을 남긴다. 그들의 설명을 들어도 내가 그래서 뭘 해야하는지 감이 잘 오지 않는다. &lt;/p&gt;
&lt;h3 id="2-divide-and-conquer"&gt;2. Divide and Conquer&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들은 얽혀버린 거대한 실뭉치 같은 문제를 덩어리 채로 가만히 두지 않는다. 그들은 문제를 더 작은 문제들로 나누었고, 오늘 당장 해결을 시도해 볼 문제를 선택했다. 그리고 작은 문제들을 계속해서 풀어가도록 팀을 독려했다. 얽힌 실타래를 잡고 흔든다고 실타래가 풀어질리 없다. 얽힌 실타래를 푸는 유일한 방법은 얽힌 실타래의 시작 지점을 찾고 거기부터 계속 풀어 나가가는 것이다. 그들은 오늘 풀어볼 수 있는 문제가 될 때까지 큰 문제를 작게 나누었고, 그것들을 풀고, 그것들을 통합해 나가는 방법을 사용했다. &lt;/p&gt;
&lt;h3 id="3-focus-on-problem"&gt;3. Focus on problem&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들은 문제 해결에 집중한다. 그들은 현재 상황에서의 최적의 해법을 찾아나선다. 반면에 문제를 해결하지 못하는 리더들은 다른 관심사들을 문제 영역으로 가져와 최적의 해법을 찾는 일 보다 앞세운다. 예를 들면 힙한 기술, 투자, 마케팅 등을 문제 영역으로 가져와 그것에 유리한 해법을 선택하곤 했다. 당연하지만 이렇게 해서 문제를 해결하는 최적의 해답이 나올리 없고 프로젝트는 조금씩 이상한 방향으로 흘러가며 표류하기 시작했다. (그러나 이건 순전히 엔지니어링 관점에서의 생각이다. 회사의 다양한 조직의 목적과 관점에 따라 프로젝트의 문제를 조금 덜 완벽하게 해결하고 다른 것들을 추구할 수 있다고 생각한다. 어쨋든 문제 해결 외에 것들이 끼어들면 엔지니어링 업무는 방해를 받고 느려지고 어려워지는 것이 사실이다. 그런 것마저 다 고려하는게 우리가 월급을 받는 이유라면 감당해야 할 일이다.)&lt;/p&gt;
&lt;h3 id="4-bridge-problem-and-solution"&gt;4. Bridge Problem and Solution&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들은 문제와 해법을 연결하기 위해 노력했다. 그들은 팀의 주간 업무를 정리며 팀원들이 어떤 기술적인 일을 했다는 것을 보고받고 거기서 그치지 않는다. 그들은 그것이 문제 해결과 어떤 관련이 있는지 이해하고 설명하려고 노력했다. 만약 그런 노력이 없다면 엔지니어링 조직은 종종 문제 해결과 관련 없는 기술 영역의 호기심에 빠지거나, 목표와 관련 없는 혹은 지나치도록 기술적인 일에 몰입하기도 한다. 문제를 해결하지 못하는 리더들은 대게 해법 영역의 기술에 지나치게 몰입하며 문제 해결이라는 목적을 잃고 표류하기도 했다.&lt;/p&gt;
&lt;h3 id="5-into-the-problem"&gt;5. Into the Problem&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 문제 속으로 과감하게 들어간다. 문제 속으로 들어간다는 게 실무자처럼 팔을 걷어붙이고 코딩을 한다는 뜻은 아니다. (물론 그럴 때도 있지만) 대신 리더는 문제에 뛰어들어 문제가 무엇인지 분명하게 이해하고, 팀이 어떻게 문제를 해결하고 있으며, 그 방향이 적절한지 검토하고 피드백을 주는 수준으로 문제 안으로 들어간다. 반면에 문제를 해결하지 못하는 리더들은 문제 밖에서 문제를 보고받고 그저 기다리는 방식으로 문제를 대한다. 이런 현상은 문제 영역이 리더가 다룰 수 있는 전문 분야가 아니기 때문일 수 있다. 만약 팀이 리더에게 문제에 대해 설명하고 리더가 그것을 이해하는데 지나치게 오랜 시간이 걸린다면 현재의 리더가 팀에 적합한 사람이 아닐 수 있고 리더와 팀 사이에 중간 관리자가 필요한 것은 아닌지 의심해 볼 필요가 있다. 리더와 팀의 기술적 간격이 큰 조직에서는 리더가 문제 속으로 들어가지도 못하고 실무자들은 리더에게 상황을 설명하는데 불필요한 시간을 사용하며 문제 해결을 도리어 방해하게 된다. &lt;/p&gt;
&lt;h3 id="6-solve-together"&gt;6. Solve Together&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 혼자 문제를 해결하지 못할 때 자신의 한계를 인정하고 주변에 도움을 요청할 줄 안다. 신기한 일이지만 경험에 의하면 팀이 매우 탁월한 사람들로 구성된 것이 아니더라도 함께 의논하고 방향을 모색하기 시작하면 문제가 어떻게든 해결되기 시작했다. 반면에 문제를 해결하지 못하는 리더들은 주변에 도움을 요청하지 않고 혼자 문제를 끌어안고 끙끙대며 문제를 키웠다. 리더들은 보통 매우 중요한 일이거나 무언가를 종합하는 일이라 혼자 이 일을 맡게 되는데 그럼에도 불구하고 한계를 만나면 팀원들에게 도움을 요청하기를 주저하지 말아야 한다. 평소에 일을 떠넘기는 리더가 아니었다면 팀원들도 그걸 사실 간절히 원하고 리더가 혼자 쓰러지기를 아무도 원하지 않는다. &lt;/p&gt;
&lt;h3 id="7-surface-the-problem"&gt;7. Surface the Problem&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 문제를 드러내기를 주저하지 않는다. 그들은 문제를 드러내는 것에 용감했다. 왜냐하면 문제를 솔직하게 드러내는 것이 문제 해결의 시작이기 때문이다. 실수한 것이 부끄러워서, 문제가 또 다른 문제가 될까봐 문제를 덮어두면 문제는 피노키오의 코 마냥 감당할 수 없을 정도로 점차 커지고 삐뚤어진 방향으로 발현된다. 그뿐아니라 문제를 솔직하게 드러내고 함께 해결하는 경험은 팀 내에 서로를 향한 신뢰를 높인다. 현명한 리더는 문제를 도리어 우리의 결속력을 다지는데 사용한다.&lt;/p&gt;
&lt;h3 id="8-find-a-way"&gt;8. &lt;strong&gt;Find a Way&lt;/strong&gt;
&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 수 많은 안되는 이유 가운데 되는 한 가지를 방법을 찾고 팀이 그것에 집중하도록 앞장서 독려한다. 이런 능력은 리더의 정말 중요하고 큰 덕목이라고 생각한다. 반면에 문제를 해결하지 못하는 리더는 안되는 이유에 매몰되고 그것을 여기저기 습관적으로 말하며 팀의 분위기 전체를 해쳐놓는다. &lt;/p&gt;
&lt;h3 id="9-hold-the-course"&gt;9. Hold the Course&lt;/h3&gt;
&lt;p&gt;문제가 해결되지 않을 때 우리는 관리 자체를 하지 않고 뭔가 알아서 잘되길 바라고 있는 경우가 많았다. 경험에 의하면 프로젝트는 가만히 두면 끊임없이 곁 길로 세고 최적의 경로를 벗어나려는 특징을 가지고 있는 것 같다. 그래서 리더는 계속해서 중요한 것과 먼저 해야 하는 것에 팀이 집중하도록 프로젝트를 관리해야 한다. 때로는 매일, 때로는 주 단위로, 때로는 문제가 있을 때마다 팀원들을 만나 관리를 해야 한다. ‘관리’라는 표현에 다소 부정적인 느낌이 있는게 사실이고, 관리하지 않아도 다 함께 목표를 향해 잘 나아가는 이상적인 조직을 꿈꾸지만, 현실의 조직은 정말 관리가 필요하다. 문제를 해결하는 리더는 프로젝트가 최적의 경로로 계속 나아가도록 관리한다. &lt;/p&gt;
&lt;p&gt;지금까지 지난 10년간 봐온 문제를 해결하는 리더들의 특징들 몇 가지를 정리해 보았다. 사실 리더가 되는 데는 연차나 직책 같은 건 중요하지 않다. 만약 스스로 일을 책임지고 해결하려는 사람이라면 누구나 다 리더다. 이 글을 읽는 스스로 자신이 리더라고 생각한다면 문제를 해결하는 데 한 번 쯤 이런 생각들을 고려해 보면 좋을 것 같다. &lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://velog.io/@joosing/9-characteristics-of-a-problem-solving-leader</id>
    <link href="https://velog.io/@joosing/9-characteristics-of-a-problem-solving-leader"/>
    <summary type="html">&lt;p&gt;&lt;img src="https://velog.velcdn.com/images/joosing/post/1826791d-627d-4abf-bb0d-c06a5fd673d0/image.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;문제를 해결하는 리더들에게는 공통적인 특징들이 있다.&lt;/p&gt;
&lt;h3 id="1-get-to-the-point"&gt;1. Get to the Point&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들의 언어는 간결하고 문제의 핵심을 찔러 쪼갠다. 그들의 언어는 문제를 꿰뚫은 뒤에 즉시 행동 가능한 방향을 가리키고 많은 사람들이 같은 생각을 가지게 한다. 반면에 문제를 해결하지 못하는 리더의 언어는 장황하다. A를 말하면 A부터 Z까지의 설명이 돌아오고 왠만한 문해력으로는 이해하기 힘든 길고 복잡한 의견을 남긴다. 그들의 설명을 들어도 내가 그래서 뭘 해야하는지 감이 잘 오지 않는다. &lt;/p&gt;
&lt;h3 id="2-divide-and-conquer"&gt;2. Divide and Conquer&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들은 얽혀버린 거대한 실뭉치 같은 문제를 덩어리 채로 가만히 두지 않는다. 그들은 문제를 더 작은 문제들로 나누었고, 오늘 당장 해결을 시도해 볼 문제를 선택했다. 그리고 작은 문제들을 계속해서 풀어가도록 팀을 독려했다. 얽힌 실타래를 잡고 흔든다고 실타래가 풀어질리 없다. 얽힌 실타래를 푸는 유일한 방법은 얽힌 실타래의 시작 지점을 찾고 거기부터 계속 풀어 나가가는 것이다. 그들은 오늘 풀어볼 수 있는 문제가 될 때까지 큰 문제를 작게 나누었고, 그것들을 풀고, 그것들을 통합해 나가는 방법을 사용했다. &lt;/p&gt;
&lt;h3 id="3-focus-on-problem"&gt;3. Focus on problem&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들은 문제 해결에 집중한다. 그들은 현재 상황에서의 최적의 해법을 찾아나선다. 반면에 문제를 해결하지 못하는 리더들은 다른 관심사들을 문제 영역으로 가져와 최적의 해법을 찾는 일 보다 앞세운다. 예를 들면 힙한 기술, 투자, 마케팅 등을 문제 영역으로 가져와 그것에 유리한 해법을 선택하곤 했다. 당연하지만 이렇게 해서 문제를 해결하는 최적의 해답이 나올리 없고 프로젝트는 조금씩 이상한 방향으로 흘러가며 표류하기 시작했다. (그러나 이건 순전히 엔지니어링 관점에서의 생각이다. 회사의 다양한 조직의 목적과 관점에 따라 프로젝트의 문제를 조금 덜 완벽하게 해결하고 다른 것들을 추구할 수 있다고 생각한다. 어쨋든 문제 해결 외에 것들이 끼어들면 엔지니어링 업무는 방해를 받고 느려지고 어려워지는 것이 사실이다. 그런 것마저 다 고려하는게 우리가 월급을 받는 이유라면 감당해야 할 일이다.)&lt;/p&gt;
&lt;h3 id="4-bridge-problem-and-solution"&gt;4. Bridge Problem and Solution&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더들은 문제와 해법을 연결하기 위해 노력했다. 그들은 팀의 주간 업무를 정리며 팀원들이 어떤 기술적인 일을 했다는 것을 보고받고 거기서 그치지 않는다. 그들은 그것이 문제 해결과 어떤 관련이 있는지 이해하고 설명하려고 노력했다. 만약 그런 노력이 없다면 엔지니어링 조직은 종종 문제 해결과 관련 없는 기술 영역의 호기심에 빠지거나, 목표와 관련 없는 혹은 지나치도록 기술적인 일에 몰입하기도 한다. 문제를 해결하지 못하는 리더들은 대게 해법 영역의 기술에 지나치게 몰입하며 문제 해결이라는 목적을 잃고 표류하기도 했다.&lt;/p&gt;
&lt;h3 id="5-into-the-problem"&gt;5. Into the Problem&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 문제 속으로 과감하게 들어간다. 문제 속으로 들어간다는 게 실무자처럼 팔을 걷어붙이고 코딩을 한다는 뜻은 아니다. (물론 그럴 때도 있지만) 대신 리더는 문제에 뛰어들어 문제가 무엇인지 분명하게 이해하고, 팀이 어떻게 문제를 해결하고 있으며, 그 방향이 적절한지 검토하고 피드백을 주는 수준으로 문제 안으로 들어간다. 반면에 문제를 해결하지 못하는 리더들은 문제 밖에서 문제를 보고받고 그저 기다리는 방식으로 문제를 대한다. 이런 현상은 문제 영역이 리더가 다룰 수 있는 전문 분야가 아니기 때문일 수 있다. 만약 팀이 리더에게 문제에 대해 설명하고 리더가 그것을 이해하는데 지나치게 오랜 시간이 걸린다면 현재의 리더가 팀에 적합한 사람이 아닐 수 있고 리더와 팀 사이에 중간 관리자가 필요한 것은 아닌지 의심해 볼 필요가 있다. 리더와 팀의 기술적 간격이 큰 조직에서는 리더가 문제 속으로 들어가지도 못하고 실무자들은 리더에게 상황을 설명하는데 불필요한 시간을 사용하며 문제 해결을 도리어 방해하게 된다. &lt;/p&gt;
&lt;h3 id="6-solve-together"&gt;6. Solve Together&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 혼자 문제를 해결하지 못할 때 자신의 한계를 인정하고 주변에 도움을 요청할 줄 안다. 신기한 일이지만 경험에 의하면 팀이 매우 탁월한 사람들로 구성된 것이 아니더라도 함께 의논하고 방향을 모색하기 시작하면 문제가 어떻게든 해결되기 시작했다. 반면에 문제를 해결하지 못하는 리더들은 주변에 도움을 요청하지 않고 혼자 문제를 끌어안고 끙끙대며 문제를 키웠다. 리더들은 보통 매우 중요한 일이거나 무언가를 종합하는 일이라 혼자 이 일을 맡게 되는데 그럼에도 불구하고 한계를 만나면 팀원들에게 도움을 요청하기를 주저하지 말아야 한다. 평소에 일을 떠넘기는 리더가 아니었다면 팀원들도 그걸 사실 간절히 원하고 리더가 혼자 쓰러지기를 아무도 원하지 않는다. &lt;/p&gt;
&lt;h3 id="7-surface-the-problem"&gt;7. Surface the Problem&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 문제를 드러내기를 주저하지 않는다. 그들은 문제를 드러내는 것에 용감했다. 왜냐하면 문제를 솔직하게 드러내는 것이 문제 해결의 시작이기 때문이다. 실수한 것이 부끄러워서, 문제가 또 다른 문제가 될까봐 문제를 덮어두면 문제는 피노키오의 코 마냥 감당할 수 없을 정도로 점차 커지고 삐뚤어진 방향으로 발현된다. 그뿐아니라 문제를 솔직하게 드러내고 함께 해결하는 경험은 팀 내에 서로를 향한 신뢰를 높인다. 현명한 리더는 문제를 도리어 우리의 결속력을 다지는데 사용한다.&lt;/p&gt;
&lt;h3 id="8-find-a-way"&gt;8. &lt;strong&gt;Find a Way&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;문제를 해결하는 리더는 수 많은 안되는 이유 가운데 되는 한 가지를 방법을 찾고 팀이 그것에 집중하도록 앞장서 독려한다. 이런 능력은 리더의 정말 중요하고 큰 덕목이라고 생각한다. 반면에 문제를 해결하지 못하는 리더는 안되는 이유에 매몰되고 그것을 여기저기 습관적으로 말하며 팀의 분위기 전체를 해쳐놓는다. &lt;/p&gt;
&lt;h3 id="9-hold-the-course"&gt;9. Hold the Course&lt;/h3&gt;
&lt;p&gt;문제가 해결되지 않을 때 우리는 관리 자체를 하지 않고 뭔가 알아서 잘되길 바라고 있는 경우가 많았다. 경험에 의하면 프로젝트는 가만히 두면 끊임없이 곁 길로 세고 최적의 경로를 벗어나려는 특징을 가지고 있는 것 같다. 그래서 리더는 계속해서 중요한 것과 먼저 해야 하는 것에 팀이 집중하도록 프로젝트를 관리해야 한다. 때로는 매일, 때로는 주 단위로, 때로는 문제가 있을 때마다 팀원들을 만나 관리를 해야 한다. ‘관리’라는 표현에 다소 부정적인 느낌이 있는게 사실이고, 관리하지 않아도 다 함께 목표를 향해 잘 나아가는 이상적인 조직을 꿈꾸지만, 현실의 조직은 정말 관리가 필요하다. 문제를 해결하는 리더는 프로젝트가 최적의 경로로 계속 나아가도록 관리한다. &lt;/p&gt;
&lt;p&gt;지금까지 지난 10년간 봐온 문제를 해결하는 리더들의 특징들 몇 가지를 정리해 보았다. 사실 리더가 되는 데는 연차나 직책 같은 건 중요하지 않다. 만약 스스로 일을 책임지고 해결하려는 사람이라면 누구나 다 리더다. 이 글을 읽는 스스로 자신이 리더라고 생각한다면 문제를 해결하는 데 한 번 쯤 이런 생각들을 고려해 보면 좋을 것 같다. &lt;/p&gt;
</summary>
    <title>문제를 해결하는 리더의 모습 9가지</title>
    <updated>2026-06-11T18:30:25+09:00</updated>
    <dc:date>2026-06-11T18:30:25+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>이경원</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;p&gt;토론토 다운타운 AGO 뒤편에 숨은 비밀 정원 그레인지 파크 — 200년 귀족 저택의 반전 역사부터 AGO 멤버스 라운지, 로컬들의 일상까지 둘러봤어요.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://kyoungwon.me/life/2026/06/13/grange-park-toronto/</id>
    <link href="https://kyoungwon.me/life/2026/06/13/grange-park-toronto/"/>
    <summary type="html">토론토 다운타운 AGO 뒤편에 숨은 비밀 정원 그레인지 파크 — 200년 귀족 저택의 반전 역사부터 AGO 멤버스 라운지, 로컬들의 일상까지 둘러봤어요.</summary>
    <title>토론토 다운타운 속 비밀 정원, 그레인지 파크 (Grange Park)</title>
    <updated>2026-06-13T09:00:00+09:00</updated>
    <dc:date>2026-06-13T09:00:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>cheese10yun</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;p&gt;Claude Code를 사용하다 보면 하단 상태 표시줄(status line)이 기본적으로 제공되는데, 여기에 모델명·컨텍스트 사용률·비용·Git 브랜치 같은 정보를 직접 구성할 수 있습니다. 이 글에서는 statusline이 어떻게 동작하는지 개념을 설명하고, 설정 방법 두 가지를 비교한 뒤, 제가 실제로 사용 중인 커스텀 구성을 소개합니다.&lt;/p&gt;
&lt;p&gt;제가 현재 사용하는 statusline의 출력 예시는 이렇습니다:&lt;/p&gt;
&lt;figure class="highlight plaintext"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;fable 5 ~/L/M/i/Documents/PKM ⎇ main 24.8k [░░░░░░░░] 2% · ↻3h50m ↑32%  ↻4d9h ↑3% $10.32&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;한 줄 안에 모델명, 경로, Git 브랜치, 토큰 수, 컨텍스트 사용률, rate limit 남은 시간, 세션 비용까지 담았습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;
&lt;span id="statuslineiran"&gt;statusline이란?&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#statuslineiran" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Claude Code statusline은 &lt;strong&gt;터미널 하단에 고정 표시되는 커스텀 상태 바&lt;/strong&gt;입니다. Claude Code가 사용자가 지정한 셸 명령을 실행하고, 그 stdout 출력을 그대로 statusline에 렌더링하는 방식으로 동작합니다.&lt;/p&gt;
&lt;h3&gt;
&lt;span id="dongjag-mekeonijeum"&gt;동작 메커니즘&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#dongjag-mekeonijeum" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;Claude Code는 스크립트를 실행할 때 &lt;strong&gt;stdin으로 현재 세션 상태를 JSON 형태로 전달&lt;/strong&gt;합니다. 스크립트는 이 JSON을 파싱해 원하는 값을 추출하고, stdout에 출력하면 그 내용이 statusline에 표시됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;갱신 시점:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어시스턴트 메시지 수신 후&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/compact&lt;/code&gt; 완료 후&lt;/li&gt;
&lt;li&gt;권한 모드 변경 시&lt;/li&gt;
&lt;li&gt;vim 모드 토글 시&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;빠른 연속 변경은 300ms 디바운스로 묶어서 한 번만 실행합니다. 스크립트가 아직 실행 중에 새 갱신이 오면 진행 중인 실행을 취소하고 새로 시작합니다.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;중요&lt;/strong&gt;: statusline은 &lt;strong&gt;로컬에서 실행&lt;/strong&gt;됩니다. API 토큰을 전혀 소비하지 않습니다.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3&gt;
&lt;span id="stdineuro-jeondaldoeneun-juyo-json-pildeu"&gt;stdin으로 전달되는 주요 JSON 필드&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#stdineuro-jeondaldoeneun-juyo-json-pildeu" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;필드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model.id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;모델 ID (예: &lt;code&gt;claude-sonnet-4-6&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model.display_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;모델 표시명 (예: &lt;code&gt;Sonnet 4.6&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;workspace.current_dir&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 작업 디렉토리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context_window.used_percentage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;컨텍스트 윈도우 사용률 (%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context_window.total_input_tokens&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 컨텍스트의 입력 토큰 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context_window.total_output_tokens&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;현재 컨텍스트의 출력 토큰 수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cost.total_cost_usd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;세션 누적 비용 (USD, 클라이언트 추정치)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cost.total_duration_ms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;세션 경과 시간 (ms)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rate_limits.five_hour.used_percentage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5시간 rate limit 사용률&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rate_limits.five_hour.resets_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5시간 윈도우 리셋 시각 (Unix epoch)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rate_limits.seven_day.used_percentage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7일 rate limit 사용률&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rate_limits.seven_day.resets_at&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;7일 윈도우 리셋 시각 (Unix epoch)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;session_id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;세션 고유 ID (캐싱 키로 활용 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;rate_limits&lt;/code&gt;는 Claude.ai Pro/Max 구독자에게만 첫 API 응답 이후 제공됩니다. 없을 수 있는 필드는 &lt;code&gt;// empty&lt;/code&gt;나 &lt;code&gt;// 0&lt;/code&gt; 폴백으로 방어해야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;
&lt;span id="seoljeong-bangbeob-inrain-vs-seukeuribteu-pail"&gt;설정 방법: 인라인 vs 스크립트 파일&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#seoljeong-bangbeob-inrain-vs-seukeuribteu-pail" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;statusline 설정은 &lt;code&gt;~/.claude/settings.json&lt;/code&gt;의 &lt;code&gt;statusLine&lt;/code&gt; 필드로 합니다. 중요한 점은 &lt;strong&gt;&lt;code&gt;type&lt;/code&gt;은 항상 &lt;code&gt;"command"&lt;/code&gt; 하나뿐&lt;/strong&gt;이라는 것입니다. “직접 작성 모드”와 “스크립트 모드”가 별도로 있는 게 아니라, &lt;code&gt;command&lt;/code&gt; 필드에 무엇을 쓰느냐의 차이입니다.&lt;/p&gt;
&lt;h3&gt;
&lt;span id="bangbeob-a-inrain-one-liner"&gt;방법 A: 인라인 one-liner&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#bangbeob-a-inrain-one-liner" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;command&lt;/code&gt;에 셸 명령을 직접 적습니다. &lt;code&gt;jq&lt;/code&gt;를 활용하면 간단한 표시는 한 줄로 충분합니다.&lt;/p&gt;
&lt;figure class="highlight json"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="punctuation"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="attr"&gt;"statusLine"&lt;/span&gt;&lt;span class="punctuation"&gt;:&lt;/span&gt; &lt;span class="punctuation"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="attr"&gt;"type"&lt;/span&gt;&lt;span class="punctuation"&gt;:&lt;/span&gt; &lt;span class="string"&gt;"command"&lt;/span&gt;&lt;span class="punctuation"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="attr"&gt;"command"&lt;/span&gt;&lt;span class="punctuation"&gt;:&lt;/span&gt; &lt;span class="string"&gt;"jq -r '[\"[\", .model.display_name, \"] \", (.context_window.used_percentage // 0 | floor | tostring), \"% context\"] | join(\"\")'"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="punctuation"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="punctuation"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;장점&lt;/strong&gt;: 파일을 따로 만들 필요 없이 바로 시작할 수 있습니다.&lt;br&gt;&lt;strong&gt;단점&lt;/strong&gt;: 명령이 길어지면 settings.json이 지저분해지고, 색상 처리나 조건 분기를 넣기 어렵습니다.&lt;/p&gt;
&lt;h3&gt;
&lt;span id="bangbeob-b-seukeuribteu-pail"&gt;방법 B: 스크립트 파일&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#bangbeob-b-seukeuribteu-pail" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;command&lt;/code&gt;에 스크립트 경로를 적고, 로직은 별도 파일에 작성합니다.&lt;/p&gt;
&lt;figure class="highlight json"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="punctuation"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="attr"&gt;"statusLine"&lt;/span&gt;&lt;span class="punctuation"&gt;:&lt;/span&gt; &lt;span class="punctuation"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="attr"&gt;"type"&lt;/span&gt;&lt;span class="punctuation"&gt;:&lt;/span&gt; &lt;span class="string"&gt;"command"&lt;/span&gt;&lt;span class="punctuation"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="attr"&gt;"command"&lt;/span&gt;&lt;span class="punctuation"&gt;:&lt;/span&gt; &lt;span class="string"&gt;"bash ~/.claude/statusline.sh"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="punctuation"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="punctuation"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;스크립트 파일(&lt;code&gt;~/.claude/statusline.sh&lt;/code&gt;)을 만들고 실행 권한을 부여합니다:&lt;/p&gt;
&lt;figure class="highlight bash"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="built_in"&gt;chmod&lt;/span&gt; +x ~/.claude/statusline.sh&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;&lt;strong&gt;장점&lt;/strong&gt;: 로직이 길어도 관리하기 좋고, 색상·조건 분기·여러 섹션을 깔끔하게 구성할 수 있습니다. Git으로 버전 관리도 됩니다. 샘플 JSON으로 독립적인 테스트도 가능합니다.&lt;br&gt;&lt;strong&gt;단점&lt;/strong&gt;: 파일을 별도로 만들고 관리해야 합니다.&lt;/p&gt;
&lt;p&gt;섹션이 8개 이상인 경우라면 스크립트 방식이 거의 유일한 선택지입니다.&lt;/p&gt;
&lt;h3&gt;
&lt;span id="x2f-statusline-jadong-saengseong-helpeo"&gt;/statusline 자동 생성 헬퍼&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#x2f-statusline-jadong-saengseong-helpeo" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;자연어로 설명하면 Claude Code가 스크립트를 자동 생성하고 settings.json까지 업데이트해 줍니다:&lt;/p&gt;
&lt;figure class="highlight plaintext"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;/statusline show model name and context percentage with a progress bar&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;이것은 별개의 설정 방식이 아니라, 위의 “스크립트 파일 방식”을 자동화해 주는 헬퍼입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;
&lt;span id="nae-statusline-guseong"&gt;내 statusline 구성&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#nae-statusline-guseong" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;h3&gt;
&lt;span id="coejong-culryeog-hyeongtae"&gt;최종 출력 형태&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#coejong-culryeog-hyeongtae" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;figure class="highlight plaintext"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;fable 5 ~/L/M/i/Documents/PKM ⎇ main 24.8k [░░░░░░░░] 2% · ↻3h50m ↑32%  ↻4d9h ↑3% $10.32&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;th&gt;색상&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;모델명 (축약)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fable 5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cyan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;현재 경로 (fish 스타일 축약)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~/L/M/i/Documents/PKM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;yellow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git 브랜치&lt;/td&gt;
&lt;td&gt;&lt;code&gt;⎇ main&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;토큰 사용량&lt;/td&gt;
&lt;td&gt;&lt;code&gt;24.8k&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;blue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;컨텍스트 사용률 바 + %&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[░░░░░░░░] 2%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;사용률에 따라 green/yellow/red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;현재 세션 한도&lt;/td&gt;
&lt;td&gt;&lt;code&gt;↻3h50m ↑32%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;리셋시간 cyan, 사용률 구간별 색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주간 한도&lt;/td&gt;
&lt;td&gt;&lt;code&gt;↻4d9h ↑3%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;리셋시간 yellow, 사용률 구간별 색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 비용&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$10.32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;magenta&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;
&lt;span id="segsyeonbyeol-guhyeon-yido"&gt;섹션별 구현 의도&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#segsyeonbyeol-guhyeon-yido" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;h4&gt;
&lt;span id="modelmyeong-cugyag"&gt;모델명 축약&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#modelmyeong-cugyag" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;model.id&lt;/code&gt;를 &lt;code&gt;sed&lt;/code&gt; 정규식으로 &lt;code&gt;claude-sonnet-4-6&lt;/code&gt; → &lt;code&gt;sonnet-4.6&lt;/code&gt; 형태로 줄입니다. 패턴 매칭에 실패하면(새 네이밍 등) &lt;code&gt;display_name&lt;/code&gt;을 소문자로 변환해 폴백합니다.&lt;/p&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;9&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;abbr=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_id&lt;/span&gt;"&lt;/span&gt; | sed -E \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;'s/claude-([a-z]+)-([0-9]+)-([0-9]+).*/\1-\2.\3/; \&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;   s/claude-([a-z]+-[a-z]+)-([0-9]+)-([0-9]+).*/\1-\2.\3/'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -z &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbr&lt;/span&gt;"&lt;/span&gt; ] || [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbr&lt;/span&gt;"&lt;/span&gt; = &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_id&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  abbr=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_display&lt;/span&gt;"&lt;/span&gt; | sed -E \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="string"&gt;'s/Claude //; s/ ([0-9]+)\.([0-9]+).*/\1.\2/'&lt;/span&gt; | \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="built_in"&gt;tr&lt;/span&gt; &lt;span class="string"&gt;'[:upper:]'&lt;/span&gt; &lt;span class="string"&gt;'[:lower:]'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;모델명이 길면 statusline이 금방 꽉 차므로 최대한 짧게 유지하는 것이 목표입니다. &lt;code&gt;claude-fable-5&lt;/code&gt;처럼 새 네이밍은 폴백 경로를 타서 &lt;code&gt;fable 5&lt;/code&gt;로 표시됩니다.&lt;/p&gt;
&lt;h4&gt;
&lt;span id="fish-shell-seutail-gyeongro-cugyag"&gt;fish shell 스타일 경로 축약&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#fish-shell-seutail-gyeongro-cugyag" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;$HOME&lt;/code&gt;을 &lt;code&gt;~&lt;/code&gt;로 치환한 뒤, awk로 &lt;strong&gt;마지막 2개 세그먼트만 전체 표시하고 나머지는 첫 글자만&lt;/strong&gt; 남깁니다.&lt;/p&gt;
&lt;figure class="highlight plaintext"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;~/Library/Mobile Documents/iCloud~md~obsidian/Documents/PKM&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;→ ~/L/M/i/Documents/PKM&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;iCloud 볼트처럼 경로가 긴 환경에서 공간을 아끼기 위한 처리입니다. fish shell에서 영감을 받았습니다.&lt;/p&gt;
&lt;h4&gt;
&lt;span id="git-beuraenci"&gt;Git 브랜치&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#git-beuraenci" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;git_branch=$(git -C &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; -c core.hooksPath=/dev/null \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  symbolic-ref --short HEAD 2&amp;gt;/dev/null)&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;&lt;code&gt;-c core.hooksPath=/dev/null&lt;/code&gt;을 추가해 git 훅 실행을 차단합니다. statusline은 자주 호출되는데, 훅이 실행되면 의도치 않은 부작용이 생길 수 있습니다. detached HEAD 상태면 &lt;code&gt;rev-parse --short HEAD&lt;/code&gt;로 커밋 해시를 대신 표시합니다. git 저장소가 아닌 디렉토리라면 섹션 자체를 생략합니다.&lt;/p&gt;
&lt;h4&gt;
&lt;span id="tokeun-sayongryang"&gt;토큰 사용량&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#tokeun-sayongryang" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;입력 + 출력 토큰을 합산해 1,000 이상이면 &lt;code&gt;24.8k&lt;/code&gt;처럼 k 단위 소수점 1자리로 포맷합니다.&lt;/p&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;total_tokens=$(( total_in + total_out ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$total_tokens&lt;/span&gt;"&lt;/span&gt; -ge 1000 ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  token_str=$(awk &lt;span class="string"&gt;"BEGIN {printf \"%.1fk\", &lt;span class="variable"&gt;$total_tokens&lt;/span&gt;/1000}"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  token_str=&lt;span class="string"&gt;"&lt;span class="variable"&gt;${total_tokens}&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;h4&gt;
&lt;span id="keontegseuteu-sayongryul-peurogeureseu-ba"&gt;컨텍스트 사용률 프로그레스 바&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#keontegseuteu-sayongryul-peurogeureseu-ba" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;used_percentage&lt;/code&gt;를 8칸 블록 바로 변환합니다. 색상은 사용률 구간별로 다르게 줍니다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0~60%: green &lt;code&gt;[████████]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;61~80%: yellow&lt;/li&gt;
&lt;li&gt;81%+: red&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;7&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$pct_int&lt;/span&gt;"&lt;/span&gt; -le 60 ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  bar_color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_GREEN&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;elif&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$pct_int&lt;/span&gt;"&lt;/span&gt; -le 80 ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  bar_color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_YELLOW&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  bar_color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_RED&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;h4&gt;
&lt;span id="rate-limit-hyeonjae-sesyeon-jugan"&gt;Rate limit (현재 세션·주간)&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#rate-limit-hyeonjae-sesyeon-jugan" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;resets_at&lt;/code&gt;(Unix epoch)에서 현재 시각을 빼 남은 시간을 &lt;code&gt;↻3h50m&lt;/code&gt;, &lt;code&gt;↻4d9h&lt;/code&gt; 형태로 표시하고, 사용률을 &lt;code&gt;↑32%&lt;/code&gt;로 붙입니다.&lt;/p&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;8&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="function"&gt;&lt;span class="title"&gt;format_remaining&lt;/span&gt;&lt;/span&gt;() {&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _rem=$(( &lt;span class="variable"&gt;$1&lt;/span&gt; - $(date +%s) ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_rem&lt;/span&gt;"&lt;/span&gt; -lt 0 ] &amp;amp;&amp;amp; _rem=0&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt;   [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_rem&lt;/span&gt;"&lt;/span&gt; -ge 86400 ]; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%dd%dh'&lt;/span&gt; $(( _rem/&lt;span class="number"&gt;86400&lt;/span&gt; )) $(( _rem%&lt;span class="number"&gt;86400&lt;/span&gt;/&lt;span class="number"&gt;3600&lt;/span&gt; ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;elif&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_rem&lt;/span&gt;"&lt;/span&gt; -ge 3600  ]; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%dh%02dm'&lt;/span&gt; $(( _rem/&lt;span class="number"&gt;3600&lt;/span&gt; )) $(( _rem%&lt;span class="number"&gt;3600&lt;/span&gt;/&lt;span class="number"&gt;60&lt;/span&gt; ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;else&lt;/span&gt;                             &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%dm'&lt;/span&gt; $(( _rem/&lt;span class="number"&gt;60&lt;/span&gt; ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;}&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;p&gt;사용률 색상은 컨텍스트 바와 동일한 60/80% 기준을 &lt;code&gt;usage_color&lt;/code&gt; 함수로 공유해 일관성을 유지합니다. &lt;code&gt;rate_limits&lt;/code&gt; 필드 자체가 없을 수 있으므로(API 키 직접 사용 시 등) &lt;code&gt;// empty&lt;/code&gt;로 처리하고 필드가 없으면 rate limit 섹션을 통째로 생략합니다.&lt;/p&gt;
&lt;h4&gt;
&lt;span id="sesyeon-biyong"&gt;세션 비용&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#sesyeon-biyong" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;cost.total_cost_usd&lt;/code&gt;를 소수점 2자리로 포맷해 &lt;code&gt;$10.32&lt;/code&gt; 형태로 표시합니다. magenta 색상. 비용 필드가 없으면 섹션을 생략합니다.&lt;/p&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;cost_usd=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.cost.total_cost_usd // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cost_usd&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  cost_str=$(awk &lt;span class="string"&gt;"BEGIN {printf \"%.2f\", &lt;span class="variable"&gt;$cost_usd&lt;/span&gt;}"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  cost_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${C_MAGENTA}&lt;/span&gt;\$%s&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cost_str&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;h3&gt;
&lt;span id="seolgye-weoncig"&gt;설계 원칙&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#seolgye-weoncig" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;가볍게&lt;/strong&gt;: statusline은 자주 실행됩니다. 외부 의존성은 &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, &lt;code&gt;git&lt;/code&gt; 정도로 제한합니다.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;방어적으로&lt;/strong&gt;: 모든 필드 추출에 &lt;code&gt;// empty&lt;/code&gt; 또는 &lt;code&gt;// 0&lt;/code&gt; 폴백을 둡니다. 필드가 없는 환경(버전 차이, API 키 직접 사용 등)에서도 오류 없이 동작하고, 해당 섹션만 자연스럽게 생략됩니다.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;일관성&lt;/strong&gt;: 색상 구간 규칙(60%/80% 경계)을 컨텍스트 바와 rate limit이 &lt;code&gt;usage_color&lt;/code&gt; 함수로 공유합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
&lt;span id="jeonce-seukeuribteu"&gt;전체 스크립트&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#jeonce-seukeuribteu" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h3&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;11&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;13&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;14&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;15&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;16&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;17&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;18&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;19&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;20&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;21&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;22&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;23&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;24&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;25&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;26&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;27&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;28&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;29&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;30&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;31&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;32&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;33&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;34&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;35&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;36&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;37&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;38&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;39&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;40&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;41&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;42&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;43&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;44&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;45&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;46&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;47&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;48&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;49&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;50&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;51&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;52&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;53&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;54&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;55&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;56&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;57&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;58&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;59&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;60&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;61&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;62&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;63&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;64&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;65&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;66&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;67&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;68&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;69&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;70&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;71&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;72&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;73&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;74&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;75&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;76&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;77&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;78&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;79&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;80&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;81&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;82&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;83&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;84&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;85&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;86&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;87&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;88&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;89&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;90&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;91&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;92&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;93&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;94&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;95&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;96&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;97&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;98&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;99&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;100&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;101&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;102&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;103&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;104&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;105&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;106&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;107&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;108&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;109&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;110&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;111&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;112&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;113&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;114&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;115&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;116&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;117&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;118&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;119&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;120&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;121&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;122&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;123&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;124&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;125&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;126&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;127&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;128&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;129&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;130&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;131&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;132&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;133&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;134&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;135&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;136&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;137&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;138&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;139&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;140&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;141&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;142&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;143&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;144&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;145&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;146&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;147&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;148&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;149&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;150&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;151&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;152&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;153&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;154&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;155&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;156&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;157&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;158&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;159&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;160&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;161&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;162&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;163&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;164&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;165&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;166&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;167&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;168&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;169&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;170&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;171&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;172&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;173&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;174&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;175&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;176&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;177&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;178&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;179&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;180&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;181&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;182&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;183&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;184&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;185&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;186&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;187&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;188&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;189&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;190&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;191&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;192&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;193&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;194&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;195&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;196&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;197&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;198&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;199&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;200&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;201&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;202&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;203&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;204&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;205&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;206&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;207&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;208&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;209&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;210&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;211&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;212&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;213&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;214&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;215&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="meta"&gt;#!/bin/sh&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# Claude Code status line script — developer edition&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;input=$(&lt;span class="built_in"&gt;cat&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ANSI color codes&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_CYAN=&lt;span class="string"&gt;'\033[36m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_YELLOW=&lt;span class="string"&gt;'\033[33m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_GREEN=&lt;span class="string"&gt;'\033[32m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_RED=&lt;span class="string"&gt;'\033[31m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_BLUE=&lt;span class="string"&gt;'\033[34m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_MAGENTA=&lt;span class="string"&gt;'\033[35m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;C_RESET=&lt;span class="string"&gt;'\033[0m'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 1. Model name (abbreviated) ──────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;model_id=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.model.id // ""'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;model_display=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.model.display_name // ""'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# Build abbreviated name: extract family + version number&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# Examples: claude-sonnet-4-5 → sonnet-4.5, claude-opus-4-6 → opus-4.6&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;abbr=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_id&lt;/span&gt;"&lt;/span&gt; | sed -E \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;'s/claude-([a-z]+)-([0-9]+)-([0-9]+).*/\1-\2.\3/; \&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;   s/claude-([a-z]+-[a-z]+)-([0-9]+)-([0-9]+).*/\1-\2.\3/'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# Fallback to display name if abbr didn't change or is empty&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -z &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbr&lt;/span&gt;"&lt;/span&gt; ] || [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbr&lt;/span&gt;"&lt;/span&gt; = &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_id&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  abbr=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_display&lt;/span&gt;"&lt;/span&gt; | sed -E \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="string"&gt;'s/Claude //; s/ ([0-9]+)\.([0-9]+).*/\1.\2/'&lt;/span&gt; | \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="built_in"&gt;tr&lt;/span&gt; &lt;span class="string"&gt;'[:upper:]'&lt;/span&gt; &lt;span class="string"&gt;'[:lower:]'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;[ -z &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbr&lt;/span&gt;"&lt;/span&gt; ] &amp;amp;&amp;amp; abbr=&lt;span class="string"&gt;"unknown"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;model_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;${C_CYAN}&lt;/span&gt;%s&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbr&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 2. Path (fish shell style: last 2 full, rest first-char only) ─────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;cwd=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.workspace.current_dir // .cwd // ""'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  home=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$HOME&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  cwd_display=&lt;span class="string"&gt;"&lt;span class="variable"&gt;${cwd#$home}&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd_display&lt;/span&gt;"&lt;/span&gt; != &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    cwd_display=&lt;span class="string"&gt;"~&lt;span class="variable"&gt;$cwd_display&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  abbreviated=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd_display&lt;/span&gt;"&lt;/span&gt; | awk &lt;span class="string"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    n = split($0, segs, "/")&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    # Identify prefix and actual segments&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    prefix = ""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    start = 1&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    if (segs[1] == "") { prefix = "/"; start = 2 }&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    # Collect non-empty segments&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    count = 0&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    for (i = start; i &amp;lt;= n; i++) {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      if (segs[i] != "") {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;        count++&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;        parts[count] = segs[i]&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    out = prefix&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    for (i = 1; i &amp;lt;= count; i++) {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      # Keep last 2 segments full; abbreviate the rest to first char&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      if (count - i &amp;gt;= 2) {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;        seg = substr(parts[i], 1, 1)&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      } else {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;        seg = parts[i]&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      if (out == "" || out == "/") out = out seg&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;      else out = out "/" seg&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    print out&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  }'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  path_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${C_YELLOW}&lt;/span&gt;%s&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$abbreviated&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  path_part=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 3. Git branch ────────────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;git_branch=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  git_root=$(git -C &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; -c core.hooksPath=/dev/null \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    rev-parse --show-toplevel 2&amp;gt;/dev/null)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$git_root&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    git_branch=$(git -C &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; -c core.hooksPath=/dev/null \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;      symbolic-ref --short HEAD 2&amp;gt;/dev/null)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="keyword"&gt;if&lt;/span&gt; [ -z &lt;span class="string"&gt;"&lt;span class="variable"&gt;$git_branch&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;      git_branch=$(git -C &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cwd&lt;/span&gt;"&lt;/span&gt; -c core.hooksPath=/dev/null \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;        rev-parse --short HEAD 2&amp;gt;/dev/null)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$git_branch&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;      GIT_ICON=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'\xe2\x8e\x87'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;      branch_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${C_GREEN}&lt;/span&gt;%s %s&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$GIT_ICON&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$git_branch&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;[ -z &lt;span class="string"&gt;"&lt;span class="variable"&gt;$git_branch&lt;/span&gt;"&lt;/span&gt; ] &amp;amp;&amp;amp; branch_part=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 5. Token usage (k, 1 decimal) ────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;total_in=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt;  | jq -r &lt;span class="string"&gt;'.context_window.total_input_tokens // 0'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;total_out=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.context_window.total_output_tokens // 0'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;total_tokens=$(( total_in + total_out ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$total_tokens&lt;/span&gt;"&lt;/span&gt; -ge 1000 ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  token_str=$(awk &lt;span class="string"&gt;"BEGIN {printf \"%.1fk\", &lt;span class="variable"&gt;$total_tokens&lt;/span&gt;/1000}"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  token_str=&lt;span class="string"&gt;"&lt;span class="variable"&gt;${total_tokens}&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;token_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${C_BLUE}&lt;/span&gt;%s&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$token_str&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 6. Context usage progress bar (8 blocks) + percentage ────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;used_pct=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.context_window.used_percentage // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;BLOCK_FULL=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'\xe2\x96\x88'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;BLOCK_EMPTY=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'\xe2\x96\x91'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;BARS=8&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$used_pct&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  pct_int=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"%.0f"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$used_pct&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  filled=$(awk &lt;span class="string"&gt;"BEGIN {n=int(&lt;span class="variable"&gt;$used_pct&lt;/span&gt;*&lt;span class="variable"&gt;$BARS&lt;/span&gt;/100+0.5); if(n&amp;gt;&lt;span class="variable"&gt;$BARS&lt;/span&gt;)n=&lt;span class="variable"&gt;$BARS&lt;/span&gt;; print n}"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  empty=$(( BARS - filled ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  bar=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  i=0&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;while&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$i&lt;/span&gt;"&lt;/span&gt; -lt &lt;span class="string"&gt;"&lt;span class="variable"&gt;$filled&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    bar=&lt;span class="string"&gt;"&lt;span class="variable"&gt;${bar}&lt;/span&gt;&lt;span class="variable"&gt;${BLOCK_FULL}&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    i=$((i + &lt;span class="number"&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  i=0&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;while&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$i&lt;/span&gt;"&lt;/span&gt; -lt &lt;span class="string"&gt;"&lt;span class="variable"&gt;$empty&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    bar=&lt;span class="string"&gt;"&lt;span class="variable"&gt;${bar}&lt;/span&gt;&lt;span class="variable"&gt;${BLOCK_EMPTY}&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    i=$((i + &lt;span class="number"&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="comment"&gt;# Color: 0-60% green, 61-80% yellow, 81%+ red&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$pct_int&lt;/span&gt;"&lt;/span&gt; -le 60 ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    bar_color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_GREEN&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;elif&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$pct_int&lt;/span&gt;"&lt;/span&gt; -le 80 ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    bar_color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_YELLOW&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    bar_color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_RED&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  ctx_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${bar_color}&lt;/span&gt;[%s]&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt; %s%%"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$bar&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$pct_int&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  empty_bar=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  i=0&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;while&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$i&lt;/span&gt;"&lt;/span&gt; -lt &lt;span class="string"&gt;"&lt;span class="variable"&gt;$BARS&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    empty_bar=&lt;span class="string"&gt;"&lt;span class="variable"&gt;${empty_bar}&lt;/span&gt;&lt;span class="variable"&gt;${BLOCK_EMPTY}&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;    i=$((i + &lt;span class="number"&gt;1&lt;/span&gt;))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;done&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  ctx_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${C_GREEN}&lt;/span&gt;[%s]&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt; --"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$empty_bar&lt;/span&gt;"&lt;/span&gt;)%%&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 7·8. Rate limits (5h session + 7d weekly) ────────────────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="function"&gt;&lt;span class="title"&gt;usage_color&lt;/span&gt;&lt;/span&gt;() {&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _pct=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"%.0f"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$1&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt;   [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_pct&lt;/span&gt;"&lt;/span&gt; -le 60 ]; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%s'&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_GREEN&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;elif&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_pct&lt;/span&gt;"&lt;/span&gt; -le 80 ]; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%s'&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_YELLOW&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;else&lt;/span&gt;                           &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%s'&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_RED&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="function"&gt;&lt;span class="title"&gt;format_remaining&lt;/span&gt;&lt;/span&gt;() {&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _rem=$(( &lt;span class="variable"&gt;$1&lt;/span&gt; - $(date +%s) ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_rem&lt;/span&gt;"&lt;/span&gt; -lt 0 ] &amp;amp;&amp;amp; _rem=0&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt;   [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_rem&lt;/span&gt;"&lt;/span&gt; -ge 86400 ]; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%dd%dh'&lt;/span&gt; $(( _rem/&lt;span class="number"&gt;86400&lt;/span&gt; )) $(( _rem%&lt;span class="number"&gt;86400&lt;/span&gt;/&lt;span class="number"&gt;3600&lt;/span&gt; ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;elif&lt;/span&gt; [ &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_rem&lt;/span&gt;"&lt;/span&gt; -ge 3600  ]; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%dh%02dm'&lt;/span&gt; $(( _rem/&lt;span class="number"&gt;3600&lt;/span&gt; )) $(( _rem%&lt;span class="number"&gt;3600&lt;/span&gt;/&lt;span class="number"&gt;60&lt;/span&gt; ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;else&lt;/span&gt;                             &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;'%dm'&lt;/span&gt; $(( _rem/&lt;span class="number"&gt;60&lt;/span&gt; ))&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;session_pct=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt;   | jq -r &lt;span class="string"&gt;'.rate_limits.five_hour.used_percentage // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;session_reset=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.rate_limits.five_hour.resets_at // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;weekly_pct=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt;    | jq -r &lt;span class="string"&gt;'.rate_limits.seven_day.used_percentage // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;weekly_reset=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt;  | jq -r &lt;span class="string"&gt;'.rate_limits.seven_day.resets_at // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="function"&gt;&lt;span class="title"&gt;make_rate_piece&lt;/span&gt;&lt;/span&gt;() {&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _color=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$1&lt;/span&gt;"&lt;/span&gt; _pct=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$2&lt;/span&gt;"&lt;/span&gt; _reset=&lt;span class="string"&gt;"&lt;span class="variable"&gt;$3&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  [ -z &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_pct&lt;/span&gt;"&lt;/span&gt; ] &amp;amp;&amp;amp; &lt;span class="built_in"&gt;return&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _used=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"%.0f"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_pct&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _ucolor=$(usage_color &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_pct&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  _time_str=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_reset&lt;/span&gt;"&lt;/span&gt; ] &amp;amp;&amp;amp; _time_str=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;${_color}&lt;/span&gt;↻%s "&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="subst"&gt;$(format_remaining &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_reset&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"%s&lt;span class="variable"&gt;${_ucolor}&lt;/span&gt;↑%d%%&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_time_str&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$_used&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;sess_piece=$(make_rate_piece &lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_CYAN&lt;/span&gt;"&lt;/span&gt;    &lt;span class="string"&gt;"&lt;span class="variable"&gt;$session_pct&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$session_reset&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;week_piece=$(make_rate_piece &lt;span class="string"&gt;"&lt;span class="variable"&gt;$C_YELLOW&lt;/span&gt;"&lt;/span&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$weekly_pct&lt;/span&gt;"&lt;/span&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$weekly_reset&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;rate_part=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$sess_piece&lt;/span&gt;"&lt;/span&gt; ] &amp;amp;&amp;amp; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$week_piece&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  rate_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" · %s  %s"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$sess_piece&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$week_piece&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;elif&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$sess_piece&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  rate_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" · %s"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$sess_piece&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;elif&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$week_piece&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  rate_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" · %s"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$week_piece&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── 9. Session cost (USD) ────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;cost_usd=$(&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$input&lt;/span&gt;"&lt;/span&gt; | jq -r &lt;span class="string"&gt;'.cost.total_cost_usd // empty'&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;cost_part=&lt;span class="string"&gt;""&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; [ -n &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cost_usd&lt;/span&gt;"&lt;/span&gt; ]; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  cost_str=$(awk &lt;span class="string"&gt;"BEGIN {printf \"%.2f\", &lt;span class="variable"&gt;$cost_usd&lt;/span&gt;}"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  cost_part=$(&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;" &lt;span class="variable"&gt;${C_MAGENTA}&lt;/span&gt;\$%s&lt;span class="variable"&gt;${C_RESET}&lt;/span&gt;"&lt;/span&gt; &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cost_str&lt;/span&gt;"&lt;/span&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="keyword"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="comment"&gt;# ── Output ────────────────────────────────────────────────────────────────────&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="built_in"&gt;printf&lt;/span&gt; &lt;span class="string"&gt;"%s%s%s%s%s%s%s\n"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$model_part&lt;/span&gt;"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$path_part&lt;/span&gt;"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$branch_part&lt;/span&gt;"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$token_part&lt;/span&gt;"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$ctx_part&lt;/span&gt;"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$rate_part&lt;/span&gt;"&lt;/span&gt; \&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;  &lt;span class="string"&gt;"&lt;span class="variable"&gt;$cost_part&lt;/span&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;hr&gt;
&lt;h2&gt;
&lt;span id="teseuteu-bangbeob"&gt;테스트 방법&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#teseuteu-bangbeob" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;스크립트를 수정하거나 새로 만들 때는 샘플 JSON을 파이프로 넘겨서 Claude Code를 열지 않고도 검증할 수 있습니다:&lt;/p&gt;
&lt;figure class="highlight sh"&gt;&lt;table&gt;&lt;tr&gt;
&lt;td class="gutter"&gt;&lt;pre&gt;&lt;span class="line"&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;6&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;7&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;8&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;9&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;10&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;11&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="line"&gt;&lt;span class="built_in"&gt;echo&lt;/span&gt; &lt;span class="string"&gt;'{&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  "model": {"id": "claude-sonnet-4-6", "display_name": "Sonnet 4.6"},&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  "workspace": {"current_dir": "/Users/yun/projects/myapp"},&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  "context_window": {"total_input_tokens": 24000, "total_output_tokens": 800, "used_percentage": 12.5},&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  "cost": {"total_cost_usd": 0.42},&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  "rate_limits": {&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    "five_hour": {"used_percentage": 32, "resets_at": 1750000000},&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;    "seven_day": {"used_percentage": 3, "resets_at": 1750500000}&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;  "session_id": "test-session-abc"&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class="line"&gt;&lt;span class="string"&gt;}'&lt;/span&gt; | bash ~/.claude/statusline.sh&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;&lt;hr&gt;
&lt;h2&gt;
&lt;span id="macimyeo"&gt;마치며&lt;/span&gt;&lt;a href="https://cheese10yun.github.io/claude-code-statusline-custom/#macimyeo" class="header-anchor"&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;statusline 커스텀의 핵심 효용은 &lt;strong&gt;컨텍스트·비용·rate limit을 Claude와 대화하면서 항상 시야에 두는 것&lt;/strong&gt;입니다. 컨텍스트가 80%를 넘으면 바 색깔이 노란색으로 바뀌고, 90%를 넘으면 빨간색이 됩니다. &lt;code&gt;/compact&lt;/code&gt;를 언제 해야 할지 판단하거나, 요금이 얼마나 나왔는지 확인하거나, rate limit 소진 속도를 체크하는 데 유용합니다.&lt;/p&gt;
&lt;p&gt;더 다양한 statusline 구성이 궁금하다면 커뮤니티 프로젝트인 &lt;a href="https://github.com/sirmalloc/ccstatusline"&gt;ccstatusline&lt;/a&gt;이나 &lt;a href="https://github.com/martinemde/starship-claude"&gt;starship-claude&lt;/a&gt;도 참고할 만합니다.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://cheese10yun.github.io/claude-code-statusline-custom/</id>
    <link href="https://cheese10yun.github.io/claude-code-statusline-custom/"/>
    <summary type="html">Claude Code의 Statusline을 커스텀하는 방법에 대해 알아보겠습니다.</summary>
    <title>Claude Code Statusline 커스텀하기</title>
    <updated>2026-06-14T00:00:00+09:00</updated>
    <dc:date>2026-06-14T00:00:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>코드리더</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;p&gt;&lt;figure class="imageblock alignCenter" data-ke-mobilestyle="widthOrigin" data-origin-width="1664" data-origin-height="2554"&gt;&lt;span data-url="https://blog.kakaocdn.net/dn/Kuzin/dJMcabLn7Nh/mf44xL9S8d9Te3gBn5zD1K/img.png" data-phocus="https://blog.kakaocdn.net/dn/Kuzin/dJMcabLn7Nh/mf44xL9S8d9Te3gBn5zD1K/img.png"&gt;&lt;img src="https://blog.kakaocdn.net/dn/Kuzin/dJMcabLn7Nh/mf44xL9S8d9Te3gBn5zD1K/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKuzin%2FdJMcabLn7Nh%2Fmf44xL9S8d9Te3gBn5zD1K%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" loading="lazy" width="1664" height="2554" data-origin-width="1664" data-origin-height="2554"&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;Anthropic이 제공하는 에이전틱 코딩 도구의 이름은 클로드 코드(Claude Code)입니다. 이때 클로드가 사람 이름인 것을 알고 계셨나요? 클로드는 정보이론의 아버지로 불리우며, 현 디지털 정보 시대의 초석을 놓은 인물로 평가받고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;1916년 미시간에서 태어난 클로드는 어릴때부터 기계와 전기 분야에 재능을 보였다고 합니다. 집에서 무선 조종 비행기, 보트를 만들었고, 800미터 떨어진 친구 집을 철조망으로 연결하여 전신 시스템 비슷한 장치를 만들면서 놀았다고 합니다. 어린 시절 발명왕 토머스 에디슨을 존경했는데, 두사람 모두 존 오그던의 후손입니다. 발명가의 피가 흐르는 집안이 있는걸까요? &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;1936년 미시건대학교에서 전기공학과 수학을 전공한 클로드는 MIT에서 전기공학 석사과정을 시작합니다. 이듬해 석사학위논문인 '릴레이 및 스위칭 회로의 기호 해석(A Symbolic Analysis of Relay and Switching Circuits)"을 작성했는데, 이 논문은 디지털 공학을 만든 논문으로 평가받고 있습니다. 이 논문 이전에는 전기회로를 설계할 때 숙련된 감각이나 복잡한 물리적 실험에 의존했습니다. 하지만 새넌은 스위치가 닫혀서 전기가 흐르는 상태를 1, 열려서 전기가 흐르지 않는 상태를 0으로 정의합니다. 이는 곧 True/False와 마찬가지라는 뜻이지요. 회로의 연결을 논리 연산으로 치환하여, 직렬연결은 논리곱(AND), 병렬연결은 논리합(OR)연산과 같다는 발견을 통해 복잡한 전기회로를 기호로 이루어진 수식으로 바꿀 수 있음을 보여주었습니다. 불 대수가 전기 회로에 접목되면서 복잡한 수식을 대수법칙으로 간단하게 정리할 수 있게 되었고, 실제 물리적인 회로도 불필요한 스위치와 배선을 제거할 수 있게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;우리가 사용하는 모든 디지털컴퓨터는 전기스위치를 사용하여 논리를 구현하고 있습니다. 섀넌의 연구는 디지털 회로 설계의 기초가 됩니다. 그래서 애니악 개발에 참여했던 허먼은 "디지털 회로 설계를 예술에서 과학으로 바꾸는데 기여한 논문"이라고 평가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;제2차 세계대전중에는 영국의 수학자였던 앨런 튜링을 만나서 독일 해군의 암호 해독 방법을 함께 연구했다고 합니다. 그때 튜링이 범용 튜링 머신 아이디어를 정의한 논문을 섀년에게 보여주었다고 합니다. 섀넌은 벨 연구소에서 암호화에 관련된 몇가지 증명을 수행합니다. 이후 CIA의 특수 암호학 자문 그룹(SCAG)의 일원으로도 활동합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class="imageblock alignCenter" data-ke-mobilestyle="widthOrigin" data-origin-width="727" data-origin-height="1002"&gt;&lt;span data-url="https://blog.kakaocdn.net/dn/6A40z/dJMcabEw03z/uoz4RkniJMDYJzHUGuchp1/img.png" data-phocus="https://blog.kakaocdn.net/dn/6A40z/dJMcabEw03z/uoz4RkniJMDYJzHUGuchp1/img.png" data-alt="외발 자전거를 타면서 저글링하는 클로드 섀넌"&gt;&lt;img src="https://blog.kakaocdn.net/dn/6A40z/dJMcabEw03z/uoz4RkniJMDYJzHUGuchp1/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6A40z%2FdJMcabEw03z%2Fuoz4RkniJMDYJzHUGuchp1%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" loading="lazy" width="727" height="1002" data-origin-width="727" data-origin-height="1002"&gt;&lt;/span&gt;&lt;figcaption&gt;외발 자전거를 타면서 저글링하는 클로드 섀넌&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="color: #0f1419;"&gt;&lt;span style="background-color: #ffffff;"&gt;섀넌은 아내와 함께 테세우스(Theseus)라는 이름의 학습 기계를 설계하여 제작합니다. 이 기계는 미로를 통과하는 기계 쥐의 경로를 추적하면서 학습하여, 미로의 임의 위치에 쥐를 놓으면 미로를 통과하는 최단 경로를 학습하여 빠져나올 수 있게 만든 장치였습니다. 일종의 인공 학습장치로 보입니다. 섀년은 '체스 게임을 위한 컴퓨터 프로그래밍', '컴퓨터와 오토마타'와 같은 인공지능 관련 논문을 여러편 작성했습니다.&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #0f1419;"&gt;&lt;span style="background-color: #ffffff;"&gt;재기발랄한 섀년은 궁극의 기계(Ultimate Machine)를 만들었는데요. 이 장치는 스위치를 켜면, 박스에서 손이 나와서 스위치를 다시 꺼버립니다. 그외에도 저글링 공을 튕겨내는 저글링 로봇, 로마숫자로 계산을 수행하는 트로박(THROBAC) 등을 개발했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;figure data-ke-type="video" data-ke-style="alignCenter" data-video-host="youtube" data-video-url="https://www.youtube.com/watch?v=gNa9v8Z7Rac" data-video-thumbnail="https://scrap.kakaocdn.net/dn/lJL6G/dJMb8QeuLfq/IxtTEs3zlWDuyJpodXj8t0/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360,https://scrap.kakaocdn.net/dn/tNLS5/dJMb8UHXOkj/jL7cPT4KoXGcC1TmsXvJG0/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360,https://scrap.kakaocdn.net/dn/JZMj4/dJMb87N5hBL/3vYXhXGBbWMOrBNZYHKbzK/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360" data-video-width="480" data-video-height="360" data-video-origin-width="480" data-video-origin-height="360" data-ke-mobilestyle="widthContent" data-video-title="The Ultimate Machine - Claude Shannon" data-original-url=""&gt;&lt;iframe src="https://www.youtube.com/embed/gNa9v8Z7Rac" width="480" height="360" frameborder="" allowfullscreen="true"&gt;&lt;/iframe&gt;
&lt;figcaption style="display: none;"&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;p data-ke-size="size16"&gt;섀넌은 투자도 잘한 것으로 알려져 있는데요. 1950년 후반부터 86년까지 그의 포트폴리오를 65년부터 95년까지 워렌버핏의 포트폴리오와 비교해 보면 새년의 수익율이 28%였고, 버핏은 27%였답니다.  섀년의 투자 방법은 현금과 주식을 같은 비율로 구성하고 정기적으로 리밸런싱하면서 주가의 변동성을 활용하는 방법이라고 합니다. 주식 투자는 물리학의 천재 뉴턴도 망했던 분야인데 말이죠.&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;그는 2001년 향년 84세로 세상을 떠났는데, 조각가 유진 다웁(Eugene Daub)에 의해 그의 동상 6개가 만들어졌고,  미시건 대학교, MIT 정보 및 의사결정시스템 연구소, 고향 미시건주 게일로드, UC 샌디에고, 벨연구소, AT&amp;amp;T 섀넌 연구소에 있습니다. AI업체인 앤트로픽은 그를 기려 LLM 이름을 Claude로 짓습니다. &lt;/p&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;blockquote data-ke-style="style3"&gt;정보는 불확실성을 해소하는 열쇠이다.( “Information is the resolution of uncertainty.”)&lt;/blockquote&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;blockquote data-ke-style="style3"&gt;우리는 과거를 알지만 통제할 수 없습니다. 우리는 미래를 통제할 수 있지만, 알 수는 없습니다.&lt;/blockquote&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;blockquote data-ke-style="style3"&gt;저는 응용 분야에는 거의 관심이 없습니다. 오히려 문제의 우아함에 더 관심이 많습니다. 좋은 문제인지, 흥미로운 문제인지에 관심이 갑니다.&lt;/blockquote&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;figure data-ke-type="video" data-ke-style="alignCenter" data-video-host="youtube" data-video-url="https://www.youtube.com/watch?v=z2Whj_nL-x8" data-video-thumbnail="https://scrap.kakaocdn.net/dn/btRVvm/dJMb82MGcNy/vOhtOxIu1Nm412eclYCev1/img.jpg?width=480&amp;amp;height=360&amp;amp;face=315_70_392_154,https://scrap.kakaocdn.net/dn/dAlvra/dJMb87NZC2y/7Rc4mdSKgXqhq64PBvEO91/img.jpg?width=480&amp;amp;height=360&amp;amp;face=315_70_392_154" data-video-width="480" data-video-height="360" data-video-origin-width="480" data-video-origin-height="360" data-ke-mobilestyle="widthContent" data-video-title="University of California Television (UCTV)" data-original-url=""&gt;&lt;iframe src="https://www.youtube.com/embed/z2Whj_nL-x8" width="480" height="360" frameborder="" allowfullscreen="true"&gt;&lt;/iframe&gt;
&lt;figcaption style="display: none;"&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;figure id="og_1781349863242" contenteditable="false" data-ke-type="opengraph" data-ke-align="alignCenter" data-og-type="website" data-og-title="The Bit Player - Claude Shannon documentary film" data-og-description=" " data-og-host="www.youtube.com" data-og-source-url="https://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I" data-og-url="http://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I" data-og-image="https://scrap.kakaocdn.net/dn/NMBp1/dJMb87N5hFc/KGfmCiBXkEzXTTcmLvKMw0/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/qdhcj/dJMb8SpQAyj/8WzuOleSCfMLlwEONnKKo1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/QQBOx/dJMb88e9gZn/MG1w6hmk8kz3OF2JrP1tU1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270"&gt;&lt;a href="https://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I" target="_blank" rel="noopener" data-source-url="https://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I"&gt;
&lt;div class="og-image" style="background-image: url('https://scrap.kakaocdn.net/dn/NMBp1/dJMb87N5hFc/KGfmCiBXkEzXTTcmLvKMw0/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/qdhcj/dJMb8SpQAyj/8WzuOleSCfMLlwEONnKKo1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/QQBOx/dJMb88e9gZn/MG1w6hmk8kz3OF2JrP1tU1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270');"&gt; &lt;/div&gt;
&lt;div class="og-text"&gt;
&lt;p class="og-title" data-ke-size="size16"&gt;The Bit Player - Claude Shannon documentary film&lt;/p&gt;
&lt;p class="og-desc" data-ke-size="size16"&gt; &lt;/p&gt;
&lt;p class="og-host" data-ke-size="size16"&gt;www.youtube.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;figure id="og_1781350540367" contenteditable="false" data-ke-type="opengraph" data-ke-align="alignCenter" data-og-type="website" data-og-title="수학적 커뮤니케이션 이론 | 클로드 섀넌 - 교보문고" data-og-description="수학적 커뮤니케이션 이론 | 『수학적 커뮤니케이션 이론』은 인간과 사회의 커뮤니케이션 과정을 수학으로 설명할 수 있다고 주장하는 최초의 언론학 모형이다. 커뮤니케이션 과정을 어떻게 " data-og-host="product.kyobobook.co.kr" data-og-source-url="https://product.kyobobook.co.kr/detail/S000001684851" data-og-url="https://product.kyobobook.co.kr/detail/S000001684851" data-og-image="https://scrap.kakaocdn.net/dn/cjD3zs/dJMb86Pajue/HS0qtawHuQIRjlth2kHoFK/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670,https://scrap.kakaocdn.net/dn/I9CvK/dJMb8Xkn148/7Q9PKAmDvaEeik2t1NvH8K/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670"&gt;&lt;a href="https://product.kyobobook.co.kr/detail/S000001684851" target="_blank" rel="noopener" data-source-url="https://product.kyobobook.co.kr/detail/S000001684851"&gt;
&lt;div class="og-image" style="background-image: url('https://scrap.kakaocdn.net/dn/cjD3zs/dJMb86Pajue/HS0qtawHuQIRjlth2kHoFK/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670,https://scrap.kakaocdn.net/dn/I9CvK/dJMb8Xkn148/7Q9PKAmDvaEeik2t1NvH8K/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670');"&gt; &lt;/div&gt;
&lt;div class="og-text"&gt;
&lt;p class="og-title" data-ke-size="size16"&gt;수학적 커뮤니케이션 이론 | 클로드 섀넌 - 교보문고&lt;/p&gt;
&lt;p class="og-desc" data-ke-size="size16"&gt;수학적 커뮤니케이션 이론 | 『수학적 커뮤니케이션 이론』은 인간과 사회의 커뮤니케이션 과정을 수학으로 설명할 수 있다고 주장하는 최초의 언론학 모형이다. 커뮤니케이션 과정을 어떻게&lt;/p&gt;
&lt;p class="og-host" data-ke-size="size16"&gt;product.kyobobook.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt; &lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://neozest2.tistory.com/entry/Claude-Shannon</id>
    <link href="https://neozest2.tistory.com/entry/Claude-Shannon"/>
    <summary type="html">&lt;p&gt;&lt;figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="1664" data-origin-height="2554"&gt;&lt;span data-url="https://blog.kakaocdn.net/dn/Kuzin/dJMcabLn7Nh/mf44xL9S8d9Te3gBn5zD1K/img.png" data-phocus="https://blog.kakaocdn.net/dn/Kuzin/dJMcabLn7Nh/mf44xL9S8d9Te3gBn5zD1K/img.png"&gt;&lt;img src="https://blog.kakaocdn.net/dn/Kuzin/dJMcabLn7Nh/mf44xL9S8d9Te3gBn5zD1K/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKuzin%2FdJMcabLn7Nh%2Fmf44xL9S8d9Te3gBn5zD1K%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" loading="lazy" width="1664" height="2554" data-origin-width="1664" data-origin-height="2554"/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;Anthropic이 제공하는 에이전틱 코딩 도구의 이름은 클로드 코드(Claude Code)입니다. 이때 클로드가 사람 이름인 것을 알고 계셨나요? 클로드는 정보이론의 아버지로 불리우며, 현 디지털 정보 시대의 초석을 놓은 인물로 평가받고 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;1916년 미시간에서 태어난 클로드는 어릴때부터 기계와 전기 분야에 재능을 보였다고 합니다. 집에서 무선 조종 비행기, 보트를 만들었고, 800미터 떨어진 친구 집을 철조망으로 연결하여 전신 시스템 비슷한 장치를 만들면서 놀았다고 합니다. 어린 시절 발명왕 토머스 에디슨을 존경했는데, 두사람 모두 존 오그던의 후손입니다. 발명가의 피가 흐르는 집안이 있는걸까요?&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;1936년 미시건대학교에서 전기공학과 수학을 전공한 클로드는 MIT에서 전기공학 석사과정을 시작합니다. 이듬해 석사학위논문인 '릴레이 및 스위칭 회로의 기호 해석(A Symbolic Analysis of Relay and Switching Circuits)"을 작성했는데, 이 논문은 디지털 공학을 만든 논문으로 평가받고 있습니다. 이 논문 이전에는 전기회로를 설계할 때 숙련된 감각이나 복잡한 물리적 실험에 의존했습니다. 하지만 새넌은 스위치가 닫혀서 전기가 흐르는 상태를 1, 열려서 전기가 흐르지 않는 상태를 0으로 정의합니다. 이는 곧 True/False와 마찬가지라는 뜻이지요. 회로의 연결을 논리 연산으로 치환하여, 직렬연결은 논리곱(AND), 병렬연결은 논리합(OR)연산과 같다는 발견을 통해 복잡한 전기회로를 기호로 이루어진 수식으로 바꿀 수 있음을 보여주었습니다. 불 대수가 전기 회로에 접목되면서 복잡한 수식을 대수법칙으로 간단하게 정리할 수 있게 되었고, 실제 물리적인 회로도 불필요한 스위치와 배선을 제거할 수 있게 되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;우리가 사용하는 모든 디지털컴퓨터는 전기스위치를 사용하여 논리를 구현하고 있습니다. 섀넌의 연구는 디지털 회로 설계의 기초가 됩니다. 그래서 애니악 개발에 참여했던 허먼은 "디지털 회로 설계를 예술에서 과학으로 바꾸는데 기여한 논문"이라고 평가합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="background-color: #ffffff; color: #0f1419; text-align: start;"&gt;제2차 세계대전중에는 영국의 수학자였던 앨런 튜링을 만나서 독일 해군의 암호 해독 방법을 함께 연구했다고 합니다. 그때 튜링이 범용 튜링 머신 아이디어를 정의한 논문을 섀년에게 보여주었다고 합니다. 섀넌은 벨 연구소에서 암호화에 관련된 몇가지 증명을 수행합니다. 이후 CIA의 특수 암호학 자문 그룹(SCAG)의 일원으로도 활동합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class="imageblock alignCenter" data-ke-mobileStyle="widthOrigin" data-origin-width="727" data-origin-height="1002"&gt;&lt;span data-url="https://blog.kakaocdn.net/dn/6A40z/dJMcabEw03z/uoz4RkniJMDYJzHUGuchp1/img.png" data-phocus="https://blog.kakaocdn.net/dn/6A40z/dJMcabEw03z/uoz4RkniJMDYJzHUGuchp1/img.png" data-alt="외발 자전거를 타면서 저글링하는 클로드 섀넌"&gt;&lt;img src="https://blog.kakaocdn.net/dn/6A40z/dJMcabEw03z/uoz4RkniJMDYJzHUGuchp1/img.png" srcset="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6A40z%2FdJMcabEw03z%2Fuoz4RkniJMDYJzHUGuchp1%2Fimg.png" onerror="this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';" loading="lazy" width="727" height="1002" data-origin-width="727" data-origin-height="1002"/&gt;&lt;/span&gt;&lt;figcaption&gt;외발 자전거를 타면서 저글링하는 클로드 섀넌&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&lt;span style="color: #0f1419;"&gt;&lt;span style="background-color: #ffffff;"&gt;섀넌은 아내와 함께 테세우스(Theseus)라는 이름의 학습 기계를 설계하여 제작합니다. 이 기계는 미로를 통과하는 기계 쥐의 경로를 추적하면서 학습하여, 미로의 임의 위치에 쥐를 놓으면 미로를 통과하는 최단 경로를 학습하여 빠져나올 수 있게 만든 장치였습니다. 일종의 인공 학습장치로 보입니다. 섀년은 '체스 게임을 위한 컴퓨터 프로그래밍', '컴퓨터와 오토마타'와 같은 인공지능 관련 논문을 여러편 작성했습니다.&lt;/span&gt;&lt;/span&gt;&lt;span style="color: #0f1419;"&gt;&lt;span style="background-color: #ffffff;"&gt;재기발랄한 섀년은 궁극의 기계(Ultimate Machine)를 만들었는데요. 이 장치는 스위치를 켜면, 박스에서 손이 나와서 스위치를 다시 꺼버립니다. 그외에도 저글링 공을 튕겨내는 저글링 로봇, 로마숫자로 계산을 수행하는 트로박(THROBAC) 등을 개발했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type="video" data-ke-style="alignCenter" data-video-host="youtube" data-video-url="https://www.youtube.com/watch?v=gNa9v8Z7Rac" data-video-thumbnail="https://scrap.kakaocdn.net/dn/lJL6G/dJMb8QeuLfq/IxtTEs3zlWDuyJpodXj8t0/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360,https://scrap.kakaocdn.net/dn/tNLS5/dJMb8UHXOkj/jL7cPT4KoXGcC1TmsXvJG0/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360,https://scrap.kakaocdn.net/dn/JZMj4/dJMb87N5hBL/3vYXhXGBbWMOrBNZYHKbzK/img.jpg?width=480&amp;amp;height=360&amp;amp;face=0_0_480_360" data-video-width="480" data-video-height="360" data-video-origin-width="480" data-video-origin-height="360" data-ke-mobilestyle="widthContent" data-video-title="The Ultimate Machine - Claude Shannon" data-original-url=""&gt;&lt;iframe src="https://www.youtube.com/embed/gNa9v8Z7Rac" width="480" height="360" frameborder="" allowfullscreen="true"&gt;&lt;/iframe&gt;
&lt;figcaption style="display: none;"&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;섀넌은 투자도 잘한 것으로 알려져 있는데요. 1950년 후반부터 86년까지 그의 포트폴리오를 65년부터 95년까지 워렌버핏의 포트폴리오와 비교해 보면 새년의 수익율이 28%였고, 버핏은 27%였답니다.&amp;nbsp; 섀년의 투자 방법은 현금과 주식을 같은 비율로 구성하고 정기적으로 리밸런싱하면서 주가의 변동성을 활용하는 방법이라고 합니다. 주식 투자는 물리학의 천재 뉴턴도 망했던 분야인데 말이죠.&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;그는 2001년 향년 84세로 세상을 떠났는데, 조각가 유진 다웁(Eugene Daub)에 의해 그의 동상 6개가 만들어졌고,&amp;nbsp; 미시건 대학교, MIT 정보 및 의사결정시스템 연구소, 고향 미시건주 게일로드, UC 샌디에고, 벨연구소, AT&amp;amp;T 섀넌 연구소에 있습니다. AI업체인 앤트로픽은 그를 기려 LLM 이름을 Claude로 짓습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style="style3"&gt;정보는 불확실성을 해소하는 열쇠이다.( &amp;ldquo;Information is the resolution of uncertainty.&amp;rdquo;)&lt;/blockquote&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style="style3"&gt;우리는 과거를 알지만 통제할 수 없습니다. 우리는 미래를 통제할 수 있지만, 알 수는 없습니다.&lt;/blockquote&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style="style3"&gt;저는 응용 분야에는 거의 관심이 없습니다. 오히려 문제의 우아함에 더 관심이 많습니다. 좋은 문제인지, 흥미로운 문제인지에 관심이 갑니다.&lt;/blockquote&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type="video" data-ke-style="alignCenter" data-video-host="youtube" data-video-url="https://www.youtube.com/watch?v=z2Whj_nL-x8" data-video-thumbnail="https://scrap.kakaocdn.net/dn/btRVvm/dJMb82MGcNy/vOhtOxIu1Nm412eclYCev1/img.jpg?width=480&amp;amp;height=360&amp;amp;face=315_70_392_154,https://scrap.kakaocdn.net/dn/dAlvra/dJMb87NZC2y/7Rc4mdSKgXqhq64PBvEO91/img.jpg?width=480&amp;amp;height=360&amp;amp;face=315_70_392_154" data-video-width="480" data-video-height="360" data-video-origin-width="480" data-video-origin-height="360" data-ke-mobilestyle="widthContent" data-video-title="University of California Television (UCTV)" data-original-url=""&gt;&lt;iframe src="https://www.youtube.com/embed/z2Whj_nL-x8" width="480" height="360" frameborder="" allowfullscreen="true"&gt;&lt;/iframe&gt;
&lt;figcaption style="display: none;"&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id="og_1781349863242" contenteditable="false" data-ke-type="opengraph" data-ke-align="alignCenter" data-og-type="website" data-og-title="The Bit Player - Claude Shannon documentary film" data-og-description=" " data-og-host="www.youtube.com" data-og-source-url="https://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I" data-og-url="http://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I" data-og-image="https://scrap.kakaocdn.net/dn/NMBp1/dJMb87N5hFc/KGfmCiBXkEzXTTcmLvKMw0/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/qdhcj/dJMb8SpQAyj/8WzuOleSCfMLlwEONnKKo1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/QQBOx/dJMb88e9gZn/MG1w6hmk8kz3OF2JrP1tU1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270"&gt;&lt;a href="https://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I" target="_blank" rel="noopener" data-source-url="https://www.youtube.com/playlist?list=PLfMzjeGTdcau7SPsnLiYUE8uBZw-OoV5I"&gt;
&lt;div class="og-image" style="background-image: url('https://scrap.kakaocdn.net/dn/NMBp1/dJMb87N5hFc/KGfmCiBXkEzXTTcmLvKMw0/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/qdhcj/dJMb8SpQAyj/8WzuOleSCfMLlwEONnKKo1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270,https://scrap.kakaocdn.net/dn/QQBOx/dJMb88e9gZn/MG1w6hmk8kz3OF2JrP1tU1/img.jpg?width=480&amp;amp;height=270&amp;amp;face=0_0_480_270');"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class="og-text"&gt;
&lt;p class="og-title" data-ke-size="size16"&gt;The Bit Player - Claude Shannon documentary film&lt;/p&gt;
&lt;p class="og-desc" data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class="og-host" data-ke-size="size16"&gt;www.youtube.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id="og_1781350540367" contenteditable="false" data-ke-type="opengraph" data-ke-align="alignCenter" data-og-type="website" data-og-title="수학적 커뮤니케이션 이론 | 클로드 섀넌 - 교보문고" data-og-description="수학적 커뮤니케이션 이론 | 『수학적 커뮤니케이션 이론』은 인간과 사회의 커뮤니케이션 과정을 수학으로 설명할 수 있다고 주장하는 최초의 언론학 모형이다. 커뮤니케이션 과정을 어떻게 " data-og-host="product.kyobobook.co.kr" data-og-source-url="https://product.kyobobook.co.kr/detail/S000001684851" data-og-url="https://product.kyobobook.co.kr/detail/S000001684851" data-og-image="https://scrap.kakaocdn.net/dn/cjD3zs/dJMb86Pajue/HS0qtawHuQIRjlth2kHoFK/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670,https://scrap.kakaocdn.net/dn/I9CvK/dJMb8Xkn148/7Q9PKAmDvaEeik2t1NvH8K/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670"&gt;&lt;a href="https://product.kyobobook.co.kr/detail/S000001684851" target="_blank" rel="noopener" data-source-url="https://product.kyobobook.co.kr/detail/S000001684851"&gt;
&lt;div class="og-image" style="background-image: url('https://scrap.kakaocdn.net/dn/cjD3zs/dJMb86Pajue/HS0qtawHuQIRjlth2kHoFK/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670,https://scrap.kakaocdn.net/dn/I9CvK/dJMb8Xkn148/7Q9PKAmDvaEeik2t1NvH8K/img.jpg?width=458&amp;amp;height=670&amp;amp;face=0_0_458_670');"&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class="og-text"&gt;
&lt;p class="og-title" data-ke-size="size16"&gt;수학적 커뮤니케이션 이론 | 클로드 섀넌 - 교보문고&lt;/p&gt;
&lt;p class="og-desc" data-ke-size="size16"&gt;수학적 커뮤니케이션 이론 | 『수학적 커뮤니케이션 이론』은 인간과 사회의 커뮤니케이션 과정을 수학으로 설명할 수 있다고 주장하는 최초의 언론학 모형이다. 커뮤니케이션 과정을 어떻게&lt;/p&gt;
&lt;p class="og-host" data-ke-size="size16"&gt;product.kyobobook.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size="size16"&gt;&amp;nbsp;&lt;/p&gt;</summary>
    <title>디지털 시대의 아버지, 클로드 섀넌(Claude Shannon)</title>
    <updated>2026-06-15T00:00:45+09:00</updated>
    <dc:date>2026-06-15T00:00:45+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>Pluu</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;div class="youtube"&gt;
    &lt;iframe width="560" height="315" src="https://www.youtube.com/embed/8PxuWdjESfg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;!--more--&gt;

&lt;hr&gt;

&lt;h1 id="compose-first"&gt;Compose First&lt;/h1&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/develop/ui/compose/images/compose-first.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compose는 Android UI 개발의 표준으로 성숙&lt;/li&gt;
  &lt;li&gt;모든 안드로이드 UI를 &lt;code class="language-plaintext highlighter-rouge"&gt;Jetpack Compose&lt;/code&gt;로 구축하는 &lt;code class="language-plaintext highlighter-rouge"&gt;Compose First&lt;/code&gt; 원칙을 발표&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;goo.gle/compose-first&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;이후 모든 API, 라이브러리, Tool, 가이드는 Compose로 제공된다. 기존 &lt;code class="language-plaintext highlighter-rouge"&gt;View 컴포넌트(Fragment, RecyclerView, Material View 컴포넌트 등)는 유지 보수 모드로 전환&lt;/code&gt;되며, 앞으로 새로운 기능 추가 없이 버그 수정만 제공된다고 한다.
    &lt;ul&gt;
      &lt;li&gt;당장 View 컴포넌트를 지원 중단(Deprecated)하거나 제거할 계획은 없음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose로-마이그레이션"&gt;Compose로 마이그레이션&lt;/h2&gt;

&lt;p&gt;XML을 Compose로 변환을 돕는 Skill외에도 Android Studio에 기능을 준비 중이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;프로젝트 정보를 기반으로 AI 에이전트로 UI 변화가 이루어짐&lt;/li&gt;
  &lt;li&gt;레이아웃이 참조하는 스타일, 리소스를 확인한 후 마이그레이션 전후를 비교할 수 있는 스크린샷 데스트를 생성해 줌&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose-111"&gt;Compose 1.11&lt;/h2&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/01.png"&gt;&lt;/p&gt;

&lt;p&gt;Compose 1.10 및 1.11에서 Retain, 테스트 API, SharedTransitionLayout, 새로운 TextField 기능이 추가되었다.&lt;/p&gt;

&lt;h2 id="new-styles-api"&gt;New Styles API&lt;/h2&gt;

&lt;p&gt;컴포넌트의 스타일 특성을 표준화된 세트로 정의해 컴포넌트의 동작과 외관을 분리되었다. 컴포넌트 스타일을 쉽게 커스텀 할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/02.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;상태 지원&lt;/li&gt;
  &lt;li&gt;상태 변경 애니메이션&lt;/li&gt;
  &lt;li&gt;성능 최적화가 적용되어 Recomposition을 최소화&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;향후 Material 컴포넌트에도 Style 지원 계획이다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Styles in Compose : https://developer.android.com/develop/ui/compose/styles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/03.png"&gt;&lt;/p&gt;

&lt;h3 id="hero-benchmarks"&gt;Hero benchmarks&lt;/h3&gt;

&lt;p&gt;최신 Compose 1.11에서는 스크롤 버벅임(Jank), Startup, View와 Compose가 공존하는 하이브리드 UI 성능이 향상되었다.&lt;/p&gt;

&lt;p&gt;실제 앱 성능을 비교하는 새로운 벤치마크 제품을 오픈소스로 출시&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hero benchmarks: http://goo.gle/hero-benchmark&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="성능-최적화-및-디버깅-도구"&gt;성능 최적화 및 디버깅 도구&lt;/h1&gt;

&lt;h2 id="r8-configuration-analyzer"&gt;R8 configuration analyzer&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;새로운 R8 인사이트 도구를 Play console에 순차적으로 출시 예정&lt;/li&gt;
  &lt;li&gt;Android Studio에서도 확인할 수 있는 R8 configuration analyzer를 출시함. 최적화, 난독화, 리소스 축소의 효율성을 점수로 노출&lt;/li&gt;
  &lt;li&gt;AI Agent가 R8과 연동할 수 있는 새로운 Skill도 출시할 계획&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/04.png"&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Use R8 Configuration Analyzer : http://goo.gle/r8-analyzer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="안드로이드-17의-메모리-관리-강화"&gt;안드로이드 17의 메모리 관리 강화&lt;/h1&gt;

&lt;h2 id="메모리-제한memory-limits"&gt;메모리 제한(Memory limits)&lt;/h2&gt;

&lt;p&gt;안드로이드 17은 메모리 누수 등으로 리소스를 과도하게 사용하는 앱에 영향을 주는 메모리 제한(Memory limits)을 도입합니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/05.png"&gt;&lt;/p&gt;

&lt;p&gt;실제로 앱이 메모리 제한에 영향을 받은 경우, 애플리케이션 종료 정보(exitinfo)에 메모리 제한에 대한 문자열이 포함된다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/06.png"&gt;&lt;/p&gt;

&lt;p&gt;ProfilingManager API에 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_anomaly"&gt;TRIGGER_TYPE_ANOMALY&lt;/a&gt;또는 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_oom"&gt;TRIGGER_TYPE_OOM&lt;/a&gt; 타입의 프로파일링 트리거가 있다. Heapdump를 얻어 메모리 문제를 진단하고 해결할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Trigger-based profiling : https://developer.android.com/topic/performance/tracing/profiling-manager/trigger-based-capture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-studio"&gt;Android Studio&lt;/h2&gt;

&lt;p&gt;안드로이드 스튜디오의 프로파일러에 LeakCanary가 통합되어 Gemini AI를 통해 메모리 누수 원인과 수정 제안을 받을 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/studio/preview/features/images/leakcanary-task.png"&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;이미지 출처 : https://developer.android.com/studio/preview/features#leakcanary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-17"&gt;Android 17&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;CustomView가 포함된 알림의 이미지 크기를 제한하여, 특정 크기를 초과하면 이미지를 제거한다.&lt;/li&gt;
  &lt;li&gt;ART에서 Young Generation GC를 더 자주 도입한다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/07.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Target Android 17로 지정 시 Reflection을 이용한 Static final field 수정은 불가능해진다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/08.png"&gt;&lt;/p&gt;

&lt;p&gt;고성능과 전력 효율을 위해 Vulkan이 자체 GPU API로 지원하고 있으며, 기존 OpenGL/WebGPU API는 Vulkan 위에 계층적으로 추가된다. 앱/게임에서 OpenGL을 사용 중이라면 ANGLE이 Vulkan으로 변환해준다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/09.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱이 GPU 성능을 활용할 수 있도록&lt;/li&gt;
  &lt;li&gt;Jetpack WebGPU 종속성을 추가하면 된다&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;AndroidX webgpu : https://developer.android.com/jetpack/androidx/releases/webgpu&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/10.png"&gt;&lt;/p&gt;

&lt;p&gt;새로운 Performance Analyzer는 하나의 툴체인으로 통합하여 디버깅을 획기적으로 간소화한다. 트레이스를 로드 및 렌더링하는 속도가 기존 대비 최대 26배 빨라졌다. 독립적인 실행하거나 Studio Profiler 내에서 실행될 수 있다.&lt;/p&gt;

&lt;h1 id="intelligence"&gt;Intelligence&lt;/h1&gt;

&lt;p&gt;Gemini와 같은 Agnet는 여러 앱에 걸쳐 오케스트레이터(Orchestrator) 역할을 할 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini는 앱 화면을 분석/탐색&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="appfunctions"&gt;AppFunctions&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/11.png"&gt;&lt;/p&gt;

&lt;p&gt;AppFunctions은 Android MCP 통합 구축을 간소화하는 Jetpack 라이브러리의 Android 플랫폼 API이다. 이를 통해 앱은 기기 내 MCP 서버처럼 작동할 수 있으며, Gemini와 같은 Client Agent 및 어시스턴트가 사용할 수 있는 도구 역할을 하는 기능을 제공한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini를 통해서 AppFunctions 구현을 쉽게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="language-kotlin highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AppFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDescribedByKDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;searchEmails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EmailSummary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;코드 출처 : https://developer.android.com/ai/appfunctions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="on-device"&gt;On device&lt;/h3&gt;

&lt;p&gt;Gemini Nano와 같은 On Device 모델을 사용하면, 사용자 데이터를 로컬에 보관하고 인터넷 연결 없이 작동하면 거래당 비용도 발생하지 않는다.&lt;/p&gt;

&lt;p&gt;올해 말 Gemma 4를 탐재한 Gemini Nano 4를 사용할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ML Kit GenAI Prompt API : https://developers.google.com/ml-kit/genai/prompt/android&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/12.png"&gt;&lt;/p&gt;

&lt;p&gt;Gemini Cloud 모델은 고급 기능을 갖추고 있으며, &lt;a href="https://firebase.google.com/docs/ai-logic"&gt;Firebase AI Logic&lt;/a&gt;을 통해 Android 앱에서 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/13.png"&gt;&lt;/p&gt;

&lt;p&gt;Cloud 기반 에이전트를 구축하려는 경우, A2UI 프로토콜을 사용하면 클라이언트에 UI를 표시할 수 있다.&lt;/p&gt;

&lt;p&gt;안드로이드용 A2UI를 표시하는 Jetpack Compose Renderer가 곧 출시 예정&lt;/p&gt;

&lt;h1 id="accessibility"&gt;Accessibility&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Compose에서 제스처를 사용해 앱 콘텐츠 크기를 조절하는 가이드가 새로 배포 (Pinch to zoom)&lt;/li&gt;
  &lt;li&gt;사용자가 생성한 콘텐츠 등에서 설명이 누락된 경우, AI를 활용해 이미지 설명을 자동으로 생성&lt;/li&gt;
  &lt;li&gt;새로운 Accessibility Scanner는 명암비가 낮거나 터치 타겟이 너무 작은 일반적인 문제들을 더욱 잘 잡아낸다&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="개인정보-보호-및-보안"&gt;개인정보 보호 및 보안&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/14.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱에서 네이티브 라이브러리를 동적으로 로드할 때 읽기 전용으로 처리&lt;/li&gt;
  &lt;li&gt;OTP가 포함된 메시지에 접근하는 것을 방지하기 위해 3시간 동안 읽기 접근을 지연&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="credential-manager"&gt;Credential Manager&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/15.png"&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;이메일과 전화번호 인증을 제공하며, 기존 비밀번호 사용자를 위해 패스키(Passkeys)를 자동으로 생성해 주어 보안성을 높인다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="access_local_network"&gt;ACCESS_LOCAL_NETWORK&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/16.png"&gt;&lt;/p&gt;

&lt;p&gt;Android 17을 Target으로하는 앱은 스마트 홈 장치 등 로컬 네트워크 장치를 찾으려면 &lt;code class="language-plaintext highlighter-rouge"&gt;ACCESS_LOCAL_NETWORK&lt;/code&gt; 권한이 runtime으로 요구됩니다.&lt;/p&gt;

&lt;h3 id="privacy-preserving-pickers"&gt;Privacy Preserving Pickers&lt;/h3&gt;

&lt;p&gt;앱이 광범위한 전체 권한을 요청하지 않아도 되도록 Picker를 제공합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Output Switcher : 특정 장치에 연결&lt;/li&gt;
  &lt;li&gt;EyeDropper API : 화면의 특정 색상을 선택&lt;/li&gt;
  &lt;li&gt;Contacts Picker : 연락처 내 특정 필드와 특정 연락처에 접근&lt;/li&gt;
  &lt;li&gt;Photo Picker : 그리드 뷰를 지원&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="os-experiences"&gt;OS Experiences&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/17.png"&gt;&lt;/p&gt;

&lt;p&gt;Live Update Notification&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;건강 및 피트니스, 앱, 타이머, 여행 앱에서 사용할 수 있는 미터법 스타일 템플릿을 추가&lt;/li&gt;
  &lt;li&gt;Sementic color API를 사용하여 실시간으로 상태를 전달할 수 있다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/18.png"&gt;&lt;/p&gt;

&lt;p&gt;올해 말 다양한 이모티콘을 업데이트할 예정이다.&lt;/p&gt;

&lt;h1 id="camera--media"&gt;Camera &amp;amp; Media&lt;/h1&gt;

&lt;h3 id="on-device-이미지비디오-강화"&gt;On device 이미지/비디오 강화&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/19.png"&gt;&lt;/p&gt;

&lt;p&gt;기기 내부에서 실행되는 AI를 사용해 오프라인 상태에서도 서버 비용 없이 사진의 화질 개선, 초점 보정(Deblur), 노이즈 제거(Denoise), 업스케일링 등을 처리할 수 있는 라이브러리가 제공됩니다.&lt;/p&gt;

&lt;h3 id="백그라운드-오디오-제한"&gt;백그라운드 오디오 제한&lt;/h3&gt;

&lt;p&gt;사용자가 의도하지 않은 배경 음악이나 소음이 갑자기 재생되는 것을 막기 위해 Android 17은 백그라운드 앱의 오디오 API 사용을 엄격히 제한합니다. (정확한 알람 제외)&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/20.png"&gt;&lt;/p&gt;

&lt;p&gt;새로운 이미지 포맷 지원&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RAW14&lt;/li&gt;
  &lt;li&gt;H.266 VVC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;스트리밍 개선&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;HE-AAC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;카메라 강화&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;제조사별 확장 기능 등&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;차세대 Eclipsa 비디오 포맷이 공식 출시&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;고품질 HDR 재생을 지원&lt;/li&gt;
  &lt;li&gt;ExoPlayer는 추가 설정 없이 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="adaptive"&gt;Adaptive&lt;/h1&gt;

&lt;h3 id="ignored-api"&gt;Ignored API&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/21.png"&gt;&lt;/p&gt;

&lt;p&gt;안드로이드 17부터는 기기의 전체 화면 비율이나 가로/세로 방향을 앱이 임의로 제한(opt-out)할 수 없습니다.&lt;/p&gt;

&lt;p&gt;무시되는 옵션&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;screenOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿resizableActivity&lt;/li&gt;
  &lt;li&gt;﻿﻿minAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿maxAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿setRequestedOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿getRequestedOrientation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="mediaquery-flexbox-grid"&gt;MediaQuery, FlexBox, Grid&lt;/h3&gt;

&lt;p&gt;Compose 1.11에서는 기기 상태를 쿼리하는 MediaQuery와 유연한 요소 배치를 위한 FlexBox, Grid 레이아웃 API가 실험적으로 제공&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MediaQuery : https://developer.android.com/develop/adaptive-apps/guides/mediaquery&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;FlexBox : https://developer.android.com/develop/ui/compose/layouts/adaptive/flexbox&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Grid : https://developer.android.com/develop/ui/compose/layouts/adaptive/grid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/22.png"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/23.png"&gt;&lt;/p&gt;

&lt;h3 id="continue-on"&gt;Continue On&lt;/h3&gt;

&lt;p&gt;한 기기에서 시작한 작업을 다른 기기로 전환하여 작업을 계속할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Continue On : goo.gle/continue-on&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="bubbles"&gt;Bubbles&lt;/h3&gt;

&lt;p&gt;모든 앱에서 화면을 띄울 수 있는 Bubbles 기능이 확대되었으며, 대화면 전용 Bubble bar가 도입되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bubbles : https://developer.android.com/develop/ui/compose/layouts/adaptive/support-bubbles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="widget"&gt;Widget&lt;/h3&gt;

&lt;p&gt;Jetpack Glance를 활용해 위젯을 여러 생태계로 손쉽게 확장할 수 있습니다. 특히 올해는 자동차에 위젯을 제공할 준비를 하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/24.png"&gt;&lt;/p&gt;

&lt;p&gt;Snap scroll API를 사용하여 위젯 애니메이션을 구현할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;SnapScrollMatchHeight : https://developer.android.com/reference/kotlin/androidx/glance/appwidget/lazy/VerticalScrollMode.SnapScrollMatchHeight&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="wear-os-7"&gt;Wear OS 7&lt;/h1&gt;

&lt;p&gt;시스템 플랫폼 개선으로 배터리 수명이 최대 10% 길어집니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/25.png"&gt;&lt;/p&gt;

&lt;p&gt;사용자가 스마트폰에서 미디어를 재생하면 워치에 자동으로 제어 컨트롤이 나타나며, 휴대폰의 실시간 알림이 시계로 브리지 연동됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/26.png"&gt;&lt;/p&gt;

&lt;p&gt;스마트 워치는 연결된 스마트폰의 미디어 출력을 제어하여 스피커에서 헤드폰으로 전환 등을 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/27.png"&gt;&lt;/p&gt;

&lt;p&gt;시계 제조 업체는 스마트폰에서 시계로 실시간 업데이트 알림을 전송하는 기능을 제공할 수 있습니다.&lt;/p&gt;

&lt;h3 id="wear-os-appfunctions"&gt;Wear OS AppFunctions&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Wear OS 6.1 이상&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;제미나이(Gemini)와 같은 AI 에이전트와 연동되는 AppFunctions를 생성할 수 있습니다. 이를 활용하면 에이전트가 사용자를 대신하여 앱 내의 특정 작업 흐름(in-app flows)을 직접 호출하고 실행할 수 있습니다.&lt;/p&gt;

&lt;h3 id="추가-업데이트"&gt;추가 업데이트&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;올해 말 Wear Workout Tracker 앱을 출시 예정&lt;/li&gt;
  &lt;li&gt;Wear OS 1.6용 Compose는 Navigation 3를 지원하며, LocalAmbientModeManager를 통해 기기가 절전모드일 때 컨텐츠를 관리할 수 있다&lt;/li&gt;
  &lt;li&gt;Wear OS 7 Canary Emulator가 Android Studio에서 제공&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="andorid-xr"&gt;Andorid XR&lt;/h1&gt;

&lt;p&gt;몰입형 가상현실과 증강현실(AR) 안경을 지원하는 Android XR SDK Developer Preview 4가 출시됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Updates to the Android XR SDK: Introducing Developer Preview 4 : https://developer.android.com/blog/posts/updates-to-the-android-xr-sdk-introducing-developer-preview-4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jetpack XR SDK 라이브러리가 베타 버전으로 출시될 예정&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="http://pluu.github.io/assets/img/blog/io/io26/whats-new-in-android/28.png"&gt;&lt;/p&gt;

&lt;p&gt;개선 사항&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;대용량 3D 모델을 앱에 포함하는 대신 실시간으로 지오메트리를 생성해 앱 크기를 줄임&lt;/li&gt;
  &lt;li&gt;XR Glasses에 Geospatial API를 도입해 공간 길 찾기를 돕는다&lt;/li&gt;
  &lt;li&gt;GODOT 및 언리얼 엔진에 대한 지원을 확장&lt;/li&gt;
  &lt;li&gt;시각적 및 상호 작용 제약 조건에 맞춰 디자인하는데 사용할 수 있는 컴포넌트 Jetpack Compose Glimmer 개선
    &lt;ul&gt;
      &lt;li&gt;Jetpack Compose Glimmer는 디스플레이 글라스에 최적화된 증강 Android XR 환경을 빌드하기 위한 Compose UI 툴킷&lt;/li&gt;
      &lt;li&gt;Glimmer를 쉽게 추가할 수 있는 Skill도 제공&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Build UI for display glasses with Jetpack Compose Glimmer : https://developer.android.com/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="cars"&gt;Cars&lt;/h1&gt;

&lt;p&gt;Android Auto와 구글이 내장된 차량용 앱간의 호환성을 높여 차량용 앱 개발을 간소화했다.&lt;/p&gt;

&lt;p&gt;단일 코드로 양쪽 플랫폼에 Media Apps Templates를 모두 사용할 수 있으며, 두 플랫폼 모두에서 콘텐츠가 포함된 지도 템플릿과 함께 Google Maps SDK를 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;Car App Library 1.9에서는 두 플랫폼에서 사용할 수 있는 새로운 컴포넌트와 레이아웃을 추가한다.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>http://pluu.github.io/blog/android/io26/2026/06/08/io26-What's_new_in_Android/</id>
    <link href="http://pluu.github.io/blog/android/io26/2026/06/08/io26-What's_new_in_Android/"/>
    <summary type="html">&lt;div class="youtube"&gt;
    &lt;iframe width="560" height="315" src="https://www.youtube.com/embed/8PxuWdjESfg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;!--more--&gt;

&lt;hr /&gt;

&lt;h1 id="compose-first"&gt;Compose First&lt;/h1&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/develop/ui/compose/images/compose-first.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Compose는 Android UI 개발의 표준으로 성숙&lt;/li&gt;
  &lt;li&gt;모든 안드로이드 UI를 &lt;code class="language-plaintext highlighter-rouge"&gt;Jetpack Compose&lt;/code&gt;로 구축하는 &lt;code class="language-plaintext highlighter-rouge"&gt;Compose First&lt;/code&gt; 원칙을 발표&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;goo.gle/compose-first&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;이후 모든 API, 라이브러리, Tool, 가이드는 Compose로 제공된다. 기존 &lt;code class="language-plaintext highlighter-rouge"&gt;View 컴포넌트(Fragment, RecyclerView, Material View 컴포넌트 등)는 유지 보수 모드로 전환&lt;/code&gt;되며, 앞으로 새로운 기능 추가 없이 버그 수정만 제공된다고 한다.
    &lt;ul&gt;
      &lt;li&gt;당장 View 컴포넌트를 지원 중단(Deprecated)하거나 제거할 계획은 없음&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose로-마이그레이션"&gt;Compose로 마이그레이션&lt;/h2&gt;

&lt;p&gt;XML을 Compose로 변환을 돕는 Skill외에도 Android Studio에 기능을 준비 중이다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;프로젝트 정보를 기반으로 AI 에이전트로 UI 변화가 이루어짐&lt;/li&gt;
  &lt;li&gt;레이아웃이 참조하는 스타일, 리소스를 확인한 후 마이그레이션 전후를 비교할 수 있는 스크린샷 데스트를 생성해 줌&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="compose-111"&gt;Compose 1.11&lt;/h2&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/01.png" /&gt;&lt;/p&gt;

&lt;p&gt;Compose 1.10 및 1.11에서 Retain, 테스트 API, SharedTransitionLayout, 새로운 TextField 기능이 추가되었다.&lt;/p&gt;

&lt;h2 id="new-styles-api"&gt;New Styles API&lt;/h2&gt;

&lt;p&gt;컴포넌트의 스타일 특성을 표준화된 세트로 정의해 컴포넌트의 동작과 외관을 분리되었다. 컴포넌트 스타일을 쉽게 커스텀 할 수 있을 것이다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/02.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;상태 지원&lt;/li&gt;
  &lt;li&gt;상태 변경 애니메이션&lt;/li&gt;
  &lt;li&gt;성능 최적화가 적용되어 Recomposition을 최소화&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;향후 Material 컴포넌트에도 Style 지원 계획이다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Styles in Compose : https://developer.android.com/develop/ui/compose/styles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/03.png" /&gt;&lt;/p&gt;

&lt;h3 id="hero-benchmarks"&gt;Hero benchmarks&lt;/h3&gt;

&lt;p&gt;최신 Compose 1.11에서는 스크롤 버벅임(Jank), Startup, View와 Compose가 공존하는 하이브리드 UI 성능이 향상되었다.&lt;/p&gt;

&lt;p&gt;실제 앱 성능을 비교하는 새로운 벤치마크 제품을 오픈소스로 출시&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hero benchmarks: http://goo.gle/hero-benchmark&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="성능-최적화-및-디버깅-도구"&gt;성능 최적화 및 디버깅 도구&lt;/h1&gt;

&lt;h2 id="r8-configuration-analyzer"&gt;R8 configuration analyzer&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;새로운 R8 인사이트 도구를 Play console에 순차적으로 출시 예정&lt;/li&gt;
  &lt;li&gt;Android Studio에서도 확인할 수 있는 R8 configuration analyzer를 출시함. 최적화, 난독화, 리소스 축소의 효율성을 점수로 노출&lt;/li&gt;
  &lt;li&gt;AI Agent가 R8과 연동할 수 있는 새로운 Skill도 출시할 계획&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/04.png" /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Use R8 Configuration Analyzer : http://goo.gle/r8-analyzer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="안드로이드-17의-메모리-관리-강화"&gt;안드로이드 17의 메모리 관리 강화&lt;/h1&gt;

&lt;h2 id="메모리-제한memory-limits"&gt;메모리 제한(Memory limits)&lt;/h2&gt;

&lt;p&gt;안드로이드 17은 메모리 누수 등으로 리소스를 과도하게 사용하는 앱에 영향을 주는 메모리 제한(Memory limits)을 도입합니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/05.png" /&gt;&lt;/p&gt;

&lt;p&gt;실제로 앱이 메모리 제한에 영향을 받은 경우, 애플리케이션 종료 정보(exitinfo)에 메모리 제한에 대한 문자열이 포함된다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/06.png" /&gt;&lt;/p&gt;

&lt;p&gt;ProfilingManager API에 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_anomaly"&gt;TRIGGER_TYPE_ANOMALY&lt;/a&gt;또는 &lt;a href="https://developer.android.com/reference/kotlin/android/os/ProfilingTrigger#trigger_type_oom"&gt;TRIGGER_TYPE_OOM&lt;/a&gt; 타입의 프로파일링 트리거가 있다. Heapdump를 얻어 메모리 문제를 진단하고 해결할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Trigger-based profiling : https://developer.android.com/topic/performance/tracing/profiling-manager/trigger-based-capture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-studio"&gt;Android Studio&lt;/h2&gt;

&lt;p&gt;안드로이드 스튜디오의 프로파일러에 LeakCanary가 통합되어 Gemini AI를 통해 메모리 누수 원인과 수정 제안을 받을 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img src="https://developer.android.com/static/studio/preview/features/images/leakcanary-task.png" /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;이미지 출처 : https://developer.android.com/studio/preview/features#leakcanary&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="android-17"&gt;Android 17&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;CustomView가 포함된 알림의 이미지 크기를 제한하여, 특정 크기를 초과하면 이미지를 제거한다.&lt;/li&gt;
  &lt;li&gt;ART에서 Young Generation GC를 더 자주 도입한다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/07.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Target Android 17로 지정 시 Reflection을 이용한 Static final field 수정은 불가능해진다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/08.png" /&gt;&lt;/p&gt;

&lt;p&gt;고성능과 전력 효율을 위해 Vulkan이 자체 GPU API로 지원하고 있으며, 기존 OpenGL/WebGPU API는 Vulkan 위에 계층적으로 추가된다. 앱/게임에서 OpenGL을 사용 중이라면 ANGLE이 Vulkan으로 변환해준다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/09.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱이 GPU 성능을 활용할 수 있도록&lt;/li&gt;
  &lt;li&gt;Jetpack WebGPU 종속성을 추가하면 된다&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;AndroidX webgpu : https://developer.android.com/jetpack/androidx/releases/webgpu&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/10.png" /&gt;&lt;/p&gt;

&lt;p&gt;새로운 Performance Analyzer는 하나의 툴체인으로 통합하여 디버깅을 획기적으로 간소화한다. 트레이스를 로드 및 렌더링하는 속도가 기존 대비 최대 26배 빨라졌다. 독립적인 실행하거나 Studio Profiler 내에서 실행될 수 있다.&lt;/p&gt;

&lt;h1 id="intelligence"&gt;Intelligence&lt;/h1&gt;

&lt;p&gt;Gemini와 같은 Agnet는 여러 앱에 걸쳐 오케스트레이터(Orchestrator) 역할을 할 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini는 앱 화면을 분석/탐색&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="appfunctions"&gt;AppFunctions&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/11.png" /&gt;&lt;/p&gt;

&lt;p&gt;AppFunctions은 Android MCP 통합 구축을 간소화하는 Jetpack 라이브러리의 Android 플랫폼 API이다. 이를 통해 앱은 기기 내 MCP 서버처럼 작동할 수 있으며, Gemini와 같은 Client Agent 및 어시스턴트가 사용할 수 있는 도구 역할을 하는 기능을 제공한다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Gemini를 통해서 AppFunctions 구현을 쉽게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="language-kotlin highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AppFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isDescribedByKDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;searchEmails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;EmailSummary&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;코드 출처 : https://developer.android.com/ai/appfunctions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="on-device"&gt;On device&lt;/h3&gt;

&lt;p&gt;Gemini Nano와 같은 On Device 모델을 사용하면, 사용자 데이터를 로컬에 보관하고 인터넷 연결 없이 작동하면 거래당 비용도 발생하지 않는다.&lt;/p&gt;

&lt;p&gt;올해 말 Gemma 4를 탐재한 Gemini Nano 4를 사용할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ML Kit GenAI Prompt API : https://developers.google.com/ml-kit/genai/prompt/android&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/12.png" /&gt;&lt;/p&gt;

&lt;p&gt;Gemini Cloud 모델은 고급 기능을 갖추고 있으며, &lt;a href="https://firebase.google.com/docs/ai-logic"&gt;Firebase AI Logic&lt;/a&gt;을 통해 Android 앱에서 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/13.png" /&gt;&lt;/p&gt;

&lt;p&gt;Cloud 기반 에이전트를 구축하려는 경우, A2UI 프로토콜을 사용하면 클라이언트에 UI를 표시할 수 있다.&lt;/p&gt;

&lt;p&gt;안드로이드용 A2UI를 표시하는 Jetpack Compose Renderer가 곧 출시 예정&lt;/p&gt;

&lt;h1 id="accessibility"&gt;Accessibility&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;Compose에서 제스처를 사용해 앱 콘텐츠 크기를 조절하는 가이드가 새로 배포 (Pinch to zoom)&lt;/li&gt;
  &lt;li&gt;사용자가 생성한 콘텐츠 등에서 설명이 누락된 경우, AI를 활용해 이미지 설명을 자동으로 생성&lt;/li&gt;
  &lt;li&gt;새로운 Accessibility Scanner는 명암비가 낮거나 터치 타겟이 너무 작은 일반적인 문제들을 더욱 잘 잡아낸다&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="개인정보-보호-및-보안"&gt;개인정보 보호 및 보안&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/14.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;앱에서 네이티브 라이브러리를 동적으로 로드할 때 읽기 전용으로 처리&lt;/li&gt;
  &lt;li&gt;OTP가 포함된 메시지에 접근하는 것을 방지하기 위해 3시간 동안 읽기 접근을 지연&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="credential-manager"&gt;Credential Manager&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/15.png" /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;이메일과 전화번호 인증을 제공하며, 기존 비밀번호 사용자를 위해 패스키(Passkeys)를 자동으로 생성해 주어 보안성을 높인다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="access_local_network"&gt;ACCESS_LOCAL_NETWORK&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/16.png" /&gt;&lt;/p&gt;

&lt;p&gt;Android 17을 Target으로하는 앱은 스마트 홈 장치 등 로컬 네트워크 장치를 찾으려면 &lt;code class="language-plaintext highlighter-rouge"&gt;ACCESS_LOCAL_NETWORK&lt;/code&gt; 권한이 runtime으로 요구됩니다.&lt;/p&gt;

&lt;h3 id="privacy-preserving-pickers"&gt;Privacy Preserving Pickers&lt;/h3&gt;

&lt;p&gt;앱이 광범위한 전체 권한을 요청하지 않아도 되도록 Picker를 제공합니다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Output Switcher : 특정 장치에 연결&lt;/li&gt;
  &lt;li&gt;EyeDropper API : 화면의 특정 색상을 선택&lt;/li&gt;
  &lt;li&gt;Contacts Picker : 연락처 내 특정 필드와 특정 연락처에 접근&lt;/li&gt;
  &lt;li&gt;Photo Picker : 그리드 뷰를 지원&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="os-experiences"&gt;OS Experiences&lt;/h1&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/17.png" /&gt;&lt;/p&gt;

&lt;p&gt;Live Update Notification&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;건강 및 피트니스, 앱, 타이머, 여행 앱에서 사용할 수 있는 미터법 스타일 템플릿을 추가&lt;/li&gt;
  &lt;li&gt;Sementic color API를 사용하여 실시간으로 상태를 전달할 수 있다&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/18.png" /&gt;&lt;/p&gt;

&lt;p&gt;올해 말 다양한 이모티콘을 업데이트할 예정이다.&lt;/p&gt;

&lt;h1 id="camera--media"&gt;Camera &amp;amp; Media&lt;/h1&gt;

&lt;h3 id="on-device-이미지비디오-강화"&gt;On device 이미지/비디오 강화&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/19.png" /&gt;&lt;/p&gt;

&lt;p&gt;기기 내부에서 실행되는 AI를 사용해 오프라인 상태에서도 서버 비용 없이 사진의 화질 개선, 초점 보정(Deblur), 노이즈 제거(Denoise), 업스케일링 등을 처리할 수 있는 라이브러리가 제공됩니다.&lt;/p&gt;

&lt;h3 id="백그라운드-오디오-제한"&gt;백그라운드 오디오 제한&lt;/h3&gt;

&lt;p&gt;사용자가 의도하지 않은 배경 음악이나 소음이 갑자기 재생되는 것을 막기 위해 Android 17은 백그라운드 앱의 오디오 API 사용을 엄격히 제한합니다. (정확한 알람 제외)&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/20.png" /&gt;&lt;/p&gt;

&lt;p&gt;새로운 이미지 포맷 지원&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;RAW14&lt;/li&gt;
  &lt;li&gt;H.266 VVC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;스트리밍 개선&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;HE-AAC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;카메라 강화&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;제조사별 확장 기능 등&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;차세대 Eclipsa 비디오 포맷이 공식 출시&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;고품질 HDR 재생을 지원&lt;/li&gt;
  &lt;li&gt;ExoPlayer는 추가 설정 없이 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="adaptive"&gt;Adaptive&lt;/h1&gt;

&lt;h3 id="ignored-api"&gt;Ignored API&lt;/h3&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/21.png" /&gt;&lt;/p&gt;

&lt;p&gt;안드로이드 17부터는 기기의 전체 화면 비율이나 가로/세로 방향을 앱이 임의로 제한(opt-out)할 수 없습니다.&lt;/p&gt;

&lt;p&gt;무시되는 옵션&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;screenOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿resizableActivity&lt;/li&gt;
  &lt;li&gt;﻿﻿minAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿maxAspectRatio&lt;/li&gt;
  &lt;li&gt;﻿﻿setRequestedOrientation&lt;/li&gt;
  &lt;li&gt;﻿﻿getRequestedOrientation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="mediaquery-flexbox-grid"&gt;MediaQuery, FlexBox, Grid&lt;/h3&gt;

&lt;p&gt;Compose 1.11에서는 기기 상태를 쿼리하는 MediaQuery와 유연한 요소 배치를 위한 FlexBox, Grid 레이아웃 API가 실험적으로 제공&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;MediaQuery : https://developer.android.com/develop/adaptive-apps/guides/mediaquery&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;FlexBox : https://developer.android.com/develop/ui/compose/layouts/adaptive/flexbox&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Grid : https://developer.android.com/develop/ui/compose/layouts/adaptive/grid&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/22.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/23.png" /&gt;&lt;/p&gt;

&lt;h3 id="continue-on"&gt;Continue On&lt;/h3&gt;

&lt;p&gt;한 기기에서 시작한 작업을 다른 기기로 전환하여 작업을 계속할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Continue On : goo.gle/continue-on&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="bubbles"&gt;Bubbles&lt;/h3&gt;

&lt;p&gt;모든 앱에서 화면을 띄울 수 있는 Bubbles 기능이 확대되었으며, 대화면 전용 Bubble bar가 도입되었습니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bubbles : https://developer.android.com/develop/ui/compose/layouts/adaptive/support-bubbles&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="widget"&gt;Widget&lt;/h3&gt;

&lt;p&gt;Jetpack Glance를 활용해 위젯을 여러 생태계로 손쉽게 확장할 수 있습니다. 특히 올해는 자동차에 위젯을 제공할 준비를 하고 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/24.png" /&gt;&lt;/p&gt;

&lt;p&gt;Snap scroll API를 사용하여 위젯 애니메이션을 구현할 수 있다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;SnapScrollMatchHeight : https://developer.android.com/reference/kotlin/androidx/glance/appwidget/lazy/VerticalScrollMode.SnapScrollMatchHeight&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="wear-os-7"&gt;Wear OS 7&lt;/h1&gt;

&lt;p&gt;시스템 플랫폼 개선으로 배터리 수명이 최대 10% 길어집니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/25.png" /&gt;&lt;/p&gt;

&lt;p&gt;사용자가 스마트폰에서 미디어를 재생하면 워치에 자동으로 제어 컨트롤이 나타나며, 휴대폰의 실시간 알림이 시계로 브리지 연동됩니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/26.png" /&gt;&lt;/p&gt;

&lt;p&gt;스마트 워치는 연결된 스마트폰의 미디어 출력을 제어하여 스피커에서 헤드폰으로 전환 등을 할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/27.png" /&gt;&lt;/p&gt;

&lt;p&gt;시계 제조 업체는 스마트폰에서 시계로 실시간 업데이트 알림을 전송하는 기능을 제공할 수 있습니다.&lt;/p&gt;

&lt;h3 id="wear-os-appfunctions"&gt;Wear OS AppFunctions&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;Wear OS 6.1 이상&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;제미나이(Gemini)와 같은 AI 에이전트와 연동되는 AppFunctions를 생성할 수 있습니다. 이를 활용하면 에이전트가 사용자를 대신하여 앱 내의 특정 작업 흐름(in-app flows)을 직접 호출하고 실행할 수 있습니다.&lt;/p&gt;

&lt;h3 id="추가-업데이트"&gt;추가 업데이트&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;올해 말 Wear Workout Tracker 앱을 출시 예정&lt;/li&gt;
  &lt;li&gt;Wear OS 1.6용 Compose는 Navigation 3를 지원하며, LocalAmbientModeManager를 통해 기기가 절전모드일 때 컨텐츠를 관리할 수 있다&lt;/li&gt;
  &lt;li&gt;Wear OS 7 Canary Emulator가 Android Studio에서 제공&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="andorid-xr"&gt;Andorid XR&lt;/h1&gt;

&lt;p&gt;몰입형 가상현실과 증강현실(AR) 안경을 지원하는 Android XR SDK Developer Preview 4가 출시됩니다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Updates to the Android XR SDK: Introducing Developer Preview 4 : https://developer.android.com/blog/posts/updates-to-the-android-xr-sdk-introducing-developer-preview-4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jetpack XR SDK 라이브러리가 베타 버전으로 출시될 예정&lt;/p&gt;

&lt;p&gt;&lt;img class="img-responsive" src="/assets/img/blog/io/io26/whats-new-in-android/28.png" /&gt;&lt;/p&gt;

&lt;p&gt;개선 사항&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;대용량 3D 모델을 앱에 포함하는 대신 실시간으로 지오메트리를 생성해 앱 크기를 줄임&lt;/li&gt;
  &lt;li&gt;XR Glasses에 Geospatial API를 도입해 공간 길 찾기를 돕는다&lt;/li&gt;
  &lt;li&gt;GODOT 및 언리얼 엔진에 대한 지원을 확장&lt;/li&gt;
  &lt;li&gt;시각적 및 상호 작용 제약 조건에 맞춰 디자인하는데 사용할 수 있는 컴포넌트 Jetpack Compose Glimmer 개선
    &lt;ul&gt;
      &lt;li&gt;Jetpack Compose Glimmer는 디스플레이 글라스에 최적화된 증강 Android XR 환경을 빌드하기 위한 Compose UI 툴킷&lt;/li&gt;
      &lt;li&gt;Glimmer를 쉽게 추가할 수 있는 Skill도 제공&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Build UI for display glasses with Jetpack Compose Glimmer : https://developer.android.com/develop/xr/jetpack-xr-sdk/jetpack-compose-glimmer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id="cars"&gt;Cars&lt;/h1&gt;

&lt;p&gt;Android Auto와 구글이 내장된 차량용 앱간의 호환성을 높여 차량용 앱 개발을 간소화했다.&lt;/p&gt;

&lt;p&gt;단일 코드로 양쪽 플랫폼에 Media Apps Templates를 모두 사용할 수 있으며, 두 플랫폼 모두에서 콘텐츠가 포함된 지도 템플릿과 함께 Google Maps SDK를 사용할 수 있다.&lt;/p&gt;

&lt;p&gt;Car App Library 1.9에서는 두 플랫폼에서 사용할 수 있는 새로운 컴포넌트와 레이아웃을 추가한다.&lt;/p&gt;
</summary>
    <title>Blog: [요약] What's new in Android (Google I/O '26)</title>
    <updated>2026-06-08T23:00:00+09:00</updated>
    <dc:date>2026-06-08T23:00:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>w0nder</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;&lt;p&gt;사람과 함께 일한다는 건 생각보다 어렵다. 일을 시작할 때 우리는 대개 문제를 풀러 모인다. 더 좋은 제품을 만들고 싶고, 더 나은 결과를 내고 싶고, 맡은 몫을 잘 해내고 싶다. 그런데 한동안 일하다 보면, 일을 정말로 어렵게 만드는 건 문제가 아니라 사람이라는 걸 알게 된다. 같은 문제를 보면서도 각자 중요하게 여기는 지점이 다르고, 같은 설명을 듣고도 전혀 다른 결론에 이른다. 그래서 조직에서 일한다는 건 문제를 푸는 일인 동시에, 서로 다른 머릿속을 맞춰 가는 일이기도 하다.
한때 나는 좋은 회의란 가장 논리적인 사람이 나머지를 설득하는 자리라고 생각했다. 근거가 가장 탄탄한 의견이 채택되고, 모두가 거기에 고개를 끄덕이는 과정이라고 믿었다. 지금은 조금 다르게 본다. 기억에 남는 회의들을 떠올려 보면, 이상하게도 누가 이겼는지가 기억나지 않는다. 누구의 안이 통과됐는지조차 흐릿한 경우가 많다. 대신 이런 장면이 남는다. 누군가 말을 하다 잠깐 멈추고 "아, 그러면 이건 안 되겠네요" 하며 자기 말을 스스로 접는다. 그 한마디에서 대화의 방향이 살짝 틀어지고, 거기에 다른 사람의 우려가 얹히고, 비어 있던 자리가 채워지면서, 처음보다 조금 나은 생각이 만들어진다. 회의가 끝날 무렵이면 처음의 의견은 이미 여러 번 모양을 바꾼 뒤다. 누구의 생각이었는지 가려내기 어려울 만큼 서로 섞여 있다. 좋은 회의는 아마 그런 것 같다. 내 생각을 지켜내는 일이 아니라, 같이 생각을 키워 가는 일이다.
그런데 이게 말처럼 쉽지가 않다. 많은 토의를 해온 사람도, 스스로 이성적이라고 생각하는 사람도, 나도 모르게 내면에서는 그렇지 않을 때가 많다. 오래 다듬은 아이디어일수록 비판은 생각에 대한 이야기가 아니라 나를 건드리는 것처럼 느껴진다. 앞에서 말한 것처럼 내가 스스로 '이건 안 되겠다'고 접을 때와, 남이 그렇게 말할 때는 다르다. 회의 전에는 아이디어와 사람을 분리하자, 개인적으로 받아들이지 말자는 말이 반복된다. 그런데 그렇게 말해도, 사람은 감정적으로 반응하기 마련이다. 그 말은 반응을 없애는 방법이 아니다. 반응이 올 수 있다는 걸 알면서도, 과제 중심으로 말하자는 약속에 가깝다. 어쩌면 그럼에도 토의를 계속해야 하기에 꺼내는 말일지도 모른다.
그래서 좋은 토의에는 논리만으로는 부족하다. 내가 맞을 수도 있지만 아닐 수도 있다는 마음, 설득하기 전에 먼저 이해해 보려는 마음, 더 나은 생각이 나타났을 때 내 것을 내려놓을 수 있는 여유가 필요하다. 회의에서 A 기술이 맞다, B는 안 된다고 말할 때도, 나도 그랬다. 그런데 돌이켜보면, 내가 아는 게 진짜 다 아는 건 아니었다. 내 경험이 내 지식의 경계를 그리고, 그 안에서만 주장을 계속했던 경우가 많았다. 그것만 써 봤고, 다른 선택지는 제대로 모르고 있었는데도, 옳다고 믿는 것과 내가 아는 범위 안에서 옳아 보이는 것을 같은 말로 착각하기 쉽다. 그래서 요즘은 주장하기 전에 반대로 생각해 본다. 왜 내가 이쪽을 편들고 있는지, 경험의 편향 때문은 아닌지. 그리고 저 사람은 왜 저런 이야기를 하는지, 그 상황에서 무엇을 보고 말하는 건지. 내가 모르는 쪽에서 다시 짚어 본다.
그런데 더 큰 문제는, 그렇게 강하게 논의했던 것들이 시간이 지나면 의미가 없었던 경우가 많다는 것이다. A로 하든 B로 하든, 이쪽이든 저쪽이든 상관없었던 일이 생각보다 훨씬 많았다. 오히려 그 논의가 업무 진행을 막고, 딜레이만 만들었던 경우도 적지 않았다. 물론 정말로 중요한 결정도 있지만, 차이를 만든 건 선택 자체가 아니라, 실행하고 배우고 고치는 속도였다. 우리는 정답을 알아서 토의하는 게 아니다. 오히려 정답을 모르기 때문에 토의한다. 토의는 정답을 고르기보다, 결정에 앞서 서로의 우려를 꺼내 두고 같이 이해해 두기 위해서다. 그래야 막상 움직일 때 모두가 같은 속도로 갈 수 있다. 완벽한 답보다, 충분히 괜찮은 답을 고르고 빠르게 움직이고 필요하면 다시 손보는 쪽이 더 중요하다.
좋은 팀은 누가 더 옳은지를 증명하기보다 함께 앞으로 나아가는 데 힘 쓰는 곳이다. 함께 일한다는 건 같은 생각을 하게 되는 일이 아니라, 다른 생각을 가진 사람들이 같은 방향을 바라보는 일이다. 충분히 고민해 결정하고, 결정했으면 함께 움직이고, 그 과정에서 배우는 것이다. 어쩌면 좋은 팀이란 늘 정답을 맞히는 팀이 아니라, 함께 배우며 앞으로 나아갈 수 있는 팀인지도 모른다.
&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://w0nder.land/posts/79-%EB%82%B4%EA%B0%80%20%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94%20%EC%A2%8B%EC%9D%80%20%ED%9A%8C%EC%9D%98</id>
    <link href="https://w0nder.land/posts/79-%EB%82%B4%EA%B0%80%20%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94%20%EC%A2%8B%EC%9D%80%20%ED%9A%8C%EC%9D%98"/>
    <summary type="html">사람과 함께 일한다는 건 생각보다 어렵다. 일을 시작할 때 우리는 대개 문제를 풀러 모인다. 더 좋은 제품을 만들고 싶고, 더 나은 결과를 내고 싶고, 맡은 몫을 잘 해내고 싶다. 그런데 한동안 일하다 보면, 일을 정말로 어렵게 만드는 건 문제가 아니라 사람이라는 걸 알게 된다. 같은 문제를 보면서도 각자 중요하게 여기는 지점이 다르고, 같은 설명을 듣고도 전혀 다른 결론에 이른다. 그래서 조직에서 일한다는 건 문제를 푸는 일인 동시에, 서로 다른 머릿속을 맞춰 가는 일이기도 하다.
한때 나는 좋은 회의란 가장 논리적인 사람이 나머지를 설득하는 자리라고 생각했다. 근거가 가장 탄탄한 의견이 채택되고, 모두가 거기에 고개를 끄덕이는 과정이라고 믿었다. 지금은 조금 다르게 본다. 기억에 남는 회의들을 떠올려 보면, 이상하게도 누가 이겼는지가 기억나지 않는다. 누구의 안이 통과됐는지조차 흐릿한 경우가 많다. 대신 이런 장면이 남는다. 누군가 말을 하다 잠깐 멈추고 "아, 그러면 이건 안 되겠네요" 하며 자기 말을 스스로 접는다. 그 한마디에서 대화의 방향이 살짝 틀어지고, 거기에 다른 사람의 우려가 얹히고, 비어 있던 자리가 채워지면서, 처음보다 조금 나은 생각이 만들어진다. 회의가 끝날 무렵이면 처음의 의견은 이미 여러 번 모양을 바꾼 뒤다. 누구의 생각이었는지 가려내기 어려울 만큼 서로 섞여 있다. 좋은 회의는 아마 그런 것 같다. 내 생각을 지켜내는 일이 아니라, 같이 생각을 키워 가는 일이다.
그런데 이게 말처럼 쉽지가 않다. 많은 토의를 해온 사람도, 스스로 이성적이라고 생각하는 사람도, 나도 모르게 내면에서는 그렇지 않을 때가 많다. 오래 다듬은 아이디어일수록 비판은 생각에 대한 이야기가 아니라 나를 건드리는 것처럼 느껴진다. 앞에서 말한 것처럼 내가 스스로 '이건 안 되겠다'고 접을 때와, 남이 그렇게 말할 때는 다르다. 회의 전에는 아이디어와 사람을 분리하자, 개인적으로 받아들이지 말자는 말이 반복된다. 그런데 그렇게 말해도, 사람은 감정적으로 반응하기 마련이다. 그 말은 반응을 없애는 방법이 아니다. 반응이 올 수 있다는 걸 알면서도, 과제 중심으로 말하자는 약속에 가깝다. 어쩌면 그럼에도 토의를 계속해야 하기에 꺼내는 말일지도 모른다.
그래서 좋은 토의에는 논리만으로는 부족하다. 내가 맞을 수도 있지만 아닐 수도 있다는 마음, 설득하기 전에 먼저 이해해 보려는 마음, 더 나은 생각이 나타났을 때 내 것을 내려놓을 수 있는 여유가 필요하다. 회의에서 A 기술이 맞다, B는 안 된다고 말할 때도, 나도 그랬다. 그런데 돌이켜보면, 내가 아는 게 진짜 다 아는 건 아니었다. 내 경험이 내 지식의 경계를 그리고, 그 안에서만 주장을 계속했던 경우가 많았다. 그것만 써 봤고, 다른 선택지는 제대로 모르고 있었는데도, 옳다고 믿는 것과 내가 아는 범위 안에서 옳아 보이는 것을 같은 말로 착각하기 쉽다. 그래서 요즘은 주장하기 전에 반대로 생각해 본다. 왜 내가 이쪽을 편들고 있는지, 경험의 편향 때문은 아닌지. 그리고 저 사람은 왜 저런 이야기를 하는지, 그 상황에서 무엇을 보고 말하는 건지. 내가 모르는 쪽에서 다시 짚어 본다.
그런데 더 큰 문제는, 그렇게 강하게 논의했던 것들이 시간이 지나면 의미가 없었던 경우가 많다는 것이다. A로 하든 B로 하든, 이쪽이든 저쪽이든 상관없었던 일이 생각보다 훨씬 많았다. 오히려 그 논의가 업무 진행을 막고, 딜레이만 만들었던 경우도 적지 않았다. 물론 정말로 중요한 결정도 있지만, 차이를 만든 건 선택 자체가 아니라, 실행하고 배우고 고치는 속도였다. 우리는 정답을 알아서 토의하는 게 아니다. 오히려 정답을 모르기 때문에 토의한다. 토의는 정답을 고르기보다, 결정에 앞서 서로의 우려를 꺼내 두고 같이 이해해 두기 위해서다. 그래야 막상 움직일 때 모두가 같은 속도로 갈 수 있다. 완벽한 답보다, 충분히 괜찮은 답을 고르고 빠르게 움직이고 필요하면 다시 손보는 쪽이 더 중요하다.
좋은 팀은 누가 더 옳은지를 증명하기보다 함께 앞으로 나아가는 데 힘 쓰는 곳이다. 함께 일한다는 건 같은 생각을 하게 되는 일이 아니라, 다른 생각을 가진 사람들이 같은 방향을 바라보는 일이다. 충분히 고민해 결정하고, 결정했으면 함께 움직이고, 그 과정에서 배우는 것이다. 어쩌면 좋은 팀이란 늘 정답을 맞히는 팀이 아니라, 함께 배우며 앞으로 나아갈 수 있는 팀인지도 모른다.
</summary>
    <title>내가 생각하는 좋은 회의</title>
    <updated>2026-06-14T18:00:00+09:00</updated>
    <dc:date>2026-06-14T18:00:00+09:00</dc:date>
  </entry>
  <entry>
    <author>
      <name>신영진</name>
    </author>
    <content type="html">&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"&gt;
&lt;html&gt;&lt;body&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;생성형 인공지능의 가장 큰 문제로 환각을 꼽는다. 말 그대로 생성형?! 이기에 뭐든지 던지기만 하면 생성을 해내는 것이다. 초창기 세종대왕 맥북 사건으로 gpt는 조롱의 대상이 되었다. 지금은 많이 괜찮아졌지만 여전히 환각은 존재한다. 그리고 llm을 실무에 도입할 때 가장 큰 어려움이 환각을 어떻게 없앨까 이기도 하다. 왜냐하면 실상 통제를 할 수 없기 때문이다. 그렇다고 코드로 강제하기도 어려운 게 결국 코드로 안 되는 부분에 llm을 도입하는 문제라 해결이 쉽지 않다.&lt;/p&gt;
&lt;p&gt;그렇다면 인간은 환각이 없을까? 내가 보기엔 더하면 더했지, 절대 덜하지는 않다. 최근 사내 코딩 에이전트를 만들면서 겪게 된 몇 가지 사례를 살펴보면 이렇다.&lt;/p&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;최근 가장 충격적이었던 한 사례는 생성형 인공지능이 수정한 코드에 있었다. 해킹툴 코드에서 시작된 사람이 제출한 pr을 보던 중 에이전트가 더 나은 방법이라고 코드를 다른 방법으로 새로 작성한 것이다. 사람이 작성한 코드는 표면적인 문제를 땜빵하는 형식이었고, 인공지능이 작성한 코드는 보다 근본적인 부분을 해결하는 코드였다. 여기서 내가 놀란 건 이건 표준적인 메커니즘이 아닌 우리 내부에서만 사용되는 방법인데 인공지능이 그 메커니즘을 다 이해해서 알맞게 구현했다는 점이었다. 실로 놀랍기 그지없었다.&lt;/p&gt;
&lt;p&gt;아무튼 문제는 그다음에 있었다. 인공지능이 사람에게 수정한 코드의 테스트를 요청했고, 사람은 테스트를 거부했다. 이유인즉슨 그렇게 해서는 동작하지 않는다는 이유였다. 하지만 여기서도 인공지능은 인내심이 있었다. 나라면 버럭 화라도 냈을 상황이지만 전체 호출 체인이 어떻게 돌아가는지를 일일이 다 설명해 준 것이다. 하지만 사람도 굴하지 않았다. 결국 인공지능이 요청한 테스트를 엉뚱하게 수행해서 잘못된 결과를 얻게 되었고, 그걸로 인공지능에게 그렇게 수정한 건 동작하지 않는다고 뭐라고 한 것이다. 이쯤 되면 인공지능이 이기긴 어렵다. 네 수정하겠습니다, 라면서 삼천포로 빠지는 것이다.&lt;/p&gt;
&lt;p&gt;여기서 이제 삼천포로 빠지기 시작하면 인공지능의 시작은 창대했지만 그 결말은 아주 시궁창인 코드가 된다.&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;정반대 사례도 있다. 이건 사람이 인공지능에 너무 주눅 든 상태거나 인공지능의 결과물을 판단할 능력이 되지 않을 때 주로 발생한다. 요즘 에이전트는 대체로 문제 해결을 요청하는 경우 해당 문제를 직접적으로 해결하기 위한 가장 좁은 선택을 취하는 경우가 많다. 이건 카파시가 말한 것처럼 수정 범위를 좁게 잡는 것과 연관이 있어 보인다. 즉, 근원적인 부분에 문제가 있고, 그걸 알더라도 그 부분을 광범위하게 수정하기보다는 문제 표면만 작게 수정해서 해결하려는 경향이 강하다는 의미다. 몰라서 그렇다기보다는 시스템에 그런 식으로 가이드가 된 것으로 보여진다. 그리고 그게 많은 경우에 상당히 유용하다. 하지만 물론 그렇지 않을 때도 있는 법이다.&lt;/p&gt;
&lt;p&gt;구조적 문제를 해결해야 하는 부분에 인공지능이 땜빵식으로 수정을 한 경우에는 사람이 적절하게 가이드를 해줘야 한다. 이 방식은 좋지 않은 것 같으니 다른 식으로 시도하라거나, 이렇게 한 이유가 뭐냐고 물어보고 근본적인 문제를 따져보거나 하는 식으로 말이다. 하지만 사람이 그걸 판단할 능력이 되지 않으면 어쨌든 문제는 해결되었고, 테스트는 통과했으니 머지를 요청한다. 하지만 이런 식의 나쁜 코드가 쌓이면 결국 엄청난 기술 부채 부메랑을 마주하게 될 것이 자명하다.&lt;/p&gt;
&lt;h2&gt;#3&lt;/h2&gt;
&lt;p&gt;물론 나도 예외는 아니다. 회사 제품의 아주 심장부 코드가 있었다. 인터페이스 부분인데 나는 주로 이 코드를 정보가 있는 곳에서, 정보가 없는 곳으로 정보를 전달하는 형식으로 사용했었다. 이걸 이해하고 사용한 인공지능도 대단한데, 내 생각의 흐름과는 정반대로 작성한 것이다. 걘 정보를 전달한 게 아니라, 정보가 없는 쪽에서 있는 쪽으로 채워달라고 요청하는 형태로 작성을 했다.&lt;/p&gt;
&lt;p&gt;인간의 에고가 어디 가겠는가? 코드를 보면서 당장 내 생각과 다르게 전개되는 걸 보면서 몹시 호통쳤다. 왜 이따위로 잘못 작성했냐고 따져 물은 것이다. 인간의 에고가 이렇게 무섭다. 멀쩡하게 동작하는데도 코드를 읽으면서 내 생각과 다르면 일단 틀렸다고 생각하고 보는 것이다. 막 뭐라고 하자 인공지능은 당연하게 자기가 잘못 생각했다면서 내 생각의 틀에 맞춰서 코드를 고치겠다며 주섬주섬 수정을 시작했다. 그런데 웃긴 건 걔가 고치는 부분 부분을 보다가 깨달았다. 아 이건 잘못 작성한 게 아니라 생각을 완전히 다르게 한 거구나. 그제야 나의 환각을 알게 됐다. 완전 잘못 작성했다면 돌아갈 리도 없었을 텐데 테스트를 다 통과한 코드를 보면서 그런 어이없는 호통을 친 것이다.&lt;/p&gt;
&lt;p&gt;결국 나처럼 수정하지 않아도 되니까 원래 코드로 롤백하라고 하고는 다시 코드를 찬찬히 살펴봤다. 진지하게 다시 보자 그 코드가 더 괜찮은 장점이 많았다. 왜냐하면 내가 생각하는 정보가 있는 곳에서 없는 곳으로 전달을 하는 구조는 일방적으로 전달을 하는 것이라서 의존성이 생긴다. 초기화 단계라 받는 쪽이 준비가 안 됐을 수도 있는 상황인데 막무가내로 정보를 던질 수도 있는 것이다. 인공지능이 작성한 코드는 반대로 필요할 때 요청하는 식이라 그런 문제가 없는 것이었다. 사과조차도 토큰 낭비니 하지는 않았지만 내심 사람이란 에고와 환각에서 자유롭기는 참 어렵다는 생각을 했다.&lt;/p&gt;
&lt;h2&gt;#4&lt;/h2&gt;
&lt;p&gt;이런 사례들을 겪다 보면, 나는 인간의 뇌 구조 자체도 근본적으로 생성형이 아닌가 싶은 생각이 든다. 왜냐하면 좌우뇌를 분리한 실험들을 보면 그런 직감이 들기 때문이다. 유명한 분리뇌 실험으로 닭발 실험이 있다. 좌우뇌가 분리된 환자에게 오른쪽 시야에는 닭발을, 왼쪽 시야에는 눈 덮인 풍경을 보여준다. 오른쪽 시야의 정보는 좌뇌가 처리하고, 왼쪽 시야의 정보는 우뇌가 처리한다. 그다음 여러 그림 중 관련 있는 것을 고르게 하면 오른손은 닭을, 왼손은 삽을 고른다. 좌뇌는 닭발 정보를 처리했기 때문에 닭을 고른 것이고, 우뇌는 눈밭 정보를 처리했기 때문에 삽을 고른 것이다. 하지만 여기서 환자에게 왜 삽을 골랐냐고 질문하면, 언어를 담당하는 좌뇌의 지독한 환각이 시작된다. 좌뇌는 우뇌가 눈밭을 봤다는 사실을 모르기 때문에 삽을 고른 진짜 이유를 알 수 없다. 그런데도 모른다고 하지 않고, "닭장을 치우려면 삽이 필요하니까요" 같은 그럴듯한 설명을 만들어낸다.&lt;/p&gt;
&lt;p&gt;결국 여기서 우리가 알 수 있는 건 좌뇌는 llm 그잡채가 아닌가 싶다는 점이다. 그러니 인공지능의 환각으로 너무 뭐라 하지는 말자. 내가 봤을 땐 인간의 환각도 도긴개긴이다.&lt;/p&gt;
&lt;p&gt;인간 환각의 화룡점정은 이런 경우가 아닌가 싶다. 고객 A가 문제를 질의한다. B가 내부에 그걸 토스한다. C가 틀린 답을 말한다. D가 칭찬한다. B가 그걸 보고한다. A는 별로 중요하지 않은 문제라 그러려니 넘긴다. 이런 일들은 부지기수로 발생한다. B, C, D가 즐거워하는데 굳이 산통을 깰 필요도 없기에 중요하지 않은 문제는 그냥 넘어가는 편이 정신 건강과 삶에 이롭다. 인간의 환각 또한 늘상 있고, 대체로는 여러 명이 모여도 환각이 있는지조차도 모르는 경우가 다반사다. 인공지능의 환각 또한 알아차리지 못하는 경우도 부지기수다. 하지만 인간의 위대한 에고는 어쩌다 알아차린 인공지능의 환각 하나를 대서특필하는 게 일상다반사다.&lt;/p&gt;
&lt;p&gt;2026년 6월 기준, 코딩 한정, 내 생각에 인공지능의 환각보다 인간의 환각이 훨씬 더 큰 문제가 되는 지점이 되지 않았나 싶다. 아무튼 요는 환각에 있어서는 인간이나 인공지능이나 다 마찬가지라는 점이다. 테스형의 일침처럼 우리는 자신을 모른다. 그리고 뭘 모르는지도 모른다. 실상은 뭘 모르는지 안다는 것, 그게 제일 어려운 일인지도 모르겠다.&lt;/p&gt;
&lt;p&gt;덧) 인간의 환각 문제에 진지한 관심이 있는 독자라면 조던 엘렌버그의 "틀리지 않는 법"을 일독하길 추천한다.&lt;/p&gt;
&lt;/body&gt;&lt;/html&gt;
</content>
    <id>https://jiniya.net/2026/06/hallucination-vs-hallucination/</id>
    <link href="https://jiniya.net/2026/06/hallucination-vs-hallucination/"/>
    <summary type="html">#0 생성형 인공지능의 가장 큰 문제로 환각을 꼽는다. 말 그대로 생성형?! 이기에 뭐든지 던지기만 하면 생성을 해내는 것이다. 초창기 세종대왕 맥북 사건으로 gpt…</summary>
    <title>[ai] 환각 vs 환각</title>
    <updated>2026-06-10T10:30:01+09:00</updated>
    <dc:date>2026-06-10T10:30:01+09:00</dc:date>
  </entry>
  <dc:date>2026-06-15T00:00:45+09:00</dc:date>
</feed>
