AI-native workspace for remote servers.
Connect to your servers over SSH, then work with terminals, files, ports, transfers, lightweight editing, and OxideSens AI in one local-first app.
Native Tauri app ยท Pure Rust SSH ยท BYOK OxideSens AI ยท No account required for core SSH workflows
Zero Electron. Zero OpenSSL. Zero Telemetry. Zero Subscription. BYOK-first. Pure Rust SSH.
*Watch OxideSens follow a user request and open a terminal inside OxideTerm.*
---
## What You Can Do
- Manage SSH terminals, SFTP, port forwards, in-terminal transfers, and local shells side by side
- Keep working through network hiccups with Grace Period reconnect
- Ask OxideSens AI to inspect live sessions and perform approved workspace actions through your own AI provider
---
## Why OxideTerm?
| If you care about... | OxideTerm gives you... |
|---|---|
| One remote node, many tools | Terminal, SFTP, port forwarding, trzsz, mini IDE, monitoring, and OxideSens AI stay attached to the same SSH workspace |
| Local-first SSH workflows | SSH, SFTP, forwarding, local shell, and config work without signup; cloud sync is opt-in via [official plugin](#official-plugins) |
| BYOK OxideSens AI instead of platform credits | OxideSens uses your OpenAI/Ollama/DeepSeek/OpenAI-compatible endpoint with MCP, RAG, and approved workspace actions |
| Reconnect stability | Grace Period probes the old connection for 30s before replacing it, so vim/htop/yazi can survive short network drops |
| Pure Rust, native app | Tauri 2.0 native app, russh 0.59 compiled against `ring`, no Electron, no OpenSSL/libssh2 dependency |
| Credential safety | Passwords and API keys stay in OS keychain, saved connection metadata is sealed locally, and `.oxide` files use ChaCha20-Poly1305 + Argon2id encryption |
## What It Is / Is Not
OxideTerm focuses on a **local-first AI workspace for remote servers**. It is built for users who want terminals, files, ports, transfers, lightweight editing, and OxideSens AI centered around their own machines and remote nodes.
It is not trying to be a hosted cloud agent platform or a benchmark-only terminal renderer. The product direction is narrower: make remote work feel like one local workspace, without requiring an OxideTerm account.
---
## Screenshots
SSH Terminal + OxideSens AI
SFTP File Manager
Built-in IDE (CodeMirror 6)
Smart Port Forwarding
---
## Download
Download the latest release from [GitHub Releases](https://github.com/AnalyseDeCircuit/oxideterm/releases/latest).
---
## Feature Overview
| Category | Features |
|---|---|
| **Terminal** | Local PTY (zsh/bash/fish/pwsh/WSL2), SSH remote, local serial terminals, split panes, broadcast input, session recording/playback (asciicast v2), WebGL rendering, 30+ themes + custom editor, command palette (`โK`), zen mode, **trzsz** in-band file transfer |
| **SSH & Auth** | Connection pooling & multiplexing, ProxyJump (unlimited hops) with topology graph, auto-reconnect with Grace Period, Agent Forwarding. Auth: password, SSH key (RSA/Ed25519/ECDSA), SSH Agent, certificates, keyboard-interactive 2FA, Known Hosts TOFU |
| **SFTP** | Dual-pane browser, drag-and-drop, smart preview (images/video/audio/code/PDF/hex/fonts), transfer queue with progress & ETA, bookmarks, archive extraction |
| **IDE Mode** | CodeMirror 6 with 24 languages, file tree + Git status, multi-tab, conflict resolution, integrated terminal. Optional remote agent for Linux; unsupported architectures can self-build and upload |
| **Port Forwarding** | Local (-L), Remote (-R), Dynamic SOCKS5 (-D), lock-free message-passing I/O, auto-restore on reconnect, death reporting, idle timeout |
| **AI (OxideSens)** | Target-first assistant for saved connections, live SSH sessions, terminal buffers, SFTP paths, settings, and knowledge base entries; can diagnose remote output, run approved commands, inspect files, and explain failures without an OxideTerm account |
| **Plugins** | Runtime ESM loading, 18 API namespaces, 24 UI Kit components, frozen API + Proxy ACL, circuit breaker, auto-disable on errors |
| **CLI** | `oxt` companion: JSON-RPC 2.0 over Unix Socket / Named Pipe, status/health/list/session inspect/forward/config/connect/focus/attach/SFTP/import/AI, human + JSON output |
| **Security** | .oxide encrypted export (ChaCha20-Poly1305 + Argon2id 256 MB), encrypted local config at rest, OS keychain, Touch ID (macOS), portable encrypted keystore, host key TOFU, `zeroize` memory clearing |
| **i18n** | 11 languages: EN, ็ฎไฝไธญๆ, ็น้ซไธญๆ, ๆฅๆฌ่ช, ํ๊ตญ์ด, FR, DE, ES, IT, PT-BR, VI |
---
## Under the Hood
OxideTerm keeps the product surface local-first, but the internals are built for SSH-heavy work. The full implementation notes are preserved below for readers who want the engineering details.
Architecture, SSH internals, reconnect, AI, forwarding, plugins, and more
### Architecture โ Dual-Plane Communication
OxideTerm separates terminal data from control commands into two independent planes:
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Frontend (React 19) โ
โ xterm.js 6 (WebGL) + 19 stores โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ Tauri IPC โ WebSocket (binary)
โ (JSON) โ per-session port
โโโโโโโโโโโโผโโโโโโโโโโโโโโโผโโโโโโโโโโโโ
โ Backend (Rust) โ
โ NodeRouter โ SshConnectionRegistry โ
โ Wire Protocol v1 โ
โ [Type:1][Length:4][Payload:n] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
- **Data plane (WebSocket)**: each SSH session gets its own WebSocket port. Terminal bytes flow as binary frames with a Type-Length-Payload header โ no JSON serialization, no Base64 encoding, zero overhead in the hot path.
- **Control plane (Tauri IPC)**: connection management, SFTP ops, forwarding, config โ structured JSON, but off the critical path.
- **Node-first addressing**: the frontend never touches `sessionId` or `connectionId`. Everything is addressed by `nodeId`, resolved atomically server-side by the `NodeRouter`. SSH reconnect changes the underlying `connectionId` โ but SFTP, IDE, and forwards are completely unaffected.
### ๐ฉ Pure Rust SSH โ russh 0.59
The entire SSH stack is **russh 0.59** compiled against the **`ring`** crypto backend:
- **Zero C/OpenSSL dependencies** โ the full crypto stack is Rust. No more "which OpenSSL version?" debugging.
- Full SSH2 protocol: key exchange, channels, SFTP subsystem, port forwarding
- ChaCha20-Poly1305 and AES-GCM cipher suites, Ed25519/RSA/ECDSA keys
- Custom **`AgentSigner`**: wraps system SSH Agent and satisfies russh's `Signer` trait, solving RPITIT `Send` bound issues by cloning `&AgentIdentity` to an owned value before crossing `.await`
```rust
pub struct AgentSigner { /* wraps system SSH Agent */ }
impl Signer for AgentSigner { /* challenge-response via Agent IPC */ }
```
- **Platform support**: Unix (`SSH_AUTH_SOCK`), Windows (`\\.\pipe\openssh-ssh-agent`)
- **Proxy chains**: each hop independently uses Agent auth
- **Reconnect**: `AuthMethod::Agent` replayed automatically
### ๐ Smart Reconnect with Grace Period
Most SSH clients kill everything on disconnect and start fresh. OxideTerm's reconnect orchestrator takes a fundamentally different approach:
1. **Detect** WebSocket heartbeat timeout (300s, tuned for macOS App Nap and JS timer throttling)
2. **Snapshot** full state: terminal panes, in-flight SFTP transfers, active port forwards, open IDE files
3. **Intelligent probing**: `visibilitychange` + `online` events trigger proactive SSH keepalive (~2s detection vs 15-30s passive timeout)
4. **Grace Period** (30s): probe the old SSH connection via keepalive โ if it recovers (e.g., WiFi AP switch), your TUI apps (vim, htop, yazi) survive completely untouched
5. If recovery fails โ new SSH connection โ auto-restore forwards โ resume SFTP transfers โ reopen IDE files
Pipeline: `queued โ snapshot โ grace-period โ ssh-connect โ await-terminal โ restore-forwards โ resume-transfers โ restore-ide โ verify โ done`
All logic runs through a dedicated `ReconnectOrchestratorStore` โ zero reconnect code scattered in hooks or components.
### ๐ก๏ธ SSH Connection Pool
Reference-counted `SshConnectionRegistry` backed by `DashMap` for lock-free concurrent access:
- **One connection, many consumers**: terminal, SFTP, port forwards, and IDE share a single physical SSH connection โ no redundant TCP handshakes
- **State machine per connection**: `connecting โ active โ idle โ link_down โ reconnecting`
- **Lifecycle management**: configurable idle timeout (5m / 15m / 30m / 1h / never), 15s keepalive interval, heartbeat failure detection
- **WsBridge heartbeat**: 30s interval, 5 min timeout โ tolerates macOS App Nap and browser JS throttling
- **Cascade propagation**: jump host failure โ all downstream nodes automatically marked `link_down` with status sync
- **Idle disconnect**: emits `connection_status_changed` to frontend (not just internal `node:state`), preventing UI desync
### ๐ค OxideSens AI
Privacy-first AI assistant with dual interaction modes:
- **Inline panel** (`โI`): quick terminal commands, output injected via bracketed paste
- **Sidebar chat**: persistent conversations with full history
- **Target-first workspace context**: sees saved connections, live SSH sessions, terminal buffers, SFTP paths, settings, and knowledge base entries as workspace targets
- **Approved actions**: can diagnose remote output, run approved commands, inspect files, and explain failures without requiring an OxideTerm account
- **MCP support**: connect external [Model Context Protocol](https://modelcontextprotocol.io) servers (stdio & SSE) for third-party tool integration
- **RAG Knowledge Base** (v0.20): import Markdown/TXT documents into scoped collections (global or per-connection). Hybrid search fuses BM25 keyword index + vector cosine similarity via Reciprocal Rank Fusion. Markdown-aware chunking preserves heading hierarchy. CJK bigram tokenizer for Chinese/Japanese/Korean.
- **Providers**: OpenAI, Ollama, DeepSeek, OneAPI, or any `/v1/chat/completions` endpoint
- **Security**: API keys stored in OS keychain; on macOS, key reads gated behind **Touch ID** via `LAContext` โ no entitlements or code-signing required, cached after first auth per session
### ๐ Port Forwarding โ Lock-Free I/O
Full local (-L), remote (-R), and dynamic SOCKS5 (-D) forwarding:
- **Message-passing architecture**: SSH Channel owned by a single `ssh_io` task โ no `Arc>`, eliminating mutex contention entirely
- **Death reporting**: forward tasks actively report exit reason (SSH disconnect, remote port close, timeout) for clear diagnostics
- **Auto-restore**: `Suspended` forwards automatically resume on reconnect without user intervention
- **Idle timeout**: `FORWARD_IDLE_TIMEOUT` (300s) prevents zombie connections from accumulating
### ๐ฆ trzsz โ In-Band File Transfer
Upload and download files directly through the SSH terminal session โ no SFTP connection required:
- **In-band protocol**: files travel as base64-encoded frames inside the existing terminal stream โ works transparently through ProxyJump chains and tmux without extra ports or agents
- **Bidirectional**: server runs `tsz ` to send files to the client; `trz` triggers client upload; drag-and-drop supported
- **Directory support**: recursive transfers via `trz -d` / `tsz -d`
- **Transfer limits**: configurable per-session limits for chunk size, file count, and total bytes
- **Native Tauri I/O**: file reads and writes use Tauri native file dialogs and Rust I/O โ no browser memory constraints
- **Live notifications**: toast notifications for start, completion, cancellation, and errors โ including a hint when trzsz is detected but the feature is disabled
- Enable in **Settings โ Terminal โ In-Band Transfer**
### ๐ Runtime Plugin System
Dynamic ESM loading with a security-hardened, frozen API surface:
- **PluginContext API**: 8 namespaces โ terminal, ui, commands, settings, lifecycle, events, storage, system
- **24 UI Kit components**: pre-built React components (buttons, inputs, dialogs, tablesโฆ) injected into plugin sandboxes via `window.__OXIDE__`
- **Security membrane**: `Object.freeze` on all context objects, Proxy-based ACL, IPC whitelist, circuit breaker with auto-disable after repeated errors
- **Shared modules**: React, ReactDOM, zustand, lucide-react exposed for plugin use without bundling duplicates
### โก Adaptive Rendering
Three-tier render scheduler that replaces fixed `requestAnimationFrame` batching:
| Tier | Trigger | Rate | Benefit |
|---|---|---|---|
| **Boost** | Frame data โฅ 4 KB | 120 Hz+ (ProMotion native) | Eliminates scroll lag on `cat largefile.log` |
| **Normal** | Standard typing | 60 Hz (RAF) | Smooth baseline |
| **Idle** | 3s no I/O / tab hidden | 1โ15 Hz (exponential backoff) | Near-zero GPU load, battery savings |
Transitions are fully automatic โ driven by data volume, user input, and Page Visibility API. Background tabs continue flushing data via idle timer without waking RAF.
### ๐ .oxide Encrypted Export
Portable, tamper-proof connection backup:
- **ChaCha20-Poly1305 AEAD** authenticated encryption
- **Argon2id KDF**: 256 MB memory cost, 4 iterations โ GPU brute-force resistant
- **SHA-256** integrity checksum
- **Optional key embedding**: private keys base64-encoded into the encrypted payload
- **Pre-flight analysis**: auth type breakdown, missing key detection before export
### ๐ก ProxyJump โ Topology-Aware Multi-Hop
- Unlimited chain depth: `Client โ Jump A โ Jump B โ โฆ โ Target`
- Auto-parse `~/.ssh/config`, build topology graph, Dijkstra pathfinding for optimal route
- Jump nodes reusable as independent sessions
- Cascade failure propagation: jump host down โ all downstream nodes auto-marked `link_down`
### โ๏ธ Local Terminal โ Thread-Safe PTY
Cross-platform local shell via `portable-pty 0.8`, feature-gated behind `local-terminal`:
- `MasterPty` wrapped in `std::sync::Mutex` โ dedicated I/O threads keep blocking PTY reads off the Tokio event loop
- Shell auto-detection: `zsh`, `bash`, `fish`, `pwsh`, Git Bash, WSL2
- `cargo build --no-default-features` strips PTY for mobile/lightweight builds
### ๐ช Windows Optimization
- **Native ConPTY**: directly invokes Windows Pseudo Console API โ full TrueColor and ANSI support, no legacy WinPTY
- **Shell scanner**: auto-detects PowerShell 7, Git Bash, WSL2, CMD via Registry and PATH
### And More
- **IDE Mode**: CodeMirror 6 over SFTP, 24 languages, file tree with Git status, multi-tab, conflict resolution โ optional remote agent (~1 MB) for enhanced features on Linux
- **Resource profiler**: live CPU/memory/network via persistent SSH channel reading `/proc/stat`, delta-based calculation, auto-degrades to RTT-only on non-Linux
- **Custom theme engine**: 31 built-in themes, visual editor with live preview, 20 xterm.js fields + 24 UI color variables, auto-derive UI colors from terminal palette
- **Session recording**: asciicast v2 format, full record and playback
- **Broadcast input**: type once, send to all split panes โ batch server operations
- **Background gallery**: per-tab background images, 16 tab types, opacity/blur/fit control
- **CLI companion** (`oxt`): ~1 MB binary, JSON-RPC 2.0 over Unix Socket / Named Pipe, status/health/list/session inspect/forward/config/connect/focus/attach/SFTP/import/AI with human or `--json` output
- **WSL Graphics** โ ๏ธ experimental: built-in VNC viewer โ 9 desktop environments + single-app mode, WSLg detection, Xtigervnc + noVNC
### Official Plugins
| Plugin | Description | Repository |
|---|---|---|
| **Cloud Sync** | Encrypted self-hosted sync โ upload and import `.oxide` snapshots via WebDAV, HTTP JSON, Dropbox, Git, or S3 | [oxideterm.cloud-sync](https://github.com/AnalyseDeCircuit/oxideterm.cloud-sync) |
| **Telnet Client** | Native Telnet client for routers, switches, and legacy devices โ no external binary needed | [oxideterm.telnet](https://github.com/AnalyseDeCircuit/oxideterm.telnet) |
๐ธ 11 languages in action
English
็ฎไฝไธญๆ
็น้ซไธญๆ
ๆฅๆฌ่ช
ํ๊ตญ์ด
Franรงais
Deutsch
Espaรฑol
Italiano
Portuguรชs
Tiแบฟng Viแปt
---
## Runtime Requirements
OxideTerm uses the native WebView runtime provided by the operating system. Most users already have it installed; install these manually only if the app fails to launch or your environment is air-gapped.
| Platform | Runtime Dependency |
|---|---|
| **Windows** | [WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) โ pre-installed on Windows 10 (1803+) and Windows 11. For **air-gapped / intranet** environments, use the [Evergreen Standalone Installer](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download) (offline, ~170 MB) or deploy the **Fixed Version** runtime via group policy. |
| **macOS** | None (uses native WebKit) |
| **Linux** | `libwebkit2gtk-4.1` (usually pre-installed on modern desktops) |
---
## Portable Mode
OxideTerm supports a fully self-contained portable mode โ all data (connections, secrets, settings) is stored beside the application binary, making it suitable for USB drives or air-gapped environments.
### Activation
**Option A โ Marker file** (simplest): create an empty file named `portable` (no extension) next to the app.
| Platform | Where to place the `portable` file |
|---|---|
| **macOS** | Next to `OxideTerm.app` (its sibling directory) |
| **Windows** | Next to `OxideTerm.exe` |
| **Linux (AppImage)** | Next to the `.AppImage` file |
```
/my-usb/
โโโ OxideTerm.app (or .exe / .AppImage)
โโโ portable โ empty file you create
โโโ data/ โ created automatically on first launch
```
**Option B โ `portable.json`** (custom data directory): place a `portable.json` in the same location:
```json
{
"enabled": true,
"dataDir": "my-data"
}
```
- `enabled` defaults to `true` if omitted
- `dataDir` must be a **relative path** (no `..`); defaults to `data` if omitted
### How It Works
1. **First launch** โ a bootstrap screen prompts you to create a portable password. This password encrypts a local keystore (ChaCha20-Poly1305 + Argon2id) that protects all saved secrets.
2. **Subsequent launches** โ enter the password to unlock. On macOS with Touch ID, you can optionally bind biometric unlock in **Settings โ General โ Portable Runtime**.
3. **Instance lock** โ only one OxideTerm instance can use a portable data directory at a time (`data/.portable.lock`).
4. **Management** โ change the portable password or toggle biometric unlock in **Settings โ General โ Portable Runtime**.
5. **Portability** โ copy the entire folder (app + `portable` marker + `data/`) to another machine. The password travels with the keystore.
> [!TIP]
> Automatic updates are disabled in portable mode. To update, replace the application binary while keeping the `data/` directory.
---
## Quick Start
### Prerequisites
- **Rust** 1.85+
- **Node.js** 18+ (pnpm recommended)
- **Platform tools**:
- macOS: Xcode Command Line Tools
- Windows: Visual Studio C++ Build Tools
- Linux: `build-essential`, `libwebkit2gtk-4.1-dev`, `libssl-dev`
### Development
```bash
git clone https://github.com/AnalyseDeCircuit/oxideterm.git
cd oxideterm && pnpm install
# Build CLI companion (required for CLI features)
pnpm cli:build
# Full app (frontend + Rust backend with hot reload)
pnpm run tauri dev
# Frontend only (Vite on port 1420)
pnpm dev
# Production build
pnpm run tauri build
```
---
## Tech Stack
| Layer | Technology | Details |
|---|---|---|
| **Framework** | Tauri 2.0 | Native binary, 25โ40 MB |
| **Runtime** | Tokio + DashMap 6 | Full async, lock-free concurrent maps |
| **SSH** | russh 0.59 (`ring`) | Pure Rust, zero C deps, SSH Agent |
| **Local PTY** | portable-pty 0.8 | Feature-gated, ConPTY on Windows |
| **Frontend** | React 19.1 + TypeScript 5.8 | Vite 7, Tailwind CSS 4 |
| **State** | Zustand 5 | 19 specialized stores |
| **Terminal** | xterm.js 6 + WebGL | GPU-accelerated, 60fps+ |
| **Editor** | CodeMirror 6 | 24 language modes |
| **Encryption** | ChaCha20-Poly1305 + Argon2id | AEAD + memory-hard KDF (256 MB) |
| **Storage** | redb 2.1 | Embedded KV store |
| **i18n** | i18next 25 | 11 languages ร 22 namespaces |
| **Plugins** | ESM Runtime | Frozen PluginContext + 24 UI Kit |
| **CLI** | JSON-RPC 2.0 | Unix Socket / Named Pipe |
---
## Project Scale
Measured with `tokei`, excluding dependencies and build artifacts.
| Metric | Current Size |
|---|---:|
| Total code | 286K+ |
| TypeScript / TSX | 130K+ |
| Rust | 100K+ |
| Frontend test code | 24K+ |
| Frontend test files | 128 |
| Source files (`src` + `src-tauri/src`) | 664 |
---
## Security
| Concern | Implementation |
|---|---|
| **Passwords** | OS keychain (macOS Keychain / Windows Credential Manager / libsecret) |
| **Portable Keystore** | ChaCha20-Poly1305 encrypted vault beside the app, optional biometric binding via OS keychain |
| **AI API Keys** | OS keychain + Touch ID biometric gate on macOS |
| **Export** | .oxide: ChaCha20-Poly1305 + Argon2id (256 MB memory, 4 iterations) |
| **Memory** | Rust memory safety + `zeroize` for sensitive data clearing |
| **Host keys** | TOFU with `~/.ssh/known_hosts`, rejects changes (MITM prevention) |
| **Plugins** | Object.freeze + Proxy ACL, circuit breaker, IPC whitelist |
| **WebSocket** | Single-use tokens with time limits |
---
## Roadmap
- [x] SSH Agent forwarding
- [x] Full ProxyCommand support
- [ ] Audit logging
- [ ] Agent enhancements
- [ ] Session search & quick-switch
- [x] Rust-native migration via GPUI (Zed's GPU-accelerated framework) โ [in progress]
---
## Support and Maintenance
Reproducible bug reports and regressions are prioritized. Feature requests are reviewed based on scope, safety, and alignment with OxideTerm's remote-server workspace direction.
If OxideTerm helps your workflow, a GitHub star, issue reproduction, translation fix, plugin, or pull request all make the project easier to keep moving.
---
## License
**GPL-3.0** โ this software is free software licensed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html).
You are free to use, modify, and distribute this software under the terms of the GPL-3.0. Any derivative work must also be distributed under the same license.
OxideTerm changed from **PolyForm Noncommercial 1.0.0** to **GPL-3.0** starting with v1.0.0. We made this switch deliberately: no "open source" cosplay with noncommercial traps or no-competition riders, just clear copyleft freedom for users, forks, redistributors, and commercial operators.
Public code is not automatically open source. If a project advertises a familiar license while adding riders like "no redistribution", "no repackaging", "no competing products", or "no unauthorized distribution platforms", that is source-available branding, not the freedom users expect from open source. OxideTerm does not add no-compete or anti-redistribution riders: the GPL-3.0 terms are the terms.
Full text: [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html)
---
## Acknowledgments
[russh](https://github.com/warp-tech/russh) ยท [portable-pty](https://github.com/wez/wezterm/tree/main/pty) ยท [Tauri](https://tauri.app/) ยท [xterm.js](https://xtermjs.org/) ยท [CodeMirror](https://codemirror.net/) ยท [Radix UI](https://www.radix-ui.com/)
---