내장 에이전트 도구
이것은 내장 에이전트 런타임이 직접 등록하는 서버 바인딩 도구 — 언어 서버, 구조적 검색, 디버거, 커널, 질문, 워커 제어 — 입니다. 런타임이 브리지로 연결하는 MCP 도구나 하네스 런타임의 일반 파일·검색·셸 도구와는 다릅니다. 이 도구들은 MCP 레지스트리에 없습니다. 외부 MCP 클라이언트는 이들을 볼 수 없는데, 각각이 하나의 실행에 속하는 살아 있는 서버 측 리소스 — 언어 서버 프로세스, 디버그 어댑터, 인터프리터 — 에 바인딩되어 있기 때문입니다.
여기 있는 모든 도구는 그 도구를 뒷받침하는 리소스가 실행에 연결되어 있을 때만 등록됩니다 — 언어 서버 또는 디버그 감독자, tree-sitter 파서, 커널 팩토리, 질문 포트, 바이브 로스터가 그것입니다. 이 체크아웃을 위한 언어 서버나 디버그 어댑터 탐지는 별개의, 이후 단계 검사(status / adapters)입니다. 그 도구들은 표면에 남아 있어, 에이전트가 아무것도 쓸 수 없는 이유를 추측하는 대신 물어볼 수 있습니다.
승인 티어
섹션 제목: “승인 티어”각 도구는 티어를 선언하고, 그 티어가 어떤 표면이 이 도구를 보는지를 결정합니다 — 단순히 프롬프트가 뜨는지 여부가 아닙니다. 플랜 모드와 읽기 전용 서브에이전트는 read로 제한되므로, write 또는 exec 티어 도구는 그들의 스키마에 아예 없습니다.
| 티어 | 의미 | 여기 있는 도구 |
|---|---|---|
read |
부작용 없음 | lsp, ast_grep, ask_user, 다섯 개의 vibe_* |
write |
파일 변경 | lsp_rename, ast_edit, resolve |
exec |
프로세스 시작 또는 제어 | debug, eval |
lsp — 언어 서버 쿼리
섹션 제목: “lsp — 언어 서버 쿼리”실행에 언어 서버 감독자와 작업 디렉터리가 있을 때 등록됩니다. 서버가 실제로 답할 수 있는지는 호출 시점에 교집합으로 탐지됩니다. 루트 마커가 존재해야 하고 서버 바이너리가 해석되어야 합니다. 둘 중 하나만 있으면 서버가 시작되지 않으며 — status가 그렇게 알려 줍니다 — 조용히 추측하지 않습니다.
위치는 열(column)이 아니라 line과 symbol 부분 문자열로 지정합니다. 열을 요구받은 모델은 추측하고, 잘못된 추측은 같은 줄의 다른 기호로 해석됩니다 — 맞아 보이지만 다른 것에 대한 답입니다. 탐색 작업에서 symbol을 생략하면 첫 번째 열로 추측하는 것이 아니라 오류입니다.
| 작업 | 인수 | 반환 |
|---|---|---|
diagnostics |
file (또는 "*") |
오류와 경고; "*"는 대신 프로젝트 검사기를 실행 |
definition |
file, line, symbol |
기호가 선언된 위치 |
type_definition |
file, line, symbol |
타입이 선언된 위치 |
implementation |
file, line, symbol |
구체 구현 |
references |
file, line, symbol |
모든 사용처, 최대 50개 |
hover |
file, line, symbol |
시그니처와 문서 주석 |
symbols |
query 또는 file |
query로 워크스페이스 검색 (최대 100개); file로 문서 기호 (최대 200개) |
code_actions |
file, line, symbol |
서버가 제공하는 빠른 수정 |
status |
— | 어떤 서버가 실행 중이며, 어떤 루트를 위한 것인지 |
reload |
— | 이 루트의 서버를 재시작 |
쓰기 시 진단
섹션 제목: “쓰기 시 진단”성과는 도구 자체에 있지 않습니다. write, edit, apply_patch는 래핑됩니다. 쓰기 후 파일이 언어 서버를 거쳐 동기화되고 저장되며, 새로 도입된 진단만 도구 결과에 접혀 들어갑니다. 에이전트는 빌드를 깨뜨린 바로 그 순간에 그것을 알게 되며, 물어볼 것을 기억할 필요가 없습니다.
이미 보고된 진단은 심각도, 코드, 메시지를 키로 하는 실행별 원장으로 억제됩니다 — 위치는 의도적으로 제외되므로, 네 줄 아래로 옮겨진 것뿐인 진단이 새것으로 다시 보고되지 않습니다.
lsp_rename — 프로젝트 전역 이름 바꾸기
섹션 제목: “lsp_rename — 프로젝트 전역 이름 바꾸기”별개의 write 티어 도구인 데에는 이유가 정확히 하나 있습니다. 티어가 가시성을 결정하기 때문입니다. 이름 바꾸기를 lsp에 합치면 읽기 전용 탐색자에게 저장소를 다시 쓸 능력을 쥐여 주거나, 모든 hover를 승인 프롬프트 뒤에 두게 됩니다.
| 인수 | 의미 |
|---|---|
file |
기호가 있는 위치 |
line |
1부터 시작하는 줄 |
symbol |
그 줄에서 기호를 식별하는 부분 문자열 |
new_name |
새로 부를 이름 |
ast_grep — 구조적 검색
섹션 제목: “ast_grep — 구조적 검색”코드를 텍스트가 아니라 형태로 찾습니다. $NAME은 모든 노드와 일치하고, $$$NAME은 형제 노드의 연속과 일치하며, $_는 아무것도 바인딩하지 않는 와일드카드입니다.
이를 몇 단계 더 거친 정규식이 아니라 진짜 매처로 만드는 특성은, 하나의 패턴에서 반복된 메타변수가 동일한 텍스트를 캡처해야 한다는 것입니다.
ast_grep(pattern: "if ($X != null) $X.dispose()", language: "dart")테스트한 것을 dispose하는 가드와 일치하고, 다른 것을 dispose하는 가드와는 일치하지 않습니다.
| 인수 | 의미 |
|---|---|
pattern |
메타변수가 있는 코드 조각 |
path |
검색할 파일 또는 디렉터리; 기본값은 워크스페이스 전체 |
language |
배포된 문법 id (dart, python, rust, c, …). path가 파일을 가리키면 추론됩니다 |
max_results |
기본값 50 |
ast_edit — 구조적 재작성, 스테이징됨
섹션 제목: “ast_edit — 구조적 재작성, 스테이징됨”동일한 매칭에 더해, 메타변수가 다시 치환되는 rewrite 템플릿이 있습니다. 아무것도 기록되지 않습니다. 변경은 스테이징되고, 결과는 edit_id를 알려 줍니다.
ast_edit(pattern: "dispose($X)", rewrite: "$X.dispose()", language: "dart")→ (proposed) 12 replacements in 4 files … call resolve with edit_id "edit_1"| 인수 | 의미 |
|---|---|
pattern |
일치시킬 대상 |
rewrite |
$NAME이 치환되어 들어갈 내용 |
path |
범위; 기본값은 워크스페이스 전체 |
language |
언어 id |
resolve — 스테이징된 변경 커밋 또는 폐기
섹션 제목: “resolve — 스테이징된 변경 커밋 또는 폐기”| 인수 | 의미 |
|---|---|
edit_id |
(proposed) 결과에서 얻음 |
action |
accept 또는 discard |
모든 파일은 스테이징 시점에 캡처한 내용과 비교되며, 어떤 불일치든 전체 변경을 거부합니다. 일부만 적용된 구조적 재작성은 예전 형태로도 새 형태로도 컴파일되지 않는 트리를 남깁니다.
debug — 디버거 구동
섹션 제목: “debug — 디버거 구동”실행에 디버그 세션 감독자, 작업 디렉터리, 대화 id가 있을 때 등록됩니다. 어댑터가 실제로 시작할 수 있는지는 호출 시점에 언어 서버와 같은 교집합 규칙(루트 마커 그리고 바이너리)으로 탐지됩니다. exec 티어이며 병렬 안전하지 않습니다(세션은 호출에 걸친 상태이므로, continue가 stack을 추월하면 이미 이동한 프레임을 읽게 됩니다).
대화당 세션 하나이며, 하드 TTL(30분)이 있습니다. 두 번째 launch는 첫 번째를 조용히 대체하는 대신 거부됩니다.
| 작업 | 인수 | 비고 |
|---|---|---|
adapters |
— | 여기서 어떤 어댑터를 쓸 수 있는지, 그리고 왜 아닌지 |
status |
— | 세션이 실행 중인지, 어디서 멈췄는지 |
breakpoints |
file, lines[] |
lines가 비어 있으면 파일을 지웁니다. 실행 전에 설정할 수 있습니다 |
launch |
program, args[] |
중지점에서 멈춘 채 프로그램을 시작 |
attach |
port |
이미 실행 중인 디버기 대상에 연결 |
continue |
thread_id? |
다음 중지 지점까지 실행 |
pause |
thread_id? |
있는 자리에서 중지 |
step_over / step_in / step_out |
thread_id? |
한 단계 이동 |
threads |
— | 스레드 id와 이름 |
stack |
thread_id? |
프레임, 최대 30개 |
scopes |
frame_id |
프레임의 스코프, 각각 reference 포함 |
variables |
reference |
자식, 최대 50개, 값은 최대 400자 |
evaluate |
expression, frame_id? |
프레임 자체의 스코프에서 평가 |
output |
— | 디버기 대상의 stdout/stderr, 크기 제한 있음 |
terminate |
— | 세션을 끝내고 어댑터를 종료 |
어댑터
섹션 제목: “어댑터”| Id | 명령 | 루트 마커 |
|---|---|---|
dart |
dart debug_adapter |
pubspec.yaml |
debugpy |
python3 -m debugpy.adapter |
pyproject.toml, setup.py, requirements.txt |
lldb |
lldb-dap |
Cargo.toml, CMakeLists.txt |
delve |
dlv dap |
go.mod |
debugpy는 $PATH보다 프로젝트 로컬 .venv/bin 또는 venv/bin을 선호합니다. $PATH의 python은 다른 환경이며, 잘못된 환경에서 연결하면 코드가 깨진 것처럼 읽히는 방식으로 실패합니다.
eval — 영속 인터프리터
섹션 제목: “eval — 영속 인터프리터”변수, 임포트, 로드한 데이터가 호출 사이에 유지되는 Python 또는 JavaScript 셀입니다. exec 티어이며 병렬 안전하지 않습니다.
| 인수 | 의미 |
|---|---|
code |
셀 |
description |
필수입니다. 트랜스크립트 레이블용 5~10단어 |
language |
python(기본값) 또는 javascript |
reset |
인터프리터를 폐기하고 먼저 깨끗하게 시작 |
- 마지막 표현식은 노트북이 하듯이 에코됩니다.
display()가 동작하고, pandas 프레임은 표로 렌더링되며, matplotlib 그림은 트랜스크립트가 보여 주는 이미지로 돌아옵니다.- 사람들이 반사적으로 입력하는 IPython 관용구 —
%pip,%cd,!cmd,%%bash,%%timeit— 는 평범한 코드로 다시 작성됩니다.%pip는sys.modules도 비우므로, 다음import는 방금 설치한 것을 봅니다.
셀 안에서 자신의 도구 호출하기
섹션 제목: “셀 안에서 자신의 도구 호출하기”contents = tool("read", {"path": "lib/auth.dart"})브리지는 하네스 도구 레지스트리로 다시 들어가므로, 가드레일, 승인, 모든 래퍼가 모델이 발행한 호출과 정확히 동일하게 적용됩니다. 루프백 소켓이 아니라 커널 자체의 파이프를 타므로, 포트도 시크릿도 이그레스 규칙도 없습니다.
셀의 타임아웃은 비활성 예산(기본 5분)이며, 브리지 호출이 진행 중인 동안에는 일시 중단되므로, 서브에이전트로 팬아웃하는 셀이 팬아웃 도중에 죽지 않습니다.
ask_user — 사람에게 질문하기
섹션 제목: “ask_user — 사람에게 질문하기”read 티어입니다. 실행이 운영자에게 무언가를 묻는 유일한 방법입니다. 대화에 번호가 매겨진 카드를 렌더링하고, 누군가 답하거나 건너뛰거나 질문이 타임아웃될 때까지 차단합니다. 질문을 채팅 메시지로 쓰지 마십시오 — 그러면 턴이 끝납니다.
| 인수 | 의미 |
|---|---|
question |
무엇을 물을지 |
context |
선택 사항: 왜 묻는지, 답에 무엇이 달려 있는지 |
options[] |
선택지, 각각 {label, description?} |
allow_free_text |
입력한 답변을 받을지 여부 |
multi_select |
여러 선택지를 고를 수 있는지 여부 |
건너뛰기는 성공입니다. 명시한 가정 위에서 진행하고 다시 묻지 않습니다. 타임아웃은 같은 지침이 담긴 오류입니다. 권한 프롬프트(“이래도 되나요?”)는 별개의 게이트이며, 대화에 같은 카드로 렌더링됩니다.
질문 포트와 대상 스페이스가 모두 있을 때만 등록됩니다. 사람이 연결되어 있지 않으면 호출은 영원히 차단되는 대신 실패합니다 — 승인자가 연결되지 않았을 때 가드레일 prompt가 취하는 것과 같은 실패 시 거부 태도입니다.
vibe_* — 백그라운드 워커 지시
섹션 제목: “vibe_* — 백그라운드 워커 지시”바이브 모드가 켜져 있는 동안에만 등록됩니다. 다섯 개 모두 read 티어입니다. 게이트는 편집이 실제로 일어나는 워커의 도구에 속하기 때문입니다.
| 도구 | 인수 | 비고 |
|---|---|---|
vibe_spawn |
brief, label, tier? |
즉시 반환하고, 워커는 계속 실행됩니다 |
vibe_send |
worker_id, message |
브리프에 덧붙이고 다시 실행합니다 |
vibe_wait |
worker_id, timeout_seconds? |
워커가 끝날 때까지 차단합니다 |
vibe_kill |
worker_id |
워커를 중지합니다 |
vibe_list |
— | 티어, 상태, 경과 시간, 마지막 결과 |
tier는 fast(명확한 명세가 있는 기계적 작업) 또는 good(설계, 판단, 또는 fast 워커의 출력 검토)입니다.