Capstone 01 — 터미널 네이티브 코딩 에이전트(Terminal-Native Coding Agent)

2026년에 이르러 코딩 에이전트(coding agent)의 형태는 거의 정착되었습니다. 터미널 사용자 인터페이스(TUI) 하네스(harness), 상태를 보존하는 계획(stateful plan), 샌드박스(sandbox)로 격리된 도구 표면(tool surface), 그리고 계획하고(plan), 행동하고(act), 관찰하고(observe), 복구하는(recover) 루프(loop)로 구성됩니다. Claude Code, Cursor 3, OpenCode를 멀리서 바라보면 모두 같은 구조처럼 보입니다. 이 캡스톤(capstone)은 그 구조를 처음부터 끝까지 직접 구현해 보도록 요구합니다. 명령행 인터페이스(CLI) 입력에서 시작해 풀 리퀘스트(pull request; PR)까지 이어지는 파이프라인을 만들고, SWE-bench Pro에서 mini-swe-agent와 Live-SWE-agent를 기준점으로 두고 측정합니다. 여기서 깨닫게 되는 핵심은 어려운 부분이 모델 호출이 아니라는 사실입니다. 진짜 까다로운 것은 도구 루프(tool loop), 샌드박스, 그리고 50턴 실행에서 비용 상한을 지키는 일입니다.

유형: Capstone 언어: TypeScript / Bun (하네스), Python (평가 스크립트) 선수 지식: Phase 11 (LLM 엔지니어링), Phase 13 (도구와 프로토콜), Phase 14 (에이전트), Phase 15 (자율 시스템), Phase 17 (인프라) 활용되는 Phase: P0 · P5 · P7 · P10 · P11 · P13 · P14 · P15 · P17 · P18 예상 시간: 35시간

문제

코딩 에이전트는 2026년 들어 가장 지배적인 인공지능(AI) 응용 범주로 자리 잡았습니다. Claude Code(Anthropic), Composer 2와 Agent Tabs를 갖춘 Cursor 3(Cursor), Amp(Sourcegraph), OpenCode(별 112k개), Factory Droids, Google Jules는 모두 동일한 아키텍처(architecture)의 변형을 출시했습니다. 터미널 하네스, 권한이 부여된 도구 표면(permissioned tool surface), 샌드박스, 그리고 프런티어 모델(frontier model)을 중심에 둔 plan-act-observe 루프가 공통 골격입니다. 프런티어의 폭은 좁습니다. Live-SWE-agent는 Opus 4.5로 SWE-bench Verified에서 79.2%에 도달했습니다. 하지만 엔지니어링 기술의 폭은 훨씬 넓습니다. 대부분의 실패 양상은 모델 자체의 실수가 아닙니다. 도구 루프의 불안정성, 문맥 오염(context poisoning), 토큰(token) 비용 폭주, 파괴적인 파일 시스템 작업이 주된 원인입니다.

이런 에이전트를 바깥에서 들여다보기만 해서는 그 동작을 추론할 수 없습니다. 직접 하나를 만들고, 47번째 턴에서 ripgrep이 8MB짜리 매치를 반환해 루프가 무너지는 장면을 직접 목격한 뒤, 잘라내기(truncation) 계층을 다시 설계해 보아야 합니다. 바로 그것이 이 캡스톤의 목적입니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.코딩 에이전트 하네스(harness)가 단일 LLM 호출이 아닌 plan-act-observe 루프를 필요로 하는 이유는 무엇인가요?

2.코딩 에이전트 아키텍처에서 샌드박스(sandbox, 예: E2B, Daytona 데브컨테이너)의 역할은 무엇인가요?

0/2 답변 완료

개념

하네스는 네 가지 표면으로 이루어집니다. Plan은 TodoWrite 형태의 상태 객체를 유지하고, 모델은 매 턴마다 이 상태를 통째로 다시 작성합니다. Act는 도구 호출(read, edit, run, search, git)을 디스패치(dispatch)합니다. Observe는 표준 출력(stdout) / 표준 에러(stderr) / 종료 코드(exit code)를 수집하고, 잘라낸 뒤, 요약을 다시 모델에게 돌려보냅니다. Recover는 도구 오류를 처리하면서도 문맥 창(context window)을 터뜨리거나 무한히 반복하지 않도록 합니다. 2026년의 형태에는 한 가지 요소가 더해집니다. 바로 훅(hooks)입니다. PreToolUse, PostToolUse, SessionStart, SessionEnd, UserPromptSubmit, Notification, Stop, PreCompact 여덟 개의 확장 지점이 있고, 운영자는 이 지점에 정책, 텔레메트리(telemetry), 가드레일(guardrail)을 주입할 수 있습니다.

샌드박스로는 E2B 또는 Daytona를 사용합니다. 각 작업은 git worktree가 읽기·쓰기로 마운트(mount)된 새로운 데브컨테이너(devcontainer)에서 실행됩니다. 하네스는 호스트(host) 파일 시스템을 절대 직접 건드리지 않습니다. worktree는 작업이 성공하든 실패하든 마지막에 폐기됩니다. 비용 제어(cost control)는 세 계층에서 강제됩니다. 턴별 토큰 상한, 세션(session)별 달러 예산, 그리고 보통 50턴인 하드 턴 제한입니다. 관측성(observability) 계층은 GenAI 의미 규약(semantic conventions)을 따르는 OpenTelemetry 스팬(span)으로 구성되며, 자체 호스팅(self-hosted) Langfuse로 전송됩니다.

아키텍처

  user CLI  ->  harness (Bun + Ink TUI)
                  |
                  v
           plan / act / observe loop  <--->  Claude Sonnet 4.7 / GPT-5.4-Codex / Gemini 3 Pro
                  |                          (OpenRouter 경유, model-agnostic)
                  v
           tool dispatcher (MCP StreamableHTTP client)
                  |
     +------------+------------+----------+
     v            v            v          v
  read/edit    ripgrep     tree-sitter   git/run
     |            |            |          |
     +------------+------------+----------+
                  |
                  v
           E2B / Daytona sandbox  (worktree isolated)
                  |
                  v
           hooks: Pre/Post, Session, Prompt, Compact
                  |
                  v
           OpenTelemetry -> Langfuse (spans, tokens, $)
                  |
                  v
           PR via GitHub app

스택

  • 하네스 런타임: Bun 1.2 + Ink 5 (터미널 안에서 동작하는 React)
  • 모델 접근: OpenRouter 통합 API를 사용해 Claude Sonnet 4.7, GPT-5.4-Codex, Gemini 3 Pro, Opus 4.5(가장 까다로운 작업용)에 접근
  • 도구 전송: Model Context Protocol StreamableHTTP (MCP 2026 개정판)
  • 샌드박스: E2B sandboxes (JS SDK) 또는 Daytona devcontainers
  • 코드 검색: ripgrep 서브프로세스(subprocess), 사전 컴파일된 17개 언어용 tree-sitter 파서(parser)
  • 격리: 작업별 git worktree add, 성공·실패 시 정리(cleanup)
  • 평가 하네스: SWE-bench Pro 검증 부분집합(verified subset) + Terminal-Bench 2.0 + 자체 30개 홀드아웃(holdout) 과제
  • 관측성: gen_ai.* 의미 규약을 사용하는 OpenTelemetry SDK → 자체 호스팅 Langfuse
  • 풀 리퀘스트 게시: 세밀한 권한(fine-grained) 토큰을 보유하고 대상 저장소(target repo)로 범위(scope)가 제한된 GitHub App

만들어보기

  1. 터미널 사용자 인터페이스(TUI)와 명령 루프. Ink를 사용해 Bun 프로젝트를 골격화(scaffold)합니다. agent run <repo> "<task>" 명령을 받도록 만듭니다. 출력은 분할 뷰(split view)로 구성합니다. 계획 영역(plan pane; 위), 도구 호출 스트림(tool-call stream; 가운데), 토큰 예산(token budget; 아래)입니다. Ctrl-C 취소 기능을 추가하되, 종료 직전에 SessionEnd 훅을 호출하도록 합니다.

  2. 계획 상태. 타입이 지정된 TodoWrite 스키마(schema)를 정의합니다. pending / in_progress / done 상태와 메모(note)를 포함합니다. 모델은 매 턴마다 전체 상태를 도구 호출로 다시 작성합니다. 모델이 점진적으로 변경(mutate)하도록 허용하지 않습니다. 충돌(crash) 후 재개할 수 있도록 계획을 .agent/state.json에 영구 저장합니다.

  3. 도구 표면. 여섯 개 도구를 정의합니다. read_file, edit_file(차이(diff) 미리보기 포함), ripgrep, tree_sitter_symbols, run_shell(타임아웃 포함), git(status / diff / commit / push)입니다. 하네스가 특정 전송 방식(transport)에 묶이지 않도록 MCP StreamableHTTP를 통해 노출합니다. 모든 도구는 잘라낸(truncated) 출력만 반환하며, 호출당 4k 토큰을 상한으로 둡니다.

  4. 샌드박스 래핑(wrapping). 각 작업은 E2B sandbox를 새로 띄웁니다. git worktree add -b agent/$TASK_ID로 신규 브랜치를 만듭니다. 모든 도구 호출은 샌드박스 안에서만 실행됩니다. 호스트 파일 시스템에는 접근할 수 없습니다.

  5. 훅(Hooks). 2026년의 여덟 개 훅 유형을 모두 구현합니다. 사용자 정의 훅을 최소 네 가지 연결합니다. (a) worktree 바깥에서 실행되는 rm -rf를 차단하는 PreToolUse 파괴적 명령 가드, (b) PostToolUse 토큰 회계(token accounting), (c) SessionStart 예산 초기화(budget initialization), (d) 종료 시 최종 추적 번들(trace bundle)을 기록하는 Stop 훅입니다.

  6. 평가 루프. SWE-bench Pro Python의 30개 이슈 부분집합(issue subset)을 복제(clone)합니다. 각 과제에 대해 하네스를 실행합니다. pass@1, 과제당 턴 수(turns-per-task), 과제당 비용($-per-task)을 기준으로 최소 베이스라인(baseline)인 mini-swe-agent와 비교합니다. 결과는 eval/results.jsonl에 기록합니다.

  7. 비용 제어. 하드 컷오프(hard cutoff)는 50턴, 200k 문맥(context), 과제당 $5입니다. 150k 지점에서 PreCompact 훅이 작동해 오래된 턴을 사전 상태 블록(prior-state block)으로 요약하고, 계획을 잃지 않으면서 새로운 관찰을 위한 공간을 확보합니다.

  8. 풀 리퀘스트 게시. 성공 시 마지막 단계는 git push와 GitHub API 호출입니다. 계획과 차이(diff) 요약을 본문에 담아 풀 리퀘스트를 엽니다.

사용해보기

$ agent run ./my-repo "Fix the race condition in worker.rs"
[plan]  1 worker.rs를 찾고 mutex 사용을 열거한다
        2 경합 중인 공유 상태를 식별한다
        3 수정안을 제안하고 테스트를 검증한다
[tool]  ripgrep mutex.*lock -t rust           (44 matches, truncated)
[tool]  read_file src/worker.rs 120..180
[tool]  edit_file src/worker.rs (+8 -3)
[tool]  run_shell cargo test worker::          (passed)
[plan]  1 done · 2 done · 3 done
[done]  PR opened: #482   turns=9   tokens=38k   cost=$0.41

제출하기

제출 산출물 스킬(skill)은 outputs/skill-terminal-coding-agent.md에 있습니다. 저장소 경로와 작업 설명이 주어지면, 샌드박스 안에서 plan-act-observe 루프 전체를 실행하고 풀 리퀘스트 URL과 추적 번들을 반환한다. 이 캡스톤의 평가 루브릭(rubric)은 다음과 같다.

가중치평가 기준측정 방법
25SWE-bench Pro pass@1 vs 베이스라인동일한 30개 Python 과제에서 mini-swe-agent와 하네스 비교
20아키텍처 명료성plan/act/observe 분리, 훅 표면, 도구 스키마를 Live-SWE-agent 구조와 대조해 검토
20안전성샌드박스 탈출 시험(sandbox escape tests), 권한 프롬프트(permission prompts), 파괴적 명령 가드의 레드팀(red-team) 통과 여부
20관측성추적 완전성(도구 호출 100%가 스팬으로 기록), 턴별 토큰 회계
15개발자 경험(Developer UX)콜드 스타트(cold-start) 2초 미만, 충돌 복구가 계획을 재개, Ctrl-C가 도구 실행 중에도 깨끗하게 취소
100

연습문제

  1. 백킹 모델(backing model)을 Claude Sonnet 4.7에서 vLLM으로 서빙되는 Qwen3-Coder-30B로 교체합니다. pass@1과 과제당 비용을 비교합니다. 오픈 모델(open model)이 어떤 부분에서 성능이 떨어지는지 보고합니다.

  2. 풀 리퀘스트 게시 직전에 차이(diff)를 읽고 재작성 루프(revision loop)를 요청할 수 있는 reviewer 서브 에이전트(sub-agent)를 추가합니다. 거짓 양성(false-positive) 리뷰가 SWE-bench 통과율을 단일 에이전트(single-agent) 베이스라인 아래로 떨어뜨리는지 측정합니다(힌트: 보통은 그렇습니다).

  3. 샌드박스를 스트레스 테스트(stress-test)합니다. 외부 URL에 curl을 시도하는 과제와 worktree 밖에 파일을 쓰려는 과제를 만듭니다. 둘 다 PreToolUse 훅에 의해 차단되는지 확인합니다. 시도 내역을 기록으로 남깁니다.

  4. 더 작은 모델(Haiku 4.5)로 PreCompact 요약(summarization)을 구현합니다. 3배 압축(compaction) 상황에서 계획 충실도(plan fidelity)가 얼마나 손실되는지 측정합니다.

  5. MCP StreamableHTTP 전송을 표준 입출력(stdio) 전송으로 교체합니다. 콜드 스타트와 호출당 지연 시간(per-call latency)을 벤치마크(benchmark)합니다. 로컬 전용 사용 환경에서 더 나은 방식이 무엇인지 판정합니다.

핵심 용어

용어흔한 설명실제 의미
하네스(Harness)"에이전트 루프"도구를 디스패치하고, 계획 상태를 유지하며, 예산을 강제하는 모델 주변의 코드 전체이다.
훅(Hook)"에이전트 이벤트 리스너"하네스가 여덟 가지 수명주기 이벤트(lifecycle event) 중 하나에서 실행하는 사용자 작성 스크립트이다.
Worktree"Git 샌드박스"별도의 경로에 연결된 git 체크아웃이며, 메인 클론(main clone)을 건드리지 않고 폐기할 수 있는 일회용 작업 공간이다.
TodoWrite"계획 상태"모델이 매 턴마다 다시 작성하는 pending / in_progress / done 항목으로 구성된 타입 지정 목록이다.
StreamableHTTP"MCP 전송 방식"2026 MCP 개정판에서 도입된, 양방향 스트리밍을 지원하는 장기 연결(long-lived) HTTP 전송으로, 기존 SSE를 대체한다.
토큰 상한(Token ceiling)"문맥 예산"입력과 출력 토큰에 대한 턴별 또는 세션별 상한으로, 초과 시 압축(compaction) 또는 종료(termination)를 유발한다.
pass@1"단일 시도 통과율"재시도나 테스트 셋 엿보기(test-set peeking) 없이 첫 실행에서 해결된 SWE-bench 과제의 비율이다.

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

terminal-coding-agent

Build and evaluate a terminal-native coding agent against SWE-bench Pro with bounded cost, sandboxed tools, and full 2026 hook surface.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.200k 문맥 창(context window)에서 150k 지점에 도달하면 PreCompact 훅(hook)이 작동합니다. 이 훅이 해결하는 문제와 핵심 트레이드오프는 무엇인가요?

2.하네스는 TodoWrite를 사용하며, 모델은 매 턴마다 계획 상태를 통째로 다시 작성합니다. 점진적 변경(incremental mutation) 대신 전체 재작성(full rewriting)이 선호되는 이유는 무엇인가요?

3.에이전트의 ripgrep 호출이 47번째 턴에서 8MB짜리 매치를 반환해 컨텍스트가 넘칩니다. 이 문제를 방지해야 하는 아키텍처 구성요소는 무엇인가요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다