DeepSeek-Reasonix Core Components: A Complete Architecture Guide
DeepSeek-Reasonix is a modular Go-based coding agent framework built around interchangeable providers, tools, plugins, and agents that enable safe, extensible LLM-driven automation.
The architecture of esengine/DeepSeek-Reasonix (commonly called Reasonix) deliberately separates concerns into thin, swappable layers. This design lets you add new language models, custom tools, or external plugins without modifying core logic. Below is a comprehensive breakdown of every component, how they interact, and how to extend them.
Provider: The LLM Abstraction Layer
The Provider component abstracts any LLM vendor behind a uniform interface. Whether you're connecting to OpenAI-compatible APIs, Anthropic Claude, or custom endpoints, the same Stream method handles token-delta delivery.
In internal/provider/provider.go, the interface looks like this:
type Provider interface {
Name() string
Stream(ctx context.Context, req Request) (<-chan Chunk, error)
}
Providers self-register via init() functions using provider.Register(kind, factory). This registry pattern lets you drop in new provider packages without touching existing code.
Built-in Provider Registration Example
// File: internal/provider/custom/custom.go
package custom
import (
"context"
"github.com/esengine/DeepSeek-Reasonix/internal/provider"
)
type SimpleProvider struct{ cfg provider.Config }
func (p *SimpleProvider) Name() string { return "custom" }
func (p *SimpleProvider) Stream(ctx context.Context, req provider.Request) (<-chan provider.Chunk, error) {
// Implementation that streams from your model endpoint
out := make(chan provider.Chunk)
go func() {
defer close(out)
// ... token streaming logic ...
}()
return out, nil
}
func init() {
provider.Register("custom", func(cfg provider.Config) (provider.Provider, error) {
return &SimpleProvider{cfg: cfg}, nil
})
}
The spec documents this pattern in SPEC §3.1.
Tool: Executable Actions for Agents
The Tool interface in internal/tool/tool.go encapsulates any callable action—from file I/O and shell commands to remote MCP tools. Every tool exposes four methods: Name, Description, Schema (JSON Schema for the LLM), and Execute.
Built-in tools live in internal/tool/builtin/. Here's how to register a simple greeting tool:
// File: internal/tool/builtin/hello.go
package builtin
import (
"context"
"encoding/json"
"github.com/esengine/DeepSeek-Reasonix/internal/tool"
)
type helloTool struct{}
func (t *helloTool) Name() string { return "hello" }
func (t *helloTool) Description() string { return "Greets the user." }
func (t *helloTool) Schema() json.RawMessage {
return json.RawMessage(`{"type":"object","properties":{}}`)
}
func (t *helloTool) Execute(_ context.Context, _ json.RawMessage) (string, error) {
return "Hello, Reasonix user!", nil
}
func init() { tool.RegisterBuiltin(&helloTool{}) }
This mirrors the tool.RegisterBuiltin pattern described in SPEC §3.2.
Plugin: Out-of-Process Extensions via MCP
The Plugin system enables external tools and prompts through the MCP (Model Context Protocol) using JSON-RPC. Implemented in internal/plugin/plugin.go, plugins support three transport types:
- stdio – Local executable subprocess
- http – HTTP POST endpoint
- sse – Server-Sent Events stream
Plugins extend the agent's capabilities at runtime without recompilation, making Reasonix ideal for integrating specialized tools maintained by separate teams.
Agent: The Core Session Orchestrator
The Agent in internal/agent/agent.go drives a single LLM conversation. Its responsibilities include:
- Building the
Request(conversation history + available tool schemas) - Streaming responses via
Provider.Stream - Detecting
ChunkToolCalldeltas and dispatching to the appropriate tool - Feeding tool results back as new messages
- Looping until completion or step limit reached
The agent also handles context compaction: when token usage nears the provider's context_window, it summarizes older turns while preserving recent facts (see SPEC §3.6).
Typical Agent Execution Flow
$ reasonix run "Write a Python function that computes Fibonacci numbers."
The CLI (cmd/reasonix/main.go) parses this, instantiates the configured provider, and hands control to Agent.Run, which streams output and automatically invokes tools like write_file or bash as needed.
Coordinator: Two-Model Collaboration
The Coordinator in internal/agent/coordinator.go implements an advanced pattern using two specialized models:
| Model | Role | Tool Access |
|---|---|---|
| Planner | Generates high-level plans from requirements | Read-only tools only |
| Executor | Executes the plan with full tool access | All enabled tools |
This separation keeps each model's prompt cache stable—the planner sees a consistent read-only view, while the executor handles mutation. When agent.planner_model is set in config, the coordinator spawns both agents and bridges their interaction.
Permission: Per-Tool Safety Gating
The Permission system in internal/permission/permission.go provides three-level gating for every tool:
allow– Execute automaticallyask– Prompt user for confirmationdeny– Block execution
Rules parse from TOML config and evaluate through the Gate.Decide method before any tool runs. This ensures safe autonomous operation even with powerful tools like bash or write_file.
Command: Slash-Command Interface
The Command handler in internal/command/command.go processes TUI inputs starting with /. Three sources populate the command registry:
- Built-ins:
/new,/clear,/compact - Custom markdown: Files in
.reasonix/commands/*.md - MCP prompts: Namespaced as
/mcp__<server>__<prompt>
Commands can trigger agent actions, modify session state, or invoke plugin-provided functionality.
Configuration: TOML-Based Setup
Reasonix uses layered TOML configuration resolved in priority order:
CLI flags → project reasonix.toml → user config → defaults
The reasonix.example.toml demonstrates providers, tools, plugins, and permission rules. Key sections include:
[provider]– Model endpoints and API keys[agent]– Model selection, planner configuration, step limits[[tool]]– Built-in tool enablement[[plugin]]– MCP server connections[[permission]]– Tool-specific gating rules
Data Types: The Streaming Protocol
Core structures in internal/provider/provider.go drive the streaming protocol:
Message– Conversation turns with role and contentChunk– Token deltas or tool call fragments from providersRequest– Complete payload sent toProvider.StreamChunkToolCall– Structured tool invocation from the LLM
These types ensure type-safe communication between agents and providers across the codebase.
CLI & Desktop: User-Facing Entry Points
The binary entry point at cmd/reasonix/main.go wires everything together:
- Parses flags and subcommands via
internal/cli/ - Loads and merges configuration
- Initializes the Bubble-Tea TUI
- Dispatches to
Agent.RunorCoordinatorbased on config
Users interact through either the TUI or direct command execution.
How Components Interact at Runtime
- Startup: CLI parses config, calls
provider.Registerandtool.RegisterBuiltinfor all built-ins - Session:
internal/agent.NewRunnerbuilds a*Registry(enabled tools + plugins) andProviderinstance - Request Loop:
Agent.RunpreparesRequest, streams viaProvider.Stream, consumesChunks - Tool Execution: On
ChunkToolCall, agent registry-lookup →permission.Gate.Decide→Tool.Execute→ result appended to messages - Two-Model Mode:
Coordinatorspawns plannerAgent(read-only), hands plan to executorAgent - Compaction: Automatic summarization when nearing
context_window
Summary
DeepSeek-Reasonix components form a plug-and-play architecture where each layer can be swapped independently:
- Provider abstracts any LLM vendor behind a streaming interface
- Tool encapsulates executable actions with JSON Schema contracts
- Plugin extends capabilities via MCP without recompilation
- Agent orchestrates single-model sessions with compaction
- Coordinator enables efficient two-model planner/executor separation
- Permission gates tool execution for safe autonomy
- Command provides flexible TUI interaction
- Configuration layers TOML settings with sensible defaults
Together these pieces let you customize models, add capabilities, and enforce policies without forking core code.
Frequently Asked Questions
What makes Reasonix different from other coding agents?
Reasonix distinguishes itself through vendor-agnostic providers and two-model coordination. Unlike agents tightly coupled to OpenAI or Claude, the Provider interface lets you swap models by changing config. The Coordinator pattern further optimizes cost and latency by using a lightweight planner model for reasoning and a capable executor for implementation.
How do I add a custom tool to Reasonix?
Implement the Tool interface with Name, Description, Schema, and Execute methods, then call tool.RegisterBuiltin in an init() function. Place your file in internal/tool/builtin/ or any package imported at runtime. No core changes required—the registry discovers your tool automatically.
Why does Reasonix use MCP for plugins instead of native Go plugins?
MCP (Model Context Protocol) via JSON-RPC provides language-agnostic, out-of-process isolation. Teams can write plugins in Python, TypeScript, or any language supporting JSON-RPC. This avoids Go plugin compatibility issues, enables separate versioning, and prevents plugin crashes from destabilizing the main agent.
What happens when a conversation exceeds the context window?
The Agent triggers compaction (SPEC §3.6). It summarizes older assistant and tool turns into compressed representations while preserving recent messages and critical state. This keeps the conversation within context_window limits without losing task continuity.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →