Claude Code 源码分析第 47 课 · 第 07
第 47 课

ULTRAPLAN

Claude Code 如何将深度多代理规划卸载到远程 CCR 会话 — 从关键字触发到计划批准以及传送回终端。

01 Overview

ULTRAPLAN 是Claude Code 的远程计划模式。 当您输入时 /ultraplan 或嵌入单词 ultraplan 在提示中的任何位置,CLI 都会在云中生成完整的 Claude Code 会话(CCR — 网络上的 Claude Code),在最强大的可用模型 (Opus) 上运行,并有 30 分钟的窗口可通过浏览器与您一起迭代计划。 您的本地终端始终保持免费状态。

覆盖源文件
commands/ultraplan.tsxutils/ultraplan/ccrSession.tsutils/ultraplan/keyword.tsutils/teleport.tsxtasks/RemoteAgentTask/RemoteAgentTask.tsx

在最高级别,ULTRAPLAN 有四个阶段,每个阶段由不同的模块管理:

第一阶段

触发检测

关键字扫描仪(keyword.ts) 在自由格式输入中查找“ultraplan”,或者使用斜杠命令直接路由它。

第二阶段

CCR 会议启动

teleportToRemote() in teleport.tsx 创建远程会话,上传 git 包,并返回会话 ID。

第三阶段

Long-Poll

pollForApprovedExitPlanMode() in ccrSession.ts 每 3 秒轮询一次事件流,持续长达 30 分钟,跟踪阶段转换。

第四阶段

计划交付

获得批准后,该计划将通过以下方式在当地落地: UltraplanChoiceDialog (传送路径)或停留在 CCR(远程执行路径)。

02 端到端流程

该图跟踪了从用户击键到计划交付的确切代码路径:

flowchart TD A["User types prompt\ncontaining 'ultraplan'\nor /ultraplan <prompt>"] --> KW["keyword.ts\nfindUltraplanTriggerPositions()\nfilters quoted/path contexts"] KW --> LP["launchUltraplan()\nultraplan.tsx"] LP --> GUARD{"ultraplanSessionUrl\nor ultraplanLaunching\nalready set?"} GUARD -->|"Yes"| DUPE["Return 'already polling'\nmessage"] GUARD -->|"No"| SET["setAppState: ultraplanLaunching=true\n(prevents duplicate launch\nduring async window)"] SET --> DETACH["launchDetached() — detached void\nReturns launch message immediately\nso terminal stays responsive"] DETACH --> ELIG["checkRemoteAgentEligibility()\nchecks: OAuth login, git repo,\ngit remote, GitHub app, policy"] ELIG -->|"ineligible"| ERR["enqueuePendingNotification\nwith reason string"] ELIG -->|"eligible"| PROMPT["buildUltraplanPrompt(blurb, seedPlan)\nwraps instructions + blurb\nin system-reminder tag"] PROMPT --> TELE["teleportToRemote({\n permissionMode: 'plan',\n ultraplan: true,\n model: getUltraplanModel()\n})\nteleport.tsx"] TELE --> BUNDLE["generateTitleAndBranch() via Haiku\ncreateAndUploadGitBundle()\nPOST /v1/sessions"] BUNDLE --> SESSION["session.id returned\nURL = getRemoteSessionUrl(id)"] SESSION --> STATEURL["setAppState: ultraplanSessionUrl=url\nultraplanLaunching=undefined"] STATEURL --> REGIST["registerRemoteAgentTask(\n remoteTaskType: 'ultraplan',\n isUltraplan: true\n)\n→ pill shown in REPL"] REGIST --> POLL["startDetachedPoll(taskId, sessionId, url)"] POLL --> LOOP["pollForApprovedExitPlanMode()\nccrSession.ts\n3s interval, 30min timeout\nMAX_CONSECUTIVE_FAILURES=5"] LOOP --> SCAN["ExitPlanModeScanner.ingest(newEvents)\nclassifies: approved / teleport /\nrejected / pending / terminated"] SCAN -->|"pending"| PHASE["onPhaseChange('plan_ready')\nupdateTaskState: ultraplanPhase"] SCAN -->|"needs_input (quiet idle)"| NI["onPhaseChange('needs_input')\nUser must reply in browser"] PHASE --> SCAN NI --> SCAN SCAN -->|"terminated"| FAIL["UltraplanPollError(reason='terminated')\narchiveRemoteSession()\nclear ultraplanSessionUrl"] SCAN -->|"approved (in-CCR execute)"| REMOTE["executionTarget='remote'\ntask→completed\nenqueuePendingNotification\n'executing in CCR'"] SCAN -->|"teleport (local execute)"| LOCAL["executionTarget='local'\nsetAppState: ultraplanPendingChoice\n{plan, sessionId, taskId}"] LOCAL --> DIALOG["UltraplanChoiceDialog mounts\nUser chooses: execute here or open in browser"] DIALOG --> ARCHIVE["archiveRemoteSession(sessionId)\nclear ultraplanSessionUrl + pendingChoice"] style A fill:#22201d,stroke:#7d9ab8,color:#b8b0a4 style REMOTE fill:#1f241d,stroke:#6e9468,color:#b8b0a4 style LOCAL fill:#1f241d,stroke:#6e9468,color:#b8b0a4 style FAIL fill:#241b19,stroke:#c47a50,color:#b8b0a4 style POLL fill:#221f28,stroke:#8e82ad,color:#b8b0a4
03 关键词触发:智能消歧

大多数 Claude 功能都需要明确的 /command。 ULTRAPLAN 很不寻常:它由自由格式的文本触发。 这个词 ultraplan 提示中的任何位置都会触发启动 - unless 上下文清楚表明它不是指令。

逻辑完全存在于 utils/ultraplan/keyword.tsfindKeywordTriggerPositions() 功能。 它通过逐个字符地遍历输入来构建“引用范围”列表,然后根据这些范围以及几个附加的防护来过滤单词边界匹配:

// keyword.ts — what is filtered OUT (never triggers)

// 1. Slash-command input — /ultraplan is routed to the command handler, not here
if (text.startsWith('/')) return []

// 2. Inside paired delimiters: `backticks`, "quotes", <tags>, {braces}, [brackets], (parens)
// e.g.  `src/ultraplan/foo.ts`  or  <ultraplan> in HTML  do NOT trigger

// 3. Path / identifier context: preceded or followed by  /  \  -
// e.g.  src/ultraplan/  or  --ultraplan-mode  do NOT trigger

// 4. Followed by ? — a question about the feature shouldn't invoke it
// e.g.  "what is ultraplan?"  does NOT trigger

// 5. Followed by . + word char (file extension)
// e.g.  ultraplan.tsx  does NOT trigger

相同的发动机手柄 ultrareview。 两者都导出类型化的 TriggerPosition[] 因此,PromptInput 组件可以用彩虹效果突出显示匹配的单词,并在用户提交之前显示“将启动 ultraplan”的工具提示。

当检测到关键字并将提示转发到远程会话时,本地提示将被重写,因此单词“ultraplan”变为“plan” - 保持转发的提示符合语法:

// keyword.ts
export function replaceUltraplanKeyword(text: string): string {
  const [trigger] = findUltraplanTriggerPositions(text)
  if (!trigger) return text
  const before = text.slice(0, trigger.start)
  const after  = text.slice(trigger.end)
  if (!(before + after).trim()) return ''
  // Preserves user casing: "ultraplan" → "plan", "Ultraplan" → "Plan"
  return before + trigger.word.slice('ultra'.length) + after
}
04 启动序列深入探讨

“分离”模式

launchUltraplan() 返回面向用户的消息 immediately,在远程会话存在之前。 所有异步工作——资格检查、俳句标题生成、git 包创建、POST 到 CCR——都在一个 void 异步闭包调用 launchDetached()。 调用者永远不会等待它。

// ultraplan.tsx — returns to the REPL in milliseconds
export async function launchUltraplan(opts): Promise<string> {
  // Synchronously set ultraplanLaunching to block duplicate launches
  setAppState(prev => prev.ultraplanLaunching ? prev : { ...prev, ultraplanLaunching: true })

  void launchDetached({ blurb, seedPlan, getAppState, setAppState, signal, onSessionReady })

  return buildLaunchMessage(disconnectedBridge)
  // ↑ "◇ ultraplan\nStarting Claude Code on the web…"
}
设计洞察
The ultraplanLaunching 标志已设置 synchronously 在分离流开始之前。 这会关闭窗口,在该窗口中,两次快速按键都可以在任一方调用之前通过警卫检查 teleportToRemote()。 一旦会话 URL 到达(或发生任何错误),该标志就会被清除。

提示构建和系统提醒技巧

最初的 CCR 消息有一个经过深思熟虑的分层。 简介和种子计划开始 outside the <system-reminder> 标签,以便 CCR 浏览器将它们呈现给用户可见。 脚手架说明(加载自 utils/ultraplan/prompt.txt 在构建时)进入标签内部,因此远程模型可以看到它们,但浏览器 UI 会隐藏它们。 并且提示文本中故意省略了“ultraplan”一词,以避免远程 CCR CLI 自触发另一个会话:

// ultraplan.tsx
export function buildUltraplanPrompt(blurb: string, seedPlan?: string): string {
  const parts: string[] = []
  if (seedPlan) {
    parts.push('Here is a draft plan to refine:', '', seedPlan, '')
  }
  parts.push(ULTRAPLAN_INSTRUCTIONS) // from prompt.txt, wrapped in <system-reminder>
  if (blurb) {
    parts.push('', blurb)
  }
  return parts.join('\n')
}

资格检查

在花时间进行网络通话之前, checkRemoteAgentEligibility() 验证了几个前提条件。 失败以通知形式出现(不是抛出的错误),因此终端不会崩溃:

// RemoteAgentTask.tsx — formatted error messages
case 'not_logged_in':
  return 'Please run /login and sign in with your Claude.ai account (not Console).'
case 'no_remote_environment':
  return 'No cloud environment available. Set one up at https://claude.ai/code/onboarding?magic=env-setup'
case 'not_in_git_repo':
  return 'Background tasks require a git repository.'
case 'no_git_remote':
  return 'Background tasks require a GitHub remote.'
case 'github_app_not_installed':
  return 'The Claude GitHub app must be installed on this repository first.'
case 'policy_blocked':
  return "Remote sessions are disabled by your organization's policy."

teleportToRemote() — CCR 会话工厂

创建远程会话的繁重工作是通过以下方式完成的 teleportToRemote() in utils/teleport.tsx。 特别对于 ULTRAPLAN,它被称为 permissionMode: 'plan' and ultraplan: true。 这会导致 CCR 会话在计划模式下创建 — 远程代理只能计划,而不能执行。 该会话还通过 git 包克隆本地 git 存储库:

// ultraplan.tsx — call site
const session = await teleportToRemote({
  initialMessage: prompt,
  description:   blurb || 'Refine local plan',
  model:         getUltraplanModel(),    // opus4.6 from GrowthBook flag
  permissionMode: 'plan',
  ultraplan:      true,
  signal,
  useDefaultEnvironment: true,
  onBundleFail:  msg => { bundleFailMsg = msg }
})

Inside teleportToRemote(),克劳德俳句生成一个简短的会话标题,并且 claude/<slug> 描述中的分支名称。 然后它发布到 /v1/sessions 包含 OAuth 标头、git 源和初始消息。 返回的 session.id 是接下来一切的锚点。

05 轮询引擎

会议直播后, startDetachedPoll() calls pollForApprovedExitPlanMode() — 30​​ 分钟的基于光标的事件调查。 该函数位于 utils/ultraplan/ccrSession.ts 并且故意没有副作用:它是一个纯异步循环,将所有分类委托给 ExitPlanModeScanner.

基于光标的分页

每一次蜱虫呼叫 pollRemoteSessionEvents(sessionId, cursor) 哪个击中 GET /v1/sessions/{id}/events?after_id={cursor},在一次调用中获取最多 50 页的事件。 光标前进至 response.lastEventId。 这意味着轮询器永远不会重新读取事件 - 每个刻度仅获取新活动。

// ccrSession.ts
const POLL_INTERVAL_MS = 3000
const MAX_CONSECUTIVE_FAILURES = 5  // ~600 calls over 30min; tolerate transient 5xx

while (Date.now() < deadline) {
  if (shouldStop?.()) throw new UltraplanPollError('poll stopped by caller', 'stopped', ...)

  const resp = await pollRemoteSessionEvents(sessionId, cursor)
  cursor = resp.lastEventId
  const result = scanner.ingest(resp.newEvents)
  // ... classify result and update phase ...
  await sleep(POLL_INTERVAL_MS)
}

ExitPlanModeScanner — 纯状态分类器

扫描器累积事件批次并对会话的 ExitPlanMode 状态进行分类。 它跟踪三个内部集合: exitPlanCalls (ExitPlanMode 的工具使用 ID), results (由 ID 键入的 tool_result 块),以及 rejectedIds (用户在浏览器中拒绝的 ID)。 每次摄取时,它都会从最新到最旧进行扫描,以查找第一个未拒绝的呼叫及其解决方案:

// ccrSession.ts — ScanResult kinds
// 'approved'   → plan in tool_result with is_error=false, marker "## Approved Plan:"
// 'teleport'   → is_error=true but contains ULTRAPLAN_TELEPORT_SENTINEL marker
// 'rejected'   → is_error=true, no sentinel — user said "revise this"
// 'pending'    → tool_use seen, no tool_result yet (browser showing approval dialog)
// 'terminated' → result(non-success) — remote session crashed or hit max turns
// 'unchanged'  → no new relevant events
边缘情况:批量订购
单次摄取可以跨越数秒的会话活动(最多 50 页的事件)。 扫描仪的设计使得如果批次同时包含批准和后续崩溃事件(type:'result', subtype:'error_during_execution'),返回批准的计划 - 代码注释明确记录了此优先级: “已批准 > 已终止 > 已拒绝 > 待定 > 未更改”.

相变和药丸徽章

轮询器通过以下方式向 UI 呈现三个阶段 onPhaseChange():

Phase

running

默认。 远程正在执行轮流。 没有特殊徽章。

Phase

needs_input

远程问了一个澄清问题并闲着。 徽章:“需要输入”。 用户必须在浏览器中回复。

Phase

plan_ready

ExitPlanMode tool_use 存在但没有 tool_result。 徽章:“计划就绪”。 浏览器正在显示批准对话框。

过渡到 needs_input 使用仔细的启发式: sessionStatus === 'idle' AND newEvents.length === 0。 第二个条件至关重要 - CCR 在工具轮次之间短暂翻转为“空闲”状态,因此轮询器仅在同一时间周期内没有活动时才信任它:

// ccrSession.ts — quiet-idle heuristic
const quietIdle =
  (sessionStatus === 'idle' || sessionStatus === 'requires_action') &&
  newEvents.length === 0

const phase: UltraplanPhase = scanner.hasPendingPlan
  ? 'plan_ready'
  : quietIdle
    ? 'needs_input'
    : 'running'
06 计划交付:两条路径

当投票结果确定后, executionTarget 字段决定计划运行的位置。 恰好有两种结果:

路径 A:远程执行(CCR 中“已批准”)

用户在 CCR 浏览器 PlanModal 中单击“执行”。 远程会话已处于编码模式。 本地 CLI 不得存档会话(存档会停止会话),并且不得显示选择对话框。 它只是标记任务已完成并将通知排入队列:

// ultraplan.tsx — remote execution path
if (executionTarget === 'remote') {
  updateTaskState(taskId, setAppState, t => ({
    ...t, status: 'completed', endTime: Date.now()
  }))
  enqueuePendingNotification({
    value: [
      `Ultraplan approved — executing in Claude Code on the web. Follow along at: ${url}`,
      '',
      'Results will land as a pull request when the remote session finishes.',
      'There is nothing to do here.'
    ].join('\n'),
    mode: 'task-notification'
  })
}

路径 B:传送(“传送回终端”)

用户在 PlanModal 浏览器中单击“传送回终端”。 浏览器发送一个 is_error=true tool_result 与哨兵字符串 __ULTRAPLAN_TELEPORT_LOCAL__ 作为前缀,后跟计划文本。 扫描仪检测到这一点并返回 { kind: 'teleport', plan }。 民意调查结果如下: executionTarget: 'local'.

然后本地 CLI 设置 ultraplanPendingChoice 在 AppState 中,这会导致 REPL 挂载 UltraplanChoiceDialog。 该对话框负责归档远程会话并根据用户选择清除状态:

// ccrSession.ts — teleport plan extraction
export const ULTRAPLAN_TELEPORT_SENTINEL = '__ULTRAPLAN_TELEPORT_LOCAL__'

function extractTeleportPlan(content): string | null {
  const text = contentToText(content)
  const marker = `${ULTRAPLAN_TELEPORT_SENTINEL}\n`
  const idx = text.indexOf(marker)
  if (idx === -1) return null         // no sentinel → normal rejection
  return text.slice(idx + marker.length).trimEnd()
}

// approved path uses a different extractor
function extractApprovedPlan(content): string {
  // Checks "## Approved Plan (edited by user):\n" first,
  // then "## Approved Plan:\n"
}
07 停止和清理

停止 ULTRAPLAN 是经过协调的:CLI 存档远程会话(这会停止它,但保持 URL 可见),终止本地任务条目,并清除所有相关的 AppState 字段。 独立民意调查 shouldStop 回调在下一个滴答声中检测到终止状态并抛出 UltraplanPollError 合理 'stopped' — 民意调查的 catch 块通过提前返回来处理(没有额外的通知)。

// ultraplan.tsx
export async function stopUltraplan(taskId, sessionId, setAppState): Promise<void> {
  await RemoteAgentTask.kill(taskId, setAppState) // archives session internally
  setAppState(prev => ({
    ...prev,
    ultraplanSessionUrl:     undefined,
    ultraplanPendingChoice:  undefined,
    ultraplanLaunching:      undefined
  }))
  // Enqueue two notifications: one for the user, one meta-instruction
  // for the model so it doesn't try to respond to the stop event
  enqueuePendingNotification({ value: `Ultraplan stopped.\n\nSession: ${url}`, ... })
  enqueuePendingNotification({
    value: 'The user stopped the ultraplan session above. Do not respond...',
    mode: 'task-notification',
    isMeta: true  // ← model-only instruction, not shown to user
  })
}
孤儿预防
如果发生错误 after teleportToRemote() 成功了但是 before poll 循环是健康的,catch 块显式地归档会话。 如果没有这个,远程容器将运行 30 分钟,而没有轮询器监视它。 当地的 sessionId 变量被精确地提升到 try 块之上,以便 catch 可以引用它。
08 远程代理任务集成

ULTRAPLAN 会话注册为 RemoteAgentTaskState 统一任务框架中的条目。 这就是驱动 REPL 状态栏中的药丸的原因。 这 isUltraplan: true 标志将它们与常规远程代理任务区分开来,因此通用轮询器(startRemoteSessionPolling) 知道不要自行声明完成 — ULTRAPLAN 生命周期由 startDetachedPoll:

// RemoteAgentTask.tsx — state shape (relevant fields)
type RemoteAgentTaskState = TaskStateBase & {
  type:             'remote_agent'
  remoteTaskType:   RemoteTaskType   // 'ultraplan' | 'ultrareview' | 'remote-agent' | ...
  sessionId:        string
  isUltraplan?:     boolean
  // Scanner-derived pill badge state
  ultraplanPhase?:  Exclude<UltraplanPhase, 'running'>  // 'needs_input' | 'plan_ready'
  log:              SDKMessage[]   // populated by the generic poller for the detail view
  todoList:         TodoList
}

该会话还通过以下方式持久保存到磁盘上的 sidecar 文件中 writeRemoteAgentMetadata()。 这意味着如果您关闭终端并重新打开它 claude --resume,ULTRAPLAN 会话恢复:读取 sidecar,获取 CCR 状态,如果会话仍在运行,则重新启动轮询。

09 模型选择和特征标志

远程模型不是硬编码的。 它在调用时从 GrowthBook 功能标志中读取,回退到 Opus 4.6 第一方 ID:

// ultraplan.tsx
function getUltraplanModel(): string {
  return getFeatureValue_CACHED_MAY_BE_STALE(
    'tengu_ultraplan_model',
    ALL_MODEL_CONFIGS.opus46.firstParty   // fallback
  )
}

请注意来源中的评论: “在调用时读取,而不是模块加载:GrowthBook 缓存在导入时为空,/config Gates 可以在调用之间翻转它。” 这就是该函数不是模块级常量的原因。

还有一个仅限开发的提示覆盖:当构建为 ant (内部)构建和 ULTRAPLAN_PROMPT_FILE env var 指向一个文件,该文件替换捆绑的 prompt.txt。 该路径在编译时从外部构建中消除了死代码。

10 阶段状态机

正在运行的 ULTRAPLAN 会话的三相状态机记录在源注释中,值得明确可视化:

stateDiagram-v2 [*] --> running : Session created\npolling starts running --> needs_input : quietIdle\n(sessionStatus=idle AND\nnewEvents=0) needs_input --> running : User replies\nin browser\n(new events arrive) running --> plan_ready : ExitPlanMode tool_use\nseen, no tool_result yet plan_ready --> running : User rejects plan\n(is_error=true, no sentinel) plan_ready --> approved : User approves\n(is_error=false)\nexecutionTarget=remote plan_ready --> teleport : User clicks\n"back to terminal"\n(sentinel found)\nexecutionTarget=local running --> terminated : result(non-success)\nsubtype=error_during_execution\nor error_max_turns running --> timeout : 30 minutes elapsed\nno approval seen approved --> [*] teleport --> [*] terminated --> [*] timeout --> [*]
深入探讨:ExitPlanModeScanner ingest() 逻辑一步一步

扫描器分两次处理事件批次。 第一遍:它​​遍历批次中的每个事件并更新三个内部数据结构:

  • For type:'assistant' messages — 任何具有名称的 tool_use 块 exit_plan_mode_v2 已将其 ID 推送至 exitPlanCalls[]
  • For type:'user' messages — tool_result 块存储在 results 地图由 tool_use_id
  • For type:'result' 具有非成功子类型 — 集 terminated 带有子类型字符串的标志

第二遍(扫描):迭代 exitPlanCalls 从最新到最旧,跳过被拒绝的 ID。 对于每位候选人:

  • 还没有工具结果 → { kind: 'pending' }
  • 工具结果与 is_error=true + 哨兵 → { kind: 'teleport' }
  • 工具结果与 is_error=true,没有哨兵 → { kind: 'rejected' }
  • 工具结果与 is_error=false{ kind: 'approved' }

优先级解析:批准/传送立即返回(无终止检查)。 拒绝的 ID 将添加到集合中,并计划在下一个周期进行重新扫描。 终止优先于拒绝和待定,但不高于批准/传送。

The rescanAfterRejection 标志是性能优化:当没有发生任何事情(没有新事件,没有拒绝最后一个滴答)时,扫描将完全跳过 - 结果不会改变。

11 要点

本课涵盖的内容

  • ULTRAPLAN 将多代理规划卸载到远程 CCR 会话(仅限规划模式、Opus 模型、30 分钟窗口),同时保持本地终端完全空闲。
  • 关键字扫描仪在 keyword.ts 在触发触发器之前过滤引用的上下文、文件路径、斜杠命令和问号 - 自由格式文本即可工作。
  • 中的“分离”模式 launchUltraplan() 立即返回一条消息并在 a 中运行所有异步工作 void 关闭——终端永远不会阻塞。
  • The ultraplanLaunching 标志已设置 synchronously 在任何异步调用之前,关闭双启动竞争窗口。
  • 轮询循环使用基于游标的分页(每个刻度最多 50 页),最多可容忍 5 次连续网络故障,并驱动三态阶段机(running → needs_input → plan_ready).
  • The ExitPlanModeScanner 是一个无副作用的状态分类器:它可以从记录的事件日志中离线重放以进行调试。
  • 两种交付路径: remote (用户在浏览器中批准,CCR 执行,结果作为 PR 落地)和 teleport (用户单击“返回终端”,计划通过哨兵字符串嵌入到拒绝 tool_result 中)。
  • 停止会清除三个 AppState 字段、存档远程会话并发送 isMeta:true 仅模型通知,因此本地模型不会尝试响应停止事件。
  • 会话存活 --resume:如果 CCR 会话仍然存在,元数据将保留到 sidecar 文件并在重新启动时恢复。

知识检查

1. 以下哪项不会触发 ULTRAPLAN 关键字扫描仪?
2. 为什么是 ultraplanLaunching 同步设置 before 分离的异步流程开始了吗?
3. 什么是 quietIdle 过渡到之前的启发式要求 needs_input?
4. 传送路径信号如何通过CCR事件流“将计划发送回本地终端”?
5. 当用户批准执行时 在 CCR 浏览器中 (远程路径),本地 CLI 应该如何处理远程会话?