Overview of the NoSuckShell desktop app: how the UI, Rust backend, and on-disk data fit together. For product history and early design notes, see plans/2026-03-17-ssh-manager-design.md. For backup cryptography, see backup-security.md.
| Layer | Technology |
|---|---|
| Desktop shell | Tauri 2 (Linux, macOS, Windows) |
| UI | React 19 + Vite + TypeScript (system webview) |
| Backend | Rust crate in apps/desktop/src-tauri |
| IPC | Tauri commands (invoke) and events (emit / listen) |
| Terminal | xterm.js in TerminalPane.tsx |
| SSH in terminal | System ssh in a PTY (session.rs) |
| SFTP (file pane) | ssh2 over direct TCP (sftp.rs) |
flowchart LR
subgraph UI["Webview (React)"]
A[App / components]
B[tauri-api.ts]
end
subgraph IPC["Tauri IPC"]
C[invoke commands]
D[events e.g. session-output]
end
subgraph Rust["Rust backend"]
E[main.rs commands]
F[session / ssh_config / host_metadata / secure_store / ...]
end
subgraph OS["OS and user data"]
G["ssh PTY"]
H["SSH dir config + metadata + store files"]
end
A --> B
B --> C
C --> E
E --> F
F --> G
F --> H
F --> D
D --> A
| Area | Location | Notes |
|---|---|---|
| Root state and wiring | App.tsx |
Hosts, sessions, workspaces, settings modal, metadata store sync |
| Reusable UI | components/ |
Sidebar, panes, modals, settings tabs |
| Domain logic | features/ |
DnD, split layout, host form helpers, view filters, backup-related types |
| IPC facade | tauri-api.ts |
All invoke calls in one place |
| Shared wire types | types.ts |
DTOs aligned with Serde on the Rust side |
| In-app help | HelpPanel.tsx |
Chaptered help (Settings → Help) |
Refactoring notes for App.tsx: refactoring-app-roadmap.md.
Command registration: main.rs (tauri::generate_handler![...]).
| Module | Responsibility |
|---|---|
session |
Allocate PTY, spawn ssh or local shell, pipe stdout/stderr to session-output events; send_input, resize, kill |
ssh_config |
Parse/render Host blocks in the effective SSH config file |
ssh_home |
Resolve SSH directory (default, override from settings) |
host_metadata |
nosuckshell.metadata.json: favorites, tags, lastUsedAt, trustHostDefault, optional strictHostKeyPolicy |
secure_store |
Encrypted entity store JSON + resolve_host_config_for_session (merge config host + HostBinding + linked UserObject) |
store_models |
Serde models for users, keys, groups, tags, bindings |
quick_ssh |
Normalize quick-connect payload into HostConfig + optional strict-host-key override |
backup / key_crypto |
Encrypted backup envelope |
layout_profiles / view_profiles |
Persisted JSON for layouts and host-list view profiles |
sftp |
Remote/local file ops over libssh2 (no ProxyJump/ProxyCommand in this path today) |
plugins |
Built-in plugin registry (plugins/mod.rs): NssPlugin trait, capabilities, enrich_resolved_host after store merge |
proxmux_ws_proxy |
Local ws://127.0.0.1 bridge from the webview to Proxmox wss:// console endpoints (proxmux_ws_proxy.rs); uses native TLS with the same relaxed verification rules as PROXMUX HTTP when Allow insecure TLS is on or a trusted PEM is stored |
license |
Offline Ed25519 license verify/activate (license.rs); entitlement checks for gated plugins |
Built-in plugins (Rust modules registered at startup) can implement NssPlugin: manifest (id, version, display name, capabilities), optional required_entitlement, enrich_host_config, and invoke for RPC-style calls from the UI.
- Host hook: After
resolve_host_config_with_store,resolve_host_config_for_sessioncallsplugins::enrich_resolved_hostso Vault/Bitwarden-style providers can adjustHostConfigbefore SSH/SFTP (see demo plugin underplugins/demo.rs). - Settings UI: Settings → Plugins (
AppSettingsPluginsTab.tsx): plugin store, list plugins, enable/disable, paste license token. - NSS-Commander (built-in plugin
dev.nosuckshell.plugin.nss-commander):plugins/file_workspace.rsgates remote/local file browser UI andsessionFileViewsinApp.tsx/SplitWorkspace.tsx/context-actions.ts. - License issuance: Separate HTTP service
services/license-server(Ko-fi webhook + admin issue endpoint). Product/legal notes: licensing.md. Ko-fi is only the payment/webhook source; signing stays on your server.
Future Phase 2 (not implemented): load third-party code via WASM or signed bundles—same hooks, stricter sandboxing.
Planned plugin-shaped features (GitHub settings sync, Bitwarden, HashiCorp Vault, command palette, public cloud) are listed with proposed IDs in roadmap.md.
Built-in plugin dev.nosuckshell.plugin.proxmux (plugins/proxmux.rs and UI under ProxmuxSidebarPanel.tsx, AppSettingsProxmuxTab.tsx, panes ProxmoxQemuVncPane.tsx / ProxmoxLxcTermPane.tsx):
- Settings → Connection → PROXMUX: cluster URLs, credentials, Allow insecure TLS, optional trusted certificate PEM (plus stored leaf SHA-256 for confirmation on change), and whether HTML5/noVNC/SPICE-style consoles open in an embedded pane or the system browser. Settings → Plugins holds built-in plugin toggles and license activation.
- TLS behavior (HTTP and upstream WebSockets): Proxmox traffic uses reqwest with native-tls. Certificate verification is not enforced when Allow insecure TLS is enabled or when a non-empty trusted PEM is stored—so custom CA / self-signed clusters work with the PEM path; treat this as an explicit trust decision.
- Sidebar: when the plugin is enabled and entitled, lists clusters and guests; uses
plugin_invokefor RPC-style calls (resource lists, guest status, console URLs). - Embedded consoles: QEMU noVNC and LXC serial/xterm views talk to the cluster through
proxmux_ws_proxy.rs(proxmux_ws_proxy_start/proxmux_ws_proxy_stopinmain.rs): the webview uses plainws://127.0.0.1, Rust openswss://upstream with native TLS. - Startup: optional warmup delays reduce duplicate work when the sidebar becomes visible (see
proxmux-startup-warmup.ts).
Deeper technical notes: superpowers/specs/2026-03-23-proxmox-console-integration-analysis.md.
- UI calls
start_sessionwith aHostConfig(alias, HostName, user, port, identity file,proxyJump,proxyCommand). resolve_host_config_for_sessionapplies the entity store binding and linked user (user string, HostName, keys, proxy fields, etc.), then runs pluginenrich_resolved_host.build_ssh_commandadds OpenSSH flags, includingStrictHostKeyCheckingfromhost_metadatafor the host alias (or from the quick-connect request for ephemeral sessions).- Child
sshruns under a PTY; output is chunked intoSessionOutputEvent(includes a flag when the known-hosts prompt substring appears).
sequenceDiagram
participant UI as React
participant TA as tauri-api
participant MR as main.rs
participant SS as secure_store
participant HM as host_metadata
participant SE as session
participant SSH as ssh binary
UI->>TA: start_session(host)
TA->>MR: invoke
MR->>SS: resolve_host_config_for_session
MR->>HM: load_metadata (inside session build)
MR->>SE: start(resolved_host, quick_policy?)
SE->>SSH: PTY spawn with -o StrictHostKeyChecking=...
SE-->>UI: session-output events
- Resolves host the same way for saved hosts (
resolve_host_config_for_session). - Opens TCP to
HostName:portand starts libssh2—not the same asssh -J/ProxyCommand. - Documented limitation: use direct-reachable hosts or rely on terminal + SSH for bastioned paths.
- Users — display name, SSH username, optional per-user HostName / ProxyJump, key references.
- Keys — path-based or encrypted key material in the store.
- Host bindings — per config-host alias: linked user, key refs, groups/tags,
proxyJump,legacyProxyCommand, etc. - At session time, binding and user rows override or fill fields on top of the parsed SSH config host.
- Hosts: list/save/delete hosts, raw config read/write, SSH dir info and override
- Metadata: list/save metadata, touch
lastUsedAt - Sessions: start SSH, start local shell, start quick SSH, send input, resize, close
- Store: CRUD-ish commands for encrypted store entities and key unlock
- Backup / profiles: export/import backup, layout and view profile persistence
- SFTP: list/download/upload/rename/… for remote and local panes
- Plugins / license:
list_plugins,set_plugin_enabled,plugin_invoke,activate_license,license_status,clear_license - PROXMUX console bridge:
proxmux_ws_proxy_start,proxmux_ws_proxy_stop(local WebSocket → clusterwss://consoles)
Authoritative list: generate_handler![...] in main.rs and matching names in tauri-api.ts.
- Primary:
session-output— terminal stream +host_key_prompthint for trust UI. - Frontend listeners:
TerminalPane.tsx,useSessionOutputTrustListener.ts, and related refs inApp.tsx.
| Artifact | Role |
|---|---|
Effective config under SSH dir |
Managed Host blocks |
nosuckshell.metadata.json |
Per-alias UI metadata and host-key policy |
| Entity store file (under app data) | Identity Store (encrypted) |
| Layout / view profile JSON | Workspace and sidebar view state |
nosuckshell.plugins.json |
Per-plugin enabled flags (under active SSH dir) |
nosuckshell.license.json |
Verified license payload + signature (under active SSH dir) |
Exact paths depend on platform and optional SSH dir override (see Settings → SSH and ssh_home).
| Doc | Content |
|---|---|
| backup-security.md | Backup format and threat model |
| licensing.md | License tokens, Ko-fi, entitlements, key rotation |
| roadmap.md | Shipped and planned plugins (NSS-Commander file panes, PROXMUX, GitHub sync, Vault, command palette, public cloud) |
| releases.md | Tags and GitHub releases |
| CHANGELOG.md | Release notes |
| README.md (repo root) | Clone, build, run |