2026-08-16 17:29:29 +08:00
2026-08-13 22:01:18 +08:00
2026-08-13 22:01:18 +08:00
2026-08-13 22:01:11 +08:00
2026-08-16 17:29:29 +08:00
2026-08-16 17:29:29 +08:00
2026-08-16 17:29:29 +08:00
2026-08-16 17:29:29 +08:00
2026-08-13 22:01:11 +08:00
2026-06-30 10:46:26 +08:00
2026-08-16 17:29:29 +08:00

Cursor Rust 服务端实施与验收计划

项目说明

cursor-byok 是一个兼容 Cursor Agent 客户端协议的自托管服务端项目,用于把 Cursor 客户端接入用户指定的 LLM Provider。项目根据真实客户端流量和提取出的 protobuf 协议实现,不依赖 Cursor 原服务保存对话状态。

当前 Rust 服务 cursor-server 实现以下完整链路:

  • 通过 RunSSE + BidiAppend 组成的双向协议与 Cursor 客户端通信。
  • 将 OpenAI Chat、OpenAI Responses 和 Anthropic 的流式响应统一为内部 ResponseEvent
  • 运行无状态 LLM LoopLLM → 客户端工具执行 → 结果追加 → 下一轮 LLM,直到 Turn 完成或被新 Run 打断。
  • 以 append-only messages 作为上下文唯一事实源,保证相邻 LLM 请求的稳定前缀和可重复投射。
  • 支持文本、thinking、tool start、参数增量、tool result、usage、model、rules、commands、skills、MCP 和 subagent 上下文。
  • 使用 SQLite 持久化 messages、Run 状态、Blob CAS、引用边和 outbox。
  • 使用不可变 Blob 对象图表达 Conversation、Turn、UserMessage 和 StepsBlobID 为原始内容的 SHA-256
  • 在客户端确认 Blob 已存储后发布 checkpoint,并提供单工具粒度的历史回滚和未确认操作恢复。

运行时职责划分如下:Cursor 客户端负责真正执行本地工具并保存服务端同步的 Blob;cursor-server 负责 Loop 决策、上下文投射、Provider 调用、状态持久化和 checkpoint 构造。Todo/Plan 等业务状态不单独维护,而是从 messages 确定性推导。

协议与状态模型的抓包结论见 Cursor上下文与状态同步抓包分析.md。Rust 服务的启动方式和运行配置见 cursor-server/README.md

目录硬约束

下列目录、文件名和职责是实现验收条件,不是建议。首版只允许一个 cursor-server crate;代码必须落在对应文件,不得用 core.rsservice.rs 等总入口替代,也不得提前创建 MCP/subagent 空模块。新增文件必须说明为何现有职责无法容纳;删除、改名或移动下列文件必须先同步修改本计划。

cursor-byok/
├── cursor-server/                 # 新 Rust 服务
│   ├── Cargo.toml
│   ├── build.rs                   # 从 cursor-proto/proto 生成 prost 类型
│   ├── README.md                  # 启动方式、架构和核心不变量
│   │
│   ├── migrations/
│   │   └── 0001_initial.sql       # Blob、messages、runs、outbox
│   │
│   ├── src/
│   │   ├── main.rs                # 进程入口
│   │   ├── lib.rs                 # 模块出口
│   │   ├── app.rs                 # 依赖组装、启动和关闭
│   │   ├── config.rs              # 地址、数据库、provider 配置
│   │   ├── error.rs               # 服务统一错误
│   │   │
│   │   ├── model/                 # 纯领域类型,不依赖 Cursor/provider
│   │   │   ├── mod.rs
│   │   │   ├── message.rs         # CanonicalMessage、Role、Origin
│   │   │   ├── runtime_tag.rs     # RuntimeEvent、exactly-once 约束
│   │   │   ├── conversation.rs    # Conversation、Turn、revision
│   │   │   ├── tool.rs            # ToolCall、ToolResult
│   │   │   └── usage.rs           # provider usage 与 Turn usage
│   │   │
│   │   ├── run/                   # Loop 引擎和一次 request 的状态机
│   │   │   ├── mod.rs
│   │   │   ├── registry.rs        # request_id → RunHandle
│   │   │   ├── actor.rs           # 每个 Run 一个 actor
│   │   │   ├── command.rs         # run_request、exec/KV result、abort
│   │   │   ├── inbox.rs           # append_seqno 排序、去重
│   │   │   ├── loop_engine.rs     # LLM → Tool → LLM 主循环
│   │   │   └── lifecycle.rs       # turn_ended/checkpoint/EndStream
│   │   │
│   │   ├── cursor/                # Cursor 协议适配器
│   │   │   ├── mod.rs
│   │   │   ├── proto.rs           # include prost 生成代码
│   │   │   ├── connect.rs         # 5-byte Connect envelope
│   │   │   ├── handlers.rs        # Axum 路由入口
│   │   │   ├── bidi_append.rs     # 上行 AgentClientMessage
│   │   │   ├── run_sse.rs         # 下行 AgentServerMessage
│   │   │   ├── interaction.rs     # 交互事件、Tool args 和 usage 投射
│   │   │   ├── exec.rs            # Exec 上行/下行解析
│   │   │   ├── pending.rs         # Exec/Interaction 的运行期 ID 关联
│   │   │   ├── tools.rs           # 唯一工具路由、本地工具和 Cursor step index
│   │   │   ├── tool_result.rs     # typed result、UI completion 和结果通道
│   │   │   ├── blob_sync.rs       # KV GET/SET、ACK、重试
│   │   │   └── checkpoint.rs      # Blob 图和 checkpoint 构造
│   │   │
│   │   ├── provider/              # LLM 端点适配器
│   │   │   ├── mod.rs             # Provider trait
│   │   │   ├── event.rs           # Canonical ResponseEvent
│   │   │   ├── openai_chat.rs     # 第一条可运行链路
│   │   │   ├── openai_responses.rs
│   │   │   └── anthropic.rs
│   │   │
│   │   ├── prompting/             # 模型请求编译
│   │   │   ├── mod.rs
│   │   │   ├── assets.rs          # 校验并嵌入根目录 prompt/
│   │   │   ├── compiler.rs        # messages + mode + tools
│   │   │   ├── projector.rs       # CanonicalMessage → provider 格式
│   │   │   └── derived_state.rs   # 从 messages fold Todo/Plan
│   │   │
│   │   └── store/                 # SQLite 持久化
│   │       ├── mod.rs
│   │       ├── sqlite.rs           # pool、事务、PRAGMA
│   │       ├── messages.rs         # append-only messages
│   │       ├── blobs.rs            # CAS 与引用边
│   │       ├── conversations.rs    # conversation head/revision
│   │       ├── runs.rs             # 活动 Run 和恢复信息
│   │       └── outbox.rs           # KV/checkpoint 待确认操作
│   │
│   └── tests/
│       ├── support/
│       │   ├── fake_provider.rs
│       │   ├── fake_cursor.rs
│       │   └── fixtures.rs
│       ├── text_turn.rs            # 纯文本完整 Turn
│       ├── tool_loop.rs            # LLM → Tool → LLM
│       ├── runtime_tag_once.rs      # Runtime tag 不重复追加
│       ├── prefix_stability.rs      # M(n) 是 M(n+1) 前缀
│       ├── checkpoint_recovery.rs   # 单 Tool 回滚
│       ├── interrupt.rs             # 新 Run 打断旧 Run
│       └── connect_wire.rs          # Connect 二进制兼容性
│
├── cursor-proto/                   # 现有 protobuf 提取和源文件
├── cursor-backend/                 # 现有 Go 抓包调试器
├── prompt/                         # 已复制的完整模式资产
└── docs/

按文件实施顺序与通过条件

  1. Cargo.tomlbuild.rssrc/{main,lib,app,config,error}.rs:服务能加载配置、迁移数据库、生成 Cursor protobuf 并启动/优雅关闭。
  2. src/model/*.rssrc/store/*.rsmigrations/0001_initial.sql:实现纯领域消息、runtime tag、tool/usage,以及 append-only messages、Blob CAS/引用边、revision、run 恢复与 outboxtests/runtime_tag_once.rstests/prefix_stability.rs 必须通过。
  3. src/cursor/{proto,connect,handlers,bidi_append,run_sse}.rs:实现抓包一致的 5-byte Connect envelope、二进制 RunSSE、BidiAppend 解码和 append_seqno 排序去重;tests/connect_wire.rs 必须通过。
  4. src/provider/{event,openai_chat,openai_responses,anthropic}.rssrc/prompting/*.rs:三个端点统一为 canonical ResponseEvent;所有 mode 的 prompt/tool 资产可加载;messages 投射幂等且保持严格前缀。
  5. src/run/*.rssrc/cursor/{tools,interaction,exec,pending,tool_result}.rs:一个 request 一个 RunActorLoop 只处理统一 ToolCompletion,工具名称到 Exec/Interaction/Local 的唯一映射只存在于 cursor/tools.rs;完成 toolstart 占位、参数增量、客户端执行、打断与 usage。每个完成的工具必须原子追加 assistant(tool_call) → tool(result),整批完成前不得进入下一次 LLM。
  6. src/cursor/{blob_sync,checkpoint}.rssrc/store/{blobs,outbox}.rs:构造不可变 Blob 对象图,KV SET 未 ACK 前不得发布引用它的 checkpointcheckpoint 达到单工具粒度,最终状态重复发布后再 EndStream;tests/checkpoint_recovery.rs 必须通过。
  7. tests/{text_turn,tool_loop,interrupt}.rstests/support/*.rs:覆盖纯文本 Turn、完整工具循环、新 Run 打断旧 Run和恢复路径。最终验收命令固定为 cargo fmt --checkcargo clippy --all-targets -- -D warningscargo test --all-targets

模块依赖方向固定为:

HTTP/Connect ↓ cursor adapter ↓ run actor ↓ model + prompting ↓ provider / client tools ↓ store + checkpoint

几个关键决定: model/ 不引用 Cursor protobuf,也不引用具体 provider。 cursor/ 只负责协议转换,不能包含 Loop 业务决策。 provider/ 只把不同端点转换为统一 ResponseEvent。 prompting/derived_state.rs 只 fold messages,不持久化 Todo/Plan。 store/messages.rs 是上下文唯一事实源。 store/outbox.rs 保存尚未确认的 Blob/checkpoint 操作。 MCP 和 subagent 暂时不建空目录:MCP 先作为动态 Tool 接入;subagent 复用 RunActor,需求落地时再加入 run/subagent.rs。

依赖建议:

tokio                异步运行时
axum + hyper         Connect HTTP 服务
prost + prost-build  protobuf
protoc-bin-vendored  避免系统 protoc 依赖
sqlx/sqlite          持久化和事务
reqwest              provider HTTP
eventsource-stream   provider SSE
serde/serde_json     模型和工具 JSON
sha2 + base64        BlobID
bytes                二进制载荷
tokio-util           CancellationToken
thiserror + tracing  错误和日志
include_dir          编译期嵌入 prompt/ 资产

Cursor上下文与状态同步抓包分析.md 来告诉你很多信息,你需要一次性读他

Users/leokun/Library/Application Support/cursor-byok/cursor-proxy-debugger.db 是cursor的原服务抓包信息,内容由/Users/leokun/Documents/cursor-byok/cursor-backend产生

S
Description
No description provided
Readme MIT
22 MiB
Languages
Go 86.4%
Vue 6.3%
JavaScript 4.8%
CSS 1%
NSIS 0.6%
Other 0.8%