<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>evan_kang.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 09 Apr 2026 15:06:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. evan_kang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/evan_kang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[gstack 실전 가이드 — Claude Code를 가상 엔지니어링 팀으로 만드는 법]]></title>
            <link>https://velog.io/@evan_kang/gstack-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C-Claude-Code%EB%A5%BC-%EA%B0%80%EC%83%81-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%ED%8C%80%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B2%95</link>
            <guid>https://velog.io/@evan_kang/gstack-%EC%8B%A4%EC%A0%84-%EA%B0%80%EC%9D%B4%EB%93%9C-Claude-Code%EB%A5%BC-%EA%B0%80%EC%83%81-%EC%97%94%EC%A7%80%EB%8B%88%EC%96%B4%EB%A7%81-%ED%8C%80%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%9C%EB%8A%94-%EB%B2%95</guid>
            <pubDate>Thu, 09 Apr 2026 15:06:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Claude Code를 쓰면서 &quot;리뷰해줄 시니어가 없다&quot;고 느낀 적 있다면, 이 글이 도움이 될 겁니다.</p>
</blockquote>
<h2 id="gstack이-뭔가">gstack이 뭔가</h2>
<p><a href="https://github.com/garrytan/gstack">gstack</a>은 Y Combinator 대표 Garry Tan이 공개한 Claude Code 슬래시 커맨드 팩입니다. GitHub 스타 54K를 넘긴 오픈소스 프로젝트로, Claude Code를 <strong>가상 엔지니어링 팀</strong>으로 바꿔줍니다.</p>
<p>핵심 철학은 단순합니다. &quot;만능 AI 하나에게 다 시키기&quot;를 그만두고, <strong>CEO, 엔지니어링 매니저, QA 리드, 릴리즈 매니저</strong> 역할을 분리하자는 겁니다.</p>
<p>왜 역할 분리가 중요할까요? 같은 AI에게 설계-구현-리뷰-배포를 한 세션에서 시키면, 각 단계에 필요한 인지 모드가 다르기 때문에 품질이 떨어집니다. CEO는 &quot;왜 이걸 만들어야 하는가&quot;를 생각하고, QA 엔지니어는 &quot;이게 실제로 작동하는가&quot;를 생각합니다. 같은 사람이 동시에 두 모드로 작업하면 둘 다 어중간해지는 것과 같습니다.</p>
<p>gstack은 이 문제를 슬래시 커맨드로 해결합니다. <code>/plan-ceo-review</code>를 치면 Claude가 CEO 모드로 전환되고, <code>/qa</code>를 치면 QA 리드 모드로 전환됩니다. 각 모드마다 고유한 우선순위, 체크리스트, 제약조건이 적용됩니다.</p>
<hr>
<h2 id="설치와-초기-세팅">설치와 초기 세팅</h2>
<h3 id="요구사항">요구사항</h3>
<ul>
<li><strong>Bun</strong> v1.0 이상</li>
<li><strong>Node.js</strong></li>
<li><strong>Git</strong></li>
<li><strong>Claude Code</strong></li>
</ul>
<p>확인 방법:</p>
<pre><code class="language-bash">echo &quot;=== Bun ===&quot; &amp;&amp; (bun --version 2&gt;/dev/null || echo &quot;NOT INSTALLED&quot;)
echo &quot;=== Node.js ===&quot; &amp;&amp; (node --version 2&gt;/dev/null || echo &quot;NOT INSTALLED&quot;)
echo &quot;=== Git ===&quot; &amp;&amp; (git --version 2&gt;/dev/null || echo &quot;NOT INSTALLED&quot;)
echo &quot;=== Claude Code ===&quot; &amp;&amp; (claude --version 2&gt;/dev/null || echo &quot;NOT INSTALLED&quot;)</code></pre>
<p>Bun이 없다면:</p>
<pre><code class="language-bash">curl -fsSL https://bun.sh/install | bash</code></pre>
<h3 id="전역-설치-vs-프로젝트별-설치">전역 설치 vs 프로젝트별 설치</h3>
<p>gstack은 두 가지 설치 방식을 지원합니다.</p>
<p><strong>전역 설치</strong> — <code>~/.claude/skills/gstack</code>에 설치되어 모든 Claude Code 세션에서 사용 가능합니다. 개인 역량 강화 목적이라면 이쪽입니다.</p>
<pre><code class="language-bash">git clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack &amp;&amp; cd ~/.claude/skills/gstack &amp;&amp; ./setup</code></pre>
<p><strong>프로젝트별 설치</strong> — 프로젝트의 <code>.claude/skills/</code>에 복사해서 git에 커밋합니다. 팀원이 <code>git clone</code>만 하면 바로 gstack을 사용할 수 있습니다.</p>
<pre><code class="language-bash">cp -Rf ~/.claude/skills/gstack .claude/skills/gstack &amp;&amp; rm -rf .claude/skills/gstack/.git &amp;&amp; cd .claude/skills/gstack &amp;&amp; ./setup</code></pre>
<p>혼자 쓸 거라면 전역 설치로 시작하고, 팀에 공유할 때 프로젝트별로 옮기면 됩니다.</p>
<h3 id="셋업-질문과-추천-선택">셋업 질문과 추천 선택</h3>
<p>설치 중에 몇 가지 질문이 나옵니다. 각각의 의미와 추천 선택을 정리합니다.</p>
<p><strong>Skill naming — Short names vs Namespaced</strong></p>
<p><code>/qa</code>로 쓸지 <code>/gstack-qa</code>로 쓸지 선택합니다. 다른 스킬팩을 병행하지 않는다면 Short names가 타이핑이 빠릅니다. 충돌이 생기면 나중에 <code>gstack-config</code>로 변경 가능합니다.</p>
<blockquote>
<p>💡 <strong>주의:</strong> 이 단계에서 Cmd+C를 누르면 복사가 아니라 터미널 인터럽트 신호가 발생합니다. 타임아웃이 걸려있어서 기본값(Short names)으로 진행됩니다. 당황하지 마세요 — 대부분의 경우 기본값이 적절합니다.</p>
</blockquote>
<p><strong>Telemetry — Community mode vs Off</strong></p>
<p>사용 통계(어떤 스킬을 얼마나 썼는지)를 gstack 개발팀에 보낼지 선택합니다. 코드나 파일 경로는 보내지 않는다고 명시하고 있지만, 굳이 켤 필요는 없습니다. Off를 선택하면 이어서 &quot;최소한 카운터만이라도?&quot;라고 다시 물어보는데, 이것도 편한 대로 선택하면 됩니다.</p>
<p><strong>Proactive — On vs Off</strong></p>
<p>작업 중에 gstack이 문맥을 읽고 적절한 커맨드를 제안해주는 기능입니다. &quot;이거 되나?&quot; 같은 말을 하면 <code>/qa</code>를 제안하고, 버그를 만나면 <code>/investigate</code>를 제안합니다. <strong>On을 추천합니다.</strong> 아직 각 커맨드의 적절한 타이밍을 모를 때, 자동 제안이 학습을 도와줍니다.</p>
<p><strong>Cross-project learnings — Enable vs Project-scoped</strong></p>
<p>gstack이 프로젝트별로 학습한 내용을 다른 프로젝트에서도 참조할지 선택합니다. 솔로 개발자라면 Enable이 유리합니다. A 프로젝트에서 배운 패턴이 B 프로젝트 작업할 때 자동으로 참조됩니다. 여러 클라이언트 코드를 다루는 에이전시/프리랜서라면 Project-scoped로 격리하세요.</p>
<p><strong>Routing rules — CLAUDE.md에 추가 여부</strong></p>
<p>프로젝트의 CLAUDE.md에 라우팅 규칙을 추가하면, Claude가 대화 맥락에 따라 적절한 스킬을 자동 호출합니다. Proactive 모드와 함께 쓸 때 효과적입니다. 본인 프로젝트라면 추가하세요.</p>
<hr>
<h2 id="핵심-커맨드-3개와-언제-쓰는가">핵심 커맨드 3개와 언제 쓰는가</h2>
<p>gstack은 20개 이상의 커맨드를 제공하지만, 처음에는 3개만 알면 충분합니다.</p>
<h3 id="retro--지금-내-프로젝트-상태가-어떤가">/retro — &quot;지금 내 프로젝트 상태가 어떤가?&quot;</h3>
<p>git 히스토리를 분석해서 엔지니어링 회고를 생성합니다.</p>
<p>분석 항목:</p>
<ul>
<li>커밋 수, LOC, 테스트 비율, PR 수 등 정량 지표</li>
<li>시간대별 작업 패턴 (언제 가장 많이 코딩하는지)</li>
<li>출하 속도와 유형 분포 (feat, fix, refactor 비율)</li>
<li>코드 핫스팟 (가장 많이 변경된 파일)</li>
<li>출하 일관성과 streak</li>
</ul>
<p><strong>언제 쓰나:</strong> 프로젝트를 처음 인수받았을 때, 스프린트 종료 시점, 또는 &quot;요즘 내가 얼마나 생산적인가?&quot; 궁금할 때.</p>
<h3 id="plan-eng-review--내-코드에-구조적-문제가-있나">/plan-eng-review — &quot;내 코드에 구조적 문제가 있나?&quot;</h3>
<p>코드베이스 전체를 엔지니어링 매니저 관점으로 스캔합니다.</p>
<p>제시하는 것:</p>
<ul>
<li><strong>보안:</strong> 키 노출, 인증 부재, 인젝션 가능성</li>
<li><strong>성능:</strong> 불필요한 순차 처리, 과도한 데이터 조회, 캐시 미설정</li>
<li><strong>버그:</strong> 실제 동작하지 않는 코드, 크래시 가능성</li>
<li><strong>코드 품질:</strong> DRY 위반, 패턴 불일치, 에러 처리 미흡</li>
</ul>
<p>각 이슈마다 <strong>P1/P2/P3 우선순위, 구체적 파일:라인번호, 수정 방법, 예상 소요시간, 완성도 점수</strong>까지 포함됩니다. 그리고 이슈별로 &quot;수정하겠다 / 보류하겠다&quot;를 선택할 수 있고, 보류한 것은 TODOS.md로 자동 생성됩니다.</p>
<p><strong>언제 쓰나:</strong> 배포 전 검수, 새 팀원이 코드베이스를 파악할 때, &quot;기술 부채가 어디에 있지?&quot; 확인할 때.</p>
<h3 id="review--이-pr을-머지해도-되나">/review — &quot;이 PR을 머지해도 되나?&quot;</h3>
<p>현재 브랜치와 main의 diff를 기반으로 코드 리뷰를 수행합니다. 스태프 엔지니어 관점에서 프로덕션 버그, 보안 취약점, 성능 이슈를 잡습니다.</p>
<p><strong>언제 쓰나:</strong> PR 머지 전. 솔로 개발자라면 <code>git checkout -b feat/thing</code> → 작업 → <code>/review</code> → <code>/ship</code> 흐름을 습관화하면 코드 품질이 올라갑니다.</p>
<hr>
<h2 id="plan-eng-review가-실제로-잡아주는-것들">/plan-eng-review가 실제로 잡아주는 것들</h2>
<p>실제 프로젝트에서 <code>/plan-eng-review</code>를 돌렸을 때 발견된 이슈들을 카테고리별로 정리합니다. 여러분의 프로젝트에서도 비슷한 패턴이 나올 수 있습니다.</p>
<h3 id="보안">보안</h3>
<p><strong>클라이언트 사이드 DB 직접 쿼리.</strong> <code>NEXT_PUBLIC_</code> 키를 사용해 브라우저에서 Supabase에 직접 쿼리를 보내는 코드. RLS(Row Level Security)가 없으면 누구든 브라우저 개발자 도구로 테이블을 조회할 수 있습니다. → API route를 경유하도록 변경.</p>
<p><strong>인증 없는 API 엔드포인트.</strong> 외부 API를 호출하는(=돈이 나가는) 라우트에 인증이 없으면, URL만 알면 누구나 호출 가능합니다. → API 키 헤더 체크 추가.</p>
<p><strong>모듈 레벨 서비스 키 초기화.</strong> 같은 프로젝트 안에서 한 파일은 lazy-init 패턴을 쓰고, 다른 파일은 모듈 최상단에서 초기화하는 불일치. → 기존 좋은 패턴으로 통일.</p>
<h3 id="성능">성능</h3>
<p><strong>순차 쿼리를 Promise.all로 병렬화.</strong> 서로 의존성 없는 DB 쿼리 3~4개를 <code>await</code>로 순차 실행하고 있는 경우. <code>Promise.all</code>로 감싸면 같은 데이터를 가져오는 시간이 3배 이상 줄어듭니다. 2분짜리 수정.</p>
<p><strong>SSR 캐시 미설정.</strong> Next.js App Router는 기본적으로 빌드 시점에 페이지를 캐시합니다. 라이브 데이터를 보여주는 페이지에 <code>export const revalidate = 300</code>을 추가하면 5분마다 갱신됩니다. 한 줄 수정.</p>
<h3 id="버그">버그</h3>
<p><strong>읽기만 있고 쓰기가 없는 코드.</strong> sessionStorage에서 데이터를 읽는 코드는 있는데, 어디에서도 쓰지 않는 경우. 생성 후 페이지 이동했다가 돌아오면 데이터가 사라집니다. → 생성 성공 시 sessionStorage.setItem 추가.</p>
<p><strong>중복 데이터 삽입.</strong> 캐시된 결과가 있는데도 매번 INSERT를 실행하는 코드. 같은 버튼을 두 번 클릭하면 중복 행이 생깁니다. 같은 프로젝트의 다른 핸들러에 이미 존재하는 체크 패턴을 그대로 적용.</p>
<p><strong>URL 파싱 크래시.</strong> <code>new URL(source).hostname</code>을 SSR 렌더링 내 <code>.map()</code>에서 호출하는 코드. 소스 URL이 유효하지 않으면 전체 페이지가 500 에러로 죽습니다. → try/catch 3줄 추가.</p>
<h3 id="코드-품질">코드 품질</h3>
<p><strong>에러 응답에 스택 트레이스 노출.</strong> catch 블록에서 에러 객체를 그대로 클라이언트에 반환하면, 내부 구현 상세가 외부에 노출됩니다. → <code>console.error</code>로 서버 로그는 유지하고, 클라이언트에는 일반 에러 메시지만 반환.</p>
<hr>
<h2 id="인상-깊었던-개념--llm-신뢰-경계trust-boundary">인상 깊었던 개념 — LLM 신뢰 경계(Trust Boundary)</h2>
<p>gstack이 단순히 &quot;이 코드가 이상하다&quot;를 넘어서 <strong>구조적 설계 개념</strong>을 짚어준 사례가 있었습니다.</p>
<p>AI(LLM)가 생성한 텍스트를 여러 시스템에 전달할 때, 각 목적지마다 다른 위험이 존재합니다.</p>
<ul>
<li><strong>Slack에 보낼 때:</strong> <code>@channel</code>, <code>&lt;!everyone&gt;</code> 같은 특수 문법이 포함되면 의도하지 않은 전체 멘션이 발생할 수 있습니다.</li>
<li><strong>DB에 저장할 때:</strong> 문자열 그대로 저장하면 대체로 안전하지만, 타입 검증은 필요합니다.</li>
<li><strong>브라우저에 보여줄 때:</strong> XSS 방지를 위한 이스케이프, 마크다운 파싱을 위한 렌더러가 필요합니다.</li>
</ul>
<p>AI 출력은 예측 가능해 보이지만 100% 통제할 수 없습니다. 외부 시스템에 넘기기 전에 &quot;이 출력이 해당 시스템에서 위험한 동작을 유발할 수 있는가?&quot;를 체크하는 경계를 두는 것이 <strong>신뢰 경계</strong>입니다. AI 앱을 만드는 개발자라면 설계 시점에 고려해야 할 원칙입니다.</p>
<hr>
<h2 id="실전-운용-팁">실전 운용 팁</h2>
<h3 id="커맨드-체인">커맨드 체인</h3>
<p>gstack 커맨드는 독립적으로도 쓸 수 있지만, 체인으로 연결하면 더 강력합니다. 앞 단계의 산출물이 뒷 단계의 입력이 됩니다.</p>
<pre><code>/office-hours (아이디어 정의)
    ↓
/plan-ceo-review (전략 검토)
    ↓
/plan-eng-review (아키텍처 검토)
    ↓
/review (코드 리뷰)
    ↓
/qa (브라우저 테스트)
    ↓
/ship (배포)
    ↓
/retro (회고)</code></pre><p>처음부터 풀 체인을 돌릴 필요는 없습니다. 파이프라인 중간 어디에서든 시작할 수 있고, <code>/plan-eng-review</code>는 design doc 없이 기존 코드베이스를 분석하는 것도 가능합니다.</p>
<h3 id="스코프-관리">스코프 관리</h3>
<p><code>/plan-eng-review</code>는 한 번에 10개 이상의 이슈를 찾아줄 수 있습니다. 전부 고치려는 충동을 참으세요. 실전에서 효과적인 판단 기준:</p>
<ul>
<li><strong>지금 고친다:</strong> 1~2분짜리 패턴 통일, 실제 동작하는 버그, 크래시 방지</li>
<li><strong>기록하고 넘긴다:</strong> 아키텍처 변경, 테스트 인프라 구축, 대규모 리팩토링</li>
</ul>
<p>보류한 이슈는 gstack이 TODOS.md를 자동 생성해주니, 다음 스프린트에서 꺼내면 됩니다.</p>
<h3 id="한국어-설정">한국어 설정</h3>
<p>gstack의 출력은 기본적으로 영어입니다. 한국어로 받으려면 <code>CLAUDE.local.md</code>에 한 줄만 추가하세요.</p>
<pre><code class="language-bash">echo &quot;\n## Language\nAlways respond in Korean (한국어).&quot; &gt;&gt; ~/.claude/CLAUDE.local.md</code></pre>
<p><code>CLAUDE.local.md</code>는 <code>.gitignore</code>에 포함되므로 gstack 원본이나 팀 설정에 영향을 주지 않습니다.</p>
<hr>
<h2 id="누구에게-추천하나">누구에게 추천하나</h2>
<p><strong>솔로 개발자</strong> — 시니어 리뷰어 없이 시니어 관점 피드백을 받을 수 있습니다. 보안, 성능, 아키텍처를 혼자서는 놓치기 쉬운데, gstack이 체계적으로 잡아줍니다.</p>
<p><strong>주니어 개발자</strong> — 각 커맨드가 &quot;시니어 엔지니어는 코드의 어디를 보는가&quot;를 보여주는 학습 도구가 됩니다. P1/P2/P3 분류, 완성도 점수, 수정 방법까지 포함되어 있어서 &quot;왜 이게 중요한지&quot;를 같이 배울 수 있습니다.</p>
<p><strong>팀 리드</strong> — 프로젝트 <code>.claude/skills/</code>에 커밋하면 팀 전체가 같은 리뷰 기준을 공유합니다. 코드 리뷰의 일관성이 올라가고, 반복적인 피드백을 자동화할 수 있습니다.</p>
<h3 id="추천-시작-순서">추천 시작 순서</h3>
<ol>
<li><strong><code>/retro</code></strong> — 현재 프로젝트 상태를 파악합니다.</li>
<li><strong><code>/plan-eng-review</code></strong> — 구조적 문제를 진단합니다.</li>
<li><strong><code>/review</code></strong> — PR 리뷰를 습관화합니다.</li>
</ol>
<p>이 세 커맨드만 2주 써봐도, &quot;Claude Code를 그냥 쓰는 것&quot;과 &quot;gstack으로 쓰는 것&quot;의 차이를 체감할 수 있을 겁니다.</p>
<hr>
<blockquote>
<p>📌 <strong>설치:</strong> <code>git clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack &amp;&amp; cd ~/.claude/skills/gstack &amp;&amp; ./setup</code></p>
<p>📌 <strong>GitHub:</strong> <a href="https://github.com/garrytan/gstack">github.com/garrytan/gstack</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Claude Code Channels 텔레그램 세팅 — 겪은 시행착오 정리]]></title>
            <link>https://velog.io/@evan_kang/Claude-Code-Channels-%ED%85%94%EB%A0%88%EA%B7%B8%EB%9E%A8-%EC%84%B8%ED%8C%85-%EA%B2%AA%EC%9D%80-%EC%8B%9C%ED%96%89%EC%B0%A9%EC%98%A4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@evan_kang/Claude-Code-Channels-%ED%85%94%EB%A0%88%EA%B7%B8%EB%9E%A8-%EC%84%B8%ED%8C%85-%EA%B2%AA%EC%9D%80-%EC%8B%9C%ED%96%89%EC%B0%A9%EC%98%A4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 26 Mar 2026 07:28:51 GMT</pubDate>
            <description><![CDATA[<p>Claude Code v2.1.80부터 Channels가 리서치 프리뷰로 출시됐습니다.
폰의 텔레그램에서 로컬 CC 세션에 명령을 보내고, 실행 결과를 받는 구조입니다.</p>
<p>세팅 절차는 <a href="https://code.claude.com/docs/en/channels">공식 Channels 문서</a>와 <a href="https://github.com/anthropics/claude-plugins-official/blob/main/external_plugins/telegram/README.md">Telegram 플러그인 README</a>를 따랐습니다.
세팅 중 겪은 시행착오를 정리합니다.</p>
<h2 id="환경">환경</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>값</th>
</tr>
</thead>
<tbody><tr>
<td>Claude Code</td>
<td>v2.1.81</td>
</tr>
<tr>
<td>메신저</td>
<td>Telegram</td>
</tr>
<tr>
<td>소요 시간</td>
<td>약 10분</td>
</tr>
</tbody></table>
<h2 id="1-플러그인-설치-후-스킬이-안-잡힘">1. 플러그인 설치 후 스킬이 안 잡힘</h2>
<p><code>/plugin install telegram@claude-plugins-official</code> 실행 후 바로 <code>/telegram:configure</code>를 실행했더니 <code>Unknown skill: telegram:configure</code> 에러가 떴습니다.</p>
<table>
<thead>
<tr>
<th>순서</th>
<th>시도</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td><code>/reload-plugins</code></td>
<td><code>Reloaded: 1 plugin</code> 표시. 에러 동일</td>
</tr>
<tr>
<td>2</td>
<td><code>/plugin marketplace update claude-plugins-official</code></td>
<td><code>Updated 1 marketplace</code> 표시. 에러 동일</td>
</tr>
<tr>
<td>3</td>
<td><code>exit</code> 후 세션 재진입</td>
<td>정상 동작</td>
</tr>
</tbody></table>
<p>세션 재시작으로 해결됐습니다.</p>
<h2 id="2-permission-relay-실제-화면">2. Permission Relay 실제 화면</h2>
<p>페어링 직후 텔레그램에 <code>Permission: Bash</code>와 <code>Permission: Write</code> 메시지가 떴습니다.
각각 See more / Allow / Deny 버튼이 표시됐고, 폰에서 Allow를 눌러 승인했습니다.</p>
<p><code>--channels</code> 플래그만으로 실행한 상태였고, <code>--dangerously-skip-permissions</code>는 사용하지 않았습니다.</p>
<p>초기 페어링 시점의 경험이고, 반복 작업에서의 안정성은 미확인입니다.</p>
<h2 id="3-기존-텔레그램-봇과의-공존">3. 기존 텔레그램 봇과의 공존</h2>
<p>텔레그램에서 다른 봇을 이미 운용 중이었습니다.
CC Channels 봇을 별도로 생성해서 추가했고, 같은 앱 안에서 충돌 없이 공존했습니다.</p>
<h2 id="4-테스트-결과">4. 테스트 결과</h2>
<p>텔레그램에서 디렉토리 목록을 요청했습니다.
CC가 명령을 실행하고 결과가 텔레그램으로 돌아왔습니다.</p>
<table>
<thead>
<tr>
<th>현상</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>응답 지연</td>
<td>체감 수 초</td>
</tr>
<tr>
<td>재확인</td>
<td>CC가 텔레그램 요청을 처리해도 되는지 재차 묻는 경우 있음</td>
</tr>
</tbody></table>
<p>리서치 프리뷰 단계입니다.</p>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://code.claude.com/docs/en/channels">공식 Channels 문서</a></li>
<li><a href="https://github.com/anthropics/claude-plugins-official/blob/main/external_plugins/telegram/README.md">Telegram 플러그인 README</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Expo 공식 튜토리얼 완주 후기 — 웹 개발자 시점 정리]]></title>
            <link>https://velog.io/@evan_kang/Expo-%EA%B3%B5%EC%8B%9D-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-%EC%99%84%EC%A3%BC-%ED%9B%84%EA%B8%B0-%EC%9B%B9-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%8B%9C%EC%A0%90-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@evan_kang/Expo-%EA%B3%B5%EC%8B%9D-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-%EC%99%84%EC%A3%BC-%ED%9B%84%EA%B8%B0-%EC%9B%B9-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%8B%9C%EC%A0%90-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 27 Feb 2026 03:22:12 GMT</pubDate>
            <description><![CDATA[<p>Next.js 웹 앱을 모바일로 전환하기 위해 Expo 공식 튜토리얼(StickerSmash)을 완주했습니다.
웹 개발 경험 기준으로 차이점 위주로 정리합니다.</p>
<h2 id="1-환경">1. 환경</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>값</th>
</tr>
</thead>
<tbody><tr>
<td>기존 스택</td>
<td>Next.js 14 + TypeScript + Supabase</td>
</tr>
<tr>
<td>전환 대상</td>
<td>iOS 앱 (Expo + React Native)</td>
</tr>
<tr>
<td>튜토리얼</td>
<td><a href="https://docs.expo.dev/tutorial/create-your-first-app/">Expo 공식 StickerSmash</a></td>
</tr>
<tr>
<td>챕터 수</td>
<td>9개</td>
</tr>
<tr>
<td>소요 시간</td>
<td>약 2일</td>
</tr>
</tbody></table>
<h2 id="2-프로젝트-시작">2. 프로젝트 시작</h2>
<pre><code class="language-bash">npx create-expo-app@latest my-app
cd my-app
npm run reset-project
npx expo start</code></pre>
<p><code>create-next-app</code>과 거의 동일한 경험입니다. TypeScript, Expo Router, 멀티플랫폼 설정이 한 줄로 완료됩니다.</p>
<h2 id="3-챕터별-요약">3. 챕터별 요약</h2>
<table>
<thead>
<tr>
<th>챕터</th>
<th>핵심 내용</th>
<th>사용 라이브러리</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>프로젝트 생성, Expo Go 연결, StyleSheet 기초</td>
<td>react-native</td>
</tr>
<tr>
<td>2</td>
<td>파일 기반 라우팅, Stack/Tabs 네비게이션</td>
<td>expo-router</td>
</tr>
<tr>
<td>3</td>
<td>Image 컴포넌트, Pressable 버튼, 컴포넌트 분리</td>
<td>expo-image</td>
</tr>
<tr>
<td>4</td>
<td>기기 갤러리에서 이미지 선택, useState로 상태 관리</td>
<td>expo-image-picker</td>
</tr>
<tr>
<td>5</td>
<td>Modal로 이모지 피커 구현, FlatList 가로 리스트</td>
<td>react-native (Modal, FlatList)</td>
</tr>
<tr>
<td>6</td>
<td>더블탭(크기 변경) + 팬(드래그) 제스처, 스프링 애니메이션</td>
<td>react-native-gesture-handler, react-native-reanimated</td>
</tr>
<tr>
<td>7</td>
<td>View 캡처 → 기기 갤러리 저장, 권한 요청</td>
<td>react-native-view-shot, expo-media-library</td>
</tr>
<tr>
<td>8</td>
<td>Platform.OS로 네이티브/웹 분기 처리</td>
<td>dom-to-image (웹 전용)</td>
</tr>
<tr>
<td>9</td>
<td>StatusBar 테마, 앱 아이콘(1024×1024), 스플래시 스크린</td>
<td>expo-status-bar, expo-splash-screen</td>
</tr>
</tbody></table>
<h2 id="4-웹-개발자가-알아야-할-차이점">4. 웹 개발자가 알아야 할 차이점</h2>
<h3 id="4-1-익숙한-것-러닝커브-낮음">4-1. 익숙한 것 (러닝커브 낮음)</h3>
<table>
<thead>
<tr>
<th>웹 (Next.js)</th>
<th>Expo</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td><code>app/page.tsx</code> → <code>/</code></td>
<td><code>app/index.tsx</code> → <code>/</code></td>
<td>파일 기반 라우팅 거의 동일</td>
</tr>
<tr>
<td><code>app/layout.tsx</code></td>
<td><code>app/_layout.tsx</code></td>
<td>공통 레이아웃 동일 개념</td>
</tr>
<tr>
<td><code>app/not-found.tsx</code></td>
<td><code>app/+not-found.tsx</code></td>
<td>404 처리</td>
</tr>
<tr>
<td>useState, useEffect, useRef</td>
<td>동일</td>
<td>React 훅 100% 호환</td>
</tr>
<tr>
<td>TypeScript</td>
<td>동일</td>
<td>타입 시스템 그대로</td>
</tr>
<tr>
<td><code>onClick</code></td>
<td><code>onPress</code></td>
<td>이름만 다름</td>
</tr>
</tbody></table>
<h3 id="4-2-다른-것-러닝커브-높음">4-2. 다른 것 (러닝커브 높음)</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>웹</th>
<th>Expo/RN</th>
</tr>
</thead>
<tbody><tr>
<td>스타일링</td>
<td>CSS 파일, className</td>
<td><code>StyleSheet.create()</code> JS 객체</td>
</tr>
<tr>
<td>기본 태그</td>
<td><code>&lt;div&gt;</code>, <code>&lt;span&gt;</code>, <code>&lt;img&gt;</code></td>
<td><code>&lt;View&gt;</code>, <code>&lt;Text&gt;</code>, <code>&lt;Image&gt;</code></td>
</tr>
<tr>
<td>리스트</td>
<td><code>array.map()</code></td>
<td><code>&lt;FlatList&gt;</code> (가상화 내장)</td>
</tr>
<tr>
<td>버튼</td>
<td><code>&lt;button&gt;</code></td>
<td><code>&lt;Pressable&gt;</code></td>
</tr>
<tr>
<td>갤러리 접근</td>
<td><code>&lt;input type=&quot;file&quot;&gt;</code></td>
<td><code>expo-image-picker</code> + 권한 요청</td>
</tr>
<tr>
<td>애니메이션</td>
<td>CSS transition/animation</td>
<td>Reanimated (<code>useSharedValue</code> + <code>withSpring</code>)</td>
</tr>
<tr>
<td>제스처</td>
<td>mouse/touch 이벤트 직접 처리</td>
<td>Gesture Handler (<code>Gesture.Tap()</code>, <code>Gesture.Pan()</code>)</td>
</tr>
<tr>
<td>플랫폼 분기</td>
<td>없음</td>
<td><code>Platform.OS</code>로 네이티브/웹 조건부 처리</td>
</tr>
<tr>
<td>파일 저장</td>
<td>다운로드 링크</td>
<td><code>MediaLibrary.saveToLibraryAsync()</code> + 권한</td>
</tr>
<tr>
<td>패키지 설치</td>
<td><code>npm install</code></td>
<td><code>npx expo install</code> (SDK 호환 버전 자동 선택)</td>
</tr>
</tbody></table>
<h3 id="4-3-주의할-점">4-3. 주의할 점</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Expo Go 제한</td>
<td>네이티브 모듈이 필요한 기능(Google Sign-In 등)은 Expo Go에서 불가. Dev Client 빌드 필요</td>
</tr>
<tr>
<td><code>app/</code> 디렉토리 규칙</td>
<td>라우트/레이아웃 파일만 허용. 커스텀 컴포넌트는 <code>components/</code>에 분리</td>
</tr>
<tr>
<td><code>collapsable={false}</code></td>
<td>View 캡처 시 Android에서 최적화로 View가 합쳐지는 것 방지용</td>
</tr>
<tr>
<td><code>GestureHandlerRootView</code></td>
<td>제스처 사용 시 최상위에 반드시 감싸야 동작</td>
</tr>
<tr>
<td>스플래시 스크린 테스트</td>
<td>Expo Go에서 불가. 프리뷰/프로덕션 빌드 필요</td>
</tr>
</tbody></table>
<h2 id="5-다음-단계">5. 다음 단계</h2>
<table>
<thead>
<tr>
<th>순서</th>
<th>작업</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>모바일 Google 로그인 검증 (Supabase + <code>@react-native-google-signin/google-signin</code>)</td>
</tr>
<tr>
<td>2</td>
<td>기존 웹 코드 재사용 범위 판단 (순수 로직 vs UI 레이어)</td>
</tr>
<tr>
<td>3</td>
<td>EAS Build로 실기기 배포 테스트</td>
</tr>
</tbody></table>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://docs.expo.dev/tutorial/create-your-first-app/">Expo 공식 튜토리얼</a></li>
<li><a href="https://docs.expo.dev/router/introduction/">Expo Router 문서</a></li>
<li><a href="https://docs.swmansion.com/react-native-gesture-handler/docs/">React Native Gesture Handler</a></li>
<li><a href="https://docs.swmansion.com/react-native-reanimated/">React Native Reanimated</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenClaw 서브에이전트 5개 세팅 과정]]></title>
            <link>https://velog.io/@evan_kang/OpenClaw-%EC%84%9C%EB%B8%8C%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-5%EA%B0%9C-%EC%84%B8%ED%8C%85-%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@evan_kang/OpenClaw-%EC%84%9C%EB%B8%8C%EC%97%90%EC%9D%B4%EC%A0%84%ED%8A%B8-5%EA%B0%9C-%EC%84%B8%ED%8C%85-%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Mon, 09 Feb 2026 15:20:50 GMT</pubDate>
            <description><![CDATA[<p>OpenClaw에 서브에이전트 5개를 세팅하고 실제 작업에 투입한 과정을 정리했습니다.</p>
<h2 id="1-환경">1. 환경</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>값</th>
</tr>
</thead>
<tbody><tr>
<td>OpenClaw</td>
<td>Main Agent (Openbot)</td>
</tr>
<tr>
<td>채널</td>
<td>Slack</td>
</tr>
</tbody></table>
<h2 id="2-서브에이전트-생성">2. 서브에이전트 생성</h2>
<p>Openbot에게 프롬프트로 요청했습니다.</p>
<pre><code>서브에이전트 5개를 세팅해줘:

Researcher:
* IDENTITY.md: name &quot;Researcher&quot;
* SOUL.md: 리서치 전문. 웹 검색, 문서 분석, 팩트체크, 요약 보고서 작성.
  출처 항상 명시. 요청 시 한국어 보고서 작성.

Coder:
* IDENTITY.md: name &quot;Coder&quot;
* SOUL.md: 코딩 전문. 클린 코드, 프로젝트 구조, 디버깅, 테스트 작성.
  기본 스택 TypeScript/Next.js. 요청 시 한국어 주석.

Reviewer:
* IDENTITY.md: name &quot;Reviewer&quot;
* SOUL.md: 코드 리뷰 전문. 버그, 보안, 성능, 모범 사례 검토.
  직접 코드 작성하지 않음. 라인 번호와 수정 제안 포함.
  요청 시 한국어 리뷰.

Writer:
* IDENTITY.md: name &quot;Writer&quot;
* SOUL.md: 한국어 기술 콘텐츠 작성 전문.
  경어체, 팩트 중심, 담백한 톤.
  X 포스트(280자), 블로그, 기술 문서, 요약 작성.
  출처 항상 명시.

Planner:
* IDENTITY.md: name &quot;Planner&quot;
* SOUL.md: 프로젝트 기획 전문.
  PRD 작성(문제, 솔루션, 타겟 유저, 핵심 기능, 기술 스택),
  작업 분해, 우선순위 결정. MVP 범위 우선 고려.
  직접 코드 작성하지 않음. 요청 시 한국어 기획서 작성.</code></pre><h2 id="3-최종-구성">3. 최종 구성</h2>
<table>
<thead>
<tr>
<th>에이전트</th>
<th>역할</th>
<th>workspace</th>
</tr>
</thead>
<tbody><tr>
<td>researcher</td>
<td>리서치, 팩트체크</td>
<td>workspace-researcher</td>
</tr>
<tr>
<td>coder</td>
<td>구현</td>
<td>workspace-coder</td>
</tr>
<tr>
<td>reviewer</td>
<td>코드 리뷰</td>
<td>workspace-reviewer</td>
</tr>
<tr>
<td>writer</td>
<td>기술 콘텐츠 작성</td>
<td>workspace-writer</td>
</tr>
<tr>
<td>planner</td>
<td>PRD, 작업 분해</td>
<td>workspace-planner</td>
</tr>
</tbody></table>
<pre><code class="language-json">&quot;allowAgents&quot;: [
  &quot;researcher&quot;,
  &quot;coder&quot;,
  &quot;reviewer&quot;,
  &quot;writer&quot;,
  &quot;planner&quot;
]</code></pre>
<h2 id="4-실제-투입">4. 실제 투입</h2>
<p>researcher + coder를 병렬로 스폰했습니다:</p>
<pre><code>1. researcher를 스폰해서 OpenClaw 설정 단계를 조사해줘.
2. coder를 스폰해서 ~/workspace/openclaw-guide-kr/에 정적 HTML 페이지를 만들어줘.
두 작업을 병렬로 진행해줘.</code></pre><table>
<thead>
<tr>
<th>방식</th>
<th>결과</th>
</tr>
</thead>
<tbody><tr>
<td>병렬 (researcher + coder 동시)</td>
<td>거의 동시에 완료, 안정적</td>
</tr>
<tr>
<td>순차</td>
<td>단계마다 상태 확인 필요</td>
</tr>
</tbody></table>
<h2 id="5-겪은-이슈">5. 겪은 이슈</h2>
<table>
<thead>
<tr>
<th>증상</th>
<th>원인</th>
<th>해결</th>
</tr>
</thead>
<tbody><tr>
<td>교차 검증 안 됨</td>
<td>한 에이전트한테 전부 맡김</td>
<td>역할별 분리 (coder → researcher → reviewer)</td>
</tr>
<tr>
<td>순차 진행 멈춤</td>
<td>자동으로 다음 단계 안 넘어감</td>
<td>중간중간 상태 확인</td>
</tr>
</tbody></table>
<p>완전 자동화보다는 반자동 팀 운영에 가까웠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS EC2에 OpenClaw를 올리고 Slack과 연동했습니다]]></title>
            <link>https://velog.io/@evan_kang/AWS-EC2%EC%97%90-OpenClaw%EB%A5%BC-%EC%98%AC%EB%A6%AC%EA%B3%A0-Slack%EA%B3%BC-%EC%97%B0%EB%8F%99%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@evan_kang/AWS-EC2%EC%97%90-OpenClaw%EB%A5%BC-%EC%98%AC%EB%A6%AC%EA%B3%A0-Slack%EA%B3%BC-%EC%97%B0%EB%8F%99%ED%96%88%EC%8A%B5%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Mon, 02 Feb 2026 15:17:41 GMT</pubDate>
            <description><![CDATA[<p>OpenClaw(구 Moltbot)를 AWS EC2 t3.small에 설치하고 Slack과 연동한 과정을 정리했습니다.</p>
<hr>
<h2 id="1-환경">1. 환경</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>값</th>
</tr>
</thead>
<tbody><tr>
<td>인스턴스</td>
<td>AWS EC2 t3.small</td>
</tr>
<tr>
<td>OS</td>
<td>Ubuntu 24.04 LTS</td>
</tr>
<tr>
<td>스토리지</td>
<td>30GB</td>
</tr>
<tr>
<td>Node.js</td>
<td>24.x</td>
</tr>
</tbody></table>
<hr>
<h2 id="2-openclaw-설치">2. OpenClaw 설치</h2>
<p><a href="https://docs.molt.bot">공식 문서</a>를 참고해서 설치했습니다.</p>
<hr>
<h2 id="3-slack-app-설정">3. Slack App 설정</h2>
<p><a href="https://api.slack.com/apps">https://api.slack.com/apps</a> → Create New App</p>
<table>
<thead>
<tr>
<th>설정</th>
<th>값</th>
</tr>
</thead>
<tbody><tr>
<td>Socket Mode</td>
<td>ON</td>
</tr>
<tr>
<td>App Home</td>
<td>Messages Tab ON</td>
</tr>
</tbody></table>
<p><strong>Bot Token Scopes:</strong></p>
<pre><code>chat:write, channels:history, channels:read,
im:history, im:read, im:write, users:read, app_mentions:read</code></pre><p><strong>Event Subscriptions:</strong></p>
<pre><code>message.im, message.channels, app_mention</code></pre><hr>
<h2 id="4-실행">4. 실행</h2>
<pre><code class="language-bash">pnpm moltbot gateway --port 18789</code></pre>
<p>Slack DM 시 페어링 코드가 나오면:</p>
<pre><code class="language-bash">moltbot pairing approve slack &lt;코드&gt;</code></pre>
<hr>
<h2 id="5-겪은-이슈">5. 겪은 이슈</h2>
<table>
<thead>
<tr>
<th>증상</th>
<th>해결</th>
</tr>
</thead>
<tbody><tr>
<td>디스크 98% 부족</td>
<td>EBS 20GB → 30GB 확장</td>
</tr>
<tr>
<td>스레드로만 응답</td>
<td>봇에게 직접 요청 (아래 이미지)</td>
</tr>
<tr>
<td>DM 안 됨</td>
<td>페어링 승인</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/evan_kang/post/9377298c-f3ee-4c2d-aa97-8f5c9165b4a9/image.png" alt=""></p>
<hr>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://github.com/moltbot/moltbot">GitHub</a></li>
<li><a href="https://docs.molt.bot">공식 문서</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Antigravity 스킬 세팅 → 프롬프트 1개로 모니터링 대시보드 만들기]]></title>
            <link>https://velog.io/@evan_kang/Antigravity-%EC%8A%A4%ED%82%AC-%EC%84%B8%ED%8C%85-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-1%EA%B0%9C%EB%A1%9C-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@evan_kang/Antigravity-%EC%8A%A4%ED%82%AC-%EC%84%B8%ED%8C%85-%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8-1%EA%B0%9C%EB%A1%9C-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 26 Jan 2026 15:04:54 GMT</pubDate>
            <description><![CDATA[<h2 id="스킬을-세팅해두면-이후가-편합니다">스킬을 세팅해두면 이후가 편합니다</h2>
<p>Antigravity는 Google이 만든 AI 에이전틱 개발 플랫폼입니다. 스킬은 에이전트의 행동 지침으로, 잘 구성해두면 매번 긴 프롬프트를 작성할 필요 없이 짧은 요청만으로 원하는 결과물을 얻을 수 있습니다.</p>
<p>이 글에서는 스킬 구성법과 실제 활용 예시를 다룹니다.</p>
<hr>
<h2 id="1-스킬-세팅--어떤-스킬을-만들어야-할지-모를-때">1. 스킬 세팅 — 어떤 스킬을 만들어야 할지 모를 때</h2>
<p>프로젝트에 맞는 스킬을 직접 설계하기 어렵다면, 에이전트에게 제안을 요청하면 됩니다.</p>
<pre><code>Read docs/prd.md.
Propose 6 skills (4 workspace, 2 global) following the codelab:
- name
- description (trigger-focused)
- body outline (Goal/Instructions/Examples/Constraints)
- optional scripts/references
Do not create files yet; ask for review.</code></pre><p>PRD를 읽고 프로젝트 맥락에 맞는 스킬 6개를 제안해달라는 요청입니다. 바로 파일을 생성하지 않고 리뷰를 거치도록 했습니다.</p>
<p>결과로 생성된 스킬 구조:</p>
<pre><code>skills/
├── init_nextjs_route/SKILL.md
├── preview_local_dashboard/SKILL.md
├── run_metric_collector/SKILL.md
├── scaffold_metric_component/SKILL.md
├── secure_shell_scripting/SKILL.md
└── validate_data_integrity/SKILL.md</code></pre><h3 id="전역-vs-워크스페이스-분류">전역 vs 워크스페이스 분류</h3>
<p>6개 중 2개는 전역 스킬로 등록했습니다.</p>
<table>
<thead>
<tr>
<th>스킬</th>
<th>분류</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><code>init_nextjs_route</code></td>
<td>전역</td>
<td>Next.js 프로젝트라면 어디서든 재사용</td>
</tr>
<tr>
<td><code>secure_shell_scripting</code></td>
<td>전역</td>
<td>프로젝트 무관한 공통 안전 규약</td>
</tr>
<tr>
<td>나머지 4개</td>
<td>워크스페이스</td>
<td>이 프로젝트 전용 로직</td>
</tr>
</tbody></table>
<hr>
<h2 id="2-활용--prd-기반으로-대시보드-생성">2. 활용 — PRD 기반으로 대시보드 생성</h2>
<p>스킬 적용을 확인하기 위해 새 세션에서 테스트했습니다.</p>
<p><strong>프롬프트</strong>: PRD 기반 구현 요청</p>
<pre><code>docs/prd.md 기반으로 구현해줘.</code></pre><p>에이전트가 PRD와 스킬을 참조해 단계별 계획을 제시했습니다.</p>
<p><img src="https://velog.velcdn.com/images/evan_kang/post/4b94cbad-5d6b-4160-8d59-a750e06d36bf/image.png" alt="계획 작성 결과"></p>
<p><strong>결과</strong>: 5초 간격으로 갱신되는 모니터링 대시보드가 생성됐습니다.</p>
<p><img src="https://velog.velcdn.com/images/evan_kang/post/c908323b-acd1-4db9-9feb-3e7667a4a228/image.png" alt="완성된 대시보드"></p>
<hr>
<h2 id="정리">정리</h2>
<ul>
<li>스킬 설계가 어려우면 에이전트에게 제안을 요청합니다</li>
<li>재사용 가능한 스킬은 전역으로, 프로젝트 전용은 워크스페이스로 분류합니다</li>
<li>스킬 세팅에 들인 시간이 이후 반복 작업을 줄여줍니다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI 코딩 도구 비교: OpenCode vs Claude Code]]></title>
            <link>https://velog.io/@evan_kang/AI-%EC%BD%94%EB%94%A9-%EB%8F%84%EA%B5%AC-%EB%B9%84%EA%B5%90-OpenCode-vs-Claude-Code</link>
            <guid>https://velog.io/@evan_kang/AI-%EC%BD%94%EB%94%A9-%EB%8F%84%EA%B5%AC-%EB%B9%84%EA%B5%90-OpenCode-vs-Claude-Code</guid>
            <pubDate>Mon, 19 Jan 2026 13:08:01 GMT</pubDate>
            <description><![CDATA[<h3 id="들어가며">들어가며</h3>
<p>이전에서 OpenCode 설치와 ulw 모드 실험을 다뤘습니다.
이번엔 같은 PRD로 Claude Code까지 포함해 세 가지 환경을 비교해봤습니다.</p>
<p>LLM에게 많이 맡길수록 더 빠르지 않을까? 라는 예상과는 달리 결과는 반대였습니다.</p>
<hr>
<h3 id="테스트-조건">테스트 조건</h3>
<p>서버 모니터링 대시보드를 동일한 PRD로 구현했습니다.</p>
<p>테스트 환경은 세 가지입니다. OpenCode + Z.ai(GLM-4.7) ulw 모드, OpenCode + Gemini ulw 모드, Claude Code 순정(Opus 계획 → Sonnet 구현).</p>
<hr>
<h3 id="결과">결과</h3>
<p><strong>OpenCode + Z.ai (ulw 모드)</strong></p>
<p>프롬프트 1회, 에러 수정 1회. 총 27분 걸렸고 PRD 충족도는 80% 정도였습니다.</p>
<p><strong>OpenCode + Gemini (ulw 모드)</strong></p>
<p>프롬프트 1회, 에러 수정 2회. 총 33분 걸렸고 완성도는 90%까지 올라갔습니다.</p>
<p><strong>Claude Code (Opus + Sonnet)</strong></p>
<p>Opus로 계획 1회, Sonnet으로 구현 4회. 총 9분, 에러 수정 0회, 완성도 100%. 아이콘이나 단위 표시 같은 UI 디테일도 잘 나왔습니다.</p>
<hr>
<h3 id="도구별-장단점">도구별 장단점</h3>
<p><strong>OpenCode + ulw 모드</strong></p>
<p>ulw 한 줄로 작업 전체를 맡길 수 있고, 병렬 에이전트로 여러 작업을 동시에 돌릴 수 있습니다. 대신 결과를 예측하기 어렵고, 에러가 나면 디버깅에 시간이 더 듭니다. spec-kitty처럼 절차가 중요한 워크플로우랑은 안 맞았습니다.</p>
<p><strong>Claude Code (Opus + Sonnet)</strong></p>
<p>Opus가 계획, Sonnet이 구현. 역할이 나뉘어 있어서 흐름이 명확합니다. 단계별로 승인하면서 방향을 잡아줄 수 있고, 에러 없이 끝나는 경우가 많았습니다. 대신 매번 확인해야 해서, 쭉 맡겨두고 싶을 땐 번거로울 수 있습니다.</p>
<hr>
<h3 id="핵심-인사이트">핵심 인사이트</h3>
<p>입력 횟수만 보면 OpenCode가 적고 Claude Code가 많습니다.
하지만 실제 소요 시간은 반대였습니다.</p>
<ul>
<li>ulw로 한 번에 위임: 27~33분 + 에러 수정</li>
<li>단계별로 확인: 9분 + 에러 없음</li>
</ul>
<p>중간에 방향을 잡아주는 게 오히려 더 빠르고 정확했습니다.</p>
<hr>
<h3 id="상황별-정리">상황별 정리</h3>
<ul>
<li>빠르고 안정적인 MVP → Claude Code (Opus 계획 → Sonnet 구현)</li>
<li>실험/탐색 목적 → OpenCode + Gemini + ulw</li>
<li>구조화된 워크플로우 → ulw 없이 단계별 진행</li>
</ul>
<hr>
<h3 id="마무리">마무리</h3>
<p>이번 테스트로 어떤 도구를 언제 써야 하는지 감이 잡혔습니다.</p>
<p>다른 조합들도 더 써보면서 정리해볼 생각입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OpenCode 도입 후기: 설치부터 ulw 실험까지]]></title>
            <link>https://velog.io/@evan_kang/OpenCode-%EB%8F%84%EC%9E%85-%ED%9B%84%EA%B8%B0-%EC%84%A4%EC%B9%98%EB%B6%80%ED%84%B0-ulw-%EC%8B%A4%ED%97%98%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@evan_kang/OpenCode-%EB%8F%84%EC%9E%85-%ED%9B%84%EA%B8%B0-%EC%84%A4%EC%B9%98%EB%B6%80%ED%84%B0-ulw-%EC%8B%A4%ED%97%98%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Mon, 12 Jan 2026 15:12:13 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가며">들어가며</h2>
<p>OpenCode를 사용한 지 약 4일이 됐습니다.
Claude Code와 병행할 수 있는 도구를 찾다가 도입하게 됐고, 설치부터 실제 프로젝트 구현까지 경험한 내용을 정리해봅니다.</p>
<hr>
<h2 id="opencode란">OpenCode란?</h2>
<p>터미널 기반 AI 코딩 에이전트입니다. Claude Code의 대안으로 주목받고 있고,
여러 LLM을 연결해서 사용할 수 있다는 점이 특징입니다.</p>
<hr>
<h2 id="1-opencode-설치">1. OpenCode 설치</h2>
<p>설치는 간단합니다.</p>
<pre><code class="language-bash">curl -fsSL https://opencode.ai/install | bash</code></pre>
<p>설치 완료 후 <code>source ~/.zshrc</code>로 터미널에 적용하고,
프로젝트 디렉토리에서 <code>opencode</code>를 실행하면 됩니다.</p>
<hr>
<h2 id="2-모델-연결">2. 모델 연결</h2>
<p>처음 실행하면 모델이 연결되지 않은 상태입니다.
<code>/connect</code> 명령어로 원하는 프로바이더를 선택하고 연결할 수 있습니다.</p>
<p>저는 처음에 z.ai의 GLM-4.7을 연결했고,
이후 Google OAuth로 Gemini 3 Flash도 추가로 연결해서 사용하고 있습니다.</p>
<hr>
<h2 id="3-oh-my-opencode-플러그인">3. oh-my-opencode 플러그인</h2>
<p>OpenCode만으로도 사용 가능하지만, oh-my-opencode를 설치하면
멀티에이전트 시스템을 활용할 수 있습니다.</p>
<table>
<thead>
<tr>
<th>도구</th>
<th>역할</th>
<th>비유</th>
</tr>
</thead>
<tbody><tr>
<td>opencode</td>
<td>AI 코딩 에이전트</td>
<td>zsh</td>
</tr>
<tr>
<td>oh-my-opencode</td>
<td>플러그인/설정 프레임워크</td>
<td>oh-my-zsh</td>
</tr>
</tbody></table>
<h3 id="설치-과정">설치 과정</h3>
<p>Bun이 필요해서 먼저 설치했습니다.</p>
<pre><code class="language-bash">curl -fsSL https://bun.sh/install | bash
exec /bin/zsh
bunx oh-my-opencode install</code></pre>
<h3 id="설치-중-구독-여부-선택">설치 중 구독 여부 선택</h3>
<ul>
<li>Claude Pro/Max: 없으면 No</li>
<li>ChatGPT Plus: 있으면 Yes</li>
<li>Gemini: 저는 일단 No로 선택했습니다</li>
</ul>
<h3 id="에이전트-구성-결과">에이전트 구성 결과</h3>
<pre><code>- Sisyphus  → glm-4.7-free (메인)
- Oracle   → gpt-5.2 (디버깅/전략)
- Librarian → glm-4.7-free (문서 탐색)
- Frontend  → glm-4.7-free (UI)</code></pre><p>마지막으로 <code>opencode auth login</code>으로 OpenAI 인증을 완료했습니다.</p>
<hr>
<h2 id="4-ulw-모드-실험">4. ulw 모드 실험</h2>
<p>oh-my-opencode의 핵심은 <code>ultrawork</code>(줄여서 <code>ulw</code>) 키워드입니다.
프롬프트에 이 단어를 넣으면 모든 멀티에이전트 기능이 자동 활성화됩니다.</p>
<h3 id="실험-내용">실험 내용</h3>
<p>서버 모니터링 대시보드 PRD를 주고 한 번에 구현을 요청했습니다.</p>
<pre><code>ulw prd.md 기반으로 전체 구현해줘</code></pre><h3 id="결과">결과</h3>
<ul>
<li>소요 시간: 27분 55초</li>
<li>개입 횟수: 1회 (에러 지적)</li>
<li>발생한 이슈: lightningcss 빌드 에러, Health 로직 버그</li>
</ul>
<p>&quot;알아서 끝까지&quot;를 기대했지만, 중간에 에러가 발생해서 디버깅이 필요했습니다.</p>
<hr>
<h2 id="장점과-단점">장점과 단점</h2>
<h3 id="장점">장점</h3>
<ul>
<li>여러 LLM을 연결해서 사용할 수 있습니다</li>
<li>ulw 한 줄로 &quot;알아서 끝까지&quot; 작업을 맡길 수 있습니다</li>
<li>여러 에이전트가 병렬로 작업합니다</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>결과를 예측하기 어렵습니다</li>
<li>에러 발생 시 디버깅 시간이 추가됩니다</li>
<li>&quot;한방에 끝내기&quot;가 오히려 시간이 더 걸릴 수 있습니다</li>
</ul>
<hr>
<h2 id="마무리">마무리</h2>
<p>OpenCode + oh-my-opencode 조합은 여러 LLM을 조합해서 AI 코딩을 해보고 싶을 때 시도해볼 만한 선택지입니다.
터미널 기반 AI 코딩을 다양한 LLM 조합으로 경험해보고 싶은 분들께 추천드립니다.</p>
<p>다만, ulw 모드로 모든 걸 맡기기보다는
단계별로 검수하는 방식이 더 빠르고 안정적일 수 있다는 걸 배웠습니다.</p>
<blockquote>
<p>다음 글에서는 Claude Code와의 비교 테스트 결과를 공유하겠습니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[오픈소스 삽질 1시간 -> 10분으로 줄이는 5단계 체크리스트]]></title>
            <link>https://velog.io/@evan_kang/%EC%98%A4%ED%94%88%EC%86%8C%EC%8A%A4-%EC%82%BD%EC%A7%88-1%EC%8B%9C%EA%B0%84-10%EB%B6%84%EC%9C%BC%EB%A1%9C-%EC%A4%84%EC%9D%B4%EB%8A%94-5%EB%8B%A8%EA%B3%84-%EC%B2%B4%ED%81%AC%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@evan_kang/%EC%98%A4%ED%94%88%EC%86%8C%EC%8A%A4-%EC%82%BD%EC%A7%88-1%EC%8B%9C%EA%B0%84-10%EB%B6%84%EC%9C%BC%EB%A1%9C-%EC%A4%84%EC%9D%B4%EB%8A%94-5%EB%8B%A8%EA%B3%84-%EC%B2%B4%ED%81%AC%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Sun, 21 Dec 2025 15:56:44 GMT</pubDate>
            <description><![CDATA[<h3 id="1-스타-3천개-문서도-깔끔한데-안된다">1. 스타 3천개, 문서도 깔끔한데, 안된다?!</h3>
<p>모두가 그런 것은 아니겠지만, 흔히 오픈소스 프로젝트를 고를 때, 보통 이렇게 할 겁니다. GitHub 스타 수, README 확인, 괜찮아 보이네.. 하고 클론.
저도 그랬습니다.</p>
<p>숏폼 영상 자동 생성 프로젝트를 위해 오픈소스를 찾던 중, README가 깔끔하고 스타도 꽤 있는 것을 발견했습니다. 기능 설명도 명확하고, 데모 영상도 있었던 만큼, 믿음직스러웠죠. 바로 포크하고 로컬에 클론했습니다.</p>
<p>결과요? 패키지 버전 충돌로 실패. 패키지 버전 조정 후, 추가 시도 후 실패. 결국, 해당 오픈소스의 이슈에 가서 비슷한 버그로 pr 요청이 있길래, 그대로 따라해도 실패. 웹 구동이 되어도 내부 로직에 문제가 있어서 실패.
거의 1시간 가량 소모하다가 포기했습니다.
README에서는 Docker 빌드 후, 실행만 하면 된다더니, 까면 깔수록 끝도 없더군요.</p>
<p>이런 경험 이후, 오픈소스를 고르는 방식을 바꿨습니다.</p>
<h3 id="2-readme는-첫인상이다">2. README는 첫인상이다.</h3>
<p>README는 프로젝트의 첫인상입니다. 다만, 첫인상이 좋다고 결과를 보장하지는 않죠. 잘 작성된 README는 프로젝트가 좋다는 증거가 아닌, 문서화를 잘했다는 증거일 뿐이죠.</p>
<p>스타 수의 착각: 스타는 관심이지 품질을 보장해주지는 않습니다. 2년 전, 바이럴 타서 스타가 많지만, 방치된 프로젝트도 수두룩하죠.</p>
<p>데모 영상: 화려한 데모 영상이 있어도, 그게 최신 버전에서 재현되는지는 별개 문제입니다.</p>
<p>마지막 커밋 날짜: README보다 이게 더 중요할 때가 많습니다. 6개월 이상 커밋이 없다면, 해당 오픈소스 속 의존성 패키지들이 충돌을 일으킬 확률이 높죠.</p>
<h3 id="3-5가지-평가-기준">3. 5가지 평가 기준</h3>
<p>여러 프로젝트를 평가하면서 만든 체크리스트입니다.</p>
<p>(1) 재현 용이성 - 가장 먼저, 실행 안 되면 끝
가장 먼저 확인합니다. 아무리 기능이 좋아도 내 환경에서 돌아가지 않으면 의미가 없죠.
체크 포인트:</p>
<ul>
<li>Docker나 원클릭 설치가 제공되나?</li>
<li>환경 변수나 API키 설정이 얼마나 복잡한가?</li>
<li>GPU 필수인가? 시스템 의존성이 있는가?</li>
<li>이슈탭에 미해결 이슈가 얼마나 있는가?</li>
</ul>
<p>탈락 기준: 문서대로 따라해도 실행이 안 되거나, 삽질이 과하게 필요하면 즉시 탈락</p>
<p>(2) 기능 적합성 - 내 목적에 맞는가</p>
<p>실행이 된다면 이제 기능을 봅니다. 비슷한 기능이 아니라 내가 필요한 기능이 있는지가 핵심입니다.
제 경우 숏폼 영상 생성이 목적이었기에, 전체 파이프라인(스크립트 -&gt; TTS -&gt; 영상 결합 -&gt; 자막 -&gt; 렌더링)이 실제로 연결되어 동작하는지를 봤습니다.</p>
<p>단계별로 체크합니다.</p>
<ul>
<li>스크립트 생성 품질</li>
<li>음성 품질과 옵션</li>
<li>영상 소스 자동 fetch 여부</li>
<li>자막 스타일링</li>
<li>최종 출력물 품질</li>
</ul>
<p>(3) 유지보수/확장성 - 6개월 후에도 쓸 수 있는가
단기 실험용이 아닌, 실제 프로젝트에 쓸 거라면, 유지보수 상태를 봐야 합니다.</p>
<p>체크포인트:</p>
<ul>
<li>코드가 모듈화되어 있는가?</li>
<li>테스트 코드가 있는가?</li>
<li>이슈나 PR에 응답률이 높은가?</li>
</ul>
<p>(4) 기술 스택 적합성 - 내 프로젝트에 붙일 수 있는가
좋은 프로젝트여도 내 스택과 맞지 않으면 비용이 커지죠.</p>
<p>체크포인트:</p>
<ul>
<li>API나 Docker로 분리되어 있어서 호출만 하면 되는 구조인가?</li>
<li>영상 처리 같은 무거운 작업을 워커로 분리할 수 있는가?</li>
<li>CLI만 있는가, REST API가 있는가, SDK가 있는가?</li>
</ul>
<p>제 경우 Next.js 프로젝트에 붙여야 했기 때문에, Docker + FastAPI로 제공되는 프로젝트가 가장 이상적이었습니다.</p>
<p>(5) 운영/제품화 - 실서비스로 갈 수 있는가
MVP를 넘어 실제 서비스로 만들 계획이라면, 운영 관점도 봐야 합니다.</p>
<p>체크포인트:</p>
<ul>
<li>비동기/큐 처리가 되어 있는가? (렌더링 중 서버가 멈추면 안 되므로)</li>
<li>결과물 저장/캐시/조회 흐름이 있는가?</li>
<li>에러 핸들링과 재시도 로직이 있는가?</li>
</ul>
<h3 id="4-실전-적용">4. 실전 적용</h3>
<p>처음 시도했던 오픈소스, 가칭 S는 재현 용이성에서부터 패키지 충돌과 Docker 실패, 이후의 기능 적합성 테스트의 경우에도 잔버그로 인해 진행도 못했으므로 탈락이었습니다.</p>
<p>하지만 기준으로 평가하면: 재현 용이성에서부터 탈락했기 때문에 나머지는 평가할 필요가 없었습니다. 1시간 가량 삽질하기 전에, 이슈 탭에 수두룩하게 쌓여있는 미해결 설치 문제들을 보고 더 빨리 판단할 수 있었을거니까요.</p>
<h3 id="5-템플릿-공유">5. 템플릿 공유</h3>
<p>제가 사용하는 평가 템플릿입니다. 숏폼 영상 자동 생성 프로젝트용으로 작성했기에, 기능 적합성 항목은 본인 프로젝트에 맞게 수정해서 쓰시면 됩니다. 
핵심은 순서대로 평가하고, 탈락하면 즉시 중단하는 것입니다. 앞에서 걸리면 과감히 다음 후보로 넘어가세요.</p>
<p><a href="https://closed-mousepad-38b.notion.site/2d0e77b9d79e8036821df232c7a3051b?source=copy_link">https://closed-mousepad-38b.notion.site/2d0e77b9d79e8036821df232c7a3051b?source=copy_link</a></p>
<hr>
<p>오픈소스 선택에 정답은 없지만, 최소한 README와 스타 수만 보고 결정하는 실수는 피할 수 있습니다. </p>
<p>이 템플릿이 여러분의 삽질 시간을 줄여주길 바랍니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Claude Code 쓰려고 채팅 한 줄 쳤는데 서버가 터졌다!]]></title>
            <link>https://velog.io/@evan_kang/Claude-Code-%EC%93%B0%EB%A0%A4%EA%B3%A0-%EC%B1%84%ED%8C%85-%ED%95%9C-%EC%A4%84-%EC%B3%A4%EB%8A%94%EB%8D%B0-%EC%84%9C%EB%B2%84%EA%B0%80-%ED%84%B0%EC%A1%8C%EB%8B%A4</link>
            <guid>https://velog.io/@evan_kang/Claude-Code-%EC%93%B0%EB%A0%A4%EA%B3%A0-%EC%B1%84%ED%8C%85-%ED%95%9C-%EC%A4%84-%EC%B3%A4%EB%8A%94%EB%8D%B0-%EC%84%9C%EB%B2%84%EA%B0%80-%ED%84%B0%EC%A1%8C%EB%8B%A4</guid>
            <pubDate>Tue, 16 Dec 2025 14:32:52 GMT</pubDate>
            <description><![CDATA[<p>발단은 이렇다.</p>
<p>AWS 서버로 원격 접속으로, VSCode + Claude Code 세팅을 끝내고, 깃 세팅도 끝냈다.</p>
<p>Claude Code for VSCode 확장자도 달아서 흐뭇한 마음으로 채팅을 입력했다.</p>
<p><img src="https://velog.velcdn.com/images/evan_kang/post/4a746c80-efd8-4c11-8c4c-51ea1b2148cc/image.png" alt=""></p>
<p>그 순간</p>
<pre><code>&quot;aws-server&quot;에 연결할 수 없음: 연결 시간이 초과되었습니다.코드를 입력하세요</code></pre><p>그러더니 튕겼다.</p>
<p>창 다시 불러오기, 재연결을 해도 튕겼다.</p>
<p>AWS 콘솔에 들어가보니 여전히 인스턴스는 실행 중이다.
SSH도 잘 살아 있다.</p>
<p>그런데 VS Code만 접속을 거부한다.</p>
<p>왤까.</p>
<p>인스턴스를 재시작하니 정상으로 돌아왔다. 접속에 성공한 것이다.</p>
<p>안심하고, 클로드 코드 사이드바를 열어 채팅을 입력한 순간...
다시 튕겼다.</p>
<p>로컬은 멀쩡하다.
몇 번이나 같은 동작을 해도, 막힘없이 작동한다.</p>
<p>서버 문제 같지도 않았다.</p>
<p>로그를 뒤져봤다.</p>
<p><code>~/.vscode-server/data/logs</code></p>
<p>그리고 extension host 로그에서 이런 문장을 발견했다.</p>
<p><code>Error: chatParticipant must be declared in package.json: claude-code</code></p>
<p>그러고보면 이상했다.
채팅을 입력하는 순간에만 발생했다.</p>
<p>혹시나 해서 GitHub Copilot Chat 확장을 껐다.</p>
<p>그리고 다시 클로드 코드를 열어서 입력하니...</p>
<p>됐다!</p>
<p>원인은 서버가 아니었다.</p>
<p>Claude Code와 Copilot Chat은 둘 다 VS Code의 Chat API를 사용한다.</p>
<p>원격 환경에서 두 확장이 동시에 활성화되면서 충돌이 발생한 것으로 보인다.
(GitHub 계정을 전환한 직후라 Copilot 인증 상태도 불안정했을 수 있다)</p>
<p>결과적으로 Remote Extension Host가 죽으면서,
서버가 터진 것처럼 보이는 타임아웃이 발생했다.</p>
<p>이번에 확실히 체감했다.
로그는 답을 알고 있다.</p>
]]></description>
        </item>
    </channel>
</rss>