English lecture · source-traced

DeepSeek-Reasonix source analysis: how “cost anxiety” grew into an “architectural constitution”

**Subject**: [esengine/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix) (product name **Reasonix**) **Baseline commit**: `627b051` (`Merge pull request #7368 … remote-workbench-reconnect-hardening`, default branch **`main-v2`**) **License**: MIT (`LICENSE`) **Code size (baseline)**: **1686** `.go` files; `internal/` non-test **216,079** lines; whole repo including tests **553,005** lines **Product in

EN
lecture
source
file:line
no
embellishment
中文
sibling

Subject: esengine/DeepSeek-Reasonix (product name Reasonix) Baseline commit: 627b051 (Merge pull request #7368 … remote-workbench-reconnect-hardening, default branch main-v2) License: MIT (LICENSE) Code size (baseline): 1686 .go files; internal/ non-test 216,079 lines; whole repo including tests 553,005 lines Product in one sentence: a DeepSeek-native terminal coding agent—a config- and plugin-driven extremely thin harness, a single static Go binary (CGO_ENABLED=0), tuned around DeepSeek’s automatic prefix cache, so long-session token cost stays controllable. Audience: product managers and engineers who have read at least one of this series’ Claude Code / Open Design / Hermes / Codex / OpenAI4S analyses. Rewrite note: this edition is rearranged in a five-beat motivation → constraint → rejected alternatives → choice → cost. First answer “why the developers built it, and what the spine in their head was,” then go into the code; every key design tries to say “what would happen if we didn’t.” Local baseline path: 参考项目/DeepSeek-Reasonix @ 627b051


Part 2

Chapter 1 · Pain and insight: cost anxiety meets an already-there saving mechanism

1.1 Answer “why” first

Before reading Reasonix’s source, read its README. The Chinese README does not open with “how smart our Agent is”; it pins the product position on cost (README.zh-CN.md:42-43):

A DeepSeek-native AI coding agent for the terminal. A config- and plugin-driven extremely thin harness—a single static Go binary, tuned around DeepSeek’s prefix cache, so even long sessions keep token cost down.

This is not marketing copy. It is the starting point of the whole architecture:

  1. Pain: in a long session, token cost grows linearly with turns; DeepSeek’s pricing makes “keep chatting” expensive.
  2. Already-there mechanism: DeepSeek automatically prefix-caches—as long as the request-prefix bytes stay stable, the hit portion is discounted.
  3. Insight: the key to saving money is not “call the model less,” but “keep hitting the prefix.” Cache is thereby promoted from an “optimization” to an “architectural constraint.”
flowchart LR
    P["Pain: long-session token cost is high"] --> I["Insight: DeepSeek auto prefix cache
stable prefix = hit = save money"] I --> C["Constraint: system prefix must be byte-stable"] C --> D["Corollary: volatile content out to turn tail
stable tool schema · compaction priced in the open · miss diagnosable"]

1.2 Three verifiable engineering claims

Claim What it looks like in code
DeepSeek-native Provider layer keeps reasoning_content round-trip; on missing reasoning, silent retry (observeMissingToolCallReasoning at agent.go:1388-1394)
Cache-first System prefix (base + tools + memory) is byte-stable across turns; volatile content rides control.Compose’s turn tail (REASONIX.md:14-16, control/input.go:181-183)
Thin harness + single binary docs/SPEC.md contract: the core only knows interfaces; CGO_ENABLED=0; capability comes from config / plugin / init() self-registration

1.3 This constraint was written as a “constitution,” not a comment

The repo’s own 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`).

Even the PR template forces Cache-impact / Cache-guard metadata (REASONIX.md:64-71). In this series only Hermes’s “prefix cache is sacred” is in the same family; Reasonix’s difference is welding it into Go runtime diagnostics + CI scripts, so “do not break the cache” becomes an executable collaboration discipline.


Part 3

Chapter 2 · Product position and motive evidence: the original words in README / REASONIX / SPEC

2.1 Motive-evidence table

Evidence Source What it proves
“tuned around DeepSeek’s prefix cache, so even long sessions keep token cost down” README.zh-CN.md:42-43 Cost is the product starting point
“must stay byte-stable… Never mutate it mid-session” REASONIX.md:14-16 The constraint is written in constitutional voice
“switching models inside one shared conversation would break the prefix and tank cache hits, so we don't” docs/SPEC.md:238-240 Even dual models are reverse-derived by the constraint into independent sessions
Compaction is a “cache-reset point”; cache hit rate is a “key observability signal” docs/SPEC.md:328-329 Compaction is a cache reset with a posted price
PRs force Cache-impact / Cache-guard REASONIX.md:64-71 The constraint is welded into the collaboration process
“Memory added mid-session rides the turn (never the cached system prefix)” internal/control/input.go:181-183 Every implementation point explains why
Economy tier is for “cost-sensitive tasks” docs/COLLABORATION_MODES.zh-CN.md:86,136 Product tiers are cut by cost

2.2 Product-manager view: what experience it is selling

Selling point Engineering landing
Long sessions use fewer tokens Stable prefix → DeepSeek automatic prefix cache; PrefixShape / CompareShape explain cache miss (agent/cache_shape.go)
Usable after install Single static binary; npm package reasonix; reasonix.example.toml
Many frontends, one set of behavior control.Controller behind TUI / HTTP-SSE / Wails desktop / ACP (REASONIX.md:11-13)
Verifiable delivery Delivery Profile: complete_step evidence sign-off + readiness gate (docs/GOAL_ENFORCEMENT.zh-CN.md)
Collaboration modes switchable Economy / Balanced / Delivery; optional planner_model dual model (docs/COLLABORATION_MODES.zh-CN.md)

🧠 One sentence: others are optimizing “how smart the tool call is”; Reasonix is optimizing “in this same session, can the prefix keep hitting cache”—and treating that as a product contract that cannot be breached.


Part 4

Chapter 3 · Repo map and stack: numeric shape and dependency direction

3.1 Digitized project shape (baseline 627b051)

Metric Magnitude
Go source files 1686 .go
internal/ non-test 216,079 lines
Whole repo including tests 553,005 lines
Giant-file hearts control/controller.go 6,560 · cli/chat_tui.go 5,154 · agent/agent.go 4,362
Builtin tool contract docs/TOOL_CONTRACT.md (compile-time builtins + full boot surface, guarded by tests)

Layout contract given by docs/SPEC.md:

cmd/reasonix/main.go          # entry; blank-import providers + builtin tools
internal/
  cli/                        # subcommands, assembly, exit codes
  control/                    # transport-agnostic Controller (behind every frontend)
  agent/                      # Session + harness loop + compact + cache shape
  provider/                   # Provider interface + openai/anthropic/responses
  tool/ + tool/builtin/       # Tool interface + init() self-registration
  permission/                 # allow / ask / deny + bash decompose
  sandbox/                    # OS sandbox wrap
  memory/ · instruction/      # background facts vs standing instructions
  plugin/ · mcp* / capability # MCP / capability proxy
  checkpoint/ · evidence/     # change rewind and delivery evidence
  acp/ · bot/ · desktop*      # editor protocol, bots, desktop

Dependency direction (docs/SPEC.md:54-56): cli → {agent, plugin, config} → {tool, provider}; parent packages do not import self-registering child packages.

3.2 Stack

Layer Tech Location
Language / distribution Go, CGO_ENABLED=0 single static binary Makefile, cmd/reasonix
Config TOML (BurntSushi/toml) internal/config, reasonix.example.toml
TUI Bubble Tea family fullscreen chat internal/cli/chat_tui.go
Desktop Wails (Go backend + frontend) desktop/
Protocols ACP, HTTP/SSE serve, MCP stdio JSON-RPC internal/acp, internal/control, internal/plugin
Provider OpenAI-compatible / Anthropic / Responses internal/provider/* blank-import

Entry is extremely thin (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 Relation to Claude Code / Hermes / Codex

Dimension Claude Code Hermes Agent OpenAI Codex Reasonix
Language shape TypeScript (closed source) Python brain + TS face Rust workspace Go single binary
Model strategy bound to Anthropic model-agnostic + learning loop bound to OpenAI stack DeepSeek-first, OpenAI-compatible pluggable
Context philosophy strong prompt engineering prefix cache sacred + memory on disk two-layer turn + compaction Cache-first written into the constitution + runtime shape diagnostics
Frontend terminal-primary CLI/TUI/desktop/20+ IM CLI + app-server Controller-unified: TUI / serve / Wails / ACP
Permissions popup + rules environment isolation, many backends AskForApproval × OS sandbox Policy rules + bash decompose + sandbox + workspace confine
Completion judgment natural end + tools skill/memory closed loop three-party stop protocol natural end + maxSteps/todo stall; Delivery evidence sign-off

If you remember only one sentence: Reasonix = Hermes’s cache philosophy × Codex’s engineering hardness × Claude Code’s terminal-coding category, welded onto DeepSeek’s automatic prefix cache.


Part II · Mind map: how one constraint yields ten designs

Part 5

Chapter 4 · Developer mind map: from “the prefix must stay stable” to ten designs

This chapter is the “map” of the whole lecture: first see the spine in the developer’s head, then go into the code. The ten items below can all be derived from “the prefix must stay byte-stable”; each also has a clear cost.

# Corollary Choice If we didn’t
1 System prefix must be stable Volatile context goes into the turn tail, not system (control.Compose) Every interjection / memory update would cold the whole prefix
2 Tool schema is also prefix Schema hashed after sort (normalizeToolSchemas) Tool-registration-order jitter causes a “false miss”
3 Interjection is inevitable Steer explicitly pays a cache tax once (run_loop.go:276-283) Pretend zero-cost interjection; cache stats go false
4 Context will eventually grow Compaction splits soft/snip/summary; compaction = cache-reset point Unrestrained summary frequently resets cache
5 MCP inventory will change use_capability fixed proxy isolates dynamic schema Installing one MCP tool colds cache once
6 bash semantics must be precise Runtime read-only degrade BashCommandIsReadOnly Schema stable but semantics fuzzy; parallel/evidence get hurt
7 DeepSeek protocol has quirks Missing reasoning silent-retry once In thinking mode a tool round fails outright
8 Hitting the budget should not count as a crash maxSteps → Pause, not Fatal Long tasks lose session assets at the budget boundary
9 Many frontends must be consistent Behavior goes into control.Controller, not the face Each frontend patches itself; behavior drifts
10 Constraints must be executable SPEC / TOOL_CONTRACT / tests same-source + PR metadata The constitution is only a wiki prop

Part 6

Chapter 5 · Cache-first constitution: stable prefix vs turn tail

5.1 Two tracks

Track Contents Rule
Cache-stable prefix base system + tool schemas + standing memory/instructions Forbidden to byte-drift inside a session
Turn tail (Compose) user body, goal block, plan marker, language preference, <memory-update>, background-jobs, hook context, retrieval recall Variable every turn; must never write back into the prefix

Controller.Compose (control/input.go:137-212) writes this into a comment (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.

Assembly order (conceptually):

flowchart TB
    IN["user text"] --> G{"running goal?"}
    G -->|yes| GB["activeGoalBlock + autoResearch"]
    G -->|no| P
    GB --> P{"planMode?"}
    P -->|yes| PM["PlanModeMarker"]
    P -->|no| L
    PM --> L["response/reasoning language wrap"]
    L --> M["drainPending → memory-update"]
    M --> J["background-jobs note"]
    J --> H["hook context"]
    H --> R["memory.recall Block (real user turn)"]
    R --> OUT["hand to Agent.Run"]

This is the same philosophy family as Open Design’s “assemble the system prompt in bands by cache frequency” and Hermes’s “memory writes to disk take effect immediately, enter the prompt only next session.” Reasonix’s distinctive move: diagnose a miss as a structured event, rather than only warning in docs.

5.2 PrefixShape: why a miss?

```13:48:参考项目/DeepSeek-Reasonix/internal/agent/cache_shape.go // 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` **sorts then hashes** tool schema (`normalizeToolSchemas`), avoiding “order jitter” false misses. `CompareShape` gives a `system` / `tools` / `log_rewrite` reason list, plus cache hit/miss tokens from usage.

Before sending to the provider it also strips UI metadata that would cold the cache: `LocalOnly` display records do not enter `ModelMessages` (`LocalOnly` mark in `provider.go`); wall-clock and cancelled half-streams never pollute the prefix.

### 5.3 Tension with dynamic MCP tools

Once dynamic `mcp__*` tools enter the main Registry, they change the tools hash → cold cache. Reasonix’s answer (`docs/TOOL_CONTRACT.md:45-96`):

- Delivery / Planner / most sub-agents: expose a **fixed-name** proxy tool `use_capability` (list / inspect / call / decline);
- **Connecting MCP on demand does not change** that proxy’s provider-visible schema;
- Balanced’s Executor **deliberately keeps** direct `mcp__*` (accepting possible prefix change)—this is a conscious product trade-off, not an omission.

> 🧠 **Load-bearing wall**: Cache-first is not “change the prompt as little as possible.” It is “**which changes are allowed to pay the cache-miss tax**” classified in the open: steer pays the tax, memory-update does not touch the prefix, MCP inventory change is isolated by a proxy.

---

<h2 id="ch6">Chapter 6 · Why dual models must split session</h2>

### 6.1 Motive

Want plan-then-execute cost/quality balance, but switching models would break the prefix.

### 6.2 Constraint and choice

`docs/SPEC.md:238-240` says it plainly:

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

When `planner_model` is configured, **Planner and Executor each have an independent session** (`agent/coordinator.go`): two prefixes each cache-stable; the sessions never mix-write. This is not the same layer as UI Plan Mode (a turn-tail marker).

### 6.3 Cost

- Two prefixes, two tool surfaces, first-round cost higher;
- Capabilities discovered in the planning phase must still be directly callable after handoff (`use_capability`’s fixed proxy exactly carries this);
- Routing more complex: `executor_only` | `plan_and_execute` | `plan_for_approval` | `plan_only` (`planner_route.go`).

---

# Part III · Implementation: from constraint to code

<h2 id="ch7">Chapter 7 · Main loop: Agent.Run → runToolLoop</h2>

### 7.1 Lifecycle entry

`Agent.Run` says it clearly itself (comment starts at `agent.go:1310`, function body `1319-1378`):

1. Resolve this turn’s `maxSteps` (overridable by context);
2. Open workspace lease / steer queue / background evidence submit defer;
3. `interceptAgentStart` (extension may abort);
4. `beginRunTurn` initializes state;
5. **`return a.runToolLoop(ctx, state)`**.

No mysterious “framework base class”—an explicit state machine; policy is split across `beginRunTurn` / `handleFinalResponse` / `handleToolRound`.

### 7.2 `runToolLoop`: what happens in one round

The core loop is at `run_loop.go:274-355`:

```mermaid
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? (write into session, may accept one cache miss)
        A->>A: CaptureShape(system+tools)
        A->>P: streamWithMissingReasoningRecovery
        P-->>A: text + reasoning + tool_calls + usage
        A->>A: CompareShape → cache diagnostics
        alt no tool_calls
            A->>A: handleFinalResponse (incl. maybeCompact)
        else has tool_calls
            A->>T: handleToolRound → parallel read-only / serial write
            T-->>A: tool results written into session
        end
    end
    A-->>U: maxStepsPause or error or nil

A few heavily flavored details:

Detail Meaning Location
Steer Mid-turn interjection into a queue; on consume, write a user message with a guidance prefix; the comment admits “one cache miss is inevitable” run_loop.go:276-283
Missing reasoning recovery In DeepSeek thinking mode a tool call missing reasoning_content → silent replay of the same request at most once run_loop.go:357-364, agent.go:1388-1394
Stream recovery Interrupted stream at most maxStreamRecoveries=3, and does not consume maxSteps (step--) run_loop.go:300-309
Cache diagnostics Every round CompareShape compares system/tools/log_rewrite run_loop.go:285-294
Pause, not crash maxStepsPause / todoStallPause: the work is already in the session; the user sending one more message continues agent.go:1469-1494
Delivery readiness failure Before a final answer the host checks todo/criteria/verify/signoff → FinalReadinessError, open the next round handleFinalResponse
Empty final / thinking-only At most maxEmptyFinalBlocks nudges run_loop.go, agent.go:42
Recovery grace After a recovery episode is exhausted, one summarize-only lap, then RecoveryPauseError recovery path

7.3 Assembly entry: boot.Build → the same Runner

Mode Trigger Turn API
TUI bare reasonix / chat async Controller.SendWithRaw
Headless reasonix run / -p run one round synchronously; Ask fail closed against the writer; needs --auto/-y
ACP reasonix acp blocking Controller.RunTurn (session/prompt)
serve / desktop / bot their own entries SSE / Wails / IM → the same Controller

boot.Build (internal/boot) freezes the system prefix in one shot (output style, environment-probe snapshot, memory, skill index), then wraps an optional planner_model into a Coordinator.

7.4 Single-tool execution pipeline

executeOne (execute_one.go:65-101) is a fixed five beats:

  1. parseToolCall — Resolve, ambiguous MCP names, duplicate success/fail loop guard, stale-anchor edit intercept; bash may degrade to read-only by args (permission.BashCommandIsReadOnly);
  2. interceptToolBefore — extension may rewrite the call;
  3. resolveToolPolicy — permission gate;
  4. prepareToolExecution — preview, mutation bookkeeping, parent write lock;
  5. finishToolExecution — actually execute + receipt.

Read-only tools may run in parallel; writes are serial—same family as Claude Code / OpenAI4S “read-only waves,” but landing on Go’s mutation observer / evidence ledger.


Part 7

Chapter 8 · Compose: drive volatile content into the turn tail

8.1 Motive

The system prefix must stay byte-stable, but goal, plan, language preference, memory updates, retrieval results may change every turn.

8.2 Constraint

Anything unstable, or that need not appear, cannot enter the cache-stable prefix.

8.3 Rejected alternatives

  • “Paste all dynamic content into the system prompt”: convenient but colds cache every turn, directly against the constitution;
  • “Dynamic content never enters context”: goal/plan/memory updates cannot take effect immediately.

8.4 Choice

control.Compose (control/input.go:137-212) assembles in a fixed order before the real user turn: activeGoalBlock → PlanModeMarker → language wrap → <memory-update> → background-jobs → hook context → memory.recall Block.

8.5 Cost

  • One extra assemble-and-strip per turn (StripComposePrefixes);
  • If a frontend/extension bypasses Compose and sends a message directly, the cache constitution is broken—so every frontend goes through the same Controller.

Part 8

Chapter 9 · Compaction three rungs: soft → snip → summary (a cache reset with a posted price)

compact.go:20-37 nails the policy:

Stage Default threshold (fraction of context window) What it does
Soft 0.5 Report that context is growing; still keep the cache-stable prefix
Tool-result snip 0.6 Cheaply rewrite stale tool results
Summary compact 0.8 (force 0.9) Summary fold; keep a recent tail of a fixed token budget (default 16384)

Design points:

  • Trigger by ratio, retain by absolute token budget—a large window will not over-compact; a small window will not get stuck compacting near the threshold;
  • Summary uses structured headings (Standing facts / Goal / Decisions / Files / Commands / Errors / Pending), wrapped in <compaction-summary>;
  • Ablation switches can turn off cache-friendly strategy for a contrast experiment (internal/ablation);
  • Compact bumps LogRewriteVersion → CompareShape will mark log_rewrite—honestly admitting this is a cache-reset point.

Compared with Raven’s “lossless archive” and Claude Code’s “summary discard”: Reasonix explicitly stands on “cheap snip first, then pay the cache tax of one summary.”


Part 9

Chapter 10 · Tool ABI: builtin + MCP + use_capability fixed proxy

10.1 Compile-time builtins (contract table)

docs/TOOL_CONTRACT.md is guarded by tests (TestBuiltinToolContractDocumentation), same-source as the runtime registry. Core surface:

Category Tools
Read read_file grep glob ls code_index web_fetch
Write write_file edit_file multi_edit move_file delete_range delete_symbol notebook_edit
Shell bash + bash_output / wait / kill_shell
Task/delivery todo_write complete_step update_goal

Implementation side is all init() { tool.RegisterBuiltin(...) } (e.g. builtin/readfile.go:27).

10.2 Full boot surface vs Economy

Default full-token boot also hangs session / memory / skill / subagent / LSP / install / slash etc.: ask, task/fleet/parallel_tasks, memory/remember/forget, run_skill, LSP four-piece, explore/research/review/security_review, etc. (docs/TOOL_CONTRACT.md).

Delivery additionally:

  • use_capability: stable MCP proxy;
  • review_report: structured review of medium/high-risk changes;
  • Host-side evidence: verification / diff / files / manual; a complete_step with no evidence is refused outright.

Economy deliberately exposes only a thin surface (about ask/bash/read_file/write_file/edit_file/background three-piece + connect_tool_source); the rest mount on demand—trading “cannot see all tools at once” for tokens and prefix stability.

10.3 Tool-interface flavor

Tools carry capability bits such as ReadOnly, preview (Previewer), images, PlanMode classification—permissions and parallel scheduling read these bits, rather than relying on the model to “behave.” Checkpoint only tracks editing tools that carry Previewer (see Chapter 12).


Part 10

Chapter 11 · Permissions, sandbox, workspace fence: application rules × OS fence

11.1 Permission Policy + Ask / Auto / Yolo

permission.Policy (permission.go):

  • Rule shape aligned with Claude Code: Tool / Tool(glob) / legacy Tool=literal (ParseRule);
  • Decide(toolName, readOnly, args); bash takes segmented decompose (DecomposeBashCommand);
  • BashCommandIsReadOnly: degrade “schema-writable bash” to read-only on the concrete argv (affects parallel, mutation, evidence);
  • BashSubjectRequiresExplicitApproval: indirect execution, dangerous git, etc. force explicit approval.

Product approval modes (docs/TOOL_APPROVAL_MODES.md) are orthogonal to collaboration mode (normal/plan/goal):

Mode Behavioral points
Ask Writes default to ask; headless reasonix run fail closed against the writer
Auto Ordinary writers auto-allow; deny/ask rules, Plan confirm, nested/indirect Bash, MCP destructive, sensitive remember/forget still ask
Yolo The only mode that can bypass the nested-Bash human gate; still does not bypass deny and sandbox

There is also internal/guardian: an independent security-review sub-session (with a denial circuit breaker)—cannot replace user confirmation of memory writes. Hooks (internal/hook) provide PreToolUse/PostToolUse/PostToolUseFailure, plus Claude tool-name compatibility mapping.

11.2 Sandbox + confine

builtin/bash.go wraps the command in sandbox.Command:

Platform Bash OS sandbox
macOS sandbox-exec (Seatbelt)
Linux bwrap
Windows product-fixed off, command unconfined; file-class builtins still have workspace confine

On enforce with no backend, fail closed (do not run naked). Escape goes through sandbox.EscapeApprover. MCP stdio by default does not inherit the Bash sandbox (product default in internal/plugin/plugin.go is the host process; comments state the reason).

SECURITY.md writes the boundary clearly: workspace fence, permissions, sandbox, secrets, HTTP serve’s localhost/CORS, desktop/bot isolation, updater verification—and what does not count as a vulnerability.

11.3 Checkpoint / Rewind

Aligned with Claude Code’s Esc-Esc / /rewind narrative (docs/CHECKPOINTS.md):

  • Mechanism: file snapshots (not git); sidecar <session-id>.ckpt/;
  • Tracked range: editing tools that carry Previewer (write_file / edit_file / multi_edit);
  • Not tracked: bash side effects; move_file has not yet implemented Previewer;
  • API: Controller.Checkpoints / Rewind / PrepareRewind+CommitRewind (including coverage confirmation);
  • Explicitly not done: git-backed rollback (docs mark out of scope).

Part 11

Chapter 12 · Checkpoint / Delivery / Goal: delivery evidence and a completion protocol

12.1 Three orthogonal axes

docs/GOAL_ENFORCEMENT.zh-CN.md opens:

Goal is the only cross-turn scheduler; Delivery is a pure quality gate; tool permissions and sandbox are unaffected by the Goal switch.

Axis Duty
Goal (/goal) Cross-turn advance, budget, pause/resume
Delivery readiness: todo / criteria / verification / review / signoff / capability…
Permission / Sandbox always independent

The model declares intent via update_goal(continue|complete|blocked); the host uses a structured ReadinessResult (agent.go:1497+) to decide whether it is truly complete. Declaring complete without evidence → open the next round, rather than believing the model’s mouth.

12.2 complete_step

The builtin tool description is fierce (TOOL_CONTRACT.md): completion must carry evidence; the host advances the todo on its behalf. Same spectrum as grok-build Goal Mode and MiMo “do not trust self-report”—Reasonix lands it with host-observed receipts.

12.3 Collaboration Profile

(docs/COLLABORATION_MODES.zh-CN.md)

Profile Points
Economy single model, thinner tool surface, for cost-sensitive tasks
Balanced full tool surface; optional independent planner_model
Delivery Balanced + use_capability + acceptance contract + review gate

Part 12

Chapter 13 · control.Controller: one face behind every frontend

13.1 Design iron law

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.

In practice there are also ACP / bot entries. Unified assembly: boot.Build → Controller → agent.Runner (or Coordinator).

13.2 Path of one user message

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

Key API family (controller.go): Send / Submit / SubmitHTTP / SubmitDisplay / RunTurn / Goal-loop variants; runGuarded does turn admission so a double-open cannot run away.

13.3 Why did Controller become a 6k-line giant file?

Because it swallowed: session restore, checkpoint, memory slash, MCP lifecycle, capability, steer fallback, yolo/plan, attachments, goal usage……all product behavior shared by every frontend. The cost is a giant file; the gain is “fix one place, TUI/desktop/HTTP all correct.” In this series OpenAI4S’s gateway.py and Codex’s turn.rs are the same “giant heart” shape.


Part 13

Chapter 14 · Memory, instructions, extensions, desktop/ACP

14.1 Context Engine v2: instructions ≠ memory

Central law of docs/SESSION_MEMORY_RETRIEVAL.md:

  • Standing instructions (REASONIX.md / AGENTS.md / CLAUDE.md + .local + ancestor directories + global): must appear on relevant turns; enter the cache-stable prefix;
  • Background memory: facts that can go stale; BM25 auto-recall (defaults defaultAutoRecallLimit=4, defaultAutoRecallChars=2400) enters the turn tail; the index merges into the prefix only next session;
  • #note / /remember write instruction files; the remember tool writes background facts—do not mix;
  • Safe writes: some scopes create-only; the rest need confirmation—Auto/Yolo/Guardian cannot bypass;
  • Instruction parse: deeper directories override broader; same directory .local wins; @path import limited to 5 layers and forbidden to escape.

14.2 Three extension layers: MCP · Plugin Package · Extension Protocol v1

Layer What it is Trust model
MCP (internal/plugin) JSON-RPC; stdio / Streamable HTTP; tool names mcp__<server>__<tool>; compatible with project .mcp.json precise rules + mcp_connect__*; OAuth etc. still deferred
Plugin packages (internal/pluginpkg) reasonix-plugin.json; compatible with .claude-plugin / .codex-plugin; contribute skills/hooks/mcp/commands/agents/themes after install-and-enable, take effect by contribution surface
Extension Protocol v1 (reasonix.extension.v1) NDJSON JSON-RPC sidecar; 17 frozen hook points (tool.before, permission.decision, system_prompt.build, compaction.*…); schema generation + CI drift-check Full trust: install is highest privilege, can override host deny; UI marks FULL TRUST

MCP and Extension are different layers: the former attaches tools/resources; the latter attaches host-lifecycle intercepts. Full-trust Extension is an independent attack surface, and also the hardest landing of an “Open Design-style public contract” inside Reasonix (docs/EXTENSION_PROTOCOL.md).

14.3 Subagent profiles

Skill frontmatter runAs: subagent (docs/SUBAGENT_PROFILES.md): builtins explore / research / review / security_review; CLI reasonix subagent …; invocation via /<profile> or task/fleet + write_paths parallel-write isolation. Default concurrency max_subagent_concurrency=6, max_parallel_writers=3. Claude plugin agents/*.md can map to /<plugin>:agent:<name>.

14.4 Desktop and ACP

  • Desktop (desktop/): nested Wails module (keep parent module CGO_ENABLED=0); React+TS webview ↔ the same Controller (no HTTP hop);
  • ACP (internal/acp, docs/ACP.md): reasonix acp [--profile …]; NDJSON JSON-RPC; loadSession + embeddedContext; capability advertisement no image/audio; MCP http: true, sse: false; vendor extensions include _reasonix.io/session/steer;
  • VS Code extension SivanLiu.reasonix-agent brings up local reasonix acp;
  • Remote-SSH / workbench: baseline PR #7368 reconnect hardening—the product has grown from a local TUI to a remote workbench.

Part IV · Taste and bounds

Part 14

Chapter 15 · Ten decisions, five-beat recap

# Choice Motive Constraint Rejected Cost
1 Volatile context into turn tail prefix stable = save money DeepSeek auto prefix cache hits by bytes dump everything into system per-turn assemble/strip cost; bypassing Compose breaks the constitution
2 Tool schema hashed after sort avoid false miss tool registration order is uncontrollable hash by registration order the sort logic itself must be test-guarded
3 Steer pays a cache tax once interjection must be immediately visible the model must see the new instruction don’t interject / pretend zero cost every interjection misses one round
4 Compaction three rungs delay the summary reset context will eventually grow one-shot summary extra snip logic and threshold tuning
5 use_capability fixed proxy dynamic MCP cannot move schema MCP inventory changes anytime register mcp__* directly into the Registry one extra parse layer and permission names (mcp_connect__*)
6 bash runtime read-only degrade schema stable, semantics precise whether bash is read-only depends on argv judge only by schema BashCommandIsReadOnly must maintain a dangerous-command list
7 Missing reasoning silent retry DeepSeek thinking occasionally missing reasoning provider requires thinking replay fail outright one extra same-request replay; need debounce cooldown
8 maxSteps → Pause session assets first budget limited but work already on disk error and start over more pause state machine and restore paths
9 Behavior into Controller many frontends consistent frontend count growing each frontend implements itself Controller becomes a 6k-line giant file
10 Contracts executable (SPEC/TOOL_CONTRACT/PR) constitution cannot rely on conscience the repo will keep growing wiki docs CI/test cost; PR metadata requirements

Part 15

Chapter 16 · Cross-cut (coding-agent table)

Dimension Claude Code Open Design OpenAI4S Hermes Codex Reasonix
Category terminal coding design host research dual-plane personal learning agent official Rust CLI DeepSeek terminal coding
Main loop own none (plugs into others) Engine+Cell Python loop run_turn runToolLoop
Context strong prompt engineering 20-layer banded cache science state in the kernel prefix sacred two-layer turn Cache-first + shape
Completion signal natural end artifact files finalize / submit_output skill sedimentation three-party stop natural end + Delivery readiness
Extension MCP/Skills CLI adapters Skills recipes 74-tool plugins MCP+crate MCP + Plugin packages + Full-trust Extension v1
Distribution closed-source product daemon+web Python daemon uv/Python Rust binary Go static binary
Permission product surface popup+rules host delegated Notebook approval environment many backends Ask×sandbox Ask/Auto/Yolo × sandbox (orthogonal)

Part 16

Chapter 17 · Honest bounds

  • Giant-file cost: controller.go / chat_tui.go / agent.go are all thousands of lines; newcomer onboarding is steep;
  • DeepSeek-first tax: reasoning recovery and cache assumptions do not necessarily hold for other gateways (there is a compatibility path, but product mindshare still leans DeepSeek);
  • Executor direct MCP: Balanced Executor can still cold cache because of MCP inventory change—the docs already admit this;
  • Windows Bash OS sandbox: product-fixed unconfined; file tools still have confinement;
  • Checkpoint coverage: does not track bash side effects; no git-backed; move_file preview unfinished;
  • Extension full trust: install is highest privilege—capability is strong; the threat model needs the user to understand it;
  • MCP long tail: OAuth, list_changed, some scopes still deferred (docs/SPEC.md:877);
  • ACP capability advertisement: no image/audio; agent-side MCP SSE narrowed;
  • Old branch: v1 only critical fixes; analysis / secondary development should align with main-v2.

Part 17

Chapter 18 · Source-tour index and local reproduction

Order Path What to look at
1 README.zh-CN.md + docs/SPEC.md product position and contract
2 REASONIX.md the team’s own cache constitution
3 cmd/reasonix/main.go + internal/boot entry and boot.Build
4 internal/control/input.go → Compose turn tail
5 internal/agent/run_loop.go main loop
6 internal/agent/cache_shape.go miss diagnostics
7 internal/agent/compact.go + prune.go compaction three rungs
8 internal/agent/execute_one.go single-tool pipeline
9 internal/agent/coordinator.go dual-model dual session
10 docs/TOOL_CONTRACT.md + internal/tool/builtin/ tool surface
11 docs/TOOL_APPROVAL_MODES.md + permission/ + sandbox/ Ask/Auto/Yolo × fence
12 docs/CHECKPOINTS.md rewind snapshots
13 docs/GOAL_ENFORCEMENT.zh-CN.md completion protocol
14 docs/SESSION_MEMORY_RETRIEVAL.md instructions vs memory
15 docs/EXTENSION_PROTOCOL.md + PLUGIN_PACKAGES.md three extension layers
16 docs/ACP.md / desktop/README.md embed and desktop
17 internal/control/controller.go (optional) multi-frontend orchestration

Local reproduction:

cd "参考项目/DeepSeek-Reasonix"
git fetch origin main-v2
git checkout main-v2
git reset --hard 627b051
# optional: run the contract test (needs local Go)
# go test ./internal/tool -run TestBuiltinToolContractDocumentation

Part 18

Appendix A · Contrast with this series’ “Catalog of agent engineering patterns”

Pattern-catalog chapter Reasonix landing
I Prompt-cache engineering Textbook: stabilize the prefix / move the volatile out / stabilize tools / compact with care / telemetry visible (all five axes)
II Stop judgment natural stop + maxSteps/todo stall Pause + Delivery readiness
III Permission gates Ask/Auto/Yolo + rules-first + bash decompose + OS sandbox (Win Bash gap)
IV Context compaction snip first, summary pays the tax; soft explicitly keeps the prefix
V Memory system instruction files (prefix) ≠ background facts (BM25/tail); confirmation gate cannot be bypassed by Yolo
VI Tool system fixed proxy isolates dynamic MCP; Economy connect_tool_source
VII Sandbox Seatbelt/bwrap; application fence → permissions → OS sandbox
VIII Sub-agents Skill profile + task/fleet; write_paths parallel-write isolation
XII Persistence file checkpoint rewind (not git); does not cover bash side effects
XIII Extension ecology MCP + Plugin packages + Full-trust Extension Protocol v1
XV Model strategy DeepSeek-first; planner_model dual session keeps each cache

Part 19

Appendix B · One-sentence close

Reasonix is not “another Go-written Claude Code imitation.” It promoted DeepSeek’s automatic prefix cache from a billing leftover to the architectural spine: Compose split, Shape diagnostics, Capability proxy, PR metadata, Delivery evidence—all turn around “do not cold the cache.” If in this series you already understand Hermes’s cache-sacred and Open Design’s banded assembly, reading Reasonix is watching the same philosophy executed to what hardness inside a Go single-binary coding agent.


Part 20

Appendix C · Restoring developer motive: from “cost anxiety” to “architectural constitution”

Chapters 1, 2, and 4 already unfolded the motive chain; here a condensed contrast table is kept for looking back.

Motive Evidence Architecture it grew into
Long-session token cost is high README.zh-CN.md:42-43 product position “tuned around prefix cache”
Prefix must stay byte-stable REASONIX.md:14-16 constitution + PR metadata + CI
Volatile content must move out control/input.go:181-183 Compose turn tail
Dual models cannot share a session docs/SPEC.md:238-240 Planner / Executor independent sessions
Compaction must post an honest price docs/SPEC.md:328-329 soft → snip → summary + LogRewriteVersion
Miss must be explainable cache_shape.go PrefixShape / CompareShape diagnostics
Cost is the product axis COLLABORATION_MODES.zh-CN.md:86,136 Economy / Balanced / Delivery three tiers

Analysis baseline: 参考项目/DeepSeek-Reasonix @ 627b051 (main-v2). Series position: a coding-agent sample; nearest neighbors Hermes (cache), Codex (sandbox orthogonal), Claude Code (category).

↑