源码解析 · DeepSeek 原生 · main-v2 @ 627b051

一条成本焦虑
长成架构宪法

Reasonix 不是「又一个 Go 写的 Claude Code 仿制品」——它把 DeepSeek 的自动前缀缓存从费用边角料提升为架构中轴:系统前缀字节稳定、易变内容走 turn tail、工具 schema 排序哈希、动态 MCP 用 use_capability 隔离、压缩明码标价、miss 可诊断。全文按「动机 → 约束 → 被否方案 → 选择 → 代价」五段式展开,标注 文件:行号,可回源码核对。

1686
.go 文件
216k
internal 非测试行
553k
含测试总行数
17
Extension hooks
Part I

起点:开发者为什么做这个东西

Chapter 01

痛点与洞察:成本焦虑撞上现成的省钱机制

1.1 先回答「为什么」

读 Reasonix 的源码之前,先读它的 README。中文 README 开篇没有讲“我们的 Agent 多聪明”,而是先把产品位钉在成本上(README.zh-CN.md:42-43):

面向终端的 DeepSeek 原生 AI coding agent。
由配置与插件驱动的极薄 harness——单一静态 Go 二进制,围绕 DeepSeek 的前缀缓存调优,长会话也能把 token 成本压低。

这不是营销话术,而是整套架构的出发点:

  1. 痛点:长会话里 token 成本随轮次线性增长;DeepSeek 的定价让“一直聊下去”变贵。
  2. 现成机制:DeepSeek 自动做前缀缓存——只要请求前缀字节稳定,命中的部分就能打折。
  3. 洞察:省钱的钥匙不是“少调用模型”,而是“让前缀一直命中”。于是 cache 从「优化项」升格为「架构约束」。
flowchart LR
    P["痛点:长会话 token 成本高"] --> I["洞察:DeepSeek 自动前缀缓存<br/>前缀稳定 = 命中 = 省钱"]
    I --> C["约束:系统前缀必须字节稳定"]
    C --> D["推论:易变内容外移 turn tail<br/>工具 schema 稳定 · 压缩明码标价 · miss 可诊断"]

1.2 三个可验证的工程主张

主张 在代码里长什么样
DeepSeek 原生 Provider 层保留 reasoning_content 往返;缺推理内容时静默重试(agent.go:1388-1394observeMissingToolCallReasoning
Cache-first 系统前缀(base + tools + memory)跨 turn 字节稳定;易变内容走 control.Compose 的 turn tail(REASONIX.md:14-16control/input.go:181-183
薄 harness + 单二进制 docs/SPEC.md 契约:核心只认接口;CGO_ENABLED=0;能力靠 config / plugin / init() 自注册

1.3 这条约束被写成了「宪法」,而不是注释

仓库自己的 standing instructions(REASONIX.md:14-16):

- Cache-first: the system-prompt prefix (base prompt + tools + memory) must stay
  byte-stable across turns so DeepSeek's automatic prefix cache stays warm. Never
  mutate it mid-session — ride the turn tail instead (see `control.Compose`).

甚至 PR 模板强制要求 Cache-impact / Cache-guard 元数据(REASONIX.md:64-71)。
本系列里只有 Hermes 的「前缀缓存神圣」能对上劲;Reasonix 的差别是把它焊进了 Go 运行时诊断 + CI 脚本,让“不许打破缓存”成为可执行的协作纪律。


Chapter 02

产品位与动机证据:README / REASONIX / SPEC 里的原话

2.1 动机证据表

证据 出处 它证明了什么
「围绕 DeepSeek 的前缀缓存调优,长会话也能把 token 成本压低」 README.zh-CN.md:42-43 成本是产品出发点
「must stay byte-stable… Never mutate it mid-session」 REASONIX.md:14-16 约束用宪法口吻写
「switching models inside one shared conversation would break the prefix and tank cache hits, so we don't」 docs/SPEC.md:238-240 连双模型都被约束反推成独立 session
Compaction 是「cache-reset point」,cache hit rate 是「key observability signal」 docs/SPEC.md:328-329 压缩是明码标价的缓存重置
PR 强制 Cache-impact / Cache-guard REASONIX.md:64-71 约束焊进协作流程
「Memory added mid-session rides the turn (never the cached system prefix)」 internal/control/input.go:181-183 每个实现点都在解释为什么
Economy 档面向「成本敏感任务」 docs/COLLABORATION_MODES.zh-CN.md:86,136 产品档位按成本切

2.2 产品经理视角:它在卖什么体验

卖点 工程落点
长会话更省 token 稳定前缀 → DeepSeek 自动 prefix cache;PrefixShape / CompareShape 解释 cache miss(agent/cache_shape.go
装完就能用 单静态二进制;npm 包 reasonixreasonix.example.toml
多前端同一套行为 control.Controller 背后挂 TUI / HTTP-SSE / Wails desktop / ACP(REASONIX.md:11-13
可验证交付 Delivery Profile:complete_step 证据签收 + readiness 门禁(docs/GOAL_ENFORCEMENT.zh-CN.md
协作模式可切换 Economy / Balanced / Delivery;可选 planner_model 双模型(docs/COLLABORATION_MODES.zh-CN.md

🧠 一句话:别家在优化「工具调用多聪明」;Reasonix 在优化「同一次会话里,前缀到底能不能一直命中缓存」——并把这件事当成不能违约的产品契约。


Chapter 03

仓库地图与技术栈:数字形状与依赖方向

3.1 数字化的项目形状(基线 627b051)

指标 量级
Go 源文件 1686.go
internal/ 非测试 216,079
全仓含测试 553,005
巨文件心脏 control/controller.go 6,560 · cli/chat_tui.go 5,154 · agent/agent.go 4,362
内置工具契约 docs/TOOL_CONTRACT.md(compile-time builtins + 全量 boot 表面,由测试守护)

docs/SPEC.md 给出的布局契约:

cmd/reasonix/main.go          # 入口;blank-import providers + builtin tools
internal/
  cli/                        # 子命令、装配、退出码
  control/                    # 传输无关 Controller(所有前端的背后)
  agent/                      # Session + harness 循环 + compact + cache shape
  provider/                   # Provider 接口 + openai/anthropic/responses
  tool/ + tool/builtin/       # Tool 接口 + init() 自注册
  permission/                 # allow / ask / deny + bash 分解
  sandbox/                    # OS 沙箱封装
  memory/ · instruction/      # 背景事实 vs standing instructions
  plugin/ · mcp* / capability # MCP / 能力代理
  checkpoint/ · evidence/     # 变更回滚与交付证据
  acp/ · bot/ · desktop*      # 编辑器协议、机器人、桌面

依赖方向(docs/SPEC.md:54-56):cli → {agent, plugin, config} → {tool, provider};父包不 import 自注册子包。

3.2 技术栈

技术 位置
语言 / 分发 Go,CGO_ENABLED=0 单静态二进制 Makefilecmd/reasonix
配置 TOML(BurntSushi/toml internal/configreasonix.example.toml
TUI Bubble Tea 系全屏聊天 internal/cli/chat_tui.go
桌面 Wails(Go 后端 + 前端) desktop/
协议 ACP、HTTP/SSE serve、MCP stdio JSON-RPC internal/acpinternal/controlinternal/plugin
Provider OpenAI 兼容 / Anthropic / Responses internal/provider/* blank-import

入口极薄(cmd/reasonix/main.go):

// Blank imports wire compile-time built-ins into their registries.
_ "reasonix/internal/provider/anthropic"
_ "reasonix/internal/provider/openai"
_ "reasonix/internal/provider/responses"
_ "reasonix/internal/tool/builtin"

3.3 与 Claude Code / Hermes / Codex 的关系

维度 Claude Code Hermes Agent OpenAI Codex Reasonix
语言形态 TypeScript(闭源) Python 大脑 + TS 脸 Rust workspace Go 单二进制
模型策略 绑 Anthropic 模型无关 + 学习闭环 绑 OpenAI 栈 DeepSeek 优先,OpenAI 兼容可插
上下文哲学 强提示词工程 前缀缓存神圣 + 记忆写盘 两层 turn + 压缩 Cache-first 写进宪法 + 运行时 shape 诊断
前端 终端为主 CLI/TUI/桌面/20+ IM CLI + app-server Controller 统一:TUI / serve / Wails / ACP
权限 弹窗 + 规则 环境隔离多后端 AskForApproval × OS 沙箱 Policy 规则 + bash 分解 + sandbox + workspace confine
完成判定 自然结束 + 工具 技能/记忆闭环 三方停机协议 自然结束 + maxSteps/todo stall;Delivery 证据签收

若只记一句:Reasonix = Hermes 的 cache 哲学 × Codex 的工程硬度 × Claude Code 的终端 coding 品类,焊在 DeepSeek 的自动前缀缓存上。


Part II

思维导图:一条约束如何推出十项设计

Chapter 04

开发者思维导图:从「前缀必须稳定」到十项设计

这一章是整篇的“地图”:先看开发者脑子里那根主轴,再进代码。下面十项都能从「前缀必须字节稳定」推出;每一项也都有明确的代价。

# 推论 选择 如果不这么做会怎样
1 系统前缀必须稳定 易变上下文进 turn tail,不进 system(control.Compose 每轮插话/记忆更新都会打冷整段前缀
2 工具 schema 也是前缀 schema 排序后再哈希(normalizeToolSchemas 工具注册顺序抖动造成“假 miss”
3 插话不可避免 Steer 明确付一次 cache 税(run_loop.go:276-283 假装零成本插话,缓存统计失真
4 上下文终会增长 压缩分 soft/snip/summary,压缩 = cache-reset point 无节制 summary 频繁重置缓存
5 MCP 库存会变 use_capability 固定代理隔离动态 schema 装一个 MCP 工具就冷一次缓存
6 bash 语义必须精确 运行时只读降级 BashCommandIsReadOnly schema 稳定但语义模糊,误伤并行/证据
7 DeepSeek 协议有怪癖 Missing reasoning 静默重试一次 thinking 模式下工具轮直接失败
8 跑满预算不该算崩溃 maxSteps → Pause 而非 Fatal 长任务在预算边界丢会话资产
9 多前端要一致 行为进 control.Controller 不进脸 每个前端各修各的,行为漂移
10 约束要可执行 SPEC / TOOL_CONTRACT / 测试同源 + PR 元数据 宪法只是 wiki 摆设

Chapter 05

Cache-first 宪法:稳定前缀 vs turn tail

5.1 两条轨道

轨道 内容 规则
Cache-stable prefix base system + tool schemas + standing memory/instructions 会话内禁止字节级漂移
Turn tail(Compose) 用户正文、goal 块、plan marker、语言偏好、<memory-update>、background-jobs、hook context、retrieval recall 每轮可变;绝不能回写进 prefix

Controller.Composecontrol/input.go:137-212)把这件事写进注释(input.go:181-183):

Memory added mid-session rides the turn (never the cached system prefix),
so it takes effect now without invalidating the prompt cache. It folds into
the system prefix on the next session, where it costs nothing per turn.

装配顺序(概念上):

flowchart TB
    IN["用户 text"] --> G{"有 running goal?"}
    G -->|是| GB["activeGoalBlock + autoResearch"]
    G -->|否| P
    GB --> P{"planMode?"}
    P -->|是| PM["PlanModeMarker"]
    P -->|否| L
    PM --> L["response/reasoning language 包装"]
    L --> M["drainPending → memory-update"]
    M --> J["background-jobs note"]
    J --> H["hook context"]
    H --> R["memory.recall Block(真实 user turn)"]
    R --> OUT["交给 Agent.Run"]

这与 Open Design「按缓存频率分带装配 system prompt」、Hermes「记忆写盘立即生效、下个会话才进提示词」是同一哲学族。Reasonix 的独特处是:把 miss 诊断成结构化事件,而不是只靠文档告诫。

5.2 PrefixShape:为什么 miss?

// PrefixShape hashes the portions of the request prefix that influence
// provider-side prompt-cache reuse. Comparing snapshots across turns
// lets us explain *why* a cache miss happened.
type PrefixShape struct {
	SystemHash        string
	ToolsHash         string
	PrefixHash        string
	LogRewriteVersion int
	ToolSchemaTokens  int
}

CaptureShape 会对 tool schema 排序后再哈希normalizeToolSchemas),避免“顺序抖动”假 miss。CompareShape 给出 system / tools / log_rewrite 原因列表,并带上 usage 里的 cache hit/miss tokens。

发往 provider 前还会剥掉会打冷缓存的 UI 元数据:LocalOnly 显示记录不进 ModelMessagesprovider.goLocalOnly 标记),墙钟与取消半截流都不会污染前缀。

5.3 与 MCP 动态工具的张力

动态 mcp__* 工具一旦进主 Registry,就会改 tools 哈希 → 冷缓存。Reasonix 的解法(docs/TOOL_CONTRACT.md:45-96):

  • Delivery / Planner / 多数 sub-agent:暴露固定名代理工具 use_capability(list / inspect / call / decline);
  • 按需连 MCP 不改变该代理的 provider-visible schema;
  • Balanced 的 Executor 刻意保留直接 mcp__*(接受可能的前缀变化)——这是有意识的产品取舍,不是疏漏。

🧠 承重墙:Cache-first 不是「尽量少改 prompt」,而是「哪些变化允许付 cache miss 的税」被显式分类:steer 付税、memory-update 不碰 prefix、MCP 库存变化用代理隔离。


Chapter 06

双模型为何必须分 session

6.1 动机

想要“先规划后执行”的成本/质量平衡,但模型切换会破坏前缀。

6.2 约束与选择

docs/SPEC.md:238-240 把话挑明:

switching models inside one shared conversation would break the prefix and tank cache hits, so we don't.

配置了 planner_model 时,Planner 与 Executor 各有独立 sessionagent/coordinator.go):两套前缀各自 cache-stable,会话永不混写。这与 UI 上的 Plan Mode(turn-tail marker)不是同一层。

6.3 代价

  • 双份前缀、双份工具面,首轮成本更高;
  • 规划期发现的能力必须在 handoff 后仍可直接 call(use_capability 的固定代理正好承担这件事);
  • 路由更复杂:executor_only | plan_and_execute | plan_for_approval | plan_onlyplanner_route.go)。

Part III

实现:从约束到代码

Chapter 07

主循环:Agent.Run → runToolLoop

7.1 生命周期入口

Agent.Run 自己说得很清楚(注释始于 agent.go:1310,函数体 1319-1378):

  1. 解析本轮 maxSteps(可被 context 覆盖);
  2. 开 workspace lease / steer 队列 / background evidence 提交 defer;
  3. interceptAgentStart(extension 可 abort);
  4. beginRunTurn 初始化状态;
  5. return a.runToolLoop(ctx, state)

没有神秘的「框架基类」——就是显式状态机,策略拆在 beginRunTurn / handleFinalResponse / handleToolRound

7.2 runToolLoop:一轮里发生什么

核心循环在 run_loop.go:274-355

sequenceDiagram
    participant U as User / Controller
    participant A as Agent.runToolLoop
    participant P as Provider.Stream
    participant T as executeOne(s)

    U->>A: Run(input)
    loop step = 0..maxSteps
        A->>A: consumeSteer?(写入 session,可接受一次 cache miss)
        A->>A: CaptureShape(system+tools)
        A->>P: streamWithMissingReasoningRecovery
        P-->>A: text + reasoning + tool_calls + usage
        A->>A: CompareShape → cache diagnostics
        alt 无 tool_calls
            A->>A: handleFinalResponse(含 maybeCompact)
        else 有 tool_calls
            A->>T: handleToolRound → 并行只读 / 串行写入
            T-->>A: tool results 写入 session
        end
    end
    A-->>U: maxStepsPause 或 error 或 nil

几个味道很重的细节:

细节 含义 位置
Steer 中途插话进队列;消费时写入 user 消息并带引导前缀;注释承认「一次 cache miss 不可避免」 run_loop.go:276-283
Missing reasoning recovery DeepSeek thinking 模式下 tool call 缺 reasoning_content → 同请求静默重放至多一次 run_loop.go:357-364agent.go:1388-1394
Stream recovery 中断流最多 maxStreamRecoveries=3,且 不消耗 maxStepsstep-- run_loop.go:300-309
Cache diagnostics 每轮 CompareShape 对比 system/tools/log_rewrite run_loop.go:285-294
暂停而非崩溃 maxStepsPause / todoStallPause:工作已在 session,用户再发一条即可续 agent.go:1469-1494
Delivery readiness 失败 终答前宿主校验 todo/criteria/verify/signoff → FinalReadinessError,开下一轮 handleFinalResponse
空终答 / thinking-only 最多 maxEmptyFinalBlocks 次回催 run_loop.goagent.go:42
Recovery grace recovery episode 耗尽后 summarize-only 一圈,再 RecoveryPauseError recovery 路径

7.3 装配入口:boot.Build → 同一 Runner

模式 触发 Turn API
TUI reasonix / chat 异步 Controller.SendWithRaw
Headless reasonix run / -p 同步跑一轮;Ask 对 writer fail closed,需 --auto/-y
ACP reasonix acp 阻塞 Controller.RunTurnsession/prompt
serve / desktop / bot 各自入口 SSE / Wails / IM → 同一 Controller

boot.Buildinternal/boot)一次性冻结 system prefix(output style、环境探针快照、memory、skill 索引),再把可选 planner_model 包成 Coordinator

7.4 单工具执行管线

executeOneexecute_one.go:65-101)是固定五段:

  1. parseToolCall — Resolve、歧义 MCP 名、重复成功/失败 loop guard、stale-anchor 编辑拦截;bash 可按参数降级为只读(permission.BashCommandIsReadOnly);
  2. interceptToolBefore — extension 可改写调用;
  3. resolveToolPolicy — 权限门禁;
  4. prepareToolExecution — 预览、mutation 记账、parent write 锁;
  5. finishToolExecution — 真正执行 + 回执。

只读工具可并行,写入串行——与 Claude Code / OpenAI4S 的「只读波次」同族,但落地在 Go 的 mutation observer / evidence ledger 上。


Chapter 08

Compose:把易变内容赶进 turn tail

8.1 动机

系统前缀要字节稳定,但 goal、plan、语言偏好、记忆更新、检索结果每轮都可能变。

8.2 约束

凡是不稳定、不必要时不出现的内容,都不能进 cache-stable prefix。

8.3 被否方案

  • “把所有动态内容都拼进 system prompt”:省事但每轮冷缓存,直接违背宪法;
  • “动态内容完全不进上下文”:goal/plan/记忆更新无法即时生效。

8.4 选择

control.Composecontrol/input.go:137-212)在真实 user turn 前按固定顺序装配:activeGoalBlock → PlanModeMarker → 语言包装 → <memory-update> → background-jobs → hook context → memory.recall Block。

8.5 代价

  • 每轮多一次装配与剥离(StripComposePrefixes);
  • 若前端/扩展绕过 Compose 直接发消息,缓存宪法会被破坏——所以所有前端都走同一 Controller。

Chapter 09

压缩三阶梯:soft → snip → summary(明码标价的缓存重置)

compact.go:20-37 把策略钉死:

阶段 默认阈值(占 context window) 做什么
Soft 0.5 报告上下文在涨,仍保 cache-stable prefix
Tool-result snip 0.6 廉价改写陈旧 tool result
Summary compact 0.8(force 0.9) 摘要折叠;保留固定 token 的 recent tail(默认 16384)

设计要点:

  • 触发用比例,保留用绝对 token 预算——大窗口不会过度压缩,小窗口也不会卡在阈值附近反复 compact;
  • Summary 用结构化标题(Standing facts / Goal / Decisions / Files / Commands / Errors / Pending),包在 <compaction-summary> 里;
  • Ablation 开关可关掉 cache 友好策略做对照实验(internal/ablation);
  • Compact 会 bump LogRewriteVersionCompareShape 会标 log_rewrite——诚实承认这是 cache 重置点

与 Raven「无损归档」、Claude Code「摘要丢弃」相比:Reasonix 明确站在 「先廉价 snip,再付一次 summary 的 cache 税」 这一边。


Chapter 10

工具 ABI:builtin + MCP + use_capability 固定代理

10.1 Compile-time builtins(契约表)

docs/TOOL_CONTRACT.md 由测试守护(TestBuiltinToolContractDocumentation),与运行时 registry 同源。核心面:

类别 工具
read_file grep glob ls code_index web_fetch
write_file edit_file multi_edit move_file delete_range delete_symbol notebook_edit
Shell bash + bash_output / wait / kill_shell
任务/交付 todo_write complete_step update_goal

实现侧全部 init() { tool.RegisterBuiltin(...) }(如 builtin/readfile.go:27)。

10.2 全量 boot 表面 vs Economy

默认 full-token boot 还挂 session / memory / skill / subagent / LSP / install / slash 等:asktask/fleet/parallel_tasksmemory/remember/forgetrun_skill、LSP 四件套、explore/research/review/security_review 等(docs/TOOL_CONTRACT.md)。

Delivery 另加:

  • use_capability:稳定 MCP 代理;
  • review_report:中高风险变更的结构化 review;
  • Host 侧 evidence:verification / diff / files / manual,无证据的 complete_step 直接拒绝

Economy 刻意只暴露瘦面(约 ask/bash/read_file/write_file/edit_file/后台三件套 + connect_tool_source),其余按需挂载——用「一次看不全工具」换 token 与前缀稳定。

10.3 Tool 接口味道

工具带 ReadOnly、预览(Previewer)、图像、PlanMode 分类等能力位——权限与并行调度读的是这些位,而不是靠模型「自觉」。Checkpoint 只跟踪带 Previewer 的编辑工具(见第 12 章)。


Chapter 11

权限、沙箱、工作区围栏:应用层规则 × OS 围栏

11.1 Permission Policy + Ask / Auto / Yolo

permission.Policypermission.go):

  • 规则形态对齐 Claude Code:Tool / Tool(glob) / legacy Tool=literalParseRule);
  • Decide(toolName, readOnly, args);bash 走分段分解DecomposeBashCommand);
  • BashCommandIsReadOnly:把「schema 上可写的 bash」在具体 argv 上降成只读(影响并行、mutation、evidence);
  • BashSubjectRequiresExplicitApproval:间接执行、危险 git 等强制显式批准。

产品审批模式(docs/TOOL_APPROVAL_MODES.md)与 collaboration mode(normal/plan/goal)正交

模式 行为要点
Ask 写入默认询问;headless reasonix run 对 writer fail closed
Auto 普通 writer 自动放行;deny/ask 规则、Plan 确认、嵌套/间接 Bash、MCP destructive、敏感 remember/forget 仍要问
Yolo 唯一可绕过嵌套 Bash 人工门槛;仍不绕过 deny 与 sandbox

另有 internal/guardian:独立安全评审子会话(带 denial circuit breaker)——不能代替记忆写入的用户确认。Hooks(internal/hook)提供 PreToolUse/PostToolUse/PostToolUseFailure,并做 Claude 工具名兼容映射。

11.2 Sandbox + confine

builtin/bash.go 把命令包进 sandbox.Command

平台 Bash OS sandbox
macOS sandbox-exec(Seatbelt)
Linux bwrap
Windows 产品固定 off,命令 unconfined;文件类 builtins 仍有 workspace confine

enforce 但无后端时 fail closed(不裸跑)。escape 走 sandbox.EscapeApprover。MCP stdio 默认不继承 Bash sandbox(internal/plugin/plugin.go 的产品默认是 host 进程,注释写明原因)。

SECURITY.md 把边界写清楚:workspace 围栏、权限、沙箱、密钥、HTTP serve 的 localhost/CORS、桌面/bot 隔离、updater 校验——以及什么不算漏洞。

11.3 Checkpoint / Rewind

对齐 Claude Code Esc-Esc / /rewind 叙事(docs/CHECKPOINTS.md):

  • 机制:文件快照(非 git);sidecar <session-id>.ckpt/
  • 跟踪范围:带 Previewer 的编辑工具(write_file / edit_file / multi_edit);
  • 不跟踪bash 副作用;move_file 尚未实现 Previewer;
  • APIController.Checkpoints / Rewind / PrepareRewind+CommitRewind(含 coverage confirmation);
  • 明确不做:git-backed rollback(文档标 out of scope)。

Chapter 12

Checkpoint / Delivery / Goal:交付证据与完成协议

12.1 正交三轴

docs/GOAL_ENFORCEMENT.zh-CN.md 开篇:

Goal 是唯一的跨 turn 调度器,Delivery 是纯质量门禁,工具权限与沙箱不受 Goal 开关影响。

职责
Goal/goal 跨 turn 推进、预算、pause/resume
Delivery readiness:todo / criteria / verification / review / signoff / capability…
Permission / Sandbox 始终独立

模型通过 update_goal(continue|complete|blocked) 申报意图;宿主用结构化 ReadinessResultagent.go:1497+)决定是否真完成。宣称 complete 但缺证据 → 开启下一轮,而不是信模型嘴硬。

12.2 complete_step

内置工具描述写得很凶(TOOL_CONTRACT.md):completion 必须带 evidence;host 代为推进 todo。这与 grok-build Goal Mode、MiMo「不信任自我报告」同谱——Reasonix 用 host-observed receipts 落地。

12.3 协作 Profile

docs/COLLABORATION_MODES.zh-CN.md

Profile 要点
Economy 单模型,较瘦工具面,面向成本敏感任务
Balanced 完整工具面;可选独立 planner_model
Delivery Balanced + use_capability + 验收合约 + review 门禁

Chapter 13

control.Controller:一张脸接所有前端

13.1 设计铁律

REASONIX.md:11-13

One transport-agnostic control.Controller sits behind every frontend (chat TUI, HTTP/SSE serve, Wails desktop). Add behavior to the controller, not a frontend, so all three inherit it.

实际还有 ACP / bot 等入口。统一装配:boot.BuildControlleragent.Runner(或 Coordinator)。

13.2 一次用户消息的路径

flowchart LR
    TUI["chat_tui"] --> SUB["Submit / Send"]
    HTTP["serve HTTP/SSE"] --> SUB
    DESK["Wails desktop"] --> SUB
    ACP["ACP"] --> SUB
    SUB --> ADM["admitGuardedTurn<br/>防重入 / park"]
    ADM --> COMP["Compose(turn tail)"]
    COMP --> RUN["Coordinator? → Agent.Run"]
    RUN --> EVT["event.Sink<br/>reasoning/text/tool/notice"]
    EVT --> TUI
    EVT --> HTTP
    EVT --> DESK

关键 API 族(controller.go):Send / Submit / SubmitHTTP / SubmitDisplay / RunTurn / Goal 循环变体;runGuarded 做 turn admission,避免双开跑飞。

13.3 为什么 Controller 会变成 6k 行巨文件?

因为它吞下了:会话恢复、checkpoint、memory slash、MCP 生命周期、capability、steer fallback、yolo/plan、attachments、goal usage……所有前端共享的产品行为。代价是文件巨大;收益是「修一处,TUI/桌面/HTTP 一起对」。本系列里 OpenAI4S 的 gateway.py、Codex 的 turn.rs 同属「巨心脏」形态。


Chapter 14

记忆、指令、扩展、桌面/ACP

14.1 Context Engine v2:指令 ≠ 记忆

docs/SESSION_MEMORY_RETRIEVAL.md 的中心法则:

  • Standing instructionsREASONIX.md / AGENTS.md / CLAUDE.md + .local + 祖先目录 + 全局):必须出现在相关 turn;进 cache-stable prefix
  • Background memory:可过时的事实;BM25 auto-recall(默认 defaultAutoRecallLimit=4defaultAutoRecallChars=2400)进 turn tail;索引在下个会话才并入 prefix;
  • #note / /remember 写指令文件;remember 工具写背景事实——不要混用
  • 安全写入:部分 scope create-only;其余需确认——Auto/Yolo/Guardian 不能绕过
  • 指令解析:更深目录覆盖更广;同目录 .local 胜出;@path 导入限 5 层且禁止逃逸。

14.2 三层扩展:MCP · Plugin Package · Extension Protocol v1

是什么 信任模型
MCPinternal/plugin JSON-RPC;stdio / Streamable HTTP;工具名 mcp__<server>__<tool>;兼容项目 .mcp.json 精确规则 + mcp_connect__*;OAuth 等仍在 deferred
Plugin packagesinternal/pluginpkg reasonix-plugin.json;兼容 .claude-plugin / .codex-plugin;贡献 skills/hooks/mcp/commands/agents/themes 安装启用后按贡献面生效
Extension Protocol v1reasonix.extension.v1 NDJSON JSON-RPC sidecar;17 个冻结 hook pointtool.beforepermission.decisionsystem_prompt.buildcompaction.*…);schema 生成 + CI drift-check Full trust:安装即最高权限,可覆写 host deny;UI 标 FULL TRUST

MCP 与 Extension 是不同层:前者接工具/资源,后者接宿主生命周期拦截。Full-trust Extension 是独立攻击面,也是「Open Design 式公开合约」在 Reasonix 里的最硬落地(docs/EXTENSION_PROTOCOL.md)。

14.3 Subagent profiles

Skill frontmatter runAs: subagentdocs/SUBAGENT_PROFILES.md):内置 explore / research / review / security_review;CLI reasonix subagent …;调用走 /<profile>task/fleet + write_paths 并行写隔离。默认并发 max_subagent_concurrency=6max_parallel_writers=3。Claude 插件 agents/*.md 可映射为 /<plugin>:agent:<name>

14.4 桌面与 ACP

  • Desktopdesktop/):嵌套 Wails 模块(保持父模块 CGO_ENABLED=0);React+TS webview ↔ 同一 Controller(无 HTTP hop);
  • ACPinternal/acpdocs/ACP.md):reasonix acp [--profile …];NDJSON JSON-RPC;loadSession + embeddedContext;能力广告 无 image/audio;MCP http: truesse: false;vendor 扩展含 _reasonix.io/session/steer
  • VS Code 扩展 SivanLiu.reasonix-agent 拉起本机 reasonix acp
  • Remote-SSH / workbench:基线 PR #7368 reconnect hardening——产品已从本地 TUI 长到远程工作台。

Part IV

品味与边界

Chapter 15

十项决策五段式复盘

# 选择 动机 约束 被否方案 代价
1 易变上下文进 turn tail 前缀稳定 = 省钱 DeepSeek 自动前缀缓存按字节命中 全部塞 system 每轮装配/剥离成本;绕过 Compose 会破坏宪法
2 Tool schema 排序后哈希 避免假 miss 工具注册顺序不可控 按注册序哈希 排序逻辑本身要测试守护
3 Steer 付一次 cache 税 插话必须立即可见 模型必须看到新指令 不插话 / 假装零成本 每插一次话就 miss 一轮
4 压缩分三阶梯 延迟 summary 重置 上下文终会增长 一次到位 summary 需要额外 snip 逻辑与阈值调参
5 use_capability 固定代理 动态 MCP 不能动 schema MCP 库存随时变 直接把 mcp__* 注册进 Registry 多一层解析与权限名(mcp_connect__*
6 bash 运行时只读降级 schema 稳定、语义精确 bash 是否只读取决于 argv 只按 schema 判 BashCommandIsReadOnly 要维护危险命令清单
7 Missing reasoning 静默重试 DeepSeek thinking 偶发缺 reasoning provider 要求回放 thinking 直接失败 增加一次同请求重放;需防抖 cooldown
8 maxSteps → Pause 会话资产优先 预算有限但工作已落盘 报错重来 暂停状态机与恢复路径变多
9 行为进 Controller 多前端一致 前端数量增长 各前端自实现 Controller 变成 6k 行巨文件
10 契约可执行(SPEC/TOOL_CONTRACT/PR) 宪法不能只靠自觉 仓库会一直长大 wiki 文档 CI/测试成本;PR 元数据要求

Chapter 16

横向对比(编程 Agent 桌)

维度 Claude Code Open Design OpenAI4S Hermes Codex Reasonix
品类 终端编程 设计宿主 科研双平面 个人学习 agent 官方 Rust CLI DeepSeek 终端编程
主循环 自有 无(接别人) Engine+Cell Python loop run_turn runToolLoop
上下文 强提示工程 20 层分带缓存 科学态在内核 前缀神圣 两层 turn Cache-first + shape
完成信号 自然结束 产物文件 finalize / submit_output 技能沉淀 三方停机 自然结束 + Delivery readiness
扩展 MCP/Skills CLI 适配器 Skills 食谱 74 工具插件 MCP+crate MCP + Plugin包 + Full-trust Extension v1
分发 闭源产品 daemon+web Python daemon uv/Python Rust 二进制 Go 静态二进制
权限产品面 弹窗+规则 宿主委托 Notebook 审批 环境多后端 Ask×沙箱 Ask/Auto/Yolo × sandbox(正交)

Chapter 17

诚实边界

  • 巨文件成本controller.go / chat_tui.go / agent.go 均数千行,新人 onboarding 陡;
  • DeepSeek 优先税:reasoning 恢复、cache 假设对其他网关不一定成立(有兼容路径,但产品心智仍偏 DeepSeek);
  • Executor 直接 MCP:Balanced Executor 仍可能因 MCP 库存变化冷缓存——文档已承认;
  • Windows Bash OS sandbox:产品固定 unconfined;文件工具仍有 confinement;
  • Checkpoint 覆盖面:不跟踪 bash 副作用;无 git-backed;move_file preview 未完成;
  • Extension full trust:安装即最高权限——能力强,威胁模型需用户理解;
  • MCP long tail:OAuth、list_changed、部分 scopes 等仍 deferred(docs/SPEC.md:877);
  • ACP 能力广告:无 image/audio;agent 侧 MCP SSE 收窄;
  • 旧分支v1 仅关键修复;分析/二次开发应对齐 main-v2

Chapter 18

源码导览索引与本地复现

顺序 路径 看什么
1 README.zh-CN.md + docs/SPEC.md 产品位与契约
2 REASONIX.md 团队自己的 cache 宪法
3 cmd/reasonix/main.go + internal/boot 入口与 boot.Build
4 internal/control/input.goCompose turn tail
5 internal/agent/run_loop.go 主循环
6 internal/agent/cache_shape.go miss 诊断
7 internal/agent/compact.go + prune.go 压缩三阶梯
8 internal/agent/execute_one.go 单工具管线
9 internal/agent/coordinator.go 双模型双 session
10 docs/TOOL_CONTRACT.md + internal/tool/builtin/ 工具面
11 docs/TOOL_APPROVAL_MODES.md + permission/ + sandbox/ Ask/Auto/Yolo × 围栏
12 docs/CHECKPOINTS.md rewind 快照
13 docs/GOAL_ENFORCEMENT.zh-CN.md 完成协议
14 docs/SESSION_MEMORY_RETRIEVAL.md 指令 vs 记忆
15 docs/EXTENSION_PROTOCOL.md + PLUGIN_PACKAGES.md 扩展三层
16 docs/ACP.md / desktop/README.md 嵌入与桌面
17 internal/control/controller.go(选读) 多前端编排

本地复现:

cd "参考项目/DeepSeek-Reasonix"
git fetch origin main-v2
git checkout main-v2
git reset --hard 627b051
# 可选:跑契约测试(需本机 Go)
# go test ./internal/tool -run TestBuiltinToolContractDocumentation

附录 A · 与本系列「Agent 工程模式目录」的对照

模式目录章节 Reasonix 落点
一 Prompt Cache 工程 教科书级:稳定前置 / 易变外移 / 工具稳定 / 压缩慎重 / 遥测可见(五板斧齐)
二 停止判定 自然停止 + maxSteps/todo stall Pause + Delivery readiness
三 权限闸门 Ask/Auto/Yolo + 规则前置 + bash 分解 + OS sandbox(Win Bash 缺口)
四 上下文压缩 snip 优先,summary 付税;soft 明确保 prefix
五 记忆体系 指令文件(prefix)≠ 背景事实(BM25/tail);确认门不可被 Yolo 绕过
六 工具系统 固定代理隔离动态 MCP;Economy connect_tool_source
七 沙箱 Seatbelt/bwrap;应用围栏 → 权限 → OS sandbox
八 子 Agent Skill profile + task/fleet;write_paths 并行写隔离
十二 持久化 文件 checkpoint rewind(非 git);不覆盖 bash 副作用
十三 扩展生态 MCP + Plugin 包 + Full-trust Extension Protocol v1
十五 模型策略 DeepSeek 优先;planner_model 双 session 保各自 cache

附录 B · 一句话收束

Reasonix 不是「又一个 Go 写的 Claude Code 仿制品」。
它把 DeepSeek 的自动前缀缓存,从费用边角料提升为架构中轴:Compose 分流、Shape 诊断、Capability 代理、PR 元数据、Delivery 证据——全部绕着「别把缓存打冷」转。若你在本系列里已经理解 Hermes 的 cache 神圣与 Open Design 的分带装配,读 Reasonix 就是看同一种哲学在 Go 单二进制 coding agent 里被执行到什么硬度。


附录 C · 开发者动机还原:从「成本焦虑」到「架构宪法」

第 1、2、4 章已经把动机链展开;这里保留一张浓缩对照表,方便回看。

动机 证据 长成的架构
长会话 token 成本高 README.zh-CN.md:42-43 产品定位「围绕前缀缓存调优」
前缀必须字节稳定 REASONIX.md:14-16 宪法 + PR 元数据 + CI
易变内容必须外移 control/input.go:181-183 Compose turn tail
双模型不能共用会话 docs/SPEC.md:238-240 Planner / Executor 独立 session
压缩必须诚实标价 docs/SPEC.md:328-329 soft → snip → summary + LogRewriteVersion
miss 必须可解释 cache_shape.go PrefixShape / CompareShape 诊断
成本是产品轴 COLLABORATION_MODES.zh-CN.md:86,136 Economy / Balanced / Delivery 三档

分析基线:参考项目/DeepSeek-Reasonix @ 627b051main-v2)。
系列位置:编程 Agent 样本;与 Hermes(cache)、Codex(沙箱正交)、Claude Code(品类)最近邻。

附录 A

附录 A · 与本系列「Agent 工程模式目录」的对照

模式目录章节 Reasonix 落点
一 Prompt Cache 工程 教科书级:稳定前置 / 易变外移 / 工具稳定 / 压缩慎重 / 遥测可见(五板斧齐)
二 停止判定 自然停止 + maxSteps/todo stall Pause + Delivery readiness
三 权限闸门 Ask/Auto/Yolo + 规则前置 + bash 分解 + OS sandbox(Win Bash 缺口)
四 上下文压缩 snip 优先,summary 付税;soft 明确保 prefix
五 记忆体系 指令文件(prefix)≠ 背景事实(BM25/tail);确认门不可被 Yolo 绕过
六 工具系统 固定代理隔离动态 MCP;Economy connect_tool_source
七 沙箱 Seatbelt/bwrap;应用围栏 → 权限 → OS sandbox
八 子 Agent Skill profile + task/fleet;write_paths 并行写隔离
十二 持久化 文件 checkpoint rewind(非 git);不覆盖 bash 副作用
十三 扩展生态 MCP + Plugin 包 + Full-trust Extension Protocol v1
十五 模型策略 DeepSeek 优先;planner_model 双 session 保各自 cache

附录 B

附录 B · 一句话收束

Reasonix 不是「又一个 Go 写的 Claude Code 仿制品」。
它把 DeepSeek 的自动前缀缓存,从费用边角料提升为架构中轴:Compose 分流、Shape 诊断、Capability 代理、PR 元数据、Delivery 证据——全部绕着「别把缓存打冷」转。若你在本系列里已经理解 Hermes 的 cache 神圣与 Open Design 的分带装配,读 Reasonix 就是看同一种哲学在 Go 单二进制 coding agent 里被执行到什么硬度。


附录 C

附录 C · 开发者动机还原:从「成本焦虑」到「架构宪法」

第 1、2、4 章已经把动机链展开;这里保留一张浓缩对照表,方便回看。

动机 证据 长成的架构
长会话 token 成本高 README.zh-CN.md:42-43 产品定位「围绕前缀缓存调优」
前缀必须字节稳定 REASONIX.md:14-16 宪法 + PR 元数据 + CI
易变内容必须外移 control/input.go:181-183 Compose turn tail
双模型不能共用会话 docs/SPEC.md:238-240 Planner / Executor 独立 session
压缩必须诚实标价 docs/SPEC.md:328-329 soft → snip → summary + LogRewriteVersion
miss 必须可解释 cache_shape.go PrefixShape / CompareShape 诊断
成本是产品轴 COLLABORATION_MODES.zh-CN.md:86,136 Economy / Balanced / Delivery 三档

分析基线:参考项目/DeepSeek-Reasonix @ 627b051main-v2)。
系列位置:编程 Agent 样本;与 Hermes(cache)、Codex(沙箱正交)、Claude Code(品类)最近邻。