다음에 올 것을 만들어가는 기술에 대한 심층 기사.

에이전틱 코딩 CLI의 내부: 루프, 컨텍스트, 권한

에이전틱 코딩 CLI가 실제로 작동하는 원리를 도구 호출 루프, 컨텍스트 관리, 권한 모델, 클라이언트/서버 설계 관점에서 살펴봅니다.

작은 빛나는 코어를 여러 겹의 톱니바퀴, 파이프, 밸브가 감싸고 있는 이미지로, 하네스와 모델의 대비를 나타냅니다.
에이전틱 코딩 CLI에서 모델은 작은 코어이고, 그 주변의 하네스가 기계의 대부분을 차지합니다.

모델은 쉬운 부분이라는 게 제 주장입니다. 지난 2년간 수십 개의 에이전틱 코딩 CLI가 등장하고, 포크되고, 비틀거리는 것을 지켜보면서 저는 이것이 사실이라고 생각하게 됐습니다. 에이전틱 코딩 CLI의 성패는 모델이 아니라 하네스(harness)에서 갈립니다. 이번 주 큰 관심을 받은 오픈소스 터미널 코딩 에이전트 OpenCode 2.0의 출시가 이 이야기를 꺼내기 좋은 계기입니다. 이번 릴리스에서 눈여겨볼 부분은 새로운 모델 연동이 아닙니다. 클라이언트/서버 분리, 핫 리로딩 플러그인, 백그라운드 실행 가능한 작업, 재설계한 에이전트 루프입니다. 즉 배관 공사입니다. 그리고 그 배관이 곧 제품입니다.

저는 전직 ML 엔지니어라서 이 결론이 조금 거슬렸습니다. 모델 품질이 차별점이었으면 했거든요. 하지만 제가 이런 도구를 계속 쓰거나 포기하는 이유를 돌아보면, 답은 한 번도 '모델이 똑똑해졌다'가 아니었습니다. '명령어마다 승인을 요구하지 않게 됐다'거나, '재시작 없이 설정을 다시 읽는다'거나, '원격 서버에서 도는 세션에 GUI를 붙일 수 있다'거나 하는 것들이었죠. 코딩 에이전트를 실제로 쓸모 있게 만드는 세 가지 하위 시스템, 즉 도구 호출 루프, 컨텍스트 관리, 권한 모델을 하나씩 뜯어보겠습니다. 그리고 역발상 주장이 어디서 무너지는지도 짚겠습니다.

도구 호출 루프는 분산 시스템이다

마케팅 수식어를 걷어내면 모든 코딩 에이전트는 같은 프로그램입니다. 프롬프트와 도구 목록을 가지고 모델을 호출하고, 텍스트나 도구 호출을 받고, 도구를 실행하고, 결과를 덧붙인 뒤 반복합니다. 이 루프는 단순해 보입니다. 하지만 전혀 단순하지 않으며, 이를 단순하게 취급한 도구는 실제로 몇 분만 써 봐도 어설프게 느껴집니다.

루프가 실제로 처리해야 할 것들을 생각해 보세요. 도구 실행은 실패합니다. 컴파일러가 에러를 내고, 테스트 스위트가 멈추고, 모델이 환각으로 만들어 낸 경로에는 파일이 없습니다. 모델은 도구 인자로 잘못된 JSON을 내보내기도 합니다. 도구 호출 하나가 40초 걸리는데 사용자가 실행 도중 Escape를 누르기도 합니다. 한 턴에 도구 호출이 두 개 들어왔는데 하나가 실패하면 다른 하나는 실행되면 안 되는 경우도 있습니다. 작업 도중 컨텍스트 윈도우가 가득 차면 무언가를 포기해야 합니다. 이 모든 문제는 지능의 문제가 아니라 동시성과 장애 처리의 문제입니다. 예전에 LLM 에이전트는 결국 분산 시스템이라는 글을 쓴 적이 있는데, 코딩 CLI가 그 가장 순수한 예입니다. 신뢰할 수 없고 비결정적인 원격 컴포넌트인 모델이 로컬의 부수효과를 가진 컴포넌트(셸, 파일시스템, LSP)와 조율해야 하고, 그 루프가 둘 사이의 합의 프로토콜 역할을 합니다.

OpenCode 2.0은 루프를 TypeScript 기반의 구조적 동시성과 타입 있는 에러 처리 프레임워크인 Effect 위에 다시 만들었다고 전해집니다. 이 선택은 팀이 루프를 'fetch가 들어 있는 while 문'으로 보지 않고, 중단 가능하고 조합 가능하며 재시도 가능한 이펙트들이 명시적인 에러 채널을 가진 시스템으로 보기 시작했다는 신호입니다. 에이전트 루프에 실제 취소 시맨틱이 있으면 '사용자가 Escape를 누름'은 상태를 망가뜨리는 사건이 아니라 일급 이벤트가 됩니다. 도구 결과에 타입이 있으면 실행 전에 모델의 출력을 검증할 수 있습니다. 이는 제약 디코딩과 잘 맞습니다. 모델의 출력 공간을 제한해서 잘못된 도구 호출을 잡아내는 대신 아예 불가능하게 만드는 방식이죠.

아무도 마케팅하지 않는 기능, 클라이언트/서버 구조

코딩 CLI가 내리는 가장 중요한 설계 결정 중 하나는 에이전트를 프로세스로 둘지 서비스로 둘지입니다. 프로세스 하나, 터미널 하나, 터미널이 죽으면 세션도 죽는 단순한 설계는 대부분의 도구가 처음 택한 방식이고, 명백한 한계입니다. OpenCode의 클라이언트/서버 모델은 오래 살아남는 서버가 세션을 소유하고, TUI, 데스크톱 앱, 웹 UI 등 여러 클라이언트가 그 서버에 붙는 구조입니다. 이 구조가 그 한계를 없앱니다. 실질적으로 말하면, 터미널을 닫아도 세션이 살아남고, 원격 개발 서버에서 에이전트를 돌리고 노트북의 네이티브 앱으로 조작할 수 있으며, 여러 인터페이스가 같은 세션을 함께 볼 수 있습니다.

VM에 SSH로 접속해서 에이전트를 돌리다가 재접속하면서 세션이 날아가 본 적이 있다면, 이것이 사소한 편의가 아니라는 걸 아실 겁니다. 장난감과 인프라의 차이죠. 오래 도는 에이전트는 빌드나 테스트 스위트와 같은 범주에 속합니다. 시작해 놓고 자리를 비웠다가 나중에 확인하는 것들이요. OpenCode 2.0의 백그라운드 실행 가능한 작업도 같은 방향입니다. 에이전트는 동기식 대화이기를 그만두고, 채팅 인터페이스를 가진 작업 실행기가 됩니다.

이제 단서를 달겠습니다. 이 의견은 일관되게 유지하고 있거든요. 서버 아키텍처가 곧 영구 데몬을 뜻하지는 않습니다. 여러 댓글 작성자가 모든 에이전트 하네스가 갑자기 사용자 머신에 상주하는 백그라운드 프로세스를 원하는 것 같다며 의심을 보였습니다. 그 직감은 옳습니다. 예전에 CLI 도구는 기본값으로 백그라운드 데몬을 설치하면 안 된다고 쓴 적이 있고, 지금도 그 입장입니다. 깔끔한 중간 지점이 있습니다. 필요할 때 서버를 띄우고, 프로젝트 디렉터리에 범위를 두고, 마지막 클라이언트가 연결을 끊으면 종료하는 것입니다. 그러면 세션 유지와 다중 클라이언트 연결은 얻으면서, 머신에서 항상 켜져 있는 프로세스가 외부와 통신하는 일은 막을 수 있습니다. OpenCode가 서버의 작업 디렉터리가 아니라 세션 폴더에서 설정을 읽는다는 점(2.0의 또 다른 변경)도 서버가 프로젝트를 따라야 하지 그 반대가 아니라는 걸 이해하고 있음을 보여줍니다.

컨텍스트 관리에 품질이 있다

한 시간쯤 작업한 뒤 에이전트가 '멍청해졌다'고 느끼는 이유를 실무자에게 물으면, 거의 항상 모델 퇴보가 아니라 컨텍스트 부패라고 답합니다. 윈도우가 오래된 도구 출력, 막다른 길, 40턴 전에는 관련 있었지만 지금은 아닌 파일 전체 내용으로 가득 찹니다. 모델은 건초 더미 속에서 결정을 내리고 있고, 명목상의 토큰 한계에 도달하기 훨씬 전부터 바늘 찾기 능력이 떨어집니다.

좋은 하네스는 컨텍스트를 파이프가 아니라 할당 정책이 있는 예산으로 다룹니다. 구체적으로는 여러 가지가 함께 작동합니다.

  • 도구 출력 잘라내기와 재조회 탈출구. 5,000줄짜리 테스트 로그는 실패한 40줄과, 모델이 다시 읽을 수 있는 경로에 전체 로그가 있다는 안내만 컨텍스트에 들어가야 합니다. 무엇이 중요한지는 하네스가 정하고, 더 필요한지는 모델이 정합니다.
  • 서브 세션과 서브 에이전트. '이 레포에서 인증이 어떻게 동작하는지 조사해서 보고해 줘' 같은 요청은 전체 탐색 기록이 아니라 요약본만 돌려주는 격리된 컨텍스트에서 실행되어야 합니다. OpenCode 2.0의 개선된 서브 세션 통신이 정확히 이 아이디어입니다.
  • 의도를 보존하는 컴팩션. 윈도우가 차면 지금까지의 대화를 요약해야 합니다. 요약을 대충 하는 하네스는 노이즈와 함께 사용자의 제약 조건('빌링 모듈은 건드리지 마')도 잃어버립니다. 좋은 컴팩션은 결정과 제약을 그대로 보존하고, 서술 부분만 압축합니다.
  • 설정과 스킬은 코드가 아니라 컨텍스트. 프로젝트 수준 지침, 플러그인이 정의한 도구, 스킬 파일은 모두 윈도우를 차지합니다. 이것들을 핫 리로딩하는 것(2.0의 또 다른 수정)이 중요한 이유는, 세션을 재시작하지 않고 에이전트의 컨텍스트를 고칠 수 있어야 에이전트 동작 자체를 반복해서 다듬을 수 있기 때문입니다.

이 중 어느 것도 모델의 지능이 아닙니다. 하지만 모두 모델이 얼마나 똑똑해 보이는지를 결정합니다. 허술한 컨텍스트 정책을 가진 최상위 모델은, 20분 넘게 걸리는 작업에서는 체계적인 정책을 가진 저렴한 모델에게 집니다.

수많은 문서 흐름을 가느다란 빛줄기로 압축하는 유리 깔때기 이미지로, 컨텍스트 압축을 상징합니다.
컨텍스트 관리는 판단을 동반한 압축입니다. 모든 것이 들어가고, 중요한 것만 나옵니다.

권한 모델: 채택 여부를 결정하는 지루하지만 중요한 기능

HN 토론에서 나온 질문 하나를 짚겠습니다. 이 분야에서 제가 가장 중요한 제품 질문이라고 생각하는 것입니다. '명령마다 승인'과 '욜로 모드' 사이에 뭔가가 있을 수 있을까요? 완전 자동 승인은 정말 위험합니다. 셸 접근 권한이 있는 코딩 에이전트는 한 턴 만에 rm -rf를 실행하고, git push --force를 하고, 환경 변수를 외부로 빼낼 수 있습니다. 완전 수동 승인은 정말 쓸 수 없습니다. 시간당 80개 명령을 승인하고 있다면 에이전트를 감독하는 게 아니라 느린 사람 키보드 인터럽트가 되는 셈입니다. 그 중간을 잘 잡는 도구가 실용주의자들을 얻습니다.

그 중간은 단계적 권한 모델이고, 그 설계 공간은 사람들이 생각하는 것보다 잘 정리되어 있습니다.

  • 읽기 전용 vs. 쓰기 vs. 실행. 읽기는 거의 공짜입니다. 쓰기는 프로젝트 트리로 범위를 제한해야 합니다. 실행은 정책이 가장 중요한 지점입니다.
  • 인자를 인식하는 허용 목록. git status는 자동 승인되고 git push는 묻습니다. 단순한 도구는 바이너리 이름만 매칭하지만, 좋은 도구는 동사와 플래그를 매칭합니다. npm test와 npm publish는 같은 바이너리지만 영향 범위는 완전히 다르니까요.
  • 세션 범위의 권한 부여. '이 세션에서 이 명령은 항상 허용'은 존재하는 권한 기능 중 가치가 가장 큰 것입니다. 프롬프트 일흔 번을 하나로 줄여 줍니다.
  • 되돌릴 수 없는 것에 대한 격리. 네트워크 접근, 프로젝트 디렉터리 바깥 접근, 자격 증명을 건드리는 작업은 프롬프트로 묻는 것이 아니라 구조적으로 제한되어야 합니다.

마지막 항목이 대부분의 하네스가 과소 투자하는 부분입니다. 프롬프트는 쉽고 격리는 어렵기 때문이죠. 하지만 프롬프트는 모델이 금요일 오후 6시에 사용자가 올바르게 답해 주기를 바라는 질문일 뿐입니다. 에이전트의 프로세스 트리를 샌드박싱하면, 즉 네트워크를 제한하고 파일시스템 마운트 범위를 좁히면, 모델이나 사용자가 무엇을 하든 전체 장애 유형이 불가능해집니다. 이 트레이드오프는 AI 에이전트의 격리 vs. 모니터링에서 자세히 다뤘습니다. 요약하면, 프롬프트는 모니터링이고 샌드박스는 격리이며, 되돌릴 수 없는 작업에는 격리가 필요합니다. CLI 생태계도 천천히 이걸 배우고 있습니다. 가장 빨리 배우는 도구가, 사용자가 지루한 90%에 대해 자동 승인을 실제로 켤 수 있을 만큼의 신뢰를 얻을 것입니다.

확장성과 셀프 호스팅 모델 문제

2.0 논의에서 얻을 수 있는 작은 교훈이 두 가지 있습니다. 첫째, '모든 것은 플러그인'이 이기고 있습니다. 사용자들은 이런 하네스 위에 스킬, 설정 편집기, 워크플로 훅을 만들고 있습니다. 플러그인을 일급 시민으로 만드는 하네스, 즉 핫 리로딩되고 세션을 관찰할 수 있으며 동작을 수정할 수 있는 하네스는 커뮤니티의 노력과 싸우지 않고 그 노력을 누적시킵니다. OpenCode가 이를 진지하게 여긴다는 신호는, 자체 GitHub 앱이 버그 리포트를 재현하고 발견 사항을 댓글로 남겨 분류한다는 점입니다. 사실상 에이전트로 에이전트를 유지보수하는 셈이죠. 사용자들이 칭찬한 '자기 인식'이 바로 그것이고, 이는 모델의 결과가 아니라 플러그인 아키텍처의 결과입니다.

둘째, 모델 중립성은 생각보다 어렵고, 이는 컨텍스트 포맷 문제입니다. 한 사용자는 bash 명령을 내도록 학습된 훌륭한 로컬 모델을 써 보려 했는데, 하네스는 JavaScript 방식의 도구 호출을 고집했고 둘은 서로 호환되지 않았습니다. 이것이 모든 에이전트 하네스에 숨어 있는 결합입니다. 도구 호출 포맷, 시스템 프롬프트의 가정, 모델의 학습 분포가 서로 맞아야 합니다. 특정 모델 계열의 관습을 하드코딩한 하네스는 모델 중립적이지 않고, 기껏해야 모델을 용인하는 수준입니다. 로컬 모델이 코딩 에이전트에서 중요해진다면(비용과 프라이버시 때문에 그래야 합니다), 하네스에는 플러그인 가능한 API 엔드포인트만이 아니라 플러그인 가능한 도구 호출 방언이 필요합니다.

역발상 주장이 무너지는 지점

모델이 쉬운 부분이라고 했으니, 이제 가장자리를 인정하겠습니다. 이 주장은 하네스 설계, 즉 루프, 컨텍스트, 권한에는 성립합니다. 하지만 모델이 실제로 병목인 곳도 있습니다. 도구 사용의 신뢰성 자체가 모델에 학습되어 있고, 유효한 함수 호출을 일관되게 내보내지 못하는 모델은 어떤 하네스든 고장 난 것처럼 보이게 만듭니다. Effect 기반의 구조적 동시성을 써도 자기 스키마와 다투는 모델은 고칠 수 없습니다. 긴 호흡의 다단계 계획은 한 세션 안에서도 체감될 만큼 모델 등급을 가릅니다. 그리고 하네스 대 모델이라는 구도에는 수명이 있습니다. 모델이 에이전트 행동을 학습에 흡수하면(네이티브 도구 사용, 네이티브 장기 계획), 기능이 하네스에서 가중치로 옮겨 갑니다. 오늘의 영리한 하네스 기능이 내일은 낭비되는 노력이 되는 것이죠. 하네스를 만드는 팀은 모델이 결국 쓸모없게 만들 비계를 짓고 있다고 가정해야 합니다. 솔직히 이는 플러그인 생태계를 갖춘 오픈소스 하네스에 대한 논거이기도 합니다. 그런 하네스는 일시적인 기능 격차가 아니라 커뮤니티 위에서 살아남기 때문입니다.

아키텍처가 면죄부를 줄 수 없는 UX의 최저선도 있습니다. 일부 사용자는 OpenCode 2.0을 써 보고도 여전히 어색하다고 느꼈고, 다른 사용자는 느린 시작과 계속 불어나는 죽은 채팅 기록 데이터베이스에 불만을 표했습니다. 깊은 문제는 아니지만, 우아한 에이전트 루프가 자랑할 기회를 얻기도 전에 사람들이 처음 10분 안에 도구에서 이탈하게 만드는 것들입니다. 완성도도 기능입니다. 그리고 오픈소스 프로젝트가 가장 자주 예산을 덜 주는 부분이기도 합니다.

코드는 모델이 쓰지만, 그 코드를 맡길 만큼 신뢰할지는 하네스가 결정합니다.

이 분야가 요동치는 것을 지켜본 사람으로서 실용적인 조언을 드리겠습니다. 코딩 에이전트를 고를 때는 모델 벤치마크 우승자를 고르듯 하지 말고, 데이터베이스를 고르듯 고르세요. 루프의 장애 처리, 컨텍스트 정책, 권한의 세분성, 그리고 터미널을 닫아도 세션이 살아남는지를 보세요. 다음 모델 출시로 모두가 다시 똑같이 똑똑해진 뒤에도 계속 중요한 부분이 바로 이것들입니다.