A cross-platform terminal and remote-access client: SSH, SFTP, Mosh, Telnet, RDP,
VNC and serial, organised around end-to-end encrypted vaults rather than a
plaintext ~/.ssh/config. Dark green throughout.
Status: early. The connection engine, vault crypto, and protocol registry are built and tested. The desktop shell and UI are in progress. See Protocol support for what actually carries traffic today.
Loki treats connection data as an object graph — Vault → Group → Host, with credentials in a Keychain that hosts reference rather than embed. Rotating a key touches one object instead of fifty host entries, and group defaults cascade so "route Production through the bastion" is set once.
The differentiator is the trust model. Loki's vaults are encrypted whole —
including hostnames, usernames and tags, not just passwords — and secrets never
leave the main process. The renderer receives hasPassword: true, never the
password itself; the window that draws your UI cannot read your credentials.
src/
shared/ domain model + protocol catalogue (no I/O)
main/
vault/ envelope encryption + on-disk store
connect/ resolver, connector registry, per-protocol transports
session/ session base class + middleware pipeline
Three ideas carry most of the weight:
Protocol connectors. Every protocol is a Connector in one registry, keyed
by a discriminated union. Nothing outside src/main/connect/ branches on
protocol. Protocols split into direct (spoken in-process, works with no server
at all) and gateway (needs a guacd sidecar — the only realistic path for RDP
and VNC from JavaScript).
Session middleware. Everything between a transport and the terminal is a pipeline stage, so transcripts, shell integration, and startup scripts are added once rather than per protocol. Output stages run in insertion order and input stages in reverse, keeping the pipeline symmetric. Sessions buffer output until the renderer attaches, so server banners are never lost to a slow-mounting UI.
Envelope encryption. passphrase --scrypt--> KEK --wraps--> DEK --> payload.
Changing the passphrase rewraps 32 bytes instead of re-encrypting the vault, and
the KDF runs once per unlock rather than once per record. Each payload carries
associated data binding it to its vault id, so an attacker with write access to
the vault directory cannot swap payloads between vaults undetected.
| Protocol | Transport | Status |
|---|---|---|
| SSH | direct | Implemented — jump-host chains, password / keyboard-interactive / key / agent auth, host-key verification |
| Telnet | direct | Implemented — full IAC option negotiation, NAWS, terminal-type |
| SFTP | direct | Pending — SSH transport is in place; needs the file-browser surface |
| Mosh | direct | Pending — needs the mosh-client binary and a UDP path |
| Serial | direct | Pending — needs the serialport native module |
| RDP | gateway | Pending — needs a guacd sidecar |
| VNC | gateway | Pending — needs a guacd sidecar |
Pending protocols are registered, not omitted: attempting one raises a
ProtocolNotImplementedError naming exactly what is missing, so the gap is
visible in the code and explainable in the UI.
Hosts, with the Host Details panel:
Group Details, including inherited defaults and cloud-sync intent:
Keychain — keys and identities, filtered by type:
Identity editor — username and password login, with the password write-only:
Deleting names what is going, and warns about anything that depends on it:
Terminal, with the appearance side panel:
Requires Node 20+ (see .nvmrc). Works the same on Windows, macOS and Linux.
npm install
npm run dev # opens the Loki windowOn Windows, npm install prints a warning about cpu-features failing to build
if Visual Studio build tools are absent. That is expected and harmless —
cpu-features is an optional dependency of ssh2, loaded inside a
try/catch, and SSH works without it. Packaging excludes it outright, so no
build toolchain is needed to produce an installer either.
npm run build:win # NSIS installer (x64 + arm64) and a portable .exe
npm run build:win-portable # portable .exe only
npm run build:mac # dmg
npm run build:linux # AppImage + deb
npm run build:unpacked # unpacked app dir, for a quick smoke testOutput lands in release/. The Windows installer is per-user, so it does not
prompt for admin rights, and lets you pick the install directory.
Windows binaries cannot be cross-built from Linux (that needs wine), so
.github/workflows/build.yml builds each platform on its own runner and uploads
the artifacts. Push a v* tag, or run the workflow manually.
npm test # 94 tests, including SSH against a real in-process server
npm run typecheckLoki is original code, but its design was chosen after studying three open-source clients. Credit where it is due:
- Tabby (MIT) — the
ProfileProviderregistry andSessionMiddlewareStackshaped Loki's connector and middleware layers, as did its trick of buffering initial output until the terminal mounts. - Termix (Apache-2.0) — demonstrated
that RDP/VNC realistically require a
guacdsidecar, which is why Loki distinguishes direct from gateway transports. - MagicTerm (MIT) — the closest existing take on encrypted vaults. Loki's envelope design is a direct response to two limits in its approach: re-deriving the KDF per record, and holding the master password in the renderer.
No code was copied from any of them.
Apache-2.0. See LICENSE.





