入口点与 SDK
如何调用 Claude Code — CLI、MCP 服务器、无头、桥接、守护进程 — 以及外部开发人员如何通过代理 SDK 在其之上进行构建。
01 入口点层
The src/entrypoints/ 目录是外部世界和 Claude Code 内部之间的边界。 它包含五个表面级文件 - cli.tsx, init.ts, mcp.ts,
agentSdkTypes.ts, 和 sandboxTypes.ts — 加上一个 sdk/ 保存可序列化合约类型的子目录。 main.tsx 位于上一层,是一个基于 Commander 的大型 CLI 处理程序,几乎每个交互式和无头路径都流经该处理程序。
cli.tsx 是一个薄引导程序,可以进行模式匹配 process.argv 和快速路径特殊命令 before 加载 200+ 模块导入图 main.tsx。 这保持 --version 和守护进程工作人员几乎即时启动。
02 cli.tsx — Bootstrap 调度程序
src/entrypoints/cli.tsx 是实际的二进制入口点。 它在任何其他模块评估之前运行。 其设计理念: 为每个快速路径加载尽可能少的负载.
快速路径(按检测顺序)
--version / -v
零进口。 印刷 MACRO.VERSION 在构建时内联并立即退出。
--dump-system-prompt
内部评估工具。 仅加载配置+模型+提示模块来渲染和打印系统提示。
Chrome / 计算机使用 MCP
--claude-in-chrome-mcp and --computer-use-mcp 启动独立的 MCP 服务器,而不使用完整的 CLI 堆栈。
--daemon-worker=<kind>
由守护进程主管产生。 仅加载工作注册表——这一层没有配置、没有身份验证、没有遥测。
桥接/远程控制
remote-control, rc, sync, bridge — 连接本地计算机作为 claude.ai 的远程控制环境。
daemon subcommand
长期运行的主管进程。 设置接收器然后委托给 daemon/main.js.
背景会议
ps, logs, attach, kill, --bg — 会话注册表管理,无需加载交互式 UI。
完整 CLI (main.tsx)
其他一切。 加载完整的基于 Commander 的 CLI 处理程序以及所有 200 多个模块导入。
// From cli.tsx — each fast-path is gated by a build-time feature() flag
if (feature('BRIDGE_MODE') && (args[0] === 'remote-control' || args[0] === 'rc'
|| args[0] === 'remote' || args[0] === 'sync' || args[0] === 'bridge')) {
// Auth check → GrowthBook gate → policy limits → bridgeMain()
const { bridgeMain } = await import('../bridge/bridgeMain.js');
await bridgeMain(args.slice(1));
return;
}
feature() flag — Bun 构建时死代码消除门。 这意味着外部发行版本中完全不存在不受支持的功能,而不仅仅是在运行时进行限制。
03 init.ts — 共享初始化
src/entrypoints/init.ts 是一个已记忆的 init() 由所有重要入口点共享的函数。 这是 不要求快速路径。 它执行第一次 API 调用之前必须发生的所有一次性设置。
init() 做了什么(按顺序)
- enableConfigs() — 验证并激活设置系统
- applySafeConfigEnvironmentVariables() — 在信任对话框之前应用安全环境变量
- applyExtraCACertsFromConfig() — 在第一个 TLS 连接之前设置 TLS CA 证书
- setupGracefulShutdown() — 注册 SIGTERM/SIGINT 处理程序以进行退出时刷新
- initialize1PEventLogging() — 延迟加载 OpenTelemetry 分析(延迟 ~400KB)
- populateOAuthAccountInfoIfNeeded() — 填充钥匙串中缺失的 OAuth 缓存
- initJetBrainsDetection() — 异步检测 IDE 主机
- initializeRemoteManagedSettingsLoadingPromise() — 设置企业策略加载
- 配置GlobalMTLS() / 配置GlobalAgents() — TLS + 代理
- preconnectAnthropicApi() — 与 CLI 解析并行地预热 TCP+TLS (~150ms)
- initUpstreamProxy() — 用于组织注入凭证的 CCR 上游代理 (CLAUDE_CODE_REMOTE)
- registerCleanup(shutdownLspServerManager) — 退出时 LSP 拆除
- ensureScratchpadDir() — 如果启用则创建暂存目录
一个单独的 initializeTelemetryAfterTrust() 仅在用户接受信任对话框后才调用该函数。 这将独立于同意的设置与同意门控遥测分开,并在初始化 OpenTelemetry 导出器之前等待远程托管设置加载。
04 mcp.ts — Claude Code 作为 MCP 服务器
当调用时 claude --mcp, Claude Code 作为标准运行
模型上下文协议服务器 通过工作室。 这会将 Claude Code 的所有工具(Bash、Edit、Read、WebFetch 等)公开给 other MCP 客户端 — 编辑器、代理或自动化脚本可以直接调用它们,而无需生成完整的 REPL。
// src/entrypoints/mcp.ts
const server = new Server(
{ name: 'claude/tengu', version: MACRO.VERSION },
{ capabilities: { tools: {} } }
)
// ListTools: enumerate every Claude Code tool with its Zod-derived JSON schema
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: await Promise.all(tools.map(async tool => ({
...tool,
description: await tool.prompt(...),
inputSchema: zodToJsonSchema(tool.inputSchema),
})))
}))
// CallTool: validate input, check permissions, execute, return result
server.setRequestHandler(CallToolRequestSchema, async ({ params }) => {
const tool = findToolByName(tools, params.name)
return await tool.call(params.arguments, toolUseContext, ...)
})
isNonInteractiveSession: true 并禁止思考(thinkingConfig: { type: 'disabled' })。 它还仅暴露
review 斜杠命令,因为斜杠命令在此上下文中没有意义。
05 agentSdkTypes.ts — 公共 SDK 合约
src/entrypoints/agentSdkTypes.ts 是 Agent SDK 包的主要导出。 它从三个子模块重新导出完整的公共 API,并声明 SDK 消费者调用的顶级函数。 所有函数体都会抛出异常 'not implemented' 在此文件中 - 实际实现由 SDK 传输层在运行时注入。
模块结构
| Module | Purpose | Examples |
|---|---|---|
sdk/coreTypes.ts |
从 Zod 模式生成的可序列化、传输安全的类型 | SDKMessage, SDKUserMessage, ModelUsage, PermissionResult, HookInput |
sdk/runtimeTypes.ts |
具有回调和方法接口的不可序列化类型 | SDKSession, Options, Query, SdkMcpToolDefinition |
sdk/controlTypes.ts |
SDK 构建器的控制协议(桥接子路径消费者) | SDKControlRequest, SDKControlResponse |
sdk/settingsTypes.generated.ts |
从设置 JSON 架构生成的完整设置类型 | Settings |
顶级 SDK 函数
// V1 API (stable) — headless one-shot query
export function query(params: {
prompt: string | AsyncIterable<SDKUserMessage>
options?: Options
}): Query
// V2 API (@alpha) — persistent multi-turn sessions
export function unstable_v2_createSession(options: SDKSessionOptions): SDKSession
export function unstable_v2_resumeSession(sessionId: string, options: SDKSessionOptions): SDKSession
export async function unstable_v2_prompt(message: string, options: SDKSessionOptions): Promise<SDKResultMessage>
// Session management
export async function listSessions(options?: ListSessionsOptions): Promise<SDKSessionInfo[]>
export async function getSessionInfo(sessionId: string): Promise<SDKSessionInfo | undefined>
export async function getSessionMessages(sessionId: string): Promise<SessionMessage[]>
export async function renameSession(sessionId: string, title: string): Promise<void>
export async function tagSession(sessionId: string, tag: string | null): Promise<void>
export async function forkSession(sessionId: string, options?: ForkSessionOptions): Promise<ForkSessionResult>
// In-process MCP server
export function createSdkMcpServer(options: { name: string; tools: SdkMcpToolDefinition[] }): McpSdkServerConfigWithInstance
export function tool<S>(name, description, schema, handler): SdkMcpToolDefinition<S>
06 控制协议(SDK 构建器)
外部 SDK 实现(如 Python claude-code-sdk) 通过基于 JSON 的方式与 Claude Code 进程进行通信 控制协议 分层在 stdio 上。 模式定义在 sdk/controlSchemas.ts.
控制请求子类型
| Subtype | Direction | Purpose |
|---|---|---|
initialize | SDK → CLI | 启动会话 — 通过钩子、MCP 服务器、代理、系统提示覆盖 |
interrupt | SDK → CLI | 取消当前正在运行的回合 |
can_use_tool | CLI → SDK | 请求工具使用许可; SDK 主机响应允许/拒绝 |
set_permission_mode | SDK → CLI | 在会话中更改权限模式(默认/acceptEdits/bypassPermissions/plan/dontAsk) |
set_model | SDK → CLI | 为后续回合切换模型 |
set_max_thinking_tokens | SDK → CLI | 调整扩展思维预算 |
mcp_status | SDK → CLI | 查询当前 MCP 服务器连接状态 |
get_context_usage | SDK → CLI | 按类别检查上下文窗口利用率 |
// Initialize request — sent by SDK to start a session
{
subtype: "initialize",
hooks: {
"PreToolUse": [{ hookCallbackIds: ["my-hook"], matcher: "Bash" }]
},
sdkMcpServers: ["my-server"],
systemPrompt: "You are a coding assistant.",
agents: {
"reviewer": { description: "Reviews code changes", ... }
}
}
// Initialize response — returned by CLI
{
commands: [...], // available slash commands
agents: [...], // available agent types
models: [...], // available models
account: {...}, // account info
pid: 12345 // @internal CLI PID for tmux socket isolation
}
07 挂钩事件 — SDK 观察者模式
SDK 公开了丰富的钩子系统,使外部主机可以观察和拦截 Claude Code 的生命周期。 有 26 个命名的钩子事件,定义在 sdk/coreTypes.ts:
export const HOOK_EVENTS = [
// Tool execution
'PreToolUse', 'PostToolUse', 'PostToolUseFailure',
// Permission flow
'PermissionRequest', 'PermissionDenied',
// Session lifecycle
'SessionStart', 'SessionEnd', 'Setup',
// Turn lifecycle
'Stop', 'StopFailure',
// Context management
'PreCompact', 'PostCompact',
// Agent/swarm lifecycle
'SubagentStart', 'SubagentStop', 'TeammateIdle',
'TaskCreated', 'TaskCompleted',
// Notifications and user input
'Notification', 'UserPromptSubmit',
// Config changes
'ConfigChange', 'InstructionsLoaded', 'CwdChanged', 'FileChanged',
// Elicitation
'Elicitation', 'ElicitationResult',
// Worktree
'WorktreeCreate', 'WorktreeRemove',
] as const
每个钩子都会发射 BaseHookInput 其中包括 session_id,
transcript_path, cwd, agent_id (如果在子代理内部),以及 agent_type。 每个事件都会在顶部添加自己的特定字段。
agent_id (仅存在于子代理内部)- 不 agent_type — 区分子代理钩子触发和主线程触发。 主线程可以有一个
agent_type 当开始于 --agent 但永远不会有 agent_id.
08 守护进程和桥接模式 (@internal)
对于高级主机架构(桌面应用程序、CI 系统、claude.ai 集成),
agentSdkTypes.ts 还出口 @internal primitives:
计划任务/Cron
// Watch .claude/scheduled_tasks.json and yield fire/missed events
export function watchScheduledTasks(opts: {
dir: string
signal: AbortSignal
getJitterConfig?: () => CronJitterConfig
}): ScheduledTasksHandle
// ScheduledTasksHandle — drain with for await
{
events(): AsyncGenerator<ScheduledTaskEvent> // fire | missed
getNextFireTime(): number | null // epoch ms of next scheduled run
}
这使得守护进程拥有父进程中的调度程序。 当任务触发时,守护进程会生成一个 query() 子进程——如果它崩溃了,守护进程可以在计划继续进行的同时重新生成它。
远程控制/桥接器
// Connect the local machine as a claude.ai remote-control environment
export async function connectRemoteControl(opts: ConnectRemoteControlOptions):
Promise<RemoteControlHandle | null>
// RemoteControlHandle — two-way bridge over WebSocket
{
sessionUrl: string
environmentId: string
bridgeSessionId: string
write(msg: SDKMessage): void // pipe query() yields in
sendResult(): void // signal turn complete
inboundPrompts(): AsyncGenerator<...> // read user messages from claude.ai
controlRequests(): AsyncGenerator<...> // interrupt, set_model, etc.
permissionResponses(): AsyncGenerator<...>
onStateChange(cb): void // ready | connected | reconnecting | failed
teardown(): Promise<void>
}
query.enableRemoteControl:WebSocket 存在于子进程中并随之消亡。 使用守护进程模式实现生产级可靠性。
09 sandboxTypes.ts — 进程隔离配置
src/entrypoints/sandboxTypes.ts 是沙箱配置类型的单一事实来源。 SDK 和设置验证系统都从此处导入。 它是通过导出的 agentSdkTypes.ts 因此 SDK 消费者可以配置沙箱。
// SandboxSettings — full configuration for process-level isolation
{
enabled: boolean
failIfUnavailable: boolean // hard-gate for managed deployments
autoAllowBashIfSandboxed: boolean
allowUnsandboxedCommands: boolean
network: {
allowedDomains: string[]
allowManagedDomainsOnly: boolean // enterprise: only managed domains
allowUnixSockets: string[] // macOS only
allowLocalBinding: boolean
httpProxyPort: number
socksProxyPort: number
}
filesystem: {
allowWrite: string[] // merged with Edit() allow rules
denyWrite: string[] // merged with Edit() deny rules
denyRead: string[]
allowRead: string[] // re-allow within denyRead regions
allowManagedReadPathsOnly: boolean
}
}
10 main.tsx — 调用模式
Once cli.tsx 落入 main.tsx,基于 Commander 的 CLI 处理其余的调用模式。 关键:
| 标志/模式 | Behavior |
|---|---|
-p / --print <prompt> |
无头模式 — 以非交互方式运行单个提示,将结果流式传输到标准输出,然后退出。 由脚本和代理 SDK 使用。 |
--mcp |
通过 stdio 将 Claude Code 作为 MCP 服务器启动。 代表们 entrypoints/mcp.ts. |
| (无旗帜) | 交互式 REPL — 渲染完整的 Ink TUI。 通话 launchRepl(). |
--resume [sessionId] |
通过 UUID 恢复之前的会话,或显示恢复选择器 TUI。 |
--continue |
继续最近的会话而不显示选择器。 |
--dangerously-skip-permissions |
绕过所有权限检查(需要在设置中明确选择加入)。 由 CI 环境使用。 |
--allowedTools |
会话的逗号分隔工具允许列表。 |
--sdk-transport=process |
SDK 进程传输模式 — 通过 stdin/stdout 控制协议连接代理 SDK。 |
11 完整的调用流程
要点
cli.tsx是一个纯粹的调度程序 - 它在加载完整的 CLI 之前快速路径 8 个以上的特殊命令,保持版本检查、守护进程工作人员和桥接模式的快速启动。- Build-time
feature()标志执行死代码消除——桥接模式、守护进程、后台会话和其他功能在外部构建中完全不存在,除非启用。 init.ts被所有入口点记忆和共享——它在第一次 API 调用之前协调 TLS 证书、代理、OAuth、遥测和清理处理程序。- Claude Code 可以 be MCP 服务器(
--mcp模式通过mcp.ts)同时也 consuming MCP 服务器 — 边界是对称的。 - 代理 SDK 公共 API (
agentSdkTypes.ts) 是一个存根文件——所有函数体都会抛出异常; 真正的实现是在运行时由 SDK 传输注入的。 - 26 个生命周期挂钩事件让 SDK 主机观察并拦截工具执行、权限决策、会话生命周期、压缩和工作树操作。
- 控制协议将 SDK 消费者(谁调用
query())来自 SDK 构建者(实现进程传输并直接讲控制协议)。 sandboxTypes.ts是进程隔离配置的单一事实来源——由 SDK 导出和设置验证系统使用。
检查你的理解情况
claude --version 为什么它加载零个模块?cli.tsx reads process.argv.slice(2) 在任何导入之前同步。 MACRO.VERSION 是构建时内联,因此不会发出动态导入。cli.tsx 之前行动 any 模块是动态导入的,直接使用检查argv MACRO.VERSION 在构建时内联。agentSdkTypes.ts throw 'not implemented'。 什么机制实际上提供了真正的实现?--sdk-transport=process,传输层通过 stdin/stdout 上的控制协议提供真正的实现。agentSdkTypes.ts 用作类型安全的 API 表面。 当进程实际运行时,SDK 传输会在运行时注入真正的实现。query.enableRemoteControl?connectRemoteControl JSDoc. 在守护进程模式下,父进程持有 WebSocket,因此它可以在代理子进程崩溃时幸存下来,从而在 claude.ai 保持相同会话的同时启用重生。connectRemoteControl 解释:守护进程模式将WebSocket保留在父进程中。 如果代理子进程崩溃,WebSocket 仍然存在,并且守护进程可以重新生成代理。feature() cli.tsx 与运行时 GrowthBook 门不同,例如 isBridgeEnabled()?feature() 必须保持内联以消除构建时的死代码。 如果禁用该功能,则外部发行版本中将完全不存在桥接块、守护程序块等。feature() 是 Bun 构建时 DCE 门。 禁用功能块内的代码将从二进制文件中删除,而不仅仅是在运行时进行分支。