Architecture of Terax AI: Inside the Two-Process Rust and React Model
Terax AI implements a strict two-process architecture where a privileged Rust backend manages all OS-level operations while a sandboxed React webview frontend communicates exclusively through Tauri’s IPC command layer, enforcing security boundaries and efficient resource pooling.
Terax AI, an open-source AI-augmented terminal application developed by crynta, separates system privileges from user interface concerns through a Tauri-based design. The architecture of Terax AI relies on a Rust core that owns PTY sessions, filesystem access, Git operations, and AI tool execution, while a Chromium-embedded React frontend renders the UI and delegates every privileged action via a tightly controlled invoke mechanism. This architectural split ensures that AI-generated commands and web content never directly interact with the host operating system.
Two-Process Model and IPC Architecture
The foundation of Terax AI’s design is a clean separation between the Rust backend and the React frontend, connected through Tauri’s inter-process communication (IPC) bridge.
Rust Backend and Command Registry
The backend resides in src-tauri/ and contains all modules that interact with the operating system. According to the crynta/terax-ai source code, src-tauri/src/lib.rs registers every callable function using tauri::generate_handler![...], exposing specific commands to the webview. Each subsystem—PTY, filesystem, Git, shell, and network—lives in its own module under src-tauri/src/modules/, exposing async functions annotated with #[tauri::command].
Key commands registered in the handler include:
- PTY operations:
pty_open,pty_write,pty_resize,pty_close,pty_has_foreground_process - Filesystem:
fs_read_file,fs_write_file,fs_stat,fs_search - Git:
git_status,git_diff,git_commit,git_push - Shell:
shell_run_command,shell_session_*,shell_bg_* - Network:
ai_http_request,ai_http_stream(with SSRF protection)
React Frontend and IPC Boundaries
The frontend in src/ is a TypeScript React application that never directly accesses the filesystem or spawns processes. Instead, it invokes backend commands through window.__TAURI__.invoke. This creates a strict capability boundary where the UI can only perform actions explicitly whitelisted in the Rust command registry.
Security Architecture
All inbound data—including terminal escape sequences, file contents, and AI-generated tool arguments—is parsed and validated inside the Rust backend before any privileged operation executes.
Core Security Mechanisms
The security model implements multiple defensive layers:
- Deny-list validation: Unsafe terminal escape sequences are filtered through
src-tauri/src/security.tsbefore reaching the PTY. - Workspace authorization: A registry restricts filesystem and shell access to directories explicitly authorized by the user.
- SSRF guarding: The
ai_http_requestcommand includes server-side request forgery protections to prevent the AI from accessing internal network resources. - Approval workflows: Mutating tools such as
write_fileorbash_backgroundreturn payloads that trigger UI approval cards; the backend executes these commands only after explicit user confirmation.
Security invariants are enforced within command implementations and verified via unit tests under src-tauri/tests/.
Terminal Renderer Pool Architecture
To support multiple terminal tabs without unbounded memory growth, Terax AI implements a bounded renderer pool rather than creating separate Xterm.js and WebGL instances for every tab.
Pool Management and Lifecycle
As implemented in src/modules/terminal/lib/rendererPool.ts, the system maintains a maximum of POOL_MAX_SIZE = 5 active renderer slots. Each slot owns a terminal instance, FitAddon, SearchAddon, SerializeAddon, and an optional WebGL addon. When a tab becomes visible, it acquires a slot via acquire(); when hidden, release() parks the slot without destroying it.
For tabs without an active renderer, the DormantRing buffer (defined in src/modules/terminal/lib/dormantRing.ts) preserves PTY output bytes without maintaining a live terminal instance. The architecture enforces a never-serialize-mid-command invariant: busy leaves are never snapshot-serialized, ensuring eviction occurs only for idle tabs.
AI Subsystem Architecture
The AI engine is provider-agnostic and integrates with any OpenAI-compatible endpoint through the Vercel AI SDK v6.
Agent Streaming and Tool Execution
The entry point runAgentStream in src/modules/ai/lib/agent.ts handles chat sessions using the SDK’s streamText function. Provider configurations mapping model IDs to endpoints, context limits, and cost metadata reside in src/modules/ai/config.ts, supporting OpenAI, Anthropic, Google, Groq, Ollama, and LM Studio.
Tool definitions in src/modules/ai/tools/tools.ts include filesystem operations, search, shell commands, sub-agents, and managed agents. Tools marked with needsApproval: true trigger the approval workflow before execution. Session persistence uses tauri-plugin-store to save chat history to terax-ai-sessions.json via src/modules/ai/lib/sessions.ts.
The React layer provides the AI composer interface through AiComposerProvider in src/modules/ai/lib/composer.tsx, managing input state, attachments, and voice handling while delegating actual tool execution to the Rust backend.
Frontend Integration and React Glue
The frontend bootstrap begins at src/main.tsx, which creates the React root, registers global shortcuts, and mounts the main App component. Custom hooks such as useZoom (src/lib/useZoom.ts) provide webview zoom controls, while usePresence tracks window focus states.
The App.tsx component establishes a live context bridge by calling setLive({ getCwd, getTerminalContext, ... }), enabling AI tools to query the current working directory and recent terminal output on demand without direct filesystem access.
Code Examples: Interacting with the Terax AI Architecture
Opening a PTY Session from React
import { invoke } from '@tauri-apps/api/tauri';
async function startShell() {
const ptyId = await invoke<string>('pty_open', {
cwd: '/home/user',
shell: 'bash',
});
console.log('PTY opened with id', ptyId);
}
The pty_open command is defined in src-tauri/src/modules/pty/mod.rs and registers the pseudoterminal with the Rust backend.
Reading Files Through the Security Layer
import { invoke } from '@tauri-apps/api/tauri';
async function readFile(path: string) {
const content = await invoke<string>('fs_read_file', { path });
return content;
}
This invocation passes through the workspace authorization and deny-list validation before fs_read_file executes in the Rust module.
Streaming AI Responses
import { runAgentStream } from '@/modules/ai/lib/agent';
async function askAI(prompt: string) {
const stream = runAgentStream({
modelId: 'gpt-4o-mini',
messages: [{ role: 'user', content: prompt }],
});
for await (const chunk of stream) {
console.log(chunk);
}
}
The runAgentStream function constructs the language model from provider configuration, streams responses via the Vercel AI SDK, and automatically injects the available tool set.
Managing Terminal Renderer Slots
import { acquireSlot, releaseSlot } from '@/modules/terminal/lib/rendererPool';
// When a tab becomes visible
const slot = acquireSlot(tabId);
// Attach slot.terminal to the DOM
// When the tab is hidden
releaseSlot(tabId);
The pool guarantees that at most five slots exist concurrently, parking idle slots to preserve memory.
Summary
- Two-process separation: The Rust backend in
src-tauri/owns all privileged operations, while the React frontend insrc/remains sandboxed and communicates via Tauri IPC commands registered insrc-tauri/src/lib.rs. - Strict security boundary: Validation occurs in Rust through deny-lists, workspace authorization, SSRF guards in
ai_http_request, and mandatory approval flows for mutating tools. - Bounded resource management: The terminal renderer pool caps active Xterm.js instances at five, using
DormantRingbuffers to preserve output for inactive tabs without memory exhaustion. - Provider-agnostic AI: The subsystem in
src/modules/ai/uses Vercel AI SDK v6 to stream responses from multiple LLM providers, with tool execution subject to backend security checks. - Clean frontend integration: React hooks and context providers bridge UI state to backend capabilities without violating the security perimeter.
Frequently Asked Questions
How does Terax AI prevent AI-generated commands from compromising the system?
Terax AI enforces a strict approval workflow where mutating tools—such as file writes or background shell commands—return payloads that the UI renders as approval cards. According to the crynta/terax-ai source code, the Rust backend executes these commands only after explicit user confirmation, and all AI network requests pass through SSRF guards in ai_http_request to prevent internal network access.
Why does Terax AI limit terminal renderers to five instances?
The renderer pool in src/modules/terminal/lib/rendererPool.ts caps active instances at POOL_MAX_SIZE = 5 to prevent memory exhaustion when users open many tabs. The architecture uses a DormantRing buffer to preserve PTY output for tabs without active renderers, ensuring smooth tab switching while maintaining bounded memory consumption.
Can Terax AI connect to local LLM providers like Ollama or LM Studio?
Yes, the AI subsystem is provider-agnostic. The configuration file src/modules/ai/config.ts defines providers including OpenAI, Anthropic, Google, Groq, Ollama, and LM Studio. Users can stream responses from local endpoints using the same runAgentStream interface used for cloud providers.
What happens when the React frontend needs to access the filesystem?
The frontend never accesses the filesystem directly. Instead, React components invoke commands like fs_read_file or fs_write_file through window.__TAURI__.invoke. These calls transit to the Rust backend, which validates the request against workspace authorizations and deny-lists before performing the operation, ensuring the sandboxed webview cannot bypass security controls.
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 →