From cb4b8ec1365788d246dc6fd510e2367b20f68868 Mon Sep 17 00:00:00 2001 From: Vantz Stockwell Date: Tue, 17 Mar 2026 06:35:21 -0400 Subject: [PATCH] docs: comprehensive README with architecture, build, and plugin guide Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..03fa0e3 --- /dev/null +++ b/README.md @@ -0,0 +1,242 @@ +

+ Wraith +

+ +

Wraith

+ +

+ Native desktop SSH + RDP + SFTP client — a MobaXTerm replacement built with Go and Vue. +

+ +

+ + Go + Wails v3 + Vue 3 + License +

+ +--- + +## Features + +- **Multi-tabbed SSH terminal** with xterm.js + WebGL rendering +- **SFTP sidebar** on every SSH session (MobaXTerm's killer feature) -- same SSH connection, separate channel +- **RDP** via FreeRDP3 dynamic linking (purego, no CGO) +- **Encrypted vault** -- master password derived with Argon2id, secrets sealed with AES-256-GCM +- **Connection manager** with hierarchical groups, tags, color labels, and full-text search +- **7 built-in terminal themes** -- Dracula, Nord, Monokai, One Dark, Solarized Dark, Gruvbox Dark, MobaXTerm Classic +- **Tab detach / reattach** -- sessions live in the Go backend; tabs can be torn off into separate windows and reattached without dropping the connection +- **MobaXTerm import** -- plugin interface for `.mobaconf` and other formats +- **Command palette** (Ctrl+K) for quick connection search and actions +- **Single binary** -- ships as `wraith.exe` + `freerdp3.dll`, no Docker, no database server + +## Tech Stack + +### Backend (Go) + +| Component | Technology | Purpose | +|-----------|-----------|---------| +| Framework | Wails v3 | Desktop shell, multi-window, type-safe Go-to-JS bindings | +| SSH | `golang.org/x/crypto/ssh` | SSH client, PTY, key/password auth | +| SFTP | `github.com/pkg/sftp` | Remote filesystem over SSH channel | +| RDP | FreeRDP3 via `purego` | RDP protocol, bitmap rendering | +| Database | SQLite via `modernc.org/sqlite` (pure Go) | Connections, credentials, settings, themes | +| Encryption | AES-256-GCM + Argon2id | Vault encryption at rest | + +### Frontend (Vue 3 in WebView2) + +| Component | Technology | Purpose | +|-----------|-----------|---------| +| Framework | Vue 3 (Composition API) | UI framework | +| Terminal | xterm.js 5.x + WebGL addon | SSH terminal emulator | +| CSS | Tailwind CSS 4 | Utility-first styling | +| Components | Naive UI | Tree, tabs, modals, dialogs | +| State | Pinia | Reactive stores for sessions, connections, app state | +| Build | Vite 6 | Frontend build tooling | + +## Prerequisites + +| Tool | Version | Install | +|------|---------|---------| +| Go | 1.22+ | [go.dev/dl](https://go.dev/dl/) | +| Node.js | 20+ | [nodejs.org](https://nodejs.org/) | +| Wails CLI | v3 | `go install github.com/wailsapp/wails/v3/cmd/wails3@latest` | + +## Quick Start + +```bash +# Clone +git clone https://github.com/vstockwell/wraith.git +cd wraith + +# Install frontend dependencies +cd frontend && npm install && cd .. + +# Run in dev mode (hot-reload frontend + Go backend) +wails3 dev +``` + +The app opens a 1400x900 window. On first launch you will be prompted to create a master password for the vault. + +## Building + +```bash +# Production build for Windows +wails3 build + +# Output: build/bin/wraith.exe +``` + +The build embeds the compiled frontend (`frontend/dist`) into the Go binary via `//go:embed`. Ship `wraith.exe` alongside `freerdp3.dll` for RDP support. + +## Project Structure + +``` +wraith/ + main.go # Entry point -- Wails app setup, service registration + go.mod # Go module (github.com/vstockwell/wraith) + internal/ + app/ + app.go # WraithApp -- wires all services, vault create/unlock + db/ + sqlite.go # SQLite open with WAL mode, busy timeout, FK enforcement + migrations.go # Embedded SQL migration runner + migrations/ + 001_initial.sql # Schema: groups, connections, credentials, ssh_keys, + # themes, host_keys, connection_history, settings + vault/ + service.go # Argon2id key derivation + AES-256-GCM encrypt/decrypt + connections/ + service.go # Connection and Group CRUD (hierarchical tree) + search.go # Full-text search + tag filtering via json_each() + settings/ + service.go # Key-value settings store (vault salt, preferences) + theme/ + builtins.go # 7 built-in theme definitions + service.go # Theme CRUD + idempotent seeding + session/ + session.go # SessionInfo struct + state machine (connecting/connected/detached) + manager.go # Concurrent session manager -- create, detach, reattach, 32-session cap + plugin/ + interfaces.go # ProtocolHandler + Importer + Session interfaces + registry.go # Plugin registry -- register/lookup protocol handlers and importers + frontend/ + package.json # Vue 3, Pinia, Naive UI, Tailwind CSS, Vite + vite.config.ts # Vite + Vue + Tailwind plugin config + src/ + main.ts # App bootstrap -- createApp, Pinia, mount + App.vue # Root component + layouts/ + MainLayout.vue # Sidebar + tab bar + session area + status bar + UnlockLayout.vue # Master password entry screen + components/ + sidebar/ + ConnectionTree.vue # Hierarchical connection/group tree + SidebarToggle.vue # Collapse/expand sidebar + session/ + TabBar.vue # Draggable session tabs + SessionContainer.vue # Active session viewport + common/ + StatusBar.vue # Bottom status bar + stores/ + app.store.ts # Global app state (sidebar, vault status) + connection.store.ts # Connection + group state + session.store.ts # Active sessions state + images/ + wraith-logo.png # Application logo +``` + +## Architecture + +``` +Go Backend Wails v3 Bindings Vue 3 Frontend +(services + business logic) (type-safe Go <-> JS) (WebView2) + | + WraithApp ─────────────────────────┼──────────────> Pinia Stores + |-- VaultService | |-- app.store + |-- ConnectionService | |-- connection.store + |-- ThemeService | |-- session.store + |-- SettingsService | | + |-- SessionManager | Vue Components + |-- PluginRegistry | |-- MainLayout + | |-- ConnectionTree + SQLite (WAL mode) | |-- TabBar + wraith.db | |-- SessionContainer + %APPDATA%\Wraith\ | |-- StatusBar +``` + +**How it fits together:** + +1. `main.go` creates a `WraithApp` and registers Go services as Wails bindings. +2. Wails generates type-safe JavaScript bindings so the Vue frontend can call Go methods directly. +3. The Vue frontend uses Pinia stores to manage reactive state, calling into Go services for all data operations. +4. All secrets (passwords, SSH keys) are encrypted with AES-256-GCM before being written to SQLite. The encryption key is derived from the master password using Argon2id and is never persisted. +5. Sessions are managed by the Go `SessionManager` -- they are decoupled from windows, enabling tab detach/reattach without dropping connections. + +**Data storage:** SQLite with WAL mode at `%APPDATA%\Wraith\wraith.db` (Windows) or `~/.local/share/wraith/wraith.db` (Linux/macOS dev). Foreign keys enforced, 5-second busy timeout. + +## Plugin Development + +Wraith uses a plugin registry with two interfaces: `ProtocolHandler` for new connection protocols and `Importer` for loading connections from external tools. + +### Implementing a ProtocolHandler + +```go +package myplugin + +import "github.com/vstockwell/wraith/internal/plugin" + +type MyProtocol struct{} + +func (p *MyProtocol) Name() string { return "myproto" } + +func (p *MyProtocol) Connect(config map[string]interface{}) (plugin.Session, error) { + // Establish connection, return a Session +} + +func (p *MyProtocol) Disconnect(sessionID string) error { + // Clean up resources +} +``` + +### Implementing an Importer + +```go +package myplugin + +import "github.com/vstockwell/wraith/internal/plugin" + +type MyImporter struct{} + +func (i *MyImporter) Name() string { return "myformat" } +func (i *MyImporter) FileExtensions() []string { return []string{".myconf"} } +func (i *MyImporter) Parse(data []byte) (*plugin.ImportResult, error) { + // Parse file bytes into ImportResult (groups, connections, host keys, theme) +} +``` + +### Registering Plugins + +Register handlers and importers with the plugin registry during app initialization: + +```go +app.Plugins.RegisterProtocol(&myplugin.MyProtocol{}) +app.Plugins.RegisterImporter(&myplugin.MyImporter{}) +``` + +The `ImportResult` struct supports groups, connections, host keys, and an optional theme -- everything needed to migrate from another tool in a single import. + +## Contributing + +1. Fork the repository +2. Create a feature branch (`git checkout -b feat/my-feature`) +3. Make your changes +4. Run tests: `go test ./...` +5. Run frontend checks: `cd frontend && npm run build` +6. Commit and push your branch +7. Open a Pull Request + +## License + +[MIT](LICENSE) -- Copyright (c) 2026 Vantz Stockwell