SSH had a good run. Time to march forward.
One binary to rule them all. TLS-encrypted. Delta-sync transfers. Fleet management built in.
Features · Quick Start · Usage · Building · Security
Because ssh was designed in 1995 when "fleet management" meant horses, and the old rsh (1983) was about as secure as a screen door on a submarine. mrsh is what happens when you rebuild remote management from scratch in Rust, with opinions:
- Delta-sync transfers — rsync-like CDC chunking, only changed blocks travel over the wire (up to 97% bandwidth savings)
- Unified binary — one
mrshexecutable works as client, server, Windows service, and system tray app - SSH compatibility — auto-detects SSH on the same port (peek first byte:
0x16=TLS,0x53=SSH) - Persistent sessions — ConPTY + ring buffer, detach and reattach from any client
- NAT traversal — built-in rendezvous relay for machines behind firewalls
- GUI automation — mouse, keyboard, window control over the wire
- Remote GUI testing — built for automated UI testing on remote machines (screenshot, click, type, verify)
- AI-friendly — designed for AI agent orchestration with built-in safety guards
| Category | Capabilities |
|---|---|
| Connection | TLS 1.3, ed25519 auth, TOTP 2FA, SSH-style TOFU, multiplexed channels, ProxyJump (-J), zstd compression |
| File Transfer | CDC delta-sync, block cache, hash cache, batch pipeline, --checksum, --backup, --bwlimit, --progress with ETA, relay push |
| Shell | Persistent ConPTY sessions, multi-client attach, tilde-escape commands, session recording (asciicast export) |
| Execution | Remote PowerShell exec, batch scripting (.mrsh files), SOCKS5 proxy (-D), --timeout flag |
| GUI | Mouse control, keyboard input, window management, screen capture (MJPEG), multi-display, remote UI test automation |
| System | reboot, shutdown, sleep, lock, wake (WoL), info, service management, ps/kill |
| Server | Windows service (SCM), system tray with notifications, console mode, auto-tray launch (WTS), DLL plugins |
| Fleet | Multi-host status, rendezvous relay, hbbs peer discovery, LAN discovery, self-update, fleet enrollment, install-pack (NSIS) |
| Dashboard | TUI fleet dashboard (mrsh dash), TUI log viewer (mrsh log), real-time status with action menu |
| Network | NAT type detection (STUN), bidirectional clipboard sync, LAN peer discovery broadcast |
| Config | SSH-style config file, Ratatui TUI editor, TUI host picker (fuzzy search), auto-DeviceID, --log-file |
| SSH | Transparent SSH fallback, SFTP, agent forwarding (-A), local/reverse port forwarding (-L/-R) |
| Security | Per-key permissions (no-exec, no-gui, no-reboot, no-clipboard, no-screenshot), rate limiting |
# Test connection (auto-tries ports 8822, 9822, 22) mrsh -h 192.168.1.100 ping # Interactive shell mrsh -h 192.168.1.100 shell # Execute command mrsh -h 192.168.1.100 exec "Get-Process" # Push files (delta-sync) mrsh -h 192.168.1.100 push ./src C:\app\src # Pull files mrsh -h 192.168.1.100 pull C:\logs\app.log ./local/# Install as Windows service .\mrsh.exe --install net start mrsh # Or run as tray icon .\mrsh.exe# Delta-sync push (only changed blocks transfer) mrsh -h host push ./project C:\deploy\project # With exclusions mrsh -h host -x '*.log' -x 'node_modules' push ./src C:\app\src # Dry-run (see what would change) mrsh -h host --dry-run push ./data C:\backup # With checksum verification mrsh -h host --checksum push ./data C:\backup # Mirror mode (delete remote files not present locally) mrsh -h host --delete push ./src C:\app\src # Bandwidth limit mrsh -h host --bwlimit 1024 push ./large-file.bin C:\data\# Start persistent session mrsh -h host shell # Reattach to existing session mrsh -h host attach <session-id> # List active sessions mrsh -h host sessions list # Kill a session mrsh -h host sessions kill <session-id> # Tilde-escape commands (inside session): # ~. detach # ~u upload file # ~d download file # ~? helpSessions persist on the server. Detach with ~. and reattach later from any client.
# List recordings mrsh -h host recording list # Export to asciicast format (for asciinema playback) mrsh -h host recording export <session-id> output.castmrsh -h host exec "Get-Service | Where Status -eq Running" mrsh -h host ps # List processes mrsh -h host kill 1234 # Kill process mrsh -h host ls C:\logs # List directory mrsh -h host cat C:\logs\app.log # Read file # With timeout (kills command after N seconds) mrsh -h host --timeout 30 exec "long-running-command"mrsh -h host reboot # Reboot remote machine mrsh -h host reboot -f # Force reboot (no graceful shutdown) mrsh -h host shutdown # Shutdown remote mrsh -h host sleep # Suspend/sleep remote mrsh -h host lock # Lock workstation mrsh -h host wake myserver # Wake-on-LAN (uses MAC from config) mrsh -h host status # Connection quality + host info mrsh -h host info # Structured system info (JSON)mrsh -h host service list # List all services mrsh -h host service status <name> # Service status mrsh -h host service start <name> # Start service mrsh -h host service stop <name> # Stop service mrsh -h host service restart <name> # Restart service# Mouse mrsh -h host mouse move 500 300 mrsh -h host mouse click mrsh -h host mouse click right # Keyboard mrsh -h host key type "Hello World" mrsh -h host key tap enter mrsh -h host key combo ctrl shift esc # Windows mrsh -h host window list mrsh -h host window find "Notepad" mrsh -h host window activate "Chrome"mrsh -h host -f commands.mrsh# commands.mrsh exec "Get-Date" mouse move 500 300 mouse click key type "automated input" sleep 2000 exec "hostname" echo "Done on: $_"# Start a control master (reuse connection for subsequent commands) mrsh -h host -M exec "hostname" # Subsequent commands reuse the existing connection (automatic) mrsh -h host exec "Get-Date" # Skip control socket for this command mrsh -h host --no-mux exec "isolated-command" # Stop control master mrsh -h host --mux-stop# Connect through a jump host mrsh -h target -J jumphost exec "hostname" # Jump host with custom port mrsh -h target -J jumphost:9822 exec "hostname"# Fleet status (probes all configured hosts + hbbs-discovered peers) mrsh fleet status # Interactive TUI dashboard (live refresh, Enter for action menu) mrsh dash # TUI log viewer (filter, search, tail mode) mrsh log # Update all outdated hosts (push binary + self-update) mrsh fleet update # Discover peers enrolled in a group mrsh fleet discover --group myteam # Create installer package with pre-configured connection mrsh install-pack --server 192.168.1.100 --key ~/.ssh/id_ed25519.pub -o installer.exe# Auto-detect: tries mrsh, falls back to SSH mrsh -h host ping # Force SSH mrsh -h host --ssh exec "uname -a" # SSH tunneling mrsh -h host tunnel -L 8080:localhost:80 # Reverse port forwarding mrsh -h host tunnel -R 9090:localhost:80 # SOCKS5 proxy mrsh -h host tunnel -D 1080 # SSH agent forwarding mrsh -h host -A shell# Connect via device ID (through relay) mrsh -h 118855822 ping # P2P and relay race in parallel — fastest winsConfigure in ~/.mrsh/config:
RendezvousServer rdv.example.com:21116 Host myserver DeviceID 118855822 Port 8822 # Run your own rendezvous server (hbbs-compatible) mrsh rendezvous --port 21116 # Run your own relay server (hbbr-compatible) mrsh relay --port 21117# Watch local directory and auto-push changes to remote mrsh -h host watch ./src C:\app\src # Useful for live development — changes sync automaticallymrsh -h host screen stream # MJPEG live stream mrsh -h host screen capture # Single screenshotSSH-style config file at ~/.mrsh/config:
# Global defaults RendezvousServer rdv.example.com:21116 # Per-host settings Host myserver Hostname 192.168.1.100 Port 8822 # Explicit port (skips auto-try) MAC aa:bb:cc:dd:ee:ff # For Wake-on-LAN DeviceID 118855822 # For relay connections Port resolution order: (1) explicit -p flag, (2) config Port field, (3) auto-try 8822 → 9822 → 22 with 3s timeout per port.
Server files live in C:\ProgramData\mrsh\:
C:\ProgramData\mrsh\ ├── mrsh.exe # Binary (service + tray + client) ├── authorized_keys # Ed25519 public keys (auto-reloaded) ├── server_key # Auto-generated on first run ├── startup.bat # Optional: runs at service start ├── plugins\ # Plugin DLLs ├── cache\ # Block cache (msgpack KV) └── mrsh.log # Server log Requires Rust 1.85+ (edition 2024) and x86_64-pc-windows-gnu target for cross-compilation.
# Linux client cargo build --release # Windows client+server (cross-compile from Linux) cargo build --release --target x86_64-pc-windows-gnu # Run tests (539 tests on Linux, ~12s) cargo test --workspaceBinaries are placed in target/release/rsh (~5.5 MB) and target/x86_64-pc-windows-gnu/release/mrsh.exe (~4.8 MB). Both are stripped with LTO enabled.
- TLS 1.3 for all connections (self-signed certs with TOFU pinning)
- Ed25519 challenge-response authentication (same key format as SSH)
- TOTP 2FA — optional per-key two-factor authentication
- No passwords — key-based auth only (ed25519)
- Known hosts — server certificate fingerprints are verified on first connect and pinned
- Authorized keys — hot-reloaded on every connection, no restart needed
- Rate limiting — IPs banned after 5 failed auth attempts within 60 seconds
mrsh has a built-in key generator (no OpenSSH required):
# Generate ed25519 key pair (default: ~/.mrsh/id_ed25519 + .pub) mrsh keygen # Generate to custom path mrsh keygen /path/to/mykey # Copy public key to server mrsh -h host push ~/.mrsh/id_ed25519.pub C:\ProgramData\mrsh\authorized_keysStandard SSH ed25519 keys (ssh-keygen -t ed25519) also work — mrsh uses the same OpenSSH format.
mrsh (workspace root) ├── src/main.rs # CLI entry point └── crates/ ├── mrsh-core/ # Protocol, TLS, auth, config ├── mrsh-client/ # Client commands, shell, SFTP, tunneling ├── mrsh-server/ # Server: dispatch, exec, service, tray, GUI ├── mrsh-transfer/ # CDC chunking, delta-sync, block cache └── mrsh-relay/ # Rendezvous server + relay protocol - Command port (default 8822, auto-tries 8822 → 9822 → 22 when
-pomitted): Length-prefixed binary framing (4-byte BE header) over TLS - Stream port (command port + 1): JSON + raw streams for push/pull
- SSH detection: First byte peek —
0x16routes to TLS,0x53routes to SSH handler - Multiplexing: Multiple logical channels over single TLS connection
Extend mrsh with custom DLL plugins:
#include "mrsh_plugin.h" MRSH_API int MRSH_GetPluginInfo(char* buf, uint32_t* len) { const char* info = "{\"name\":\"myplugin\",\"version\":\"1.0\",\"commands\":[\"hello\"]}"; strcpy(buf, info); *len = strlen(info); return 0; } MRSH_API int MRSH_Execute(const char* req, uint32_t reqLen, char* resp, uint32_t* respLen) { snprintf(resp, *respLen, "{\"success\":true,\"output\":\"Hello from plugin!\"}"); *respLen = strlen(resp); return 0; }See plugins/ for the full header and example.
mrsh is designed to be used by AI agents (Claude Code, similar tools) for autonomous remote machine management. Several features make it particularly suited for AI orchestration:
Structured output: All commands return JSON responses with success, output, and error fields — easy to parse programmatically without screen-scraping.
Native commands: Built-in ps, ls, cat, screenshot, mouse, key, window commands eliminate the need to construct shell one-liners for common operations.
Batch scripting: .mrsh script files allow multi-step automation sequences.
The server includes built-in protection against self-destructive commands — a critical safety net when AI agents manage remote machines. The exec handler blocks commands that would kill or stop the mrsh process serving the current connection:
| Blocked Pattern | Why |
|---|---|
taskkill /im mrsh.exe | Would kill the process serving this connection |
Stop-Service mrsh / net stop mrsh | Would stop the service, cutting off access |
Stop-Process -Name mrsh | PowerShell equivalent of taskkill |
Remove-Item ... mrsh.exe | Deleting the binary prevents service restart |
sc delete mrsh | Removing service registration prevents restart |
Blocked commands return an error with the reason and suggested safe alternative (e.g., mrsh self-update). This prevents the most common AI agent lockout scenario without restricting legitimate operations.
mrsh includes several measures to prevent misuse as a covert remote access tool:
| Measure | Description |
|---|---|
| Mandatory tray icon | Service installation (--install) registers a logon task that launches the tray companion at every user login. Users always see a system tray icon indicating mrsh is active. |
| Connection toast notifications | When a client authenticates, the tray icon displays a Windows balloon notification showing the client IP and key comment. Every remote connection has user-visible evidence. |
| Failed auth rate limiting | IPs that fail authentication 5 times within 60 seconds are banned for 5 minutes. Prevents brute-force key guessing. |
| Exec safety guards | Server blocks commands that would kill/stop/delete the mrsh process (see table above). Prevents both accidental and deliberate self-destruction. |
These measures ensure that a legitimate administrator always has visibility into mrsh activity, while making it impractical for casual attackers to abuse an installed mrsh instance without detection.
The rendezvous and relay protocol in mrsh-relay is a clean-room MIT rewrite that is wire-compatible with RustDesk hbbs/hbbr servers. This means:
- If you already run your own RustDesk relay infrastructure, mrsh can use it as-is — no need to deploy new relay servers
- The same rendezvous server (hbbs) and relay server (hbbr) handle both RustDesk and mrsh clients
- Protocol extensions (health checks, metrics) use high field numbers that are silently ignored by standard RustDesk servers
The implementation is written from scratch with no derived code, using the same publicly documented wire format (protobuf message types and BytesCodec framing).
mrsh stands on the shoulders of these projects and ideas:
| Project | What we drew from |
|---|---|
| OpenSSH | Ed25519 key format, authorized_keys convention, ~. escape sequences, config file syntax, SSH protocol detection for interop |
| RustDesk | Rendezvous/relay wire protocol (protobuf over BytesCodec). mrsh-relay is a clean-room MIT rewrite that is wire-compatible with RustDesk hbbs/hbbr servers |
| rsync | Inspiration for delta-sync file transfers. mrsh uses Rabin-polynomial CDC (content-defined chunking) with block-level dedup and SHA-256 verification |
| mosh | The idea that SSH can be reimagined for modern use — roaming, resilience, and state synchronization |
| ConPTY | Microsoft's pseudo-console API that makes proper Windows terminal emulation possible for persistent shell sessions |
| RFC 1928 | SOCKS5 protocol for the built-in proxy (mrsh tunnel -D) |
- GUI automation is Windows-only — ConPTY shell, service SCM, tray icon, mouse/keyboard/window control require Windows. Server daemon mode (exec, file transfer, relay) works on all platforms
- QUIC transport — server + client behind
--features quic; supportspingandexecover QUIC (mrsh --quic -h host exec 'cmd') - Go→Rust migration — self-update on old Go mrsh machines breaks the Windows service (single-dash vs double-dash CLI flags). Manual service reinstall required
mrsh = Marco Rust Secure sHell. Sounds like marsh (where things grow wild), and Marsch (German: to march forward). We chose it because the old rsh (1983) was already taken, and honestly? That one deserved to be replaced anyway.
MIT — see LICENSE.
Contributions welcome. Open an issue first so we can discuss before you wade into the marsh.
