코딩 에이전트의 CLI가 자동화 API가 되어서는 안 되는 이유
요약
코딩 에이전트의 CLI 인터페이스를 자동화 API로 직접 사용하는 것의 위험성을 경고합니다. CI/CD와 같은 자동화 환경에서는 인간을 위한 대화형 CLI 대신 구조화된 상태와 명확한 세션 경계를 제공하는 API 계층이 필요함을 강조합니다.
핵심 포인트
- CLI는 인간용 인터페이스이며 자동화 계약(contract)으로는 부적합함
- 에이전트의 대화 방식 변화는 자동화 파이프라인의 결합도를 높임
- 자동화 시스템을 위해 구조화된 상태와 명확한 세션 경계가 필요함
- AgentAPI와 같은 HTTP 제어 계층을 통한 통합 접점 구축 권장
대화형 코딩 에이전트(interactive coding agent)를 기다리고 있는 CI 작업을 상상해 보세요. 프로세스는 안심시키는 듯한 산문을 스트리밍하고, 아무도 대답할 수 없는 질문을 던지며, 몇 개의 파일을 수정하고, 마침내 작업이 완료되었다고 출력합니다. 그리고 종료 코드 0(code 0)과 함께 종료됩니다.
하지만 풀 리퀘스트(pull request)는 여전히 안전하게 진행될 수 없습니다. 기계는 에이전트가 의도한 파일을 변경했는지, 필요한 체크(checks)를 실행했는지, 단계를 건너뛰었는지, 아니면 그럴듯한 설명을 내놓은 뒤 조용히 포기했는지 알 수 없기 때문입니다.
터미널은 개발자에게는 훌륭한 인터페이스(surface)가 될 수 있지만, 자동화(automation)를 위한 계약(contract)으로는 끔찍합니다. 인간은 대화를 해석하고, 요청을 명확히 하며, 에이전트가 경로를 벗어났을 때 이를 알아차릴 수 있습니다. 반면 CI는 명시적인 상태(state)와 아티팩트(artifacts)가 필요합니다.
CLI는 운영자(operators)를 위해 남겨두세요. 해당 CLI와 나머지 전달 시스템(delivery system) 사이에 작은 작업(task), 세션(session), 그리고 결과(result) 경계를 설정하십시오.
하나의 에이전트에는 매우 다른 두 명의 소비자가 있습니다
코딩 도구들은 이제 에디터 어시스턴트(editor assistants), 터미널 에이전트(terminal agents), 브라우저 빌더(browser builders), 풀 리퀘스트 봇(pull-request bots), 그리고 API 기반 서비스(API-driven services)의 형태로 나타납니다. 이러한 다양성은 워크플로(workflows)가 다르기 때문에 유용합니다. 코드베이스를 탐색하는 엔지니어는 모든 새로운 풀 리퀘스트를 검토하는 CI 작업과는 다른 상호작용(interaction)을 필요로 합니다.
실수는 모든 다운스트림 시스템(downstream system)이 오늘 설치된 에이전트의 대화 습관을 학습하도록 만드는 것입니다.
| 운영자는 ... 할 수 있습니다 | 자동화에는 ... 가 필요합니다 |
|---|---|
| 스트리밍되는 산문을 읽을 수 있음 | 구조화된 상태 (structured status) |
| ... | ... |
터미널 포맷팅(formatting)은 변경됩니다. 프롬프트(prompts)도 변경됩니다. 에이전트 버전이 업데이트되면서 새로운 질문과 새로운 모드(modes)가 추가됩니다. 만약 파이프라인(pipeline)이 이러한 세부 사항을 맞추는 것에 의존한다면, 그 파이프라인은 사람을 위해 설계된 인터페이스에 결합(coupled)된 것입니다.
그러한 결합은 관리되지 않는 첫 번째 실행이 프롬프트에서 멈추거나, 다음 단계에서 기대하는 아티팩트(artifact)를 생성하지 못한 채 성공을 보고하기 전까지는 대개 보이지 않습니다.
프로세스 상단에 작은 세션 경계를 두십시오
AgentAPI는 이러한 아키텍처적 변화의 한 가지 구체적인 버전입니다. 이는 여러 코딩 에이전트(coding-agent) CLI 앞에 HTTP 제어 계층(control layer)을 배치하며, 풀 리퀘스트(pull-request) 리뷰 및 MCP 통합과 같은 사용 사례를 문서화합니다. 이 프로젝트는 모든 에이전트가 동일하게 동작한다는 것을 증명하지 않고도 통합 접점(integration seam)을 구체화합니다.
자동화 경계(automation boundary)는 작게 유지될 수 있습니다. 경계는 다음과 같은 질문에 답할 수 있을 만큼 충분한 구조를 갖추어야 합니다:
- 호출자가 제출한 작업은 무엇인가?
- 어떤 세션이 해당 작업을 소유하고 있는가?
- 실행 상태가 대기 중(queued), 활성(active), 승인 대기(waiting for approval), 완료(complete), 실패(failed), 시간 초과(timed out), 또는 취소(canceled) 중 어느 것인가?
- 실행이 종료되었을 때 호출자가 무엇을 검색(retrieve)할 수 있는가?
HTTP는 서비스에 적합할 수 있습니다. 로컬 감독자(local supervisor)는 파일, 소켓(socket), 또는 작업 큐(job queue)를 통해 동일한 계약(contract)을 노출할 수 있습니다. 어떤 구현 방식이든 터미널의 산문(prose) 대신 기계가 이해할 수 있는 구조화된 상태(structured state)를 제공할 수 있습니다.
다음은 제안된 표준이 아닌, 예시적인 작업 요청입니다:
repository: payments-service
goal: add validation for expired checkout sessions
constraints:
...
어댑터(adapter)는 해당 요청을 선택된 에이전트가 이해할 수 있는 형태로 번역합니다. 또한 프로세스 동작을 다시 세션 상태(session state)로 번역합니다. 어댑터 상위의 워크플로(workflow)는 에이전트가 스피너(spinner)를 출력하는지, 전체 화면 터미널 인터페이스를 여는지, 또는 업데이트 후에 권한 요청 문구를 다르게 표현하는지 알 필요가 없어야 합니다.
구조화된 경계가 출력의 정확성을 보장할 수는 없습니다. 다만 다른 시스템이 다음 단계에서 무엇을 할지 결정할 수 있을 만큼 실행 과정을 관찰 가능(observable)하게 만들 수는 있습니다.
코드 옆에 작업 정의의 버전을 관리하십시오
비공개 프롬프트 레시피(private prompt recipes)는 팀 자동화를 위한 나쁜 기반입니다. 레시피가 언제 변경되었는지, 어떤 리포지토리(repository) 가정을 포함하고 있는지, 또는 왜 한 엔지니어가 다른 엔지니어와 다른 결과를 얻는지 아무도 검토할 수 없기 때문입니다.
Auggie는 대화형 터미널 에이전트를 코드베이스 인식(codebase-aware) 커스텀 명령 및 GitHub Actions 워크플로와 결합합니다. 이러한 배치는 반복 가능한 작업 정의를 팀이 소유하고 버전 관리되는 프로젝트 컨텍스트(context) 내에 유지합니다.
리포지토리 작업은 다음과 같이 정의될 수 있습니다:
- 에이전트가 검사하거나 수정할 수 있는 파일들
- 필수 체크 항목 및 타임아웃 (timeout)
- 항상 승인이 필요한 명령 (commands)
- 리뷰 작업 (review job)이 반환해야 하는 결과물 (artifacts)
- 부분적인 실행을 실패로 전환하는 조건들
이러한 규칙들을 검토하는 것이 좋은 에이전트 출력 (output)을 보장하는 것은 아닙니다. 그것은 더 근본적인 역할을 수행합니다. 바로 자동화에 대한 변경 사항을 가시화(visible)하는 것입니다. 풀 리퀘스트 (pull request)를 통해 팀이 쓰기 가능한 경로를 확장했거나, 체크 항목을 제거했거나, 혹은 결정이 향후 모든 실행에 도달하기 전에 예상되는 결과물 (artifact)을 변경했다는 사실을 보여줄 수 있습니다.
에이전트는 여전히 작업 내에서 추론할 수 있는 여지를 가집니다. 전달 시스템 (delivery system)은 그 주변의 경계에 대한 소유권을 유지합니다.
성공적인 프로세스 종료가 수락을 의미하지는 않는다
에이전트 자동화는 종종 세 가지 서로 다른 이벤트를 하나로 뭉뚱그려 처리하곤 합니다:
- 에이전트 프로세스가 중단됨
- 에이전트가 완료했다고 주장함
- 요청된 작업이 수락 체크 (acceptance checks)를 통과함
오직 세 번째 이벤트만이 다음 전달 단계 (delivery step)를 해제해야 합니다.
의도 (Intent)는 기능 설명 (feature description)으로 시작하여 격리된 작업, 검증, 그리고 전달로 이어지는 라이프사이클 (lifecycle)을 중심으로 배치됩니다. 그것은 제품 작성자가 작성한 설명이지, 워크플로 (workflow)에 대한 독립적인 증거가 아닙니다. 이는 여전히 올바른 통합 질문을 가리킵니다: 작업이 완료되었을 때 어떤 증거가 경계를 넘어오는가?
코딩 작업의 경우, 결과 계약 (result contract)은 다음과 같은 사항을 요구할 수 있습니다:
- 허용된 범위 내의 변경 사항을 포함하는 패치 (patch) 또는 커밋 (commit)
- 지정된 체크 항목의 종료 상태 (exit status) 및 출력값
- 변경된 영역과 의도적으로 건드리지 않은 영역에 대한 짧은 요약
- 예상된 결과물 (artifact)이 누락되었을 때의 기계 판독 가능한 실패 이유
로그 (logs)는 진단에 도움이 되지만, 대화 기록 (transcript)을 그대로 쏟아내는 것은 결과 계약이 아닙니다. 다운스트림 리뷰어 (downstream reviewer)가 테스트가 실행되었는지 확인하기 위해 대화 내용을 다시 재생해야 해서는 안 됩니다. 디프 (diff), 체크 항목, 그리고 제한된 범위의 요약을 직접 제공하십시오.
부분적인 작업(Partial work)에도 동일한 정밀함이 필요합니다. 만약 에이전트가 코드를 변경했지만 필수 테스트가 시간 초과(timeout)되었다면, 패치(patch)를 보존하고 실패한 수락 상태(failed acceptance state)를 반환해야 합니다. 이렇게 하면 리뷰어는 잘못된 성공 신호를 받지 않으면서도 유용한 결과물(artifact)을 유지할 수 있습니다.
원하는 것보다 덜 정규화하십시오 (Normalize less than you want to)
한 팀이 하나의 경계(boundary) 뒤에 두 개의 에이전트를 두게 되면, 보편적인 에이전트 프로토콜(universal agent protocol)을 설계하고 싶은 유혹에 빠지게 됩니다. 하지만 그러한 추상화는 빠르게 비용이 많이 들게 됩니다.
에이전트들은 컨텍스트 처리(context handling), 리뷰 모드(review modes), 도구 제어(tool controls), 권한 모델(permission models), 그리고 리포지토리 인식(repository awareness) 측면에서 서로 다릅니다. 이 모든 것을 최소 공통 분모(lowest common denominator)로 평탄화(flatten)해 버리면, 래퍼(wrapper)가 특정 에이전트를 선택했던 정당한 기능들을 지워버릴 수 있습니다.
지루한 부분들은 정규화하십시오:
- 작업 입력 (task input)
- 세션 식별 및 생명주기 (session identity and lifecycle)
- 실행 범위 (execution scope)
- 취소 및 실패 (cancellation and failure)
- 필수 결과물 (required result artifacts)
네이티브 기능들은 의도적이고 명명된 확장 기능(named extensions) 뒤에 유지하십시오. 에이전트 전용 리뷰 모드를 선택하는 워크플로(workflow)는 이를 명시해야 합니다. 이식성(Portability)은 계약(contract)이 무엇이 이식 가능한지에 대해 진실을 말할 때에만 유용합니다.
직접적인 CLI 사용 또한 대화형 로컬 작업, 실험, 그리고 운영자(operator)가 주도하는 일회성 작업을 위한 올바른 선택으로 남아 있습니다. 모든 터미널 세션을 서비스로 바꿀 필요는 없습니다. 경계(boundary)는 다른 머신이 그 결과에 의존할 때 비로소 필요해집니다.
5부 구성의 계약 (The five-part contract)
에이전트를 CI 또는 내부 도구에 연결하기 전에, 다섯 가지를 정의하십시오.
1. 작업 계약 (Task contract)
리포지토리, 목표, 제약 조건, 그리고 수락 검사(acceptance checks)를 명시하십시오. 단 한 명의 호출자(caller)만이 알고 있는 프롬프트 산문(prompt prose) 속에 지속적인 요구 사항을 숨기지 마십시오.
2. 세션 계약 (Session contract)
시작, 진행, 승인, 취소, 시간 초과(timeout), 그리고 실패를 명시적인 상태(explicit states)로 나타내십시오. 터미널 출력으로부터 이를 추론하지 마십시오.
3. 실행 계약 (Execution contract)
워크스페이스(workspace), 쓰기 가능한 파일, 사용 가능한 도구, 네트워크 액세스, 그리고 승인 경계(approval boundaries)를 선언하십시오. API 래퍼(wrapper)는 정의되지 않은 권한 모델(authority model)을 보완할 수 없습니다.
4. 결과 계약 (Result contract)
diff, 테스트 결과, 로그, 요약 또는 다음 시스템이 실행(run)을 평가할 수 있게 해주는 기타 아티팩트 (artifact)를 요구해야 합니다. 프로세스 완료와 작업 수락은 별개의 사실입니다.
5. 기능 탈출구 (Capability escape hatch)
워크플로가 의도적으로 네이티브 기능 (native feature)을 요청할 수 있도록 허용하십시오. 워크플로가 모든 에이전트에서 동일하게 동작할 것처럼 가장하는 대신, 해당 의존성 (dependency)을 명시하십시오.
이 다섯 가지 요소는 실무적인 검토 체크리스트이며, 업계 표준은 아닙니다. 소규모 팀은 로컬 감독자 (local supervisor)와 결과 디렉토리 (result directory)를 통해 이를 구현할 수 있습니다. 플랫폼 팀은 API, 작업 큐 (job queue), 아티팩트 저장소 (artifact store)를 사용할 수 있습니다. 두 구현 방식 모두 동일한 좁은 범위의 계약 (contract)을 강제할 수 있습니다.
실행 과정을 먼저 검토 가능하게 만드십시오
코딩 에이전트를 자동화된 배포 경로에 추가하기 전에, 팀은 다음 다섯 가지 질문에 답할 수 있어야 합니다:
- 정확히 무엇이 작업을 시작하는가?
- 호출자 (caller)가 세션을 관찰, 취소 또는 타임아웃 시키는 방법은 무엇인가?
- 어떤 리소스와 권한이 실행 (run)을 제한하는가?
- 어떤 아티팩트와 체크 사항이 수락을 증명하는가?
- 어떤 부분이 네이티브 에이전트 기능 (native agent capability)에 의존하는가?
만약 답변이 프롬프트 (prompt)와 터미널 기록 (terminal transcript)에만 존재한다면, 그 시스템은 API에 의존하는 것이 아니라 대화를 자동화하고 있는 것입니다.
정직한 경계 설정은 에이전트를 교체하기 더 쉽게 만들 수도 있습니다. 더 즉각적으로는, 검토자가 에이전트의 마지막 문장을 신뢰할 필요 없이 작업 내용을 판단할 수 있게 해줍니다.
출처 (Source notes)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기