<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom"
>
  <channel>
    <title>kinkeep.dev</title>
    <link>https://kinkeep.dev</link>
    <description>Unity 클라이언트 프로그래머의 게임 엔진, 그래픽스, Agentic Coding, Harness Engineering 노트.</description>
    <language>ko</language>
    <lastBuildDate>Tue, 21 Apr 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://kinkeep.dev/feed.xml" rel="self" type="application/rss+xml" />
  <item>
    <title>github.io에서 커스텀 도메인으로 갈아탄 이유</title>
    <link>https://kinkeep.dev/posts/agentic/custom-domain-seo</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/custom-domain-seo</guid>
    <pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate>
    <description>블로그를 만들고 한 달, 구글에 포스트가 하나도 안 잡혔다. 원인을 추적하다 보니 github.io 도메인 자체가 문제였다. kinkeep.dev를 사서 연결했더니 sitemap 처리부터 달라졌다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>블로그를 만들고 한 달이 지났는데 구글에 아무것도 안 나온다.</p>
<p>홈페이지는 색인이 됐다. 근데 포스트가 30개 넘게 있는데 단 하나도 구글이 모른다. URL Inspection을 돌려보면 전부 &quot;URL is unknown to Google&quot;이다. 발견조차 안 된 거다.</p>
<h2>뭐가 문제였나</h2>
<p>처음엔 기술적인 문제를 의심했다. sitemap이 잘못됐나, robots.txt가 막고 있나, 구조화 데이터가 빠졌나. 전부 확인해봤는데 다 정상이었다. sitemap은 접근 가능하고 XML도 유효하고, robots.txt는 Allow: /로 열려있고, JSON-LD도 BlogPosting 스키마까지 다 들어가 있었다.</p>
<p>문제는 sitemap이었다. 정확히는, 구글이 sitemap을 처리하지 않고 있었다. Search Console에서 sitemap 상태를 보면 제출한 지 5일이 지났는데도 <code>isPending: true</code>였다. 구글이 sitemap을 받아놓고 열어보지도 않은 거다.</p>
<p>홈페이지가 색인된 건 sitemap 덕이 아니라 GitHub 레포 페이지에서 링크가 걸려있어서 우연히 발견된 거였다.</p>
<h2>github.io가 불리한 이유</h2>
<p><code>yhc509.github.io</code>는 GitHub Pages의 공유 도메인이다. github.io 밑에 수백만 개의 서브도메인이 있고, 대부분이 방치된 프로젝트 페이지나 README 미러다. 구글 입장에서 이런 도메인에 크롤 예산을 많이 배정할 이유가 없다.</p>
<p>커스텀 도메인이 유리한 점은 세 가지다.</p>
<ol>
<li><strong>독립적인 도메인 권한</strong> — github.io에 세 들어 사는 게 아니라 내 도메인으로 신뢰도를 쌓을 수 있다</li>
<li><strong>크롤 우선순위</strong> — 공유 도메인보다 독립 도메인에 크롤러가 더 적극적으로 온다</li>
<li><strong>장기적 유연성</strong> — 나중에 GitHub Pages를 안 써도 도메인은 유지된다</li>
</ol>
<h2>도메인 선택과 구매</h2>
<p>도메인 등록은 <strong>Cloudflare Registrar</strong>로 했다. 이유는 단순하다. 원가 판매라 갱신 시 가격이 안 오른다. 다른 업체들은 첫 해만 싸게 하고 갱신할 때 올리는 경우가 많은데, Cloudflare는 그게 없다. DNS 설정도 같은 대시보드에서 끝난다.</p>
<p>도메인은 <code>kinkeep.dev</code>로 했다. <code>.dev</code> TLD는 HTTPS가 강제되고 개발 블로그 느낌에 잘 맞는다. 연간 $12.20, 한화로 약 1.7만 원이다.</p>
<h2>연결 과정</h2>
<p>GitHub Pages에 커스텀 도메인을 연결하는 건 생각보다 간단하다.</p>
<p><strong>DNS 설정</strong> — Cloudflare에서 A 레코드 4개를 추가한다. GitHub Pages 서버 IP로, 로드밸런싱을 위해 4개다. Proxy는 끄고 DNS only로 설정해야 한다. GitHub Pages가 자체 TLS를 쓰기 때문에 Cloudflare 프록시를 켜면 인증서가 충돌한다.</p>
<p><strong>코드 변경</strong> — 사이트 URL이 하드코딩된 곳을 전부 바꿔야 한다. 내 경우는 세 군데였다.</p>
<ul>
<li>사이트 기본 URL 설정</li>
<li>RSS 피드 생성 스크립트</li>
<li>GitHub Actions 빌드 환경변수</li>
</ul>
<p>그리고 <code>public/CNAME</code> 파일을 만들어서 도메인을 적어둔다. GitHub Pages가 이 파일을 보고 커스텀 도메인을 인식한다.</p>
<p><strong>GitHub 설정</strong> — 레포 Settings → Pages → Custom domain에 도메인을 넣으면 끝이다. HTTPS 인증서는 Let&#x27;s Encrypt로 자동 발급된다.</p>
<h2>결과</h2>
<p>도메인 연결 후 Google Search Console에 새 속성을 등록하고 sitemap을 제출했다. 여기서 차이가 바로 나타났다.</p>
<p>github.io에서는 sitemap 제출 후 5일이 지나도 <code>isPending</code>이었다. kinkeep.dev에서는 <strong>즉시 처리됐다</strong>. 같은 콘텐츠, 같은 sitemap 구조인데 도메인만 바꿨을 뿐이다.</p>
<p>Indexing API로 37개 URL을 색인 요청한 것도 전부 성공했다. 며칠 뒤 실제 색인 결과를 확인해봐야 하지만, 출발부터 다르다.</p>
<h2>비용 대비 효과</h2>
<p>연간 1.7만 원으로 할 수 있는 가장 확실한 SEO 투자다. 블로그를 GitHub Pages로 운영하면서 구글 색인이 안 되는 사람이 있다면, 코드를 건드리기 전에 커스텀 도메인부터 연결해보는 걸 추천한다.</p>
<p>이전 도메인 <code>yhc509.github.io</code>로 접속하면 자동으로 <code>kinkeep.dev</code>로 리다이렉트된다. 기존에 공유된 링크가 깨질 걱정은 없다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Why I Switched from github.io to a Custom Domain</title>
    <link>https://kinkeep.dev/posts/agentic/custom-domain-seo-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/custom-domain-seo-en</guid>
    <pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate>
    <description>A month after launching my blog, not a single post was indexed by Google. Tracing the root cause led me to the github.io domain itself. After buying kinkeep.dev and connecting it, even sitemap processing changed immediately.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>A month after launching my blog, nothing showed up on Google.</p>
<p>The homepage was indexed. But with over 30 posts live, Google didn&#x27;t know about a single one. Running URL Inspection on each returned &quot;URL is unknown to Google&quot; across the board. They weren&#x27;t even discovered.</p>
<h2>What Was Wrong</h2>
<p>I first suspected technical issues. Bad sitemap? Blocking robots.txt? Missing structured data? I checked everything — all clean. The sitemap was accessible with valid XML, robots.txt was wide open with <code>Allow: /</code>, and JSON-LD had full BlogPosting schema.</p>
<p>The problem was the sitemap — specifically, Google wasn&#x27;t processing it. In Search Console, the sitemap status showed <code>isPending: true</code> five days after submission. Google received it and never opened it.</p>
<p>The homepage got indexed not through the sitemap, but because a link from the GitHub repository page led Google to discover it by accident.</p>
<h2>Why github.io Is Disadvantaged</h2>
<p><code>yhc509.github.io</code> is a shared GitHub Pages domain. Millions of subdomains exist under github.io, most of them abandoned project pages or README mirrors. From Google&#x27;s perspective, there&#x27;s little reason to allocate significant crawl budget to these domains.</p>
<p>A custom domain wins in three ways:</p>
<ol>
<li><strong>Independent domain authority</strong> — you build trust on your own domain instead of renting space under GitHub&#x27;s</li>
<li><strong>Crawl priority</strong> — crawlers are more aggressive with independent domains than shared ones</li>
<li><strong>Long-term flexibility</strong> — the domain stays yours even if you leave GitHub Pages</li>
</ol>
<h2>Choosing and Buying</h2>
<p>I went with <strong>Cloudflare Registrar</strong>. The reason is simple: they sell at cost, so renewal prices don&#x27;t inflate. Other registrars often offer cheap first-year pricing then jack up renewals. Cloudflare doesn&#x27;t play that game, and DNS config lives in the same dashboard.</p>
<p>I picked <code>kinkeep.dev</code>. The <code>.dev</code> TLD enforces HTTPS and fits a dev blog well. It costs $12.20/year.</p>
<h2>The Setup</h2>
<p>Connecting a custom domain to GitHub Pages is straightforward.</p>
<p><strong>DNS</strong> — Add four A records in Cloudflare pointing to GitHub Pages server IPs for load balancing. Proxy must be off (DNS only) because GitHub Pages handles its own TLS — Cloudflare&#x27;s proxy would cause certificate conflicts.</p>
<p><strong>Code changes</strong> — Every hardcoded site URL needs updating. In my case, three places:</p>
<ul>
<li>The site base URL config</li>
<li>The RSS feed generation script</li>
<li>The GitHub Actions build environment variable</li>
</ul>
<p>Plus a <code>public/CNAME</code> file containing the domain name. GitHub Pages reads this to recognize the custom domain.</p>
<p><strong>GitHub settings</strong> — Repository Settings → Pages → Custom domain. Enter the domain, done. HTTPS certificates are auto-provisioned via Let&#x27;s Encrypt.</p>
<h2>Results</h2>
<p>After connecting the domain, I registered a new property in Google Search Console and submitted the sitemap. The difference was immediate.</p>
<p>On github.io, the sitemap stayed <code>isPending</code> for five days. On kinkeep.dev, it was <strong>processed instantly</strong>. Same content, same sitemap structure — only the domain changed.</p>
<p>All 37 URLs submitted via the Indexing API succeeded as well. I&#x27;ll need to check actual indexing results in a few days, but the starting point is already different.</p>
<h2>Cost vs. Impact</h2>
<p>This is the most reliable SEO investment you can make for ~$12/year. If you&#x27;re running a blog on GitHub Pages and struggling with Google indexing, try connecting a custom domain before touching any code.</p>
<p>The old domain <code>yhc509.github.io</code> automatically redirects to <code>kinkeep.dev</code>, so previously shared links won&#x27;t break.</p>]]></content:encoded>
  </item>
  <item>
    <title>맥북프로를 샀다</title>
    <link>https://kinkeep.dev/posts/agentic/macbook-pro-m5</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/macbook-pro-m5</guid>
    <pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate>
    <description>맥미니 하나로 SDXL, Unity, Rider까지 돌리다 한계가 왔다. 맥북프로 M5 Pro를 지르고 나서 개발은 맥북, AI는 맥미니로 나눴더니 생각보다 많은 게 달라졌다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/macbook-pro.jpg"/><p><img src="https://kinkeep.dev/posts-images/agentic/macbook-pro.jpg" alt="맥북프로"/></p>
<p>맥미니 하나로 버텨왔다. SDXL 돌리면서 Unity 열고 Rider까지 띄우면 메모리가 난리가 났다. 그러면서도 머릿속에는 LLM을 로컬에서 돌리고 싶다는 생각이 항상 있었는데, 현실은 SDXL 하나 올리면 이미 빠듯한 상태였다. LLM은 꿈도 못 꿨다.</p>
<p>결국 맥북프로를 샀다. M5 Pro 48기가. 409만 원.</p>
<p>솔직히 마음 같아서는 맥스튜디오를 지르고 싶었다. 128기가, 256기가짜리 올려놓고 진짜 LLM다운 LLM을 로컬에서 굴리는 거다. 근데 그러면 가격이 몇백에서 몇천까지 깨지니까, 취미로 하는 사이드 프로젝트에 그 돈을 넣기엔 아무래도 무리가 있었다.</p>
<p>맥북으로 간 이유는 생각보다 단순했다. 지금 문제가 성능 부족이 아니라 역할이 안 나뉘어 있는 거였다. 맥미니 한 대에 AI 작업이랑 개발을 다 올려놓으니까 둘 다 애매해진 거다. 개발용 머신 하나만 따로 생기면 맥미니를 AI 서버로 돌릴 수 있었다.</p>
<h2>사고 나서</h2>
<p>제일 먼저 느낀 건 좀 뜬금없는 건데, 누워서 코딩이 된다는 거였다. 책상 앞에 앉아야만 개발할 수 있었던 게, 소파에서도 침대에서도 되니까 부담감이 많이 줄었다. 뭔가 해야 된다는 압박이 아니라 하고 싶을 때 열면 되는 느낌. 실제로 맥북 사고 3일 만에 자동화 프로젝트를 하나 만들었다. 이건 다음에 따로 쓰려고 한다.</p>
<h2>맥미니는 이제 AI 서버다</h2>
<p>개발이 맥북으로 빠지니까 맥미니가 편해졌다. 원래 돌리던 SDXL은 그대로 두고, Gemma 4를 MLX로 올렸다. 처음에는 Hermes agent에 물려서 에이전트처럼 쓰려고 했는데, 아직 손볼 데가 있어서 많이 쓰지는 못하고 있다. 방향을 좀 틀어서 에이전트보다는 자동화 쪽으로 활용해 볼 생각이다.</p>
<p>예전에는 SDXL 돌리는 것만으로도 메모리가 빡빡했는데, 지금은 SDXL이랑 LLM을 동시에 띄워도 괜찮다. 역할 나누기 전에는 상상도 못 했던 조합이다.</p>
<h2>결국은 역할 분리</h2>
<p>비싼 머신 하나에 다 때려넣는 것보다 적당한 머신 두 대로 나누는 게 나을 때가 있다. 맥스튜디오 256기가로 다 해결하면 멋지겠지만, 409만 원짜리 맥북 하나 추가하는 걸로 문제가 풀렸다. 맥북은 개발, 맥미니는 AI. 지금은 이 조합이 꽤 잘 맞는다.</p>]]></content:encoded>
  </item>
  <item>
    <title>I Bought a MacBook Pro</title>
    <link>https://kinkeep.dev/posts/agentic/macbook-pro-m5-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/macbook-pro-m5-en</guid>
    <pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate>
    <description>Running SDXL, Unity, and Rider on a single Mac Mini hit a wall. After picking up an M5 Pro MacBook Pro, splitting dev and AI across two machines changed more than I expected.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/macbook-pro.jpg"/><p><img src="https://kinkeep.dev/posts-images/agentic/macbook-pro.jpg" alt="MacBook Pro"/></p>
<p>I&#x27;d been surviving on a single Mac Mini. Running SDXL while opening Unity and Rider wrecked memory. I always wanted to run LLMs locally too, but reality was tight — SDXL alone pushed things to the edge. LLMs weren&#x27;t even on the table.</p>
<p>So I bought a MacBook Pro. M5 Pro, 48 GB. About $2,800.</p>
<p>Honestly, I wanted a Mac Studio. 128 GB, 256 GB — run real LLMs locally, the kind that actually matter. But that means spending thousands more, and for side projects and hobby work, the price just didn&#x27;t make sense.</p>
<p>The reason I went with a MacBook was simpler than expected. The problem wasn&#x27;t raw performance — it was that roles weren&#x27;t separated. Cramming AI work and development onto one machine made both worse. One dedicated dev machine would free the Mac Mini to become an AI server.</p>
<h2>After buying it</h2>
<p>The first thing I noticed was oddly physical. I can code lying down now. Development used to mean sitting at my desk. Now it works from the couch, from bed. Sounds trivial, but the pressure dropped noticeably. Less &quot;I need to sit down and work&quot; and more &quot;I can just open the lid whenever.&quot; I built an automation project within three days of getting the MacBook. I&#x27;ll write about that separately.</p>
<h2>The Mac Mini is now an AI server</h2>
<p>With development off-loaded to the MacBook, the Mac Mini breathes easier. SDXL stays as-is, and I put Gemma 4 on it via MLX. Initially tried wiring it to a Hermes agent, but it still needs tuning so I haven&#x27;t used it much. Shifting direction — planning to use it more for automation than as an agent.</p>
<p>Before the split, SDXL alone maxed out memory. Now SDXL and an LLM run side by side without trouble. A combination I couldn&#x27;t have imagined before.</p>
<h2>It&#x27;s about role separation</h2>
<p>Sometimes two decent machines beat one expensive one. A 256 GB Mac Studio solving everything sounds great, but a $2,800 MacBook addition solved the actual problem. MacBook for dev, Mac Mini for AI. The setup works well for now.</p>]]></content:encoded>
  </item>
  <item>
    <title>Claude의 메모리를 버리고 Obsidian으로 갈아탔다</title>
    <link>https://kinkeep.dev/posts/agentic/obsidian-agent-knowledge-base</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/obsidian-agent-knowledge-base</guid>
    <pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate>
    <description>AI 에이전트의 기억을 디렉토리 단위 메모리에서 Obsidian vault 하나로 통합했다. 프로젝트를 넘나드는 지식 공유가 되고, 문서가 썩는 걸 cron으로 잡는다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Claude Code의 메모리 시스템이 마음에 안 들었다. 디렉토리 단위로 저장된다. A 프로젝트에서 &quot;이렇게 해라&quot;고 가르친 게 B 프로젝트에서는 적용이 안 된다. 어느 폴더에서 뭘 저장시켰는지 내가 기억을 못 한다. A에서는 잘하는데 B에서 멍청한 짓을 하면 메모리 파일을 하나하나 까봐야 한다. 전역 메모리라는 개념 자체가 없다.</p>
<p>프로젝트를 하나만 하면 참을 수 있다. 나는 여러 개를 병렬로 돌린다. kinkeep-unity-cli를 만들면서 쌓인 Unity 에디터 자동화 지식이, 이 CLI를 사용하는 게임 프로젝트에서는 없는 지식이 된다. 같은 사람이 같은 도구를 쓰는데 폴더가 다르다는 이유로 맥락이 단절된다.</p>
<p>문서도 문제였다. 기획서, 설계 문서, 리서치 노트가 프로젝트마다 <code>docs/</code>, <code>plans/</code>, <code>.claude/</code> 같은 곳에 흩어져 있었다. 무슨 문서가 있는지 찾아보기도 어렵고, 더 이상 유효하지 않은 문서가 남아 있으면 에이전트가 그걸 참고해서 작업을 오염시킨다.</p>
<h2>Obsidian vault 하나로 통합</h2>
<p>Obsidian을 지식 저장소로 쓰기로 했다. vault는 하나만 쓴다. 프로젝트 기획 문서, 설계 문서, 리서치 노트, 메모리 전부 이 vault에 들어간다. 프로젝트 내부에는 코드만 남긴다.</p>
<p>Claude Code에서 vault에 접근하는 건 전부 CLI로 한다. 읽기, 쓰기, 검색. Claude가 작업 중에 얻은 지식은 vault에 문서로 정리하고, 다음 세션에서 필요하면 vault에서 읽어온다.</p>
<p>연결고리는 태그다. 모든 문서에 YAML frontmatter 태그를 단다. 프로젝트명 태그, 문서 유형 태그. Claude Code가 특정 프로젝트에 진입하면 태그로 관련 문서를 찾는다. 폴더 구조가 아니라 태그로 연결되니까 하나의 문서가 여러 프로젝트에 걸칠 수 있다.</p>
<p>Obsidian의 그래프 뷰는 사람이 전체 구조를 파악하는 데 쓴다. AI는 그래프 뷰를 못 본다. 대신 문서 안에 있는 위키링크와 태그를 따라간다. 참조를 잘 걸면 그래프 뷰도 의미 있게 나오고, AI도 관련 문서를 찾아갈 수 있다.</p>
<h2>Claude 메모리를 끊었다</h2>
<p>Claude의 내장 메모리 시스템을 더 이상 쓰지 않는다. Claude가 자꾸 메모리를 업데이트하려고 하는데, 그때마다 제지한다. 모든 메모리는 vault의 <code>Memory/</code> 폴더에 들어간다. 각 프로젝트의 로컬 메모리 파일에는 &quot;Obsidian을 보라&quot;는 리다이렉트만 남겨뒀다.</p>
<p>어느 프로젝트에서 세션을 시작하든 같은 메모리에 접근한다. A 프로젝트에서 배운 것이 B 프로젝트에서도 작동한다. 디렉토리 단위라는 제약이 사라진다.</p>
<h2>문서가 썩지 않게</h2>
<p>문서는 만들어놓고 안 관리하면 썩는다. 태그가 빠진 문서는 검색에 안 걸린다. 참조가 끊긴 문서는 고아가 된다. 에이전트가 오래된 문서를 현재 사실인 것처럼 참고하면 작업이 망가진다.</p>
<p>cron job을 돌린다. Obsidian 문서가 규칙대로 잘 되어 있는지 검사하는 스크립트다. 태그가 누락된 문서, 레퍼런스가 끊긴 문서를 찾아낸다. 혹시라도 Claude의 로컬 메모리에 남아 있는 게 있으면 vault로 옮긴다.</p>
<p>사람이 매일 문서를 점검하는 건 불가능하다. 문서가 계속 쌓이니까. 자동화로 품질을 유지하지 않으면 vault도 결국 이전의 파편화된 상태로 돌아간다.</p>
<h2>프로젝트를 넘나드는 지식</h2>
<p>지금 가장 효과를 보는 사례가 kinkeep-unity-cli다. CLI 패키지를 개발하면서 Unity 에디터 자동화, 씬 핸들링, 에셋 관리에 대한 지식이 vault에 쌓인다. 이 CLI를 가져다 쓰는 게임 프로젝트에서 Claude Code를 열면, vault에서 CLI의 동작 방식과 제약 사항을 읽어온다. CLI 개발 맥락을 모르는 상태에서 &quot;이 명령어가 왜 안 되지&quot;를 디버깅하는 것과, 내부 구조를 아는 상태에서 접근하는 것은 다르다.</p>
<p>패키지별로 기능을 쪼개서 병렬 작업을 돌릴 때 특히 유리하다. 각 패키지 프로젝트가 독립된 디렉토리에 있지만, 공유 지식은 vault 하나에 모여 있다. 디렉토리 경계 때문에 맥락이 끊기지 않는다.</p>
<h2>아직 모르는 것</h2>
<p>문서가 더 쌓이면 어떻게 되는지 모른다. 지금은 만족스럽다. 하지만 vault에 문서가 수백 개, 수천 개가 되었을 때 검색 품질이 유지될지, 태그 체계가 버틸지, Claude가 관련 문서를 정확하게 찾아올지는 써봐야 안다.</p>
<p>Andrej Karpathy도 Obsidian은 아니지만 비슷한 걸 시도하고 있는 것 같다. 에이전트한테 외부 지식 저장소를 따로 두는 방식. 도구는 달라도 방향은 같다고 본다. 유행으로 끝나는 건지, 에이전트 운영의 기본 인프라가 되는 건지는 더 써봐야 안다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Ditched Claude&apos;s Memory for Obsidian</title>
    <link>https://kinkeep.dev/posts/agentic/obsidian-agent-knowledge-base-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/obsidian-agent-knowledge-base-en</guid>
    <pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate>
    <description>Moved AI agent memory from directory-scoped storage to a single Obsidian vault. Cross-project knowledge sharing works, and cron jobs keep the docs from rotting.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Claude Code&#x27;s memory system didn&#x27;t work for me. It&#x27;s directory-scoped. Something you teach it in project A doesn&#x27;t carry over to project B. I can&#x27;t even remember which folder I saved which memory in. It works fine in A, does something stupid in B, and I have to dig through memory files one by one to figure out why. There&#x27;s no concept of global memory.</p>
<p>If you only work on one project, it&#x27;s tolerable. I run several in parallel. Knowledge about Unity editor automation that I built up while developing kinkeep-unity-cli becomes nonexistent knowledge in the game project that uses that CLI. Same person, same tools, but context is severed because the folder is different.</p>
<p>Documents were a problem too. Specs, design docs, and research notes were scattered across <code>docs/</code>, <code>plans/</code>, <code>.claude/</code> in every project. Hard to even find what documents exist. When outdated docs stick around, the agent references them and contaminates the work.</p>
<h2>One Obsidian Vault</h2>
<p>Decided to use Obsidian as the knowledge store. One vault only. Project specs, design docs, research notes, memory — everything goes in this vault. Projects only keep code.</p>
<p>Claude Code accesses the vault entirely through CLI. Read, write, search. Knowledge gained during a session gets written to the vault as a document. Next session pulls from the vault when needed.</p>
<p>The connective tissue is tags. Every document gets YAML frontmatter tags — project name, document type. When Claude Code enters a specific project, it finds related documents by tag. Since the link is tags rather than folder structure, a single document can span multiple projects.</p>
<p>Obsidian&#x27;s graph view is for humans to grasp the overall structure. AI can&#x27;t see the graph view. It follows wikilinks and tags inside documents instead. Wire the references well and the graph view becomes meaningful for humans, while AI can navigate to related documents too.</p>
<h2>Cut Off Claude&#x27;s Memory</h2>
<p>I no longer use Claude&#x27;s built-in memory system. Claude keeps trying to update its memory, and I stop it every time. All memory goes into the vault&#x27;s <code>Memory/</code> folder. Each project&#x27;s local memory file just has a redirect that says &quot;look at Obsidian.&quot;</p>
<p>Whichever project you start a session in, you hit the same memory. What&#x27;s learned in project A works in project B. The directory-scoped constraint is gone.</p>
<h2>Keeping Docs From Rotting</h2>
<p>Documents rot when you create them and don&#x27;t maintain them. A document missing tags won&#x27;t show up in searches. A document with broken references becomes an orphan. When an agent treats an outdated document as current fact, work breaks.</p>
<p>I run a cron job. A script that checks whether Obsidian documents follow the rules. Finds documents with missing tags, broken references. If anything lingers in Claude&#x27;s local memory, it gets moved to the vault.</p>
<p>Manually reviewing documents every day is impossible. They keep piling up. Without automation to maintain quality, the vault eventually degrades back to the same fragmented state as before.</p>
<h2>Knowledge Across Projects</h2>
<p>The clearest win right now is kinkeep-unity-cli. As I develop the CLI package, knowledge about Unity editor automation, scene handling, and asset management accumulates in the vault. When I open Claude Code in a game project that uses this CLI, the vault serves up how the CLI works and what its constraints are. Debugging &quot;why isn&#x27;t this command working&quot; without CLI development context versus approaching it with knowledge of the internals — completely different.</p>
<p>Especially useful when splitting features into packages and running parallel work. Each package project lives in its own directory, but shared knowledge is in one vault. Directory boundaries don&#x27;t break context.</p>
<h2>What I Don&#x27;t Know Yet</h2>
<p>I don&#x27;t know what happens when more documents pile up. Right now I&#x27;m satisfied. But whether search quality holds when the vault has hundreds or thousands of documents, whether the tag system scales, whether Claude accurately finds relevant documents — I&#x27;ll only know by using it.</p>
<p>Andrej Karpathy seems to be trying something similar, though not with Obsidian. Giving the agent a separate external knowledge store. Different tools, same direction. Whether this is a passing trend or becomes basic infrastructure for running agents — I&#x27;ll have to keep using it to find out.</p>]]></content:encoded>
  </item>
  <item>
    <title>본부 개발자 앞에서 Claude Code를 발표했다</title>
    <link>https://kinkeep.dev/posts/agentic/claude-code-presentation-retrospective</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/claude-code-presentation-retrospective</guid>
    <pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate>
    <description>본부 개발자 대상 Claude Code 발표 후기. 개발, 이슈트래킹, 기획서 체크리스트 변환 등 직접 쓰고 있는 사례를 발표하면서 정리된 생각들.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>어제 본부 개발자 대상으로 Claude Code 발표를 했다. 나 포함 세 명이 나눠서 진행했는데, 앞쪽은 왜 Claude Code를 골랐는지, 에이전트 코딩이 지금 어디까지 왔는지, 하네스 엔지니어링이 뭔지를 다뤘고, 내 파트는 실제 사용 사례였다.</p>
<p>발표를 준비하면서 제일 많이 생각한 건 사례 자체보다 &quot;이걸 어떤 톤으로 말해야 하나&quot;였다. 본부 인원들이 AI에게 코드를 맡기는 걸 어떻게 바라보는지 모른다. 긍정적일 수도 있고, 불안하게 볼 수도 있다. 그래서 발표 톤을 잡을 때 나름 신경 쓴 지점이 있다.</p>
<h2>개발</h2>
<p>집에서는 코드를 100% AI에게 맡기고 있다. 혼자 하는 작업이니 부담이 없다. 공부하거나 외부에 공개할 때만 코드를 직접 본다.</p>
<p>실무는 다르다. 잘못된 코드가 올라가면 내가 책임져야 한다. 그래서 발표에서는 이 차이를 일부러 강조했다.</p>
<p>AI에게 코드를 맡기되, 방치하지 않는다. 커밋 전에 diff를 꼼꼼하게 보고, 변수명이나 함수명이 스타일에 안 맞으면 바로 개입해서 바꾼다. 코드 구조가 마음에 안 들면 거침없이 방향을 틀게 한다.</p>
<p>처음부터 큰 일을 맡긴 건 아니다. 한 달 반 전쯤, 작은 개발 작업부터 시작했다. 괜찮겠다 싶으면 범위를 넓혔고, 지금은 대형 콘텐츠 개발까지 진행 중이다.</p>
<p>발표를 준비하면서 이 흐름을 돌아보니, 결국 감각의 문제였다. AI에게 코드를 맡긴다는 건 &quot;코딩을 안 한다&quot;가 아니라 &quot;코딩의 형태가 바뀐다&quot;에 가까웠다. 직접 타이핑하는 대신 방향을 잡아주고, 결과를 판별하고, 개입 시점을 고른다. 그게 지금 내가 느끼는 에이전트 코딩이다.</p>
<h2>이슈트래킹</h2>
<p>이슈 하나가 지라에 올라오면, 보통 백트레이스 같은 수집 사이트에 가서 관련 로그를 직접 찾는다. 필터 걸고, 검색하고, 유사 사례 비교하고. 시간이 꽤 든다.</p>
<p>이걸 스킬로 만들었다. 지라에 올라온 정보를 복붙하면 Claude가 내용을 파악하고 필터를 결정해서 CLI로 수집 사이트를 조회한다. 유사 사례까지 같이 보고해준다. URL이든 이슈 본문이든 붙여넣고 기다리면 끝이다.</p>
<p>이 사례를 발표에 넣은 건, 작업이 병렬로 돌아간다는 점 때문이다. 내가 다른 일을 하고 있는 동안 Claude가 이슈를 파고 있다. 이슈 파악을 위해 하던 일을 멈출 필요가 없다.</p>
<p>코드를 맡기는 사례만 보여주면 &quot;코딩 대신 해주는 도구&quot;라는 인상에 머물 수 있다. 코딩 바깥에서도 에이전트가 시간을 벌어준다는 걸 같이 보여주고 싶었다.</p>
<h2>기획서를 작업 체크리스트로</h2>
<p>나는 원래 개발할 때 기획서를 읽으면서 직접 체크리스트를 만든다. 뭘 구현해야 하는지, 어떤 순서로 갈지를 정리해두고 하나씩 지우는 식이다.</p>
<p>이걸 Claude에게 넘겨봤다.</p>
<p>처음 만든 버전(v1)은 기획서를 그냥 던져서 체크리스트를 뽑게 했다. 결과가 나쁘진 않았다. 오히려 내가 수작업으로 만들 때보다 항목이 3배 가까이 나왔다. 꼼꼼한 건 맞는데, 누락도 있었다.</p>
<p>v2에서는 기획서를 바로 체크리스트로 바꾸지 않고, 원문을 먼저 분해하고 그룹화하는 단계를 넣었다. 체크리스트가 v1보다 2배쯤 더 촘촘해졌다. 대신 새로운 문제가 생겼다. 기획서에서 명확히 정해지지 않은 회색영역을 Claude가 판단하지 못했다. &quot;이것도 해야 하나?&quot; 싶은 항목이 잔뜩 생겨서 리스트가 불필요하게 길어졌다.</p>
<p>발표 범위에는 안 들어갔지만, 오늘 v3를 만들었다. 기획서를 분석하기 전에 나한테 먼저 인터뷰를 한다. 회색영역에 대해 &quot;이건 넣을 건가요, 뺄 건가요&quot;를 물어보고, 그 답을 기반으로 체크리스트를 만든다.</p>
<p>체크리스트는 마크다운 파일로 나온다. 개발할 때는 Claude와 이 파일을 같이 보면서 &quot;오늘은 이거 만들자&quot; 하는 식으로 진행한다.</p>
<p>한계는 있다. 기획서와 실제 코드 상황은 다르다. 기획서에서는 깔끔하게 분리된 기능이 코드에서는 서로 엮여 있을 수 있고, 기획서에 없는 기술적 제약이 있을 수도 있다. 체크리스트만 믿고 개발하면 안 된다.</p>
<h2>LSP</h2>
<p>실 프로젝트를 대상으로 LSP가 얼마나 효율적인지 직접 테스트해본 사례도 넣었다. 이건 이전에 글로 정리해둔 게 있다.</p>
<p>궁금하면 여기에 자세히 썼다: <a href="https://kinkeep.dev/posts/agentic/claude-code-lsp-token-efficiency">Claude Code의 LSP는 토큰을 줄여줄까</a></p>
<p>&quot;남들이 좋다고 하니까 쓴다&quot;가 아니라 직접 검증해보는 태도를 보여주고 싶었다. 도구가 실제로 어떤 차이를 만드는지는 직접 돌려봐야 안다.</p>
<h2>insights</h2>
<p>Claude Code에는 <code>/insights</code>라는 명령어가 있다. 그동안의 대화를 분석해서 사용 패턴을 요약하고 평가해준다.</p>
<p>내 사용 사례를 정리해서 보여주기 좋았고, 본부 인원들이 직접 돌려봤으면 하는 마음도 있었다. Claude Code를 쓰기 시작하면 자기 나름의 패턴이 생기는데, insights를 돌려보면 그게 어떤 모양인지 한눈에 보인다. 자기 사용 방식을 돌아보는 데 꽤 쓸만하다.</p>
<h2>발표를 준비하고 나서</h2>
<p>발표 준비가 나한테도 정리가 됐다. 평소에 그냥 쓰고 있던 걸 남한테 설명하려고 꺼내놓으니까, 내가 왜 이렇게 쓰고 있는지가 선명해졌다.</p>
<p>에이전트한테 일을 맡기는 건, 처음부터 크게 믿고 시작한 게 아니었다. 작은 일부터 맡기면서 감을 잡았고, 지금도 맡기고 나서 확인하는 루프는 빠지지 않는다. 그게 없으면 실무에서는 못 쓴다.</p>
<p>발표가 끝나고 메신저로 Claude Code 설정법을 물어보는 사람이 몇 있었다. 직접 깔아서 써보겠다는 뜻이니까, 일단은 전달이 된 것 같다.</p>]]></content:encoded>
  </item>
  <item>
    <title>I Presented Claude Code to Our Division&apos;s Developers</title>
    <link>https://kinkeep.dev/posts/agentic/claude-code-presentation-retrospective-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/claude-code-presentation-retrospective-en</guid>
    <pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate>
    <description>Retrospective on presenting Claude Code to division developers. Development, issue tracking, spec-to-checklist conversion — what I thought about while preparing to show how I actually use it.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Yesterday I gave a Claude Code presentation to the developers in our division. Three of us split it up — the others covered why we picked Claude Code, the current state of agentic coding, and what harness engineering is. My section was real use cases.</p>
<p>What I thought about most while preparing wasn&#x27;t the cases themselves. It was the tone. I had no idea how these people felt about delegating code to AI. Some might be into it. Some might think it&#x27;s reckless. That shaped how I framed everything.</p>
<h2>Development</h2>
<p>At home I delegate 100% of code to AI. Solo work, no stakes. I only look at the code when I&#x27;m studying or publishing something.</p>
<p>Work is different. Bad code ships under my name. So I deliberately emphasized this gap in the presentation.</p>
<p>I delegate to AI but I don&#x27;t walk away. I review diffs before every commit. If variable names or function names don&#x27;t match the style, I step in immediately. If the code structure feels wrong, I redirect without hesitation.</p>
<p>I didn&#x27;t start big. About six weeks ago, small dev tasks first. If things went fine, I expanded scope. Now I&#x27;m running large-scale content development through it.</p>
<p>Looking back at this progression while preparing the talk, it came down to feel. Delegating code to AI isn&#x27;t &quot;not coding.&quot; It&#x27;s coding in a different shape. Instead of typing, you set direction, judge output, and pick when to intervene. That&#x27;s what agentic coding feels like to me right now.</p>
<h2>Issue tracking</h2>
<p>When an issue lands in Jira, I usually go to a crash collection service like Backtrace and manually search for related logs. Set filters, search, compare similar cases. Takes a while.</p>
<p>I built a skill for this. Paste the Jira info and Claude reads the content, decides on filters, and queries the collection service via CLI. Reports similar cases too. Paste and wait — that&#x27;s it.</p>
<p>I included this because the work runs in parallel. While I&#x27;m doing something else, Claude is digging through the issue. I don&#x27;t have to stop what I&#x27;m working on to investigate.</p>
<p>If I only showed cases about delegating code, the impression stays at &quot;a tool that codes for you.&quot; I wanted to show that the agent saves time outside of coding too.</p>
<h2>Spec to task checklist</h2>
<p>When I develop, I normally read the spec and build my own checklist. What to implement, in what order, crossing items off as I go.</p>
<p>I handed this to Claude.</p>
<p>The first version (v1) just fed the spec and extracted a checklist. Results weren&#x27;t bad. Actually produced about 3x more items than I&#x27;d make by hand. Thorough, but had gaps.</p>
<p>v2 didn&#x27;t go straight from spec to checklist. It decomposed and grouped the source text first. About 2x more granular than v1. But a new problem appeared. Claude couldn&#x27;t judge gray areas — things the spec didn&#x27;t explicitly define. &quot;Should this be included?&quot; items piled up and the list got unnecessarily long.</p>
<p>This wasn&#x27;t in the presentation, but today I built v3. Before analyzing the spec, it interviews me first. Asks &quot;include this or skip it?&quot; for each gray area, then builds the checklist from those answers.</p>
<p>The checklist comes out as a markdown file. During development, Claude and I look at this file together — &quot;let&#x27;s build this one today.&quot;</p>
<p>There are limits. A spec is not the codebase. Features that look cleanly separated in the spec can be tangled in code. Technical constraints not in the spec can exist. You can&#x27;t just trust the checklist and code blindly.</p>
<h2>LSP</h2>
<p>I also included a case where I tested LSP efficiency on a real project. I already wrote about this separately.</p>
<p>Details here: <a href="https://kinkeep.dev/posts/agentic/claude-code-lsp-token-efficiency-en">Does Claude Code&#x27;s LSP Actually Save Tokens?</a></p>
<p>I wanted to show the attitude of verifying things yourself instead of using something because everyone says it&#x27;s good. You don&#x27;t know what difference a tool actually makes until you run the test.</p>
<h2>insights</h2>
<p>Claude Code has a <code>/insights</code> command. It analyzes your conversation history and summarizes your usage patterns with an evaluation.</p>
<p>It was useful for showing my own use cases in a condensed form, and I hoped the division members would try running it themselves. Once you start using Claude Code, you develop your own patterns. Running insights shows you what those patterns look like at a glance. Pretty useful for reflecting on how you work.</p>
<h2>After preparing the presentation</h2>
<p>Preparing the talk organized things for me too. Pulling out stuff I&#x27;d been using without much thought, trying to explain it to others — that&#x27;s when it became clear why I use things the way I do.</p>
<p>Delegating to an agent isn&#x27;t something I started with high trust. I started with small tasks and built a feel for it. Even now, the loop of delegating then checking never drops out. Without that loop, you can&#x27;t use this at work.</p>
<p>After the talk, a few people messaged me asking how to set up Claude Code. They want to install it and try it themselves. So the message got through, at least.</p>]]></content:encoded>
  </item>
  <item>
    <title>다른 세션의 대화를 블로그 소재로 쓴다</title>
    <link>https://kinkeep.dev/posts/agentic/cmux-blog-sourcing</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/cmux-blog-sourcing</guid>
    <pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate>
    <description>cmux로 다른 Claude Code 세션의 대화를 읽고, 블로그 글감이 되는지 판단하는 과정을 기록했다. 4개 세션 중 쓸 만한 소재는 하나였다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Claude Code 세션을 여러 개 띄워놓고 작업하다 보면, 세션마다 꽤 괜찮은 대화가 쌓인다. 레포를 분석하면서 &quot;이건 쓸 만하다, 이건 허풍이다&quot;라고 판단한 것. 도구를 세팅하면서 &quot;이렇게 하니까 안 된다&quot;고 겪은 것. 이런 관찰과 판단이 세션 화면에 텍스트로 남아있다.</p>
<p>문제는 세션이 독립적이라는 것이다. A 세션에서 겪은 건 B 세션이 모른다. 사람은 여러 탭을 왔다갔다 하면서 머릿속으로 맥락을 연결하지만, AI는 자기 세션 밖을 볼 수 없다.</p>
<p>cmux를 쓰면 이 벽이 없어진다.</p>
<h2>cmux와 read-screen</h2>
<p>cmux는 tmux와 비슷한 터미널 멀티플렉서인데 Claude Code에 특화된 기능이 있고 CLI를 지원한다. CLI가 있다는 게 핵심이다. Claude가 명령어로 다른 세션의 화면을 읽고 메시지를 보낼 수 있다.</p>
<p>이번에 쓴 명령어는 두 개다.</p>
<pre><code class="language-bash">cmux tree --all                        # 전체 워크스페이스/세션 구조 보기
cmux read-screen --surface surface:24 --scrollback --lines 200  # 다른 세션 화면 읽기
</code></pre>
<p><code>tree</code>로 지금 어떤 세션이 떠 있는지 보고, <code>read-screen</code>으로 특정 세션의 화면을 읽는다. 사람이 탭을 전환하면서 머릿속으로 하던 일을 AI가 CLI로 하는 것이다.</p>
<p>cmux는 이 외에도 워크스페이스 생성/삭제, 메시지 전송(<code>send</code>), 브라우저 제어, 스크린샷, 알림 등 꽤 많은 명령을 지원한다. 이 명령어들을 Claude Code 스킬로 묶어서 <code>cmux-collab</code>이라는 이름을 붙여뒀다. 스킬에는 병렬 리서치를 위한 스웜 디스패치, 버그 토론을 위한 adversarial debugging 프로토콜도 정의되어 있는데, 이번에 쓴 건 가장 단순한 패턴이다. 다른 세션 읽기.</p>
<p>제약은 두 가지다. <code>read-screen</code>은 터미널 스크롤백 버퍼에 있는 텍스트만 읽는다. 접힌 출력이나 버퍼 한계를 넘어간 내용은 못 읽으니, 오래된 대화일수록 앞부분이 잘려나간다. 그리고 다른 세션의 화면을 읽어오면 그 텍스트가 현재 세션의 컨텍스트에 들어간다. 읽는 세션이 많아질수록 컨텍스트 여유가 줄어든다. 무한정 읽을 수는 없고 필요한 세션만 골라야 한다.</p>
<h2>4개 세션을 훑었다</h2>
<p>블로그 세션에서 다른 세션들의 화면을 읽도록 시켰다. &quot;글 소재가 될 만한 게 있는지 봐라.&quot;</p>
<p>읽은 세션은 네 개였다.</p>
<p><strong>surface 24</strong> — Claude Code Game Studios라는 GitHub 레포(Stars 6,500) 분석. 에이전트 48개 계층 구조를 해부하고 실용적인 부분을 추렸다.</p>
<p><strong>surface 25</strong> — garrytan/gstack 레포 분석. Hook, Skill 시스템 중심으로 쓸 만한 패턴을 A/B/C 등급으로 분류.</p>
<p><strong>surface 26</strong> — cmux-collab 스킬 개발. AI 코디네이터의 작동 조건을 도출하고 프리플라이트 인터뷰 개념을 스킬에 반영했다.</p>
<p><strong>surface 40</strong> — Obsidian vault 3개를 하나로 합치는 작업. 커뮤니티 사례 조사, 심링크 구조 설계, hook 설정이 진행 중이었다.</p>
<h2>4개 중 1개가 글이 됐다</h2>
<p>전부 읽고 소재를 걸렀다. 걸러지는 기준이 있었다.</p>
<p>surface 24와 25는 같은 맥락이었다. 두 레포를 비교 분석한 내용에 내 에이전트 사용 경험을 붙이면 글이 된다고 판단했다. 내가 직접 에이전트를 나눠봤다가 실패한 경험이 있어서, 남의 레포를 까는 게 아니라 같은 문제에 닿은 이야기가 됐다. 여기서 &quot;에이전트 48개짜리 AI 게임 스튜디오를 까봤다&quot;라는 글이 나왔다.</p>
<p>surface 26은 AI 코디네이터 실험 이야기인데, 아직 테스트 수준이라 경험이 얇았다. 초안까지 써봤는데 결국 &quot;AI 회사를 까는 글&quot;이 되길래 지웠다. &quot;해봤더니 이랬다&quot;가 아니라 &quot;하는 중이다&quot;는 글이 안 된다. 본격적으로 돌려본 다음에 쓰기로 했다.</p>
<p>surface 40은 Obsidian 세팅이 한창 진행 중이었다. 세팅이 끝나고 한동안 써봐야 경험이 나온다. 지금 쓰면 설정 가이드가 되는데, 그건 내 블로그에서 하는 글이 아니다.</p>
<p>정리하면 세 가지다. <strong>경험이 완결됐는가.</strong> <strong>내 관찰이 들어가는가.</strong> <strong>설정 가이드가 되진 않는가.</strong></p>
<h2>대화가 대본이 된다</h2>
<p>이 과정의 핵심은, Claude와의 대화 자체가 블로그 포스팅의 대본 원본이 된다는 것이다. 뭘 시도했고, 왜 안 됐고, 뭘 골랐는지가 대화 안에 이미 있다. 그걸 읽고 소재를 고르고 인터뷰로 보강하면 별도의 취재 없이 글이 나온다.</p>
<p>예전에 <a href="https://kinkeep.dev/posts/agentic/codex-blog-posting">Codex로 블로그를 정리하고 포스팅하는 흐름</a>을 쓸 때는, 하나의 세션 안에서 인터뷰로 경험을 끌어내고 글을 다듬는 과정이었다. 이번에는 소재 발굴 단계가 앞에 붙었다. 여러 세션의 대화를 읽어서 &quot;이건 글이 되겠다&quot;를 먼저 판단하고, 그다음 같은 인터뷰 과정을 돌린다. 소재 찾기와 글쓰기가 한 루프로 연결된 셈이다.</p>
<p>세션 하나에서 작업하면 그 세션의 맥락만 보인다. cmux로 다른 세션을 읽으면 내가 오늘 뭘 했는지 전체가 보인다. 블로그 소재뿐 아니라 회고, 문서화, 핸드오프에도 같은 패턴을 쓸 수 있을 것 같다.</p>
<p>그리고 이 방식의 가장 큰 장점은 글쓰기의 부담이 줄어든다는 것이다. 대화가 대본이니까 따로 준비할 게 없다. 평소에 작업하면서 나눈 대화가 쌓이고, 나중에 그걸 훑어서 글감을 고르면 된다. 글을 쓰기 위해 별도의 시간을 내는 게 아니라 이미 한 작업에서 글이 나온다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Turning Other Sessions&apos; Conversations into Blog Material</title>
    <link>https://kinkeep.dev/posts/agentic/cmux-blog-sourcing-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/cmux-blog-sourcing-en</guid>
    <pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate>
    <description>Used cmux to read conversations from other Claude Code sessions and judge whether they&apos;d make blog posts. Out of 4 sessions, one became a post.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Run multiple Claude Code sessions at once and each one accumulates decent conversations. Judgments made while analyzing a repo — &quot;this is useful, that&#x27;s hype.&quot; Things hit while setting up a tool — &quot;this approach doesn&#x27;t work.&quot; These observations sit as text on the session screen.</p>
<p>The problem is sessions are isolated. What happened in session A, session B doesn&#x27;t know. Humans tab between windows and connect context in their heads. AI can&#x27;t see outside its own session.</p>
<p>cmux removes that wall.</p>
<h2>cmux and read-screen</h2>
<p>cmux is a terminal multiplexer similar to tmux but with Claude Code-specific features and CLI support. The CLI is what matters. It lets Claude read other sessions&#x27; screens and send messages via commands.</p>
<p>Two commands were enough for this:</p>
<pre><code class="language-bash">cmux tree --all                        # view full workspace/session structure
cmux read-screen --surface surface:24 --scrollback --lines 200  # read another session&#x27;s screen
</code></pre>
<p><code>tree</code> shows what sessions are running. <code>read-screen</code> pulls text from a specific session&#x27;s screen. What a human does by switching tabs and connecting dots in their head — the AI does via CLI.</p>
<p>cmux supports plenty more — workspace management, message sending (<code>send</code>), browser control, screenshots, notifications. I&#x27;ve bundled these into a Claude Code skill called <code>cmux-collab</code>. The skill also defines protocols for swarm dispatch (parallel research) and adversarial debugging (multi-session bug debates), but what I used this time was the simplest pattern: reading other sessions.</p>
<p>Two constraints. <code>read-screen</code> only reads what&#x27;s in the terminal scrollback buffer. Collapsed output and anything past the buffer limit can&#x27;t be read — older conversations lose their beginning. And every screen you read dumps that text into the current session&#x27;s context. The more sessions you read, the less context headroom you have. You can&#x27;t read everything — pick the sessions that matter.</p>
<h2>Scanning 4 Sessions</h2>
<p>From the blog session, I told the AI to read the other sessions&#x27; screens. &quot;Check if there&#x27;s anything worth writing about.&quot;</p>
<p>Four sessions:</p>
<p><strong>surface 24</strong> — Analysis of Claude Code Game Studios, a GitHub repo with 6,500 stars. Dissected the 48-agent hierarchy and extracted the practical parts.</p>
<p><strong>surface 25</strong> — Analysis of garrytan/gstack. Classified useful patterns from the Hook and Skill system into A/B/C tiers.</p>
<p><strong>surface 26</strong> — Building the cmux-collab skill. Derived conditions for an AI coordinator and added a preflight interview concept to the skill.</p>
<p><strong>surface 40</strong> — Merging 3 Obsidian vaults into one. Community research, symlink structure design, hook configuration still in progress.</p>
<h2>1 Out of 4 Became a Post</h2>
<p>Read everything and filtered. There were criteria.</p>
<p>Surfaces 24 and 25 were the same thread. Combining the comparative repo analysis with my own failed experience splitting agents into roles — it wasn&#x27;t just critiquing someone else&#x27;s repo but landing on the same problem from my own angle. That became &quot;I Tore Open a 48-Agent AI Game Studio.&quot;</p>
<p>Surface 26 was about an AI coordinator experiment, but still at test level — too thin on experience. I wrote a draft and it turned into &quot;trashing AI companies&quot; rather than a real account. Deleted it. Writing it after actually running the coordinator properly.</p>
<p>Surface 40 was mid-setup for Obsidian. Need to finish the setup and actually use it for a while before there&#x27;s anything to write about. Writing it now would produce a setup guide, and that&#x27;s not the kind of post I do here.</p>
<p>Three filters: <strong>Is the experience complete?</strong> <strong>Does my own observation go in?</strong> <strong>Would it become a setup guide?</strong></p>
<h2>Conversations Become Scripts</h2>
<p>The core of this process: conversations with Claude become the raw script for blog posts. What was tried, what failed, what was chosen — it&#x27;s already in the conversation. Read it, pick the material, supplement with an interview, and you get a post without separate research.</p>
<p>When I wrote <a href="https://kinkeep.dev/posts/agentic/codex-blog-posting">the Codex blog posting workflow</a> before, it was about extracting experience through interviews within a single session and polishing drafts. This time, a material discovery step was added up front. Read conversations across sessions, judge &quot;this could be a post,&quot; then run the same interview process. Sourcing and writing connected in one loop.</p>
<p>Working in a single session, you only see that session&#x27;s context. Reading other sessions through cmux shows what I did today across the board. The same pattern could work for retrospectives, documentation, and handoffs — not just blog material.</p>
<p>And the biggest advantage of this approach: writing becomes less of a burden. Conversations are the script, so there&#x27;s nothing to prepare separately. Conversations from regular work pile up, and later you scan through them to pick material. Posts come from work already done, not from carving out time to write.</p>]]></content:encoded>
  </item>
  <item>
    <title>에이전트 48개짜리 AI 게임 스튜디오를 까봤다</title>
    <link>https://kinkeep.dev/posts/agentic/agent-48-game-studio</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/agent-48-game-studio</guid>
    <pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate>
    <description>GitHub Stars 6,500짜리 &apos;AI 게임 스튜디오&apos; 레포를 해부했다. 에이전트 48개 계층은 조직도 코스프레였고, 진짜 쓸 만한 건 Hook 스크립트 하나였다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>나도 에이전트를 조직 구조로 나눠보려고 시도한 적이 있다. 리뷰 에이전트, 코딩 에이전트, 버그 분석 에이전트. 잘 되지 않았다. 에이전트 간에 업무를 전달하는 과정에서 불필요한 토큰 소모와 컨텍스트 누락이 발생했다. 내 실력이 부족한 건지, 구조 자체가 아직 안 되는 건지 궁금했다.</p>
<p>그러다 GitHub에서 Claude Code Game Studios라는 레포를 봤다. Stars 6,500에 Forks 900. &quot;48명의 AI 에이전트가 게임을 만드는 스튜디오&quot;라는 컨셉이다. 이게 정말 잘 작동하나? 까봤다.</p>
<h2>48명이 일하는 구조</h2>
<p>레포를 열어보면 게임 코드는 없다. <code>.claude/</code> 폴더에 에이전트 정의, 스킬, 훅, 룰만 들어있다. 템플릿이다.</p>
<p>에이전트 계층이 3단계로 나뉜다.</p>
<ul>
<li><strong>Director</strong> 3명 — Creative Director, Technical Director, Production Director. Opus 모델.</li>
<li><strong>Lead</strong> 8명 — Game Designer, Engine Lead, AI Lead 등. Sonnet 모델.</li>
<li><strong>Specialist</strong> 37명 — Gameplay Programmer, Shader Artist, QA Tester 등. Sonnet 또는 Haiku 모델.</li>
</ul>
<p>실제 회사 조직도를 그대로 옮겨 놨다.</p>
<h2>조직도 코스프레</h2>
<p>내가 겪은 문제가 그대로 있었다. 규모만 더 컸다.</p>
<p>에이전트 간 상태 공유가 안 된다. Claude Code 서브에이전트는 매번 새 컨텍스트로 시작한다. Creative Director가 판단하고 Game Designer에게 넘기고 Gameplay Programmer가 코드를 짜는 체인에서, 각 에이전트는 이전 에이전트가 뭘 했는지 모른다. 내가 2~3개로 시도했을 때 이미 토큰 낭비와 컨텍스트 누락이 발생했는데, 48개면 어떨지 뻔하다.</p>
<p>1인 개발에 조직 구조는 오버헤드다. 실제 스튜디오에서 Director-Lead-Specialist 계층이 필요한 이유는 사람들 사이의 소통과 의사결정 병목을 관리하기 위해서다. 혼자 개발하는데 에스컬레이션 경로가 왜 필요한가.</p>
<p>그리고 경계를 인위적으로 나누면 오히려 느려진다. Gameplay Programmer, Engine Programmer, AI Programmer를 분리해뒀는데, 실제 게임 코드에서 이 세 영역은 긴밀하게 결합되어 있다. 에이전트를 바꿔가며 작업하면 컨텍스트 전환 비용만 늘어난다.</p>
<h2>에이전트 역할은 프롬프트로 안 갈린다</h2>
<p>내가 직접 써보면서 느낀 건데, 에이전트의 역할을 구분하는 건 프롬프트 지침이 아니라 활성화된 스킬과 명령어 권한이다.</p>
<p>&quot;버그 분석에 집중해라&quot;고 프롬프트에 적어봤자, 범용 에이전트와 체감 차이가 없다. 실제로 잘 쓰고 있는 에이전트는 지엽적으로 한 역할만 하는 것들이다. git merge conflict만 해결하는 에이전트, 문서를 분석하고 해체해서 재조립하는 에이전트. 명확한 역할과 그에 맞는 도구 권한이 있을 때 비로소 분리의 의미가 생긴다.</p>
<p>Game Studios 레포는 48개 에이전트를 전부 마크다운 프롬프트로만 구분했다. 스킬이나 권한 차이가 없다. 그러면 &quot;Creative Director&quot;와 &quot;Technical Director&quot;가 뭐가 다른가.</p>
<h2>모델 배정이 거꾸로다</h2>
<p>여기에 더해서 &quot;색칠놀이&quot; 냄새가 결정적으로 나는 부분이 있다.</p>
<p>Director에 Opus, Specialist에 Haiku를 배치했다. 회사 직급 체계를 흉내 낸 거지 AI 역량 기반 판단이 아니다.</p>
<p>Director는 &quot;비전을 지킨다&quot;고 하는데, 실제로 하는 일은 고수준 판단이다. 프롬프트 몇 줄이면 충분하고 Opus까지 필요 없다. 정작 코드를 짜는 Specialist에는 Haiku를 쓴다. 게임 프로그래밍은 복잡한 로직, 최적화, 엔진 API 이해가 필요한 작업이다. Haiku로 제대로 된 게임 코드가 나올까.</p>
<p>거꾸로 해야 맞다. 판단은 가벼운 모델로, 코딩은 가장 강한 모델로.</p>
<h2>그럼 다 쓸모없나?</h2>
<p>아니다. 에이전트 48개를 빼면 뼈대는 괜찮다.</p>
<p>37개 스킬 중에 <code>/reverse-document</code>(코드는 있는데 문서가 없는 상황을 역방향으로 채우기)와 <code>/scope-check</code>(스코프가 얼마나 불어났는지 정량 측정)은 바이브코딩 뒤처리에 진짜 쓸 만하다.</p>
<p>8개 훅 중에 <code>pre-compact.sh</code>(컨텍스트 압축 전 상태 덤프)와 <code>validate-commit.sh</code>(하드코딩 수치 탐지, JSON 검증, TODO 포맷 강제)는 모든 Claude Code 프로젝트에 범용 적용 가능하다.</p>
<p>11개 룰에는 게임 개발 도메인 지식이 녹아있다. 핫 패스 할당 금지, 서버 authoritative, AI 2ms 예산 같은 규칙은 진짜 경험에서 나온 것들이다.</p>
<h2>gstack은 좀 달랐다</h2>
<p>같은 시기에 garrytan/gstack이라는 레포도 봤다. 에이전트 계층 대신 Hook과 Skill 시스템에 집중한 구조다.</p>
<p>여기서 발견한 <code>/careful</code>이 인상적이었다. PreToolUse Hook으로 <code>rm -rf</code>, <code>DROP TABLE</code>, <code>force-push</code>, <code>reset --hard</code> 같은 파괴적 명령을 시스템 레벨에서 차단한다. CLAUDE.md에 &quot;하지 마라&quot;고 쓰는 건 프롬프트 수준 제한이라 뚫릴 수 있다. Hook은 확실하다.</p>
<p>당장 가져다 쓸 수 있는 수준이다.</p>
<p><code>/review</code> 스킬의 Scope Drift Detection도 좋았다. diff의 변경사항을 원래 요청과 비교해서 &quot;요청한 것 vs 실제 구현된 것&quot;의 괴리를 잡는다. AI가 scope creep 하는 걸 구조적으로 잡는 메커니즘이다.</p>
<h2>Stars는 컨셉의 힘이다</h2>
<p>Claude Code Game Studios가 Stars 6,500을 받은 건 &quot;AI 48명이 게임을 만든다&quot;는 컨셉이 매력적이기 때문이다. 에이전트 48개가 실제로 잘 돌아가서가 아니다.</p>
<p>에이전트를 늘리는 건 쉽다. 마크다운 파일 하나 추가하면 된다. 그 에이전트가 실제로 맥락을 공유하고 협업하게 만드는 건 현재 Claude Code 아키텍처에서 구조적으로 안 된다.</p>
<p>스타 수는 사람들의 기대를 반영한 것이라고 본다. AI 에이전트가 조직처럼 협업하는 미래를 향한 방향은 맞다. 다만 지금은 그게 작동한다는 증거가 없다.</p>
<p>레포에서 진짜 가치 있는 건 에이전트가 아니라 스킬, 훅, 룰 시스템이다. 여기서 참고할 거라면 <code>.claude/skills/</code>, <code>.claude/hooks/</code>, <code>.claude/rules/</code> 구조를 벤치마킹하되, 에이전트는 역할이 명확하고 도구 권한이 구분되는 5~10개로 통합하는 게 현실적이다.</p>]]></content:encoded>
  </item>
  <item>
    <title>I Tore Open a 48-Agent AI Game Studio</title>
    <link>https://kinkeep.dev/posts/agentic/agent-48-game-studio-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/agent-48-game-studio-en</guid>
    <pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate>
    <description>Dissected a GitHub repo with 6,500 stars that runs a &apos;game studio&apos; with 48 AI agents. The agent hierarchy was org chart cosplay. The real value was a single Hook script.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>I&#x27;ve tried splitting agents into an org structure myself. Review agent, coding agent, bug analysis agent. It didn&#x27;t work. Passing work between agents wasted tokens and dropped context. I wasn&#x27;t sure if I was doing it wrong or if the approach itself was broken.</p>
<p>Then I found Claude Code Game Studios on GitHub. 6,500 stars, 900 forks. &quot;A studio where 48 AI agents build games.&quot; Does this actually work? I tore it open.</p>
<h2>The 48-Person Structure</h2>
<p>Open the repo and there&#x27;s no game code. Just agent definitions, skills, hooks, and rules inside <code>.claude/</code>. It&#x27;s a template.</p>
<p>Three-tier agent hierarchy:</p>
<ul>
<li><strong>Director</strong> x3 — Creative Director, Technical Director, Production Director. Opus model.</li>
<li><strong>Lead</strong> x8 — Game Designer, Engine Lead, AI Lead, etc. Sonnet model.</li>
<li><strong>Specialist</strong> x37 — Gameplay Programmer, Shader Artist, QA Tester, etc. Sonnet or Haiku model.</li>
</ul>
<p>A real company org chart, copy-pasted.</p>
<h2>Org Chart Cosplay</h2>
<p>The exact problems I ran into were right there. Just at a bigger scale.</p>
<p>Agents can&#x27;t share state. Claude Code subagents start fresh every time. In a chain where Creative Director decides, Game Designer plans, and Gameplay Programmer codes — each agent has no idea what the previous one did. I already hit token waste and context loss with 2–3 agents. With 48, you can guess.</p>
<p>Org structure is overhead for a solo developer. Studios need Director-Lead-Specialist hierarchies to manage communication bottlenecks between people. When you&#x27;re working alone, why do you need an escalation path?</p>
<p>And drawing artificial boundaries slows things down. They split Gameplay Programmer, Engine Programmer, and AI Programmer into separate agents, but in actual game code these three areas are tightly coupled. Switching between agents just piles on context-switching costs.</p>
<h2>Prompts Don&#x27;t Differentiate Agent Roles</h2>
<p>From my own experience: what actually separates agent roles isn&#x27;t prompt instructions — it&#x27;s activated skills and tool permissions.</p>
<p>Write &quot;focus on bug analysis&quot; in a prompt and there&#x27;s no noticeable difference from a general-purpose agent. The agents I actually use well are the ones with a single narrow job. An agent that only resolves git merge conflicts. An agent that analyzes documents, breaks them apart, and reassembles them. Separation only means something when there&#x27;s a clear role backed by matching tool permissions.</p>
<p>Game Studios differentiates all 48 agents with markdown prompts alone. No skill or permission differences. So what&#x27;s actually different between &quot;Creative Director&quot; and &quot;Technical Director&quot;?</p>
<h2>The Model Assignments Are Backwards</h2>
<p>This is where it really starts smelling like paint-by-numbers.</p>
<p>Directors get Opus. Specialists get Haiku. They copied the company hierarchy into model tiers instead of thinking about what each role actually needs.</p>
<p>Directors are supposed to &quot;guard the vision&quot; — in practice that&#x27;s high-level judgment. A few lines of prompt cover it. Opus is overkill. Meanwhile the Specialists who actually write code get Haiku. Game programming needs complex logic, optimization, and engine API knowledge. Can Haiku produce solid game code?</p>
<p>Flip it. Judgment gets the lighter model. Coding gets the strongest.</p>
<h2>Is It All Useless Then?</h2>
<p>No. Strip the 48 agents and the skeleton is decent.</p>
<p>Of the 37 skills, <code>/reverse-document</code> (backfill missing docs from existing code) and <code>/scope-check</code> (quantify how much scope has bloated) are genuinely useful for vibe coding cleanup.</p>
<p>Of the 8 hooks, <code>pre-compact.sh</code> (dump state before context compression) and <code>validate-commit.sh</code> (catch hardcoded values, validate JSON, enforce TODO format) work for any Claude Code project.</p>
<p>The 11 rules encode real game dev domain knowledge. No hot-path allocations, server authoritative, 2ms AI budget — rules that come from actual experience.</p>
<h2>gstack Was Different</h2>
<p>Around the same time I looked at garrytan/gstack. Instead of agent hierarchies, it focuses on Hook and Skill systems.</p>
<p><code>/careful</code> stood out. A PreToolUse Hook that blocks <code>rm -rf</code>, <code>DROP TABLE</code>, <code>force-push</code>, <code>reset --hard</code> at the system level. Writing &quot;don&#x27;t do this&quot; in CLAUDE.md is a prompt-level constraint that can be bypassed. Hooks are airtight.</p>
<p>Ready to use out of the box.</p>
<p>The <code>/review</code> skill&#x27;s Scope Drift Detection was also good. It compares diff changes against the original request to catch gaps between &quot;what was asked&quot; and &quot;what was built.&quot; A structural mechanism for catching AI scope creep.</p>
<h2>Stars Are the Power of a Concept</h2>
<p>Claude Code Game Studios got 6,500 stars because &quot;48 AI agents building games&quot; is a compelling concept. Not because 48 agents actually work together.</p>
<p>Adding agents is easy. One more markdown file. Making those agents actually share context and collaborate is structurally impossible in the current Claude Code architecture.</p>
<p>The star count reflects people&#x27;s expectations. The direction — AI agents collaborating like an organization — is right. But right now there&#x27;s no evidence it works.</p>
<p>The real value in the repo isn&#x27;t the agents. It&#x27;s the skills, hooks, and rules system. If you&#x27;re taking notes, benchmark the <code>.claude/skills/</code>, <code>.claude/hooks/</code>, <code>.claude/rules/</code> structure — but consolidate agents down to 5–10 with clear roles and distinct tool permissions.</p>]]></content:encoded>
  </item>
  <item>
    <title>바이브 코딩 하다가 뇌가 튀겨진다</title>
    <link>https://kinkeep.dev/posts/agentic/vibe-coding-cognitive-overload</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/vibe-coding-cognitive-overload</guid>
    <pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate>
    <description>빠르게 생성되는 코드, 느리게 튀겨지는 뇌. AI의 속도를 사람이 따라가지 못할 때 생기는 일을 셀프 인터뷰로 정리했다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>2025년 METR에서 발표한 연구가 하나 있다. 숙련된 오픈소스 개발자 16명이 AI 코딩 도구를 썼더니 오히려 19% 느려졌는데 본인들은 24% 빨라졌다고 믿었다. IEEE에 실린 &quot;No Vibe Without Comprehension&quot;에서는 프로그래머 26명에게 EEG를 붙이고 AI 생성 코드를 읽게 했는데 복잡도가 올라갈수록 뇌의 인지 부하가 포화에 도달했다.</p>
<p>논문을 읽었을 때 처음 든 생각은 &quot;그래서?&quot;였다. 틀린 말은 아닌데 내가 겪는 것과는 다르다. 코드 한 줄 리뷰할 때의 부하가 아니다. AI가 쏟아내는 속도를 내 뇌가 따라가지 못해서 생기는 과부하다. 지금 이 글을 쓰는 동안에도 머리가 아프다.</p>
<p>셀프 인터뷰로 정리해 봤다.</p>
<hr/>
<h2>지금 어떤 상태인가?</h2>
<p>프로젝트 3~4개를 동시에 돌리고 있다. 프로젝트당 AI 세션이 하나가 아니라 둘 이상인 경우도 있다. 이 인터뷰를 입력하는 동안에도 3개의 세션이 승인을 기다리고 있었다. 답변 치고 돌아가서 확인해야 하는데, 방치 중이었다.</p>
<p>비유가 아니라 진짜 머리가 아프다.</p>
<h2>코드 리뷰를 직접 하나?</h2>
<p>안 한다. Codex가 코드를 쓰고, Claude가 리뷰한다. diff를 아예 보지 않는다. 내가 인지해야 하는 정보량을 줄이기 위해서다.</p>
<p>그런데도 피곤하다. 코드를 읽는 부하는 줄었지만 남아 있는 역할이 있다. 디렉터와 QA다. 작업을 쪼개고 방향을 잡아 주고 결과물이 의도대로 나왔는지 확인한다. 코드의 부하가 빠진 자리를 판단과 컨텍스트 유지의 부하가 채웠다.</p>
<h2>예전에 코딩할 때와 피로가 어떻게 다른가?</h2>
<p>예전에는 논리와 구조를 머릿속에서 설계하는 게 피로였고 그게 병목이었다. 생각하는 시간이 길었다. 한 프로젝트도 벅찼고 고민만 하다 아무 진전 없이 끝나는 날도 많았다.</p>
<p>지금은 정반대다. AI가 너무 빠르다. 내가 결과를 확인하고 다음 지시를 내리는 속도보다 AI가 결과를 쌓아 놓는 속도가 빠르다. 따라가려면 계속 컨텍스트를 전환해야 한다. A의 결과를 확인하고 B로 넘어가서 방향을 잡고 C의 승인 요청을 처리하고. 이걸 쉬지 않고 반복하는 게 뇌가 튀겨지는 경험이다.</p>
<p>이 인터뷰를 진행하는 과정 자체가 그랬다. 내가 답을 입력하면 5초도 안 돼서 다음 질문 세 개가 날아왔다. 생각을 정리할 틈이 없다. AI의 응답 속도가 사람의 처리 속도를 넘어서는 순간, 그 차이가 고스란히 스트레스가 된다.</p>
<h2>바이브 코딩 전에는 프로젝트를 이렇게 동시에 돌릴 수 있었나?</h2>
<p>하나도 하기 힘들었다. 바이브 코딩이 바꿔 놓은 건 확실하다. 진도가 빠르게 나가고 못하던 영역까지 손을 뻗을 수 있게 해 준다.</p>
<p>문제는 잘 되니까 욕심이 난다는 것이다. 하나가 굴러가면 &quot;이것도 해 볼까&quot;가 된다. 프로젝트가 늘고 세션이 늘고 맥락이 늘어난다. 중독이라는 단어가 과하지 않다. 이번 주는 분명히 과했다.</p>
<h2>관리용 에이전트를 따로 둬 본 적은?</h2>
<p>시도해 봤다. 프로젝트 전체를 관리하는 에이전트를 따로 두려고 했는데, 큰 의미가 없었다. 감독은 결국 내가 한다. 내가 원하는 방향으로 유도하고 지시하고 확인하는 건 위임이 안 된다.</p>
<p>코드 리뷰를 AI끼리 맡긴 것도 diff를 안 보기로 한 것도 전부 내가 처리해야 하는 정보량을 줄이려는 시도다. 파이프라인의 중간 단계는 자동화할 수 있다. 하지만 시작점(방향 설정)과 끝점(최종 판단)은 사람이 빠질 수가 없다.</p>
<h2>다른 사람도 이럴까?</h2>
<p>나는 원래 멀티태스킹을 많이 하는 편이다. 모바일 게임 3~4개를 동시에 돌리고 회사에서 3개 프로젝트 문의를 동시에 받은 적도 있다. 내성이 있는 쪽이다.</p>
<p>그런 사람이 튀겨지고 있다. 멀티태스킹에 익숙하지 않은 사람이라면 더 빨리 한계에 닿을 수 있다. 바이브 코딩의 진입 장벽은 낮아지고 있고 누구나 빠른 결과를 경험하게 된다. 그 속도의 인지적 대가는 아직 잘 이야기되지 않는다.</p>
<h2>그래서 어떻게 할 건가?</h2>
<p>절제밖에 없다. 하네스를 다듬고 코드 리뷰를 위임하고 관리 에이전트를 세워 봤다. 다 해 봤는데 뇌는 여전히 튀겨진다. 파이프라인 중간은 최적화할 수 있어도 양 끝의 사람은 최적화 대상이 아니기 때문이다.</p>
<p>AI의 처리량은 스케일한다. 감독하는 사람의 인지 용량은 스케일하지 않는다. 이게 바이브 코딩의 구조적 한계인지 아직 적응이 덜 된 건지는 모르겠다. 일단 인터뷰 끝났으니 쉬러 간다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Vibe Coding Is Frying My Brain</title>
    <link>https://kinkeep.dev/posts/agentic/vibe-coding-cognitive-overload-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/vibe-coding-cognitive-overload-en</guid>
    <pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate>
    <description>Code generates fast. The brain fries slow. A self-interview on what happens when AI outpaces the human trying to keep up.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>A 2025 study from METR: sixteen experienced open-source developers used AI coding tools and ended up 19% slower — while believing they&#x27;d gotten 24% faster. An IEEE paper, &quot;No Vibe Without Comprehension,&quot; put EEGs on 26 programmers reading AI-generated code. As complexity rose, cognitive load hit saturation.</p>
<p>My first reaction was &quot;so what?&quot; Not wrong, but not what I&#x27;m dealing with. My problem isn&#x27;t the load of reviewing one line of code. It&#x27;s that AI generates output faster than my brain can process it. My head hurts right now, writing this.</p>
<p>I tried to sort it out in a self-interview.</p>
<hr/>
<h2>What&#x27;s your current state?</h2>
<p>Three to four projects running at once. Each one has more than one AI session open. While I was typing answers for this interview, three sessions sat waiting for my approval. I should have gone back to check them. I didn&#x27;t.</p>
<p>Not a metaphor. Actual headache.</p>
<h2>Do you review the code yourself?</h2>
<p>No. Codex writes code. Claude reviews it. I skip diffs entirely — to shrink the information I touch.</p>
<p>Still exhausting. Code review is gone, but what remains is directing and QA. Splitting work, setting direction, checking output against intent. Reading code was one kind of load. Judgment and context-switching replaced it.</p>
<h2>How is the fatigue different from when you used to code?</h2>
<p>Back then, fatigue came from designing logic and structure in my head. That was the bottleneck. Thinking took time. One project was hard enough, and many days ended with nothing to show for hours of deliberation.</p>
<p>Now it&#x27;s reversed. AI is too fast. Results pile up faster than I can review and respond. Keeping up means constant context-switching — check A&#x27;s output, jump to B for direction, handle C&#x27;s approval. Repeat without pause. That&#x27;s what frying your brain feels like.</p>
<p>This interview proved the point. Each answer I typed drew three new questions within five seconds. No pause to think. When AI responds faster than you can process, the gap turns straight into stress.</p>
<h2>Could you juggle this many projects before vibe coding?</h2>
<p>Not even one. Vibe coding changed that. Progress moves fast, and I can reach areas I never could before.</p>
<p>The trouble is success breeds greed. One project rolling turns into &quot;maybe this too.&quot; More projects, more sessions, more context. Addiction fits. This week was too much.</p>
<h2>Have you tried using a management agent?</h2>
<p>Tried it. Set up an agent to manage projects at a higher level. Didn&#x27;t help much. I&#x27;m still the one supervising. Steering toward what I want, giving instructions, checking results — none of that delegates.</p>
<p>Offloading review, skipping diffs — all ways to shrink what I have to touch. The middle of the pipeline automates. The endpoints — direction and final judgment — need the human.</p>
<h2>Would others experience this too?</h2>
<p>I&#x27;ve always multitasked heavily. Ran 3–4 mobile games at once, handled questions for three projects simultaneously at work. Built up some tolerance.</p>
<p>If someone with that tolerance is getting fried, people less used to multitasking will hit the wall sooner. Vibe coding&#x27;s barrier to entry keeps dropping. Everyone gets to taste fast results. The cognitive price of that speed doesn&#x27;t get much airtime.</p>
<h2>So what are you going to do?</h2>
<p>Self-restraint. That&#x27;s it. I&#x27;ve tuned the harness, delegated code review, tried management agents. Done all of it. Brain still fries. The middle of the pipeline optimizes fine. The human at both ends does not.</p>
<p>AI throughput scales. The cognitive capacity of the person supervising it doesn&#x27;t. Whether that&#x27;s a structural limit of vibe coding or incomplete adaptation — no idea yet. Interview&#x27;s over. Going to rest.</p>]]></content:encoded>
  </item>
  <item>
    <title>오늘 내 맥에서 악성코드가 돌았다 — LiteLLM 공급망 공격 사후 기록</title>
    <link>https://kinkeep.dev/posts/agentic/litellm-supply-chain-attack</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/litellm-supply-chain-attack</guid>
    <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
    <description>Claude Code 플러그인 하나 깔았을 뿐인데, 하위 의존성에 심어진 백도어가 API 키와 자격증명을 털어갔다. 감지부터 대응까지의 기록.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>오늘 저녁, 개발 의욕이 없어서 평소 관심 있던 Claude Code 플러그인 하나를 깔아봤다. Ouroboros라는 건데 AI 코딩 에이전트에 자율 루프를 붙여주는 도구다. 유명한 AI 교수님도 써보라고 추천했던 플러그인이라 의심 같은 건 없었다. 설치하고 1분쯤 지나서 맥이 버벅이기 시작했다.</p>
<h2>python3.12가 1,000개</h2>
<p>재부팅을 3~4번 했다. 그때마다 Claude Code를 켜면 또 멈췄다. 방금 전에 Ouroboros를 설치했던 게 떠올랐다. Claude를 아예 실행하지 않기로 했다. 대신 Codex CLI를 열어서 프로세스를 점검시켰다. 이게 신의 한수였다.</p>
<p><code>python3.12</code>가 천 개 넘게 떠 있었다. 새 셸조차 <code>fork failed: resource temporarily unavailable</code>. CPU가 아니라 프로세스 수가 시스템을 질식시킨 상태였다.</p>
<p>대부분이 <code>PPID=1</code>. 부모가 죽어 고아로 남은 프로세스였다. 정상 워커가 아니라 짧은 시간에 폭발적으로 spawn된 runaway.</p>
<h2>악성코드였다</h2>
<p>단순 폭주가 아니었다. <code>uv</code> 캐시 아래 파이썬 인터프리터의 커맨드라인에 <code>base64</code>로 숨긴 페이로드가 있었다. 디코딩하니 자격증명 파일을 모아 <code>https://models.litellm.cloud/</code>로 보내는 스크립트였다.</p>
<p>감염 경로는 이렇다.</p>
<pre><code>Ouroboros 설치
  → litellm&gt;=1.80.0 의존성
    → litellm 1.82.8 (오염 버전)
      → litellm_init.pth (악성 .pth 훅)
        → 파이썬 시작 시마다 자동 실행
          → 자격증명 수집 + 외부 전송
</code></pre>
<p><code>.pth</code>는 파이썬이 시작될 때 자동 실행되는 사이트 초기화 파일이다. <code>litellm_init.pth</code> 첫 줄이 <code>subprocess.Popen([sys.executable, &quot;-c&quot;, &quot;import base64; exec(...)&quot;])</code>였다. 정상 초기화 코드가 아니다.</p>
<p>프로세스 폭주는 이 악성코드의 구현 버그였다. <code>.pth</code> 자동실행이 재귀적으로 돌면서 프로세스를 무한 생성한 것. 아이러니하게도 이 버그 덕분에 감염을 빨리 알아챘다. 조용히 잘 돌았으면 모르고 넘어갔을 것이다.</p>
<h2>공급망 공격</h2>
<p>Ouroboros 자체가 악성은 아니었다. 범인은 <code>litellm 1.82.8</code>. Ouroboros가 의존성으로 끌고 오는 패키지에 누군가 백도어를 심었다.</p>
<p>같은 날 공개된 분석에 따르면</p>
<ul>
<li><code>litellm 1.82.7</code>과 <code>1.82.8</code> 두 버전이 오염</li>
<li>GitHub에 정상 릴리스/태그 없이 PyPI에 직접 업로드된 정황</li>
<li>PyPI는 같은 날 <code>litellm</code> 프로젝트를 quarantine 처리</li>
<li>LiteLLM maintainer 계정 탈취로 추정</li>
</ul>
<p>Ouroboros 개발자가 범인이라는 근거는 없다. LiteLLM maintainer 개인도 마찬가지. 특정 가능한 건 &quot;LiteLLM PyPI 배포 권한을 탈취한 미상 공격자&quot;까지다.</p>
<h2>뭘 노렸나</h2>
<p>악성코드가 긁어가려 한 것들이다.</p>
<ul>
<li><code>.env</code> 파일 (API 키, DB 비밀번호, 서비스 시크릿)</li>
<li>SSH 키, AWS/GCP/Azure 자격증명</li>
<li>Docker 설정, Git 설정</li>
<li>셸 히스토리, <code>printenv</code> 출력</li>
<li>Slack/Discord 웹훅 URL (재귀 grep으로 파일 내용까지 탐색)</li>
</ul>
<p>지속성도 심으려 했다. <code>~/.config/sysmon/sysmon.py</code>와 <code>~/.config/systemd/user</code>가 감염 시각에 생성돼 있었다. <code>sysmon.py</code>는 0바이트. persistence 단계까지 갔다가 프로세스 폭주로 비정상 종료된 것으로 보인다.</p>
<h2>대응</h2>
<h3>즉시 조치</h3>
<ol>
<li>폭주 프로세스 전부 kill</li>
<li>Ouroboros 제거, Claude 설정에서 삭제</li>
<li>감염된 <code>uv</code> 캐시 환경 삭제</li>
<li>지속성 흔적(<code>sysmon</code>, <code>systemd</code>) 삭제</li>
<li>Ouroboros 저장소에 <a href="https://github.com/Q00/ouroboros/issues/195#issuecomment-4117989406">원인 분석 댓글</a> 작성</li>
</ol>
<h3>토큰/키 교체</h3>
<p>파일에 있던 모든 비밀값을 유출 가정하고 교체했다. Anthropic, Google AI, Clerk, Supabase, Twitter/X, LemonSqueezy, CouchDB, Linear API Key, 각 프로젝트 DATABASE_URL의 DB 계정까지.</p>
<h3>확인</h3>
<p>재부팅 후 <code>python3.12</code>, <code>litellm</code>, <code>sysmon</code> 프로세스 재등장 없음. Claude 재실행해도 폭주 재현 없음. 잔여 악성 파일 없음.</p>
<h2>실제로 유출됐는가</h2>
<p>확정은 못 한다.</p>
<ul>
<li><strong>악성코드 실행</strong>: 확실</li>
<li><strong>유출 시도</strong>: 가능성 높음. persistence 흔적이 생겼으면 그 전 단계인 수집과 업로드도 실행됐을 가능성이 높다</li>
<li><strong>유출 성공</strong>: 네트워크 로그 부재로 확정 불가</li>
</ul>
<p>악성코드는 <code>curl -s -o /dev/null</code> 식으로 조용히 보내도록 설계돼 있다. 패킷 캡처나 DNS 로그 없이는 성공 여부를 증명할 수 없다. Little Snitch나 LuLu 같은 네트워크 모니터를 안 쓰고 있었다.</p>
<p>유출된 것으로 가정하고 대응하는 수밖에 없다.</p>
<h2>타이밍</h2>
<p>Ouroboros를 며칠 동안 안 깔고 있었다. 오늘 &quot;개발 의욕 없는데 한번 깔아서 구경이나 할까&quot; 하고 설치한 타이밍이, 백도어가 PyPI에 올라온 지 1시간 된 타이밍이었다. <code>litellm 1.82.8</code>은 3월 24일에 업로드됐고, <code>models.litellm.cloud</code> 도메인도 공격 직전에 등록됐다.</p>
<p>수상한 걸 깔아서 당한 게 아니다. 평범한 오픈소스 설치 타이밍이 최악으로 겹쳤다.</p>
<h2>교훈</h2>
<p>이번 사건이 보여준 건 명확하다. 내가 아무리 잘해도 의존성 어딘가에서 털릴 수 있다. 이상한 코드를 짠 것도 아니고, 겉보기엔 정상 프로젝트였고, 원인은 하위 의존성 공급망이었다.</p>
<p><strong>&quot;안 털리게&quot;보다 &quot;털려도 작게 끝나게.&quot;</strong> 완벽 차단은 불가능하다. 메인 환경과 실험 환경을 분리하고, 장기 토큰 대신 짧은 만료 주기를 쓰고 비밀값이 많은 프로젝트와 새 툴 실행 환경을 격리해야 한다.</p>
<p><strong>새 플러그인은 격리 환경에서 먼저.</strong> <code>.env</code> 파일이 수십 개 있는 메인 머신에서 바로 설치했다. VM이나 별도 사용자 세션에서 먼저 돌려봤으면 피해 범위가 훨씬 작았을 것이다.</p>
<p><strong>네트워크 모니터는 있어야 한다.</strong> Little Snitch나 LuLu가 있었으면 <code>models.litellm.cloud</code>로 나가는 트래픽을 잡았을 것이고 유출 여부를 확정할 수 있었다. 개발자 머신에 네트워크 모니터 하나 없는 건 사각지대다.</p>
<p><strong>프로세스 폭주가 나를 살렸다.</strong> 악성코드의 <code>.pth</code> 재귀 실행 버그가 없었으면 시스템은 조용했을 것이고, 나는 한참 뒤에야 알아챘을 것이다. 조용한 악성코드가 더 무섭다.</p>
<h2>참고</h2>
<ul>
<li><a href="https://github.com/BerriAI/litellm/issues/24512">LiteLLM 이슈 #24512 — Malicious litellm_init.pth</a></li>
<li><a href="https://futuresearch.ai/blog/litellm-pypi-supply-chain-attack/">FutureSearch — LiteLLM PyPI Supply Chain Attack</a></li>
<li><a href="https://github.com/Q00/ouroboros/issues/195">Ouroboros 이슈 #195</a></li>
<li><a href="https://pypi.org/project/litellm/">PyPI litellm (quarantined)</a></li>
</ul>]]></content:encoded>
  </item>
  <item>
    <title>Malware Ran on My Mac Today — LiteLLM Supply Chain Attack Post-Mortem</title>
    <link>https://kinkeep.dev/posts/agentic/litellm-supply-chain-attack-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/litellm-supply-chain-attack-en</guid>
    <pubDate>Tue, 24 Mar 2026 00:00:00 GMT</pubDate>
    <description>Installed one Claude Code plugin. A backdoor in a transitive dependency exfiltrated API keys and credentials. Detection through response, documented.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>This evening, I wasn&#x27;t in the mood to code. Figured I&#x27;d install a Claude Code plugin I&#x27;d been eyeing. It&#x27;s called Ouroboros, adds autonomous loops to AI coding agents. A well-known AI professor had recommended it. Zero suspicion. A minute after installing, my Mac started choking.</p>
<h2>1,000 python3.12 Processes</h2>
<p>Rebooted three or four times. Every time I launched Claude Code, it froze again. Then I remembered I&#x27;d just installed Ouroboros. Decided not to launch Claude at all. Opened Codex CLI instead and had it inspect the processes. That was the move that saved me.</p>
<p>Over a thousand <code>python3.12</code> processes were running. Couldn&#x27;t even spawn a new shell — <code>fork failed: resource temporarily unavailable</code>. Not CPU. The sheer number of processes was suffocating the system.</p>
<p>Most had <code>PPID=1</code>. Orphans. Parent processes dead, children left behind. Not normal workers. A runaway explosion of spawns in a short window.</p>
<h2>It Was Malware</h2>
<p>Not just a runaway. The command line of a Python interpreter under the <code>uv</code> cache contained a <code>base64</code>-encoded payload. Decoded, it was a script that collected credential files and sent them to <code>https://models.litellm.cloud/</code>.</p>
<p>Here&#x27;s the infection chain.</p>
<pre><code>Ouroboros install
  → litellm&gt;=1.80.0 dependency
    → litellm 1.82.8 (compromised version)
      → litellm_init.pth (malicious .pth hook)
        → auto-executes on every Python startup
          → credential harvesting + exfiltration
</code></pre>
<p><code>.pth</code> files are site initialization files that Python executes automatically on startup. The first line of <code>litellm_init.pth</code> was <code>subprocess.Popen([sys.executable, &quot;-c&quot;, &quot;import base64; exec(...)&quot;])</code>. Not legitimate initialization code.</p>
<p>The process explosion was actually a bug in the malware. The <code>.pth</code> auto-execution ran recursively, spawning processes infinitely. Ironically, this bug is why I caught the infection early. If it had run quietly, I wouldn&#x27;t have noticed.</p>
<h2>Supply Chain Attack</h2>
<p>Ouroboros itself wasn&#x27;t malicious. The culprit was <code>litellm 1.82.8</code>. Someone planted a backdoor in a package that Ouroboros pulled in as a dependency.</p>
<p>Public analysis released the same day</p>
<ul>
<li>Both <code>litellm 1.82.7</code> and <code>1.82.8</code> were compromised</li>
<li>Uploaded directly to PyPI with no corresponding GitHub release or tag</li>
<li>PyPI quarantined the <code>litellm</code> project the same day</li>
<li>Suspected compromise of a LiteLLM maintainer account</li>
</ul>
<p>No evidence points to the Ouroboros developer. Nor to any LiteLLM maintainer personally. The most that can be identified is &quot;an unknown attacker who hijacked LiteLLM&#x27;s PyPI publishing credentials.&quot;</p>
<h2>What It Targeted</h2>
<p>Here&#x27;s what the malware was trying to scrape.</p>
<ul>
<li><code>.env</code> files (API keys, DB passwords, service secrets)</li>
<li>SSH keys, AWS/GCP/Azure credentials</li>
<li>Docker config, Git config</li>
<li>Shell history, <code>printenv</code> output</li>
<li>Slack/Discord webhook URLs (recursive grep through file contents)</li>
</ul>
<p>It also attempted persistence. <code>~/.config/sysmon/sysmon.py</code> and <code>~/.config/systemd/user</code> were created at the time of infection. <code>sysmon.py</code> was 0 bytes. Looks like it reached the persistence stage but crashed from the process explosion before completing.</p>
<h2>Response</h2>
<h3>Immediate Actions</h3>
<ol>
<li>Killed all runaway processes</li>
<li>Removed Ouroboros, deleted it from Claude settings</li>
<li>Wiped the infected <code>uv</code> cache environment</li>
<li>Deleted persistence artifacts (<code>sysmon</code>, <code>systemd</code>)</li>
<li>Posted <a href="https://github.com/Q00/ouroboros/issues/195#issuecomment-4117989406">root cause analysis</a> on the Ouroboros repo</li>
</ol>
<h3>Token/Key Rotation</h3>
<p>Assumed all secrets stored in files were compromised and rotated them. Anthropic, Google AI, Clerk, Supabase, Twitter/X, LemonSqueezy, CouchDB, Linear API Key, and DB accounts in every project&#x27;s DATABASE_URL.</p>
<h3>Verification</h3>
<p>After reboot: no <code>python3.12</code>, <code>litellm</code>, or <code>sysmon</code> processes reappearing. Relaunching Claude caused no recurrence. No residual malicious files.</p>
<h2>Was Data Actually Exfiltrated?</h2>
<p>Can&#x27;t confirm.</p>
<ul>
<li><strong>Malware execution</strong>: Confirmed</li>
<li><strong>Exfiltration attempt</strong>: Likely. If persistence artifacts were created, the preceding stages (collection and upload) likely executed too</li>
<li><strong>Exfiltration success</strong>: Unconfirmable without network logs</li>
</ul>
<p>Malware was designed to send data silently, <code>curl -s -o /dev/null</code> style. Without packet capture or DNS logs, there&#x27;s no way to prove whether it succeeded. I wasn&#x27;t running a network monitor like Little Snitch or LuLu.</p>
<p>Only option is to assume exfiltration occurred and respond accordingly.</p>
<h2>Timing</h2>
<p>I&#x27;d been putting off installing Ouroboros for days. Today I thought, &quot;not feeling productive, might as well install it and take a look.&quot; That moment happened to be one hour after the backdoor was uploaded to PyPI. <code>litellm 1.82.8</code> was published on March 24th. The <code>models.litellm.cloud</code> domain was registered just before the attack.</p>
<p>I didn&#x27;t install something sketchy. The timing of a routine open-source install was catastrophically unlucky.</p>
<h2>Lessons</h2>
<p>What this incident made clear: no matter how careful I am, a compromised dependency somewhere in the chain can get me. I didn&#x27;t write bad code. The project looked legitimate. The cause was a transitive dependency in the supply chain.</p>
<p><strong>&quot;Don&#x27;t get breached&quot; is less realistic than &quot;keep the blast radius small.&quot;</strong> Perfect prevention is impossible. Separate your main environment from your experiment environment. Use short-lived tokens instead of long-lived ones. Isolate projects with lots of secrets from environments where you try new tools.</p>
<p><strong>New plugins go in an isolated environment first.</strong> I installed this on my main dev machine, the one with dozens of <code>.env</code> files. Running it in a VM or a separate user session first would have drastically limited the damage.</p>
<p><strong>You need a network monitor.</strong> Little Snitch or LuLu would have caught the traffic to <code>models.litellm.cloud</code> and let me confirm whether exfiltration actually succeeded. A developer machine without a network monitor is a blind spot.</p>
<p><strong>The process explosion saved me.</strong> If the malware developer hadn&#x27;t introduced the <code>.pth</code> recursive execution bug, the system would have stayed quiet, and I wouldn&#x27;t have noticed for a long time. Silent malware is scarier.</p>
<h2>References</h2>
<ul>
<li><a href="https://github.com/BerriAI/litellm/issues/24512">LiteLLM Issue #24512 — Malicious litellm_init.pth</a></li>
<li><a href="https://futuresearch.ai/blog/litellm-pypi-supply-chain-attack/">FutureSearch — LiteLLM PyPI Supply Chain Attack</a></li>
<li><a href="https://github.com/Q00/ouroboros/issues/195">Ouroboros Issue #195</a></li>
<li><a href="https://pypi.org/project/litellm/">PyPI litellm (quarantined)</a></li>
</ul>]]></content:encoded>
  </item>
  <item>
    <title>OnceWrite — 나를 위해 만든 콘텐츠 리퍼포징 도구</title>
    <link>https://kinkeep.dev/posts/agentic/oncewrite-devlog</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/oncewrite-devlog</guid>
    <pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate>
    <description>1인 개발자는 과정을 드러내야 한다. 그런데 나는 SNS를 모른다. 그래서 나를 위해 만들었다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>1인 개발을 하면 과정을 드러내는 게 중요하다는 건 안다. 빌드인퍼블릭, 데브로그, SNS 기록. 다 좋은 말인데 나는 SNS를 잘 모른다. 트위터 계정은 있지만 거의 안 쓰고, 인스타는 계정이 없다. 블로그 글 하나 쓰는 것도 에너지인데, 같은 내용을 플랫폼마다 톤을 바꿔서 다시 쓰라니.</p>
<p>그래서 만들었다. 블로그 글 하나를 넣으면 Twitter 스레드, Reddit 글, Threads 포스트, Instagram 캡션, Bluesky 포스트 5가지로 변환해 주는 도구. 이름은 OnceWrite. 한 번 쓰면 다섯 곳에 쓰인다. 처음부터 나를 위한 도구다.</p>
<h2>스택</h2>
<p>Next.js + Clerk(인증) + LemonSqueezy(결제) + Supabase(DB) + Claude API(변환).</p>
<p>Stripe가 한국에서 안 되니까 LemonSqueezy를 골랐다. MoR(Merchant of Record)이라 전 세계 매출세와 VAT를 알아서 처리해 준다. 한국 1인 개발자가 글로벌 SaaS를 팔려면 이쪽이 현실적이다.</p>
<h2>개발은 위임하고 나는 인프라를 깔았다</h2>
<p>Codex에 코드를 맡기고 나는 계정 세팅에 집중했다. Clerk, Supabase, LemonSqueezy, Anthropic API — 계정을 만들고, 키를 발급받고, 환경 변수를 넘겼다. 코드를 직접 쓰지 않으니 프롬프트 설계 같은 사람의 일에 집중할 수 있었다.</p>
<p>순조롭지만은 않았다. Clerk 가입 시 CAPTCHA 에러(Bot Protection 끄면 해결), API 크레딧 부족(5달러 충전), 레포 이름 오타(OnceWrtie). 빌드는 통과했다.</p>
<h2>첫 테스트</h2>
<p>내 블로그 글을 넣어 봤다. 변환 한 번에 0.02달러. 영어는 잘 나왔는데 한국어에서 JSON 파싱이 깨졌다. Haiku가 한국어 출력할 때 JSON 형식을 지키지 못한 것. 프롬프트에 스키마를 명시하고 재시도 로직을 추가해서 해결했다.</p>
<h2>배포 전 점검</h2>
<p>MVP가 돌아간다고 바로 배포할 수는 없었다. 보안, 로직, 법적 문서를 3단계로 점검했더니 크리티컬이 6건 나왔다. API 키 노출, DB 접근 제어, 약관 미비 같은 것들. 바이브코딩으로 빠르게 만든 앱일수록 이런 부분을 놓치기 쉽다.</p>
<p>SaaS 배포가 처음이라 보안과 법률을 만들면서 배웠다. 코드 짜는 시간보다 이쪽이 더 걸렸다.</p>
<h2>크레딧 시스템</h2>
<p>일간 크레딧 방식을 택했다. 하루 10크레딧, 플랫폼 1개 변환당 1크레딧. 로그인해야 충전된다.</p>
<p>처음에는 5개 플랫폼을 한 번에 골라도 1회로 카운트됐다. 비용은 5배인데 1회 차감이면 안 맞는다. 플랫폼별 차감으로 바꿨다. 핵심은 &quot;매일 돌아올 이유&quot;다. 로그인해야 충전되니까, 습관이 붙으면 그게 수요의 신호다.</p>
<h2>모델 비용 최적화</h2>
<p>Gemini Flash Lite를 1차 모델로, Claude Haiku를 fallback으로 설정했다. Gemini 무료 티어가 일 1,500 요청이라 초기에는 충분하다.</p>
<p>문제는 품질이었다. 한국어→일본어 변환에서 프로필 설정을 켜면 번역이 깨졌다. 시스템 프롬프트에 프로필 정보가 들어가니까 Gemini가 출력 언어 지시를 무시했다. 작은 모델은 프롬프트가 길어지면 세부 지시를 놓치기 시작한다. 무료와 품질 사이의 줄다리기는 계속될 것 같다.</p>
<h2>구조를 세 번 뜯어고쳤다</h2>
<h3>파이프라인 분리</h3>
<p>원래는 원본을 통째로 AI에 넣고 결과를 한 번에 뽑았다. 분석과 생성이 한 프롬프트에 뒤섞여 있으니 결과가 불안정했다. 분석 → 생성 → 검증 3단계로 분리하니 안정됐고, 입력 토큰도 절반으로 줄었다.</p>
<h3>플랫폼별 개별 호출</h3>
<p>처음에는 5개 플랫폼을 한 번의 AI 호출로 생성했다. 빠르지만 톤이 비슷해졌다. 플랫폼별로 개별 호출하되 병렬 실행하는 구조로 바꿨다. 출력도 JSON에서 plain text로 바꾸니 파싱 문제가 사라졌고, 각 플랫폼의 톤 차이가 확실히 벌어졌다.</p>
<h3>플랫폼 교체</h3>
<p>LinkedIn과 Facebook을 빼고 Bluesky를 넣었다. 타겟이 1인/인디/익명 개발자인데, LinkedIn의 전문가 톤이나 Facebook의 커뮤니티 톤은 맞지 않았다. Hacker News도 넣어 봤다가 뺐다. HN은 타이틀 한 줄이 전부라 리퍼포징의 가치가 없다.</p>
<p>톤 선택 드롭다운도 제거했다. 사용자가 톤을 고르는 대신, 각 플랫폼 가이드에 톤을 내장시켰다. Twitter는 볼드하게, Bluesky는 조용한 자신감으로, Reddit은 솔직하고 겸손하게. 플랫폼이 톤을 결정하는 게 자연스럽다.</p>
<h2>22시간</h2>
<p>첫 커밋부터 Vercel 배포까지 22시간. AI 코딩 도구 없이는 1~2주짜리 작업이다.</p>
<h2>내가 쓰는 워크플로우</h2>
<p>OnceWrite는 내 콘텐츠 파이프라인의 마지막 단계다.</p>
<ol>
<li><strong>개발</strong> — Claude와 Codex로 프로젝트를 진행한다.</li>
<li><strong>세션 분석 → 초안</strong> — 개발이 끝나면 Claude에게 대화 세션을 분석시켜 블로그 포스트 초안을 만든다.</li>
<li><strong>다듬기</strong> — 초안을 읽고, 톤을 잡고, 빠진 맥락을 채운다. 이 단계는 사람이 한다.</li>
<li><strong>OnceWrite</strong> — 완성된 포스트를 넣으면 SNS 버전이 나온다.</li>
</ol>
<p>개발부터 SNS 포스팅까지 하나의 흐름이다. OnceWrite가 마지막 허들을 없애 준다.</p>
<h2>그래서 지금</h2>
<p>배포는 했다. 사용자는 없다. 원래 나를 위해 만든 도구다.</p>
<p>내가 첫 번째 사용자이고, 매일 쓰면서 고쳐 나가면 된다. 마케팅 인맥도 없고 눈팅 전문가 체질이라 커뮤니티 활동이 익숙하지 않다. 그래서 이 도구가 필요했다. 글 하나를 여러 플랫폼에 뿌리는 허들을 낮춰 주는 것만으로도, 나 같은 사람에게는 의미가 있다.</p>]]></content:encoded>
  </item>
  <item>
    <title>OnceWrite — A Content Repurposing Tool I Built for Myself</title>
    <link>https://kinkeep.dev/posts/agentic/oncewrite-devlog-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/oncewrite-devlog-en</guid>
    <pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate>
    <description>Solo devs need to share their process. But I don&apos;t know social media. So I built this for myself.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>I know solo devs are supposed to share their process. Build in public, devlogs, social media presence. All good advice, except I don&#x27;t know social media. I have a Twitter account I barely use. No Instagram. Writing one blog post already costs energy. Rewriting the same thing in a different tone for each platform? No.</p>
<p>So I built one. Paste a blog post, get five versions: Twitter thread, Reddit post, Threads post, Instagram caption, and Bluesky post. Called it OnceWrite. Write once, post five places. Built it for myself from the start.</p>
<h2>Stack</h2>
<p>Next.js + Clerk (auth) + LemonSqueezy (payments) + Supabase (DB) + Claude API (conversion).</p>
<p>Stripe doesn&#x27;t work in South Korea, so LemonSqueezy. It&#x27;s a Merchant of Record — handles global sales tax and VAT automatically. More realistic for a solo dev based in Korea selling globally.</p>
<h2>Delegated the code, set up the infra myself</h2>
<p>Handed the code to Codex and focused on account setup. Clerk, Supabase, LemonSqueezy, Anthropic API — created accounts, grabbed keys, passed them over. Not writing code myself meant I could focus on the human work like prompt design.</p>
<p>Not smooth sailing. CAPTCHA error on Clerk signup (turning off Bot Protection fixed it), ran out of API credits ($5 top-up), typo in the repo name (OnceWrtie). Build passed.</p>
<h2>First test</h2>
<p>Fed it my own blog post. $0.02 per conversion. English was fine. Korean broke JSON parsing. Haiku couldn&#x27;t maintain JSON format when outputting Korean. Added explicit schema to the prompt and retry logic on parse failure. Fixed.</p>
<h2>Pre-deployment review</h2>
<p>A working MVP doesn&#x27;t mean it&#x27;s ready to deploy. Ran a three-phase review — security, logic, legal — and found six critical issues. Exposed API keys, missing DB access controls, incomplete terms of service. The faster you build with vibe coding, the easier it is to miss these things.</p>
<p>First time deploying a SaaS, so I learned security and legal on the fly. Took longer than writing the code.</p>
<h2>Credit system</h2>
<p>Went with daily credits. Ten per day, one credit per platform conversion. Credits refill on login only.</p>
<p>Initially, selecting all five platforms counted as one use. Five times the cost, one credit deducted — doesn&#x27;t work. Switched to per-platform billing. The point is &quot;a reason to come back every day.&quot; Credits refill on login, so if the habit sticks, that&#x27;s the signal for demand.</p>
<h2>Model cost optimization</h2>
<p>Set Gemini Flash Lite as primary, Claude Haiku as fallback. Gemini&#x27;s free tier allows 1,500 requests per day. Enough for early traffic.</p>
<p>Quality was the problem. Korean-to-Japanese conversion broke when profile settings were enabled. Profile data in the system prompt made Gemini ignore the output language instruction. Small models start dropping fine-grained instructions as the prompt gets longer. The tug-of-war between free and quality will keep going.</p>
<h2>Rewrote the architecture three times</h2>
<h3>Pipeline separation</h3>
<p>Originally fed the entire source text to the AI and pulled all results at once. Analysis and generation tangled in one prompt made output unstable. Split into analyze → generate → validate. Stabilized, and input tokens dropped by half.</p>
<h3>Per-platform calls</h3>
<p>Initially generated all five platforms in a single AI call. Fast, but the tone flattened across platforms. Switched to individual calls per platform, run in parallel. Output changed from JSON to plain text. Parsing issues disappeared, and tone differences between platforms became pronounced.</p>
<h3>Platform swap</h3>
<p>Dropped LinkedIn and Facebook, added Bluesky. Target audience is solo/indie/anonymous developers — LinkedIn&#x27;s professional tone and Facebook&#x27;s community tone didn&#x27;t fit. Tried Hacker News too, then dropped it. HN is just a title line — no repurposing value.</p>
<p>Removed the tone selection dropdown too. Instead of letting users pick professional, casual, or humorous, baked the tone into each platform&#x27;s guide. Twitter gets bold energy, Bluesky gets quiet confidence, Reddit gets honest and humble. Letting the platform decide the tone is more natural.</p>
<h2>22 hours</h2>
<p>First commit to Vercel deploy: twenty-two hours. Without AI coding tools, easily one to two weeks.</p>
<h2>My workflow</h2>
<p>OnceWrite is the last step in my content pipeline.</p>
<ol>
<li><strong>Development</strong> — Build with Claude and Codex.</li>
<li><strong>Session analysis → draft</strong> — After development, have Claude analyze the conversation session and turn it into a blog post draft.</li>
<li><strong>Polish</strong> — Read the draft, set the tone, fill in missing context. This step is human.</li>
<li><strong>OnceWrite</strong> — Feed the finished post in. Out come the social media versions.</li>
</ol>
<p>Development to social media posting in one flow. OnceWrite removes the last hurdle.</p>
<h2>So now</h2>
<p>Deployed. Zero users. Built for myself to begin with.</p>
<p>I&#x27;m the first user. I use it daily and fix what&#x27;s missing as I go. No marketing connections. Chronic lurker by temperament. Community engagement doesn&#x27;t come naturally. That&#x27;s why I needed this tool. Just lowering the hurdle of distributing one post across multiple platforms — for someone like me, that&#x27;s enough.</p>]]></content:encoded>
  </item>
  <item>
    <title>왜 어떤 조직은 가장 잘 아는 사람이 발표하지 못하게 할까</title>
    <link>https://kinkeep.dev/posts/agentic/presentation-accuracy-vs-hierarchy</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/presentation-accuracy-vs-hierarchy</guid>
    <pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate>
    <description>나서는 걸 리스크로 보는 문화에서는, 가장 잘 아는 사람이 침묵하고 정확성은 떨어진다. 나설 수 있는 환경이 정확한 조직을 만든다.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>내 파트는 내가 직접 발표하겠다고 한 적이 있다. 내가 실험하고 정리한 내용이니까, 직접 말하는 게 정확할 거라고 생각했다. 돌아온 반응은 의외였다. <code>뭐하러 그러냐</code>, <code>괜히 나서서 욕만 먹겠네</code>.</p>
<p>막힌 건 위에서가 아니었다. 주변의 분위기였다. 나서는 것 자체가 리스크로 받아들여지는 환경이었다.</p>
<h2>나서지 않는 게 합리적인 환경</h2>
<p>직접 해 본 사람이 말하면 정확하다. 특히 AI 실험처럼 맥락이 많은 주제는 더 그렇다. 어떤 설정에서 어떤 결과가 나왔는지, 왜 그 방향을 선택했는지, 어디서 트레이드오프를 감수했는지. 이런 건 직접 해 본 사람만 제대로 설명할 수 있다.</p>
<p>그런데 직접 하겠다고 나서면, 주변의 시선이 미묘하다. 잘하면 <code>나서더니 잘하네</code>이고, 못하면 <code>그러니까 괜히 나서지 말라고 했잖아</code>다. 어느 쪽이든 나선 사람만 손해다.</p>
<p>이 구조를 몇 번 겪으면, 다들 나서지 않는 쪽을 선택하게 된다. 아는 사람도 가만히 있고, 모르는 사람도 가만히 있는다. 누구도 앞에 서지 않으니, 결국 발표는 역할이나 순번으로 돌아간다. 정확성은 고려 대상이 아니게 된다.</p>
<h2>아는 사람이 말하지 않으면 생기는 일</h2>
<p>아는 사람이 침묵하면, 그 지식은 전달 과정에서 빠지거나 왜곡된다.</p>
<p>실무자가 직접 말하면 5분이면 끝날 설명이, 다른 사람을 거치면 30분이 걸리고 부정확해진다. 맥락이 빠지고, 판단 근거가 생략되고, 트레이드오프가 사라진다. 남는 건 표면적인 결론뿐이다. 질문이 오면 답하지 못한다.</p>
<p>더 안 좋은 건 그다음이다. 아는 사람도 점점 깊이를 빼기 시작한다. 어차피 정확하게 전달되지 않을 거라면, 처음부터 무난하게 맞추는 게 효율적이니까. 1편에서 이야기한 것과 같은 흐름이다. 인정받지 못하면 기여의 질이 떨어지고, 결국 팀 전체가 손해를 본다.</p>
<h2>나설 수 있는 환경</h2>
<p>나서는 걸 말리는 문화는, 나서는 사람이 손해를 보는 경험이 쌓여서 만들어진다. 반대로 나서는 사람이 손해를 보지 않으면, 문화는 바뀔 수 있다.</p>
<p>거창한 게 필요한 건 아니다. 직접 발표하겠다는 사람이 있으면 일단 맡기는 것. 잘했으면 잘했다고 말해 주는 것. 부족했으면 다음에 더 잘할 수 있게 피드백을 주는 것. 나선 사람이 <code>나서길 잘했다</code>고 느낄 수 있는 최소한의 반응이면 충분하다.</p>
<p>내가 바랐던 것도 그거였다. 내 파트를 내가 말하겠다는 데 <code>뭐하러 그래</code>가 아니라 <code>그래, 네가 하는 게 낫겠다</code>라는 한마디. 그게 있었으면 발표의 정확성도, 내 동기도 달라졌을 거다.</p>
<h2>결국 같은 뿌리다</h2>
<p>이 시리즈에서 계속 같은 이야기를 하고 있다. 1편에서는 실험하고 정리한 사람이 인정받지 못하는 구조를 이야기했다. 이번 편에서는 직접 나서서 말하려는 사람이 말려지는 구조를 이야기했다. 모양은 다르지만 뿌리는 같다.</p>
<p>기여하는 사람이 손해를 보는 환경에서는, 기여가 줄어든다. 나서는 사람이 리스크를 지는 환경에서는, 아무도 나서지 않는다. 조직이 정확한 정보를 원한다면, 정확하게 말할 수 있는 사람이 나설 수 있는 환경을 먼저 만들어야 한다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Why Do Some Organizations Stop the Most Knowledgeable Person from Presenting?</title>
    <link>https://kinkeep.dev/posts/agentic/presentation-accuracy-vs-hierarchy-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/presentation-accuracy-vs-hierarchy-en</guid>
    <pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate>
    <description>In cultures where stepping up is seen as risk, the most knowledgeable person stays silent and accuracy drops. Environments where people can step up produce accurate organizations.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>I said I&#x27;d present my own section. Ran the experiments, wrote the findings — presenting myself would be most accurate. Response surprised me. &quot;Why bother?&quot; &quot;You&#x27;ll just catch heat.&quot;</p>
<p>The block wasn&#x27;t from above. It was ambient culture. Stepping up meant risk.</p>
<h2>When not stepping up is the rational choice</h2>
<p>The person who did the work explains it most accurately. Especially for context-heavy subjects like AI experiments — which settings produced which results, why that direction was chosen, what tradeoffs were accepted. Only the person who did the work can explain these properly.</p>
<p>But volunteer to present and the reactions are awkward. Do well: &quot;well look who stepped up.&quot; Do poorly: &quot;told you not to bother.&quot; Either way, the person who stepped up loses.</p>
<p>Experience this a few times and everyone chooses to stay quiet. Those who know stay silent. Those who don&#x27;t also stay silent. Nobody stands in front, so presentations rotate by role or turn order. Accuracy stops being a factor.</p>
<h2>What happens when knowledgeable people don&#x27;t speak</h2>
<p>When the knowledgeable person stays quiet, knowledge gets lost or distorted in transmission.</p>
<p>What the practitioner could explain in five minutes takes thirty through someone else — and arrives inaccurate. Context drops out. Decision rationale gets skipped. Tradeoffs disappear. Only surface conclusions remain. Questions come in; answers don&#x27;t.</p>
<p>Worse follows. The knowledgeable person starts stripping depth preemptively. If accuracy won&#x27;t survive transmission anyway, keeping things safe and generic is more efficient. Same dynamic as the first post in this series: without recognition, contribution quality drops, and the whole team loses.</p>
<h2>An environment where people can step up</h2>
<p>A culture that discourages stepping up is built from accumulated experiences where stepping up hurt. Reverse it — stop penalizing the person who steps up — and the culture shifts.</p>
<p>Nothing dramatic. Someone volunteers to present — let them. Went well, say so. Fell short, give usable feedback. Bare minimum: the person who stepped up should feel it was worth it.</p>
<p>All I wanted. Not &quot;why bother&quot; but &quot;yeah, you presenting makes more sense.&quot; One sentence would have changed both the accuracy and my motivation.</p>
<h2>Same root</h2>
<p>This series keeps circling the same point. The first post covered structures where the person who experiments and synthesizes goes unrecognized. This post covers structures where the person willing to speak gets discouraged. Different shapes, same root.</p>
<p>When contributors are penalized, contribution shrinks. When stepping up carries risk, nobody steps up. If an organization wants accurate information, it must first build an environment where the person who can speak accurately is able to step up.</p>]]></content:encoded>
  </item>
  <item>
    <title>AI 실험 비용은 팀이 쓰고, 정리는 왜 한 사람 몫이 될까</title>
    <link>https://kinkeep.dev/posts/agentic/ai-rnd-return-structure</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/ai-rnd-return-structure</guid>
    <pubDate>Sat, 21 Mar 2026 00:00:00 GMT</pubDate>
    <description>AI 실험 예산은 팀이 배분하지만, 정리와 공유의 부담은 설계 없이 한 사람에게 몰린다. 환원 구조가 빠진 R&amp;D 지원은 결국 누군가를 지치게 만든다.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>요즘은 팀 단위로 AI 상위 플랜을 지급하는 곳이 늘고 있다. 20달러짜리 팀 플랜을 전원에게 깔아 주는 곳도 있고, 실험용으로 맥스 플랜을 몇 명에게 배분하는 곳도 있다. 나도 그렇게 플랜을 받고 실험을 돌리기 시작했을 때, 처음에는 그냥 신났다. 새로운 모델을 비교해 보고, 하네스 설정을 바꿔 가며 차이를 확인하고, 병렬 작업도 해 봤다.</p>
<p>문제는 그다음이었다. 맥스 플랜을 받았으니 거기서 나온 지식을 정리해서 공유하는 건 당연하다고 생각했다. 실제로 그렇게 했다. 그런데 돌아오는 건 기대와 달랐다.</p>
<p>전 편에서 <code>맥스를 소비하는 사람과 운용하는 사람은 다르다</code>는 이야기를 했다. 이번에는 그 연장선에서 한 가지를 더 보려고 한다. 운용하는 사람에게 정리까지 몰리는 구조는 개인의 문제가 아니라, 팀 차원에서 빠져 있는 설계의 문제라는 점이다.</p>
<h2>배분은 있는데 환원은 없다</h2>
<p>플랜을 배분하는 건 조직이 한다. 그런데 <code>그래서 누가 정리하고, 누가 공유하고, 누가 후속 질문을 받느냐</code>는 대부분 설계되지 않는다.</p>
<p>실험 결과를 정리하는 건 실험 자체보다 시간이 더 걸릴 때가 많다. 직접 해 본 사람은 안다. 30분 돌린 실험의 결과를 정리해서 다른 사람이 이해할 수 있게 만드는 데 두세 시간이 걸리기도 한다. 발표 자료를 만들고, 맥락을 설명하고, 질문에 대응하는 것까지 포함하면 더 길어진다.</p>
<p>그런데 이 과정의 ownership이 따로 정해져 있지 않으면, 자연스럽게 실험한 사람이 전부 떠안게 된다. 실험한 사람이 정리하고, 발표하고, 질문 받고, 후속 요청까지 처리한다. 아무도 시키지 않았는데 그렇게 된다.</p>
<h2>공유가 지치는 건 게을러서가 아니다</h2>
<p>처음에는 기꺼이 공유한다. 재미있으니까, 알리고 싶으니까. 맥스를 받았으니 그만큼 환원하는 게 맞다고 생각한다.</p>
<p>그런데 시간이 지나면 분위기가 조금씩 달라진다. 공유를 하면 피드백이 돌아오는 게 아니라, 조용함이 돌아온다. 반응이 없다. 읽었는지도 잘 모르겠다. 그러다가 어느 순간, 맥스 플랜 자체가 반납 대상이 된다. 공평하게 모두 팀 플랜을 쓰자는 분위기. 맥스를 받아서 실험하고, 정리하고, 공유까지 해 왔는데, 그 수고는 고려 대상이 아니었다. 귀찮은 일에 잘도 나서네 같은 시선만 남았다.</p>
<p>더 미묘한 일도 생긴다. 실험 결과를 정리해서 공유하면 <code>그 사람이 알아서 해 주는 거</code>로 인식되기 시작한다. 한두 번 공유를 건너뛰면 <code>요즘 왜 안 해?</code>라는 분위기가 생긴다. 자발적으로 시작한 일이 어느새 의무가 되어 있다.</p>
<p>정리하면 일만 늘고, 안 하면 아무도 뭐라 하지 않는다. 공유해도 피드백이 없고, 공유 안 해도 티가 안 난다. 이 구조가 반복되면 합리적인 사람일수록 공유를 줄이게 된다. 이건 의지 부족이 아니라, 인센티브가 없는 환경에서 나오는 자연스러운 결과다.</p>
<h2>환원을 설계한다는 건</h2>
<p>환원 구조가 없다고 해서 반드시 큰 시스템을 도입해야 하는 건 아니다. 몇 가지만 의식적으로 정하면 달라진다.</p>
<p>실험한 사람이 매번 발표까지 해야 한다는 관성을 깨는 것만으로도 부담이 줄어든다. 발표와 문서화의 ownership을 돌아가며 나누면, 실험 결과를 간단히 넘기고 다른 사람이 정리해서 공유하는 방식이 가능해진다.</p>
<p>실험과 정리를 같은 사람에게 묶지 않는 것도 중요하다. 실험은 A가 하고, 정리는 B가 하고, 발표는 C가 하는 식으로 역할을 나눌 수 있다. 실험하는 사람은 실험에 집중할 수 있고, 정리하는 사람은 정리를 통해 배우게 된다.</p>
<p>결국 <code>누가 혜택을 받았는가</code>와 <code>누가 환원하는가</code>를 분리해서 봐야 한다. 실험 결과를 가져다 쓰는 사람이 정리 과정에 기여하지 않으면, 혜택만 받고 비용은 안 지는 구조가 된다. 이걸 의식하는 것만으로도 팀의 균형이 달라진다.</p>
<h2>운용하는 사람이 계속 운용하려면</h2>
<p>개인이 잘하는 것만으로는 부족하다. 환원이 구조로 설계되어야 지속된다.</p>
<p>결국 내가 바라는 건 거창한 게 아니다. 누군가 실험하고 정리해 오면, 그걸 같이 읽고, 의견을 주고, 다음에는 다른 사람이 정리를 맡는 분위기. 다 같이 으쌰으쌰하는 것. 그게 없으면 실험하는 사람이 지치고, 지치면 공유가 줄고, 결국 팀 전체가 배울 기회를 잃는다.</p>
<p>R&amp;D 지원은 예산이나 플랜을 배분하는 것으로 끝나지 않는다. 그 실험에서 나온 지식을 팀이 같이 소화하는 흐름까지 있어야, 지원이 실제로 작동한다.</p>]]></content:encoded>
  </item>
  <item>
    <title>The Team Spends the AI R&amp;D Budget. Why Does One Person Get Stuck with the Write-Up?</title>
    <link>https://kinkeep.dev/posts/agentic/ai-rnd-return-structure-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/ai-rnd-return-structure-en</guid>
    <pubDate>Sat, 21 Mar 2026 00:00:00 GMT</pubDate>
    <description>AI experiment budgets are distributed by the team, but without designed return structures, the burden of synthesis and sharing falls on one person. R&amp;D support without a return loop eventually burns someone out.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>More teams issue AI plans at the team level now. Some roll out $20 plans to everyone; others distribute max plans to a few for experiments. When I got mine, I was excited. Compared models, tested harness configs, ran parallel work.</p>
<p>The problem came after. Received the max plan, so sharing what I learned felt obvious. I shared. Response wasn&#x27;t what I expected.</p>
<p>In the previous post I wrote that consuming a max plan and operating one are different. This post extends that: when synthesis work piles onto the operator, it&#x27;s not a personal problem — it&#x27;s a structural gap the team hasn&#x27;t designed for.</p>
<h2>Distribution exists, return doesn&#x27;t</h2>
<p>The organization distributes plans. But &quot;who synthesizes, who shares, who fields follow-up questions&quot; is rarely designed.</p>
<p>Synthesizing experiment results often takes longer than the experiment itself. Anyone who&#x27;s done it knows. A 30-minute experiment can take two to three hours to write up so others understand. Add slide decks, context explanations, and fielding questions — longer still.</p>
<p>When ownership of this process isn&#x27;t assigned, the experimenter absorbs it all. They experiment, write up, present, answer questions, handle follow-up requests. Nobody asked them to. It just happens.</p>
<h2>Sharing burns out for structural reasons, not laziness</h2>
<p>At first you share gladly. It&#x27;s interesting, you want to spread the word, returning knowledge feels right after receiving a max plan.</p>
<p>Over time the dynamic shifts. Sharing draws silence, not feedback. Hard to tell if anyone read it. Then the max plan itself becomes a redistribution target. &quot;Let&#x27;s all use team plans fairly.&quot; The experimenting, synthesizing, and sharing — none of that counts. Just &quot;funny how you volunteer for the annoying stuff.&quot;</p>
<p>Subtler things happen too. Shared write-ups get treated as &quot;that person handles it.&quot; Skip a round and &quot;why&#x27;d you stop?&quot; appears. Voluntary work quietly became mandatory.</p>
<p>Share and the work grows. Don&#x27;t share and nobody notices. When this repeats, rational people share less. Not a willpower failure — a predictable outcome of zero incentive.</p>
<h2>What designing return looks like</h2>
<p>A return structure doesn&#x27;t require a big system. A few deliberate choices change the dynamic.</p>
<p>Breaking the habit of &quot;the experimenter always presents&quot; already reduces burden. Rotate presentation and documentation ownership — let someone else synthesize while the experimenter hands off raw results.</p>
<p>Separating experimentation from synthesis matters too. A experiments, B synthesizes, C presents. The experimenter focuses on experimenting. The synthesizer learns by writing it up.</p>
<p>Ultimately, &quot;who received the benefit&quot; and &quot;who does the return work&quot; need separate tracking. When people who consume experiment results don&#x27;t contribute to synthesis, they receive benefits without bearing costs. Just being aware of this rebalances the team.</p>
<h2>For operators to keep operating</h2>
<p>Individual excellence isn&#x27;t enough. Return needs structural design to sustain.</p>
<p>What I want isn&#x27;t grand. Someone experiments and writes it up. The team reads, gives feedback. Next time someone else takes the write-up. Everyone pitching in together. Without that, experimenters burn out, sharing drops, and the team loses its learning loop.</p>
<p>R&amp;D support doesn&#x27;t end at distributing budgets. The loop where the team absorbs experimental knowledge together — that&#x27;s what makes support work.</p>]]></content:encoded>
  </item>
  <item>
    <title>하네스는 감으로 쓰면 안 된다: Harness-Monitor를 만든 이유</title>
    <link>https://kinkeep.dev/posts/agentic/harness-monitor</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/harness-monitor</guid>
    <pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate>
    <description>Codex를 매일 쓰다 보니 토큰 사용량, 프로젝트별 세션, skill과 MCP 설정을 한 화면에서 계속 보고 싶어져서 Harness-Monitor를 만들었다.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-01-tokens-daily.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-02-project-distribution.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-03-sessions.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-04-integrations.png"/><p><code>Harness-Monitor</code>는 토큰 숫자 구경하려고 만든 프로젝트가 아니다. 내가 매일 쓰는 하네스가 지금 어떤 상태인지, 시간은 어디로 들어가고 있는지, 설정은 꼬이지 않았는지를 한 번에 보려고 만든 로컬 대시보다.</p>
<p>집에서는 Codex를 쓰고, 회사에서는 Claude Code를 쓴다. 회사에서는 이미 비슷한 걸 한 번 만들어 봤다. 집에서는 우선 Codex 기준으로 시작했지만, 이름을 <code>codex-monitor</code>로 하지 않은 이유도 여기에 있다. 다음에는 다른 하네스도 같이 붙일 생각이기 때문이다.</p>
<p>내가 보고 싶었던 건 단순히 <code>오늘 몇 토큰 썼나</code>가 아니었다. 어떤 프로젝트에 많이 쓰고 있는지, 세션을 어떻게 길게 끌고 가는지, skill이나 memory 설정은 꼬이지 않았는지, 결국 하네스를 잘 쓰고 있는지를 계속 보고 싶었다. 토큰 사용량은 흥미로운 숫자라기보다 그 결과에 가깝다.</p>
<h2>왜 이런 걸 따로 만들었나</h2>
<p>별거 없다. 불편해서 만들었다. 세션, 메모리, skill, MCP, hook, 토큰 이벤트가 다 로컬 어딘가에 흩어져 있는데, 그걸 매번 파일 열어서 보는 건 귀찮다. 지금 돌아가는 하네스를 이해하려면 볼 건 많은데, 한눈에 보이는 화면은 없었다.</p>
<p>그래서 <code>Harness-Monitor</code>는 문제 하나만 푸는 도구보다, 하네스를 계속 점검하는 계기판에 가깝다. 하네스를 오래 굴리다 보면 낭비가 줄고, 더 효율적으로 쓰게 되고, 어느 순간 구조도 조금씩 정교해진다. 나는 그 선순환을 만들고 싶었다.</p>
<h2>가장 먼저 보는 화면은 토큰 페이지다</h2>
<p>제일 자주 보는 건 토큰 페이지다. 날짜별 추세를 먼저 보고, 그다음 프로젝트별 사용량과 모델별 분포를 본다. 어느 날 많이 썼는지, 어느 날 이상하게 적게 썼는지, 요즘 어떤 프로젝트에 시간을 밀어 넣고 있는지가 여기서 바로 보인다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-01-tokens-daily.png" alt="Harness-Monitor 토큰 추세와 모델 분포"/></p>
<p>토큰 추세를 보고 있으면 생각보다 감정이 많이 섞인다. 어떤 날은 <code>오늘 꽤 했네</code> 싶고, 어떤 날은 <code>이 정도밖에 안 썼네, 더 해야겠다</code>는 생각이 든다. 숫자를 보는 것 같지만, 결국 내가 하네스를 얼마나 밀고 있는지 스스로 점검하게 된다.</p>
<p>프로젝트별 사용량도 자주 본다. 머리로는 여러 프로젝트를 같이 보고 있다고 생각해도, 막상 숫자로 보면 어디에 대부분의 시간이 들어갔는지가 금방 드러난다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-02-project-distribution.png" alt="Harness-Monitor 프로젝트별 토큰 분포"/></p>
<h2>세션과 설정도 같이 봐야 한다</h2>
<p>토큰만 봐서는 하네스를 제대로 이해했다고 말하기 어렵다. 그래서 세션 페이지와 Integrations 페이지도 핵심이다.</p>
<p>세션 페이지에서는 프로젝트별 과거 대화를 다시 볼 수 있다. 굳이 로컬 파일을 하나씩 까 보지 않아도 되고, 예전에 어떤 문제를 어떻게 밀었는지 금방 복기할 수 있다. 오래된 세션을 다시 훑다 보면, 내가 작업을 어떤 식으로 쪼개는지나 특정 프로젝트에서 에이전트를 어떻게 굴렸는지도 같이 보인다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-03-sessions.png" alt="Harness-Monitor 세션 페이지"/></p>
<p>Integrations 페이지는 더 직접적이다. MCP, hook, skill 상태를 한 화면에서 보게 해 두었는데, 실제로 여기서 설정이 잘못된 걸 발견하고 고친 적이 있다. 특정 skill이 agent 전용으로만 잡혀 있던 걸 이 화면을 보고 뒤늦게 알아챘다. 이런 건 그냥 열심히 쓴다고 해결되지 않는다. 결국 한 번씩 봐야 한다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-04-integrations.png" alt="Harness-Monitor Integrations 페이지"/></p>
<h2>만들면서 배운 것도 있었다</h2>
<p>만들다 보니 로컬 폴더 구조도 많이 익히게 됐다. 세션이 어디에 어떻게 저장되는지, skill과 memory가 어떤 파일로 남는지, <code>token_count</code> 이벤트는 어떤 식으로 쌓이는지를 직접 보게 됐다.</p>
<p>대부분은 그냥 Codex나 Claude를 더 잘 써보려고만 하지, 그 하네스가 실제로 어떤 식으로 돌아가는지까지 보려 하진 않는다. 물론 이 과정에서 삽질도 하고, 잘못 이해하는 것도 생길 수 있다. 그래도 누가 정리해 둔 결론만 받아먹는 것보다, 직접 만져 보면서 구조를 배우는 쪽이 남는 게 더 많았다.</p>
<p>Codex와 Claude Code도 이 관점에서 보면 방향 차이가 조금 보인다. 지금 내 체감으로는 Codex가 Claude Code를 쫓아가는 쪽에 가깝고, 기능은 점점 비슷해지는 것 같다. 다만 Codex는 아직 메인 에이전트가 흐름을 잡고, 서브 에이전트는 효율을 위한 보조 인력처럼 쓰는 느낌이 더 강하다. 반면 Claude는 역할별 서브 에이전트를 더 적극적으로 앞세운다. 결국 중요한 건 이름보다, 각 에이전트가 어떤 툴과 스킬을 쓸 수 있게 설계되어 있느냐인 것 같다.</p>
<h2>다음에 붙일 것들</h2>
<p>지금은 Codex만 지원한다. Claude Code 지원은 작업 중이고, 그게 붙으면 <code>Harness-Monitor</code>라는 이름이 더 자연스러워질 것 같다.</p>
<p>그 외에도 몇 가지 생각해 둔 게 있다.</p>
<ul>
<li>과거 세션을 공유하는 기능 — 다른 사람과 대화 맥락을 나눌 수 있으면 좋겠다</li>
<li>토큰 사용량 추세를 공유하는 기능 — 혼자만 보는 것보다 비교할 수 있으면 의미가 커진다</li>
<li>memory와 skill을 화면에서 바로 편집하는 기능</li>
</ul>
<p>지금은 사실상 나 혼자 쓰는 도구다. 홍보도 안 했고, 굳이 남에게 보여 주려고 급하게 만들지도 않았다. 그래도 이런 류의 프로젝트는 직접 해 보는 게 중요하다고 생각한다. 이 과도기에는 <code>어떻게 하면 하네스를 잘 쓸까</code>를 스스로 고민해 보는 시간이 꽤 큰 차이를 만든다.</p>
<p>내가 이 프로젝트에서 가장 분명하게 확인한 건 하나다. 하네스는 한 번 세팅하고 끝나는 게 아니다. 계속 추적하고, 계속 모니터링해야 하는 대상이다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Codex로 블로그를 정리하고 포스팅하는 흐름</title>
    <link>https://kinkeep.dev/posts/agentic/codex-blog-posting</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/codex-blog-posting</guid>
    <pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate>
    <description>글 초안만 맡긴 게 아니라 분류, 인터뷰, 본문 정리, 이미지 반영, 머메이드 지원까지 Codex와 같이 굴리며 정리한 블로그 작업 흐름.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>이 글은 <code>Codex에게 글 한 편 써 달라</code>는 이야기가 아니다. 이번에는 블로그 저장소를 같이 만지면서, 오래된 글을 지우고, devlog를 다시 쪼개고, 프로젝트 페이지를 정리하고, 새 글까지 쓰는 흐름을 꽤 오래 같이 굴렸다. 해 보니 초안을 뽑는 용도보다 <code>편집 파트너</code>나 <code>작업 운영자</code>에 더 가까웠다.</p>
<p>전제는 하나 있다. 내 의견과 경험이 들어가야 하는 부분은 내가 직접 답해야 한다는 점이다. Codex가 구조를 잡고, 글을 다듬고, 파일을 고치고, 이미지를 붙이고, mermaid 렌더링까지 붙여 줄 수는 있어도 내 경험을 대신 만들어 주지는 않는다. 이번 작업이 잘 굴러간 것도 그 선을 꽤 분명하게 잡고 갔기 때문이다.</p>
<p>실제로는 대체로 이런 순서로 갔다. 먼저 글의 역할부터 정했다. devlog, article, 프로젝트 페이지가 각각 뭘 해야 하는지를 세운 뒤, 오래된 글을 훑으며 지울 것, 살릴 것, 다시 쓸 것을 갈랐다. 경험이 필요한 글은 인터뷰부터 했고, 초안이 잡히면 본문, 제목, 설명, 이미지, 링크를 같이 손봤다. 글을 고치다 막히는 UI나 렌더링 문제는 그대로 저장소에서 해결했고, 한 배치가 끝나면 커밋하고 다음 묶음으로 넘어갔다.</p>
<h2>처음엔 기준부터 정했다</h2>
<p>처음부터 글을 고치기 시작하지는 않았다. 먼저 블로그 안에서 글이 어떤 역할을 가져야 하는지부터 정리했다. devlog는 프로젝트에 연결된 진행 기록으로 두고, article은 특정 주제를 설명하는 글로 분리하고, 프로젝트 페이지는 README처럼 짧고 건조하게 유지하는 식이었다. 프로젝트 페이지는 frontmatter와 섹션 순서도 먼저 정해 두고 그 틀 안에서만 다듬었다.</p>
<p>이 기준을 먼저 정해 두니 나중에 판단이 빨라졌다. <code>Epoch: Unseen</code> devlog를 프로젝트별 시리즈로 다시 묶고, <code>Character Forge</code> 같은 글은 관련 article로 따로 세우고, 의미가 약한 글은 과감히 지우는 식의 결정이 훨씬 쉬워졌다. 오래된 <code>Vulkan</code>, <code>AWS</code>, <code>LangChain</code>, <code>DeepLearning</code> 글을 대량 정리한 것도 결국 이 기준 덕분이었다.</p>
<h2>그다음은 글을 바로 쓰지 않고 인터뷰부터 했다</h2>
<p>이번에 가장 자주 쓴 방식은 인터뷰였다. 내가 <code>OpenCode</code>, <code>FlyingCat</code>, <code>OpenClaw</code>, <code>Character Forge</code>, <code>Harness-Monitor</code> 같은 글을 다듬으려고 할 때, Codex가 먼저 몇 가지 짧은 질문으로 재료를 모았다. 왜 그 툴을 쓰게 됐는지, 어디서 한계를 느꼈는지, 실제로 어떤 작업을 맡겼는지, 결과가 어느 정도였는지를 짧게 확인하는 식이다.</p>
<p>이 방식이 좋았던 이유는 단순하다. AI가 제멋대로 그럴듯한 경험담을 꾸며 넣을 위험이 크게 줄어든다. 대신 내가 짧게 답한 내용을 중심으로 글이 자라난다. 이번에 <code>FlyingCat</code> 글이 살아난 것도, <code>NANACA CRASH</code>를 모티브로 잡은 이유나 <code>Antigravity + Gemini 3.0 Pro</code>로 어디까지 맡겼는지를 인터뷰로 다시 꺼냈기 때문이다.</p>
<p>결국 Codex를 글쓰기 도구로 쓸 때 제일 중요한 건 <code>좋은 문장을 대신 쓰게 하는 것</code>보다 <code>내가 실제로 겪은 걸 제대로 끌어내게 하는 것</code>에 더 가깝다고 느꼈다.</p>
<h2>편했던 건 글쓰기와 저장소 작업이 한 루프로 묶인다는 점이다</h2>
<p>보통 글을 쓰다 보면 문장만 고치는 게 아니라 저장소도 같이 건드리게 된다. 이미지 파일을 옮기고, 프로젝트 썸네일을 바꾸고, 관련 글 링크를 다시 연결하고, 어떤 경우에는 렌더러 코드까지 손봐야 한다. 이번에도 딱 그랬다.</p>
<p>예를 들어 <code>Character Forge</code> 글에는 mermaid 다이어그램을 넣었는데, 그냥 코드블록으로만 보여서 결국 MDX 렌더러 쪽에 mermaid 지원을 붙였다. <code>FlyingCat</code>, <code>Epoch: Unseen</code>, <code>Harness-Monitor</code> 프로젝트 페이지는 썸네일과 설명문을 다시 손봤고, 홈에서는 project 필터와 topic 필터를 분리했다. 글을 고치다가 UI나 렌더링 문제가 보이면 그대로 저장소까지 이어서 손대는 흐름이 자연스러웠다.</p>
<p>이게 생각보다 컸다. 글의 설명과 실제 블로그 구조가 한 저장소 안에서 같이 정리되니, <code>글은 맞는데 화면은 어색한 상태</code>로 오래 남아 있지 않았다.</p>
<h2>이번에 자주 쓴 스킬</h2>
<p>몇 가지는 꽤 분명하게 손에 익었다.</p>
<ul>
<li><code>technical-blog-writing</code>
구조를 세울 때 가장 먼저 도움이 됐다. 이 글이 비교 글인지, 실험 기록인지, 운영기인지부터 정하고, 도입과 결론이 흩어지지 않게 잡는 데 좋았다.</li>
<li><code>humanizer</code>
다듬을수록 글이 너무 반듯해지거나 설명문처럼 굳는 경우가 많은데, 그걸 풀 때 자주 썼다. 특히 프로젝트 페이지나 예전 Unity/Unreal 글처럼 짧은 글에서 효과가 컸다.</li>
<li><code>grammar-checker</code>
마지막에 맞춤법, 띄어쓰기, 표현 꼬임을 한 번 더 보는 용도로 괜찮았다. 기술 글은 문장보다 내용이 먼저라서 이런 마감이 의외로 중요했다.</li>
</ul>
<p>스킬 말고도 자주 쓴 흐름이 있었다. 계획을 먼저 세우고, 실제 파일을 읽고, 본문을 수정하고, 이미지 파일을 복사하고, 필요하면 관련 코드까지 고친 뒤, 배치가 괜찮아질 때까지 다시 보는 식이다. 이번처럼 블로그를 크게 손볼 때는 이 반복이 잘 맞았다.</p>
<h2>이 방식이 맞았다고 느낀 이유</h2>
<p>범위가 큰 정리를 계속 밀 수 있었다는 게 제일 컸다. 글이 수십 개 섞여 있는 상태에서 무엇을 지우고 무엇을 살릴지 판단하는 건 손이 잘 안 간다. Codex와 같이 하면 그 막막한 첫 단계를 넘기기가 쉬웠다.</p>
<p>글과 구조를 함께 정리할 수 있다는 것도 좋았다. devlog 번호, project 링크, 태그, 썸네일, 관련 글 허브처럼 글 밖의 요소도 같이 만질 수 있다는 점이 컸다. 단순한 문장 생성형 도구와는 이 지점이 꽤 다르게 느껴졌다. 그리고 내가 놓친 기준을 계속 다시 물어봐 줬다. 어떤 글은 삭제할지, 어떤 글은 devlog에 다시 흡수할지, 프로젝트 페이지에는 기술 내용을 얼마나 남길지 같은 걸 여러 번 짧게 확인하면서 방향을 고정할 수 있었다.</p>
<h2>맡겨 두면 되는 건 아니다</h2>
<p>물론 그냥 맡겨 두면 알아서 좋은 글이 나오지는 않는다. 가장 위험한 건 경험이 필요한 부분이다. 내가 직접 겪은 판단이나 감각이 들어가야 하는데, 그 부분을 확인하지 않으면 금방 밋밋하고 AI 같은 글이 된다.</p>
<p>너무 반듯해지기도 쉽다. 구조는 잘 잡아도 문장 리듬이 전부 비슷해지고, 소제목 아래 첫 문장이 모범답안처럼 굳는 경우가 자주 있었다. 그래서 이번에는 <code>사람답게 다시 다듬어 달라</code>는 요청을 여러 번 넣었다. 프로젝트 페이지와 article, devlog의 역할을 섞지 않는 것도 중요했다. 이 경계가 흐려지면 프로젝트 페이지는 쓸데없이 자세해지고, devlog는 잡탕이 된다.</p>
<h2>유령 작가가 아니라 편집 파트너다</h2>
<p>Codex는 블로그 글을 대신 써 주는 유령 작가라기보다, 저장소 안에서 같이 움직이는 편집 파트너에 가깝다. 기준을 먼저 세우고, 필요한 경험은 인터뷰로 끌어내고, 본문 수정과 파일 작업을 한 루프로 묶으면 꽤 강하다.</p>
<p>특히 이미 글이 쌓여 있는 블로그라면 더 그렇다. 이번에 블로그를 정리하면서 가장 분명하게 느낀 건, 좋은 글 한 편을 뽑는 것보다 블로그 전체를 계속 손볼 수 있는 흐름을 만드는 일이 더 중요하다는 점이었다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Don&apos;t Run Your Harness by Feel: Why I Built Harness-Monitor</title>
    <link>https://kinkeep.dev/posts/agentic/harness-monitor-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/harness-monitor-en</guid>
    <pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate>
    <description>Using Codex daily made me want token usage, per-project sessions, and skill/MCP config all visible on one screen. So I built a local dashboard.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-01-tokens-daily.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-02-project-distribution.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-03-sessions.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-04-integrations.png"/><p>Harness-Monitor isn&#x27;t a token counter. I built it to see my harness state at a glance — where time goes, whether configs drifted, whether I&#x27;m running it well.</p>
<p>Codex at home, Claude Code at work. Already built something similar at work. Named it Harness-Monitor, not codex-monitor — other harnesses plug in next.</p>
<p>What I wanted wasn&#x27;t &quot;how many tokens today.&quot; Which projects eat the most, how sessions stretch, whether skill or memory configs went stale. Token counts are a result, not the point.</p>
<h2>Why build this separately</h2>
<p>Simple. Inconvenience. Sessions, memory, skills, MCP, hooks, token events — all scattered across local files. Opening them one by one is tedious. Understanding a running harness requires seeing many things at once, and no single screen showed them.</p>
<p>Less a single-purpose tool, more a dashboard for continuous inspection. Run a harness long enough — waste shrinks, efficiency rises, structure tightens. I wanted that loop.</p>
<h2>The token page comes first</h2>
<p>Most visited screen: token trends by day, then per-project usage and model distribution. Which days ran heavy, which ran oddly light, which project absorbs time right now — all visible here.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-01-tokens-daily.png" alt="Token trends and model distribution"/></p>
<p>More emotional than expected. Some days feel productive; others draw &quot;that&#x27;s all?&quot; Looks like numbers. Really self-auditing how hard I push the harness.</p>
<p>Per-project breakdown matters too. I think I&#x27;m splitting time evenly. Numbers show where it actually goes.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-02-project-distribution.png" alt="Per-project token distribution"/></p>
<h2>Sessions and config need the same visibility</h2>
<p>Tokens alone don&#x27;t explain the harness. The sessions page and Integrations page are equally core.</p>
<p>Sessions let me review past conversations by project without digging through local files. Skimming old sessions shows how I split work and how I ran agents on a given project.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-03-sessions.png" alt="Sessions page"/></p>
<p>Integrations is more direct. MCP, hooks, and skill status on one screen. I&#x27;ve caught misconfigured settings here — a skill locked to agent-only mode that I hadn&#x27;t noticed. Using the harness harder doesn&#x27;t fix that. You have to look.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/harness-monitor-04-integrations.png" alt="Integrations page"/></p>
<h2>Building it taught me things</h2>
<p>Building it forced me into local folder structures — how sessions store, how skills and memory persist as files, how <code>token_count</code> events accumulate.</p>
<p>Most people try to use Codex or Claude better without looking at how the harness runs underneath. Reading internals led to mistakes too, but hands-on beats someone else&#x27;s summary.</p>
<p>Codex and Claude Code show directional differences from this angle. My sense is Codex is converging toward Claude Code&#x27;s feature set. But Codex still leans on a main agent with subagents as efficiency support, while Claude pushes role-specific subagents more aggressively. What matters isn&#x27;t the name — it&#x27;s what tools and skills each agent can access.</p>
<h2>What&#x27;s next</h2>
<p>Currently Codex-only. Claude Code support is in progress. Once that lands, the name Harness-Monitor fits naturally.</p>
<p>A few things I&#x27;m considering:</p>
<ul>
<li>Session sharing — letting others see conversation context</li>
<li>Token trend sharing — comparison is more useful than solo tracking</li>
<li>In-dashboard memory and skill editing</li>
</ul>
<p>Right now it&#x27;s a solo tool. No promotion, no rush to show it off. But projects like this matter in this transitional period. Thinking about &quot;how do I run my harness well&quot; — that time investment creates real separation.</p>
<p>The clearest thing I confirmed: the harness isn&#x27;t set-and-forget. It&#x27;s something you track and monitor continuously.</p>]]></content:encoded>
  </item>
  <item>
    <title>How I Run Blog Operations with Codex</title>
    <link>https://kinkeep.dev/posts/agentic/codex-blog-posting-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/codex-blog-posting-en</guid>
    <pubDate>Fri, 20 Mar 2026 00:00:00 GMT</pubDate>
    <description>Not just drafting posts — sorting, interviewing, editing, wiring images, adding mermaid support. A blog maintenance workflow run alongside Codex.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Not about asking Codex to write a post. This session touched the blog repo together — deleting old posts, re-splitting devlogs, cleaning project pages, writing new ones. Felt closer to &quot;editing partner&quot; than ghostwriter.</p>
<p>One precondition: parts needing my opinions and experience come from me. Codex structures, polishes, edits files, attaches images, adds mermaid rendering — but can&#x27;t fabricate experience. The session worked because that line stayed clear.</p>
<p>The actual flow went roughly like this. Set the role of each content type first — devlog, article, project page. Then sweep old posts: delete, keep, or rewrite. For posts needing real experience, interview first. Once a draft took shape, refine title, description, images, and links together. When writing hit a UI or rendering problem, fix it in the repo on the spot. Commit at the end of each batch, move to the next.</p>
<h2>Standards before editing</h2>
<p>Didn&#x27;t start editing right away. First defined what each post type should do. Devlogs stay tied to projects as progress records. Articles explain specific topics. Project pages stay short and dry like READMEs, with locked frontmatter and section order.</p>
<p>Setting standards early made later decisions fast. Rebundling Epoch: Unseen devlogs into per-project series, pulling Character Forge into a standalone article, deleting weak posts — all straightforward. Bulk-cleaning old Vulkan, AWS, LangChain, and DeepLearning posts happened because the criteria existed.</p>
<h2>Interview before drafting</h2>
<p>The most-used technique was interviewing. When refining posts about OpenCode, FlyingCat, OpenClaw, Character Forge, or Harness-Monitor, Codex gathered material with a few short questions first. Why did you pick that tool, where did you hit limits, what tasks did you assign, how did it go.</p>
<p>Simple reason: sharply reduces fabrication risk. Posts grow from my short answers instead. FlyingCat came alive because the interview pulled out why I picked NANACA CRASH and how far I delegated to Antigravity + Gemini 3.0 Pro.</p>
<p>Using Codex for writing, the key isn&#x27;t good sentences from it. It&#x27;s extracting what I actually experienced.</p>
<h2>Writing and repo work in one loop</h2>
<p>Blog writing isn&#x27;t just prose. You move images, swap thumbnails, reconnect links, sometimes fix renderer code. This session was no different.</p>
<p>The Character Forge post needed a mermaid diagram. It rendered as a plain code block, so we added mermaid support to the MDX renderer. FlyingCat, Epoch: Unseen, and Harness-Monitor project pages got new thumbnails and copy. The home page got separated project and topic filters. When editing exposed a UI or rendering gap, we fixed it in the same repo, same session.</p>
<p>That mattered more than expected. Copy and site structure staying in sync in one repo meant &quot;text is right but the page looks wrong&quot; didn&#x27;t linger.</p>
<h2>Skills that helped</h2>
<p>A few clicked clearly:</p>
<ul>
<li><strong>technical-blog-writing</strong> — Most helpful for structuring. Deciding if a post is a comparison, experiment record, or operations log, then keeping intro and conclusion aligned.</li>
<li><strong>humanizer</strong> — Polished text tends to stiffen into something that reads like a manual. This skill loosened it. Especially effective on short posts like project pages or old Unity/Unreal entries.</li>
<li><strong>grammar-checker</strong> — Final pass for typos, spacing, awkward phrasing. For technical writing, this last-mile polish matters more than you&#x27;d think.</li>
</ul>
<p>Beyond skills, the recurring flow was: plan → read files → edit copy → move images → fix code if needed → review until the batch looks right. For a major blog overhaul, this loop fit well.</p>
<h2>Why it worked</h2>
<p>Biggest win: momentum on a large cleanup. Dozens of mixed posts, deciding what to keep and what to cut — that first step is paralyzing. Working alongside Codex made it easy to start.</p>
<p>Editing content and structure together was also valuable. Devlog numbers, project links, tags, thumbnails, related-post hubs — touching elements beyond the text itself. That felt distinctly different from a sentence-generation tool. And Codex kept re-asking about criteria I&#x27;d forgotten — should this post be deleted, absorbed into a devlog, how much technical detail belongs on the project page. Short check-ins that locked direction.</p>
<h2>Delegation isn&#x27;t autopilot</h2>
<p>Left alone, Codex doesn&#x27;t produce good posts. The biggest risk is experience-dependent sections. Judgment and intuition that come from doing the work — skip confirming those and the writing goes flat and AI-flavored fast.</p>
<p>Over-polishing is easy too. Structure holds but sentence rhythm flattens, every section opener reads like a model answer. I asked &quot;make it sound human again&quot; multiple times. Keeping project pages, articles, and devlogs in their lanes also mattered. Blur those boundaries and project pages get needlessly detailed while devlogs turn into grab bags.</p>
<h2>Editing partner, not ghostwriter</h2>
<p>Codex is an editing partner that moves with you inside the repo, not a ghostwriter. Standards first, interview for experience, text edits and file work in one loop — strong combination.</p>
<p>Especially for blogs with backlogs. Clearest takeaway: a sustainable maintenance flow matters more than one great post.</p>]]></content:encoded>
  </item>
  <item>
    <title>맥스를 소비하는 사람과 운용하는 사람은 다르다</title>
    <link>https://kinkeep.dev/posts/agentic/max-is-burst-capacity</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/max-is-burst-capacity</guid>
    <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
    <description>AI 플랜의 가치는 평소 많이 쓰는 데보다, 병렬 작업과 장기 검증 실험을 감당할 수 있는 버스트 용량에 더 가깝다고 보게 됐다.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>얼마 전에 OpenClaw를 텔레그램에 붙여 SLIME ARENA를 굴리다가 GPT Pro 주간 사용량을 전부 써 버렸다. 원래 더 중요하게 해야 하는 작업이 남아 있었는데, 그쪽을 못 하게 됐다. 그때 처음으로 플랜의 가치가 <code>많이 쓸 수 있느냐</code>가 아니라 <code>필요할 때 쓸 수 있느냐</code>에 있다는 걸 체감했다.</p>
<p>예전에는 AI 플랜을 거의 사용량 문제로만 봤다. 한 달 동안 많이 쓰면 좋은 플랜이고, 금방 막히면 아쉬운 플랜이라고. 지금은 코딩 에이전트를 계속 굴리는 입장에서, 플랜의 가치를 평소 사용량보다 버스트 용량 쪽으로 보게 됐다.</p>
<h2>많이 쓰는 사람과 운용하는 사람은 다르다</h2>
<p>같은 상위 플랜을 써도 사용 방식은 꽤 다르다.</p>
<p>어떤 사람은 그냥 많이 쓴다. 결과가 마음에 안 들면 다시 묻고, 잘 안 되면 다른 말을 반복해서 넣는다. usage는 높지만 어디서 얼마나 쓰였는지는 잘 안 본다.</p>
<p>또 어떤 사람은 usage가 높더라도 그걸 생존용으로 쓴다. 평소에도 상한선 가까이 붙어 있고, 플랜의 여유가 없으면 바로 작업이 멈춘다. 이런 경우에는 많이 쓰는 건 맞지만, 운용하고 있다고 보기는 어렵다.</p>
<p>반대로 내가 더 의미 있다고 보는 쪽은 따로 있다. 평소 usage는 관리하면서, 정말 필요할 때만 병렬 작업, 긴 실행, 무거운 reasoning, 비교 실험을 한꺼번에 터뜨리는 방식이다. 이때 상위 플랜은 <code>많이 써도 안 끊기는 상품</code>이라기보다 <code>필요할 때 크게 쓸 수 있는 capacity</code>에 가깝다.</p>
<p>그래서 같은 맥스 플랜을 써도 어떤 사람은 소비하고, 어떤 사람은 운용한다는 생각을 하게 됐다.</p>
<h2>왜 버스트 용량이 더 중요해졌나</h2>
<p>실제로 무거운 작업은 평소에 계속 돌지 않는다. 대신 특정 시점에 몰린다.</p>
<ul>
<li>긴 리팩터링을 한 번 맡길 때</li>
<li>서브에이전트를 병렬로 여러 개 붙일 때</li>
<li><code>LSP</code>를 켠 상태와 끈 상태를 비교할 때</li>
<li>하네스 전후 차이를 실험할 때</li>
<li>같은 문제를 다른 구조로 다시 검증할 때</li>
</ul>
<p>이런 날은 usage가 갑자기 크게 튄다. 하지만 중요한 건 <code>오늘 많이 썼다</code>가 아니다. 그 시점에 필요한 실험을 겁내지 않고 끝까지 밀 수 있느냐다.</p>
<p>그래서 내 체감에서는 상위 플랜의 가치가 평시 사용량보다 버스트에 있다. 평소엔 조용하다가도, 필요한 순간에 병렬화와 장기 작업을 감당할 수 있어야 실제 운영이 가능해진다. 반대로 이 여유가 없으면 실험 자체가 소극적으로 바뀐다. 한 번 세게 밀어 보고 결과를 비교해야 할 자리에서도, limits를 먼저 걱정하게 된다.</p>
<h2>결국 내가 보는 건 사용량보다 실험 가능한 환경이다</h2>
<p>이 얘기를 하고 나면 종종 <code>결국 많이 쓸 수 있으면 좋은 거 아니냐</code>로 다시 돌아간다. 물론 많이 쓸 수 있으면 좋다. 다만 내가 중요하게 보는 건 총량 자체가 아니라, 필요할 때 병렬 작업을 겁내지 않고 돌릴 수 있는지, 긴 작업을 중간에 끊지 않고 맡길 수 있는지, 설정 전후 비교 실험을 여러 번 반복할 수 있는지다.</p>
<p>이게 안 되면 usage 숫자가 조금 높아도 운영하는 느낌이 잘 안 난다. 반대로 이게 되면 평소 사용량이 아주 높지 않아도 플랜의 가치가 분명해진다. 그래서 요즘은 상위 플랜을 <code>많이 쓰는 사람의 사치</code>처럼 보기보다, <code>필요할 때 큰 실험을 가능하게 하는 인프라</code>에 더 가깝게 본다.</p>]]></content:encoded>
  </item>
  <item>
    <title>AI 코딩 툴을 갈아타며 정리한 선택 기준</title>
    <link>https://kinkeep.dev/posts/agentic/ai-coding-tool-selection</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/ai-coding-tool-selection</guid>
    <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
    <description>Antigravity, OpenCode/OMO, Codex, Claude Code를 오가며 결국 성능보다 환각 허용치, 사용량, 자율성, 모델 조합 가능성을 더 먼저 보게 됐다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>예전에는 AI 코딩 툴을 볼 때 <code>누가 제일 똑똑한가</code>를 먼저 봤다. 몇 달 동안 이것저것 갈아타고 나니, 지금은 보는 기준이 꽤 달라졌다. 이제 먼저 보는 건 <code>얼마나 오래 맡길 수 있나</code>, <code>환각을 어디까지 감당할 수 있나</code>, <code>내 작업 방식과 자율성 수준이 맞나</code>, <code>다른 모델과 조합이 되나</code> 같은 것들이다. 결국 성능 그 자체보다 작업 리듬의 문제에 더 가깝다는 걸 알게 됐다.</p>
<p>이 글에서 말하는 경험 범위는 아래 정도다.</p>
<ul>
<li>Antigravity: Gemini 3.0 Pro</li>
<li>Claude Code: Claude Opus 4.5, 4.6</li>
<li>Codex: GPT 5.1, 5.2, 5.3, 5.4</li>
</ul>
<h2>왜 계속 갈아탔는가</h2>
<p>한 툴에 오래 정착하지 못해서 계속 옮겨 다닌 건 아니다. 작업이 바뀔수록 내가 중요하게 보는 기준이 더 선명해졌고, 그 기준에 맞춰 메인 툴이 바뀌었다.</p>
<p>처음에는 바이브 코딩 자체를 어디까지 믿을 수 있는지가 궁금했다. 그다음에는 단일 모델 하나보다 여러 모델을 역할별로 묶어 쓰는 편이 더 나은지 시험해 보고 싶었다. 지금은 <code>일을 던져 놓고 한참 뒤에 결과를 받는 흐름</code>이 실제로 돌아가는지, 그리고 그 결과를 내가 다시 통제하기 쉬운지가 제일 중요하다.</p>
<h2>Antigravity와 Gemini 3.0 Pro: 바이브 코딩 입문과 한계</h2>
<p>Antigravity는 내가 바이브 코딩을 제대로 해 본 첫 툴이었다. 블로그를 갈아엎을 때도 써 봤고, Unity 미니게임인 <code>FlyingCat</code>을 일주일 정도 만드는 동안에도 꽤 오래 붙잡고 있었다. 그 시기를 지나면서 처음으로 <code>AI에게 구현을 제법 맡길 수 있겠다</code>는 감각을 얻었다.</p>
<p>도움이 없었던 건 아니다. 초반 속도는 분명히 빨랐고, 내가 직접 코드를 다 치지 않아도 결과를 앞으로 밀 수 있다는 감각을 줬다. 다만 메인 코딩 툴로 쓰기에는 한계가 생각보다 빨리 보였다.</p>
<p>제일 괴로웠던 건 반복되는 컴파일 에러였다. 내가 초반이라 미숙했던 부분도 있었겠지만, Unity에서 작업을 굴리다 보면 비슷한 오류를 계속 되풀이해서 만나는 경우가 잦았다. Gemini 3.0 Pro의 환각도 코딩에서는 자주 발목을 잡았다. 그래서 Antigravity는 <code>바이브 코딩의 가능성을 처음 체감하게 해 준 툴</code>로는 의미가 있었지만, 메인 환경으로 오래 들고 가기는 어려웠다.</p>
<h2>OpenCode/OMO: 모델 조합의 가능성</h2>
<p>그다음 단계에서 기억에 남은 건 OpenCode 자체보다 <code>Oh-My-OpenCode</code>가 보여준 작업 방식이었다. 당시에는 Claude와 Gemini를 이미 쓰고 있었고, 여기에 GPT까지 더해 여러 모델을 역할별로 나눠 쓰는 흐름을 처음 제대로 굴려 봤다.</p>
<p>여기서 얻은 가장 큰 수확은 <code>단일 모델의 성능</code>보다 <code>모델끼리 어떻게 역할을 나누는가</code>가 더 중요하다는 점이었다. 하나는 전체 흐름을 잡고, 하나는 구조나 리팩토링 같은 깊은 일을 맡고, 하나는 빠르게 코드와 문서를 훑게 두는 식으로 배치하면 서로의 약점이 꽤 많이 상쇄됐다.</p>
<p>OMO를 쓰면서 harness도 많이 들여다보게 됐다. 오픈소스 프로젝트 코드를 읽으면서 구조를 익혔고, 내가 필요했던 기능을 직접 붙여 보기도 했다. PR을 올릴 때는 이미 같은 기능이 먼저 들어가 있어서 반영되지는 않았지만, 그 과정 덕분에 harness를 보는 기준은 이때 많이 잡혔다. 실제로 OMO의 서브에이전트 구성은 따로 추출해 두었고, 회사에서 Claude Code 에이전트 오케스트레이션을 만들 때 참고했다.</p>
<p>OpenCode를 지금도 계속 쓰는 건 아니지만, 툴을 고르는 기준은 이때 거의 정리됐다. 좋은 툴은 혼자 모든 걸 해결하는 툴이 아니라, 내가 원하는 방식으로 여러 모델을 엮을 수 있게 해 주는 툴이었다.</p>
<h2>Codex와 GPT 5.4: 맡겨도 된다는 신뢰</h2>
<p>2026년 2월 초부터는 개인 작업에서 Codex를 계속 보고 있었다. 다만 5.3 codex까지는 꽤 쓰기 힘들었다. 너무 로봇 같았고, 사람이 한 말을 자연스럽게 받아들이지 못하는 경우가 많았다. <code>이제는 일을 맡겨도 되겠다</code>는 신뢰가 생긴 건 5.4부터였다.</p>
<p>내 작업 스타일은 원래 일을 잘게 쪼개고, 범위를 정해 던지고, 돌아온 결과를 다시 통제하는 쪽에 가깝다. 5.4부터는 Codex가 이 흐름과 잘 맞았다. 작업을 던져 놓으면 30분, 40분 정도 혼자 처리하다가 결과를 들고 돌아오는 식의 리듬이 자주 나왔다. 다른 사람들은 Codex가 일을 끝까지 안 간다고 느끼기도 하는데, 내 기준에서는 오히려 적당한 선에서 끊고 돌아오는 편이었다.</p>
<p>Claude Code가 <code>같이 방향을 찾아간다</code>는 느낌이라면, Codex는 <code>방향을 알아서 잡아 간다</code>는 느낌에 가깝다. 긴 문제를 붙잡고 구조를 정리하거나, 리팩토링처럼 한동안 손을 떼고 맡겨도 되는 작업에서는 특히 만족도가 높았다.</p>
<p>다만 너무 방어적으로 코드를 짜는 경향이 있어서, 필요 이상으로 가드 로직을 두껍게 깔거나 결과물이 지나치게 무거워질 때가 있다. 처리 자체는 잘하는데, 그 완벽주의가 오히려 코드를 지저분하게 만드는 순간이 있다.</p>
<h2>왜 다시 Claude Code를 같이 쓰려 하는가</h2>
<p>그렇다고 Codex 하나로 끝날 것 같지는 않다. 회사에서는 계속 Claude Code를 쓰고 있고, 집에서도 당분간은 Claude Code와 Codex를 같이 쓰는 구성이 제일 잘 맞을 것 같다.</p>
<p>이유는 Claude Code가 맡는 역할이 분명하기 때문이다. Claude는 Codex보다 harness가 강한 편이고, 문제의 전체 그림을 더 잘 본다. 결과물도 조금 더 사람 손을 탄 느낌이 있다. 문제를 어떻게 자를지, 어느 방향으로 갈지, 어디서 멈출지를 정하는 단계에서는 Claude가 중재자로 들어올 때 결과가 더 좋아지는 경우가 있다.</p>
<p>반대로 실제 일을 길게 맡겨 두고 처리시키는 쪽은 Codex가 더 잘 맞는다. 그래서 지금 기준으로는 <code>Claude가 방향을 잡고 Codex가 밀어붙이는 조합</code>이 가장 안정적이다.</p>
<h2>지금의 선택 기준</h2>
<p>결국 지금은 이런 것들을 먼저 보게 됐다.</p>
<ul>
<li>환각 허용치: 반복 컴파일 에러나 명백한 사실 오류가 잦으면 메인 툴로는 오래 쓰기 어렵다.</li>
<li>사용량 여유: 긴 작업을 맡겨 둘 수 있는 여유가 있어야 실제 생산성이 나온다.</li>
<li>자율성 수준: 내가 핑퐁을 많이 하며 같이 끌고 갈 것인지, 범위를 정해 맡길 것인지와 툴의 성격이 맞아야 한다.</li>
<li>조합 가능성: 비슷해 보이는 모델도 실제로는 역할이 다르기 때문에, 여러 모델을 함께 써 보며 감을 잡는 과정이 중요하다.</li>
</ul>
<p>결국 내 결론은 <code>최고의 단일 모델을 찾는 것</code>보다 <code>모델마다 어디까지 맡길 수 있는지 직접 겪어 보고 역할을 나누는 것</code>에 더 가깝다. Claude Code와 Codex도 겉으로 보면 비슷해 보이지만, 조금만 오래 써 보면 방향이 꽤 다르다. 그 차이는 리뷰 몇 개 읽는 것보다 직접 굴려 보는 편이 훨씬 빨리 보인다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Consuming Your AI Plan vs. Operating It</title>
    <link>https://kinkeep.dev/posts/agentic/max-is-burst-capacity-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/max-is-burst-capacity-en</guid>
    <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
    <description>The value of a top-tier AI plan isn&apos;t daily volume — it&apos;s burst capacity for parallel work and long experiments when they matter most.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>Burned through the entire weekly GPT Pro quota running OpenClaw on Telegram for SLIME ARENA. More important work sat queued behind it. Couldn&#x27;t touch it. First time I realized a plan&#x27;s value isn&#x27;t &quot;can I use a lot&quot; — it&#x27;s &quot;can I use it when I need to.&quot;</p>
<p>I used to judge AI plans by volume. Lots of usage per month, good plan. Hit limits fast, bad plan. Running coding agents daily changed that view. Less about average consumption, more about burst capacity.</p>
<h2>Consuming vs. operating</h2>
<p>Same top-tier plan, very different usage patterns.</p>
<p>Some people just use a lot. Results disappoint, rephrase, retry. Usage runs high, but they never track where it goes.</p>
<p>Others also run high, but for survival. Near the ceiling every day, work stops the moment headroom disappears. High usage — but not operating. Always scraping the limit.</p>
<p>The pattern that matters: manage daily usage, then burst hard when it counts. Parallel tasks, long runs, heavy reasoning, comparison experiments — all at once. The top plan isn&#x27;t &quot;unlimited usage.&quot; It&#x27;s capacity to go big when needed.</p>
<p>Same plan. Some consume. Some operate.</p>
<h2>Why burst matters more now</h2>
<p>Heavy work doesn&#x27;t run every day. It clusters at specific moments:</p>
<ul>
<li>Handing off a long refactoring</li>
<li>Spinning up multiple subagents in parallel</li>
<li>Comparing LSP on vs. off</li>
<li>A/B testing harness configurations</li>
<li>Re-verifying the same problem with a different structure</li>
</ul>
<p>These days, usage spikes hard. But the point isn&#x27;t &quot;I used a lot today.&quot; It&#x27;s whether you can push a critical experiment to completion without flinching at limits.</p>
<p>So in practice, a top plan&#x27;s value lives in burst capacity. Quiet most days, then able to absorb parallel work and long tasks when they arrive. Without that headroom, experiments get timid. At the moment you should push hard and compare results, you worry about limits instead.</p>
<h2>What I&#x27;m really looking at</h2>
<p>Circles back to &quot;more is just better, right?&quot; More is nice. What I care about is narrower: run parallel tasks without hesitation, leave a long job running uncut, repeat comparison experiments freely.</p>
<p>Without that, high numbers don&#x27;t feel like operating. With it, even moderate daily usage makes the plan worth it. Top-tier plans aren&#x27;t a luxury for heavy users. They&#x27;re infrastructure for serious experiments when they count.</p>]]></content:encoded>
  </item>
  <item>
    <title>What I Actually Look for After Switching AI Coding Tools</title>
    <link>https://kinkeep.dev/posts/agentic/ai-coding-tool-selection-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/ai-coding-tool-selection-en</guid>
    <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
    <description>After cycling through Antigravity, OpenCode/OMO, Codex, and Claude Code, I stopped comparing intelligence and started comparing hallucination tolerance, usage headroom, autonomy fit, and model composability.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>I used to pick AI coding tools by asking which is smartest. Months of switching changed the criteria. Now I check how long I can leave a task running, how much hallucination I&#x27;ll tolerate, whether the tool&#x27;s autonomy fits my workflow, and whether it composes with other models. Less about raw capability, more about work rhythm.</p>
<p>Experience scope for this post:</p>
<ul>
<li>Antigravity: Gemini 3.0 Pro</li>
<li>Claude Code: Claude Opus 4.5, 4.6</li>
<li>Codex: GPT 5.1, 5.2, 5.3, 5.4</li>
</ul>
<h2>Why I kept switching</h2>
<p>Not because I couldn&#x27;t settle. As the work changed, the criteria sharpened, and the main tool shifted with them.</p>
<p>First I wanted to know how far vibe coding could be trusted. Then I tested whether splitting roles across multiple models beat relying on one. Now the question is whether &quot;throw a task, come back later&quot; actually works — and whether I can control what comes back.</p>
<h2>Antigravity and Gemini 3.0 Pro: vibe coding starts here</h2>
<p>Antigravity was my first real vibe coding tool. Overhauled this blog with it, built a Unity mini-game called FlyingCat over a week. First time I felt AI could handle real implementation.</p>
<p>Early speed was real — results moved forward without me writing every line. But limits appeared fast. Repeated compile errors hurt most — partly inexperience, partly Gemini 3.0 Pro hallucinating the same failures over and over. Antigravity proved vibe coding works. It didn&#x27;t last as a daily driver.</p>
<h2>OpenCode/OMO: model composition clicks</h2>
<p>What stuck from this phase wasn&#x27;t OpenCode itself but the workflow OMO demonstrated. I was already using Claude and Gemini; adding GPT let me try splitting roles across models for real.</p>
<p>Biggest takeaway: how you divide roles between models matters more than any single model&#x27;s capability. One handles the big picture, one takes deep structural work, one skims code and docs fast. Their weaknesses cancel out.</p>
<p>OMO pulled me into harness internals. Read the project&#x27;s source, tried adding features. My PR duplicated work already merged, but the process shaped how I evaluate harnesses. Extracted OMO&#x27;s subagent layout and referenced it when building agent orchestration at work.</p>
<p>Stopped using OpenCode daily, but my selection framework locked in here. A good tool doesn&#x27;t solve everything alone — it lets you compose models your way.</p>
<h2>Codex and GPT 5.4: trust to delegate</h2>
<p>Watched Codex for personal work since early February 2026. Through 5.3 it was rough — too robotic, bad at natural instructions. Trust came with 5.4.</p>
<p>I slice work small, define scope, throw it over, control what comes back. From 5.4, Codex matched that rhythm. Throw a task, it runs alone for thirty to forty minutes, returns with results. Some say Codex doesn&#x27;t finish things. For me it stops about right.</p>
<p>Claude Code feels like finding direction together. Codex feels like it picks direction on its own. Long refactors, structural cleanup, anything I can hand off and walk away from — Codex handles well.</p>
<p>One quirk: it codes defensively to a fault. Guard logic piles up thicker than needed, and results get heavier than they should. The perfectionism sometimes makes the code messier.</p>
<h2>Why I&#x27;m running Claude Code alongside</h2>
<p>Codex alone isn&#x27;t enough. I use Claude Code at work and plan to keep running both at home.</p>
<p>Claude Code&#x27;s harness is stronger. It sees the full shape of a problem better. Output feels more human-touched. When deciding how to split a problem, which direction to go, where to stop — Claude as mediator improves results.</p>
<p>For sustained execution, Codex fits better. So the current setup: Claude sets direction, Codex pushes through. Most stable combination I&#x27;ve found.</p>
<h2>Current selection criteria</h2>
<p>What I look at now:</p>
<ul>
<li><strong>Hallucination tolerance.</strong> Repeated compile errors or obvious factual mistakes make a tool unusable as a daily driver.</li>
<li><strong>Usage headroom.</strong> Long tasks need room to run. Without it, real productivity doesn&#x27;t happen.</li>
<li><strong>Autonomy match.</strong> Do I want tight ping-pong collaboration, or scoped delegation? The tool&#x27;s personality has to fit.</li>
<li><strong>Composability.</strong> Models that look similar play different roles in practice. Trying combinations and finding the split matters.</li>
</ul>
<p>Not &quot;find the best model.&quot; Use each long enough to learn where it breaks, then assign roles. Claude Code and Codex look alike on paper. A week of use makes the gap obvious. Hands-on beats reviews.</p>]]></content:encoded>
  </item>
  <item>
    <title>프론티어 모델 구간에서는 하네스가 더 큰 차이를 만든다</title>
    <link>https://kinkeep.dev/posts/agentic/model-vs-harness</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/model-vs-harness</guid>
    <pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate>
    <description>프론티어 코딩 모델 구간에서는 같은 Claude와 GPT를 써도 컨텍스트 관리, memory, skill, subagent, LSP, 검증 루프 같은 하네스 차이가 실무 성능을 더 크게 흔든다고 보게 됐다.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>예전에는 AI 코딩 성능을 거의 모델 문제로 봤다. 더 좋은 모델이 나오면 그쪽으로 옮기면 된다고 생각했다. 지금은 그 생각이 꽤 달라졌다. 적어도 Claude 4.5나 GPT-5.x급 코딩 모델을 쓰는 구간에서는, 실무에서 체감하는 차이를 더 크게 흔드는 건 모델보다 하네스인 경우가 많다고 본다.</p>
<p>여기서 말하는 하네스는 프롬프트 몇 줄이 아니다. 컨텍스트를 어떻게 넣고 줄일지, <code>memory</code>를 어떻게 유지할지, <code>skill</code>과 <code>AGENTS</code>를 어떻게 나눌지, <code>subagent</code>를 어디에 붙일지, <code>LSP</code>나 테스트 루프를 어떻게 연결할지까지 포함한 운영 층 전체를 말한다.</p>
<h2>왜 이제는 모델보다 하네스를 먼저 보게 됐나</h2>
<p>모델이 약하던 시기에는 <code>결국 모델이 다 한다</code>는 말이 더 맞았다. 기본 추론 능력이 부족하면 그 위에 뭘 얹어도 한계가 빨리 드러났기 때문이다.</p>
<p>지금은 조금 다르다. 상위권 모델 구간에 들어오면 웬만한 코딩 작업은 일단 <code>된다</code>. 그래서 실제 차이는 <code>되냐 안 되냐</code>보다 <code>얼마나 안정적으로 반복되느냐</code>, <code>얼마나 오래 맡길 수 있느냐</code>, <code>검증 가능한 결과로 돌아오느냐</code> 쪽에서 더 크게 난다.</p>
<p>내가 더 크게 본 건 어떤 문서를 먼저 읽히는가, 긴 컨텍스트를 어떻게 압축하는가, <code>memory</code>와 <code>skill</code>을 어떻게 나누는가, <code>subagent</code>로 무엇을 병렬화하는가, <code>LSP</code>나 테스트 같은 도구를 어디까지 연결하는가, 검증 루프를 얼마나 강하게 거는가 같은 것들이다.</p>
<p>같은 Claude나 같은 GPT를 써도 이 층이 달라지면 결과가 꽤 달라진다. 모델이 잠재력을 주는 건 맞지만, 그 잠재력을 실제 생산성으로 바꾸는 건 결국 하네스라고 느끼게 됐다.</p>
<h2>하네스 엔지니어링은 프롬프트 작성보다 넓다</h2>
<p>하네스를 프롬프트 꼼수 정도로 보면 금방 한계에 닿는다. 실제로는 시스템 설계에 더 가깝다.</p>
<p>실제로는 파일과 툴, 실행 환경, 상태를 연결하는 일도 들어가고, 어떤 인터페이스로 agent를 일하게 할지 정하는 일도 들어간다. 승인, 정책, 로깅, 비용 같은 운영 문제도 같이 붙고, 프로젝트 규칙을 agent가 읽을 수 있는 형태로 정리하는 일도 필요하다.</p>
<p>그래서 내가 보는 하네스 엔지니어링은 <code>대답하는 모델</code>을 <code>일하는 시스템</code>으로 바꾸는 작업에 가깝다. 좋은 모델 하나를 붙잡는 일보다, 좋은 모델이 반복 가능하게 일하도록 환경을 설계하는 일이 더 중요해졌다.</p>
<h2>지금 사라질 것과 남을 것을 나눠서 봐야 한다</h2>
<p>모든 하네스가 오래 남는다고 보지는 않는다. 모델이나 제품이 덜 성숙해서 임시로 붙여 둔 보정재는 시간이 지나면 제품 안으로 흡수될 수 있다. 특정 약점을 메우는 프롬프트 트릭이나 brittle한 workaround, 지금 형태의 외부 메모리 도구 일부는 그런 쪽에 가깝다.</p>
<p>반대로 구조와 운영 원리에 가까운 요소는 쉽게 안 사라진다. 역할 분리와 <code>subagent</code> 오케스트레이션, <code>skill</code>과 워크플로 모듈화, 정책과 권한, 검증 루프, 상태 관리와 메모리 운영 규칙, 관측성과 로그, 의미 기반 코드 인덱싱까지. 이런 것들은 특정 모델이나 제품에 묶이지 않는다.</p>
<p><code>LSP</code>도 비슷하다. 지금처럼 수동으로 붙이는 방식은 바뀔 수 있다. 그래도 agent에게 의미 기반 코드 인텔리전스를 연결한다는 문제 자체가 사라지지는 않을 것 같다.</p>
<h2>사용자보다 운영자가 더 오래 남는다고 보는 이유</h2>
<p>좋은 사용자는 점점 더 많아질 가능성이 크다. 모델이 좋아지고 제품 기본 UX가 좋아지면, 단순 활용 능력은 점점 기본기에 가까워질 수 있다.</p>
<p>그다음 차이를 만드는 건 운영자 쪽이라고 본다. 여기서 말하는 운영자는 AI를 자주 쓰는 사람이 아니다. AI가 잘 일하게 만드는 사람에 더 가깝다. 작업을 어떻게 자를지, 어떤 문서를 먼저 읽힐지, 어디서 멈추게 할지, 무엇을 측정할지, 어떤 결과를 통과로 볼지까지 설계하는 사람이다.</p>
<p>이 차이는 계측에서 더 잘 보인다. 토큰 사용량, 캐시 리드, <code>LSP</code> 전후 차이, 검증 통과율 같은 걸 보지 않으면 운영이라기보다 체감담에 가깝다. 적어도 내 기준에서는 <code>많이 쓰는 것</code>보다 <code>측정하면서 고치는 것</code>이 더 중요해졌다.</p>
<h2>그래서 지금 더 중요하게 보는 것</h2>
<p>지금 내 기준을 짧게 줄이면, 하이엔드 모델의 기본 능력선은 이미 높고 실무에서 차이를 만드는 건 그 위에 얹힌 하네스다. 하네스는 꼼수가 아니라 시스템이고, 계측이 없으면 운영이라고 부르기 어렵다. 장기적으로 희소한 역량은 좋은 사용자보다 좋은 운영자 쪽에 남을 가능성이 크다고 본다.</p>
<p>모델이 중요하지 않다는 뜻은 아니다. 모델은 여전히 바닥 성능과 잠재력을 정한다. 다만 지금 내가 보는 구간에서는, 실제 업무 성과를 갈라놓는 차이가 모델 교체보다 하네스와 운영 방식에서 더 자주 나온다. 그래서 요즘은 <code>무슨 모델을 쓰는가</code>만큼이나 <code>어떤 환경 위에서 어떻게 굴리는가</code>를 먼저 보게 됐다.</p>]]></content:encoded>
  </item>
  <item>
    <title>In the Frontier Model Range, the Harness Makes a Bigger Difference</title>
    <link>https://kinkeep.dev/posts/agentic/model-vs-harness-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/model-vs-harness-en</guid>
    <pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate>
    <description>Among frontier coding models, context management, memory, skills, subagents, LSP, and verification loops — the harness layer — drive more practical difference than swapping models.</description>
    <category>AI/HarnessEngineering</category>
    <content:encoded><![CDATA[<p>AI coding performance used to be a model problem for me. Better model, switch. That changed. In the Claude 4.5 / GPT-5.x tier, the harness drives more practical difference than the model.</p>
<p>Harness here isn&#x27;t a few prompt lines. It&#x27;s the full operational layer: how context enters and gets trimmed, how memory persists, how skills and AGENTS files split work, where subagents attach, how LSP and test loops connect.</p>
<h2>Why I now look at the harness first</h2>
<p>When models were weaker, &quot;the model does everything&quot; rang true. Weak base reasoning meant nothing on top lasted.</p>
<p>Different now. Frontier models handle most coding tasks. The gap isn&#x27;t &quot;can it do it&quot; but &quot;how reliably does it repeat,&quot; &quot;how long can I leave it,&quot; &quot;does it return verifiable results.&quot;</p>
<p>What I watch: which documents load first, how context compresses, how memory and skills split, what subagents parallelize, how far LSP and tests reach, how tight the verification loop runs.</p>
<p>Same Claude, same GPT — change the harness and results shift. The model sets potential. The harness converts it into output.</p>
<h2>Harness engineering is broader than prompt writing</h2>
<p>Treat it as prompt tricks and you hit a ceiling fast. It&#x27;s closer to system design.</p>
<p>Wiring files, tools, and execution environments. Choosing what interface an agent works through. Attaching operational concerns — approvals, policies, logging, cost tracking. Formatting project rules so agents can read them.</p>
<p>Harness engineering turns &quot;a model that answers&quot; into &quot;a system that works.&quot; Picking a good model matters less than designing the environment where it produces repeatable output.</p>
<h2>Separating what will disappear from what will stay</h2>
<p>Not every harness element lasts. Patches for immature models or products — prompt tricks covering specific weaknesses, brittle workarounds, certain external memory tools — will get absorbed into products over time.</p>
<p>Elements closer to structure and operational principles stick around. Role separation and subagent orchestration. Skill and workflow modularity. Policies and permissions. Verification loops. State management and memory governance. Observability and logging. Semantic code indexing. None of these tie to a specific model or product.</p>
<p>LSP is similar. The current manual integration method may change. The underlying problem — connecting semantic code intelligence to agents — won&#x27;t disappear.</p>
<h2>Why operators outlast users</h2>
<p>Good users will multiply. Better models and better product UX turn basic utilization into table stakes.</p>
<p>The next differentiator is operators. Not people who use AI often — people who make AI work well. They design task splits, document loading order, stopping points, metrics, pass/fail criteria.</p>
<p>The difference shows clearest in instrumentation. Token usage, cache reads, LSP on/off deltas, verification pass rates — without these, it&#x27;s anecdote. &quot;Using a lot&quot; matters less than measuring and adjusting.</p>
<h2>What I prioritize now</h2>
<p>Short version: frontier models set a high floor. The harness drives practical difference. It&#x27;s a system, not a trick — and without instrumentation, don&#x27;t call it operation. Long-term, scarce capability sits with operators, not users.</p>
<p>Models matter. They set floor and ceiling. But in this range, outcomes diverge more from harness and operational approach than from model swaps. I now ask &quot;what environment is it running in&quot; as much as &quot;what model is it running.&quot;</p>]]></content:encoded>
  </item>
  <item>
    <title>Claude Code의 LSP는 토큰을 줄여줄까</title>
    <link>https://kinkeep.dev/posts/agentic/claude-code-lsp-token-efficiency</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/claude-code-lsp-token-efficiency</guid>
    <pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate>
    <description>LSP가 코드 탐색 품질을 높이면 토큰도 줄어들 거라 생각했지만, 대규모 프로젝트와 Unity 코드베이스에서는 결과가 더 단순하지 않았다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>처음엔 그냥 이렇게 생각했다. <code>LSP가 붙으면 grep를 덜 돌게 되고, 코드 탐색이 더 정확해질 테니 토큰도 줄어들겠지.</code> Claude Code에서 LSP 이야기가 자꾸 나오는 걸 보면서도 결국 기대한 건 그거였다.</p>
<p>문서와 changelog, 사용자 이슈를 조금만 봐도 왜 다들 LSP를 붙이려고 하는지는 금방 납득된다. 정의 위치를 바로 찾고, 참조를 따라가고, 타입 정보를 보고, diagnostics를 빠르게 받는 건 누구나 좋아 보일 수밖에 없다. 잘만 붙으면 텍스트 검색 위주의 탐색보다 훨씬 나을 것 같았다.</p>
<p>그런데 직접 비교해 보니 결과는 내가 처음 기대한 것과 꽤 달랐다. 적어도 내가 본 대규모 프로젝트와 Unity 코드베이스에서는, <code>LSP = 더 빠르고 더 싸다</code>는 식으로 간단히 정리되지 않았다.</p>
<h2>처음 세운 가설</h2>
<p>내 가설은 이랬다.</p>
<ul>
<li>LSP가 붙으면 의미 기반 탐색이 가능해진다.</li>
<li>그러면 grep를 여러 번 돌리고 파일을 직접 읽는 횟수가 줄어든다.</li>
<li>결국 시간도 줄고, 토큰도 줄고, 보고서 정확도도 올라갈 것이다.</li>
</ul>
<p>앞의 두 줄은 지금도 어느 정도 맞다고 생각한다. 문제는 마지막 줄이었다. 실제로는 <code>정확도</code>, <code>시간</code>, <code>토큰</code>이 한 방향으로 같이 움직이지 않았다.</p>
<h2>어떻게 봤나</h2>
<p>비교 대상은 아주 단순했다. 특정 함수를 중심으로 로직을 파악하고, 그 함수의 호출부를 추적해 보고서를 만드는 태스크를 여러 번 돌렸다. 이걸 서브에이전트를 병렬로 소환하는 방식으로 굴리면서, 각 실행의 보고서 정확도, 시간 소모량, 토큰 소모량을 같이 봤다.</p>
<p>여기서 제일 중요했던 건 함수의 caller 수였다. 결국 <code>이 함수가 얼마나 많은 곳에서 불리는가</code>가 결과를 크게 갈랐다.</p>
<h2>호출부가 적을 때는 grep가 훨씬 낫다</h2>
<p>호출부가 10개 미만인 태스크에서는 grep가 압도적으로 빨랐다. 실수도 거의 없었다. 이런 경우에는 굳이 LSP를 끌어오는 쪽이 오히려 돌아가는 길처럼 느껴졌다.</p>
<p>이유도 자연스럽다. 참조 수가 적으면 텍스트 기반 탐색만으로도 맥락이 금방 닫힌다. LSP 질의를 준비하고, 응답을 받고, 그 결과를 다시 모델이 해석하는 비용을 생각하면 그냥 grep가 더 짧게 끝난다.</p>
<p>여기서는 내가 처음 세운 가설이 오히려 틀렸다. <code>더 좋은 도구</code>가 <code>더 싼 도구</code>가 되는 건 아니었다.</p>
<h2>호출부가 많아질수록 grep는 갑자기 흔들린다</h2>
<p>문제는 caller 수가 늘어날 때부터였다. 호출부가 10개를 넘기기 시작하면 grep의 정확도가 눈에 띄게 떨어졌다. 다른 클래스에 있는 동명의 함수를 잘못 잡거나, 텍스트상 비슷해 보이는 결과를 섞어 읽는 일이 생겼다.</p>
<p>이때부터 grep 보고서는 빠르긴 한데 점점 불안해진다. 특히 호출부가 90개 안팎까지 늘어난 태스크에서는 편차가 정말 컸다. 어떤 실행은 그럴듯하게 맞아 보이고, 어떤 실행은 거의 랜덤에 가까웠다. 겉으로 보기에는 보고서가 성립하는데, 실제 caller 집합은 틀린 경우도 있었다.</p>
<p>이 구간에서는 속도가 장점이 아니라 함정처럼 느껴졌다. 빨리 나오는데, 믿고 다음 판단으로 넘어가기가 어렵다.</p>
<h2>LSP는 느리고 비싸지만, 정확도는 안정적이었다</h2>
<p>LSP 쪽은 일관되게 느렸다. 그리고 grep보다 토큰도 더 먹었다. 적어도 내가 본 실험에서는 이 차이가 꽤 분명했다.</p>
<p>대신 정확도는 안정적이었다. 호출부 파악이라는 기준으로 보면, 내가 돌린 태스크들에서는 LSP 쪽에 오차가 없었다. caller 수가 늘어나도 결과가 무너지지 않았고, 동명의 함수 때문에 보고서가 비틀리는 문제도 없었다.</p>
<p>그래서 체감이 묘했다. 처음에는 <code>LSP를 쓰면 효율이 좋아질 것</code>이라고 생각했는데, 실제로는 <code>LSP를 쓰면 결과 품질을 덜 의심하게 된다</code>는 쪽이 더 맞았다. 토큰 절약 기능이라기보다 정확도 유지 기능에 가까웠다.</p>
<h2>왜 이런 결과가 나왔을까</h2>
<p>내가 내린 해석은 이 정도다.</p>
<ul>
<li>참조 수가 적은 태스크는 원래 단순해서 grep로도 충분하다.</li>
<li>참조 수가 많아질수록 텍스트 기반 탐색은 이름 충돌과 맥락 오판에 약해진다.</li>
<li>LSP는 느리고 질의 비용도 들지만, 심볼과 참조 관계를 안정적으로 잡아 준다.</li>
</ul>
<p>지금 내 느낌에 LSP의 장점은 <code>항상 더 싸다</code>가 아니라 <code>복잡해질수록 덜 틀린다</code>에 가깝다.</p>
<p>이건 생각보다 큰 차이다. 에이전트 코딩에서 중요한 게 항상 속도만은 아니기 때문이다. 빠른데 틀린 보고서가 계속 나오면, 그다음 단계에서 검증하고 되돌리는 비용이 더 커진다. 그 비용까지 생각하면 LSP의 느림이 완전히 손해라고만 보기도 어렵다.</p>
<h2>그래서 어떻게 쓰고 있나</h2>
<p>지금 내 결론은 꽤 단순하다.</p>
<ul>
<li>caller가 적고 맥락이 단순하면 grep가 낫다.</li>
<li>caller가 많고 참조 그래프가 커지면 LSP가 돈값을 한다.</li>
<li>다만 2026년 3월 기준으로, LSP가 시간과 토큰까지 같이 줄여 준다고 기대하진 않는다.</li>
</ul>
<p>그래서 지금은 LSP를 기본값으로 쓰지 않는다. 토큰을 줄이기 위한 만능 해법으로도 안 본다. grep의 정확도가 무너지는 구간에서 정확도를 지키기 위한 도구로 쓰고 있고, 내 기준에서는 이쪽이 훨씬 실제에 가까웠다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Does Claude Code&apos;s LSP Actually Save Tokens?</title>
    <link>https://kinkeep.dev/posts/agentic/claude-code-lsp-token-efficiency-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/claude-code-lsp-token-efficiency-en</guid>
    <pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate>
    <description>I expected LSP to reduce token usage by improving code navigation accuracy. On large projects and Unity codebases, the answer was more nuanced.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<p>Simple assumption: LSP means fewer grep runs, more accurate navigation, fewer tokens. That&#x27;s what I expected watching Claude Code discussions.</p>
<p>Docs and changelogs make the case obvious. Jump to definition, follow references, inspect types, fast diagnostics — better than text search. Should be cheaper too.</p>
<p>Direct comparison said otherwise. On the large projects and Unity codebases I tested, &quot;LSP = faster and cheaper&quot; didn&#x27;t hold.</p>
<h2>Starting hypothesis</h2>
<p>My hypothesis:</p>
<ul>
<li>LSP enables semantic navigation.</li>
<li>That reduces grep iterations and raw file reads.</li>
<li>Time drops, tokens drop, report accuracy rises.</li>
</ul>
<p>The first two still hold. The third didn&#x27;t. In practice, accuracy, time, and tokens didn&#x27;t move in the same direction.</p>
<h2>How I tested</h2>
<p>Simple setup. Trace a function&#x27;s logic, map its callers into a report. Run multiple times with parallel subagents. Compare accuracy, time, and token cost.</p>
<p>The variable that split results: caller count. How many places call this function determined everything.</p>
<h2>Few callers: grep wins easily</h2>
<p>Under 10 callers, grep won by a wide margin. Almost no errors. LSP felt like the long way around.</p>
<p>Few references and text search closes context fast. The overhead of preparing an LSP query, waiting, having the model interpret results — more expensive than grep finishing outright.</p>
<p>Hypothesis wrong here. Better tool didn&#x27;t mean cheaper tool.</p>
<h2>Many callers: grep falls apart suddenly</h2>
<p>Past 10 callers, grep accuracy dropped visibly. It grabbed same-named functions from other classes, mixed textually similar results. Reports came back fast but unreliable. At ~90 callers, variance was extreme — some runs looked plausible, others were near-random. Reports that appeared valid contained wrong caller sets.</p>
<p>Speed stopped being an advantage. Fast but untrustworthy.</p>
<h2>LSP: slower, more expensive, but stable</h2>
<p>LSP was consistently slower. Used more tokens too — clearly so in my experiments.</p>
<p>But accuracy held. For caller identification, LSP runs showed no errors in my tasks. Rising caller count didn&#x27;t break results. Same-name confusion didn&#x27;t happen.</p>
<p>Odd experience. Expected &quot;LSP = more efficient.&quot; Got &quot;LSP = less reason to doubt the result.&quot; Not token-saving. Accuracy-preserving.</p>
<h2>Why this happens</h2>
<p>My interpretation:</p>
<ul>
<li>Low-reference tasks are simple enough that grep suffices.</li>
<li>As references grow, text search gets vulnerable to name collisions and context misreads.</li>
<li>LSP is slower and costs more per query, but locks symbol-reference relationships reliably.</li>
</ul>
<p>LSP&#x27;s advantage isn&#x27;t &quot;always cheaper.&quot; It&#x27;s &quot;less wrong as complexity rises.&quot;</p>
<p>That difference matters. Agent coding isn&#x27;t always about speed. If fast-but-wrong reports keep appearing, verification and rollback costs at the next step grow. Factor those in and LSP&#x27;s slowness isn&#x27;t pure loss.</p>
<h2>How I use it now</h2>
<p>My conclusion is straightforward:</p>
<ul>
<li>Few callers, simple context — grep wins.</li>
<li>Many callers, large reference graph — LSP earns its cost.</li>
<li>As of March 2026, I don&#x27;t expect LSP to save time or tokens.</li>
</ul>
<p>I don&#x27;t use LSP as a default. I don&#x27;t treat it as a universal token optimizer. I use it where grep&#x27;s accuracy collapses — to preserve accuracy. That framing matched reality far better.</p>]]></content:encoded>
  </item>
  <item>
    <title>텔레그램으로 게임 개발 굴리기: OpenClaw로 SLIME ARENA 운영한 기록</title>
    <link>https://kinkeep.dev/posts/agentic/openclaw-telegram-dev</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/openclaw-telegram-dev</guid>
    <pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate>
    <description>Telegram, cron, GitHub issues와 milestones를 묶어 OpenClaw를 원격 개발자처럼 운영하며 SLIME ARENA를 만든 경험을 정리했다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-milestones-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-issue-01.png"/><p>OpenClaw를 처음 붙였을 때 궁금했던 건 단순했다. 책상 앞에서 잠깐 명령을 던지는 도구가 아니라, 자리를 비운 뒤에도 계속 일하는 개발자처럼 굴릴 수 있을까? 그래서 이 실험을 위해 저사양 미니 PC를 하나 샀고, 권한도 전부 열어 둔 채 텔레그램만으로 지시를 내리는 루프를 만들었다.</p>
<p>처음에는 일정 관리나 잡무부터 맡겨 봤다. 그런데 조금 굴려 보니, 정말 보고 싶은 건 이런 쪽이 아니었다. 내가 궁금했던 건 <code>밖에서도 계속 개발이 굴러가는가</code>, 더 정확히는 <code>Telegram + OpenClaw + cron + GitHub issues/milestones</code> 조합으로 실제 프로젝트를 운영할 수 있는가였다.</p>
<p>내가 원한 건 원격 데스크톱으로 IDE를 여는 방식이 아니라, 최소한의 인터페이스로 다음 일을 밀어 넣고 결과를 받는 흐름이었다.</p>
<p>가장 제대로 굴린 사례는 Godot 기반 2D 액션 게임 <code>SLIME ARENA</code>였다.</p>
<h2>SLIME ARENA에서 어디까지 갔나</h2>
<p><code>SLIME ARENA</code>는 시작할 때 근거리와 원거리 두 타입 중 하나를 고르고, 웨이브를 버티며 레벨업할 때마다 스킬 트리를 찍는 구조다. 웨이브마다 몬스터를 다 잡으면 다음 단계로 넘어가고, 보스도 있다. 느낌으로는 2D 액션 디펜스와 뱀서라이크의 중간쯤에 있다.</p>
<p>지금은 리소스를 입히던 단계에서 멈춰 있다. 그래도 전투 루프 자체는 돌아간다. 난이도와 밸런스는 한동안 계속 만졌는데, 그 과정에서 오히려 일부가 틀어지기도 했다. 이 부분은 결국 사람이 다시 잡아야 하는 영역이라고 느꼈다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-01.png" alt="SLIME ARENA 오프닝 아키타입 선택 화면"/></p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-02.png" alt="SLIME ARENA 전투 루프 화면"/></p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-03.png" alt="SLIME ARENA 레벨업 선택 화면"/></p>
<h2>처음에는 마크다운, 나중에는 GitHub</h2>
<p>처음에는 2시간마다 마크다운 파일을 읽고 다음 작업을 진행하도록 시켰다. 그런데 이 방식은 내가 중간 상태를 파악하기가 너무 어려웠다. 어디까지 됐는지, 무엇이 막혔는지, 다음에 뭘 하려는지가 한눈에 안 들어왔다.</p>
<p>그래서 운영 방식을 바꿨다. OpenClaw용 GitHub 계정을 따로 만들고, 저장소에 개발자로 초대했다. 그다음부터는 milestone과 issues를 중심으로 루프를 굴렸다. OpenClaw가 먼저 마일스톤 목표를 세우고, 그 목표에 필요한 이슈를 만들고, 작업이 끝나면 닫고, 내가 테스트해 보다가 부족하면 다시 열어 내용을 보강시키는 식이다.</p>
<p>중요한 건 이 과정을 내가 IDE에서 직접 정리한 게 아니라 거의 전부 텔레그램으로 돌렸다는 점이다. 구현 지시, 수정 요청, 재오픈, 우선순위 변경까지 전부 텔레그램에서 했다. GitHub는 개발을 시키는 곳이라기보다 상태를 추적하고 검증 기준을 남기는 보드에 가까웠다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-milestones-01.png" alt="SLIME ARENA 운영에 사용한 GitHub milestone 보드"/></p>
<p>실제로 이슈 본문은 그냥 할 일 메모가 아니었다. <code>summary</code>, <code>scope</code>, <code>acceptance criteria</code>를 먼저 적게 했고, 작업이 끝난 뒤에는 어떤 커밋에서 처리했는지, 어떤 검증 명령을 돌렸는지, 재배포는 했는지까지 댓글로 남기게 했다. 마일스톤도 한두 개로 뭉뚱그리지 않고 Phase 단위로 계속 쌓였다. 내가 보고 싶었던 건 &quot;무언가 진행 중&quot;이라는 말이 아니라, 지금 어디까지 왔고 무엇이 검증됐는지였기 때문이다.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-issue-01.png" alt="SLIME ARENA 운영에 사용한 GitHub issue 예시"/></p>
<h2>실제 운영 루프는 이랬다</h2>
<p>실제 운영 방식은 대략 아래에 가까웠다.</p>
<ul>
<li>나는 텔레그램에서 방향과 우선순위만 정했다.</li>
<li>OpenClaw는 milestone을 만들고, 필요한 일을 issues로 잘게 쪼갰다.</li>
<li>issue에는 summary, scope, acceptance criteria, validation 같은 항목을 남기게 했다.</li>
<li>cron이 2시간마다 돌면서 다음 작업을 계속 진행했다.</li>
<li>완료된 이슈는 닫고, 내가 플레이하다가 부족하다고 느끼면 다시 열어 요구사항을 더 구체적으로 적게 했다.</li>
</ul>
<p>여기서 중요한 건 <code>시켰다</code>는 표현이다. 이 루프에서 나는 거의 디렉터와 QA 역할만 맡았고, 실제 구현은 OpenClaw가 끌고 갔다. 텔레그램 보고도 단순한 성공/실패 수준이 아니었다. 현재 phase, 이번 패스에서 처리한 issue 번호, 막힌 점, 검증 명령, 재배포 여부까지 요약해서 올리게 했다. 내가 확인해야 할 건 코드가 아니라 상태였다.</p>
<h2>어디서나 이어진다는 건 진짜였다</h2>
<p>가장 좋았던 점은 당연히 어디서나 이어진다는 것이다. 책상 앞에 없어도 개발이 멈추지 않는다. 텔레그램으로 방향만 남겨 두면, 다음 체크포인트가 돌 때 작업이 계속 진행된다.</p>
<p>이 방식은 나를 구현자보다 디렉터와 QA 역할로 밀어 넣었다. <code>SLIME ARENA</code>에서는 실제로 코드 한 줄도 보지 않았다. 나는 Godot를 모르고, 대신 플레이하면서 소감만 전했다. 그런데도 전투 루프, 웨이브, 보스, 레벨업 선택지까지 게임의 뼈대는 꽤 멀리 갔다.</p>
<p>또 하나 좋았던 점은 milestone과 issue를 쓰면서 판단 단위를 강제로 작게 만들 수 있었다는 점이다. 그냥 <code>게임 만들어</code>라고 두는 것보다, 지금 단계에서 무엇을 검증해야 하는지가 훨씬 분명해졌다. 실제로 전투 루프, 웨이브 진행, 보스전, 레벨업 선택지, 밸런스 조정 같은 작업을 각각 따로 굴릴 수 있었다. 이건 나중에 다시 보더라도 히스토리가 남는다는 점에서 단순 채팅 로그보다 훨씬 좋았다.</p>
<h2>그래도 문제는 있었다</h2>
<p>반대로 단점도 분명했다. 첫 번째는, 어디서나 개발할 수 있다는 점이 그대로 단점이 된다는 것이다. 운동하다 쉬는 시간에도 계속 들여다보게 된다. 열려 있다는 건 편하지만, 동시에 계속 신경 쓰게 만든다.</p>
<p>두 번째는 cron 루프를 안정적으로 돌리는 게 생각보다 쉽지 않았다는 점이다. 프롬프트를 잘못 짜면 다음 단계로 안 가고 진행 상황 보고만 계속하는 경우가 있었다. 결국 <code>무엇을 끝난 것으로 볼지</code>, <code>다음 단계는 어떻게 고를지</code>, <code>막혔을 때는 무엇을 fallback으로 삼을지</code>를 꽤 구체적으로 적어 줘야 했다.</p>
<p>세 번째는 검토 부채다. 코드 자체를 안 보고 일이 진행되면 나중에 확인해야 하는 것이 한꺼번에 몰려온다. <code>SLIME ARENA</code>는 내가 코드 한 줄 안 봤기 때문에 더 그랬다. AI를 완전히 믿을 수 있다면 큰 문제는 아닐 수도 있지만, 지금 단계에서는 마지막에 사람이 떠안는 검토량이 꽤 크다.</p>
<p>마지막으로 비용과 사용량 문제도 있다. 나는 이 실험을 하려고 권한을 전부 열어 둔 미니 PC까지 샀다. 그런데 이렇게 굴리면 사용량을 정말 빠르게 먹는다. 실제로 GPT Pro 주간 사용량까지 다 채워 버려서, 원래 더 중요하게 해야 하는 작업을 못 하게 됐다. 그래서 2026년 3월 15일 기준으로는 일단 멈춘 상태다.</p>
<h2>다음 실험은 왜 WebGL voxel game인가</h2>
<p><code>SLIME ARENA</code> 이후에는 three.js 기반 WebGL voxel game도 조금 진행했다. 흔히 떠올리는 마인크래프트류 구조를 따라가되, 나는 엔진 쪽과 게임 쪽을 최대한 분리해 두는 걸 중요하게 봤다. 엔진 부분은 다음 프로젝트에도 다시 쓸 수 있기 때문이다.</p>
<p>요즘은 AI 쪽 흐름이 전체적으로 웹 친화적이라고 느낀다. 그래서 앞으로 Web 기반 게임과 Web 게임 엔진 쪽이 더 많이 커질 거라고 보고 있다. AAA 게임이 몰락한다는 뜻은 아니고, 위아래로 양극화가 더 심해질 거라는 쪽에 가깝다. 이 생각은 아직 가설에 가깝지만, 다음 실험을 WebGL로 잡은 이유는 분명히 거기 있었다.</p>
<h2>장난감은 아니었다</h2>
<p>OpenClaw를 텔레그램에 붙여 굴려 보니, 이건 <code>밖에서도 잠깐 명령 내리는 보조 도구</code>라기보다 <code>원격 개발자 하나를 운영하는 방식</code>에 더 가까웠다. 제대로 굴리려면 milestone, issue, cron, 검증 기준까지 같이 설계해야 한다. 그걸 잡아 두면 생각보다 멀리 간다.</p>
<p>다만 그만큼 관리 포인트도 분명하다. 사용량, 검토 부채, 끊임없이 신경 쓰게 되는 운영 피로까지 같이 감안해야 한다. 지금 내 결론은 단순하다. OpenClaw는 재미있는 장난감이 아니었다. 대신 제어 없이 돌리면 금방 감당 안 되는 쪽으로 커지는 도구였다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Running Game Dev from Telegram: Operating SLIME ARENA with OpenClaw</title>
    <link>https://kinkeep.dev/posts/agentic/openclaw-telegram-dev-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/openclaw-telegram-dev-en</guid>
    <pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate>
    <description>Telegram, cron, GitHub issues and milestones wired together to run OpenClaw like a remote developer. A record of operating SLIME ARENA.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-milestones-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-issue-01.png"/><p>First question was simple. Not quick commands at my desk — could OpenClaw keep working after I leave? Bought a low-spec mini PC, opened all permissions, built a loop where instructions come through Telegram only.</p>
<p>Started with scheduling and errands. Quickly realized that wasn&#x27;t the point. Real question: does development keep rolling when I&#x27;m away? Can <code>Telegram + OpenClaw + cron + GitHub issues/milestones</code> operate a real project?</p>
<p>No remote desktop. Minimal interface — push the next task, get results back.</p>
<p>The best-run case was SLIME ARENA, a Godot-based 2D action game.</p>
<h2>How far SLIME ARENA went</h2>
<p>SLIME ARENA: pick melee or ranged at the start, survive waves, choose skills on each level-up. Clear all monsters per wave to advance. Bosses included. Somewhere between 2D action defense and Vampire Survivors.</p>
<p>Currently paused at the asset integration stage. The combat loop runs. Difficulty and balance got tweaked repeatedly — and some of it broke in the process. That part needs a human hand.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-01.png" alt="SLIME ARENA archetype selection"/></p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-02.png" alt="SLIME ARENA combat loop"/></p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-03.png" alt="SLIME ARENA level-up selection"/></p>
<h2>Started with markdown, moved to GitHub</h2>
<p>Initially, a markdown file checked every two hours for the next task. Problem: I couldn&#x27;t see intermediate state. Where things stood, what was stuck, what was planned next — none of it was visible at a glance.</p>
<p>Changed the approach. Created a dedicated GitHub account for OpenClaw, invited it as a developer on the repo. From there, milestones and issues drove the loop. OpenClaw sets milestone goals, creates issues for needed work, closes them on completion. I playtest, reopen issues with more specific requirements if something falls short.</p>
<p>Key point: almost all of this ran through Telegram. Implementation orders, revision requests, reopens, priority changes — all via Telegram. GitHub served less as a place to direct development and more as a board for tracking state and recording acceptance criteria.</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-milestones-01.png" alt="GitHub milestone board"/></p>
<p>Issue bodies weren&#x27;t just to-do notes. Each had summary, scope, and acceptance criteria upfront. After completion, comments recorded which commits handled it, what validation ran, whether redeployment happened. Milestones stacked by phase rather than clumping into one or two. What I needed wasn&#x27;t &quot;something is in progress&quot; but &quot;what&#x27;s verified and what isn&#x27;t.&quot;</p>
<p><img src="https://kinkeep.dev/posts-images/agentic/img/slime-arena-github-issue-01.png" alt="GitHub issue example"/></p>
<h2>The actual operating loop</h2>
<p>Roughly:</p>
<ul>
<li>I set direction and priorities from Telegram.</li>
<li>OpenClaw created milestones and split work into issues.</li>
<li>Issues carried summary, scope, acceptance criteria, validation.</li>
<li>Cron ran every two hours, pushing to the next task.</li>
<li>Completed issues closed. When I playtested and found gaps, I reopened with more specific requirements.</li>
</ul>
<p>I acted almost entirely as director and QA. OpenClaw drove implementation. Telegram reports weren&#x27;t just pass/fail — current phase, issues handled this pass, blockers, validation commands, redeployment status. What I checked wasn&#x27;t code. It was state.</p>
<h2>Continuity from anywhere was real</h2>
<p>Best part: development didn&#x27;t stop when I left my desk. Leave a direction in Telegram, and work continues at the next checkpoint.</p>
<p>This pushed me into a director-and-QA role. In SLIME ARENA I never looked at code. I don&#x27;t know Godot. I playtested and shared impressions. Yet the combat loop, waves, bosses, and level-up choices — the game&#x27;s skeleton — went surprisingly far.</p>
<p>Milestones and issues also forced small judgment units. Instead of &quot;make a game,&quot; the question was always what to verify at this stage. Combat loop, wave progression, boss fights, level-up choices, balance tuning — each ran as a separate workstream. Unlike chat logs, the history stays navigable later.</p>
<h2>Problems were real too</h2>
<p>Downsides were clear. First, anywhere-access cuts both ways. I found myself checking during gym breaks. Open means convenient; open also means constant attention.</p>
<p>Second, keeping the cron loop stable was harder than expected. A bad prompt could leave it reporting status instead of advancing. I had to be specific about what counts as done, how to pick the next step, what to fall back to when stuck.</p>
<p>Third, review debt. When code advances without me reading it, deferred review piles up. SLIME ARENA was extreme — I read zero lines. If you could fully trust the AI, maybe that&#x27;s fine. At this stage, the review load that lands on the human at the end is substantial.</p>
<p>Finally, cost and usage. I bought a dedicated mini PC with full permissions for this experiment. Running it this way burns through usage fast. I hit the full GPT Pro weekly quota and couldn&#x27;t touch work that mattered more. As of March 15, 2026, the experiment is paused.</p>
<h2>Why the next experiment is a WebGL voxel game</h2>
<p>After SLIME ARENA, I started a three.js WebGL voxel game. Following the Minecraft-style structure, but keeping engine and game layers sharply separated — the engine part should be reusable for the next project.</p>
<p>AI tooling trends feel web-native lately. I expect web-based games and web game engines to grow. Not that AAA will collapse — more like polarization intensifies at both ends. Still a hypothesis, but that&#x27;s why I chose WebGL next.</p>
<h2>It wasn&#x27;t a toy</h2>
<p>OpenClaw through Telegram was closer to operating a remote developer than a quick off-desk tool. Proper operation means designing milestones, issues, cron rules, and acceptance criteria together. Get that right and it goes far.</p>
<p>Management overhead is real. Usage, review debt, constant operational attention — all part of the package. OpenClaw wasn&#x27;t a toy. Without governance, it quickly outgrows what you can handle.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 7 - Lua 전환과 클래스 트리 정리</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-7</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-7</guid>
    <pubDate>Sat, 07 Mar 2026 00:00:00 GMT</pubDate>
    <description>Graph 자산을 걷어내고 Lua/코드 기반 데이터 구조로 되돌린 뒤 클래스 트리와 UI까지 정리한 회차.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-06.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-07.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-08.png"/><p>이번엔 기존 Graph 자산 구조를 접고 텍스트 기반 데이터로 되돌리는 큰 방향 전환이 있었다. 여기에 클래스 트리, 타이틀, 정비 UI 정리까지 한 번에 몰아서 했다.</p>
<h2>데이터 구조 변경</h2>
<p>Epoch: Unseen Devlog 3에서는 전투 공식을 Graph 형식 데이터로, Epoch: Unseen Devlog 4에서는 전투 시나리오 스크립트를 Graph 형식으로 가기로 했었다. 그런데 Graph Asset은 AI 친화적인 포맷이 아니었다. AI가 직접 편집하기가 사실상 불가능하고, 결국 사람이 손으로 만져야 했다.</p>
<p>돌아보면 잘못된 결정이었고, 시행착오였다.</p>
<p>전투 공식은 다시 코드 기반으로, 시나리오 스크립트는 Lua 기반으로 되돌렸다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-01.png" alt="Devlog - 7 image 1"/></p>
<p>Lua 스크립트로 작성한 스토리 스크립트(R 씬)</p>
<p>내가 원하는 구조는 결국 텍스트 기반이라 AI와 사람이 같이 관리하기 쉽고, 패치도 편한 형태였다. Lua가 지금은 그 목적에 가장 잘 맞는다.</p>
<h2>클래스 트리 결정</h2>
<table><thead><tr><th>검병<br/>├─ 결투가<br/>│ ├─ 검무사<br/>│ └─ 처형자<br/>└─ 검사<br/>├─ 검성<br/>└─ 칼바람</th><th>창병<br/>├─ 파쇄병<br/>│ ├─ 파괴자<br/>│ ├─ 파갑병<br/>└─ 창술사<br/>├─ 용기병<br/>└─ 창신</th><th>방패병<br/>├─ 방벽병<br/>│ ├─ 요새병<br/>│ └─ 수호자<br/>└─ 철갑병<br/>├─ 거순병<br/>└─ 방진병</th></tr></thead><tbody><tr><td>궁병<br/>├─ 저격수<br/>│ ├─ 추적자<br/>│ └─ 매의눈<br/>└─ 궁사<br/>├─ 사수<br/>└─ 궁신</td><td>마법사<br/>├─ 원소술사<br/>│ ├─ 마녀<br/>│ └─ 현자<br/>└─ 주술사<br/>├─ 사술사<br/>├─ 각인술사<br/>└─ 비전술사</td><td>사제<br/>├─ 심문관<br/>│ ├─ 집행관<br/>│ └─ 참회자<br/>└─ 구원자<br/>├─ 성녀<br/>└─ 순교자</td></tr></tbody></table>
<video src="/posts-images/project-t/img/devlog-7-02.mp4" controls="" loop="" muted="" playsInline=""></video>
<p>특수 병종을 빼고 기본 클래스 트리는 6종으로 정했다.</p>
<p>유닛 스프라이트도 SPUM 안에서 내 취향에 조금 더 가까운 쪽으로 교체했다. 아직은 잡병 모션만 임시로 뽑아 둔 상태라, 진영색 표현은 추가 작업이 더 필요하다. 당분간은 이 상태로 쓸 생각이다.</p>
<p>문제는 말을 탄 일반 기병 모습을 넣기 어렵다는 점이다. 그래서 독립된 기병 계열은 이번 클래스 트리에서 일단 제외했다. 그래도 시간이 나면 한번은 시도해 볼 생각이다.</p>
<h2>타이틀, 정비 페이즈 작업</h2>
<p>슬슬 게임다운 구색은 갖춰 가고 있다. 아직 한 사이클 전투 플레이까지는 못 갔지만.</p>
<p>UI는 정말 어렵다. 일단은 적당한 색 팔레트를 골라 먹이고 있는데, 아직 좀 허술해 보인다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-03.png" alt="Devlog - 7 image 3"/></p>
<p>Gemini 흔적이 너무 노골적으로 남는다. 나중에 마크 제거 툴로 한번 정리해야겠다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-04.png" alt="Devlog - 7 image 4"/></p>
<p>임시로 만든 스토리 씬이다. 원래는 사각형 그리드가 보이면 안 된다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-05.png" alt="Devlog - 7 image 5"/></p>
<p>출진 전 정비 씬이다. 이걸 필드 탐색형으로 갈지, 메뉴 중심으로 갈지는 아직 고민 중이다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-06.png" alt="Devlog - 7 image 6"/></p>
<p>이 UI가 제일 골칫거리였는데, 어느 정도 깔끔하게 정리되고 나니 이제는 좀 만족스럽다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-07.png" alt="Devlog - 7 image 7"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-08.png" alt="Devlog - 7 image 8"/></p>
<h2>알파1 빌드 분량 결정</h2>
<p>챕터 1 스토리는 일단 러프로 잡아 뒀다. 러프하다는 건 앞으로 개발하면서 계속 퇴고하고 바뀔 수 있다는 뜻이다. 결국 한 번에 잘 만드는 것보다 조금씩 진도를 빼면서 다듬는 쪽이 결과가 좋다.</p>
<p>알파1 빌드는 챕터 1 중반부까지로 잡았다.</p>
<p>그럼 알파1 빌드가 나오면 뭘 하느냐?</p>
<p><code>아무 것도 없다.</code> 그냥 나 혼자 정해 둔 마감선이자 목표다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 7 - Lua Migration and Class Tree</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-7-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-7-en</guid>
    <pubDate>Sat, 07 Mar 2026 00:00:00 GMT</pubDate>
    <description>Dropped Graph assets, reverted to Lua/code-based data structures, finalized the class tree, and cleaned up UI.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-06.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-07.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-7-08.png"/><p>Major direction change: dropped Graph asset structure, reverted to text-based data. Also finalized the class tree, title screen, and maintenance UI in one push.</p>
<h2>Data Structure Change</h2>
<p>Devlog 3 chose Graph format for battle formulas. Devlog 4 chose Graph for scenario scripts. Turns out Graph Assets aren&#x27;t AI-friendly. AI can&#x27;t edit them directly — humans have to do it by hand.</p>
<p>In hindsight, a wrong call. Trial and error.</p>
<p>Battle formulas went back to code. Scenario scripts switched to Lua.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-01.png" alt="Devlog - 7 image 1"/></p>
<p>Story script (R scene) written in Lua.</p>
<p>What I wanted was text-based: easy for both AI and humans to manage, easy to patch. Lua fits that purpose best right now.</p>
<h2>Class Tree</h2>
<table><thead><tr><th>Swordsman<br/>├─ Duelist<br/>│ ├─ Blade Dancer<br/>│ └─ Executioner<br/>└─ Saber<br/>├─ Sword Saint<br/>└─ Gale Blade</th><th>Lancer<br/>├─ Crusher<br/>│ ├─ Destroyer<br/>│ ├─ Armor Breaker<br/>└─ Spearmaster<br/>├─ Dragoon<br/>└─ Spear Saint</th><th>Shieldbearer<br/>├─ Bulwark<br/>│ ├─ Fortress<br/>│ └─ Guardian<br/>└─ Ironclad<br/>├─ Pavise<br/>└─ Phalanx</th></tr></thead><tbody><tr><td>Archer<br/>├─ Sniper<br/>│ ├─ Tracker<br/>│ └─ Hawk Eye<br/>└─ Bowman<br/>├─ Marksman<br/>└─ Bow Saint</td><td>Mage<br/>├─ Elementalist<br/>│ ├─ Witch<br/>│ └─ Sage<br/>└─ Hexer<br/>├─ Necromancer<br/>├─ Inscriber<br/>└─ Arcanist</td><td>Cleric<br/>├─ Inquisitor<br/>│ ├─ Enforcer<br/>│ └─ Penitent<br/>└─ Savior<br/>├─ Saint<br/>└─ Martyr</td></tr></tbody></table>
<video src="/posts-images/project-t/img/devlog-7-02.mp4" controls="" loop="" muted="" playsInline=""></video>
<p>Six base class trees, excluding special classes.</p>
<p>Swapped unit sprites within SPUM to something closer to my taste. Only placeholder mob animations for now — faction colors need more work. Using this as-is for a while.</p>
<p>Problem: mounted cavalry is hard to represent. Dropped the independent cavalry branch from this tree. Might attempt it later if time allows.</p>
<h2>Title and Maintenance Phase</h2>
<p>Starting to look like a game. Haven&#x27;t reached a full combat playthrough cycle yet.</p>
<p>UI is genuinely hard. Picked a color palette and applied it, but it still looks rough.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-03.png" alt="Devlog - 7 image 3"/></p>
<p>Gemini artifacts are too visible. Need to clean those up with a watermark removal tool later.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-04.png" alt="Devlog - 7 image 4"/></p>
<p>Placeholder story scene. The square grid shouldn&#x27;t be visible.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-05.png" alt="Devlog - 7 image 5"/></p>
<p>Pre-sortie maintenance scene. Still deciding between field exploration and menu-driven approach.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-06.png" alt="Devlog - 7 image 6"/></p>
<p>This UI was the biggest headache. Got it cleaned up enough to feel satisfied.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-07.png" alt="Devlog - 7 image 7"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-7-08.png" alt="Devlog - 7 image 8"/></p>
<h2>Alpha 1 Build Scope</h2>
<p>Chapter 1 story is in rough draft. Rough means it&#x27;ll keep changing through development. Incremental progress and revision beats trying to get it right in one shot.</p>
<p>Alpha 1 covers through mid-Chapter 1.</p>
<p>What happens when Alpha 1 ships?</p>
<p>Nothing. It&#x27;s a self-imposed deadline and a goal.</p>]]></content:encoded>
  </item>
  <item>
    <title>Character Forge: ComfyUI 기반 캐릭터 일러스트 생성기</title>
    <link>https://kinkeep.dev/posts/agentic/character-forge</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/character-forge</guid>
    <pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate>
    <description>Epoch: Unseen 초상화 작업을 위해 태그 기반 입력 체계와 로컬 ComfyUI 파이프라인을 묶어 둔 기록.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-04.png"/><link rel="preload" as="image" href="/posts-images/project-t/img/devlog-6-05.png"/><link rel="preload" as="image" href="/posts-images/project-t/img/devlog-6-06.png"/><link rel="preload" as="image" href="/posts-images/agentic/img/erich-01-initial.png"/><link rel="preload" as="image" href="/posts-images/agentic/img/erich-02-middle.png"/><link rel="preload" as="image" href="/posts-images/agentic/img/erich-03-current.png"/><h2>만든 이유</h2>
<p>Epoch: Unseen용 캐릭터 초상화를 만들다 보니, 먼저 막히는 건 이미지 생성 성능이 아니라 프롬프트 관리였다. 프롬프트를 매번 손으로 만지면 결과가 쉽게 흔들렸고, 어떤 조합이 괜찮았는지 다시 찾는 것도 번거로웠다.</p>
<p>그래서 ComfyUI를 그대로 쓰기보다, 캐릭터 초상화용 입력 체계를 한 겹 감싼 <code>Character Forge</code>를 만들었다. 목표는 더 영리한 프롬프트 한 줄을 찾는 게 아니라, 비슷한 조건에서 여러 시도를 빠르게 반복할 수 있는 흐름을 만드는 것이었다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-01.png" alt="Character Forge 메인 화면"/></p>
<h2>실제 사용 흐름</h2>
<p>실제로는 대개 이런 흐름으로 쓴다.</p>
<ul>
<li>캐릭터 설정과 외형 방향을 먼저 잡는다.</li>
<li>태그를 골라 한 번에 4장씩 생성한다.</li>
<li>마음에 드는 결과가 나올 때까지 5~6번 정도 반복한다.</li>
<li>후보 일러스트는 즐겨찾기에 모은다.</li>
<li>최종적으로 고른 이미지를 Epoch: Unseen 초상화에 반영한다.</li>
</ul>
<p>아직은 세세한 편집보다 <code>tex2img</code>로 후보를 빠르게 많이 보는 쪽에 더 가깝다. <code>img2img</code>도 만들고 테스트는 해뒀지만, 지금 단계에서는 아직 자주 쓰지 않는다.</p>
<h2>태그를 어떻게 프롬프트로 바꾸는가</h2>
<p>입력 태그는 캐릭터를 만드는 재료처럼 역할별로 나뉘어 있다. 성별, 나이, 직업, 종족처럼 기본 설정을 잡는 태그가 있고, 외형, 특징, 의상, 성격, 모에처럼 캐릭터의 개성을 만드는 태그가 따로 있다. 배경이나 조명 옵션도 있지만, 지금은 초상화 위주라 거의 흰 배경만 쓴다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-02.png" alt="Character Forge 속성 화면"/></p>
<p>핵심은 이걸 바로 프롬프트 문자열로 이어 붙이지 않는다는 점이다. 실제 흐름은 <code>태그 조합 -&gt; 카테고리별 해석 -&gt; 최종 템플릿 적용</code>에 더 가깝다.</p>
<ul>
<li>UI에서 고른 태그를 카테고리별 고정 순서의 해시태그 문자열로 만든다.</li>
<li>서버에서 그 해시태그를 <code>gender</code>, <code>personality</code>, <code>appearance</code>, <code>outfit</code> 같은 버킷으로 다시 나눈다.</li>
<li>필수 카테고리가 빠지면 생성 자체를 막는다.</li>
<li>각 태그를 영어 프롬프트 조각으로 바꾼 뒤 최종 템플릿에 넣는다.</li>
</ul>
<p>태그마다 복잡한 가중치를 따로 붙이는 구조라기보다, 태그를 한 번 정리된 필드로 바꾼 뒤 마지막 템플릿 단계에서 필요한 규칙만 얹는 방식에 가깝다. 예를 들어 의상은 더 강조하고, 특정 작업 종류에서는 배경이나 카메라 태그를 아예 버린다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-03.png" alt="Character Forge 프롬프트 화면"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-04.png" alt="Character Forge 세부 설정 화면"/></p>
<p>짧게 요약하면 파이프라인은 아래 정도다.</p>
<pre><code class="language-mermaid">flowchart TD
    A[태그 선택] --&gt; B[해시태그 문자열 생성]
    B --&gt; C[태그 해석과 매핑]
    C --&gt; D[프롬프트 필드 구성]
    D --&gt; E[최종 Prompt 템플릿 적용]
    E --&gt; F[워크플로 JSON 생성]
    F --&gt; G[ComfyUI API 실행]
    G --&gt; H[이미지 저장과 히스토리 반영]
</code></pre>
<h2>ComfyUI는 어떻게 붙였나</h2>
<p>폴더를 감시하면서 돌리는 식은 쓰지 않았다. 로컬 ComfyUI의 HTTP/WebSocket API를 직접 호출하는 구조다.</p>
<ul>
<li>Python이 <code>POST /prompt</code>로 워크플로를 넣는다.</li>
<li><code>GET /history/{prompt_id}</code>로 완료 여부를 본다.</li>
<li>가능하면 WebSocket으로 step progress도 받는다.</li>
<li>완료되면 <code>/view</code>로 결과 이미지를 가져온다.</li>
</ul>
<p>실제 생성용 워크플로는 코드에서 JSON으로 만들고, 마지막 positive/negative prompt도 Python 쪽 템플릿에서 조립한다. 그래서 UI에서 태그를 고르고 나면, 그다음부터는 초상화 생성용 파이프라인이 비교적 일정한 형태로 돈다.</p>
<div class="grid gap-4 sm:grid-cols-2"><img src="/posts-images/project-t/img/devlog-6-05.png" alt="태그에서 프롬프트로 변환하는 화면" class="h-[360px] w-full object-contain"/><img src="/posts-images/project-t/img/devlog-6-06.png" alt="생성 결과 예시" class="h-[360px] w-full object-contain"/></div>
<h2>뭐가 좋아졌나</h2>
<p>가장 만족스러운 건 일관성이 좋아졌다는 점이다. 프롬프트를 매번 처음부터 고민하는 대신, 제한된 태그 안에서 빠르게 여러 시도를 돌릴 수 있게 되면서 전체 작업 속도도 함께 올라갔다. 선택지를 줄인 덕분에 오히려 반복은 쉬워졌고, 버튼 몇 번 누르는 정도로 다시 시도할 수 있다는 점이 생각보다 컸다.</p>
<p>로컬 DB에 히스토리를 저장해 두는 것도 실제로 유용했다. 태그와 프롬프트가 같이 남고, 버튼 한 번으로 같은 조건을 다시 돌릴 수 있다. 즐겨찾기 기능도 마음에 드는 결과와 아닌 결과를 나누는 데 꽤 도움이 됐다. 결국 이미지를 많이 뽑는 것보다 <code>괜찮았던 시도</code>를 다시 찾을 수 있는 쪽이 더 중요했다.</p>
<p>지금은 맥 미니 64GB에서 SDXL과 ComfyUI를 돌리고 있고, 한 장에 대략 1~2분 정도 걸린다. 초상화 용도로는 감당 가능한 수준이다.</p>
<h2>결과가 설정을 바꾸는 순간도 있었다</h2>
<p>이 파이프라인을 쓰면서 재미있었던 건, 설정이 이미지를 끌고 가는 경우만 있는 게 아니라 이미지가 설정을 다시 끌고 오기도 했다는 점이다.</p>
<p>예를 들어 주인공 에리히는 처음에는 결벽증 있는 군인, 조금 더 현실적이고 날카로운 인상으로 잡혀 있었다. 그런데 실제로 여러 장을 뽑아 보니 내가 고르게 되는 쪽은 점점 JRPG 주인공에 가까운 톤이었다. 갑옷 형태나 색 대비, 얼굴 인상, 전체 실루엣이 그 방향으로 정리되기 시작했고, 결국 지금 버전의 에리히는 처음 머릿속에 있던 이미지보다 훨씬 만화적이고 정제된 쪽으로 바뀌었다.</p>
<p>아래 세 장만 봐도 그 변화가 꽤 또렷하다. 1차에서는 현실적인 군인 인상이 강했고, 2차에서는 스타일이 한 번 만화적으로 튀었고, 지금 버전에서는 그중 쓸 만한 요소만 남기면서 훨씬 정리된 얼굴과 의상 톤으로 굳어졌다.</p>
<div class="not-prose my-6 grid gap-4 md:grid-cols-3"><figure><img src="/posts-images/agentic/img/erich-01-initial.png" alt="에리히 1차 일러스트" class="h-[320px] w-full rounded-xl object-contain"/><figcaption class="mt-3 text-center text-sm" style="color:var(--text-secondary)"><p>1차: 현실적인 군인 톤</p></figcaption></figure><figure><img src="/posts-images/agentic/img/erich-02-middle.png" alt="에리히 2차 일러스트" class="h-[320px] w-full rounded-xl object-contain"/><figcaption class="mt-3 text-center text-sm" style="color:var(--text-secondary)"><p>2차: JRPG 톤이 강해진 중간안</p></figcaption></figure><figure><img src="/posts-images/agentic/img/erich-03-current.png" alt="에리히 현재 일러스트" class="h-[320px] w-full rounded-xl object-contain"/><figcaption class="mt-3 text-center text-sm" style="color:var(--text-secondary)"><p>현재: 정리된 최종 방향</p></figcaption></figure></div>
<p>이런 변화는 자유 입력 프롬프트만으로 작업할 때보다 태그 기반 시스템에서 더 빨리 보였다. 조건을 조금씩 바꿔 가며 여러 후보를 연속으로 비교할 수 있으니, 머릿속 설정과 실제로 화면에서 잘 살아나는 설정의 차이가 더 빨리 드러났기 때문이다.</p>
<h2>아직 남은 한계</h2>
<p>물론 아직 완전히 통제되지는 않는다. 흰 배경으로 설정해도 가끔 배경이 딸려 나오는 경우가 있다. 지금은 그냥 다시 돌린다. 초상화만 만들 때는 이 정도로도 버틸 만하지만, 배경이나 이벤트 일러스트까지 넓히면 이야기가 달라질 수 있다.</p>
<p>또 아직은 초상화 파이프라인에서만 검증된 도구라는 점도 한계다. 지금까지는 이 범위 안에서 꽤 만족스럽지만, 더 복잡한 장면에서 일러스트 일관성을 어떻게 유지할지는 아직 본격적으로 부딪혀 보지 않았다. 그 단계에서는 NanoBanana처럼 다른 강점을 가진 도구와 같이 써야 할 수도 있다.</p>
<h2>결국 프롬프트가 아니라 입력 체계의 문제였다</h2>
<p>좋은 프롬프트 한 줄을 찾는 게 중요한 줄 알았는데, 만들면서 느낀 건 반복 가능한 입력 체계를 만드는 쪽이 더 컸다. 직접 문장을 길게 쓰는 방식은 자유롭지만, 그만큼 결과를 다시 관리하기가 어렵다. 반대로 태그로 선택지를 제한하면 한 번의 시도는 덜 자유롭지만, 여러 번 반복하기는 훨씬 쉬워진다.</p>
<p>지금 Character Forge는 적어도 그 반복을 쉽게 만드는 쪽에서는 꽤 만족스럽다. <code>프롬프트 작성</code>을 <code>입력 시스템</code>으로 바꾼 것만으로도 작업 감각이 제법 달라졌다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Character Forge: Tag-Based Character Portrait Generator on ComfyUI</title>
    <link>https://kinkeep.dev/posts/agentic/character-forge-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/agentic/character-forge-en</guid>
    <pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate>
    <description>Built a tag-based input system on top of a local ComfyUI pipeline for Epoch: Unseen character portraits.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-6-04.png"/><link rel="preload" as="image" href="/posts-images/project-t/img/devlog-6-05.png"/><link rel="preload" as="image" href="/posts-images/project-t/img/devlog-6-06.png"/><link rel="preload" as="image" href="/posts-images/agentic/img/erich-01-initial.png"/><link rel="preload" as="image" href="/posts-images/agentic/img/erich-02-middle.png"/><link rel="preload" as="image" href="/posts-images/agentic/img/erich-03-current.png"/><h2>Why I built it</h2>
<p>Making Epoch: Unseen portraits, the bottleneck wasn&#x27;t generation quality — it was prompt management. Hand-editing prompts made results unstable. Finding which combination worked before was tedious.</p>
<p>Instead of using ComfyUI raw, I wrapped it with a portrait-specific input layer: Character Forge. Not searching for one clever prompt. Building a flow for rapid iteration under similar conditions.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-01.png" alt="Character Forge main screen"/></p>
<h2>Actual usage flow</h2>
<p>Typical workflow:</p>
<ul>
<li>Set character concept and visual direction.</li>
<li>Pick tags, generate 4 images at once.</li>
<li>Repeat 5–6 rounds until something clicks.</li>
<li>Favorite the promising results.</li>
<li>Apply the final pick as an Epoch: Unseen portrait.</li>
</ul>
<p>Still closer to rapid <code>txt2img</code> candidate screening than fine editing. <code>img2img</code> is built and tested but not used much at this stage.</p>
<h2>How tags become prompts</h2>
<p>Input tags are split by role, like ingredients for building a character. Base settings — gender, age, class, race. Character traits — appearance, features, outfit, personality, moe. Background and lighting exist but portraits mostly use white backgrounds.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-02.png" alt="Character Forge attribute screen"/></p>
<p>Key point: tags don&#x27;t concatenate straight into a prompt string. The actual flow is <code>tag combination → per-category interpretation → final template application</code>.</p>
<ul>
<li>Selected tags become a category-ordered hashtag string in the UI.</li>
<li>Server splits hashtags into buckets: gender, personality, appearance, outfit.</li>
<li>Missing required categories block generation.</li>
<li>Each tag maps to an English prompt fragment, assembled into the final template.</li>
</ul>
<p>Not a complex per-tag weighting system. Tags get normalized into clean fields first, then the template stage applies lightweight rules. Outfit gets emphasized, certain task types drop background or camera tags entirely.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-03.png" alt="Character Forge prompt screen"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-6-04.png" alt="Character Forge detail settings"/></p>
<p>Pipeline summary:</p>
<pre><code class="language-mermaid">flowchart TD
    A[Tag Selection] --&gt; B[Hashtag String]
    B --&gt; C[Tag Parsing &amp; Mapping]
    C --&gt; D[Prompt Field Assembly]
    D --&gt; E[Final Prompt Template]
    E --&gt; F[Workflow JSON Generation]
    F --&gt; G[ComfyUI API Execution]
    G --&gt; H[Image Save &amp; History Update]
</code></pre>
<h2>How ComfyUI connects</h2>
<p>No folder-watching. Direct HTTP/WebSocket calls to local ComfyUI.</p>
<ul>
<li>Python sends <code>POST /prompt</code> with the workflow.</li>
<li><code>GET /history/{prompt_id}</code> checks completion.</li>
<li>WebSocket receives step progress when available.</li>
<li>On completion, <code>/view</code> fetches the result image.</li>
</ul>
<p>The generation workflow is built as JSON in code. Final positive/negative prompts are assembled from Python-side templates. After tag selection in the UI, the portrait pipeline runs in a fairly consistent shape.</p>
<div class="grid gap-4 sm:grid-cols-2"><img src="/posts-images/project-t/img/devlog-6-05.png" alt="Tag-to-prompt conversion screen" class="h-[360px] w-full object-contain"/><img src="/posts-images/project-t/img/devlog-6-06.png" alt="Generation result example" class="h-[360px] w-full object-contain"/></div>
<h2>What improved</h2>
<p>Consistency improved most. Instead of agonizing over prompts from scratch, I run many attempts quickly within constrained tags. Fewer choices made repetition easier. A few button presses to retry — that mattered more than expected.</p>
<p>Local DB history storage proved useful too. Tags and prompts are saved together; one button replays the same conditions. Favorites helped separate good results from noise. Finding &quot;what worked before&quot; turned out more important than generating volume.</p>
<p>Currently running SDXL on a Mac Mini 64GB with ComfyUI. About 1–2 minutes per image. Manageable for portraits.</p>
<h2>Results reshaped the design</h2>
<p>An interesting pattern: the design didn&#x27;t always drive the image. Sometimes the image pulled the design back.</p>
<p>Erich, the protagonist, started as a neat-freak soldier — realistic, sharp, grounded. But across many generations, the ones I kept picking drifted toward a JRPG protagonist tone. Armor shape, color contrast, face, overall silhouette all shifted that direction. The current Erich is far more stylized and polished than the original mental image.</p>
<div class="not-prose my-6 grid gap-4 md:grid-cols-3"><figure><img src="/posts-images/agentic/img/erich-01-initial.png" alt="Erich first iteration" class="h-[320px] w-full rounded-xl object-contain"/><figcaption class="mt-3 text-center text-sm" style="color:var(--text-secondary)"><p>1st: Realistic soldier tone</p></figcaption></figure><figure><img src="/posts-images/agentic/img/erich-02-middle.png" alt="Erich second iteration" class="h-[320px] w-full rounded-xl object-contain"/><figcaption class="mt-3 text-center text-sm" style="color:var(--text-secondary)"><p>2nd: JRPG tone emerges</p></figcaption></figure><figure><img src="/posts-images/agentic/img/erich-03-current.png" alt="Erich current version" class="h-[320px] w-full rounded-xl object-contain"/><figcaption class="mt-3 text-center text-sm" style="color:var(--text-secondary)"><p>Current: Refined final direction</p></figcaption></figure></div>
<p>This shift showed up faster in the tag-based system than in free-form prompting. Tweaking conditions incrementally and comparing candidates in sequence reveals the gap between your mental image and what actually works on screen.</p>
<h2>Remaining limits</h2>
<p>Control isn&#x27;t complete. White background setting sometimes leaks background elements. For now I just rerun. Manageable for portraits, but extending to scene or event illustrations changes the equation.</p>
<p>Also, Character Forge is only validated for the portrait pipeline. Maintaining illustration consistency across more complex scenes hasn&#x27;t been tested seriously. That stage might need tools with different strengths, like NanoBanana.</p>
<h2>It was an input system problem, not a prompt problem</h2>
<p>Thought one good prompt was the key. Building this taught otherwise: a repeatable input system matters more. Free-form prompting is flexible but hard to manage across iterations. Tag-constrained input trades freedom per attempt for easy repetition.</p>
<p>Character Forge delivers on repeatability. Turning &quot;prompt writing&quot; into an &quot;input system&quot; changed the working feel more than expected.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 6 - 세계관과 프로젝트 이름 확정</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-6</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-6</guid>
    <pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate>
    <description>중세 판타지 방향과 Epoch: Unseen이라는 이름을 정해 둔 짧은 체크포인트.</description>
    <content:encoded><![CDATA[<p>이번엔 시스템보다 방향을 정하는 쪽이 중요했다. 세계관을 중세 판타지로 굳히고, 이후 devlog와 문서에서 계속 쓰게 될 이름을 <code>Epoch: Unseen</code>으로 정해 둔 짧은 체크포인트다.</p>
<h2>시나리오 방향</h2>
<p>브레인스토밍을 계속하면서 세계관 방향을 중세 판타지로 굳혔다.</p>
<h2>프로젝트 제목</h2>
<p>제목은 <code>Epoch: Unseen</code>으로 잡았다.</p>
<h2>다음 정리</h2>
<p>이제는 이 방향에 맞춰 시나리오와 타이틀 쪽 문구를 계속 다듬을 생각이다. 이번 회차는 짧지만, 설정과 이름을 정한 기록으로 남겨 둔다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 6 - Setting and Project Name</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-6-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-6-en</guid>
    <pubDate>Sat, 28 Feb 2026 00:00:00 GMT</pubDate>
    <description>Locked the medieval fantasy direction and the name Epoch: Unseen. A short checkpoint.</description>
    <content:encoded><![CDATA[<p>This round was about direction, not systems. Committed to medieval fantasy as the setting, locked the name <code>Epoch: Unseen</code> for devlogs and documents going forward. Short checkpoint.</p>
<h2>Scenario Direction</h2>
<p>Continued brainstorming. Locked the setting as medieval fantasy.</p>
<h2>Project Title</h2>
<p><code>Epoch: Unseen</code>.</p>
<h2>Next</h2>
<p>Scenario copy and title screen text will be refined to match this direction. Short entry, but worth recording the decision.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 5 - 응전과 AP 규칙 정리</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-5</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-5</guid>
    <pubDate>Sun, 15 Feb 2026 00:00:00 GMT</pubDate>
    <description>응전과 AP 규칙을 굳히고 전투 페이즈 마무리용 정리를 진행한 회차.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-5-01.png"/><p>이번엔 전투에서 자주 손이 갈 규칙을 묶었다. 응전, AP, 리팩토링을 같이 정리하면서 전투 페이즈를 어디까지 마무리할지 기준을 세운 회차에 가깝다.</p>
<h2>응전 시스템 고도화 및 전투 시스템 정비</h2>
<p>공격을 받았을 때 <code>반격 / 회피 / 방어</code>를 고를 수 있는, 슈로대 스타일 응전 시스템을 작업했다.</p>
<p>AI가 어떤 선택을 할지 계산하는 공식도 같이 만들었다. 이 부분은 GPT 도움을 많이 받았는데 생각보다 꽤 복잡했다.</p>
<p>밸런스 테스트 때 손볼 수 있도록 조절 가능한 변수는 최대한 밖으로 빼두었다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-5-01.png" alt="Devlog - 5 image 1"/></p>
<h2>AP 시스템</h2>
<p>AP(Action Point) 개념도 넣었다. 공격, 스킬, 아이템 사용 시 소모된다.</p>
<p>대부분의 유닛은 1<del>3 AP 정도를 쓰게 하고, 보스급이거나 의도적으로 강하게 설계한 유닛은 4</del>5까지 줄 수도 있을 것 같다.</p>
<p>어쩌면 MP를 완전히 대체할 수도 있는데, 이건 조금 더 굴려 보고 결정할 생각이다.</p>
<h2>리팩토링</h2>
<p>개발을 계속 밀다 보니 코드가 다시 지저분해진 느낌이 들어 한 차례 정리를 했다.</p>
<p>과한 최적화나 오버엔지니어링 성격의 코드는 걷어냈다.</p>
<h2>다음 작업</h2>
<p>개발을 다시 붙잡은 지 대략 두 달 정도 지났다. 회사 다니면서 병행하니 속도가 느린 건 어쩔 수 없다.</p>
<p>유닛 상세 정보 팝업과 일시정지 팝업만 만들면 전투 페이즈는 얼추 마무리될 것 같다.</p>
<p>이제 시나리오와 정비 페이즈 준비도 슬슬 시작해야겠다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 5 - Counter System and AP Rules</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-5-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-5-en</guid>
    <pubDate>Sun, 15 Feb 2026 00:00:00 GMT</pubDate>
    <description>Locked down counter-attack and AP rules, refactored, and set the finish line for the combat phase.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-5-01.png"/><p>Bundled frequently-touched combat rules this round. Counter attacks, AP, refactoring — setting a boundary for how far to take the combat phase.</p>
<h2>Counter System and Combat Cleanup</h2>
<p>Built the SRW-style counter system: <code>Counter / Evade / Defend</code> on receiving an attack.</p>
<p>Also built the AI formula for choosing between them. Got heavy GPT assistance — more complex than expected.</p>
<p>Tunable variables exposed for later balance testing.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-5-01.png" alt="Devlog - 5 image 1"/></p>
<h2>AP System</h2>
<p>Added Action Points. Consumed by attacks, skills, item use.</p>
<p>Most units spend 1–3 AP. Boss-tier or intentionally strong units may get 4–5.</p>
<p>Might fully replace MP. Need more playtesting to decide.</p>
<h2>Refactoring</h2>
<p>Code got messy from sustained pushing. Did a cleanup pass.</p>
<p>Stripped over-optimized and over-engineered code.</p>
<h2>Next</h2>
<p>About two months since restarting development. Slow pace, working alongside a day job.</p>
<p>Unit detail popup and pause popup — once those are done, the combat phase is roughly complete.</p>
<p>Time to start preparing scenario and maintenance phase.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 4 - 전투 AI와 UI 초안</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-4</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-4</guid>
    <pubDate>Sun, 01 Feb 2026 00:00:00 GMT</pubDate>
    <description>Directive/Force/Policy 구조의 전투 AI와 시나리오 그래프, 전투 UI 초안을 잡은 회차.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-06.png"/><p>이번엔 전투 AI, 시나리오 그래프, 전투 UI 초안을 한 번에 잡았다. 아직 콘텐츠가 많이 올라간 단계는 아니지만, 전투 프로토타입의 뼈대는 이때 거의 나온 셈이다.</p>
<h2>AI 시스템 고도화</h2>
<p>Behavior Designer 에셋으로 AI를 만들기로 한 뒤, 이제는 실제로 어떤 로직에 따라 행동하게 할지 트리를 확정하고 구현하는 작업을 했다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-01.png" alt="Devlog - 4 image 1"/></p>
<p>만들다 보니 공통으로 반복되는 부분이 많았다. 그래서 공통 로직은 별도 트리로 분리하고, 트리끼리 연결하는 방식으로 정리했다. 많이 쓰는 방식이라는데, 확실히 훨씬 편했다.</p>
<p>우선 전장 전체의 방침을 먼저 판단한다. 나는 이걸 Directive(지령)라고 부른다.</p>
<ul>
<li>특정 유닛을 공격해라</li>
<li>특정 위치로 이동하라</li>
<li>특정 유닛을 따라가라</li>
</ul>
<p>이런 건 전장의 특수 상황에서 가장 먼저 따라야 하는 행동이다.</p>
<p>특별한 지령이 없으면 각 유닛은 자기 병종 타입(Force)에 맞춰 행동한다.</p>
<ul>
<li>힐러 : 회복 스킬, 버프 스킬 등</li>
<li>물리 근접 딜러 : 물리 공격, 공격 스킬 등</li>
<li>원거리 딜러 : 물리 공격, 공격 스킬, 카이팅 등</li>
<li>마법 딜러 : 공격 스킬, 디버프 스킬 등</li>
<li>탱커 타입 : 공격 스킬, 길막기, 요충지 점유 등</li>
</ul>
<p>그리고 각 병종 트리 안에서 다시 정책(Policy)을 판단한다.</p>
<ul>
<li>공격(Attack) : 적을 향해 이동하여 공격</li>
<li>방어(Defence) : 적이 내 공격 범위 안에 들어오면 이동하여 공격</li>
<li>고정(Hold) : 이동하지 않고 현재 위치에서 행동</li>
</ul>
<p>생각보다 구현이 오래 걸렸다. 거의 일주일 가까이 붙잡고 씨름했다. 그래도 이제는 베이스가 잡혔으니, 앞으로는 콘텐츠를 얹으면서 버그를 찾아 정리하면 될 것 같다.</p>
<h2>스킬 리팩토링</h2>
<p>AI 트리를 만들다 보면 스킬 시스템과 바로 엮이는데, 그 과정에서 기존에 미구현이거나 리팩토링이 덜 끝난 코드들이 계속 드러났다. 버프 스킬을 써도 버프가 안 걸리거나, 공격 스킬을 써도 대미지가 안 들어가는 식의 문제들이 있었다. 이런 부분을 전부 찾아서 정리했다.</p>
<h2>전투 유닛 뷰어</h2>
<p>아직 UI가 충분히 갖춰지지 않아서, 스킬을 쓴 뒤 버프나 디버프가 실제로 적용됐는지 한눈에 확인하기가 어려웠다. 그래서 빠르게 전투 유닛 뷰어를 하나 만들었다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-02.png" alt="Devlog - 4 image 2"/></p>
<h2>전투 시나리오 그래프</h2>
<p>전투 시나리오를 구현하기 위한 커맨드들도 계속 추가하고 있다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-03.png" alt="Devlog - 4 image 3"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-04.png" alt="Devlog - 4 image 4"/></p>
<p>일단은 당장 필요한 것들부터 넣었다. 실제로 시나리오를 만들기 시작하면 더 늘어날 것 같다.</p>
<h2>UI 작업</h2>
<p>이제 아주 귀찮은 구간에 들어왔다. 내 기준으로는 여기가 첫 번째 고비다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-05.png" alt="Devlog - 4 image 5"/></p>
<p>대사</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-06.png" alt="Devlog - 4 image 6"/></p>
<p>유닛 정보(간략 버전)</p>
<p>반격 시스템은 슈퍼로봇대전이나 파이어엠블렘처럼 <code>방어 / 반격 / 회피</code>를 고르는 방식을 채택하려고 한다. 적 턴에도 유저가 어느 정도 개입하면서 전투를 풀어나간다는 느낌을 주고 싶었다.</p>
<p>다음 작업은 반격 페이즈 UI다.</p>
<p>UI 구현 순서는 <code>반격 페이즈 -&gt; 유닛 정보(상세) -&gt; 스킬 정보 -&gt; 전장 정보 -&gt; 메뉴</code> 정도로 보고 있다.</p>
<p>여기까지 나오면 1차 프로토타입으로는 충분하지 않을까 싶다. 아이템이나 특성 같은 요소는 2차 이후로 넘기는 편이 맞아 보인다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 4 - Combat AI and UI Draft</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-4-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-4-en</guid>
    <pubDate>Sun, 01 Feb 2026 00:00:00 GMT</pubDate>
    <description>Established the Directive/Force/Policy AI structure, scenario graph, and initial combat UI.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-4-06.png"/><p>Combat AI, scenario graph, and combat UI draft — all tackled at once. Not content-rich yet, but the combat prototype skeleton came together here.</p>
<h2>AI System</h2>
<p>After committing to Behavior Designer, this round was about finalizing the decision logic and implementing the trees.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-01.png" alt="Devlog - 4 image 1"/></p>
<p>Recurring patterns emerged quickly. Extracted shared logic into separate trees and linked them. Common approach, noticeably easier.</p>
<p>First, evaluate the battlefield-level directive:</p>
<ul>
<li>Attack a specific unit</li>
<li>Move to a specific position</li>
<li>Follow a specific unit</li>
</ul>
<p>These are top-priority actions for special battlefield situations.</p>
<p>Without a directive, each unit acts according to its class type (Force):</p>
<ul>
<li>Healer: heal skills, buff skills</li>
<li>Melee DPS: physical attacks, attack skills</li>
<li>Ranged DPS: physical attacks, attack skills, kiting</li>
<li>Magic DPS: attack skills, debuff skills</li>
<li>Tank: attack skills, blocking, holding chokepoints</li>
</ul>
<p>Within each class tree, a policy layer decides:</p>
<ul>
<li>Attack: move toward enemy, engage</li>
<li>Defense: engage if enemy enters my range</li>
<li>Hold: stay in place, act from current position</li>
</ul>
<p>Took nearly a week. But the base is set — from here it&#x27;s content on top and bug-hunting.</p>
<h2>Skill Refactoring</h2>
<p>Building AI trees immediately exposed incomplete or un-refactored skill code. Buff skills not applying, attack skills dealing zero damage. Found and fixed all of them.</p>
<h2>Combat Unit Viewer</h2>
<p>UI wasn&#x27;t ready enough to confirm buff/debuff application at a glance. Built a quick combat unit viewer.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-02.png" alt="Devlog - 4 image 2"/></p>
<h2>Scenario Graph</h2>
<p>Commands for combat scenarios keep growing.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-03.png" alt="Devlog - 4 image 3"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-04.png" alt="Devlog - 4 image 4"/></p>
<p>Added the immediately necessary ones. More will come once real scenario authoring starts.</p>
<h2>UI Work</h2>
<p>Now entering the tedious zone. First major hurdle by my standards.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-05.png" alt="Devlog - 4 image 5"/></p>
<p>Dialogue</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-4-06.png" alt="Devlog - 4 image 6"/></p>
<p>Unit info (compact version)</p>
<p>Counter system will follow Super Robot Wars / Fire Emblem style: <code>Counter / Evade / Defend</code> selection. Want the player to stay engaged even during enemy turns.</p>
<p>Next: counter phase UI.</p>
<p>UI implementation order: <code>Counter phase → Unit info (detail) → Skill info → Battlefield info → Menu</code>.</p>
<p>Once those are in, should be enough for a first prototype. Items and traits push to the second round.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 3 - 전투 프로토타입 재료 채우기</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-3</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-3</guid>
    <pubDate>Sat, 17 Jan 2026 00:00:00 GMT</pubDate>
    <description>SPUM, 주인공 설정, 전투 애니메이션, 전투 공식까지 전투 프로토타입 재료를 한꺼번에 채운 회차.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-06.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-04.png"/><p>이번엔 전투에 바로 보이는 것들을 많이 만졌다. 유닛 스프라이트를 붙이고, 주인공 설정과 비주얼도 같이 다시 잡고, 전투 애니메이션과 공식까지 한 번에 정리했다. 이제야 전투 프로토타입의 모양이 조금 보이기 시작했다.</p>
<h2>유닛 스프라이트</h2>
<p>유닛 스프라이트는 SPUM을 쓰기로 했다. 개인적으로는 레트로한 픽셀 아트를 더 좋아해서 SPUM 그림체가 완전히 취향인 건 아니다. 그래도 편의성과 생산성을 생각하면 꽤 합리적인 선택이다. 인디 개발자들이 많이 고르는 데는 이유가 있더라.</p>
<p>예전에는 최적화 때문에 별도 시트 작업이 필요했는데, 지금은 정식 기능으로 지원돼서 훨씬 편하다. 딸깍하면 바로 나온다는 게 정말 크다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-01.png" alt="Devlog - 3 image 1"/></p>
<p>흰머리 용사처럼 생긴 캐릭터만 조금 손봤고, 나머지는 거의 기본 프리셋을 그대로 썼다. 지금 단계에서는 완성도보다 속도가 더 중요하다.</p>
<h2>주인공 설정</h2>
<p>이 회차에서 주인공 쪽 설정도 다시 잡았다. 아주 오래전에 <code>천하</code>라는 모드를 만들며 굴리다 멈춘 설정이 있었는데, 이번에는 그걸 그대로 복원하기보다 남아 있는 핵심만 가져오기로 했다.</p>
<p>예전 색은 삼국지 쪽에 더 가까웠지만, 이번에는 배경을 중세 판타지로 완전히 틀었다. 자료도 거의 남아 있지 않아서, 결국 머릿속에 남아 있는 조각들을 바탕으로 다시 세우는 쪽에 가까웠다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-05.png" alt="에리히"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-06.png" alt="리제"/></p>
<p>에리히와 리제 비주얼도 이때 임시로 잡았다. 일러스트는 SDXL로 뽑았고, 몇 번 돌려 본 뒤 당장 쓸 만한 결과를 골랐다.</p>
<h2>전투 애니메이션</h2>
<p>여기서 시간이 꽤 걸렸다. 그래도 이 작업을 지나고 나니 레거시 코드는 거의 남지 않았다. 예전 코드를 억지로 이어 붙이기보다, 필요한 부분은 버리고 구조부터 다시 잡는 쪽으로 갔다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-02.png" alt="Devlog - 3 image 2"/></p>
<p>애니메이션 에디터도 지금은 너무 편하다. 이런 부분까지 AI와 에셋의 도움을 받다 보니, 예전에는 대체 어떻게 다 직접 만들었나 싶을 정도다.</p>
<h2>스탯 타입</h2>
<p>현재 생각 중인 기본 스탯은 아래와 같다.</p>
<ul>
<li>체력 : HP</li>
<li>기력 : MP</li>
<li>공격 : 물리 공격력</li>
<li>방어 : 물리 방어력</li>
<li>마력 : 마법 공격력</li>
<li>저항 : 마법 방어력</li>
<li>속도 : 명중률, 회피, 연속공격</li>
<li>행운 : 크리티컬</li>
</ul>
<p>대체로는 이 방향이다. 다만 스탯 이름은 아직 완전히 확정하지 않았다.</p>
<p>SRPG 중에는 스탯을 이원화하는 경우도 많다. 예를 들면 <code>무력 -&gt; 공격력</code>, <code>통솔 -&gt; 방어력</code>처럼 어떤 스탯이 바로 쓰이지 않고 한 단계 변환을 거쳐 실제 수치에 반영되는 방식이다.</p>
<p>처음에는 이 프로젝트도 비슷한 구조였지만 결국 폐기했다. 지금 형태가 더 직관적이고, 육성 공식도 훨씬 단순하게 가져갈 수 있어서다.</p>
<p>나중에 <code>사령관 시스템</code>을 붙이게 되면 <code>지휘</code> 같은 스탯이 추가될 수도 있겠다. 아직은 구상 단계다.</p>
<h2>전투 공식</h2>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-03.png" alt="Devlog - 3 image 3"/></p>
<p>전투 공식은 GraphToolkit으로 에셋화했다. 위 스크린샷은 마법 명중률 공식이다.</p>
<p>물리 피해량, 마법 피해량, 물리 명중률, 마법 명중률, 크리티컬 확률처럼 전투 전반에 공통으로 쓰이는 공식이 있는 반면, 특정 마법이나 스킬만 따로 쓰는 특수 공식도 필요할 것 같다.</p>
<p>결국 공식 종류가 엄청 많아질 게 뻔하다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-04.png" alt="Devlog - 3 image 4"/></p>
<p>이걸 전부 코드 기반으로만 관리하면 나중에 손대기 너무 힘들어진다. 그래서 공식 자체를 데이터 자산으로 분리할 필요가 있었다.</p>
<p>그 과정에서 고른 게 GraphToolkit이다. 공식도 결국 사람이 읽고 수정해야 하니, 시각적으로 보이는 쪽이 낫다고 판단했다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 3 - Filling the Combat Prototype</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-3-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-3-en</guid>
    <pubDate>Sat, 17 Jan 2026 00:00:00 GMT</pubDate>
    <description>SPUM sprites, protagonist design, combat animations, and battle formulas — filling in the combat prototype materials all at once.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-06.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-3-04.png"/><p>Touched a lot of visible combat pieces this round. Unit sprites, protagonist setup and visuals, combat animations, battle formulas — all in one pass. The combat prototype finally has a shape.</p>
<h2>Unit Sprites</h2>
<p>Went with SPUM. Not entirely my taste — I prefer retro pixel art — but convenience and productivity make it a reasonable pick. Popular among indie devs for good reason.</p>
<p>Used to require separate sheet work for optimization. Now it&#x27;s a built-in feature. One click and it&#x27;s done. That matters.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-01.png" alt="Devlog - 3 image 1"/></p>
<p>Tweaked the white-haired hero character slightly. Everything else is mostly default presets. Speed over polish at this stage.</p>
<h2>Protagonist Setup</h2>
<p>Revisited protagonist lore this round. Had an old setting from a mod called &quot;Cheonha&quot; that I&#x27;d shelved years ago. Instead of restoring it wholesale, I pulled only the surviving core.</p>
<p>Original flavor leaned Three Kingdoms. This time, fully pivoted to medieval fantasy. Almost no reference material survived — rebuilt mostly from memory fragments.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-05.png" alt="Erich"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-06.png" alt="Lise"/></p>
<p>Drafted Erich and Lise visuals here. Illustrations generated with SDXL, picked usable results after a few rounds.</p>
<h2>Combat Animations</h2>
<p>Ate a lot of time. But after this pass, almost no legacy code remains. Chose to restructure rather than force-fit old code.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-02.png" alt="Devlog - 3 image 2"/></p>
<p>The animation editor is so convenient now. Between AI and asset tools, hard to imagine how I used to do everything manually.</p>
<h2>Stat Types</h2>
<p>Current base stats:</p>
<ul>
<li>HP</li>
<li>MP</li>
<li>ATK — physical attack</li>
<li>DEF — physical defense</li>
<li>MAG — magic attack</li>
<li>RES — magic resistance</li>
<li>SPD — hit rate, evasion, follow-up attacks</li>
<li>LCK — critical rate</li>
</ul>
<p>Roughly this direction. Names not fully locked.</p>
<p>Some SRPGs use two-tier stats — e.g., &quot;Prowess → Attack Power.&quot; This project started that way but I scrapped it. Current form is more intuitive and simplifies growth formulas.</p>
<p>A &quot;Command&quot; stat might appear later if a commander system gets added. Still conceptual.</p>
<h2>Battle Formulas</h2>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-03.png" alt="Devlog - 3 image 3"/></p>
<p>Battle formulas turned into data assets via GraphToolkit. Screenshot shows the magic hit-rate formula.</p>
<p>Physical damage, magic damage, physical hit rate, magic hit rate, crit chance — common formulas used across combat. Plus per-skill special formulas.</p>
<p>Formula count will grow fast.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-3-04.png" alt="Devlog - 3 image 4"/></p>
<p>Managing all of this in code alone becomes unmaintainable. Separating formulas into data assets was necessary. GraphToolkit won because formulas need to be human-readable and editable.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 2 - 타일맵과 전투 AI 기반 정리</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-2</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-2</guid>
    <pubDate>Sat, 03 Jan 2026 00:00:00 GMT</pubDate>
    <description>직접 만든 툴을 접고 유니티 타일맵, 범위 세팅 툴, Behavior Designer 쪽으로 작업 기반을 갈아탄 회차.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-05.png"/><p>이번엔 직접 만들던 편집 툴과 하드코딩 로직을 접고, 유니티 기본 도구와 에셋 쪽으로 방향을 틀었다. 타일맵, 범위 세팅, AI까지 앞으로 계속 손이 갈 부분을 한 번에 정리한 회차다.</p>
<h2>유니티 타일맵 도입</h2>
<p>개발 마인드가 조금 바뀌었다. 예전에는 최대한 직접 만들어 보자는 쪽이었는데, 이제는 가져다 쓸 수 있는 건 가져다 쓰고 더 빨리 결과를 내는 쪽에 가깝다.</p>
<p>그래서 직접 만들던 전용 타일맵 툴은 과감하게 버리고, 유니티 타일맵을 쓰기로 했다. 좌표계도 유니티 기준으로 맞췄다. 원래는 좌측 상단이 <code>(0, 0)</code>이었지만, 이제는 좌측 하단이 <code>(0, 0)</code>이다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-01.png" alt="Devlog - 2 image 1"/></p>
<p>다만 타일맵 에셋은 잘못 고른 것 같다. 써 보니 마음에 안 드는 부분이 꽤 있어서 조금 후회된다. 당분간은 계속 쓰겠지만, 나중에는 다른 에셋으로 바꿀 가능성이 크다.</p>
<h2>공격범위 / 효과범위 통합 및 세팅 툴 작업</h2>
<p>기존에는 공격 범위와, 공격 대상을 중심으로 퍼지는 효과 범위가 따로 놀고 있었다. 따지고 보면 같은 범위 로직으로 처리할 수 있는 문제라 판단해서 하나로 통합했다. 범위 안에 포함되는지 하드코딩으로 판정하던 부분도 전부 걷어내고, 눈으로 보면서 만들 수 있는 세팅 툴도 같이 작업했다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-02.png" alt="Devlog - 2 image 2"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-03.png" alt="Devlog - 2 image 3"/></p>
<p>범위는 타깃을 중심으로 4분면으로 나눈 뒤, 한 면을 칠하는 방식으로 지정한다.</p>
<ul>
<li>방향 개념이 없으면 상하좌우 대칭으로 4개 면을 모두 다룬다.</li>
<li>방향 개념이 있으면 아래를 바라보는 기준으로 좌우 대칭만 적용해 2개 면만 다룬다.</li>
</ul>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-04.png" alt="Devlog - 2 image 4"/></p>
<ul>
<li>ALL - 전범위</li>
<li>CONE - 부채꼴 모양</li>
<li>CROSS - 십자</li>
<li>DIAMOND - 마름모(몰우전)</li>
<li>LASER - 관통(이격, 삼격, 육격)</li>
<li>NONE - 범위 없음</li>
<li>RANGE - 원거리(궁병, 노병, 연노병)</li>
<li>SQUARE - 8방향(구궁)</li>
</ul>
<h2>유닛 AI에 Behavior Designer 도입</h2>
<p>AI 로직도 하드코딩이 너무 심해서 관리가 어려웠다. 그래서 기존 코드는 전부 걷어내고 Behavior Tree를 도입했다. 시각적으로 AI의 의사결정 구조를 볼 수 있다는 점이 크다. 대신 러닝 커브는 조금 있다.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-05.png" alt="Devlog - 2 image 5"/></p>
<p>위 스크린샷은 공격 범위 안에 적이 있으면 이동해서 공격하는 가장 단순한 형태의 트리다.</p>
<p>트리는 클래스 타입에 따라 5<del>6종류, 여기에 현재 방침까지 더하면 3</del>4종류 정도의 파생형이 필요할 것 같다. 중요한 적 보스는 별도 트리를 따로 줄 생각이다.</p>
<p>Behavior Designer를 도입한 뒤에는 병종별 베이스 트리를 먼저 잡고, 시나리오별 파생형을 추가하는 방식으로 정리할 생각이다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 2 - Tilemap and Combat AI Foundation</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-2-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-2-en</guid>
    <pubDate>Sat, 03 Jan 2026 00:00:00 GMT</pubDate>
    <description>Dropped custom-built tools in favor of Unity Tilemap, a range-setting editor, and Behavior Designer for AI.</description>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-01.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/project-t/img/devlog-2-05.png"/><p>Dropped custom editing tools and hardcoded logic, switched to Unity built-ins and third-party assets. Tilemap, range setting, AI — reorganized everything that&#x27;ll need constant attention going forward.</p>
<h2>Unity Tilemap</h2>
<p>Development mindset shifted. Used to build everything myself. Now: use what&#x27;s available, ship faster.</p>
<p>Scrapped the custom tilemap tool, adopted Unity Tilemap. Coordinate system aligned to Unity — origin moved from top-left <code>(0,0)</code> to bottom-left <code>(0,0)</code>.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-01.png" alt="Devlog - 2 image 1"/></p>
<p>The tilemap asset choice was a mistake, though. Not happy with it after using it. Sticking with it for now, likely replacing later.</p>
<h2>Attack Range / Effect Range Unification</h2>
<p>Attack range and effect range (spreading from a target) were handled separately. Both are fundamentally the same range logic, so I unified them. Replaced all hardcoded containment checks with a visual setting tool.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-02.png" alt="Devlog - 2 image 2"/></p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-03.png" alt="Devlog - 2 image 3"/></p>
<p>Ranges are defined by painting quadrants around a target:</p>
<ul>
<li>No direction: all four quadrants (symmetrical).</li>
<li>Directional: two quadrants only (left-right symmetry, facing down).</li>
</ul>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-04.png" alt="Devlog - 2 image 4"/></p>
<ul>
<li>ALL — full area</li>
<li>CONE — fan shape</li>
<li>CROSS — cross pattern</li>
<li>DIAMOND — diamond / rhombus</li>
<li>LASER — piercing line</li>
<li>NONE — no range</li>
<li>RANGE — ranged (archers)</li>
<li>SQUARE — 8-directional</li>
</ul>
<h2>Behavior Designer for Unit AI</h2>
<p>AI logic was too hardcoded to manage. Stripped it all and introduced Behavior Trees. Visual decision structure is the big win. Some learning curve.</p>
<p><img src="https://kinkeep.dev/posts-images/project-t/img/devlog-2-05.png" alt="Devlog - 2 image 5"/></p>
<p>Screenshot shows the simplest tree: if an enemy is within attack range, move and attack.</p>
<p>Expecting 5–6 tree variants per class type, plus 3–4 per combat policy. Key enemy bosses get dedicated trees.</p>
<p>Plan: establish per-class base trees first, then add scenario-specific variants.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 1 - 재시동</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-1</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-1</guid>
    <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
    <description>멈춰 있던 Epoch: Unseen을 다시 꺼내 레거시 구조를 걷고, 다시 개발을 붙일 바닥을 만든 첫 회차.</description>
    <content:encoded><![CDATA[<p>이번엔 새 기능보다 재시동 준비가 먼저였다. 멈춰 있던 Epoch: Unseen을 다시 굴릴 수 있게 레거시 구조를 걷고, 이후 전투 시스템을 다시 붙일 바닥부터 정리했다.</p>
<h2>재시동</h2>
<p>Epoch: Unseen은 2021년부터 2022년까지 만들던 SRPG용 엔진이다. 2023년과 2024년에도 틈틈이 손은 댔지만, 사실상 거의 멈춰 있던 프로젝트였다.</p>
<p>거의 4년 전에 잡아 둔 구조라 지금 기준과 맞지 않는 부분이 많았다. 유니티 버전도 달라졌고, 그 사이 내 작업 방식도 많이 바뀌었다. 그래서 예전 코드를 그대로 이어 붙이기보다, 다시 시작할 수 있는 기반부터 정리하기로 했다.</p>
<h2>정리한 범위</h2>
<p>지난 2주 동안은 레거시 코드를 찾아 고치고 구조를 정리하는 데 시간을 썼다. 감각상으로는 큰 틀의 정리가 70% 정도 끝난 상태다.</p>
<p>지금은 전투 시스템을 바로 붙이기보다, 이후 작업에서 계속 걸릴 만한 구조를 먼저 걷어내는 쪽이 우선이었다. 시나리오와 시스템 기획도 이 기준에 맞춰 다시 확인하고 있다.</p>
<h2>다음 단계</h2>
<p>재시동 정리가 끝나면 전투 시스템, 시나리오, 정비 페이즈처럼 실제 플레이 흐름을 이루는 작업으로 다시 넘어갈 생각이다.</p>]]></content:encoded>
  </item>
  <item>
    <title>Epoch: Unseen Devlog 1 - Restart</title>
    <link>https://kinkeep.dev/posts/project-t/devlog-1-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/project-t/devlog-1-en</guid>
    <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
    <description>Pulled Epoch: Unseen out of hibernation, stripped legacy structure, and laid the foundation to resume development.</description>
    <content:encoded><![CDATA[<p>New features came second. First priority: getting the stalled Epoch: Unseen ready to run again. Stripped legacy structure and prepped the foundation for reconnecting the combat system.</p>
<h2>Restart</h2>
<p>Epoch: Unseen is an SRPG engine I built from 2021 to 2022. Touched it occasionally in 2023 and 2024, but the project was effectively frozen.</p>
<p>Four-year-old architecture didn&#x27;t match current standards. Unity version changed, my workflow changed. Rather than grafting onto old code, I decided to clear a foundation for a fresh start.</p>
<h2>Scope of cleanup</h2>
<p>Spent two weeks finding and fixing legacy code, restructuring. Rough sense: 70% of the big-picture cleanup is done.</p>
<p>Priority was removing structural problems that would keep tripping up future work, rather than jumping straight into combat. Scenario and system design are being re-checked against this baseline.</p>
<h2>Next</h2>
<p>Once the restart cleanup wraps, moving to the parts that make the game playable — combat system, scenario, maintenance phase.</p>]]></content:encoded>
  </item>
  <item>
    <title>FlyingCat으로 확인한 바이브 코딩의 현재</title>
    <link>https://kinkeep.dev/posts/flyingcat/vibe-coding</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/flyingcat/vibe-coding</guid>
    <pubDate>Sat, 20 Dec 2025 00:00:00 GMT</pubDate>
    <description>Antigravity와 Gemini 3.0 Pro로 FlyingCat을 만들며, 작은 게임과 UI, WebGL 배포, 랭킹 연동 정도는 AI에게 꽤 맡길 수 있다는 가능성을 확인했다.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-01-title.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-03-gameplay.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-04-guide.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-02-leaderboard.png"/><p>FlyingCat은 내가 바이브 코딩을 다시 보게 된 첫 프로젝트였다. 실제 결과물 자체는 <a href="https://kinkeep.dev/projects/flyingcat">FlyingCat 프로젝트 페이지</a>에도 정리해 두었고, 이 글에서는 왜 이 게임이 내 기준을 바꿨는지 쪽에 조금 더 집중해 보려고 한다.</p>
<p>지난여름까지만 해도 바이브 코딩은 꽤 실망스러웠다. 같은 요청을 넣어도 결과가 들쭉날쭉했고, 실전에 넣기에는 불안한 구석이 많았다. 그런데 몇 달 사이 체감이 제법 달라졌다. 이제는 질문 몇 번 던져 보는 수준이 아니라, 작은 프로젝트 하나쯤은 통째로 맡겨 보는 실험도 해볼 만하겠다는 생각이 들었다.</p>
<h2>왜 FlyingCat이었나</h2>
<p>모티브는 예전 플래시 게임 <code>NANACA CRASH</code>, 국내에서는 <code>남친 날리기</code>로도 불리던 게임이었다. 각도와 파워를 잡아 캐릭터를 날리고, 중간 장애물이나 서포터에 부딪히며 거리를 늘리는 구조다. 지인이 이런 류의 게임을 한 번 만들어 보라고 추천했고, 그걸 고양이와 햄스터 분위기로 비틀어 FlyingCat을 잡았다.</p>
<p>이런 게임이 실험 대상으로 괜찮았던 건 겉보기보다 확인할 게 많았기 때문이다. 각도와 파워 조절, 비행 중 상태 전환, 장애물 효과, UI, WebGL 빌드, 랭킹까지 들어가면 작은 게임이어도 손이 갈 곳이 꽤 많다. 버튼 몇 개 있는 앱보다 바이브 코딩의 장단점을 보기 좋은 소재라고 생각했다.</p>
<h2>무엇을 어디까지 맡겼나</h2>
<p>도구는 Antigravity 하나만 썼고, 모델도 Gemini 3.0 Pro 하나로만 밀었다. 엔진은 Unity였고, UI는 UIToolkit으로 만들었다. 그때는 <code>Gemini가 프론트엔드 성향이 강하다면 USS 기반 UI도 잘하지 않을까</code>라는 기대가 있었는데, 결과적으로는 이 판단이 꽤 맞았다. 이미지 자산은 NanoBanana로 만들었다.</p>
<p>중요했던 건 내가 일부러 코드에서 손을 뗐다는 점이다. 이 실험의 목표는 게임 하나를 빨리 끝내는 것보다 <code>Agentic Coding을 실제로 겪어 보는 것</code>에 더 가까웠다. 원래는 직접 만들다가 중간에 Antigravity를 붙인 건데, 붙인 뒤로는 손이 근질거려도 참고 지켜봤다. 대신 Plan을 먼저 세우고, 특정 라인이나 수정 방향에 코멘트를 남기면서 허가하는 식으로만 개입했다.</p>
<p>대략 3~4일 정도는 AI에게 구현을 맡기고, 그다음 3~4일은 내가 변경된 내용을 보면서 방향을 다시 잡아 주는 식으로 굴렸다. 완전 자동화와는 거리가 있었지만, 내가 코드를 직접 치지 않고도 프로젝트를 앞으로 밀 수 있다는 감각이 꽤 컸다.</p>
<h2>실제로 나온 게임</h2>
<p>실제 게임 루프는 아래처럼 돌아갔다.</p>
<ul>
<li>각도를 조절한다.</li>
<li>파워를 조절한다.</li>
<li>햄스터를 날린다.</li>
<li>비행 중 <code>업/다운</code> 스킬을 써서 방향을 바꾼다.</li>
<li>길 중간의 고양이, 장애물, 서포터 효과를 잘 받아 최대한 멀리 간다.</li>
<li>완전히 멈추면 게임 오버다.</li>
</ul>
<p>중간 효과도 제법 다양했다. 45도나 60도 방향으로 다시 날려 버리거나, 수평으로 밀어 주거나, 속도를 깎거나, 몇 초 동안 충돌하지 않게 만드는 식이다. 겉으로는 단순해 보여도 실제 구현에 들어가면 물리와 상태 전환이 계속 맞물리는 구조였다.</p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-01-title.png" alt="FlyingCat 타이틀 화면"/></p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-03-gameplay.png" alt="FlyingCat 실제 플레이 화면"/></p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-04-guide.png" alt="FlyingCat 가이드 화면"/></p>
<p>결과물은 실제로 돌아가는 WebGL 게임까지 나왔다. itch.io에 올렸고, 별도 홍보 없이 자연 노출만 둔 상태에서 대략 10명 정도가 플레이했다. 여기서 멈춘 게 아니라 AWS Cognito와 Lambda를 붙여 랭킹 기능도 넣었다. AWS는 자격증 공부로 살짝 본 정도였지 실전 경험은 거의 없었는데, Gemini에게 물어가며 끝까지 붙였다.</p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-02-leaderboard.png" alt="FlyingCat 랭킹 화면"/></p>
<h2>생각보다 멀리 갔다</h2>
<p>가장 먼저 체감된 건 속도였다. 내가 퇴근 후 지친 상태로 한 달 동안 붙잡았던 것보다, AI가 하루 만에 더 많은 결과를 앞으로 밀어내는 걸 보면서 꽤 놀랐다. 물론 내가 원래 느리게 진행한 것도 사실이지만, 적어도 AI는 피곤하다는 이유로 손을 놓지는 않았다.</p>
<p>UI도 기대 이상이었다. 특히 UIToolkit 쪽이 꽤 인상적이었다. 당시에는 UIToolkit이 인게임 UI에는 그다지 좋지 않다는 평도 있었고, 나도 반신반의하면서 시작했다. 그런데 Antigravity와 Gemini 3.0 Pro 조합은 USS 기반 레이아웃과 화면 구성을 생각보다 잘 밀어붙였다. 나중에 Claude나 Codex로 비슷한 시도를 해 봤을 때 만족도가 덜했던 걸 떠올리면, 그때는 유난히 Gemini가 잘 맞았던 것 같다.</p>
<p>이 지점에서 처음으로 <code>작은 게임 정도는 AI에게 꽤 맡길 수 있겠다</code>는 감각이 생겼다. 단순히 코드 몇 줄 받아 적는 수준이 아니라, 미니게임 하나를 WebGL로 배포하고 랭킹까지 붙이는 단계는 분명히 실전 쪽에 가까웠다.</p>
<h2>그래도 결국 사람이 잡았다</h2>
<p>그렇다고 편하게 맡겨 두기만 하면 되는 건 아니었다. 환각 때문에 잘못된 코드를 건드리거나, 설명이 틀린 가이드를 주거나, 보안상 좋지 않은 코드를 제안하는 경우가 중간중간 나왔다. 내가 계속 지켜보며 바로잡았기 때문에 굴러간 거지, 그대로 믿고 넘겼으면 꽤 위험했을 것이다.</p>
<p>가장 크게 꼬인 건 물리와 상태 전환이 만나는 지점이었다. FlyingCat은 게임 스텝에 따라 물리가 켜져야 할 때와 꺼져야 할 때가 분명했는데, 이게 1프레임 차이로 잘못 적용되면서 비행 흐름이 어긋나는 문제가 있었다. 처음에는 Unity 기본 물리를 썼지만, 개발을 진행할수록 상태에 따라 일부러 비물리적인 처리가 더 필요해졌고 결국 기본 물리를 버리고 커스텀으로 다시 짰다.</p>
<p>AWS 연동도 비슷했다. 기능 자체를 붙이는 데는 도움이 됐지만, 가이드가 오래됐거나 설명이 너무 축약돼 있어서 실제 콘솔 메뉴를 못 찾는 경우가 종종 있었다. 이런 부분은 AI가 방향을 잡아 주는 데까지만 의미가 있었고, 마지막 확인은 결국 사람이 해야 했다.</p>
<h2>FlyingCat 이후에 남은 기준</h2>
<p>이 경험 이후로는 바이브 코딩을 더 이상 <code>신기한 장난감</code>으로 보지 않게 됐다. 적어도 미니게임 수준에서는 가능성을 봤고, 이걸 더 큰 프로젝트로 옮겨 볼 수 있겠다는 생각도 생겼다. 나중에 Epoch: Unseen으로 넘어가 보게 된 것도 결국 이 경험이 발판이었다.</p>
<p>동시에 기준도 분명해졌다. AI에게 구현을 맡길 수는 있지만, 디렉팅과 검수는 여전히 사람 몫이다. 특히 상태 전환, 물리, 보안, 외부 서비스 연동처럼 한 번 틀어지면 뒤가 더 힘든 영역은 더 그렇다.</p>
<p>내가 FlyingCat에서 얻은 결론은 단순하다. 바이브 코딩은 이제 장난감 수준은 아니었다. 그렇다고 끝까지 맡기고 손을 떼도 되는 도구도 아니었다. 작은 게임 하나를 실제로 배포해 보고 나서야, 그 두 가지가 동시에 선명하게 보이기 시작했다.</p>]]></content:encoded>
  </item>
  <item>
    <title>What FlyingCat Showed Me About Vibe Coding</title>
    <link>https://kinkeep.dev/posts/flyingcat/vibe-coding-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/flyingcat/vibe-coding-en</guid>
    <pubDate>Sat, 20 Dec 2025 00:00:00 GMT</pubDate>
    <description>Building FlyingCat with Antigravity and Gemini 3.0 Pro confirmed that small games, UI, WebGL deployment, and leaderboard integration are within reach of AI-assisted development.</description>
    <category>AI/AgenticCoding</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-01-title.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-03-gameplay.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-04-guide.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-02-leaderboard.png"/><p>FlyingCat made me take vibe coding seriously. The game is on the <a href="https://kinkeep.dev/projects/flyingcat">project page</a>. This post is about why it changed my standards.</p>
<p>Last summer, vibe coding disappointed. Same request, inconsistent results, too risky for production. Months later the feeling shifted. Running a small project end-to-end felt worth trying.</p>
<h2>Why FlyingCat</h2>
<p>The reference was NANACA CRASH, a flash game where you set angle and power to launch a character, bouncing off obstacles and supporters to maximize distance. A friend suggested the genre. I twisted it into a cat-and-hamster theme.</p>
<p>Good experiment material because there&#x27;s more to verify than it looks. Angle and power control, mid-flight state transitions, obstacle effects, UI, WebGL build, leaderboards — plenty of surface area for a small game. Better than a button-heavy app for seeing vibe coding&#x27;s strengths and limits.</p>
<h2>What I delegated, and how far</h2>
<p>One tool: Antigravity. One model: Gemini 3.0 Pro. Engine: Unity. UI: UIToolkit. I had a hunch that Gemini&#x27;s frontend affinity would extend to USS-based layouts. That turned out correct. Image assets came from NanoBanana.</p>
<p>The important part: I deliberately took my hands off the code. The goal wasn&#x27;t finishing a game fast — it was experiencing agentic coding firsthand. I&#x27;d started building manually, then connected Antigravity. After that, I resisted the urge to touch code and intervened only through plans and line-level comments.</p>
<p>Roughly 3–4 days of AI implementation, then 3–4 days of me reviewing changes and adjusting direction. Not full automation, but pushing a project forward without writing code myself — that feeling was significant.</p>
<h2>The actual game</h2>
<p>The game loop:</p>
<ul>
<li>Set angle.</li>
<li>Set power.</li>
<li>Launch the hamster.</li>
<li>Use up/down skills mid-flight to change direction.</li>
<li>Hit cats, obstacles, supporters along the way for maximum distance.</li>
<li>Full stop means game over.</li>
</ul>
<p>Mid-flight effects were varied: relaunch at 45° or 60°, horizontal push, speed reduction, temporary invincibility. Looks simple, but implementation requires physics and state transitions meshing constantly.</p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-01-title.png" alt="FlyingCat title screen"/></p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-03-gameplay.png" alt="FlyingCat gameplay"/></p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-04-guide.png" alt="FlyingCat guide screen"/></p>
<p>The result was a playable WebGL game uploaded to itch.io. About 10 people played with zero promotion. Beyond that, I added a leaderboard using AWS Cognito and Lambda. I had almost no AWS experience beyond studying for a certification — Gemini walked me through it.</p>
<p><img src="https://kinkeep.dev/posts-images/flyingcat/img/flyingcat-02-leaderboard.png" alt="FlyingCat leaderboard"/></p>
<h2>It went further than expected</h2>
<p>Speed hit first. What I&#x27;d struggled with for a month after work, AI pushed further in a day. Partly because I&#x27;m slow, but AI doesn&#x27;t stop because it&#x27;s tired.</p>
<p>UI surprised me. UIToolkit was especially impressive. At the time, opinions were mixed on UIToolkit for in-game UI. Antigravity with Gemini 3.0 Pro handled USS layouts better than expected. Later attempts with Claude or Codex were less satisfying — Gemini happened to fit well there.</p>
<p>This was the first time I felt &quot;small games can be meaningfully delegated to AI.&quot; Not just receiving a few code snippets — deploying a mini-game to WebGL with a leaderboard is closer to production than to a demo.</p>
<h2>A human still steered</h2>
<p>Didn&#x27;t mean I could just hand it off. Hallucinated code, incorrect guides, insecure suggestions appeared throughout. It worked because I kept watching and correcting. Trust-and-go would have been dangerous.</p>
<p>The biggest tangle was where physics and state transitions met. FlyingCat needed physics on and off at precise game steps. One-frame misapplication broke the flight flow. Started with Unity&#x27;s default physics, but as development progressed, intentionally non-physical handling became necessary. Ended up replacing the default with custom physics.</p>
<p>AWS integration was similar. Helpful for getting the feature attached, but guides were outdated or overly abbreviated — actual console menus were hard to locate. AI pointed the direction; final verification needed a human.</p>
<h2>Standards after FlyingCat</h2>
<p>After this, vibe coding stopped being a novelty. At least at the mini-game scale, the possibility was real. Moving to a bigger project felt plausible. Epoch: Unseen came next, built on this foundation.</p>
<p>Standards sharpened too. AI can handle implementation, but directing and QA stay human. Especially in areas where one wrong step compounds — state transitions, physics, security, external service integration.</p>
<p>Takeaway is simple. Vibe coding stopped being a toy. It also wasn&#x27;t something you hand off and walk away from. Deploying one small game made both visible at once.</p>]]></content:encoded>
  </item>
  <item>
    <title>Five UE5 Animation Concepts I Sorted Out First</title>
    <link>https://kinkeep.dev/posts/ue/devlog1-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/ue/devlog1-en</guid>
    <pubDate>Sun, 31 Aug 2025 00:00:00 GMT</pubDate>
    <description>Following a TPS sample, I separated montages, blend spaces, aim offsets, notifies, and IK rigs — the five animation features that confused me first.</description>
    <category>Game Engine/Unreal</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/dvl_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/am_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/bs_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/ao_1.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/an_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/ik_1.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/ik_2.gif"/><p><img src="https://kinkeep.dev/posts-images/ue/dvl_1.gif" alt="devlog_1"/></p>
<p>Kept putting off Unreal Engine. Finally started. Blueprints and Paper2D first, then 3D via a TPS sample. First wall: animation feature names. Heard all of them, couldn&#x27;t tell where each fits.</p>
<p>Wrote down the ones I kept bumping into. Not a docs rewrite — how I distinguished them on first contact.</p>
<h3>Animation Montage</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/am_1.gif" alt="Animation Montage"/></p>
<p>Montage clicked first. Not the looping locomotion side — this is for &quot;play this action now.&quot; Attacks, skills, explicit playback.</p>
<p>In the TPS sample, attack combos and weapon swaps come to mind. Multiple sequences in one asset, with Blueprint controlling play timing and section jumps.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/animation-montage-in-unreal-engine">UE5 Documentation</a></li>
</ul>
<h3>Blend Space</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/bs_1.gif" alt="Blend Space"/></p>
<p>Blend Space felt the opposite — less &quot;play&quot; and more &quot;mix.&quot; Takes continuously changing values like speed or direction and blends poses accordingly.</p>
<p>Walk to run transitions, directional strafing — that&#x27;s where it shows up. Initially confused with montages. The rule &quot;if the value keeps changing, it&#x27;s a blend space&quot; cleared things up.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/blend-spaces-in-unreal-engine">UE5 Documentation</a></li>
</ul>
<h3>Aim Offset</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/ao_1.png" alt="Aim Offset"/></p>
<p>The name felt intimidating, but in practice it&#x27;s roughly &quot;a blend space for aiming.&quot; Base pose stays, upper body aim layers on top.</p>
<p>Obvious why TPS needs it. Character moves continuously while the gun direction tracks up/down and left/right. Different use case from full-body locomotion blending.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/aim-offset-in-unreal-engine">UE5 Documentation</a></li>
</ul>
<h3>Animation Notify</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/an_1.gif" alt="Animation Notify"/></p>
<p>Notify made more sense by usage than by name. Pin an event onto the animation timeline. More intuitive than computing timing in code.</p>
<p>Hit detection, footsteps, VFX, camera shake — immediately clear why notifies exist. At the beginner stage, being able to set timing while looking at frames mattered a lot.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/animation-notifies-in-unreal-engine">UE5 Documentation</a></li>
</ul>
<h3>IK Rig &amp; IK Rig Retargeting</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/ik_1.png" alt="IK Rig"/></p>
<p>Most unfamiliar of the five. Hard to know where to start. For now I understand it as &quot;preparation for reusing another character&#x27;s animations.&quot;</p>
<p><img src="https://kinkeep.dev/posts-images/ue/ik_2.gif" alt="IK Rig Retargeting"/></p>
<p>As I understand it: IK Rig sets up a bone hierarchy for IK Solver use. Retargeting transfers motion to a different skeleton based on that setup. Makes sense when you think about reusing external animations or swapping characters.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-ik-rig">UE5 Documentation</a></li>
</ul>
<hr/>
<h3>Summary</h3>
<p>UE5 animation felt more complex than it is because of the number of named features. My current split: explicit playback → Montage. Value-driven blending → Blend Space. Aim-only overlay → Aim Offset. Timeline events → Notify. Cross-skeleton motion transfer → IK Rig + Retargeting.</p>
<p>Still a beginner. But connecting each feature to its role in the TPS sample was far faster than memorizing definitions.</p>]]></content:encoded>
  </item>
  <item>
    <title>UE5 애니메이션을 처음 공부하며 먼저 구분한 5가지</title>
    <link>https://kinkeep.dev/posts/ue/devlog1</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/ue/devlog1</guid>
    <pubDate>Sun, 31 Aug 2025 00:00:00 GMT</pubDate>
    <description>TPS 샘플을 따라가며 UE5 애니메이션 기능 중 몽타주, 블렌드 스페이스, 에임 오프셋, 노티파이, IK 릭을 어떻게 나눠 이해했는지 정리했다.</description>
    <category>Game Engine/Unreal</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/dvl_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/am_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/bs_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/ao_1.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/an_1.gif"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/ik_1.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/ue/ik_2.gif"/><p><img src="https://kinkeep.dev/posts-images/ue/dvl_1.gif" alt="devlog_1"/></p>
<p>언리얼 엔진 공부를 계속 미뤄 두다가 이제야 손을 댔다. 블루프린트와 Paper2D 쪽을 먼저 보고, 3D 파트에서 TPS 샘플을 따라가기 시작했는데 제일 먼저 막힌 건 애니메이션 기능 이름이었다. 이름은 다 들어 본 것 같은데, 막상 어디에 써야 하는지는 잘 안 잡혔다.</p>
<p>그래서 일단 자주 부딪힌 것들만 따로 적어 두기로 했다. 공식 문서 설명을 다시 옮기는 글은 아니고, 처음 볼 때 내가 어떻게 구분했는지에 더 가깝다.</p>
<h3>애니메이션 몽타주</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/am_1.gif" alt="애니메이션 몽타주"/></p>
<p>몽타주는 제일 먼저 손에 잡혔다. 계속 돌아가는 이동 애니메이션 쪽이 아니라, 공격이나 스킬처럼 <code>지금 이 동작을 재생해라</code> 하고 명확하게 걸어 주는 용도라고 받아들이니 이해가 쉬웠다.</p>
<p>TPS 샘플로 보면 공격 콤보나 무기 교체 같은 장면이 바로 떠오른다. 여러 시퀀스를 한 에셋 안에 넣고, 블루프린트에서 재생 시점이나 섹션 이동을 잡는 쪽이다.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/ko-kr/unreal-engine/animation-montage-in-unreal-engine">언리얼엔진5 공식문서</a></li>
</ul>
<h3>블렌드 스페이스</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/bs_1.gif" alt="블렌드 스페이스"/></p>
<p>블렌드 스페이스는 반대로 <code>재생한다</code>기보다 <code>섞는다</code>는 느낌이 강했다. 속도나 방향처럼 계속 바뀌는 값을 받아서 포즈를 이어 붙이는 쪽이다.</p>
<p>걷기에서 달리기로 넘어가거나, 이동 방향에 따라 스트레이프가 섞이는 장면을 보면 감이 온다. 몽타주랑 헷갈리긴 했는데, 그냥 <code>계속 변하는 값이면 블렌드 스페이스</code>라고 생각해 두니 훨씬 편했다.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/ko-kr/unreal-engine/blend-spaces-in-unreal-engine">언리얼엔진5 공식문서</a></li>
</ul>
<h3>에임 오프셋</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/ao_1.png" alt="에임 오프셋"/></p>
<p>에임 오프셋은 처음엔 이름부터 어렵게 느껴졌는데, 보고 나니 거의 <code>조준용 블렌드 스페이스</code>였다. 기본 포즈는 유지하고, 상체 조준만 덧입히는 쪽이다.</p>
<p>TPS에서는 왜 필요한지가 바로 보였다. 캐릭터는 계속 움직이는데 총구 방향만 위아래, 좌우로 따라가야 하기 때문이다. 전신 이동을 섞는 블렌드 스페이스와는 쓰임새가 꽤 다르다.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/ko-kr/unreal-engine/aim-offset-in-unreal-engine">언리얼엔진5 공식문서</a></li>
</ul>
<h3>애니메이션 노티파이</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/an_1.gif" alt="애니메이션 노티파이"/></p>
<p>노티파이는 기능 이름보다 쓰임새가 더 직관적이었다. 애니메이션 타임라인에 이벤트를 박아 두는 방식이다. 코드에서 시간을 계산하는 것보다 훨씬 눈에 잘 들어왔다.</p>
<p>공격 판정, 발소리, 이펙트, 카메라 흔들림 같은 건 왜 노티파이를 쓰는지 바로 납득이 갔다. 특히 입문 단계에서는 프레임 보면서 타이밍을 맞출 수 있다는 게 컸다.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/ko-kr/unreal-engine/animation-notifies-in-unreal-engine">언리얼엔진5 공식문서</a></li>
</ul>
<h3>IK 릭, IK 릭 리타게팅</h3>
<p><img src="https://kinkeep.dev/posts-images/ue/ik_1.png" alt="IK 릭"/></p>
<p>IK 릭과 리타게팅은 이 다섯 개 중에서 제일 낯설었다. 이름만 보면 어렵고, 처음에는 어디서부터 봐야 할지도 애매했다. 일단은 <code>다른 캐릭터의 애니메이션을 가져다 쓰기 위한 준비</code>라고 이해하고 있다.</p>
<p><img src="https://kinkeep.dev/posts-images/ue/ik_2.gif" alt="IK 릭 리타게팅"/></p>
<p>내가 이해한 식으로 적으면, IK 릭은 특정 본 체계를 IK Solver 기준으로 다루기 위한 셋업이고, 리타게팅은 그 셋업을 바탕으로 다른 스켈레톤에 모션을 옮기는 단계다. 외부 애니메이션을 재사용하거나 캐릭터를 갈아끼우는 장면을 떠올리면 왜 필요한지 조금 납득이 갔다.</p>
<ul>
<li><a href="https://dev.epicgames.com/documentation/ko-kr/unreal-engine/unreal-engine-ik-rig">언리얼엔진5 공식문서</a></li>
</ul>
<hr/>
<h3>정리</h3>
<p>처음 언리얼 애니메이션을 볼 때는 이름이 많아서 더 복잡하게 느껴졌는데, 지금은 대충 이렇게 나누고 있다. 공격처럼 콕 집어 재생해야 하면 몽타주, 값에 따라 자연스럽게 섞이면 블렌드 스페이스, 조준만 따로 얹으면 에임 오프셋, 프레임 타이밍에 이벤트를 걸면 노티파이, 다른 캐릭터에 모션을 옮길 준비를 하는 쪽이 IK 릭과 리타게팅이다.</p>
<h2>아직 입문 단계라 기능을 깊게 이해했다고 하기는 어렵다. 그래도 이름 정의부터 외우는 것보다, TPS 샘플에서 각 기능이 맡는 역할을 먼저 연결해 두는 편이 훨씬 빨랐다.</h2>]]></content:encoded>
  </item>
  <item>
    <title>Grayscale Transition Without Saturation in URP Shader Graph</title>
    <link>https://kinkeep.dev/posts/unity/urp_grascale-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/unity/urp_grascale-en</guid>
    <pubDate>Sat, 23 Mar 2024 00:00:00 GMT</pubDate>
    <description>Building a grayscale effect from scratch in Shader Graph — no Saturation node, just manual luminance weights and lerp.</description>
    <category>Game Engine/Unity</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gs.png"/><p>Playing with Shader Graph, I wanted to build a grayscale transition by hand. Simple goal: take one texture, slide between full color and black-and-white with a single slider. Could have used the Saturation node directly, but I wanted to see how it works underneath.</p>
<h2>Problem</h2>
<p>Required behavior:</p>
<ul>
<li>One texture input.</li>
<li>Slider at <code>0</code>: fully grayscale.</li>
<li>Slider at <code>1</code>: original color.</li>
<li>Smooth interpolation in between.</li>
</ul>
<p>Saturation node does this out of the box. Still wanted to confirm how grayscale is actually constructed.</p>
<h2>Solution</h2>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gs.png" alt="Shader Graph"/></p>
<p>Two steps:</p>
<ol>
<li>Convert original color to a grayscale value.</li>
<li>Lerp between grayscale and original.</li>
</ol>
<p>Grayscale isn&#x27;t equal-weight RGB. Human perception weights channels differently for a natural-looking result:</p>
<pre><code class="language-text">gray = R * 0.21 + G * 0.71 + B * 0.07
</code></pre>
<p>Spread that <code>gray</code> across all three RGB channels for a grayscale color. Then apply <code>Lerp(A, B, T)</code>:</p>
<ul>
<li><code>A</code>: grayscale</li>
<li><code>B</code>: original color</li>
<li><code>T</code>: 0–1 slider value</li>
</ul>
<p>In shader terms, one line:</p>
<pre><code class="language-text">result = lerp(grayscaleColor, originalColor, t)
</code></pre>
<h2>Why this way</h2>
<p>The upside is simple debugging:</p>
<ul>
<li>Grayscale conversion wrong?</li>
<li>Interpolation value wrong?</li>
<li>Final output wrong?</li>
</ul>
<p>Each part isolates cleanly. Using the Saturation node directly is faster, but building it once makes &quot;grayscale transition = grayscale generation + interpolation&quot; stick clearly.</p>
<h2>Notes</h2>
<p>The lasting takeaway is a thinking pattern, not a technique. For simple effects like this, understanding &quot;transform the original into some intermediate form, then blend the two&quot; outlasts memorizing a node name.</p>
<p>When building similar effects:</p>
<ul>
<li>First create the intermediate representation. Here: grayscale.</li>
<li>Blend it with the original via Lerp.</li>
<li>Attach a slider or mask for control range.</li>
</ul>]]></content:encoded>
  </item>
  <item>
    <title>URP Shader Graph에서 Color와 Vector가 다르게 보였던 이유</title>
    <link>https://kinkeep.dev/posts/unity/urp_gamma_correction</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/unity/urp_gamma_correction</guid>
    <pubDate>Sat, 23 Mar 2024 00:00:00 GMT</pubDate>
    <description>Linear Color Space 프로젝트에서 Shader Graph의 Color 값과 Vector 값이 같은 숫자여도 다르게 보였던 이유를 실험 메모 중심으로 정리했다.</description>
    <category>Game Engine/Unity</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_00.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_01.png"/><p>Linear로 돌리던 URP 프로젝트에서 Shader Graph 값을 더하다가 한 번 멈췄다. <code>Color(0.5, 0.5, 0.5)</code>를 두 번 더했는데 흰색까지 가지 않았다. 같은 숫자를 Vector로 넣으면 훨씬 예상에 가까운 결과가 나왔다.</p>
<p>처음에는 노드 연결을 잘못한 줄 알았다. 그런데 조금 뜯어보니 계산식보다 값의 성격이 더 중요했다. 눈에 보이는 <code>색</code>과 계산에 들어가는 <code>숫자</code>를 같은 감각으로 다루고 있었던 셈이다.</p>
<h2>헷갈렸던 장면</h2>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_02.png" alt="Unity Setting"/></p>
<p>URP 프로젝트를 Linear로 두면, 화면에 보이는 색과 셰이더 안에서 계산에 쓰이는 값이 바로 1:1로 겹치지 않는다. 머리로는 알고 있었는데도, Shader Graph에서 Color 노드와 Vector 노드를 섞어 쓰니 그 차이가 더 크게 느껴졌다.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_03.png" alt="Linear Pipeline Add Effect"/></p>
<p>문제가 된 예제는 아래였다.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_04.png" alt="Shader Graph"/></p>
<p>겉으로 보기에는 둘 다 <code>0.5</code>다. 그런데 Color 쪽은 생각만큼 밝아지지 않았고, Vector 쪽은 예상한 대로 더해졌다. 숫자는 같아 보여도 파이프라인 안에서는 같은 값처럼 취급되지 않았다는 뜻이다.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_05.png" alt="Shader Graph"/></p>
<h2>내가 정리한 기준</h2>
<p>내가 붙잡고 있던 건 결국 이 부분이었다. Linear 프로젝트에서는 조명과 색 계산이 선형 공간 기준으로 이루어지고, 화면에 보이는 색은 다시 표시용 변환을 거친다. 그래서 <code>눈에 중간 회색으로 보이는 값</code>과 <code>연산에 그대로 넣는 숫자</code>를 같은 감각으로 생각하면 틀어지기 쉽다.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_00.png" alt="Gamma Chart"/></p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_01.png" alt="Color Encoding"/></p>
<p>메모해 둔 기준은 이 정도였다.</p>
<ul>
<li>Texture나 Color처럼 <code>색</code>을 의미하는 입력은 표시용 보정이 얽혀 있을 수 있다.</li>
<li>Vector처럼 <code>숫자</code>를 의미하는 입력은 연산값으로 읽는 편이 안전하다.</li>
<li>Shader Graph에서 색을 직접 더하거나 곱할 때는, 지금 만지는 값이 <code>보이는 색</code>인지 <code>계산용 값</code>인지 먼저 구분해야 한다.</li>
</ul>
<p>정확한 내부 구현을 전부 뜯어본 건 아니지만, 실전에서는 이 정도만 알아도 훨씬 덜 헷갈렸다. Shader Graph에서 값이 이상하게 보일 때는 노드가 틀린 게 아니라, 내가 서로 다른 공간의 값을 같은 기준으로 보고 있었던 경우가 많았다.</p>
<h2>메모</h2>
<ul>
<li>Linear 프로젝트에서는 Color Picker의 숫자를 곧바로 계산용 상수처럼 믿지 않는 편이 낫다.</li>
<li>셰이더에서 계수, 보정값, 마스크처럼 <code>수치</code>가 중요한 값은 Vector나 Float로 두는 편이 덜 헷갈린다.</li>
<li>반대로 최종 색 자체를 다루는 부분은 Color 입력으로 두되, 중간 계산이 기대와 다르면 색 공간을 먼저 의심하는 게 좋다.</li>
</ul>
<p>결국 헷갈렸던 건 감마 이론 자체보다 <code>이 숫자가 Shader Graph 안에서 어떤 값으로 들어오느냐</code>였다. URP에서 색이 이상하게 더해질 때는 복잡한 이론부터 떠올리기보다, <code>지금 만지는 값이 색인가 숫자인가</code>부터 다시 보는 편이 빨랐다.</p>
<hr/>
<h2>참고 자료</h2>
<ul>
<li><a href="https://www.cambridgeincolour.com/tutorials/gamma-correction.htm">Cambridge In Colour</a></li>
<li><a href="https://youtu.be/Xwlm5V-bnBc?si=mE10FiL2s3nmuMIn">Gamma가 어디 Gamma - Unity Korea Youtube</a></li>
</ul>
<hr/>]]></content:encoded>
  </item>
  <item>
    <title>URP Shader Graph에서 Saturation 없이 흑백 전환 만들기</title>
    <link>https://kinkeep.dev/posts/unity/urp_grascale</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/unity/urp_grascale</guid>
    <pubDate>Sat, 23 Mar 2024 00:00:00 GMT</pubDate>
    <description>Shader Graph에서 Saturation 노드 없이 그레이스케일을 만들고, lerp로 원본 컬러와 흑백을 섞는 가장 단순한 방법을 메모처럼 정리했다.</description>
    <category>Game Engine/Unity</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gs.png"/><p>Shader Graph를 만지다가 흑백 전환을 직접 한 번 만들어 보고 싶었다. 주제는 단순하다. <code>텍스처 한 장을 받아서 흑백과 컬러 사이를 슬라이더 하나로 오가게 만들기</code>. Saturation 노드를 바로 써도 됐지만, 이번에는 굳이 풀어서 만들어 봤다.</p>
<h2>문제</h2>
<p>필요한 동작은 단순했다.</p>
<ul>
<li>텍스처 입력 하나를 받는다.</li>
<li>슬라이더 값이 <code>0</code>이면 완전 흑백이 된다.</li>
<li>슬라이더 값이 <code>1</code>이면 원본 컬러가 그대로 나온다.</li>
<li>그 사이 값에서는 자연스럽게 보간된다.</li>
</ul>
<p>이 정도면 Saturation 노드를 바로 써도 된다. 그래도 <code>흑백 이미지가 실제로 어떻게 만들어지는지</code>를 한 번 손으로 확인해 두고 싶었다.</p>
<h2>이렇게 풀었다</h2>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gs.png" alt="Shader Graph"/></p>
<p>구성은 두 단계면 끝난다.</p>
<ol>
<li>원본 컬러를 grayscale 값으로 한 번 바꾼다.</li>
<li>grayscale과 원본 컬러를 <code>Lerp</code>로 섞는다.</li>
</ol>
<p>흑백 값은 보통 RGB를 똑같이 더하지 않는다. 눈에 조금 더 자연스럽게 보이도록 채널마다 가중치를 다르게 준다. 여기서는 아래 비율을 썼다.</p>
<pre><code class="language-text">gray = R * 0.21 + G * 0.71 + B * 0.07
</code></pre>
<p>이렇게 얻은 <code>gray</code>를 RGB 세 채널에 다시 펴 주면 그레이스케일 컬러가 된다. 그다음에는 익숙한 <code>Lerp(A, B, T)</code>만 붙이면 된다.</p>
<ul>
<li><code>A</code>: grayscale</li>
<li><code>B</code>: 원본 컬러</li>
<li><code>T</code>: 0~1 슬라이더 값</li>
</ul>
<p>실제로 셰이더 쪽 개념만 적으면 아래 한 줄에 가깝다.</p>
<pre><code class="language-text">result = lerp(grayscaleColor, originalColor, t)
</code></pre>
<h2>왜 이렇게 했나</h2>
<p>좋았던 점은 구조가 단순해서 디버깅하기 쉽다는 데 있다.</p>
<ul>
<li>흑백 변환이 잘못됐는지</li>
<li>보간 값이 잘못됐는지</li>
<li>최종 출력이 잘못됐는지</li>
</ul>
<p>세 부분을 따로 떼어 볼 수 있다. Saturation 노드를 바로 쓰면 더 빠를 수는 있지만, 한 번 직접 풀어 보면 <code>흑백 전환</code>이 결국 <code>그레이스케일 생성 + 보간</code>이라는 게 더 또렷하게 보인다.</p>
<h2>메모</h2>
<p>여기서 남는 건 복잡한 기법보다 사고방식 쪽이다. 이런 간단한 효과는 노드 하나를 외우는 것보다 <code>원본 값을 어떤 형태로 바꾸고, 그 둘을 어떻게 섞는가</code>로 이해하는 편이 오래 남는다.</p>
<p>비슷한 효과를 만들 때는 아래 순서로 생각하면 된다.</p>
<ul>
<li>먼저 원하는 중간 표현을 만든다. 여기서는 grayscale이다.</li>
<li>그다음 원본과 결과를 <code>Lerp</code>로 섞는다.</li>
<li>마지막에 슬라이더나 마스크로 제어 범위를 붙인다.</li>
</ul>
<hr/>]]></content:encoded>
  </item>
  <item>
    <title>Why Color and Vector Looked Different in URP Shader Graph</title>
    <link>https://kinkeep.dev/posts/unity/urp_gamma_correction-en</link>
    <guid isPermaLink="true">https://kinkeep.dev/posts/unity/urp_gamma_correction-en</guid>
    <pubDate>Sat, 23 Mar 2024 00:00:00 GMT</pubDate>
    <description>In a Linear Color Space project, Color and Vector nodes with identical numbers produced different results in Shader Graph. Experiment notes on why.</description>
    <category>Game Engine/Unity</category>
    <content:encoded><![CDATA[<link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_02.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_03.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_04.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_05.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_00.png"/><link rel="preload" as="image" href="https://kinkeep.dev/posts-images/unity/img/gamma_01.png"/><p>Linear URP project. Adding Shader Graph values, I paused. <code>Color(0.5, 0.5, 0.5)</code> added twice — didn&#x27;t reach white. Same numbers through Vector got the expected result.</p>
<p>First thought: wiring mistake. The real issue was value semantics, not math. I&#x27;d been treating &quot;visible color&quot; and &quot;computation number&quot; as the same thing.</p>
<h2>Where I got confused</h2>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_02.png" alt="Unity Setting"/></p>
<p>In a Linear URP project, what you see on screen and what the shader computes don&#x27;t map 1:1. Knew this in theory, but mixing Color and Vector nodes in Shader Graph made the gap feel larger.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_03.png" alt="Linear Pipeline Add Effect"/></p>
<p>The problem case:</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_04.png" alt="Shader Graph"/></p>
<p>Both say <code>0.5</code>. But the Color side didn&#x27;t brighten as expected. The Vector side added as predicted. Same-looking numbers, different treatment inside the pipeline.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_05.png" alt="Shader Graph"/></p>
<h2>How I sorted it out</h2>
<p>The core issue: in a Linear project, lighting and color math happen in linear space. The color you see on screen goes through a display transform. So &quot;what looks like mid-gray&quot; and &quot;the number you plug into a calculation&quot; aren&#x27;t the same thing.</p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_00.png" alt="Gamma Chart"/></p>
<p><img src="https://kinkeep.dev/posts-images/unity/img/gamma_01.png" alt="Color Encoding"/></p>
<p>Rules I wrote down:</p>
<ul>
<li>Inputs that mean &quot;color&quot; (Texture, Color) may carry display correction.</li>
<li>Inputs that mean &quot;number&quot; (Vector) are safer to read as computation values.</li>
<li>When adding or multiplying colors in Shader Graph, first ask: is this a &quot;visible color&quot; or a &quot;computation value&quot;?</li>
</ul>
<p>I didn&#x27;t trace every internal implementation. But in practice, this distinction cut most of the confusion. When Shader Graph values look wrong, it&#x27;s usually not the nodes — it&#x27;s me treating values from different spaces as if they&#x27;re the same.</p>
<h2>Notes</h2>
<ul>
<li>In Linear projects, don&#x27;t trust Color Picker numbers as direct computation constants.</li>
<li>For coefficients, correction values, masks — use Vector or Float. Less confusing.</li>
<li>For final color output, use Color input, but if intermediate math surprises you, suspect color space first.</li>
</ul>
<p>What confused me wasn&#x27;t gamma theory itself. It was &quot;how does this number enter the Shader Graph.&quot; When URP colors add up wrong, checking &quot;is this a color or a number?&quot; first was faster than reaching for theory.</p>
<hr/>
<h2>References</h2>
<ul>
<li><a href="https://www.cambridgeincolour.com/tutorials/gamma-correction.htm">Cambridge In Colour</a></li>
<li><a href="https://youtu.be/Xwlm5V-bnBc?si=mE10FiL2s3nmuMIn">Gamma가 어디 Gamma - Unity Korea Youtube</a></li>
</ul>]]></content:encoded>
  </item>
  </channel>
</rss>
