篇章一 · 1.5
六种运行模式与 SDK
篇章一最后一站:看同一个 cli.tsx 如何分化出终端工具、CI 脚本、MCP 服务器、后台守护、嵌入式 SDK 五副面孔——这是后面 Agent 系统的地基。
一套代码,六种形态
你平时敲 claude 进交互界面,只是它的主形态。同一份代码还可以作为脚本跑在 CI 里、作为工具服务器被别的 AI 调用、作为库被嵌进你的应用——入口都是一个。
六种运行模式
| 模式 | 触发方式 | UI | 用途 |
|---|---|---|---|
| 交互式 REPL | claude(默认) | Ink/React TUI | 主形态,日常使用 |
| 非交互 Print | claude -p "…" | 纯文本 stdout | CI/CD 集成、脚本调用(runHeadless) |
| MCP Server | claude mcp serve | 无(stdio) | 把自己作为 MCP 服务端,供其他 AI 当工具用 |
| Daemon | claude daemon | 无 | 长驻后台监督进程 |
| SDK | NPM 包引入 | 程序化 | 嵌入其他应用(本站下半场) |
| Remote | claude remote-control | 无 | 远程桥接控制 |
✳ Welcome to Claude Code╭────────────────────╮│ ❯ 你好,帮我看看这个项目_|(交互对话、权限弹窗、Esc 中断都在这)
$ claude -p "总结这个项目"本项目是一个 React 组件库,包含 42 个组件…(纯 stdout,没有界面——给 CI 管道用的)
(静默等待 stdio…)→ {"jsonrpc":"2.0","method":"tools/list"}← {"tools":[{"name":"Bash"},…]}(它成了别的 AI 的工具服务器)
[daemon] listening on /tmp/claude/…sock[daemon] task queued: 3 running: 1(后台长驻,管着别的会话的生死)
import { query } from '@anthropic-ai/claude-code';const msg = await query({ prompt: "hi" });(它成了一行 import——嵌进你的应用里)
bridge: connected → claude.aichannel: Telegram/iMessage 待命(远程桥接:手机上继续指挥电脑里的它)
六副面孔底下是同一套内脏:工具系统、权限管线、会话存储、上下文压缩全部共享——这就是「一套代码多种形态」的价值。
SDK 的戏法 · 类型桩 + 构建注入
源码里有一个文件 agentSdkTypes.ts,导出 15+ 个函数(tool()、query()、listSessions()…),但每个函数体都只有一行:
export function tool(…): Tool {
throw new Error('not implemented') // ← 源码里的全部
} 这不是没写完——这些是类型占位桩。真正的实现在打包构建时由 esbuild/bun 替换注入。发布出去的 npm 包里,桩被真实现覆盖;仓库源码里,桩只负责让 TypeScript 类型检查通过。
SDK ↔ CLI · JSON-over-stdio 协议
你的应用(SDK 侧)和 Claude Code(CLI 侧)是两个进程,靠 stdin/stdout 传 JSON 通信:
你的应用 → stdin → CLI
⇅
CLI → stdout → 你的应用
📦
支持 20+ 种控制操作:initialize、interrupt、权限处理、模型切换、MCP 管理……协议定义集中在 controlSchemas.ts(Zod 校验)。KeepAlive 消息维持心跳,防止空闲断连。
篇章一收束:现在你知道了它怎么泄露的(1.1)、长什么样(1.2)、怎么启动(1.3)、有几副面孔(1.4)。下一章进它的心脏——queryLoop 主循环与 AsyncGenerator 流式管道,那里才是 Agent 真正「活着」的地方。