에이전틱 엔지니어링을 하는 가장 솔직한(허세 없는) 방법: 그냥 모델에게 말을 거세요.
TMT요즘 여기에서 조금 조용했던 이유는, 새 프로젝트에 푹 빠져 있기 때문입니다. 에이전틱 엔지니어링이 너무 좋아져서 이제는 제 코드를 거의 100% 대신 써줄 정도가 되었습니다. 그런데도 여전히 많은 사람들이 실제로 일을 끝내기보다는, 문제를 풀겠다며 과하게 꾸며낸 퍼포먼스만 만들어내는 걸 자주 보게 됩니다.
이 글은 어젯밤 런던에서 열린 Claude Code Anonymous에서 나눈 대화들에서 일부 영감을 받았고, 동시에 마지막으로 워크플로우를 정리한 뒤 AI 한 해가 지나기도 했기에, 한 번 점검해 볼 때가 되었다고 느껴서 쓰게 되었습니다.
기본적인 아이디어들은 여전히 유효하기 때문에, 컨텍스트 관리 같은 기초적인 내용은 다시 설명하지 않겠습니다. 그런 것들이 궁금하다면 제 Optimal AI Workflow 글을 먼저 읽어보세요.
컨텍스트 & 기술 스택
저는 혼자 작업하고 있고, 현재 프로젝트는 약 30만 줄 규모의 TypeScript React 앱, 크롬 익스텐션, CLI, Tauri 기반 클라이언트 앱, 그리고 Expo로 만든 모바일 앱으로 구성되어 있습니다. 호스팅은 vercel을 쓰고 있고, PR을 올리면 제 웹사이트의 새 버전이 약 2분 만에 올라와 바로 테스트할 수 있습니다. 나머지(앱 등)는 자동화되어 있지 않습니다.
하네스 & 전반적인 접근 방식
저는 일상적인 작업 환경을 완전히 codex CLI로 옮겼습니다. 3x3 터미널 그리드에서 동시에 3~8개 정도를 돌리고 있고, 대부분은 같은 폴더에서, 일부 실험용 작업만 별도의 폴더에서 실행합니다. git worktree나 PR 기반 워크플로우도 여러 번 시도해 봤지만, 결국 항상 지금 이 셋업으로 돌아오게 됩니다. 이 방식이 일을 가장 빨리 끝내주기 때문입니다.
제 에이전트들은 git 원자적 커밋(atomic commits)을 스스로 합니다. 커밋 히스토리를 최대한 깔끔하게 유지하기 위해 에이전트 파일을 상당히 많이 다듬어 왔습니다. 덕분에 git 작업이 훨씬 날카로워져서, 각 에이전트가 실제로 수정한 파일만 정확히 커밋하게 됩니다.
맞아요, Claude에서는 훅(hook)을 붙일 수 있고 codex는 아직 그걸 지원하지 않습니다. 하지만 요즘 모델들은 너무 똑똑해서, 한 번 무엇을 하겠다고 마음먹으면 어떤 훅으로도 막을 수가 없습니다.
예전에는 제가 slop-generator라고 놀림을 받기도 했는데, 이제는 병렬 에이전트 돌리는 방식이 천천히 주류가 되어 가는 걸 보니 꽤 흐뭇합니다.
모델 선택
저는 거의 모든 작업을 gpt-5-codex의 중간 설정으로 합니다. 이 설정은 “똑똑함”과 속도 사이의 균형이 아주 좋고, 생각하는 강도를 자동으로 올렸다 내렸다 해줍니다. 이런 설정들을 지나치게 고민해 봐야 크게 의미 있는 차이를 못 느꼈고, ultrathink 같은 걸 매번 신경 쓰지 않아도 된다는 점이 정말 편합니다.
폭발 반경
무언가 작업을 시작할 때마다 저는 항상 “폭발 반경(blast radius)”을 염두에 둡니다. 이 표현을 제가 만든 건 아니지만, 정말 마음에 들어합니다. 어떤 변경을 하려 할 때, 대략 얼마나 시간이 걸릴지, 몇 개의 파일을 건드리게 될지 감이 옵니다. 코드베이스에 작은 폭탄을 여러 개 던질 수도 있고, “Fat Man”급 대형 폭탄 하나에 작은 것 몇 개를 곁들일 수도 있습니다. 그런데 대형 폭탄을 여러 개 던지기 시작하면, 커밋을 독립적으로 나누는 것이 사실상 불가능해지고, 뭔가 잘못됐을 때 되돌리는 것도 훨씬 어려워집니다.
이 개념은 에이전트들을 지켜볼 때에도 좋은 기준이 됩니다. 어떤 작업이 제가 예상한 것보다 오래 걸리는 것 같으면, 그냥 ESC를 눌러 멈추고 “현재 상태가 어때?”라고 물어보며 상태 업데이트를 받습니다. 그다음 모델이 올바른 방향을 잡도록 도와주거나, 작업을 중단하거나, 계속 진행하게 할지 결정합니다. 모델을 중간에 멈추는 걸 두려워할 필요는 없습니다. 파일 변경은 원자적으로 처리되고, 모델은 중단 지점 이후부터 다시 이어서 진행하는 데 꽤 능숙합니다.
변경의 영향을 잘 가늠하기 어려울 때는, 먼저 “변경을 적용하기 전에 몇 가지 옵션을 제시해줘”라고 시켜 보고 그걸 보면서 범위를 재봅니다.
worktrees를 사용하지 않는 이유
저는 개발 서버를 하나만 띄워둔 채로 프로젝트를 발전시키면서 여기저기 클릭해 보고, 여러 변경 사항을 한 번에 테스트합니다. 변경마다 별도의 tree/브랜치를 쓰는 방식은 이런 흐름을 상당히 느리게 만들고, 개발 서버를 여러 개 띄우는 건 금방 짜증 나는 일이 됩니다. 게다가 Twitter OAuth 제약도 있어서, 콜백용으로 등록할 수 있는 도메인 수에도 한계가 있습니다.
Claude Code
예전에는 Claude Code를 정말 좋아했는데, 요즘은 도저히 못 쓰겠습니다. (codex는 좋아하는 것 같지만요) 말투도 그렇고, 끊임없이 나오는 “absolutely right”, 테스트는 깨지는데 “100% 프로덕션 준비 완료”라고 떠드는 메시지들… 더 이상은 못 견디겠더군요. 반면 codex는 묵묵히 일만 잘하는 내향적인 엔지니어에 가깝습니다. 작업을 시작하기 전에 훨씬 더 많은 파일을 읽기 때문에, 짧은 프롬프트만 줘도 대부분 제가 원하는 걸 정확히 해냅니다.
제 타임라인만 봐도, 이제는 codex가 답이다 라는 쪽으로 대체로 의견이 모아지고 있습니다.
codex의 다른 이점들
- 클로드의 156k 대비 약 230k의 실사용 컨텍스트. 운이 좋거나 API 요금을 감수하면 Sonnet 1Mio도 있긴 합니다. 하지만 현실적으로 Claude는 그 컨텍스트를 다 쓰기 훨씬 전부터 이상한 행동을 하기 때문에, 실제로 제대로 쓸 수 있는 옵션이라고 보긴 어렵습니다.
- 더 효율적인 토큰 사용. OpenAI가 뭘 다르게 하는지는 모르겠지만, Claude Code를 쓸 때보다 컨텍스트가 훨씬 천천히 차오릅니다. Claude를 쓸 때는 “Compacting…” 메시지를 정말 자주 봤는데, codex에서는 컨텍스트 한도를 넘기는 일이 거의 없습니다.
- 메시지 큐잉. Codex는 메시지 큐잉을 지원합니다. Claude도 한때 이 기능이 있었지만, 몇 달 전에 메시지를 “모델 조종(steer)” 용으로 바꿔버렸죠. codex를 조정하고 싶으면, 그냥 ESC를 누르고 엔터를 쳐서 새 메시지를 보내면 됩니다. 두 방식 모두 선택할 수 있다는 점이 훨씬 낫습니다. 저는 관련된 기능 작업들을 큐에 쌓아두곤 하는데, codex는 그걸 정말 꾸준하게 잘 처리해 나갑니다.
- 속도. OpenAI는 codex를 Rust로 다시 썼고, 그게 체감됩니다. 정말 빠릅니다. Claude Code를 쓸 때는 몇 초씩 멈추는 일이 잦았고, 프로세스 메모리가 몇 기가바이트까지 불어났습니다. 게다가 특히 Ghostty를 쓸 때는 터미널이 계속 깜빡였죠. Codex에는 그런 게 없습니다. 믿기 힘들 정도로 가볍고 빠르게 느껴집니다.
- 언어. 이건 제 멘탈 건강에 진짜 큰 영향을 줍니다. 저는 Claude에게 수없이 소리를 질러왔습니다. 하지만 codex에게 화가 나는 일은 거의 없습니다. 설령 codex가 더 나쁜 모델이라고 해도, 이런 언어 스타일 하나만으로도 codex를 쓸 겁니다. 둘을 몇 주만 같이 써보면 무슨 말인지 바로 이해하게 될 겁니다.
- 여기저기 랜덤한 마크다운 파일이 생기지 않습니다. 아는 사람은 다 아는 얘기죠(IYKYK).
다른 harness가 아닌 이유
제 생각에, 최종 사용자와 모델 회사 사이에는 사실상 큰 여지가 없습니다. 저는 구독 모델을 쓰는 것이 압도적으로 가장 좋은 딜이라고 보고 있습니다. 지금은 OpenAI 구독 4개, Anthropic 구독 1개를 쓰고 있고, 사실상 토큰 무제한에 가까운 사용을 월 약 1,000달러 정도에 해결하고 있습니다. 같은 양을 API 콜로 쓰면 비용이 대략 10배쯤 나올 겁니다. ccusage 같은 토큰 카운팅 툴을 써서 대략 계산해 본 거라 완벽히 정확하진 않겠지만, 설령 5배 차이 정도라고 해도 여전히 엄청 좋은 조건입니다.
amp나 Factory 같은 도구들이 존재한다는 점은 좋다고 생각합니다. 다만 이런 도구들이 장기적으로 살아남을 거라고는 잘 상상되지 않습니다. codex와 Claude Code는 새로 나올 때마다 계속 좋아지고 있고, 결국 비슷한 아이디어와 기능 집합으로 수렴하고 있습니다. 일부 도구들이 할 일 리스트, steering, 약간 더 나은 DX 같은 걸로 잠깐 우위를 점할 수는 있겠지만, 장기적으로 큰 AI 회사들을 유의미하게 이길 수 있을 것 같진 않습니다.
amp는 GPT-5를 드라이버로 쓰는 걸 그만두고 이제는 이를 “오라클(oracle)”이라고 부릅니다. 반면 저는 codex를 쓰면서 사실상 항상 그 “더 똑똑한 모델”, 즉 오라클과 함께 일하고 있습니다. 벤치마크는 물론 존재합니다. 하지만 실제 사용 패턴이 너무 왜곡되어 있어서, 그런 수치를 신뢰하긴 어렵다고 봅니다. 제 경험상 amp보다 codex가 훨씬 좋은 결과를 줍니다. 다만 세션 공유 같은 기능은 꽤 괜찮고, 몇 가지 흥미로운 아이디어를 앞서서 밀어붙이고 있다는 점은 인정해야겠습니다.
Factory에 대해서는 아직도 확신이 없습니다. 홍보 영상은 조금 민망할 정도고요. 이미지가 (아직) 지원되지 않고 시그니처 깜빡임 문제도 있지만, 제 타임라인에서는 좋은 얘기들도 조금씩 들려오긴 합니다.
Cursor… 아직도 스스로 코드를 직접 많이 치는 사람에게는 탭 자동완성 모델이 업계 최고 수준입니다. 저는 주로 VS Code를 쓰지만, 브라우저 자동화나 plan mode 같은 걸 밀어붙이는 점은 높게 평가합니다. GPT-5-Pro도 Cursor에서 조금 써봤지만, 5월에 저를 괴롭히던 버그들이 여전히 그대로 남아 있더군요. 고치고 있다는 얘기는 들었기에, 일단 Dock에는 계속 올려두고 있습니다.
Auggie 같은 것들은 제 타임라인에 잠깐 스쳐 지나갔을 뿐이고, 그 뒤로는 아무도 다시 언급하지 않았습니다. 결국 이런 도구들은 전부 GPT-5나 Sonnet(혹은 둘 다)을 감싸는 래퍼에 불과하고, 언제든 다른 걸로 대체 가능합니다. RAG는 Sonnet에게는 도움이 되었을지 모르지만, GPT-5의 검색 능력이 워낙 좋아서, 코드용 벡터 인덱스를 따로 둘 필요가 없습니다.
가장 가능성이 있어 보이는 후보는 opencode와 crush 정도인데, 특히 오픈 모델과 조합해서 쓸 때 그렇습니다. 여기에 OpenAI나 Anthropic 구독을 붙여서 쓰는 것도 (교묘한 꼼수 덕분에) 이론상 가능하긴 합니다. 다만 이게 허용되는지 애매하고, codex나 Claude Code에 맞춰 최적화된 모델을 일부러 더 부족한 harness에 물려서 쓸 이유가 뭔지도 잘 모르겠습니다.
다른 openmodel
중국발 오픈 모델들도 계속 지켜보고 있는데, 따라오는 속도가 꽤 인상적입니다. GLM 4.6과 Kimi K2.1은 Sonnet 3.7 수준에 서서히 근접해 가는 강력한 경쟁자들입니다. 그렇다고 해서 이들을 매일 쓰는 주력 모델(daily driver)로 추천하고 싶지는 않습니다.
벤치마크는 전체 이야기의 절반만 말해줄 뿐입니다. 제 생각에 에이전틱 엔지니어링은 Sonnet 4.0이 나온 5월쯤에 “이건 별로” 수준에서 “오, 괜찮은데”로 올라섰고, gpt-5-codex가 등장하면서 “괜찮다”에서 “이건 진짜 미쳤다” 수준으로 한 번 더 도약했습니다.
플랜 모드와 접근법
벤치마크가 놓치는 부분은, 모델과 harness가 프롬프트를 받았을 때 “어떤 전략으로” 움직이는지입니다. codex는 훨씬, 정말 훨씬 더 신중하고, 무엇을 할지 결정하기 전에 레포 안의 파일들을 훨씬 많이 읽습니다. 말도 안 되는 요청을 하면 더 강하게 반박하기도 하고요. Claude나 다른 에이전트들은 훨씬 성급해서, 일단 뭔가를 해보려 드는 쪽에 가깝습니다. plan mode와 빡빡한 구조화 문서를 쓰면 이 문제를 어느 정도 완화할 수는 있지만, 제게는 그게 망가진 시스템을 둘러서 우회하는 느낌에 가깝습니다.
그래서 저는 이제 codex를 쓸 때 큰 plan 파일을 잘 쓰지 않습니다. codex에는 전용 plan mode조차 없지만, 프롬프트를 따르는 능력이 워낙 좋아서 그냥 “먼저 같이 논의해보자”거나 “옵션들을 먼저 제시해줘” 정도만 써도, 제 승인을 받을 때까지 성실하게 기다립니다. 별도의 harness 쇼를 벌일 필요가 없습니다. 그냥 말 걸면 됩니다.
그러나 Claude Code에 플러그인 기능이 추가됨
멀리서 한숨 소리 들리나요? 그게 접니다. 정말 거대한 헛소리 더미라고밖에 표현할 수가 없습니다. 이 기능은 Anthropic이 어디에 집중하고 있는지에 대해 상당히 실망스럽게 만들었습니다. 모델의 비효율을 플러그인으로 땜질하려는 느낌이에요. 물론 특정 작업을 위해 좋은 문서를 잘 관리하는 건 좋은 생각입니다. 저도 docs 폴더 안에 유용한 문서들을 마크다운으로 잔뜩 모아두고 있습니다.
But but Subagents !!!1
이제 서브에이전트(subagents)라는 춤사위에 대해서도 한마디 해야겠죠. 5월까지만 해도 이건 “subtasks”라고 불렸고, 주로 모델이 전체 텍스트를 다 볼 필요가 없을 때, 작업을 별도 컨텍스트로 떼어내는 용도였습니다. 시끄러운 빌드 스크립트 같은 걸 분리해서 병렬 작업을 하거나, 컨텍스트 낭비를 줄이는 용도였죠. 나중에 이걸 서브에이전트라는 이름으로 리브랜딩하면서, 약간 개선해서 “지시사항을 달고 잘 포장된 별도 작업”처럼 보이게 만들었습니다.
하지만 사용 사례는 그대로입니다. 다른 사람들이 서브에이전트로 하는 일을, 저는 보통 터미널 창을 나누는 걸로 해결합니다. 뭔가 조사를 하고 싶으면, 그건 그냥 다른 터미널 패널에서 시키고, 필요한 결과만 복사해서 다른 패널에 붙여넣습니다. 이렇게 하면 제가 구성하는 컨텍스트를 100% 눈으로 보고, 손으로 제어할 수 있습니다. 반면 subagents는 어떤 컨텍스트가 오가는지, 무엇이 다시 돌아오는지 보기/조정/통제하기가 오히려 더 어려워집니다.
그리고 Anthropic이 블로그에서 추천하는 서브에이전트에 대해서도 짚고 넘어가야 합니다. 이 “AI Engineer” 에이전트를 한 번 보세요. GPT-4o랑 o1을 통합하겠다는 얘기나 잔뜩 들어 있고, 전체적으로는 그럴듯해 보이려 애쓴 자동 생성된 문장 수프에 가깝습니다. 이걸 쓴다고 해서 당신의 에이전트가 더 나은 “AI 엔지니어”가 되는 건 전혀 아닙니다.
그게 대체 무슨 의미일까요? 더 나은 출력을 얻고 싶다면, 모델에게 “너는 프로덕션급 LLM 애플리케이션에 특화된 AI 엔지니어야”라고 설정해 준다고 해서 상황이 달라지지 않습니다. 진짜 도움이 되는 건 문서, 예제, 그리고 해도 되는 것/하면 안 되는 것들입니다. 솔직히 말해, 이런 문구를 집어넣는 것보다는 차라리 에이전트에게 “AI 에이전트 구축 베스트 프랙티스를 구글링해서 읽어 와”라고 지시해서 몇 개 웹사이트를 컨텍스트에 로딩시키는 편이 훨씬 나은 결과를 줄 겁니다. 이런 문장 덩어리들은 오히려 컨텍스트를 오염시키는 쓰레기(context poison)라고 봐도 무방합니다.
내가 프롬프트를 작성하는 방법
Claude를 쓸 때만 해도 저는 (정확히 말하면 말로 떠들었지만요) 아주 긴 프롬프트를 쓰곤 했습니다. 이 모델은, 더 많은 컨텍스트를 줄수록 “나를 이해한다”는 느낌이 있었기 때문입니다. 사실 이건 어떤 모델이든 어느 정도는 맞는 말이긴 합니다. 그런데 codex로 옮기고 나니, 제 프롬프트 길이가 눈에 띄게 짧아졌습니다. 이제는 보통 한두 문장에 이미지 하나를 덧붙이는 정도가 전부입니다. 이 모델은 코드베이스를 읽어들이는 능력이 엄청 좋아서, 정말 “나를 알아듣습니다.” 심지어 가끔은, codex가 이해하는 데 필요한 컨텍스트 양이 너무 적다 보니, 예전보다 다시 키보드를 많이 치게 되기도 합니다.
이미지를 붙이는 건 컨텍스트를 늘리는 데 정말 놀라운 트릭입니다. 모델은 화면에 보이는 것들을 정확히 찾아내는 데 능숙합니다. 문자열을 읽고, 코드와 매칭해서, 제가 가리키는 위치를 바로 찾아갑니다. 제 프롬프트의 최소 50%에는 스크린샷이 들어갑니다. 저는 여기에 따로 주석을 다는 경우가 거의 없습니다. 주석을 달면 정확도는 더 올라가지만 속도가 느려지기 때문입니다. 스크린샷 하나 끌어다 터미널에 드롭하는 데는 2초밖에 안 걸립니다.
시맨틱 보정이 들어간 Wispr Flow는 여전히 왕입니다.
웹 기반 에이전트
최근에 Devin, Cursor, Codex 같은 웹 에이전트들을 다시 한 번 시험해 봤습니다. 구글의 Jules는 겉보기엔 괜찮아 보였지만, 설정 과정이 정말 짜증났고, Gemini 2.5는 이제 더 이상 좋은 모델이라고 부르기 힘든 수준입니다. Gemini 3 Pro가 나오면 상황이 달라질 수도 있겠죠. 이 중에서 결국 계속 쓰고 있는 건 codex web뿐입니다. 이쪽도 설정은 짜증 나고, 현재는 터미널이 제대로 로딩되지 않는 버그가 있긴 합니다. 다만 제 환경의 예전 버전이 있어서 그걸로 어떻게든 돌려 쓰고 있고, 그 대신 워밍업이 좀 더 느려지는 대가를 치르고 있습니다.
저는 codex web을 단기 이슈 트래커처럼 씁니다. 밖에 나가 있을 때 아이디어가 떠오르면, iOS 앱으로 한 줄만 적어두고, 나중에 맥에서 그걸 다시 봅니다. 마음만 먹으면 폰으로 더 많은 걸 할 수도 있고, 코드 리뷰나 머지도 할 수 있겠죠. 하지만 저는 일부러 그렇게 하지 않습니다. 지금도 일 자체가 이미 충분히 중독성이 강해서, 밖에 나가 있거나 친구들을 만날 때까지 더 끌려 들어가고 싶진 않거든요. 이렇게 말하는 저도, 사실은 폰으로 코딩하기 쉽게 만드는 도구를 두 달 가까이 만들어본 적이 있는 사람입니다.
예전에는 codex web 사용량이 아예 사용 제한에 잡히지도 않았습니다. 하지만 그 행복한 시절도 이제는 얼마 남지 않았습니다.
에이전틱 여정
이제 도구들에 대해 얘기해 봅시다. Conductor, Terragon, Sculptor, 그리고 그 밖의 수많은 것들. 어떤 건 취미 프로젝트이고, 어떤 건 VC 돈에 허우적대고 있습니다. 저도 이런 것들을 정말 많이 써봤지만, 결국 어느 것도 계속 쓰게 되진 않았습니다. 제 생각에 이 도구들은 대부분 현재 모델의 비효율을 둘러 가는 데 초점을 맞추고 있고, 결국 최선이 아닌 워크플로우를 부추깁니다. 게다가 대부분의 도구는 터미널을 숨겨 버리고, 모델이 실제로 어떤 걸 보고 있는지 전부 보여주지도 않습니다.
대부분은 Anthropic SDK에 얇게 래핑을 씌우고, 거기에 worktree 관리 정도만 덧댄 수준입니다. 해자(moat)라고 부를 만한 게 전혀 없습니다. 게다가, 정말로 “폰에서 코딩 에이전트에 더 쉽게 접근할 수 있어야 한다”는 게 좋은 목표인지도 의문입니다. 이런 도구들이 제게 제공했던 작은 사용 사례들은, codex web 하나면 이미 충분히 커버됩니다.
그렇지만 이런 패턴은 분명 존재합니다. 거의 모든 엔지니어가 한 번쯤은 자기만의 도구를 만드는 단계에 들어갑니다. 대부분 재미있기도 하고, 예전보다 훨씬 쉽게 만들 수 있기 때문이죠. 그리고 “무엇을 만들까?”라고 생각하면, 자연스럽게 “더 많은 도구를 더 쉽게 만들 수 있게 해 줄 도구”를 만들게 됩니다.
하지만 Claude Code는 백그라운드 작업을 지원
맞습니다. 현재 codex에는 Claude가 가진 몇 가지 번쩍이는 기능들이 없습니다. 그중에서 가장 아픈 부분은 백그라운드 작업 관리입니다. 적당한 타임아웃이 있어야 하는데, 실제로는 dev 서버를 띄우는 작업이나 데드락 걸린 테스트처럼 끝나지 않는 CLI 작업에 꽤 자주 갇히는 모습을 봤습니다.
이게 제가 한때 Claude로 돌아갔던 이유 중 하나였습니다. 하지만 그 모델은 다른 면에서 너무 멍청해서, 지금은 대신 tmux를 씁니다. tmux는 오래된 도구이지만, CLI를 백그라운드의 지속 세션으로 돌릴 수 있게 해 줍니다. 이미 모델 안에는 tmux에 대한 세계 지식이 충분히 들어 있으니, 그냥 “tmux로 실행해 줘(run via tmux)”라고만 말하면 됩니다. 별도의 커스텀 에이전트 마크다운 쇼를 벌일 필요가 없습니다.
MCP
MCP에 대해서는 다른 사람들이 이미 글을 많이 썼습니다. 제 생각에, MCP의 대부분은 마케팅 부서가 체크박스를 채우고 뿌듯해하기 위한 장치에 가깝습니다. 거의 모든 MCP는 사실 CLI였어야 합니다. 저도 직접 MCP를 다섯 개나 만들어 본 사람으로서 하는 말입니다.
저는 그냥 CLI 이름만 언급하면 됩니다. 에이전트 파일에 그에 대한 장황한 설명을 적어 둘 필요가 없습니다. 에이전트는 첫 호출에서 대충 $randomcrap 같은 명령을 시도해 볼 것이고, CLI는 도움말 메뉴를 출력합니다. 그러면 컨텍스트 안에 이미 “이 도구가 어떻게 동작하는지”에 대한 정보가 다 들어가게 되고, 그다음부터는 문제없이 쓸 수 있습니다. MCP와 달리, 이런 도구들을 위해 별도의 “컨텍스트세금(context tax)”을 치를 필요가 없습니다. GitHub MCP를 한 번 써 보면 23k 토큰이 순식간에 날아갑니다. 이마저도 개선된 뒤의 수치이고, 처음 나왔을 땐 거의 50,000 토큰에 달했습니다. 아니면 기능적으로 거의 동일한 gh CLI를 쓰면 됩니다. 모델은 이미 이 도구를 어떻게 쓰는지 알고 있고, 컨텍스트세금은 0입니다.
제가 만든 CLI 도구들 중 일부는 bslog, inngest처럼 오픈 소스로 공개해 두었습니다.
요즘 제가 쓰는 MCP는 chrome-devtools-mcp 정도입니다. 이건 웹 디버깅에서 “루프를 닫기 위해(close the loop)” 쓰고 있고, 덕분에 예전에는 Playwright로 하던 작업들을 대부분 대체했습니다. 자주 쓰는 건 아니지만, 필요할 때는 꽤 유용합니다. 저는 제 웹사이트를 설계할 때, 모델이 curl을 통해 어떤 엔드포인트든 직접 호출할 수 있도록 API 키를 만들 수 있게 해 두었습니다. 이게 대부분의 상황에서 더 빠르고 토큰 효율도 좋기 때문에, 이 MCP조차도 매일 필요하다고 느끼진 않습니다.
하지만 코드 품질은 별로다
제 시간의 약 20% 정도는 리팩터링에 씁니다. 물론 이 작업도 전부 에이전트가 합니다. 제가 손으로 직접 하는 데 시간을 낭비하지 않습니다. 리팩터링 데이는 집중력이 떨어지거나 피곤할 때 하기 좋습니다. 머리를 너무 많이 쓰지 않고도, 코드베이스를 꽤 크게 개선해 나갈 수 있기 때문입니다.
전형적인 리팩터링 작업 목록은 대략 이렇습니다. 코드 중복 탐지는 jscpd, 데드 코드 정리는 knip, eslint의 react-compiler와 deprecation 플러그인 실행, 통합될 수 있는 API 라우트를 새로 만든 건 없는지 점검, 문서 유지 보수, 너무 커진 파일 쪼개기, 까다로운 부분에 테스트와 코드 주석 추가, 의존성 업데이트, 툴 업그레이드, 파일 구조 재정리, 느린 테스트 찾고 다시 쓰기, 최신 React 패턴(예: 굳이 useEffect가 필요 없는 경우)을 언급하고 코드 다시 짜기 등등입니다. 할 일은 항상 넘쳐납니다.
이런 일들을 매 커밋마다 조금씩 해도 되지 않냐고 말할 수도 있겠죠. 하지만 제겐, 빠르게 기능을 쌓는 시기와, 나중에 코드베이스를 정리하고 개선하는 시기를 분리하는 편이 훨씬 생산적이고, 무엇보다 재미있습니다. 일종의 기술 부채를 갚는 기간이라고 보면 됩니다.
스펙 기반 개발을 하시나요?
예전에는, 6월쯤까지만 해도 큰 스펙을 먼저 설계해 두고, 그걸 모델에게 넘겨서 몇 시간 동안 계속 돌리게 두는 식으로 개발했습니다. 제 생각에 이제 이 방식은 “예전식” 소프트웨어 개발 방식에 가깝습니다.
지금은 보통 codex와 대화를 시작하는 방식으로 접근합니다. 관련된 웹사이트를 붙여 넣고, 제 아이디어를 좀 얘기하고, 코드도 읽어보라고 시키면서, 새 기능을 모델과 함께 살을 붙여 갑니다. 복잡한 기능일 경우에는, 일단 codex에게 전체 내용을 스펙으로 정리해 달라고 한 뒤 그 스펙을 GPT-5-Pro에게(예: chatgpt.com을 통해) 리뷰를 맡겨서 더 나은 아이디어가 있는지 확인합니다. 놀랍게도, 이 과정에서 제 계획이 크게 개선되는 경우가 꽤 많습니다. 그런 다음 제가 보기엔 의미 있어 보이는 부분들을 다시 메인 컨텍스트에 붙여 넣어 파일을 업데이트합니다.
이제는 어떤 작업이 얼마나 많은 컨텍스트를 요구하는지 감이 꽤 잡혀 있고, codex의 컨텍스트 용량도 넉넉한 편이라, 그냥 바로 구현부터 시작하는 경우가 많습니다. 어떤 사람들은 상당히 원리주의적으로, 항상 플랜용 새 컨텍스트를 따로 만들어 쓰기도 합니다. Sonnet 시절에는 그런 방식이 꽤 유용했지만, GPT-5는 큰 컨텍스트를 다루는 능력이 훨씬 좋습니다. 매번 새 컨텍스트를 파는 건, 결국 모델이 필요한 파일들을 다시 하나하나 읽어들이느라 작업마다 10분씩 그냥 날려버리는 셈이 됩니다.
UI 작업을 할 때는 이 과정이 훨씬 더 재미있습니다. 보통은 아주 단순하고, 솔직히 말해 “한참 모자란 수준”의 스펙만 적어 주고, 모델이 코드를 짜는 모습을 지켜보면서 브라우저가 실시간으로 업데이트되는 걸 봅니다. 그런 다음 추가 변경 사항들을 큐에 쌓아두고, 기능을 돌려가며 계속 손봅니다. 이 경우에는 저도 처음부터 “최종 모습”이 정확히 어떤 형태여야 할지 모를 때가 많기 때문에, 이런 식으로 아이디어를 가지고 놀면서, 구현이 서서히 형태를 잡아가는 과정을 그대로 지켜볼 수 있습니다. 그러다 보면 제가 미처 생각하지 못했던 흥미로운 UI를 codex가 만들어내는 경우도 자주 있습니다. 저는 리셋하지 않고, 그저 반복해서 바꾸고 다듬으면서, 이 혼돈을 점점 “딱 맞는 형상”으로 빚어 갑니다.
이렇게 작업하다 보면, 관련된 인터랙션이나 다른 부분에 대한 아이디어가 계속 떠오르기도 합니다. 그런 것들은 보통 다른 에이전트에서 처리하면서, 동시에 같이 다듬습니다. 그래서 보통은 하나의 메인 기능을 중심으로 작업하면서, 옆에 작은 관련 작업들을 몇 개씩 병렬로 진행하는 식입니다.
지금 이 글을 쓰는 시점에도, 저는 크롬 익스텐션에 새 Twitter 데이터 임포터를 만들고 있고, 이를 위해 기존 GraphQL 임포터를 재구성하고 있습니다. 이 접근이 맞는지 아직 좀 확신이 없어서, 그 작업은 별도 폴더에서 진행 중입니다. 나중에 PR 전체를 한 번에 보고, 이 방향이 괜찮은지 판단하려는 거죠. 그 사이 메인 레포 쪽에서는 리팩터링 작업이 돌아가고 있고, 저는 이렇게 글 쓰는 데 집중하고 있습니다.
슬래쉬 커맨드
저는 슬래시 커맨드를 몇 개만 가지고 있고, 그것도 자주 쓰지는 않습니다.
/commit(여러 에이전트가 같은 폴더에서 작업하고 있으니, 각자 수정한 파일만 커밋하라고 설명하는 커스텀 텍스트를 함께 보내는 명령입니다. 이렇게 해야 커밋 메시지가 깔끔하게 유지되고, 다른 에이전트가 만든 변경 때문에 linter가 실패했을 때 GPT가 괜히 겁먹고 전부 되돌리려 들지 않습니다.)/automerge(한 번에 하나의 PR만 처리하면서, 봇 코멘트에 대응하고, 필요하면 답글도 달고, CI가 초록불이 되면 자동으로 squash 머지하는 플로우입니다.)/massageprs(/automerge와 비슷하지만 squash는 하지 않습니다. PR이 아주 많을 때 병렬로 돌리기 좋습니다.)/review(기본 제공 명령입니다. GitHub에 리뷰 봇이 따로 있어서 자주 쓰진 않지만, 가끔은 유용합니다.)
그리고 사실 이 명령들이 있어도, 대부분의 경우 저는 그냥 “commit”이라고만 입력합니다. 진짜로 더러운 파일이 너무 많아서, 가이던스가 없으면 에이전트가 망가질 게 뻔한 상황이 아니라면요. 괜히 과한 쇼를 벌이면서 컨텍스트를 낭비할 필요가 없습니다. 이런 부분들도 결국에는 “감”이 생깁니다. 아직까지는, 이거 말고 정말 유용하다고 느낀 슬래시 커맨드는 별로 못 봤습니다.
또 다른 팁
에이전트가 오래 걸리는 작업을 끝까지 하도록 만들기 위해 “완벽한 프롬프트”를 고민하기보다는, 더 게으른 꼼수를 쓰는 편이 낫습니다. 큰 리팩터링을 시켜 보면, codex는 종종 중간 단계에서 답변을 멈춥니다. 이때 자리를 비우고 돌아와서 결과만 보고 싶다면, 미리 continue 같은 메시지를 줄줄이 큐에 쌓아두면 됩니다. 만약 codex가 작업을 이미 끝낸 뒤에 추가 메시지를 받게 되면, 그냥 기쁘게 무시해 버립니다.
각 기능이나 버그 수정을 마칠 때마다, 모델에게 **“이제 방금 변경에 대한 테스트를 써줘”**라고 요청해 보세요. 같은 컨텍스트를 그대로 사용한 상태에서요. 이렇게 하면 훨씬 더 나은 테스트가 나올 가능성이 높고, 구현에 숨어 있던 버그를 찾아낼 확률도 커집니다. 순수한 UI 미세 조정이라면 테스트까지 만드는 게 그리 큰 의미는 없겠지만, 그 외의 거의 모든 경우에는 이걸 하는 편이 좋습니다. AI가 “정말 잘 설계된 테스트”를 쓰는 데는 아직 서투른 편이지만, 그래도 꽤나 도움이 되며, 솔직히 말해서… 당신은 진짜로 모든 수정에 테스트를 직접 쓰고 있나요?
모델에게 “내 의도를 유지해 달라”, “까다로운 부분에는 코드 코멘트를 추가해 달라”고 부탁하는 것도 좋습니다. 이건 미래의 “나”에게도 도움이 되고, 나중에 다시 이 코드를 읽게 될 모델에게도 도움이 됩니다.
문제가 어려워질수록, 프롬프트에 특정 트리거 문구를 추가하면 좋습니다. 예를 들면 “시간 충분히 써도 돼(take your time)”, “철저하게(comprehensive)”, “관련될 수 있는 코드는 전부 읽어봐(read all code that could be related)”, “가능한 가설들을 세워봐(create possible hypothesis)” 같은 표현들입니다. 이렇게 써두면 codex는 꽤 난도 높은 문제들도 놀라울 정도로 잘 풀어냅니다.
Agents/Claude 파일 구조
저는 Agents.md라는 파일 하나를 두고, Anthropic이 표준을 맞추지 않겠다고 결정한 바람에, 여기에 claude.md로 심볼릭 링크를 걸어 두었습니다. 이 방식이 어렵고 최선은 아니라는 걸 저도 잘 압니다. GPT-5가 Claude와는 꽤 다른 프롬프트 스타일을 선호하기 때문입니다. 이 부분을 아직 안 읽어보셨다면, 여기서는 잠깐 멈추고 GPT-5 프롬프트 가이드를 먼저 읽어보시는 걸 추천합니다.
Claude는 “이 명령을 제대로 수행하지 않으면 100마리의 아기 고양이가 죽을 것이다” 같은, 🚨 대문자로 된 과격한 명령 🚨에 꽤 잘 반응합니다. 하지만 GPT-5에게 이런 식으로 말하면, 이쪽은 도리어 화들짝 겁을 먹습니다. (사실 이게 더 정상적인 반응이죠.) 따라서 이런 톤은 전부 버리고, 그냥 사람에게 말하듯 평범한 언어를 사용하는 편이 낫습니다. 이런 이유들 때문에, 이 에이전트 파일을 두 모델 사이에서 “완벽하게 공유”하는 건 불가능에 가깝습니다. 하지만 저는 어차피 대부분 codex만 쓰고, 가끔 Claude가 필요할 때는 조금 덜 최적화된 지시를 쓰는 정도는 감수합니다.
제 에이전트 파일은 지금 약 800줄 정도 되고, 일종의 “조직에 남은 흉터들을 모아 놓은 문서” 같은 느낌입니다. 이걸 제가 직접 쓴 것도 아니고, 대부분 codex가 작성했습니다. 뭔가 일이 생길 때마다, 저는 codex에게 “방금 겪은 문제를 에이전트 파일에 간결하게 메모해 둬”라고 시킵니다. 언젠가는 한 번 정리를 해야겠지만, 분량이 이 정도로 커졌는데도 놀라울 만큼 잘 작동하고 있고, GPT 계열은 그 안의 지시를 꽤 성실하게 따라줍니다. 적어도, Claude가 그랬던 것보다 훨씬 자주 말입니다. (공평하게 말하자면, Sonnet 4.5에서는 이런 부분이 꽤 나아지긴 했습니다.)
이 파일에는 git 작업 지침 외에도, 제가 만들고 있는 제품에 대한 설명, 선호하는 네이밍/API 패턴, React Compiler 관련 메모들이 들어 있습니다. 제 기술 스택이 꽤 최첨단이라, 이 문서에 들어 있는 내용은 세계 지식보다 더 최신인 경우도 많습니다. 모델이 업데이트될 때마다, 이 파일에서 내용 일부를 지워도 되겠지 기대하고 있습니다. 예를 들면, Sonnet 4.0 시절에는 Tailwind 4를 이해시키려면 별도의 가이드가 꼭 필요했지만, Sonnet 4.5와 GPT-5는 이미 Tailwind 4를 “기본 지식”으로 알고 있어서, 그때 추가해 둔 설명들을 통째로 지워버릴 수 있었습니다.
문서의 상당 부분은, 제가 선호하는 React 패턴, 데이터베이스 마이그레이션 관리, 테스트 전략, 그리고 ast-grep 규칙을 쓰고 활용하는 법에 대해 할애되어 있습니다. (만약 아직 ast-grep을 코드베이스용 린터로 쓰고 있지 않다면, 여기서 잠깐 멈추고, “ast-grep을 git 훅으로 설정해서, 특정 규칙을 어기는 커밋을 막아 달라”고 지금 쓰고 있는 모델에게 시켜보는 걸 추천합니다.)
또한, 화면이 어떻게 보여야 하는지를 텍스트로 정의하는 텍스트 기반 “디자인 시스템”도 실험적으로 도입해 봤습니다. 이게 얼마나 좋은 접근인지에 대해서는 아직 판단이 완전히 서지는 않았습니다.
그래서 GPT-5-Codex는 완벽한가?
당연히 아닙니다. 가끔은 30분 동안 리팩터링을 하다가 갑자기 패닉이 와서 모든 변경을 한꺼번에 되돌려 버리기도 합니다. 그럴 때는 작업을 다시 시키고, “시간 충분하니까 천천히 해도 된다”고 아기를 달래듯 안심시켜야 합니다. 또 가끔은 자기가 bash 명령을 실행할 수 있다는 사실을 잊어버리는지, 몇 번 격려를 해 줘야만 쉘 명령을 쓰기 시작하기도 합니다. 드물게는 러시아어나 한국어로 답변을 내놓을 때도 있고요. 아주 가끔은, “몬스터”가 미끄러져서 원래 숨겨야 할 thinking을 그대로 bash에 쳐 넣어버리기도 합니다. 그렇지만 이런 일들은 전반적으로 꽤 드뭅니다. 나머지 거의 모든 면에서 워낙 압도적으로 잘하기 때문에, 저는 이런 결함들을 충분히 눈감아 줄 수 있습니다. 사람들도 완벽하지 않죠.
codex에 대해 제가 가장 짜증 나는 점 하나를 꼽자면, 출력 줄들을 “잃어버리는” 버그입니다. 스크롤을 조금만 빨리 올려도, 화면 일부가 사라져 버립니다. 이 문제가 OpenAI의 버그 리스트 최상단에 있기를 진심으로 바랍니다. 이 버그 때문에 저는 가끔 속도를 줄이고, 메시지가 사라지지 않게 조심스럽게 터미널을 써야 합니다.
결론
RAG, 서브에이전트, Agents 2.0 같은 것들에 너무 많은 시간을 쓰지 마세요. 이들 중 상당수는 결국 “겉멋 퍼포먼스”에 가깝습니다. 그냥 모델에게 말을 거세요. 가지고 놀아 보고, 감을 기르세요. 에이전트와 함께 일하는 시간이 늘어날수록, 결과도 점점 더 좋아질 겁니다.
Simon Willison의 글은 아주 중요한 지적을 합니다. 에이전트를 잘 다루는 데 필요한 많은 스킬들이, 사실 엔지니어들을 관리할 때 필요한 스킬과 매우 비슷합니다. 그리고 이런 역량의 대부분은, 시니어 소프트웨어 엔지니어들의 특징이기도 합니다.
그리고 물론, 좋은 소프트웨어를 만드는 일은 여전히 어렵습니다. 제가 더 이상 직접 코드를 치지 않는다고 해서, 아키텍처, 시스템 디자인, 의존성 관리, 기능 설계, 사용자 경험을 어떻게 즐겁게 만들지에 대해 깊이 고민하지 않는 건 아닙니다. AI를 도입했다는 건, 단지 “내가 만들어야 하는 결과물에 대한 기대치”가 더 높아졌다는 뜻일 뿐입니다.
추신: 이 글은 100% 사람이 직접 쓴, “오가닉” 텍스트입니다. 저는 AI를 정말 좋아하지만, 어떤 일들은 여전히 옛날 방식대로 하는 편이 훨씬 낫다는 것도 알고 있습니다. 오타도 그대로 두고, 제 목소리도 그대로 남겨두죠. 🚄✌️
추신 2: 헤더 그래픽의 크레딧은 Thorsten Ball에게 돌아갑니다.