시선아이티 면접 준비 · 메커니즘 심층

에이전트 루프 · 도구 시스템 — oxicode ⇄ oxios 해부

LLM은 상태가 없다. 그래서 에이전트의 본질은 "도구 결과를 다시 먹이는 while 루프"다. 이 페이지는 그 루프가 도는 정확한 코드 경로를 — 도구가 정의되고 등록되고 승인되고 실행되고 결과가 돌아오는 순서까지 — 실제 파일:라인 근거와 함께 따라간다. 정적 구조(16 port)는 SDK ↔ oxios 관계, 프레임워크 비교는 에이전트 SDK 비교에 뒀고, 여기는 동적 거동만 다룬다.

결론 먼저 — 세 문장

  1. 도구 = 트레이트. AgentTool(이름·설명·JSON Schema·execute)이 실행의 옷을 입고, 매 턴 oxicode-ai::Tool JSON으로 갈아입어 LLM 요청에 실린다.
  2. 루프 = oxicode-agent의 소유. AgentLoop::run_loop(mod.rs:761)의 2중 while이 1턴(응답→도구→결과)을 반복한다. oxios는 자체 루프를 만들지 않고 run_streaming() 한 번으로 위임한다.
  3. oxios의 차별점 = 도구와 정책. 커널 도구 30+를 KernelToolProvider로 주입하고, 표면·오케스트레이터·수퍼바이저가 그 루프를 감싼다.

0. 전체 지도 — 호출이 지나는 5개 층

같은 루프를 두 소비자가 쓴다. oxicode CLI는 TUI에서 바로 SDK로, oxios는 Web WS·Telegram 표면에서 게이트웨이→오케스트레이터→수퍼바이저를 거쳐 같은 SDK 계약층으로 내려온다.

oxicode ⇄ oxios 전체 스택 — 표면에서 도구까지
SURFACE oxicode TUI · CLI oxicode-cli — agent_session.rs oxios 표면 — Web WS · Telegram src/api/routes/chat.rs:1265 ORCHESTRATION (oxios-kernel) CLI 세션 — persist · resume agent_session.rs:1094 · session.rs:893 gateway gateway.rs orchestrator handle_unified fork agent_lifecycle BasicSuper visor.rs AgentRun time.rs:737 SDK CONTRACT oxicode-sdk — AgentBuilder · 16 port (AccessGate · HookRunner · AuditTrail · ModelCatalog …) KernelToolProvider (kernel_bridge.rs:111) — 계약만 정의, 구현은 제품(oxios)이 주입 AGENT CORE oxicode-agent — Agent → AgentLoop::run_loop (mod.rs:761) 2중 while · ToolRegistry(tools.rs:997) · 9단계 도구 관문 oxicode-ai — Provider 스트리밍 Anthropic · OpenAI · Ollama · Gemini → LLM API TOOLS ① 내장 도구 read · write · bash · edit … with_builtins_cwd(tools.rs:1128) ③ oxios 커널 도구 30+ exec · memory_* · a2a_* · browse_* — OxiosKernelBridge(:41) ② 외부 MCP 서버 McpManager::spawn → 프록시 도구 (mcp/mod.rs:606) KernelToolProvider 주입 프록시 등록 범례 — oxicode oxios SDK 계약 oxicode-ai 도구 · 외부 같은 루프, 다른 소비자 — CLI는 2층, oxios는 5층을 거쳐 같은 SDK로 수렴한다.
파랑=oxicode, 주황=oxios, 보라=SDK 계약, 청록=oxicode-ai. 점선은 도구 주입 경로(아래→위)다.

1. 도구의 정체 — 하나의 트레이트, 두 벌의 옷

oxicode에서 도구는 enum도 구조체 등록도 아닌 async 트레이트다. 실행 로직(Rust 세계)과 모델에게 보이는 정의(JSON 세계)가 서로 다른 타입으로 분리돼 있다 — 이것이 "같은 도구가 공급자를 바꿔도 동작하는" 비결이다.

실행의 옷 — AgentTool (oxicode-agent)

pub trait AgentTool: Send + Sync {
    fn name(&self) -> &str;                      // "bash"
    fn label(&self) -> &str;                     // UI 표시용
    fn description(&self) -> &str;               // ← 모델이 읽는 설명
    fn parameters_schema(&self) -> Value;        // ← JSON Schema
    fn essential(&self) -> bool { false }        // 컨텍스트 축소 시에도 유지
    fn tool_tier(&self) -> ToolTier { ToolTier::Exec }  // 권한 티어

    async fn execute(&self, tool_call_id: &str, params: Value,
        signal: Option<oneshot::Receiver<()>>,     // 취소 신호
        ctx: &ToolContext) -> Result<AgentToolResult, ToolError>;

    fn to_definition(&self) -> ToolDefinition;   // LLM 전송용 변환
    // … 총 15개 메서드 (render_call · intent · execution_mode · tab slot …)
}
// oxicode-agent/src/tools.rs:744-873 — 트레이트다 (enum/구조체 아님)

선택의 옷 — Tool JSON (oxicode-ai)

// oxicode-ai/src/providers/anthropic.rs:205-207, 664-680
body["tools"] = json!([{
    "name": "bash",
    "description": "Run a shell command …",
    "input_schema": { "type": "object", "properties": { … } }
}]);
// 같은 정의가 방언만 바껴 나간다 —
// OpenAI openai.rs:598-620 · Ollama ollama.rs:210-225 · Gemini google_shared.rs:210

모델은 오른쪽만 본다. 매 턴 streaming.rs:57-99에서 ToolRegistry.definitions()OxTool::new(name, desc, schema)context.set_tools()로 새로 조립된다 — 도구 목록은 요청마다 동봉되는 상수가 아니라 매번 계산되는 값이다.

도구의 두 벌 옷 — Rust 트레이트와 LLM JSON
Rust 세계 — 실행 name() = "bash" parameters_schema() → JSON Schema tool_tier() → Read | Write | Exec execute(id, params, signal, ctx) 매 턴 조립 streaming.rs:57-99 LLM 세계 — 선택 { "name": "bash", "description": "Run a shell …", "input_schema": { … } } body["tools"] — 공급자별 방언
왼쪽에서 실행되고, 오른쪽에서 선택된다. 변환점이 to_definition()/definitions() (tools.rs:860, streaming.rs:57).

ToolTier { Read, Write, Exec }(tools.rs:732-742)는 도구의 위험도 등급이다. 읽기 도구와 셸 실행이 같은 승인 정책을 통과하면 안 되기 때문 — 아래 §3 관문에서 이 등급이 그대로 승인 판정의 기준이 된다. 구체 예: BashTool(tools/bash.rs:168-171 구조체, :490-540 impl)는 essential = true라 컨텍스트 절약을 위해 도구를 골라 낼 때도 살아남는다.

2. 등록 — ToolRegistry로 모이는 3갈래 공급원

레지스트리는 HashMap<String, Arc<dyn AgentTool>> 하나다(tools.rs:997-1003). 정적 내장·외부 MCP·호스트 커널 도구가 전부 같은 이름 공간에 등록되고, 루프는 그 출처를 구분하지 않는다. 구분하는 책임은 등록하는 쪽에 있다.

도구 공급원 3갈래 → ToolRegistry → 매 턴 직렬화
① oxicode 내장 with_builtins_cwd (tools.rs:1128) ReadTool · WriteTool · BashTool EditTool · GrepTool · … ② 외부 MCP McpManager::spawn (mcp/mod.rs:606) .oxicode/mcp.json 서버 스폰 McpTool 프록시 · McpDirectTool 캐시 SpawnValidator + consent 게이트 ③ 호스트 커널 도구 KernelToolProvider (kernel_bridge.rs:111) oxios OxiosKernelBridge(:41) always-on 8 + 커널 도메인 21 + browser 5 + MCP 동적 ToolRegistry — HashMap<String, Arc<dyn AgentTool>> (tools.rs:997) register · register_arc — 출처 무관 단일 이름 공간 definitions() 매 턴 수집 → oxicode-ai Tool → 공급자 방언 직렬화 (streaming.rs:57, anthropic.rs:205)
③이 확장 지점이다 — oxios가 도구를 끼워 넣는 정식 문이 KernelToolProvider (oxicode-sdk/src/kernel_bridge.rs:111-124).

oxios가 주입하는 도구 30+ — 실제 목록

분류도구근거 · 비고
always-on 파일 · 검색 (8) read · write · edit · grep · find · ls · web_search · get_search_results registration.rs register_always_on — SDK 파일 도구와 같은 이름 공간
커널 도메인 (21) exec · memory_read · memory_write · memory_search · subagent · project · mount · kernel_agent · persona · cron · security · budget · resource · a2a_delegate · a2a_send · a2a_query · knowledge · ask_user · marketplace · skill_forge · calendar · send_email builtin/mod.rs:70 register_all_kernel_tools — 'canonical list'. memory 3종은 brain-backed 무조건 등록 (': every agent gets memory read + write'), subagent는 oxicode-agent 네이티브 재사용(:88)
브라우저 5종 (feature) browse · browse_extract · browse_session · browse_script · browse_screenshot kernel_bridge.rs:81-90 — oxios 자체 브라우저 스위트 (RFC-046, oxibrowser 연계)
외부 MCP (동적) 서버별 full_name으로 열거 — 정적 목록에 없음 kernel_bridge.rs:77-78 주석 — 등록 시점에 per-server 결정 + McpToolWrapper (builtin/mod.rs:108)

확장 계약 — KernelToolProvider (oxicode-sdk)

// oxicode-sdk/src/kernel_bridge.rs:111-124 — 호스트 도구 주입 계약
pub trait KernelToolProvider: Send + Sync {
    fn tool_names(&self) -> Vec<&str>;
    fn register_tools(&self, registry: &ToolRegistry, context: &KernelToolContext);
}
// KernelToolContext(:24-80) = workspace · agent_id · session_id · permissions

oxios의 구현은 OxiosKernelBridge(oxios-kernel/src/tools/kernel_bridge.rs:41-105) — tool_names()가 위 표의 목록을 반환하고 register_tools()register_always_on + builtin::register_all_kernel_tools(builtin/mod.rs:70)를 호출한다. SDK 쪽에서 이것이 불리는 지점은 agent_builder.rs:388-393 kernel_tools().

3. 호출 1회의 관문 — ToolCall에서 ToolResult까지 9단계

모델이 tool_use 블록을 내놓는 순간부터 결과가 히스토리에 꽂히기까지, 도구 호출은 9개의 관문을 순서대로 통과한다. 면접에서 "에이전트 안전성"을 묻는다면 이 9단계가 답이다.

도구 호출 1회 — 9단계 관문
① ToolCall 파싱 스트림에서 tool_use 블록 추출 — mod.rs:986 ② ToolRegistry.get(name) 미등록 → "Tool not found" — tool_exec.rs:871 ③ before_tool_call 훅 인자 검사 · 차단 가능 — tool_exec.rs:879-888 ④ check_tool_approval ToolTier × ApprovalConfig — tool_exec.rs:280-345 Allow→실행 · Deny→에러 · RequireApproval→승인 요청 ⑤ ToolExecutionStart intent·context emit — tool_exec.rs:391, events.rs:245 ⑥ execute(id, params, signal, ctx) 실제 실행 · 취소 select! — tool_exec.rs:913-1003 ⑦ after_tool_call 훅 결과 오버라이드 · terminate 투표 — tool_exec.rs:450-475 ⑧ ToolResult 히스토리 삽입 ToolExecutionEnd → Message::ToolResult — tool_exec.rs:479 ⑨ ToolCallLoopGuard 동일 호출 5회 반복 → steering 탈출 tool_call_loop.rs (read·ls·grep 면제) → 다음 턴: 모델이 ToolResult를 읽고 판단한다
② 미등록 즉시 거절 → ③ 사전 훅 → ④ 승인 → ⑥ 실행 → ⑧ 히스토리 삽입. ⑨는 턴 간 방어.

승인 판정 — 3분기와 opt-in 설계

판정동작근거
Allow즉시 실행config.rs:276, tool_exec.rs:300-311
Deny(reason)에러 반환 — 모델에게 거절 사유가 ToolResult로 전달config.rs:277
RequireApprovalAgentEvent::ApprovalRequired emit + 에러 — 호스트 UI가 승인 대기tool_exec.rs:312-325

주의 — 권한 시스템은 opt-in이다. ApprovalConfig.require_approval_for가 비어 있으면 전부 즉시 허용된다(tool_exec.rs:292-294). .oxi 권한 규칙 파일 같은 건 없고 정책은 전부 코드/훅으로 주입한다 — 파일 기반 설정은 MCP에만 있다(.oxicode/mcp.json + 동의 파일 mcp-consent.json, consent.rs:210). 제품 수준의 정책(권한·감사·비용)은 oxios가 SDK port(AccessGate·authorizer)로 끼워 넣는다 — agent_runtime.rs:1046-1054에서 authorizer · tracer · cost_tracker를 AgentBuilder에 꽂는 게 그 지점.

4. 루프 해부 — 2중 while과 1턴의 14단계

run_loop(mod.rs:761)는 상태 머신이 아니라 플래그 기반 2중 루프다. 안쪽 while이 "1턴"의 단위(모델 응답 → 도구 실행 → 결과 삽입), 바깥 loop는 실행 중 개입(steering·follow-up)을 놓치지 않기 위한 재드레인 층이다. 이중 구조가 "에이전트가 일하는 도중에 말을 걸 수 있는" 이유다.

AgentLoop::run_loop — 2중 while 구조
바깥 loop — mod.rs:786 · 재드레인 :1212-1257 안쪽 while — has_more_tool_calls || pending (mod.rs:794) TurnStart · steering 삽입 (:794-814) poll_external_queues (:816-818) maybe_compact (:820) 토큰 임계면 압축 후 진행 stream_assistant_response (:827) StreamOutcome · StopReason 분기 (:831-972) Error→재시도 · Aborted→종료 · TTSR→폐기·재시도 extract_tool_calls (:986) — 없으면 has_more=false execute_tool_calls — 9 관문 (:991) ToolResult 삽입 · 루프 가드 · soft-requirement TurnEnd · should_stop_after_turn (:1176-1190) tool_use 있음 → 다음 턴 late steering · follow-up · todo 리마인더 (:1212-1257) 있으면 1턴 더 종료 조건 (A-J) A 텍스트-only 응답 → 정상 종료 B external_stop · Ctrl+C C StopReason::Error 비재시도 D Aborted · Cancelled F 도구 실행 오류 G after_tool_call 만장일치 stop H TTSR 위반 → 폐기·재시도(계속) I 루프 가드 5회 반복 J 최대 턴수 없음 — 유계 장치로만 보호 (가드·dedup·상한) StopReason (types.rs:100) Stop · Length · ToolUse · Error · Aborted anthropic.rs:946-953 매핑 도구 실행 모드 시퀀셜 / 병렬 분기 (tool_exec.rs:340-355) 스트리밍 감시 취소 500ms 폴링 · 30s idle 타임아웃 (streaming.rs:157-210)
점선 환류 = 다음 턴. 텍스트-only 응답이 나오면 안쪽을 탈출하고, 바깥은 late steering·follow-up·todo 리마인더만 확인 후 break한다.

1턴 전체 시퀀스 — 14단계

  1. 1 TurnStart { turn_number } mod.rs:794-804
  2. 2 steering 메시지 처리 — 실행 중 끼어든 사용자 입력을 히스토리에 삽입 mod.rs:806-814, :675-703
  3. 3 poll_external_queues — 훅이 새로 넣은 steer/follow-up 드레인 mod.rs:816-818, :465
  4. 4 maybe_compact — 토큰 임계면 컨텍스트 압축 (아래 §6) mod.rs:820-821
  5. 5 append_only.sync_from — prefix-stable 컨텍스트 동기화 mod.rs:823-825
  6. 6 stream_assistant_response — 시스템 프롬프트+도구 정의 조립 → LLM 스트리밍 mod.rs:827-829, streaming.rs:68-129
  7. 7 StreamOutcome 분기 — Error→재시도/종료 · Aborted→종료 · TTSR 위반→부분 출력 폐기 후 재시도 mod.rs:831-972, retry.rs
  8. 8 extract_tool_calls — tool_use 없으면 has_more_tool_calls = false mod.rs:986-990, helpers.rs:7
  9. 9 execute_tool_calls — 9 관문 통과 (시퀀셜/병렬 분기) mod.rs:991-1015, tool_exec.rs:340-355
  10. 10 ToolResult 메시지 삽입 → 루프 가드 → soft-requirement 검사 mod.rs:1020-1169
  11. 11 TurnEnd 이벤트 → should_stop_after_turn (external_stop이면 즉시 종료) mod.rs:1176-1190, helpers.rs:50
  12. 12 안쪽 while 판정 — has_more_tool_calls || pending_messages mod.rs:794, :1201-1206
  13. 13 바깥 loop — late steering · follow-up · final steering 재드레인 mod.rs:1212-1234
  14. 14 todo 리마인더 (유계: signature dedup + 상한) 후 없으면 break mod.rs:1240-1257
#조건동작근거
A 모델이 텍스트만 응답 (tool_use 없음) 내부 루프 탈출 → 큐 비면 break — 정상 종료 mod.rs:794, :1258
B external_stop · Ctrl+C should_stop_after_turn → TurnEnd 후 종료. 스트리밍 중엔 500ms 주기 취소 감지 helpers.rs:50, mod.rs:1187-1206, streaming.rs:157-180
C StopReason::Error (비재시도) handle_streaming_error → 에러 메시지로 TurnEnd 후 반환 mod.rs:906-938, :708-759
D StopReason::Aborted / Cancelled 즉시 반환 mod.rs:939-960, :877-884
F 도구 실행 오류 TurnEnd 후 반환 (에러는 ToolResult로 모델에게도 전달됨) mod.rs:995-1014
G after_tool_call 훅 만장일치 terminate has_more_tool_calls = false mod.rs:1015-1018, helpers.rs:39
H TTSR 룰 위반 (스트리밍 중) 폐기·재시도 — 종료 아님. 룰 메시지 주입 후 continue mod.rs:885-938, ttsr.rs
I 같은 도구 호출 5회 반복 루프 가드가 steering 주입해 탈출 mod.rs:1078-1093
J 최대 턴수 없음 — 루프는 가드·soft-requirement·todo 리마인더(모두 유계)로만 보호된다 mod.rs:777-780 주석

TTSR(Time-Traveling Stream Rules) — 스트리밍 중 프로젝트 룰 위반을 TextDelta마다 검사해(ttsr.rs, streaming.rs:316-360) 위반 시 그 턴의 부분 출력을 버리고 룰을 시스템 리마인더로 주입한 뒤 재시도한다(mod.rs:885-938). omp의 TtsrManager 이식이며 Regex + AST(ast-grep) 2종 매칭을 지원한다. (구 보고서의 "Textual Trajectory Stream Rule" 표기는 오기다.)

5. 살아있는 루프 — 컴팩션 · 스트리밍 · 훅 · 세션

컨텍스트 압축 — 2단 컴팩션

maybe_compact (mod.rs:1283-1436)
토큰 임계 판정 provider 입력 토큰 우선 cold start는 bytes/4 휴리스틱 (mod.rs:1299-1329) 1차 mechanical shake LLM 없이 정리 폐기 가능한 도구 출력 제거 (mod.rs:1331-1364) 충분? 아니오 history 교체 · 루프 계속 2차 LLM / Snapcompact (mod.rs:1377-1385) → Compaction 이벤트 · 교체
LLM 왕복은 마지막 수단이다 — 기계적 정리(shake)로 부족할 때만 요약 비용을 쓴다.

compactor는 교체 가능하다 — SDK의 SnapcompactCompactor(vision 모델용 PNG 렌더)를 끼우는 지점이 mod.rs:145-153. 컴팩션 전후로 AppendOnlyContext(mod.rs:782-784)가 prefix 안정성을 지킨다.

스트리밍 · 훅 · 세션

  • 실시간 토큰TextDelta → MessageUpdate{StreamDelta}(streaming.rs:303-323)를 emit 클로저가 std mpsc(agent.rs:738-756) 또는 tokio mpsc(:1079-1090)로 소비자에게. oxios는 콜백에서 세션별 StreamingSink로 push(agent_runtime.rs:1102-1117, RFC-015).
  • 훅은 2층 — 코어 내장 before/after_tool_call 클로저(tool_exec.rs:867-902) + SDK HookRunner port(ports/hooks.rs:90)를 HookMiddleware가 PreToolUse/PostToolUse로 라우팅(middleware/hook.rs:24-130). CLI는 CommandHookRunner로 셸 훅 실행(bootstrap.rs:103-113).
  • 세션 지속 — CLI가 persist_session(agent_session.rs:1094-1183)으로 session.json JSONL append, 재개는 resume_from_file(:2937-2999)이 브랜치를 역직렬화해 Agent state에 시드.
  • oxios 장애 복구 — 모델 실패 시 이전 실행의 대화 상태를 import_state로 복원해 fallback 모델이 처음부터가 아니라 체크포인트에서 계속(agent_runtime.rs:1080-1087, RFC-029 P2b).

6. oxios — 루프를 만들지 않고 루프를 산다

oxios의 가장 중요한 설계 결정: 자체 에이전트 루프를 작성하지 않았다. run_agent(agent_runtime.rs:737)는 SDK의 AgentBuilder로 Agent를 조립하고 run_streaming() 한 번을 기다리기만 한다. oxios가 소유한 것은 루프 주변이다 — 표면·오케스트레이션·도구·정책.

oxios의 조립 코드 — agent_runtime.rs (요약)

// oxios/crates/oxios-kernel/src/agent_runtime.rs — run_agent(:737)
let mut builder = engine.oxi()            // oxicode-sdk Oxicode 진입점
    .agent(agent_config)                  // AgentBuilder (RFC-014 Phase D)
    .workspace(&workspace)
    .system_prompt(system_prompt);
// … authorizer · tracer · cost_tracker · rate limit · token budget (:1046-1066)

let built = builder.build()?;

// SDK builder의 .tool()은 concrete 타입만 받는데 oxios 도구는 Arc<dyn AgentTool>.
// SDK가 pre-built ToolRegistry 주입을 지원하지 않으므로
// build 후 agent.tools() 레지스트리에 register_arc로 주입한다 (:1071-1078).
for tool in cspace_tool_arcs {
    agent_tools.register_arc(tool);
}

// 루프는 여기서 시작되지 않는다 — 소유권은 SDK에 있다.
let result = agent.run_streaming(prompt, move |event| { … }).await;  // :1109-1110

:1030-1036의 주석이 설계 지향을 그대로 보여준다 — SDK builder의 .tool()은 concrete 타입만 받는데 oxios 도구는 Arc<dyn AgentTool>이라 build 후 agent.tools() 레지스트리에 register_arc로 주입한다. 계약을 우회한 게 아니라 SDK가 남겨둔 정식 확장점(:1071-1078 주석 "canonical extension point")을 찾아 쓴 것.

oxios에서 입력 1줄이 응답이 되기까지 — 8단계 위임 경로
① Web WS 수신 src/api/routes/chat.rs:1265-1277 → IncomingMessage ② gateway 이벤트 루프 oxios-gateway/gateway.rs — mpsc 채널 디스패치 ③ orchestrator.handle_unified → execute_directive agent_lifecycle.rs — 에이전트 fork 결정 ④ BasicSupervisor.run_with_directive oxios-kernel/src/supervisor.rs — 에이전트 실행 감독 ⑤ AgentRuntime::execute → run_agent agent_runtime.rs:737 — 여기서부터 조립 ⑥ AgentBuilder 조립 · build agent_runtime.rs:1024-1068 · CSpace 도구 register_arc(:1075) authorizer · tracer · cost_tracker · budget (:1046-1066) ⑦ SDK Agent::run_streaming — 루프 소유권 이양 agent_runtime.rs:1109-1110 · 내부는 run_loop 2중 while ⑧ oxicode-ai Provider → LLM · 도구 실행 ToolRegistry (내장 + 커널 30+ + MCP) — 9 관문 통과 AgentEvent → KernelEvent → StreamDelta WS (RFC-015) ⑤까지 oxios — ⑥부터 oxicode-sdk. 경계에서 일어나는 건 '위임'뿐이다.
①-⑤는 oxios 소유(오케스트레이션), ⑥-⑧은 oxicode-sdk 소유(루프). 오른쪽 점선은 이벤트의 역류 — RFC-015 채팅 투명성.

supervisor가 두 개다 — 역할이 다르다

이름위치역할
BasicSupervisoroxios/crates/oxios-kernel/src/supervisor.rs에이전트 1개 실행 — run_with_directive로 AgentRuntime을 돌린다
TaskSupervisoroxios/src/supervisor.rs프로세스 감시 — 게이트웨이·표면·채널. 웹 표면은 유한 백오프 재시작, 치명 오류 시 OS 재시작

흔한 오해 2개 — 짚고 가기

  • "oxios는 MCP 서버를 돌린다" → 아니다. oxios-mcpMCP 클라이언트 라이브러리다 (lib.rs:1-4 "Model Context Protocol client library" — Consumer → McpBridge → McpClient → stdio JSON-RPC → 외부 서버). oxios는 외부 MCP 도구를 소비하는 쪽이지, 자신을 MCP로 노출하지 않는다. 반대로 oxibrain-mcp는 서버(5 transport)다 — 방향이 정반대.
  • "ClawHub 스킬은 도구다" → 아니다. 스킬은 ~/.oxios/skills에 설치되는(clawhub/installer.rs — 다운로드→추출→origin.json→lockfile) 문서고, <available_skills> 블록이 시스템 프롬프트에 주입된 뒤 모델이 read 도구로 본문을 로드한다(skill/prompt.rs:26-36). 도구 수 = 스키마 토큰이므로, 지식은 도구가 아니라 문서로 제공하는 게 토큰 경제학상 이득 — Claude Code의 Skill과 같은 progressive disclosure 전략.

7. 면접 답변 스크립트

"에이전트 루프가 정확히 뭔가?" — 30초 답변

LLM은 상태가 없어서 '도구 결과를 다시 먹여야' 다음 판단을 한다. 이 while 루프가 에이전트다. oxicode에서는 oxicode-agent의 AgentLoop::run_loop(mod.rs:761)가 2중 while — 안쪽이 1턴(모델 응답→도구 실행→결과 삽입), 바깥이 실행 중 개입(steering·follow-up) 재드레인. 모델이 tool_use 없이 텍스트만 내보내면 루프가 끝난다.

"도구는 어떻게 모델에게 제공되나?" — 90초 답변

도구 하나 = AgentTool 트레이트(이름·설명·JSON Schema·execute). 매 턴 ToolRegistry에서 definitions()를 모아 oxicode-ai의 Tool로 변환해 요청 body['tools']에 실는다 — 공급자별 방언(Anthropic input_schema / OpenAI function)으로 번역만 바뀐다. 등록은 3갈래: oxicode 내장(with_builtins_cwd) + 외부 MCP(McpManager 스폰→프록시 도구) + 호스트 커널(KernelToolProvider — oxios가 30+ 도구를 여기로 주입). 실행은 9단계 관문: 조회→사전 훅→승인(ToolTier)→실행→사후 훅→ToolResult.

"oxios와 oxicode는 역할이 어떻게 나뉘나?"

루프·도구·와이어(oxicode-ai)는 oxicode가 소유하고, oxios는 그 위에 '에이전트 OS'를 얹는다 — 표면(Web WS·Telegram)·게이트웨이·오케스트레이터(fork)·커널 도구 30+(memory·a2a·cron·browse…)·정책(authorizer·budget). oxios는 자체 while 루프를 만들지 않고 agent.run_streaming() 한 번으로 SDK 루프에 위임한다(agent_runtime.rs:1110). 이벤트만 KernelEvent로 중계해 표면으로 스트리밍.

"무한 루프에 빠지면?"

최대 턴수 제한은 없다. 대신 3중 방어: ToolCallLoopGuard(같은 호출 5회 반복 감지, read/ls/grep 면제), after_tool_call 훅 만장일치 terminate, todo 리마인더의 유계 설계(signature dedup + 상한 — mod.rs:777-780 주석). TTSR은 스트리밍 중 룰 위반을 실시간 감지해 출력을 폐기하고 룰을 주입한 뒤 재시도한다.

근거

이 페이지의 모든 file:line은 2026-08-16 코드베이스 직접 검증(스카웃 3건 교차 + 재검증)이다. oxicode 경로는 /Volumes/MERCURY/PROJECTS/oxicode/, oxios 경로는 /Volumes/MERCURY/PROJECTS/oxios/ 기준.

  • 도구 정의·등록: oxicode-agent/src/tools.rs(732-742, 744-873, 997-1040, 1128-1175) · tools/bash.rs(168-540) · oxicode-ai/src/tools.rs(21-36)
  • LLM 직렬화: agent_loop/streaming.rs(57-99) · oxicode-ai/src/providers/anthropic.rs(205-207, 664-680) · openai.rs(598-620) · ollama.rs(210-225) · google_shared.rs(210)
  • 루프: agent_loop/mod.rs(761-1260 run_loop · 1283-1436 maybe_compact) · helpers.rs · retry.rs · ttsr.rs · oxicode-ai/src/types.rs(100)
  • 도구 실행·승인: agent_loop/tool_exec.rs(280-345, 340-518, 867-1003) · agent_loop/config.rs(276-320)
  • MCP 클라이언트: oxicode-agent/src/mcp/(mod.rs 606·882·1163, client.rs 125·225, spawn.rs, consent.rs:210)
  • SDK 계약: oxicode-sdk/src/kernel_bridge.rs(24-124) · agent_builder.rs(388-393) · ports/hooks.rs(90) · middleware/hook.rs(24-130)
  • oxios: crates/oxios-kernel/src/agent_runtime.rs(737-748, 1016-1117) · tools/kernel_bridge.rs(41-105) · tools/builtin/mod.rs(70-123) · supervisor.rs · orchestrator.rs · agent_lifecycle.rs · skill/prompt.rs(26-36) · skill/clawhub/installer.rs · src/api/routes/chat.rs(1265-1277) · src/supervisor.rs · crates/oxios-mcp/src/lib.rs(1-25)
  • 세션: oxicode-cli/src/app/agent_session.rs(1094-1183, 2937-2999) · store/session.rs(893) · bootstrap.rs(103-113)

관련 페이지 — 정적 구조(16 port·wire 매핑): SDK ↔ oxios 관계 · 프레임워크 비교(제어 흐름 소유권 4티어): 에이전트 SDK 비교 · 전체 생태계 개요: oxi 생태계 해부