con un clic
coding-guidance
本地模式实现指南
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
本地模式实现指南
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Use when extracting, formatting, refreshing, or investigating a read-only formatted snapshot of the installed Cursor.app bundle under .cursor-app-formatted; includes git-ignore rules, snapshot generation workflow, and the rule to inspect formatted code without patching either the snapshot code or the installed app.
Use when debugging Cursor client agent/local-mode/tool/backend-store/provider-replay failures in this repo, especially after the state/context history-store refactor, when triaging installed app bundles read-only, correlating installed-client behavior with repo code, mapping a user-provided id to conversation/request/model-call evidence, replaying provider requests from debug logs, or locating the current client/backend/protocol/log files quickly.
当需要调查 Cursor 本地模式 debug/log 证据时使用:config.yaml 的 log 热加载、history/<conversationId>/debug JSONL 文件、Bidi 原始/解码记录、RunSSE 记录、runtime/provider debug 记录、debug 文件缺失原因,或解释这些 debug 文件如何生成与如何查询。
Use when changing prompt compilation, history replay, persisted conversation state, model request construction, or dynamic reminders in this repo; protects prefix-cache hit rate by keeping model-visible history append-only and dynamic attention scoped to the latest request.
本仓库代码禁止写任何测试
| name | coding-guidance |
| description | 本地模式实现指南 |
当用户在处理本地模式的时候,使用此指南
先遵守这个约束:
如果问题已经涉及以下任一事项,请同时读取 ../cursor-client-e2e-debugging/SKILL.md:
本地模式协议需要优先核对这些文件:
cursor-app-formatted skill。.cursor-app-formatted/,排查客户端 bundle 时优先读取这里的格式化副本。.cursor-app-formatted/ 是从 /Applications/Cursor.app/Contents/Resources/app 只读提取后格式化生成的本地快照;它不应写回、替换或影响已安装的 Cursor.app。.cursor-app-formatted/extensions/cursor-always-local/dist/main.js.cursor-app-formatted/extensions/cursor-agent-exec/dist/main.js.cursor-app-formatted/extensions/cursor-agent-worker/dist/main.js.cursor-app-formatted/out/vs/workbench/workbench.desktop.main.js.cursor-app-formatted/out/vs/workbench/api/node/extensionHostProcess.js.cursor-app-formatted/ 不存在、明显过期,或需要核对真实安装包 hash,再只读读取 /Applications/Cursor.app 原始 bundle。history/<conversationId>/state.json + history/<conversationId>/context.json 为持久化事实源。state.json 保存会话元数据和当前状态,例如 next_turn_seq、next_entry_seq、context_version、current_todos、current_plans、latest_request_prefix、last_provider_call。context.json.items 保存 append-only 的语义历史 entries;provider messages 不是主存储事实,而是由 ProjectPromptReplay() 从 entries 投影出来。modelID 决定;当前规范化渠道 ID 是 baseURL + modelID + apiKey + displayName + openAIEndpoint 的短 SHA-256 hash,resolver 仍兼容 legacy baseURL + modelID + apiKey + displayName。state.json 状态或本轮 latest-only suffix;不要无意持久化成会在后续轮次无限 replay 的历史。run_request 到来时,服务端应通过 LoadConversation() 读取 state.json + context.json,再由 projector 投影 prompt replay;客户端带回来的 checkpoint/replay 不参与历史承接真相判定。summary.json、replay.json、runtime.json、request.json、conversation.json、entries.jsonl、turns/ 和数字 turn 目录都属于旧持久化产物,会被 history maintenance 当 legacy artifact 清理。context.json.items 是否缺失、重复、顺序异常,以及 state.json 的 next_entry_seq、next_turn_seq、context_version、当前状态字段是否与 entries 派生结果一致;不要再按旧 summary.json 路径排查。AgentServerMessage 不是统一都要“回复完成”要按 oneof message 分类看:
exec_server_message
ExecClientMessage。ExecClientControlMessage,常见是:
stream_closethrowheartbeatinteraction_query
InteractionResponse。interaction_update
conversation_checkpoint_update
kv_server_message
exec_server_control_message
ServerMessage 自动回 ack”的通用层在 cursor-always-local/dist/main.js 里,BidiTransport.startYieldingInputsToTheServer 只会把“客户端主动产出的消息”送到 BidiAppend:
p.value.toBinary() 后 hex 编码,再发 BidiAppendRequest.dataAgentClientMessage 才会上行AgentServerMessage 就自动回 completed/ack”的统一机制因此客户端是否回包,取决于上层业务逻辑有没有因为某个下行消息而主动构造新的 AgentClientMessage。
从 cursor-always-local/dist/main.js 里能直接确认:
AgentServerMessage 的下行类型里有:
interaction_updateexec_server_messageexec_server_control_messageconversation_checkpoint_updateinteraction_queryAgentClientMessage 的上行类型里有:
run_requestexec_client_messageexec_client_control_messageinteraction_response这意味着本地模式不是“server message -> 通用 ack”模型,而是:
exec_server_message
-> 客户端执行本地工具
-> 产出 exec_client_message
-> 以及可选 exec_client_control_messageinteraction_query
-> 客户端展示或处理交互
-> 产出 interaction_responseexec_server_message 常见的客户端回包形态客户端协议模型里已确认这些回包类型:
ExecClientMessage
read_result / write_result / grep_result / ls_result / diagnostics_result / mcp_result / shell_stream 等ExecClientControlMessage
stream_closethrowheartbeat所以调查本地模式 exec 问题时,不要只盯 ExecClientMessage:
shell_streamstream_close / heartbeat)exec_server_message 的完整回包形态事实依据:
proto/agent_v1.proto
ExecServerMessage.oneof messageExecClientMessage.oneof messageExecClientControlMessage.oneof messagecursor-always-local/dist/main.js
BidiTransport.startYieldingInputsToTheServer 说明客户端上行消息来自业务逻辑主动构造,不存在通用自动 ackExecServerMessage -> ExecClientMessageExecServerMessage 的 message 分支与 ExecClientMessage 的 message 分支是一一对应的:
shell_args
-> shell_resultwrite_args
-> write_resultdelete_args
-> delete_resultgrep_args
-> grep_resultread_args
-> read_resultls_args
-> ls_resultdiagnostics_args
-> diagnostics_resultrequest_context_args
-> request_context_resultmcp_args
-> mcp_resultshell_stream_args
-> shell_streambackground_shell_spawn_args
-> background_shell_spawn_resultlist_mcp_resources_exec_args
-> list_mcp_resources_exec_resultread_mcp_resource_exec_args
-> read_mcp_resource_exec_resultfetch_args
-> fetch_resultrecord_screen_args
-> record_screen_resultcomputer_use_args
-> computer_use_resultwrite_shell_stdin_args
-> write_shell_stdin_resultexecute_hook_args
-> execute_hook_resultsubagent_args
-> subagent_result所有这些结果面回包都带:
idexec_id服务端匹配时通常优先用:
exec_ididExecServerMessage -> ExecClientControlMessage除了结果面回包外,客户端还可能回控制面消息:
stream_close
idthrow
id + error + 可选 stack_traceheartbeat
idExecClientControlMessage 不是某个单独 ExecServerMessage 分支的“专属结果类型”ExecClientMessageExecClientControlMessage对于任意 exec_server_message,至少要确认以下之一是否发生:
ExecClientMessageExecClientControlMessage.throwExecClientMessagestream_close如果只看到 started / pending,没有任何结果面或控制面回包,服务端 pending 大概率不会收口。
排查时优先搜索这些关键字:
在本仓库修本地模式 forwarder 时,默认遵守下面这些稳定约束,避免再次引入“工具晚到污染当前轮”或“同一 request 在 [DONE] 后又续跑一轮”的问题。
request_id 不是 provider 调用代次;同一个 request 可以合法包含多次 provider pass。scheduleProviderResume 不能只依赖 request 级布尔态(例如单个 ResumePending)。driveProvider 开始与结束时都要显式清理上一轮的 resume 状态,不能让旧状态跨 pass 残留。ExecClientMessage / ExecClientControlMessage 晚于 provider [DONE] 到达是正常现象。stream_close synthetic recovery 也必须沿用原工具的来源 pass,不能按 request 级全局状态续跑。selectPendingExec / selectPendingExecByControl 只允许按:
exec_idmessage_id
进行匹配。stream_close / throw 如果 pending 已不存在:
RecentCompletedExecs 做幂等忽略如果出现下面任一现象,先查 forwarder 状态机,不要先怪客户端:
request_id 在 [DONE] 后又出现新的 model_call_idturns/<n+1>/request.json 与 turns/<n>/request.json messages 几乎完全相同grepResult/readResult/... 晚于上一轮 [DONE]stream_close 恰好跨到下一轮 provider 已经启动之后优先核对:
ProviderPassCount
resume 请求的来源 pass
PendingExec.ProviderPass
selectPendingExec 是否存在跨轮误匹配
startYieldingInputsToTheServer
bidiAppend({requestId:A,appendSeqno
ExecServerMessage
ExecClientMessage
ExecClientControlMessage
InteractionQuery
InteractionResponse
exec_server_message / interaction_query 属于“请求型下行消息”
interaction_update / conversation_checkpoint_update 属于“通知型下行消息”
AgentServerMessage 是哪一类exec_server_message
ExecClientMessagestream_close 但没有真正结果exec_id / id 是否匹配interaction_query
InteractionResponseconversation_checkpoint_update
pending_tool_calls / root_prompt_messages_json / turnsServerMessage 统一建模成“发出去就等一个完成 ack”PendingExecPendingInteractionRunSSE 重连,要优先看 checkpoint / pending_tool_calls 里的 live pendinghistory/<conversationId>/state.json + history/<conversationId>/context.json