A Rust coding agent that uses the Claude Code CLI (Claude Max OAuth) or ChatGPT Pro via OAuth.
- No API keys needed - Uses Claude Code CLI credentials and Codex OAuth
- Dual provider support - Works with Claude Code CLI and OpenAI/Codex
- Server/Client architecture - Run as daemon, connect from multiple clients
- 20+ built-in tools - File ops, search, web, shell, memory, and parallel execution
- MCP support - Extend with Model Context Protocol servers
- Cross-session memory - Learns and remembers across sessions
- Swarm coordination - Multiple agents can work together with conflict detection
- NO RENDERING ISSUES - Unlike a certain Cl@ude C*de (also renders at 1k+fps)
- Innovative TUI - Info widgets, status line, pagnitation
You need at least one of:
- Claude Max subscription - Install Claude Code CLI, then run
claudeto authenticate - ChatGPT Pro/Plus subscription - Run
codex loginto authenticate
cargo install --path .Or build from source:
cargo build --release
./target/release/jcode# Interactive TUI (default - connects to server or starts one)
jcode
# Run a single command
jcode run "Create a hello world program in Python"
# Start as background server
jcode serve
# Connect to running server
jcode connect
# Specify provider explicitly
jcode --provider claude
jcode --provider openai
# Change working directory
jcode -C /path/to/project
# Resume a previous session
jcode --resume fox # by memorable name
jcode --resume session_abc123_fox # by full ID| Tool | Description |
|---|---|
bash |
Execute shell commands |
read |
Read file contents with line numbers |
write |
Create or overwrite files |
edit |
Edit files by replacing text |
multiedit |
Apply multiple edits to one file |
patch |
Apply unified diff patches |
glob |
Find files by pattern |
grep |
Search file contents with regex |
ls |
List directory contents |
webfetch |
Fetch URL content |
websearch |
Search the web (DuckDuckGo) |
codesearch |
Search code/documentation via Exa |
skill |
Load a skill from SKILL.md |
task |
Run a delegated sub-task |
todowrite |
Update todo list |
todoread |
Read todo list |
remember |
Store persistent memories |
session_search |
Search past sessions (RAG) |
conversation_search |
Search current conversation |
communicate |
Send messages to other agents |
bg |
Run tasks in background |
batch |
Execute up to 10 tools in parallel |
mcp |
Manage MCP server connections |
High-Level Architecture
┌─────────────────────────────────────────────────────────────────┐
│ CLI (main.rs) │
│ jcode [serve|connect|run|repl|login|update|self-dev] │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐
│ TUI (app.rs) │ │ Server │ │ Standalone │
│ - Rendering │◄─│ (Unix Sock) │ │ Agent Loop │
│ - Input │ │ │ │ (--standalone) │
│ - State │ └──────┬──────┘ └─────────────────┘
└─────────────────┘ │
▼
┌─────────────────────────┐
│ Agent (agent.rs) │
│ - Turn loop │
│ - Tool execution │
│ - Session management │
└───────────┬─────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌───────────┐ ┌─────────────────┐
│ Provider │ │ Registry │ │ Session │
│ (Claude/OpenAI)│ │ (Tools) │ │ (Persistence) │
└─────────────────┘ └───────────┘ └─────────────────┘
Data Flow:
- User input enters via TUI or CLI
- Server routes requests to appropriate Agent session
- Agent sends messages to Provider, receives streaming response
- Tool calls are executed via Registry
- Session state is persisted to
~/.jcode/sessions/
Provider System
┌─────────────────────────────────────────────────────────────────┐
│ MultiProvider (provider/mod.rs) │
│ - Detects available credentials on startup │
│ - Allows runtime model switching across providers │
│ - Defaults to Claude if available, otherwise OpenAI │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ ClaudeProvider │ │ OpenAIProvider │
│ (provider/claude.rs) │ │ (provider/openai.rs) │
├─────────────────────────┤ ├─────────────────────────┤
│ - Claude Code CLI │ │ - Codex OAuth │
│ - CLI subprocess │ │ - Direct HTTP API │
│ - Tool execution by CLI │ │ - Local tool execution │
│ - Session resume │ │ - Reasoning effort ctrl │
└─────────────────────────┘ └─────────────────────────┘
│ │
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ ~/.claude/ │ │ ~/.codex/auth.json │
│ .credentials.json │ │ │
└─────────────────────────┘ └─────────────────────────┘
Provider Trait:
┌─────────────────────────────────────────────────────────────────┐
│ trait Provider: Send + Sync { │
│ async fn complete(...) -> Result<EventStream>; │
│ fn name(&self) -> &str; │
│ fn model(&self) -> String; │
│ fn set_model(&self, model: &str) -> Result<()>; │
│ fn handles_tools_internally(&self) -> bool; │
│ fn supports_compaction(&self) -> bool; │
│ } │
└─────────────────────────────────────────────────────────────────┘
Key Design Decisions:
MultiProviderallows seamless switching between Claude and OpenAI mid-session- Claude Code CLI handles tool execution internally; OpenAI requires local execution
- Credentials are loaded lazily and cached
Tool System & Registry
┌─────────────────────────────────────────────────────────────────┐
│ Registry (tool/mod.rs) │
│ Arc<RwLock<HashMap<String, Arc<dyn Tool>>>> │
├─────────────────────────────────────────────────────────────────┤
│ Methods: │
│ - new(provider) -> Self Create with default tools │
│ - definitions() -> Vec<ToolDef> Get schemas for API │
│ - execute(name, input, ctx) Run a tool │
│ - register(name, tool) Add tool dynamically (MCP) │
│ - unregister_prefix(prefix) Remove tools (MCP cleanup) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ File Tools │ │ Search/Nav │ │ Execution │
├─────────────┤ ├─────────────┤ ├─────────────────┤
│ read │ │ glob │ │ bash │
│ write │ │ grep │ │ task (subagent) │
│ edit │ │ ls │ │ batch (parallel)│
│ multiedit │ │ codesearch │ │ bg (background) │
│ patch │ │ │ │ │
│ apply_patch │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ Web Tools │ │ Memory/RAG │ │ Meta/Control │
├─────────────┤ ├─────────────┤ ├─────────────────┤
│ webfetch │ │ remember │ │ todowrite/read │
│ websearch │ │ session_ │ │ skill_manage │
│ │ │ search │ │ communicate │
│ │ │ conversation│ │ mcp │
│ │ │ _search │ │ selfdev │
└─────────────┘ └─────────────┘ └─────────────────┘
Tool Trait:
┌─────────────────────────────────────────────────────────────────┐
│ #[async_trait] │
│ trait Tool: Send + Sync { │
│ fn name(&self) -> &str; │
│ fn description(&self) -> &str; │
│ fn parameters_schema(&self) -> Value; // JSON Schema │
│ async fn execute(&self, input: Value, ctx: ToolContext) │
│ -> Result<ToolOutput>; │
│ } │
└─────────────────────────────────────────────────────────────────┘
Tool Categories:
- File Tools: Direct filesystem operations with line-number tracking
- Search Tools: Pattern matching, regex search, directory listing
- Execution: Shell commands, sub-agents, parallel execution
- Web Tools: HTTP fetch, search engines
- Memory: Cross-session persistence and RAG retrieval
- Meta: Todo tracking, skill loading, inter-agent communication
Server Architecture & Swarm
┌─────────────────────────────────────────────────────────────────┐
│ Server (server.rs) │
│ Listens on: /run/user/{uid}/jcode.sock (or $JCODE_SOCKET) │
└─────────────────────────────────────────────────────────────────┘
│
│ Unix Socket (newline-delimited JSON)
│
├──────────────┬──────────────┬──────────────┐
▼ ▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client 1 │ │ Client 2 │ │ Client 3 │ │ Debug │
│ (TUI) │ │ (TUI) │ │ (External) │ │ Socket │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
Server State:
┌─────────────────────────────────────────────────────────────────┐
│ sessions: HashMap<String, Arc<Mutex<Agent>>> │
│ swarm_members: HashMap<String, SwarmMember> │
│ swarms_by_cwd: HashMap<PathBuf, HashSet<String>> │
│ file_touches: HashMap<PathBuf, Vec<FileAccess>> │
│ shared_context: HashMap<PathBuf, HashMap<String, SharedCtx>> │
│ event_tx: broadcast::Sender<ServerEvent> │
└─────────────────────────────────────────────────────────────────┘
Swarm Coordination:
┌─────────────────────────────────────────────────────────────────┐
│ Same Working Directory │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ fox │◄──────►│ oak │◄──────►│ river │ │
│ │ (agent) │ │ (agent) │ │ (agent) │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ └──────────────────┼──────────────────┘ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ File Touch Events │ │
│ │ Conflict Detection │ │
│ │ Shared Context │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Protocol (protocol.rs):
Request types: Message, Cancel, Clear, Ping, Subscribe, GetHistory,
ResumeSession, CycleModel, SetModel, Reload,
CommShare, CommRead, CommMessage, CommList
Event types: Ack, TextDelta, ToolStart, ToolResult, TurnComplete,
Error, History, TokenUsage, ModelChanged, Notification
TUI & Rendering Architecture
┌─────────────────────────────────────────────────────────────────┐
│ App (tui/app.rs) │
│ 262KB - Main TUI application state and logic │
├─────────────────────────────────────────────────────────────────┤
│ State: │
│ - display_messages: Vec<DisplayMessage> │
│ - streaming_text: String (current response buffer) │
│ - input: String (user input buffer) │
│ - scroll_offset: usize │
│ - processing_status: ProcessingStatus │
│ - queued_messages: Vec<String> │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐
│ ui.rs │ │ keybind.rs │ │ markdown.rs │
│ 100KB render │ │ Keybinds │ │ MD→styled text │
│ draw(frame, │ │ handling │ │ syntax hilite │
│ state) │ │ │ │ │
└─────────────────┘ └─────────────┘ └─────────────────┘
Rendering Pipeline:
┌─────────────────────────────────────────────────────────────────┐
│ render_frame(frame, state) │
├─────────────────────────────────────────────────────────────────┤
│ 1. Layout calculation (header, messages, input, status) │
│ 2. For each DisplayMessage: │
│ ├─► parse_markdown() → Vec<MarkdownBlock> │
│ ├─► syntax_highlight() for code blocks │
│ └─► wrap_text() for terminal width │
│ 3. Render streaming_text with partial markdown │
│ 4. Render tool call widgets (collapsible, with status icons) │
│ 5. Render input line with cursor │
│ 6. Render status bar (tokens, model, session info) │
└─────────────────────────────────────────────────────────────────┘
TuiState Trait (30+ methods):
┌─────────────────────────────────────────────────────────────────┐
│ Implemented by both App (standalone) and ClientApp (remote) │
│ │
│ fn display_messages(&self) -> &[DisplayMessage]; │
│ fn streaming_text(&self) -> &str; │
│ fn input(&self) -> &str; │
│ fn is_processing(&self) -> bool; │
│ fn provider_name(&self) -> String; │
│ fn provider_model(&self) -> String; │
│ fn streaming_tokens(&self) -> (u64, u64); │
│ fn status(&self) -> ProcessingStatus; │
│ fn scroll_offset(&self) -> usize; │
│ fn animation_elapsed(&self) -> f32; │
│ ... │
└─────────────────────────────────────────────────────────────────┘
Backend Abstraction (backend.rs):
┌─────────────────────────────────────────────────────────────────┐
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ LocalBackend │ │ RemoteConnection │ │
│ │ (standalone mode) │ │ (client mode) │ │
│ ├─────────────────────┤ ├─────────────────────┤ │
│ │ Direct Agent access │ │ Unix socket to │ │
│ │ In-process events │ │ server, JSON events │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │ │ │
│ └──────────┬───────────────────┘ │
│ ▼ │
│ BackendEvent enum │
│ (TextDelta, ToolStart, ToolDone, etc.) │
└─────────────────────────────────────────────────────────────────┘
UI Layout:
┌─────────────────────────────────────────────────────────────────┐
│ [claude-opus-4-5] [fox] [2 clients] [▶ running] ◀─ Status │
├─────────────────────────────────────────────────────────────────┤
│ │
│ User: Help me fix the bug in auth.rs │
│ │
│ Assistant: I'll look at that file... │
│ ┌─────────────────────────────────────────┐ │
│ │ read auth.rs (245 lines) │ ◀─ Tool calls │
│ └─────────────────────────────────────────┘ │
│ │
│ The issue is on line 45... │
│ │
├─────────────────────────────────────────────────────────────────┤
│ > Type your message here... ◀─ Input │
├─────────────────────────────────────────────────────────────────┤
│ Streaming... 1.2k in / 456 out ◀─ Progress │
└─────────────────────────────────────────────────────────────────┘
Key Files:
tui/app.rs(262KB) - Main application state, event looptui/ui.rs(100KB) - Frame rendering, layouttui/markdown.rs(23KB) - Markdown parsing, syntax highlightingtui/core.rs(15KB) - Shared state between local/remote modestui/backend.rs(13KB) - Backend abstraction, debug eventstui/client.rs(34KB) - Remote client implementationtui/keybind.rs(8KB) - Keyboard shortcut handlingtui/info_widget.rs(25KB) - Floating info paneltui/session_picker.rs(15KB) - Session browser with previewtui/visual_debug.rs(8KB) - Frame capture for debugging
UI Features
A smart floating panel that finds empty screen space on the right side and displays contextual information:
┌─────────────────────────────────────────────────────────────────────────────┐
│ [opus-4.5] [fox] [▶ streaming] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ User: Help me refactor the auth module ┌────────────────────────────┐ │
│ │ ⚡ opus-4.5 (hi) │ │
│ Assistant: I'll analyze the code... │ 2 sessions │ │
│ │ Ctx 45k/200k 22% │ │
│ Looking at auth.rs, I can see │ [███████░░░░░░░░░░░░░░░░░] │ │
│ several opportunities for... │ │ │
│ │ Todos │ │
│ ```rust │ ◐ Refactoring auth │ │
│ pub fn authenticate(...) │ ○ Update tests │ │
│ ``` │ ○ Add documentation │ │
│ │ │ │
│ │ • · · │ │
│ └────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ > | │
└─────────────────────────────────────────────────────────────────────────────┘
Features:
- Auto-positions in largest empty rectangle on right side
- Shows model name, reasoning effort, session count
- Context usage bar (tokens used / limit)
- Todo list with status icons (◐ in_progress, ✓ completed, ○ pending)
- Auto-pages between expanded views every 30 seconds
- Toggle with keyboard shortcut (Ctrl+I)
When resuming sessions (jcode --resume or /sessions command), shows an interactive browser:
┌──────────────────────────────────────┬──────────────────────────────────────┐
│ Sessions (12) │ Preview: fox │
├──────────────────────────────────────┤──────────────────────────────────────┤
│ > 🦊 fox ▶ active 5 min ago │ User: │
│ 🌳 oak ✓ closed 2 hrs ago │ Help me fix the auth bug │
│ 🌊 river ✓ closed 1 day ago │ │
│ ⭐ star 💥 crashed 2 days │ Assistant: │
│ 🌙 moon ✓ closed 3 days │ I'll look at the auth module. │
│ 🔥 ember ✓ closed 1 week │ Let me read the relevant files... │
│ │ │
│ │ [read] src/auth/mod.rs (245 lines) │
│ │ │
│ │ I found the issue on line 142... │
│ │ │
│ ↑/↓ Navigate Enter Select q Quit │ 12 messages · 45k tokens │
└──────────────────────────────────────┴──────────────────────────────────────┘
Features:
- Split view: session list (left) + conversation preview (right)
- Shows session status icons (▶ active, ✓ closed, 💥 crashed, 🔄 reloaded)
- Memorable animal names with emoji icons
- Message count, token estimate, timestamps
- Keyboard navigation (↑/↓/Enter/q)
Frame-by-frame capture system for debugging rendering issues:
/debug-visual on # Enable capture
/debug-visual off # Disable capture
/debug-visual dump # Write frames to file
Captures for each frame:
- Terminal dimensions and layout areas
- State snapshot (processing, input, scroll position)
- Rendered text content (stripped of ANSI codes)
- Detected anomalies (layout overflow, missing content)
Ring buffer keeps last 100 frames for analysis.
Rendering Benchmarks
┌─────────────────────────────────────────────────────────────────┐
│ tui_bench (bin/tui_bench.rs) │
│ Autonomous rendering benchmark for performance testing │
└─────────────────────────────────────────────────────────────────┘
Usage:
cargo run --release --bin tui_bench -- [OPTIONS]
Options:
--frames <N> Number of frames to render (default: 300)
--width <W> Terminal width (default: 120)
--height <H> Terminal height (default: 40)
--turns <N> Number of message turns (default: 200)
--user-len <N> User message length in chars (default: 120)
--assistant-len <N> Assistant message length (default: 600)
--stream-chunk <N> Streaming chunk size (default: 80)
--scroll-cycle <N> Scroll animation cycle length (default: 80)
--mode <MODE> idle | streaming (default: idle)
Benchmark Modes:
┌─────────────────────────────────────────────────────────────────┐
│ Idle Mode: │
│ - Renders static conversation history │
│ - Tests markdown parsing + layout performance │
│ - Simulates scrolling through history │
│ │
│ Streaming Mode: │
│ - Simulates active streaming response │
│ - Incrementally grows streaming_text each frame │
│ - Tests real-time rendering performance │
└─────────────────────────────────────────────────────────────────┘
Example Output:
mode: Idle
frames: 1000
total_ms: 677.94
avg_ms: 0.68
fps: 1475.1
Performance Targets:
- Idle: < 1ms/frame (1000+ fps headroom)
- Streaming: < 2ms/frame (500+ fps headroom)
- With 200 turns of history + markdown + syntax highlighting
Benchmark Results (1000 frames, 200 turns, 120x40 terminal):
| Mode | Avg Frame | FPS | Memory (RSS) |
|---|---|---|---|
| Idle | 0.68ms | 1475 | 18 MB |
| Streaming | 0.67ms | 1498 | 18 MB |
What It Measures:
- Markdown parsing throughput
- Syntax highlighting performance
- Text wrapping and layout calculation
- Scroll offset handling
- Widget rendering overhead
Real-World Usage:
The benchmark measures raw rendering throughput (no throttling). In practice, the TUI is event-driven and only renders when needed:
- User input (keystrokes)
- New streaming text arrives
- Scroll/resize events
- Animation ticks (status spinner)
Typical resource usage for a running jcode session:
- TUI client: ~170 MB RAM, near-idle CPU when waiting
- Server: ~185 MB RAM, ~1% CPU when idle
- During streaming: Brief CPU spikes for rendering, still sub-ms per frame
The sub-millisecond frame times mean plenty of headroom—even at 60 FPS, rendering uses only ~4% of available time budget.
MCP (Model Context Protocol) Integration
┌─────────────────────────────────────────────────────────────────┐
│ MCP Manager (mcp/manager.rs) │
│ Manages lifecycle of external MCP tool servers │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ MCP Client (mcp/client.rs) │
│ JSON-RPC 2.0 over stdio to each server │
├─────────────────────────────────────────────────────────────────┤
│ Methods: │
│ - initialize() Handshake with server │
│ - list_tools() Get available tools │
│ - call_tool(name, args) Execute a tool │
└─────────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MCP Server 1 │ │ MCP Server 2 │ │ MCP Server 3 │
│ (playwright) │ │ (filesystem) │ │ (custom) │
│ │ │ │ │ │
│ stdin <-------> │ │ stdin <-------> │ │ stdin <-------> │
│ stdout │ │ stdout │ │ stdout │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Config (~/.claude/mcp.json or .claude/mcp.json):
┌─────────────────────────────────────────────────────────────────┐
│ { │
│ "servers": { │
│ "playwright": { │
│ "command": "npx", │
│ "args": ["@anthropic/mcp-playwright"], │
│ "env": {} │
│ } │
│ } │
│ } │
└─────────────────────────────────────────────────────────────────┘
Tool Naming: mcp__{server}__{tool}
Example: mcp__playwright__screenshot
Session & Memory System
┌─────────────────────────────────────────────────────────────────┐
│ Session (session.rs) │
├─────────────────────────────────────────────────────────────────┤
│ struct Session { │
│ id: String, // "session_abc123_fox" │
│ short_name: String, // "fox" (memorable) │
│ parent_id: Option<String>, │
│ messages: Vec<StoredMessage>, │
│ status: SessionStatus, // Active/Closed/Crashed/... │
│ is_canary: bool, // Self-dev testing │
│ working_dir: String, │
│ } │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Storage Layout │
├─────────────────────────────────────────────────────────────────┤
│ ~/.jcode/ │
│ ├── sessions/ │
│ │ ├── session_abc123_fox.json │
│ │ ├── session_def456_oak.json │
│ │ └── ... │
│ ├── memory/ │
│ │ ├── global.json # User-wide memories │
│ │ └── projects/ │
│ │ └── {hash}.json # Per-directory memories │
│ ├── build_number # Auto-increment patch version │
│ └── logs/ # Debug logs │
└─────────────────────────────────────────────────────────────────┘
Memory System (memory.rs):
┌─────────────────────────────────────────────────────────────────┐
│ struct MemoryEntry { │
│ id: String, │
│ category: Fact | Preference | Entity | Correction, │
│ content: String, │
│ tags: Vec<String>, │
│ access_count: u32, │
│ source: Option<String>, // Session that created it │
│ } │
└─────────────────────────────────────────────────────────────────┘
Compaction System
┌─────────────────────────────────────────────────────────────────┐
│ CompactionManager (compaction.rs) │
│ Background summarization when context approaches token limit │
└─────────────────────────────────────────────────────────────────┘
Token Budget: 100k tokens
Threshold: 80% (triggers compaction)
Keep Recent: 10 turns verbatim
Flow:
┌─────────────────────────────────────────────────────────────────┐
│ │
│ [Turn 1] [Turn 2] ... [Turn N-10] | [Turn N-9] ... [Turn N] │
│ <------ To be summarized -------> | <---- Keep verbatim ----> │
│ | │
│ v | │
│ ┌─────────────────────┐ | │
│ │ Background Task │ | │
│ │ (Summarize early │ | │
│ │ turns) │ | │
│ └──────────┬──────────┘ | │
│ v | │
│ ┌─────────────────────┐ | │
│ │ Summary │ | │
│ │ "Context: Working │ | │
│ │ on auth bug..." │ | │
│ └─────────────────────┘ | │
│ | │
└─────────────────────────────────────────────────────────────────┘
After Compaction:
┌─────────────────────────────────────────────────────────────────┐
│ [Summary] | [Turn N-9] [Turn N-8] ... [Turn N] │
│ | <----------- Recent turns (verbatim) ------------> │
└─────────────────────────────────────────────────────────────────┘
RAG Support: Full history kept in full_history for search
Event Bus
┌─────────────────────────────────────────────────────────────────┐
│ Bus (bus.rs) │
│ Global broadcast channel for internal events │
│ static INSTANCE: OnceLock<Bus> │
└─────────────────────────────────────────────────────────────────┘
│
│ broadcast::channel(256)
│
┌─────────────────────────┼─────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ ToolUpdated │ │ TodoUpdated │ │ FileTouch │
│ - session │ │ - session │ │ - session │
│ - tool_name │ │ - todos │ │ - path │
│ - status │ │ │ │ - op (r/w/edit) │
│ - title │ │ │ │ - summary │
└─────────────┘ └─────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ Subagent │ │ Background │ │ │
│ Status │ │ Task │ │ │
│ - session │ │ Completed │ │ │
│ - status │ │ - task_id │ │ │
│ text │ │ - output │ │ │
└─────────────┘ └─────────────┘ └─────────────────┘
Subscribers:
- TUI (for live status updates)
- Server (for swarm conflict detection)
- Tools (for coordination)
Self-Dev Mode
┌─────────────────────────────────────────────────────────────────┐
│ Self-Development Workflow │
│ Hot-reload loop for developing jcode itself │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ Stable Binary │
│ (promoted) │
└────────┬────────┘
│
┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Session A │ │ Session B │ │ Session C │
│ (stable) │ │ (stable) │ │ (canary) │
└───────────────┘ └───────────────┘ └───────┬───────┘
│
▼
┌───────────────────┐
│ selfdev tool: │
│ - reload │
│ - status │
│ - promote │
│ - rollback │
└───────────────────┘
Workflow:
1. Make code changes (edit/write tools)
2. cargo build --release
3. selfdev { action: "reload" } -> Restart with new binary
4. Test the changes
5. If crash -> Auto-rollback to stable, wake with crash context
6. If good -> selfdev { action: "promote" }
Files:
~/.jcode/
├── stable_binary # Path to known-good binary
├── canary_binary # Path to testing binary
└── crash_history.json # Recent crashes for debugging
Module Dependency Graph
main.rs
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
tui/ server.rs agent.rs
│ │ │
│ ┌──────┴──────┐ │
│ ▼ ▼ │
│ protocol.rs bus.rs │
│ │ │ │
└──────────────┼─────────────┼──────────────┘
│ │
▼ ▼
session.rs compaction.rs
│ │
┌──────────────┴─────────────┴──────────────┐
│ │ │
▼ ▼ ▼
provider/ tool/ mcp/
│ │ │
▼ ▼ ▼
auth/ memory.rs skill.rs
│
▼
config.rs <---- storage.rs <---- id.rs
Shared utilities:
- message.rs (Message, ContentBlock, ToolCall types)
- prompt.rs (System prompt construction)
- logging.rs (File + stderr logging)
- background.rs (Background task manager)
jcode supports MCP servers, allowing you to extend its capabilities with external tools.
Add MCP servers to .claude/mcp.json (project-local) or ~/.claude/mcp.json (global):
{
"servers": {
"playwright": {
"command": "npx",
"args": ["@anthropic/mcp-playwright"],
"env": {}
},
"filesystem": {
"command": "/path/to/mcp-filesystem",
"args": ["--root", "/home/user"],
"env": {}
}
}
}Servers are automatically connected on startup and their tools are available with the prefix mcp__servername__toolname.
The agent can manage MCP servers at runtime using the mcp tool:
# List connected servers and their tools
{"action": "list"}
# Connect to a new server
{"action": "connect", "server": "my-server", "command": "npx", "args": ["@some/mcp-server"]}
# Disconnect from a server
{"action": "disconnect", "server": "my-server"}
# Reload from config file
{"action": "reload"}
MCP servers communicate via JSON-RPC 2.0 over stdio. See the MCP specification for details on implementing your own servers.
J-Code uses the Claude Code CLI to talk to Claude. Credentials are stored at:
~/.claude/.credentials.json(Claude Code CLI)~/.local/share/opencode/auth.json(OpenCode, if installed)
OpenAI/Codex OAuth credentials are stored at:
~/.codex/auth.json
For provider/auth details, see OAUTH.md.
cargo test- Run all testscargo run --bin test_api- Claude Code CLI smoke testcargo run --bin jcode-harness- Tool harness (add--include-networkfor web tools)cargo run --release --bin tui_bench- TUI rendering benchmark (see Architecture > Rendering Benchmarks)scripts/agent_trace.sh- End-to-end agent smoke test (setJCODE_PROVIDER=openai|claude)
MIT