SNA

런타임

런타임 어댑터, AgentProvider 내부 구조, 런타임별 차이를 정리합니다.

각 런타임은 공통 AgentProvider 인터페이스를 구현하는 클래스로 연결됩니다. 어댑터는 core/providers/{claude-code,codex,opencode,grok,cursor}.ts이며, ACP로 말하는 런타임(Grok Build, Cursor)은 core/providers/acp/base.ts를 공유합니다.

지원 런타임 개요

SNA는 제품이 하나의 CLI에 고정되지 않고, workflow에 맞는 runtime을 고를 수 있도록 설계되어 있습니다. 아래 표는 제품 관점의 개요입니다. 세부 기능 대응은 기능 × 런타임 매트릭스 에서 확인할 수 있습니다.

런타임잘 맞는 경우장점Tradeoff
Claude CodeAnthropic model과 안정적인 local coding session, 풍부한 permission behavior가 필요한 경우.CLI behavior가 성숙했고, tool-use UX가 좋습니다. Thinking/tool input delta streaming과 token/cost metadata가 자세합니다.호출/세션 단위 stateless 구조라 daemon pooling은 없습니다. Permission approval은 SNA와 양방향으로 주고받는 방식이 아니라 hook 기반입니다.
Codex여러 session, one-shot job, 잦은 runtime reuse가 필요한 low-latency 제품 통합.RuntimePool로 daemon을 재사용하고, thread별 cwd 변경을 지원합니다. Item lifecycle event와 shell output delta가 풍부합니다.Codex native config shape가 따로 있고, Claude Code의 stream-json처럼 tool input delta를 노출하지는 않습니다.
OpenCode이미 OpenCode를 쓰거나 OpenCode model/provider 설정을 HTTP daemon으로 활용하고 싶은 앱.Pooled daemon과 SDK-backed HTTP path를 쓸 수 있고, 하나의 cwd에서 반복 prompt를 처리하기 좋습니다.Daemon이 single-cwd이며, 일부 runtime mutation은 respawn이 필요합니다. Event detail은 OpenCode stream이 제공하는 범위에 좌우됩니다.
Grok BuildGrok Build와 공개 protocol surface인 ACP를 쓰고 싶은 session.SNA의 shared ACP adapter를 쓰고, bidirectional permission request와 단순한 stateless session lifecycle을 제공합니다.Runtime pooling은 없고, model/cwd 변경은 respawn이 필요합니다. Token/tool detail metadata는 Claude/Codex보다 얇습니다.
CursorCursor를 주 작업 환경으로 쓰고, Cursor subscription-backed headless CLI를 SNA에서 구동하고 싶은 경우.cursor-agent와 기존 Cursor login을 사용합니다. ACP permission, Cursor model selection, model-id reasoning variant를 활용할 수 있습니다.Daemon pooling은 없고, model/cwd 변경은 respawn이 필요합니다. 사용자의 Cursor CLI 인증 상태에 setup이 의존합니다.

아래 내용은 이 product-level 선택지 뒤에 있는 adapter 내부 구조를 설명합니다.

AgentProvider

interface AgentProvider {
  name: string;
  isAvailable(): Promise<boolean>;
  spawn(opts: SpawnOptions): AgentProcess;
  complete(opts: CompleteOptions): Promise<CompletionResult>;
  // ...
}

interface AgentProcess {
  send(message: string, opts?): void;
  interrupt(): void;
  setModel(model: string): void;
  setPermissionMode(mode: PermissionMode): void;
  applyPatch(patch: SessionPatch): PatchResult;
  respondToPermission(approved: boolean): void;
  kill(): void;
  on(event: string, handler): void;  // AgentEvent emit
}

applyPatch()PATCH /agent/session이 쓰는 필드별 디스패치 훅입니다. 각 런타임 어댑터가 어떤 필드를 인플레이스로 적용할 수 있고, 어떤 필드는 respawn-with-history-replay가 필요한지 결정합니다.

런타임별 전략

런타임전송상태풀?
claude-codeclaude -p (one-shot) + claude --resume (replay)호출 단위 무상태아니오
codexcodex app-server 데몬, stdio 위 JSON-RPC영구 데몬, 멀티 스레드
opencodeopencode serve 데몬 + SDK HTTP영구 데몬, single-cwd
grokgrok agent stdio (stdio 위 Agent Client Protocol — Grok Build CLI)세션 단위 무상태아니오
cursorcursor-agent acp (stdio 위 Agent Client Protocol — Cursor CLI)세션 단위 무상태아니오

Codex와 OpenCode 런타임 어댑터는 RuntimePool을 통해 데몬을 공유합니다. 세션이 열릴 때 (provider, cwd, config) 키로 풀이 조회되고, 호환되는 기존 데몬이 있으면 재사용해서 cold-start 비용을 줄입니다(Codex 약 2초, OpenCode 약 3초).

Grok Build는 SNA에서 처음으로 공개 표준 (ACP)을 와이어 프로토콜로 쓴 런타임이었습니다. Cursor가 두 번째 ACP-speaking 런타임으로 합류하면서, 공유 로직은 core/providers/acp/base.ts로 추출됐습니다 — JSON-RPC pump, initialize/session/new 핸드셰이크, session/updateAgentEvent 변환, 양방향 session/request_permission (+bypassPermissions 자동승인), 런타임 간 resource block history 주입까지. 각 서브클래스에는 실제로 다른 부분만 남깁니다: CLI 경로 탐색, spawn 인자, 선택적 인증 단계(Cursor의 authenticate({methodId:"cursor_login"})), 벤더 확장 알림 prefix(_x.ai/* for Grok, cursor/* for Cursor), 런타임 고유 tool-call unwrap.

런타임 간 history replay는 ACP 세션의 첫 session/prompt에 정규화된 대화 이력을 단일 ACP resource content block으로 담아 보내는 식으로 처리합니다 — 기능 매트릭스 페이지의 런타임 간 history replay 항목에 정리되어 있습니다.

Cursor는 사용자가 이미 끝낸 cursor-agent login을 그대로 씁니다(macOS Keychain의 cursor-access-token / cursor-refresh-token 항목 → Cursor 구독 사용). CURSOR_API_KEY 같은 추가 발급이 필요 없습니다. SNA는 spawn 환경변수를 그대로 통과시키고, 자식 프로세스는 사용자가 인터랙티브하게 쓸 때와 동일한 자격증명을 사용합니다. Reasoning level은 모델 ID 자체에 인코딩됩니다 (gpt-5.3-codex → level 4면 gpt-5.3-codex-high로 변환). reasoning-level.tsapplyCursorReasoning이 이 변환을 처리하고, effort family에 속하지 않는 모델(composer-*, auto 등)은 그대로 통과합니다.

RuntimePool

  • prepare(opts, provider): 알려진 cwd에 대해 데몬을 미리 warm-up.
  • findExisting(spawnOpts): 세션 spawn용 strict 매치 (설정 정렬 필요).
  • findCompatible(provider, cwd): completion() / runOnce() 같은 단발 호출용 loose 매치 (MCP, hooks, permission mode는 무시).
  • shutdown(handle): refcount가 0이면 graceful 종료.

Claude Code는 풀링하지 않습니다. CLI 자체가 무상태라서, 일반적인 세션 세분도에선 호출 단위 spawn이 데몬 resume과 경쟁력이 있습니다.

SNA가 ACP만을 런타임 계층으로 삼지 않고 고충실도 네이티브 런타임 어댑터를 유지하는 이유는 SNA와 ACP 에서 다룹니다.

크로스 런타임 노브

모든 런타임에 걸쳐 쓸 수 있는 두 가지 레이턴시 설정:

  • reasoningLevel: 0..5: 런타임 비종속, 가장 가벼움부터 가장 무거움까지. Claude Code의 --effort, Codex의 model_reasoning_effort, Grok Build의 --effort, Cursor의 모델 ID 접미사(gpt-5.3-codex-high 등)로 reasoning-level.ts가 번역합니다. OpenCode는 이 필드를 무시합니다.
  • providerOptions.serviceTier: Codex 전용. Codex의 /fast 슬래시 명령을 모방함 (값: "priority", "flex", "batch"). Claude Code에는 의도적으로 자동 매핑하지 않습니다. Claude Code의 /fast는 별도 과금 풀을 가진 다른 MODEL variant이기 때문입니다.

모든 런타임에 대한 기능별 호환성은 기능 × 런타임 매트릭스 페이지에서 확인할 수 있습니다.

목차