with one click
coding-guidance
本地模式实现指南
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
本地模式实现指南
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
| 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.jsonUse 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.
本仓库代码禁止写任何测试