Nexus Terminal
A full SSH + serial + port-forwarding client inside VS Code — without Remote-SSH's 300MB server payload on the box.

- Replaces PuTTY + MobaXterm + SecureCRT + TeraTerm — SSH, serial consoles, local shells, port forwarding, and SFTP live in one VS Code sidebar instead of four separate windows.
- Unlike Remote-SSH, nothing is installed on the remote. It's a pure client: no
vscode-server unpacked into the target, no node process running on the far end. That matters when the far end is a Cisco switch, a bastion you only get a shell on, or a change-controlled box where you can't drop an agent.
- Bring your existing connections — import session profiles straight from MobaXterm
.ini and SecureCRT XML exports, folder hierarchy preserved, so switching costs you minutes, not a weekend.
- Onboard a whole rack in one paste — feed it a CSV export or a plain list of hostnames and it creates the connections in bulk, with folders, ports, and usernames picked up from the columns. Duplicates are skipped and unparsable lines are reported with their line numbers instead of failing the batch.
- Sync servers straight from NetBox or EVE-NG — point an inventory source at your NetBox instance and devices become connection profiles, foldered by site and rack, linked to an auth profile so they can actually connect the moment they land. Point one at an EVE-NG server instead and the lab tree comes across the same way: labs become folders, nodes become servers on their own telnet consoles, and running labs light up in the tree. Re-syncing follows renames and rack moves at the source (with one documented exception — renaming or moving an EVE-NG lab re-creates its nodes, see the walkthrough), every sync shows you its plan before anything is applied, and removing a source then re-adding it later offers to re-adopt the servers you kept instead of duplicating them.
- Edit root-owned files without dropping to a shell — save
/etc/* over SFTP with sudo, writing through the file's existing inode so owner, mode, and ACLs are preserved. Your sudo password goes to the SSH channel's stdin only: never to disk, never to secret storage, never to a log.
Reaching a device two hops away
Jump hosts are set per server, and a jump host can have a jump host of its own — so the chain goes as deep as your network does. Below, an access switch is reached through an NMS host, which is itself reached through a bastion. One connect walks the chain, authenticating each hop in turn, and the shell lands on the switch. No ProxyJump stanza to hand-write, and nothing installed on any host along the way.

Who it's for
- Network and infra engineers on Cisco, Juniper, and embedded gear — multi-hop jump-host chaining (A → B → C) and a per-server legacy KEX/cipher toggle keep you connected to old IOS boxes that modern clients refuse.
- Embedded and firmware developers on serial consoles — Smart Follow rides through Windows COM-port renumbering, reconnecting only to the device you already approved instead of dropping the session.
- Homelab and self-hosters — one sidebar for every box, tunnel, and serial cable, with expect/send auto-trigger macros and a JavaScript scripting engine for repeatable tasks.
- VSCodium and Open VSX users — full SSH that Remote-SSH (proprietary, Marketplace-only) can't give you, plus 2FA keyboard-interactive auth and encrypted config backup.
Install
Features
SSH Terminal Sessions — Connect to remote servers with password, private key, or SSH agent authentication. Two-factor authentication (keyboard-interactive) is fully supported — passwords auto-fill while verification codes are prompted separately. Credentials are cached securely via VS Code SecretStorage with silent re-auth. Per-server legacy algorithm toggle for older devices (Cisco IOS, embedded systems). An optional Alternate host gives a server a second SSH address (e.g. the IPv6 to its IPv4); if the primary can't be reached at the connection level — no route, refused, timed out, or a name that won't resolve — Nexus retries the alternate once automatically and names the address that won, while auth/host-key/proxy failures are never retried on the other address. Faults that arrive after a session is up — a keepalive timeout, a protocol error, the connection closing — are recorded in the Nexus SSH output channel, so a terminal that drops on its own leaves a cause behind instead of only "Connection lost".
SSH Key Deployment — Right-click any server and select "Deploy SSH Key" to automate key-based authentication setup. Discovers existing local keys or generates new ed25519 key pairs, deploys the public key to the remote authorized_keys, and optionally converts the server profile to key auth. Cross-platform (Windows, macOS, Linux).
SSH Host Key Verification — Trust-on-first-use (TOFU) model stores host keys on first connection and alerts if a key changes (potential MITM). Configurable via nexus.ssh.trustNewHosts.
Auth Profiles — Define reusable credential sets (password, private key, or SSH agent) and apply them to individual servers or entire folders in bulk. A NetBox inventory source can carry a profile too, so every server it syncs connects with those credentials from the start. The link is a reference, not a copy — edit the profile once and every server using it picks up the change, no re-sync needed. A failed login on one linked server never erases the profile's saved credential — one broken device can't lock the rest of the fleet out of silent re-auth; the stored credential is only replaced when a device actually signs in with a new one. Manage profiles from a dedicated editor panel accessible via the Settings tree or context menu.
Proxy Support — Route SSH connections through intermediaries when direct access isn't available. Three proxy types are supported per server:
- SSH Jump Host — Select another configured server as a bastion/jump host (ProxyJump equivalent). Supports multi-hop chaining (A → B → C) with full auth reuse.
- SOCKS5 Proxy — Connect through a SOCKS5 proxy server with optional username/password authentication.
- HTTP CONNECT Proxy — Connect through an HTTP proxy using the CONNECT method, common in corporate environments.
SFTP File Explorer — Browse, download, and manage remote files on connected servers. Drag-and-drop support for moving files between directories, and for uploading local files and folders onto a remote directory. Every upload and download is size-checked against its source once it finishes, and an item that was attempted and failed is counted as a failure rather than folded into the skip count. Windows network shares (\\server\share) are handled explicitly — see below. One SSH profile can be set to open the File Explorer automatically after normal Connect when the view is not already showing that server.
Directory Sync (Follow Terminal Directory) — Keeps the File Explorer pointed at whatever directory your SSH terminal is actually in, instead of wherever you last browsed. It's continuous, not a one-off jump, on any shell that announces its own directory (fish, starship, or bash/zsh with one added line — see below); everything else gets a manual Go to Terminal Directory action. Nexus never types anything into a session to make this work.
Telnet Sessions — Set a server's Protocol to Telnet and it connects over raw telnet instead of SSH, for console servers, virtual-lab consoles, and gear that offers nothing else. It is a per-server switch on the profile you already have, not a separate kind of profile: pick Telnet and the credential fields disappear, because telnet has no login of its own — you authenticate at the device's own prompt, in the terminal. Nexus speaks the negotiation properly (echo and suppress-go-ahead, terminal type, and live window-size updates on resize), so full-screen tools and line editing behave. Everything the terminal layer gives an SSH tab it gives a telnet tab too: highlighting, Reset / Clear Scrollback / Copy All, auto-trigger macros, and scripts (@target-type telnet). Telnet is cleartext — there is no encryption and no authentication in the protocol — so SFTP, port forwarding, jump hosts and key deployment aren't available on a telnet server, and asking for one says so up front instead of failing inside a handshake.
Serial Terminal Sessions — Connect to serial ports (COM/ttyUSB) with configurable baud rate, data bits, parity, stop bits, and RTS/CTS flow control. Supports break signal and XON passthrough. Includes Smart Follow mode for Windows COM-port renumbering: it retries the preferred port, silently reconnects only to the previously approved device when metadata matches, prompts before switching to unfamiliar replacement ports, updates the saved preferred port after a successful move, and keeps the terminal open while waiting or stopped instead of tearing the tab down on serial errors. Runs in an isolated sidecar process for crash safety.
Local Shell Profiles — Save named local terminal profiles and open one or more local shell sessions from the Connectivity Hub. Use a launchable VS Code terminal profile from the profile dropdown, including common resolved PowerShell, Git Bash, Command Prompt, and WSL profiles when available, or choose Custom Shell to set an explicit shell path, one argument per line, a working directory, and an optional startup command. Manual macros, auto-trigger macros, and Nexus scripts work with Local Shell sessions.
Port Forwarding (TCP Tunnels) — Three tunnel modes:
- Local (-L) — Forward a local port to a remote host through SSH.
- Reverse (-R) — Forward a remote port back to a local target.
- Dynamic SOCKS5 (-D) — Run a local SOCKS5 proxy that routes traffic to any destination through SSH.
All modes support configurable local bind addresses (localhost, LAN, or all interfaces), auto-start/auto-stop with server connections, live traffic counters, and a browser URL shortcut for quick access.
Embedded Network Servers (TFTP + DHCP) — Serve firmware and configs to lab hardware, and hand it addresses, without installing a separate daemon or borrowing the office DHCP server. Both services bind every interface (0.0.0.0) unless you pick one, from a live list of this machine's IPv4 addresses, in Quick Settings or the full form. TFTP is read-only until you opt into uploads, and sandboxes every filename a client sends inside the configured root, so a ../ cannot escape it; live transfers show progress and speed and can be cancelled from the sidebar. DHCP runs full DORA with static reservations, leases that survive a restart, and the ZTP boot options a switch actually asks for (66, 67, 150, 60, 43). A Network (CIDR) row in both Quick Settings and the full form takes a whole network in one go — type 192.168.2.0/24 and the subnet mask, pool, gateway and DNS that follow from it are filled in; nothing is stored under that shorthand, and Quick Settings shows exactly what it would write and asks before writing it. If the NIC the service is bound to is not on the subnet the pool hands out — a lab that binds 192.168.1.x and offers 10.0.0.x leases looks correct in every individual field and serves nothing usable — the sidebar, Quick Settings and the form all say so, and offer the one NIC already on that subnet when exactly one matches — never a virtual adapter (Docker, WSL, Hyper-V, VPN), which stays selectable but is not something to pick for you. Save refuses a bind only when the interface's network genuinely does not match the pool and no pool could be derived on that interface either, so a pool that already fits the NIC you picked — a /30 point-to-point link, a range narrowed inside a wider subnet, a NIC the platform reports without a netmask — saves as it always did. Quick Settings also offers to fill in the gateway, broadcast, and DNS that follow from a new pool, and named profiles capture a whole bench setup for next week, relay-agent support included. Both run inside one isolated daemon child process — the same crash-isolation model as the serial sidecar — so closing VS Code always releases UDP 69/67. Requires a trusted workspace. The daemon has two interchangeable implementations behind nexus.networkServers.engine. Since 2.8.205 the default is the native Rust one, packaged for all six supported platforms; the bundled JavaScript daemon remains available and is still the automatic fallback if no native binary is available here, so the services start either way.
SSH Connection Multiplexing — Share SSH connections across terminals, tunnels, and SFTP for the same server. Reduces connection overhead with automatic ref-counting and configurable idle timeout. Per-server toggle lets you disable multiplexing for devices that don't support multiple channels (e.g. Cisco). Automatic fallback to standalone connections handles channel failures transparently.
Connectivity Hub — Sidebar tree view showing all servers, serial devices, and local shell profiles, organized into nested folders. Built-in filter to quickly search by name; when a filter matches nothing, the Hub says "No matches found" instead of showing the first-run onboarding. Drag and drop to rearrange profiles, move between folders, or assign tunnels to servers. Active SSH and serial sessions highlight unread terminal activity in the tree and prepend ● to the terminal tab title until you focus that terminal again.
Terminal Appearance — Customize terminal font family, size, and weight. Import color schemes from MobaXterm INI files or configure custom themes with live preview.
Local Servers — Run the local processes a bench needs alongside everything else: a dev server, a proxy, a mock API, a build watcher. Save a profile with an executable, arguments, working directory and environment, then start, stop and restart it from the Connectivity Hub, with its output in an ordinary Nexus terminal — highlighting, scrollback capture, Reset / Clear Scrollback / Copy All, and session transcripts all apply. A process that exits on its own can be restarted automatically, with the delay doubling on each attempt and the count clearing once it has run steadily; five consecutive failures is a hard ceiling, because a process that has died five times without once staying up is broken rather than unlucky. Working directories are confined to the folders you have open, and starting one requires a trusted workspace. Distinct from Embedded Network Servers, which serves TFTP and DHCP to hardware on the wire — Local Servers runs programs on this machine.
Terminal Highlighting — Configurable regex-based pattern highlighting for SSH, serial, and Local Shell terminal output. 22 built-in rules detect errors, warnings, status keywords, IPv4/MAC addresses, URLs, interface counters and more with inline ANSI colouring while respecting existing terminal colours. The IPv6 and UUID rules ship disabled — those two patterns cost more than all the others combined — but stay in the list, ready to switch on with a per-row checkbox in the Rule Editor. Every rule can also carry its own label and description so the list stays readable without decoding regexes. Includes a visual Rule Editor with live preview, staged Apply/Cancel, rule ordering, custom SGR foreground codes, regex safety checks, and one-click reset to defaults.
Terminal Macros — Define reusable text sequences and send them to the active terminal with one click or keyboard shortcut. Assign any macro a custom keybinding from 108 combinations across three modifier groups: Alt, Alt+Shift, and Ctrl+Shift with A-Z or 0-9 keys. Macros without a keybinding are accessible via Alt+S quick-pick. Includes a Macro Editor panel with multiline editing, secret macro support, inline keybinding assignment, and Macros-view actions to copy or paste secret values via the system clipboard. Clipboard copies place the value in the OS clipboard as plain text. Auto-trigger (expect/send): add a triggerPattern regex to any macro — when terminal output matches, the macro text is sent automatically. Existing macros default to all-terminal matching for compatibility; new macros can be scoped to the active terminal or a matching profile, which is recommended for secret prompts. triggerCooldown prevents echo loops, triggerInterval enables prompt-gated polling macros, and macros can optionally start with auto-trigger paused until you resume them from the Macros view. Pause/resume, interval ownership, and cooldown state all follow the macro itself, so reordering or deleting other macros never moves that state onto the wrong one. See the macro guide for step-by-step setup, trigger scopes, cooldowns, intervals, and regex examples.
Macro Variables — Declare named variables on a macro (label, default, mask-input, remember) in the Macro Editor and reference them in its text as $name or ${name}; running the macro walks a step-by-step prompt (with Back) for each variable actually used, then sends the filled-in command to the terminal you invoked it from — even if you switch tabs while the prompts are open. A placeholder for a name you never declared is sent through unchanged rather than blocking the macro. Variables and auto-trigger can't be combined on the same macro — prompting needs a foreground input box, which a background pattern match can't safely open. See the macro guide for the full variable reference.
Server profile tokens & IPMI/BMC macros — Reference the server a macro runs against with ${profile.host}, ${profile.port}, ${profile.username}, ${profile.name}, ${profile.ipmiHost} (set IPMI / BMC Host under Advanced in the server form) and ${profile.ipmiUsername} (taken from the IPMI Auth Profile linked beside it). Right-click a server in the Connectivity Hub → Run Macro on Server… to resolve them against that server; macros can target the session, a local terminal (ipmitool SOL), or the browser (BMC web console). Five starter templates ship in Add Macro From Template — SOL console, chassis power status/on/off, and the web console. See the macro guide.
BMC access without typing a password — Link an IPMI Auth Profile to a server (the same auth profiles you already use for SSH — one shared BMC credential can serve the whole fleet) and tick Provide IPMI credentials on an ipmitool macro. Nexus puts that profile's saved password into the macro's local terminal as IPMITOOL_PASSWORD/IPMI_PASSWORD, where ipmitool -E reads it — so the password never appears on the command line, in ps, in the scrollback, or in Copy All to Clipboard. The checkbox is off by default and never arrives switched on from a shared or restored macro: capability settings are always re-confirmed on this machine. Shipped ipmitool templates arrive with it already set, so the common path needs no configuration.
One-click BMC actions — Right-click a server → Connect BMC Serial Console opens a local terminal already running ipmitool … -E sol activate against that server's BMC, and Open BMC Web Console opens its web interface in your browser (HTTPS by default; switch a server to plain HTTP under Advanced when its card offers nothing else). Both reuse the same address and credential rules as the macros — a server missing a piece gets an error that names the field and where to set it, rather than a broken command.
Keyboard Passthrough — Optionally pass Ctrl+ key combinations (e.g. Ctrl+B, Ctrl+N) directly to the terminal for applications like vim, nano, and htop. Configurable per-key with 10 supported combinations.
Session Transcript Logging — Automatically log clean terminal output (ANSI codes stripped) to files with configurable rotation. Per-profile toggle.
Terminal Tab Commands — Right-click any Nexus terminal tab for three PuTTY-style commands: Reset Terminal (clears the visible screen while preserving scrollback), Clear Scrollback (clears visible and captured transcript together), and Copy All to Clipboard (ANSI-stripped transcript of the session). After a session disconnects, Reset and Clear grey out; Copy All stays enabled so a run can always be captured for a ticket or chat.
Settings Panel — View and edit extension settings in a dedicated webview panel with grouped categories, terminal-adjacent actions, validation, and host-confirmed auto-save.
Configuration Export/Import — Full encrypted backup with master password protection, or sanitized share export (credentials stripped, IDs remapped). Proxy configurations are preserved across backup and restore.
Import from MobaXterm / SecureCRT — Migrate SSH session profiles directly from MobaXterm INI files or SecureCRT XML exports and session directories. Folder hierarchy is preserved.
NetBox Inventory Sync — Add your NetBox instance as an inventory source and Nexus creates and maintains server profiles from its devices: placed under a target folder of your choosing, organized by a folder template ({site}/{rack} by default; {location}, {role}, and {tenant} also available), narrowed by any NetBox device filter, with virtual machines included on request. The API token lives in VS Code SecretStorage, never in a settings file. Nothing is applied blind: every sync computes a plan — servers to add, update, move, or remove — and shows it for confirmation first, with warnings and affected-server lists one click away. A device NetBox has no usable IP for is created as well, as a server with no address and counted in the plan's warnings, rather than being dropped with a "skipped" note — so it stays in your tree and starts connecting once NetBox gives it an address. Devices renamed or re-racked at the source follow on the next sync; a device that disappears is moved to the source's _orphaned subfolder by default, keeping its settings in case it returns (deleting or keeping it in place are per-source alternatives). Removing a source asks whether to delete the servers it created or keep them — and a kept server remembers the device and NetBox it was synced from, so re-adding that NetBox later asks once whether to Adopt Existing (re-link the kept servers: each keeps its saved credentials and settings, while the source takes over its name, address, folder, and — from then on — its Removed-Device Policy) or Add Separately. Adoption is deliberately narrow: only a server a source actually synced, kept when that source was removed, and still at its device's address qualifies, and only for a source pointed at the same NetBox — a server you made by hand is never taken over, however exactly its address matches; a record kept from a lab instance can't be claimed by the same device id in production; and when two kept records claim one device, Nexus adopts neither rather than guessing. The answer alone changes nothing: adoptions go through the same plan as everything else, counted in the preview and named, pair by pair, under Show Warnings. Link an Auth Profile to the source and every server it creates connects with those credentials. Servers from earlier syncs adopt the profile on the next sync — but only those still carrying exactly what the sync gave them: anything you've hand-edited keeps its own credentials, and clearing the profile on one synced server is a per-server opt-out that later syncs respect. A source's Primary IP Family (Automatic / Prefer IPv4 / Prefer IPv6) decides which address fills each server's Host; when a device carries both families, the other family's primary IP is written into Alternate host automatically, so synced servers arrive ready to fall back from one stack to the other. The folder a source syncs into carries an inline sync icon — when that folder exists and exactly one source targets it — so re-syncing one source is a single click on the tree. Manage sources from Settings → Inventory Sources (Sync Now / Edit / Template Rules / Remove per source) or the Command Palette.
EVE-NG Lab Sync — Add an EVE-NG server as an inventory source and its lab tree becomes connection profiles: labs become folders, nodes become servers, each pointed at the node's own telnet console. The username and password you log into EVE-NG with are kept in VS Code SecretStorage, never in a settings file. Narrow what comes across with a Root Folder (scan one subtree of the lab tree) and a Lab Filter (a case-insensitive substring of a lab's full path), and set a Console Host Override for an EVE-NG behind NAT — a console EVE-NG reports on 127.0.0.1 or 0.0.0.0 is describing its own machine, so Nexus substitutes the host from the base URL, and an override wins over both. A node with no telnet console is still created, as a visible server with no address rather than being dropped. A stopped node upgrades to a real telnet server as soon as it starts and its console exists (downgrading again if it goes away); an HTML5/VNC-only node has a console Nexus cannot drive, so it stays addressless until its console type is changed to telnet in EVE-NG. Refresh Lab Status paints running nodes and the labs holding them green in the tree, and each source's own Lab Status Poll Interval keeps that current while the Command Center is open — set per source, so a busy lab can poll often and a quiet one not at all. Start Node / Stop Node on a node's right-click menu bring a lab node up or down without leaving the editor. The folder a source syncs into carries an inline sync icon — when that folder exists and exactly one source targets it (two sources sharing a folder, or a source targeting the root, get no icon) — so re-syncing one source is a single click on the tree rather than a trip through Settings. Community edition is the certified target: Nexus is edition-aware and works against Professional, but Pro support is preliminary and a sync against one says so in its warnings.
Device Templates — Apply a named, reusable bundle of connection settings to the servers a sync creates and maintains, instead of hand-editing each one. A device template can set Proxy, Auth Profile (SSH), Multiplexing, Legacy Algorithms, Session Logging, IPMI Auth Profile, and IPMI Gateway; each field is tri-state — Not set, Fill (only where nothing is set), or Override (replace source and earlier-synced values) — and templates never store secrets, so proxies still prompt on first connect. Bind a template to a source's devices with filter rules (role=switch&site=syd; keys role, site, location, rack, tenant, status, platform, tag, name), or pick one Device Template in the source form to cover everything it syncs. When several rules match a device the settings cascade per field — the most specific rule wins each setting it sets, never by rule order. Your own edits always win, clearing a template-applied value opts that server out, and changes land on each source's next sync. Create and manage templates with New Device Template / Manage Device Templates / Edit Template Rules, or apply one to a folder immediately with Apply Device Template.
Scripts — Author .js automation scripts under .nexus/scripts/ (or the folder of your choice via Nexus Settings → Scripts → Scripts Folder, which exposes a native folder picker; works with or without an open workspace — when none is open, scripts live in the extension's global storage) and run them against any active SSH, Serial, or Local Shell session. Scripts use an async expect/send API (waitFor, expect, waitAny, send, sendLine, sendKey, poll, prompt, confirm, alert, sleep, log, nexus.fs, nexus.include) with IntelliSense auto-seeded on first run. Long scripts split across files: await nexus.include("./lib/helpers.js") loads a plain .js file as a module and resolves to its exports, with relative paths resolving against the file they are written in. Each script runs in an isolated worker_threads Worker so runaway loops can be stopped in <100 ms. Macros on the script's session are suspended automatically (configurable via nexus.scripts.macroPolicy and the per-script @allow-macros header); macros on unrelated sessions keep firing normally. Scripts require a trusted workspace — Restricted Mode disables them. Minimal example:
/**
* @nexus-script
* @name Quick login check
* @target-type ssh
*/
await expect(/[$#] $/, { timeout: 10_000 });
await sendLine("uname -a");
const out = await expect(/[$#] $/);
log.info("kernel:", out.before.trim());
See the full scripting guide for the complete API reference, header fields, match-window semantics, error-handling patterns, macro coordination, and examples/scripts/ for seven runnable scripts demonstrating if / while / for loops, retries, polling, user interaction, and complete multi-step procedures.
Folders for Macros and Scripts — Group Terminal Macros and Nexus Scripts into folders, the same way servers and serial profiles are organized in the Connectivity Hub. Create a macro folder explicitly (New Folder) or by moving/dragging a macro into it; script folders are just directories under the scripts folder — create one with New Folder, or give New Script a folder/name path and Nexus creates the folder for you. A folder is yours to create and persists even while empty; removing a macro folder re-parents its macros instead of deleting them. See the macro guide and the scripting guide.
Web Extension Fallback — Graceful degradation in browser-based VS Code (SSH/serial features require desktop runtime).
Getting Started
Nexus Terminal is available from both the VS Code Marketplace and Open VSX registries.
Requires VS Code 1.105 or newer (or an Open VSX-compatible editor built on that API level). Older hosts are not offered the extension by the Marketplace, and installing the VSIX by hand on one is refused.
First Use Flow
- Open the Nexus sidebar and create a profile with
Nexus: Add Profile, Nexus: Add Server, Nexus: Add Serial Profile, or Nexus: Add Local Shell Profile — or sync your whole device inventory in one go with Nexus: Add Inventory Source (NetBox, EVE-NG…).
- Select Connect / Open Local Shell on the profile to open an SSH, Serial, or Local Shell terminal.
- For SSH profiles, open File Explorer and run Browse Files to choose the connected profile and browse SFTP files.
- Open Port Forwarding, add a tunnel with
Nexus: Add Tunnel, assign an SSH server, then select Start.
- Create repeatable terminal input with
Nexus: Add Blank Macro or Add Macro From Template; create longer automation with Nexus: New Nexus Script.
- Open Settings and use Encrypted Backup to save a password-protected backup, or Export for Sharing to create a sanitized export without secrets.
Install from VS Code Marketplace
- Open VS Code and go to the Extensions view (
Ctrl+Shift+X)
- Search for Nexus Terminal
- Select the listing from the Visual Studio Marketplace
- Click Install
- Open the Nexus sidebar (activity bar icon)
Install from Open VSX
- Open your Open VSX-compatible editor (for example VSCodium, Eclipse Theia, or Gitpod).
- Go to the Extensions view and search for Nexus Terminal in the Open VSX registry, then click Install.
- Or install directly from a downloaded VSIX:
Extensions > ... > Install from VSIX... and select the package file.
- Open the Nexus sidebar (activity bar icon).
Install from VSIX
- Download the
.vsix from GitHub Releases
- In VS Code or Open VSX-compatible editors:
Extensions > ... > Install from VSIX...
- Open the Nexus sidebar (activity bar icon)
Add a Server
- Click
+ in the Connectivity Hub title bar, or run Nexus: Add Server from the command palette
- Enter host, port, username, and authentication details (password, private key, or SSH agent)
- Optionally configure a proxy (SSH jump host, SOCKS5, or HTTP CONNECT) under the Proxy section
- Right-click the server and select Connect to open a terminal session
- To set up key-based auth: right-click the server → Deploy SSH Key → select or generate a key → the public key is deployed automatically
Connect Through a Proxy
If your target server is behind a firewall or bastion host:
- SSH Jump Host — First add the bastion server as a regular server profile, then edit the target server and set its proxy to "SSH Jump Host", selecting the bastion from the dropdown. Multi-hop chains (A → B → C) work automatically.
- SOCKS5 / HTTP CONNECT — Edit the target server and set its proxy type, entering the proxy host, port, and optional credentials. Proxy passwords are stored securely in VS Code SecretStorage.
Sync Servers from NetBox
If your device inventory already lives in NetBox, you don't have to re-type it:
- Run
Nexus: Add Inventory Source (NetBox, EVE-NG…) and choose NetBox — the first step is choosing a provider — or open Settings → Inventory Sources, which lists every configured source with inline Sync Now, Edit, Template Rules, and Remove
- Enter your NetBox base URL and an API token with read access to DCIM (and Virtualization, if you include VMs). The token is stored in VS Code SecretStorage. Test Connection confirms the URL is reachable and the token is accepted — it does not check that the token can read your devices, so a token NetBox accepts but hasn't granted DCIM access will pass here and fail on the first sync
- Optionally narrow the sync with a device filter (e.g.
status=active&site=syd), shape the folder layout with a template ({site}/{rack} by default), and set a Target Folder to keep synced servers under
- Pick an Auth Profile so the servers the sync creates can actually connect — choose an existing profile or create one inline without leaving the form. Its username fills the Default SSH Username field; with (None), servers use the default username with SSH agent authentication
- If the base URL is
https:// and your NetBox is behind a self-signed certificate — or you reach it by IP address and its certificate does not list that address (a certificate can cover an IP, so check before assuming) — tick Allow a Self-Signed or Mismatched Certificate under Advanced options. It is off by default; read the note below the list before turning it on
- Save, then choose Sync Now. The plan is shown before anything is applied — how many servers will be added, updated, moved, or removed, and, when credentials would change, exactly which servers by name under Show Warnings
Allow a Self-Signed or Mismatched Certificate is the same option EVE-NG sources have, doing the same thing: Nexus connects over HTTPS without checking the server's certificate for that one source. The traffic is still encrypted, but it is no longer authenticated — anything on the network path can intercept it, and your NetBox API token is sent over that connection, on every request. That is the part worth pausing on: the token is a bearer credential with nothing else standing behind it, so anyone who captures it has your NetBox's read access until you revoke it. Reasonable for a self-hosted NetBox on a network you trust; not for one reachable from outside it. It applies to that source alone — nothing else in VS Code is affected — and it does nothing at all on an http:// base URL, which is not encrypted in the first place. Two things to know before you turn it on: if you reach NetBox through a proxy, this connection bypasses VS Code's http.proxy setting and goes direct, so a proxied source can start failing for reasons that have nothing to do with the certificate; and every sync that actually runs unverified says so in its plan, by design, so the choice does not go quiet after you make it. Leave it off and use a trusted certificate where you can. If you hit a certificate error before finding this, the error itself names the option.
One-time prompt on upgrade. Adding this option changed the NetBox source form, and Nexus asks you to re-confirm handing a changed provider your saved credentials whenever that happens. Existing NetBox sources will therefore prompt once on their next sync — exactly as EVE-NG sources did in 2.8.190. Confirm once and it does not come back.
A device NetBox has no usable IP for is not skipped. It arrives as a server with no address — visible in the tree, marked (no address), and counted in the plan's warnings — keeping its folder and settings until NetBox gives it an address, which the next sync fills in on that same server. It can't connect in the meantime, and asking it to says exactly that rather than failing inside a handshake (see Servers with no address yet).
A device that carries an out-of-band IP in NetBox (oob_ip) also fills that server's IPMI / BMC Host, so ${profile.ipmiHost} macros — the IPMI SOL console and BMC web console templates — work on synced servers without typing an address anywhere. A value you typed by hand is never overwritten, clearing the field on one server is a per-server opt-out later syncs respect, and a device that stops reporting an out-of-band IP keeps its last known address rather than having it erased. Where an address you typed already matches exactly what the device reports — the usual outcome of copying it out of NetBox — the sync starts keeping that field current: nothing visible changes, and from then on it follows the BMC when it is re-addressed at the source. An address NetBox reports that can't be used as a host — a URL, say — is reported in the plan's warnings instead of being stored. Removing a source with Keep Servers and reclaiming its servers later preserves all of this. (One caveat if you move between versions: syncing on a build older than 2.8.97 drops the record of which addresses the sync owns. The addresses themselves survive, and any server whose address still matches its device picks the record back up on the next sync from a current build; for the rest — those whose BMC also moved meanwhile — clearing the IPMI / BMC Host hands the field back to the sync.)
A synced server's own Host and Port now follow that same discipline. Earlier builds took them from the source on every sync, so an address you corrected by hand was silently overwritten on the next one; from 2.8.189 they behave like every other synced field — the sync keeps them current while the record still carries exactly what the sync last wrote, and hands off for good once you have edited them. A device that genuinely moves at the source is still followed. Lab nodes get one extra piece of care: EVE-NG hands out console ports dynamically, so a restarted node often lands on a new one, and a Refresh Lab Status stores the new port so the next connect goes to the right place instead of a dead one. Only a port the sync owns is healed that way — a port you set by hand never is — and it is the next connect that uses it; a terminal already open keeps the port it connected with. (The same version caveat as above applies: syncing on a build older than 2.8.189 leaves no record of which addresses the sync owns. A server whose address still matches its device picks the record up on the next sync from a current build; one whose address moved at the source in between reads as hand-edited and stops following until you set it back to the device's address.)
Run Sync Now again whenever devices change at the source: renames and rack moves follow, and a device that disappears from NetBox is handled per the source's Removed-Device Policy — moved to an _orphaned subfolder (the default, which keeps its settings in case it returns), deleted, or kept in place.
You can also re-sync straight from the tree: the folder a source syncs into carries an inline sync icon in the Command Center. It appears only where the answer is unambiguous — the folder has to exist, and exactly one source can target it, so two sources sharing a folder get no icon and neither does a source that syncs into the root. The same icon appears for every kind of source, EVE-NG labs included.
Removing a source (Remove, beside Sync Now) asks what to do with the servers it created: Delete Servers, or Keep Servers as ordinary servers in your list. Keeping them doesn't strand them — each kept server records which device and which NetBox it was synced from, so if you add the same NetBox back later, the sync notices and asks once: Adopt Existing re-links those servers instead of adding copies — each keeps its saved credentials and settings, the source takes over its name, address and folder from then on, and its Removed-Device Policy now applies to it like any other synced server — while Add Separately leaves them alone and adds the devices as new servers. Your answer on its own changes nothing: the sync plan still follows, counting the adoptions, and Show Warnings names every kept server alongside the device reclaiming it, so you can check each pairing before Apply.
The eligibility rule is narrow on purpose. A server is offered for adoption only if a source actually synced it, you kept it when that source was removed, it's still at the address the device reports, and the source you're syncing points at the same NetBox it was synced from (compared by base URL, so a record kept from your lab instance can never be claimed by the same device id in production). A server you created by hand is never adopted, no matter how exactly its address matches. When adoption is refused — the device changed address while detached, or two kept records claim the same device — the device is added as a new server instead, and the plan's warnings say which device and why. There is one exception, and it is what a restored id-preserving backup leaves behind: when the kept server still holds the identifier a new server for its device would need, there is nothing to add the device beside, so it is skipped rather than duplicated. The warning says that too — naming that server as the device's own former record rather than as an unrelated one, and giving the repair, which is to put it back at the device's address and reclaim it on the next sync, or delete it and let the next sync add the device fresh.
Credentials stay yours. If a source gains an auth profile later, servers from earlier syncs adopt it on the next sync — but only servers still carrying exactly what the sync gave them. A server whose username or authentication you've edited keeps its own credentials (use Apply Auth Profile on it or its folder if you do want it on the profile), and setting one synced server's Auth Profile back to (None) is a per-server opt-out that later syncs respect. That opt-out survives remove-and-re-add, too: a link you cleared before the source was removed stays cleared after the source adopts the server back, while a kept server the old source never gave a profile picks one up on the reclaim, exactly as a newly synced server does. One combination is refused up front: a private-key profile that carries no key file works fine on a server that brings its own key, but a synced server has none to bring, so linking such a profile to a source is rejected with the reason instead of creating servers that could never log in.
Sync Servers from an EVE-NG Lab
EVE-NG labs are an inventory source too, and the shape is the same: labs become folders, nodes become servers, each pointed at the node's native telnet console.
- Run
Nexus: Add Inventory Source (NetBox, EVE-NG…), choose EVE-NG, and enter the base URL of the EVE-NG web UI plus the username and password you log into it with. The password is stored in VS Code SecretStorage
- Optionally set a Root Folder to scan only part of the lab tree, a Lab Filter (a case-insensitive substring of a lab's full path), and a Console Host Override for when EVE-NG sits behind NAT and reports console addresses you cannot reach
- Include Stopped Nodes is on by default. Turning it off makes a stopped node look deleted to the sync, so the source's Removed-Device Policy applies to it — leave it on unless you only ever want running gear
- If the base URL is
https:// and the server holds EVE-NG's own self-signed certificate — or you reach it by IP address and its certificate does not list that address (a certificate can cover an IP, so check before assuming) — tick Allow a Self-Signed or Mismatched Certificate under Advanced options. It is off by default; read the note below the list before turning it on
- Save, then Sync Now. As with any source, the plan is shown before anything is applied
Allow a Self-Signed or Mismatched Certificate is the honest name for what it does: Nexus connects over HTTPS without checking the server's certificate for that one source. The traffic is still encrypted, but it is no longer authenticated — anything on the network path between you and the lab can intercept it, and the EVE-NG username and password are sent over that connection. It is a reasonable trade for a lab box on a network you trust, which is what EVE-NG usually is; it is not reasonable for a server reachable from outside that network. It applies to that source alone — nothing else in VS Code is affected — and it does nothing at all on an http:// base URL, which is not encrypted in the first place. Leave it off and use a trusted certificate where you can. If you hit a certificate error before finding this, the error itself now names the option.
Each lab becomes a folder under the source's Target Folder, named after the lab file, nested under whatever folders it sits in relative to the Root Folder. A node with a native telnet console arrives as a telnet server on the console's own port. When EVE-NG reports that console on 127.0.0.1 or 0.0.0.0 — the usual answer, since it is describing its own machine — Nexus substitutes the host from the base URL, and a Console Host Override wins over both.
Rename nodes freely; rename labs deliberately. A node renamed inside its lab keeps its server — the name just follows on the next sync, as with any other source. A lab is different: EVE-NG offers no identifier for a lab that survives a rename, so Nexus identifies a node by its lab's path plus its node id, and renaming or moving a lab makes every node in it look like a brand-new device. The servers you had are handed to the source's Removed-Device Policy — moved to _orphaned with the default setting — and the nodes come back as fresh servers, without the credentials, jump host or other per-server settings you had put on the old ones. Nothing is lost silently (the plan shows the removals and the adds before it applies them), but there is no way to carry those edits across: settle the lab tree first, then invest in per-server settings.
Nodes with an HTML5/VNC console, and nodes that have no console address yet, are still imported — as servers with no address. The two are not the same wait, though the warning wording covers both: a stopped node is temporary and gets its address the moment it starts, while an HTML5/VNC-only node already has a working console — it simply isn't telnet, which is what Nexus speaks to a lab node — so it stays a placeholder for good, until you change that node's console type to telnet in EVE-NG. One warning line mentions them, and the sync owns it: it gives the total and, when both apply, splits it into the placeholders this sync just added and the ones that were already placeholders from an earlier sync. They are deliberately not dropped: a device missing from the tree reads as deleted at the source, and the source's Removed-Device Policy would act on it. What such a placeholder can and can't do is below, in Servers with no address yet.
A sync is bounded rather than open-ended, so a huge or unresponsive installation can't hang it: the crawl stops at 1,000 labs, 10,000 nodes, 12 folder levels, 2,000 folder listings, or 120 seconds — whichever comes first — and the plan's warnings name what it didn't reach. A crawl that stopped short never prunes: servers whose labs it never got to are left alone instead of being read as deleted.
Community edition is the certified target. The client is edition-aware and works against Professional, but a Pro server adds a warning to every sync saying so: lab discovery and console mapping are validated against Community, and Pro's differences are not yet covered.
See which labs are running, live. Just sync — a completed EVE-NG sync brings every node's running/stopped state up to date, no extra step, including the stopped nodes Include Stopped Nodes leaves out of the sync itself. (A crawl that stopped at one of its limits updates only what it reached.) Between syncs, run Refresh Lab Status from the Command Palette, or set the source's Lab Status Poll Interval (seconds) under Advanced options to poll while the Command Center is open — it is per source (0–3600, whole seconds, 0 = off), so a busy lab can poll every 30 seconds while a quiet one stays off. Read the note on EVE-NG sessions below before turning it on. Running EVE-NG nodes get a green dot with a (running) tag, while stopped ones get a hollow grey dot and a (stopped) tag. A green ▶ rides on every running node's row and on the lab folder holding it, so an at-a-glance look at the tree tells you which labs are up. A node you are already connected to keeps its plug icon, and there the ▶ and the (running) tag are what carry its lab state.
Give Nexus its own EVE-NG account. EVE-NG Community allows only one active session per user account — confirmed in direct testing, where every poll deauthenticated the browser session; Professional is untested in this respect. Whichever login happened most recently is the one that stays: sync or poll while you are signed in as the same user and Nexus logs you out of the EVE-NG web UI — and when you log back in, Nexus's session is the one that goes. It also shows up as an occasional mid-sync session timed out / HTTP 412 failure. Nexus recovers from that by logging in again once, silently, which works but evicts the browser again in turn; with polling on and a browser open the two will keep taking the session off each other. Create a second EVE-NG account for Nexus and the problem disappears. Failing that, leave Lab Status Poll Interval at 0 and sync when you are not using the web UI.
Start and stop nodes from the tree. Right-click an EVE-NG node whose state is known and choose Start Node (on a stopped one) or Stop Node (on a running one); Nexus issues the start/stop and refreshes the status a beat later once the node has begun booting. Tested against EVE-NG Community; EVE-NG Professional support is preliminary.
Servers with no address yet
A sync creates a server for every device it finds, including one it has no address for — a stopped or VNC-only EVE-NG node, a NetBox device with no usable IP. Rather than vanishing from the tree (which would read as deleted at the source and hand it to the Removed-Device Policy), it arrives as a placeholder: a real row, marked (no address), with its folder, its auth profile and its BMC settings intact. Only the console endpoint is missing.
Everything that needs that endpoint says so by name instead of failing later:
- Connect, Test Connection, Deploy SSH Key, Browse Files, and assigning a tunnel each refuse up front, naming the server and the reason — no password prompt, no handshake against an empty host. Duplicate refuses too, since a copy would be a placeholder no source could ever fill in.
- Connect Folder Servers skips the placeholders in a folder and tells you how many it skipped, rather than raising one notice per stopped node — an EVE-NG lab folder is mostly stopped nodes.
- It is left out of the Jump Host and IPMI Gateway pickers. A choice you saved earlier, on a server that went addressless since, is refused before any credential is read — and a BMC command routed through such a gateway aborts with the reason rather than quietly running on your own machine.
- BMC actions still work on a placeholder that has a BMC address of its own, because the out-of-band address isn't part of the console endpoint.
When the device gains an address, the next sync fills it in on that same server — same row, same folder, same settings — and it starts connecting. Not every placeholder is waiting on that, though: an HTML5/VNC-only EVE-NG node will not gain one, because its console already exists and simply isn't telnet. If the address goes away again the server reverts to a placeholder, unless it's an address you typed yourself, which is kept. You can give one an address by hand too: Host and Port aren't required when editing a placeholder, typing a host makes it an ordinary addressed server on save, and the Port field is pre-filled with the right default for its protocol (23 for telnet).
Apply a Device Template to Synced Servers
A source's auth profile is one setting shared across every server it creates. A device template carries the rest: a proxy, a multiplexing choice, a legacy-algorithm toggle, session logging, and a BMC login (its own IPMI Auth Profile and IPMI Gateway) — a reusable bundle applied to matched devices so you don't set them on each synced server by hand.
- Create one with
Nexus: New Device Template (or Manage Device Templates). For each field, choose Not set, Fill (write only where the server has nothing set), or Override (replace source data and values earlier syncs wrote — but never a value you set by hand). Templates hold no secrets, so a templated proxy still prompts for its password on first connect.
- Bind it to devices. The simplest path is the Device Template select in the inventory source form, which applies one template to every device that source syncs. For finer control, run
Nexus: Edit Template Rules and add filter rules like role=switch&site=syd (keys role, site, location, rack, tenant, status, platform, tag, name; a repeated key is OR, distinct keys are AND, an empty filter matches every device), each pointing at a template.
- When more than one rule matches a device, the settings cascade per field: the most specific rule wins each setting it defines, while broader rules supply the rest — the order you added the rules never decides it.
- The ownership rules match the rest of inventory sync: your own edits always win, clearing a template-applied value is a per-server opt-out, and changes apply on each source's next sync rather than the moment you save the template.
To apply a template to servers already in a folder without waiting for a sync, right-click the folder and choose Apply Device Template. Values written that way count as your own edits, so later syncs leave them alone — which is also how you overwrite a pre-template hand value that Override deliberately preserves.
Reach a device on either its IPv4 or its IPv6
A server can hold a second SSH address in its Alternate host field (Advanced section of the server form) — typically the IPv6 to its IPv4, or the reverse. When a terminal can't reach the primary Host at the connection level (no route, refused, timed out, or a name that won't resolve), Nexus retries once against the alternate and the terminal banner names the address that won. It falls back only on those transport-level failures — an authentication, host-key, key, or proxy failure is never retried on the other address, since it would fail there too and could cost a second credential prompt. This covers the SSH terminal only; tunnels and jump hosts stay on the primary Host.
From NetBox, this fills itself in. Set the source's Primary IP Family — Automatic (NetBox's own primary IP, IPv6 when a device has both), Prefer IPv4, or Prefer IPv6 — to choose which family becomes the Host; when the device carries both, the other family's primary IP is written into Alternate host automatically. That alternate is sync-owned like every other synced field: an address you type in yourself is never overwritten, clearing it is a per-server opt-out, and a device that stops reporting a second family keeps its last known alternate. The out-of-band (BMC) address is not affected by the family choice.
Add a Serial Device
- Click the serial icon in the Connectivity Hub title bar, or run
Nexus: Add Serial Profile
- Use Scan Serial Ports to discover available ports
- Choose Standard or Smart Follow connection mode, then configure baud rate, data bits, parity, and stop bits
- Right-click the profile and select Connect
- Smart Follow profiles coexist with other serial sessions on different ports, print status updates in the terminal when they switch ports or wait for reattach, silently reconnect only to the previously approved device, and prompt before switching to unfamiliar free ports. Connecting any serial profile is blocked only when the target port is already held by another Nexus serial session.
Add a Local Shell Profile
- Run
Nexus: Add Local Shell Profile, or use Nexus: Add Profile and select Local Shell Profile
- Name the profile for the workflow you want to save, for example
PowerShell Admin, WSL Ubuntu, or Project Shell
- Choose VS Code Terminal Profile to pick a launchable VS Code terminal profile. Nexus lists explicit-path profiles plus common resolved profiles such as PowerShell, Git Bash, Command Prompt, and detected WSL distros when their executable can be found.
- Choose Custom Shell when you need a path, command, or arguments Nexus cannot infer. For WSL on Windows, use
C:\Windows\System32\wsl.exe; add arguments one per line when you need a distro or startup option, for example -d and Ubuntu
- Optionally set a working directory and startup command, then save the profile
- Right-click the profile and select Open Local Shell. You can open multiple sessions from the same saved Local Shell profile.
- Auto-trigger macros can match Local Shell output. Existing macros scoped to All terminals will also apply to Local Shell sessions; use profile-scoped macros for shell-specific prompts.
Add a Local Server
- Run
Nexus: Add Local Server Profile, or use Nexus: Add Profile and select Local Server
- Name it for the thing it runs —
API (dev), Mock Billing, Vite watch
- Set the executable. A bare name is looked up on
PATH; ~, ${workspaceFolder} and ${env:NAME} are expanded
- Add arguments one per line, and a working directory if the default is wrong. The directory must resolve inside a folder you have open — a profile pointing outside it is refused rather than started
- Add environment variables as
KEY=value, one per line. Three forms are distinct: KEY=value sets it, KEY= sets it to an empty string, and KEY=null unsets it for the child process even when the extension host inherited one. ${workspaceFolder} and ${env:NAME} are expanded in values
- Optionally enable Auto-Restart so the process comes back when it exits on its own. Leave the per-profile limit empty to follow Nexus Settings → Local Servers, or set your own;
0 means never restart it
- Right-click the profile and choose Start. Its output opens in a Nexus terminal, and the row shows whether it is running, restarting or failed. From the Command Palette the same commands are grouped under
Nexus Local Servers: — Nexus Local Servers: Start, Stop, Restart, Inspect Logs
Auto-restart counts consecutive failures. A server that runs for the stable-runtime threshold without exiting has its count cleared, so this bounds a crash loop rather than restarts over the profile's life — and once the limit is reached the server is marked failed and waits for you to start it again.
Macro Variables
A macro can prompt you for input every time it runs, instead of sending fixed text. Open a macro in the Macro Editor and add one or more entries under Variables: a name, an optional label (the prompt text shown in the input box), an optional default, Mask input (never stored) for secrets like passwords, and whether to remember the last value entered in the current VS Code window.
Reference a declared variable in the macro's text as $name or ${name} — both forms work once name is declared. A placeholder whose name was never declared as a variable is sent to the terminal exactly as written, so a typo in a variable name doesn't block the macro; watch the live hints under the Text field in the Macro Editor to catch it.
Running the macro opens one input box per declared-and-used variable, in declaration order, with a Back button to return to the previous prompt (not shown on the first one). Pressing Esc or closing the box at any step cancels the whole run — nothing is sent. Once every prompt is answered, Nexus sends the filled-in text to the terminal you invoked the macro from, even if you've since switched to a different terminal tab.
Prompted variables are for values that genuinely change per run. The IPMI SOL console template no longer needs any: it reads everything from the server profile instead.
Text: ipmitool -I lanplus -H ${profile.ipmiHost} -U ${profile.ipmiUsername} -E sol activate
Run in: Local terminal
Provide IPMI credentials: on
Nothing is prompted for. ${profile.ipmiHost} and ${profile.ipmiUsername} come from the server profile you run the macro against (its IPMI / BMC Host and the IPMI Auth Profile linked beside it), and -E tells ipmitool to read the password from the environment, which the Provide IPMI credentials checkbox fills in from that same auth profile. Right-click a server in the Connectivity Hub → Run Macro on Server…, pick the macro, and the completed command runs in a fresh local terminal. If no password is saved for the profile, Nexus asks for one — masked, used for that run only, never stored.
The checkbox is what authorizes the hand-over, and it is off unless you tick it. A macro that uses IPMI tokens without it still runs; ipmitool simply prompts or fails, and Nexus tells you which switch is missing. A macro that arrives from a colleague's share file or from a restored backup always arrives with the box clear, whatever the file says — consent belongs to the person who ticked it here. Re-tick it on the macros you trust after a restore.
A macro can prompt for input, or auto-trigger from terminal output — not both. If a macro somehow ends up with both, Nexus treats it as a plain, non-auto-triggering macro instead of running either behavior partially.
See the macro guide for the full variable syntax table, the '${password}' quoting idiom, and the HISTCONTROL=ignorespace trick for keeping a value out of the remote shell's history.
Organizing Macros and Scripts into Folders
Both the Macros view and the Scripts view group their contents into folders, matching the Connectivity Hub. Folders are yours to create — an empty folder stays until you remove it.
For macros, folders are a display grouping: use New Folder in the Macros view title bar to create one, then drag a macro onto it (or right-click a macro → Move to Folder) to move it in. Running Move to Folder from the Command Palette with nothing selected opens a multi-select quick pick first, so sorting a flat pile of macros into folders is a bulk operation rather than one drag per macro. Removing a folder re-parents its macros to the parent folder instead of deleting them, and reordering with Move Up / Move Down only ever swaps a macro with its neighbor in the same folder.
For scripts, a folder is a real directory under your configured scripts folder (nexus.scripts.path, default .nexus/scripts). Use New Folder in the Scripts view, or give New Script a path like cisco/backup and Nexus creates cisco/ for you if it doesn't exist yet. A folder's right-click menu repeats New Script and New Folder scoped to that folder, plus Reveal in Explorer. The Scripts view scans up to 10 folder levels deep and up to 500 directories/files (scripts included) before stopping, to keep a misconfigured scripts path from hanging the sidebar; if that happens, a row pinned at the top of the view links straight to the setting.
Both views validate folder paths the same way: . and .. segments are rejected, and a \ is rejected with a message telling you to use / — a path like ../../home/you/something can never write or move something outside where it belongs.
Set Up Port Forwarding
- Switch to the Port Forwarding section in the sidebar
- Click
+ to add a tunnel profile and choose the type:
- Local Forward (-L): specify local port, remote host, and remote port
- Reverse Forward (-R): specify remote bind address/port and local target host/port
- Dynamic SOCKS5 (-D): specify local port (default 1080) — routes traffic to any destination through SSH
- Assign an SSH server to the tunnel, or leave it unassigned to choose at start time
- Right-click the tunnel and select Start
You can also drag a tunnel profile onto a server in the Connectivity Hub to start it immediately.
Browse Remote Files
- Connect to an SSH server
- Open the File Explorer section in the Nexus sidebar
- Click the server icon to set it as the active SFTP target
- Browse, download, or drag files between remote directories
In an SSH profile's advanced options, enable Open File Explorer on first connection to start SFTP automatically after normal Connect when the File Explorer is not already showing that server. Saving it checked disables it on any other SSH profile, and it does not run when that profile is used as a jump host, tunnel connection, group connect item, or script-started connection.
Saving a remote file in the editor, and creating one with New File, leave permissions alone: an existing file keeps its own mode, and a new file is created under the remote server's umask. Earlier releases wrote through a path that chmod'd every file it opened to 0666, which quietly made a 0600 key or credentials file world-readable and world-writable on save.
Save as Root
SFTP writes as the logged-in SSH user, so editing a root-owned file normally fails. If your SSH user has sudo rights on the remote host, Nexus can save it anyway:
- Reactive: edit and save a root-owned file as usual. If the write is denied, Nexus offers to retry with
sudo. Declining suppresses the offer for that file until you close its editor tab or explicitly choose Edit as Root (sudo).
- Proactive: right-click a file in the File Explorer and choose Edit as Root (sudo) to mark it editable up front — needed for files with no write bits at all (e.g.
0444), which VS Code otherwise blocks from editing before the save is ever attempted. This only helps with writes: elevated reads are not supported, so a file you can't even read as your SSH user (e.g. 0440 root:root on /etc/sudoers) still fails to open, Edit as Root notwithstanding.
Elevation covers saving file contents only — deleting, renaming, and creating directories are not elevated, because those need write access to the parent directory rather than to the file. So you can save a new file into a root-owned directory and then find you can't remove it from the File Explorer; do that from a terminal on the host. Extending elevation to those operations is tracked in #32.
The file is staged to a temporary path over SFTP and then moved into place with sudo over an SSH exec channel. Your sudo password (only asked if the account needs one) is piped directly to that channel — it is never written to disk, VS Code's secret storage, or any log. By default the password isn't kept between saves; enable nexus.sftp.sudo.rememberPasswordForSession to keep it in memory until that server disconnects or the window closes. Either way, the remote host's own sudo credential timestamp (typically ~5 minutes) can let consecutive saves skip the password prompt regardless of this setting. A short grace window (30 seconds) after you type the password also covers an immediately-following elevated write to the same server — such as VS Code's own Save As, which issues two writes for one save — without prompting twice.
For an existing file, the write goes through the file's own inode, so its owner, mode, ACLs, and hard links are preserved exactly. A brand-new file — or an existing one recreated because it vanished remotely between open and save (log rotation, a concurrent delete) — is created using the mode last observed for it, or 644 if none was ever observed. That restoration is read/write bits only — a recreated file never comes back with execute or setuid/setgid/sticky bits, which can be narrowed but never restored. A staged write the server refuses outright — no space left, an over-quota home directory, an appliance rejecting the path — fails the save instead of being installed over the target; ssh2 reports a rejected SFTP write and a completed one with the same stream event, so such a save used to be reported as done and then moved a truncated file into place. The write is not atomic — a disk-full condition or a dropped connection partway through can leave the target partially written with no backup, so if a save fails, keep the editor open and retry rather than closing it. Sudoers policies requiring a TTY (requiretty) are not supported over this path — a plain-language error explains that up front, along with how to work around it. The install writes through a shell redirect (cat < temp > target), which follows symlinks and does not check the target's type first: if another local, non-root account on the remote host can write to the target's parent directory, it can swap the target for a symlink between your open and your save, and the elevated write lands root-owned content wherever that link points — the same exposure as the common sudo tee /path idiom. Elevated saves can be turned off entirely with nexus.sftp.sudo.enabled.
Elevation depends on the SSH account actually having sudo rights on the remote host (sudoers membership, or a group like wheel/sudo) — the password Nexus asks for is normally your own login password, the same one a sudo prompt at a real terminal would ask for. If you're not in sudoers but happen to know the root password, elevation can't use it: sudo authenticates the invoking user, not root, so the root password isn't accepted in its place. The practical workaround is to add a second Nexus server profile that logs in as root over SSH and edit the file directly through that connection — only possible if the remote host's SSH server permits root login. Elevating with the root password via su instead of sudo is not supported and isn't planned: unlike sudo -S, su on Linux reads its password from /dev/tty rather than stdin, and Nexus has no PTY channel available to drive that prompt. One host-configuration wrinkle worth knowing: if the remote sudoers file sets Defaults rootpw (or targetpw), sudo actually wants root's password instead of yours — a password rejected on such a host isn't necessarily wrong, just the wrong kind, and the retry prompt calls this out.
Transfers to and from a Windows network share
VS Code blocks access to Windows network paths (\\server\share) unless the host is listed in its own security.allowedUNCHosts setting. Nexus reads and writes the local side of a transfer through Node directly, so a blocked share fails with the real reason and names the host — a drag-and-drop upload from one used to be counted as a skipped file and finish as Upload completed with skips, having moved nothing.
A blocked transfer offers Allow Host… and Open Settings. Allow Host… asks again in a modal that names both the host and the setting, and only a positive answer there appends the host to security.allowedUNCHosts in your user settings; declining at either step changes nothing. security.restrictUNCAccess itself is never touched — the restriction stays on, one host is added to the list it consults. The extension host is handed that list once when it starts, so Nexus re-checks the path afterwards: if it works now, it just asks you to repeat the transfer, and it offers Reload Window only when the change genuinely hasn't taken effect yet. One prompt per host rather than per file, so a directory upload from a blocked share asks once.
Downloading into a network share no longer takes the server's other sessions with it. The local file was opened deep inside the SSH client's own callback stack, so VS Code's UNC check threw there and tore down the shared connection — every terminal on that server disconnected at once. The destination is now probed first, on Nexus's own stack, without creating or truncating anything.
A transfer whose local side is a UNC path also runs a smaller pipeline — 8 concurrent 32 KB operations instead of the default 64 — because the default queues far more parallel file operations than Node's thread pool can serve and stalls the whole extension host whenever the share does. A mapped drive letter (Z:\…) can't be told from a local disk without Windows API calls, so it keeps the default profile.
Blocked hosts, and the byte count of every completed transfer, are recorded in the Nexus SSH output channel.
Directory Sync (Follow Terminal Directory)
The File Explorer can track whichever SSH terminal you're focused on, so it moves with that terminal's current directory instead of sitting wherever you last navigated.
This is continuous sync — not a one-off jump — for any shell that announces its own directory. fish (≥ 3.x) does this unconditionally, and prompt frameworks like starship do too, using the same OSC 7 escape sequence Nexus already reads out of the terminal's own output. Plain bash and zsh don't announce it by default, but one snippet each fixes that for good:
# ~/.bashrc — let Nexus follow this shell's directory
PROMPT_COMMAND='printf "\033]7;file://%s%s\033\\" "$HOSTNAME" "$PWD"'"${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
# ~/.zshrc — let Nexus follow this shell's directory
__nexus_osc7() { printf '\033]7;file://%s%s\033\\' "${HOST}" "$PWD"; }
precmd_functions+=(__nexus_osc7)
(zsh sets $HOST automatically — $HOSTNAME is frequently unset there, unlike in bash.) Add either once and that shell reports its directory continuously from then on — no waiting for a future Nexus release.
For anything that isn't a POSIX shell — Cisco IOS, Juniper, FortiOS, or any other device that will never emit that escape sequence — run Go to Terminal Directory to jump the File Explorer to your terminal's current directory on demand, using a best-effort read of the visible prompt.
Turn continuous following on or off from the toggle at the left of the File Explorer title bar, or from the right-click menu on the . row that shows your current directory — never from Settings. Turning it on jumps immediately to the focused terminal's already-known directory if one is on record and the explorer is idle and visible, rather than waiting for the next cd or focus change. Navigating manually (Go to Path, Go Home, or ..) pauses following rather than fighting it; one click on Resume Following Terminal Directory jumps straight back to the terminal's directory.
If you turn following on for a terminal that hasn't reported a directory yet, Nexus tells you right away instead of leaving the toggle looking broken: Show Me How drops the rc one-liner into the Nexus Directory Sync output channel, and Go to Terminal Directory jumps there manually in the meantime. That notice shows once per server per window.
Nexus never types anything into your session to make this work, in this release. Every part of this feature only reads what the shell already sends — it either volunteers its own directory, or you ask for it explicitly with Go to Terminal Directory.
Open a profile from the command line
Nexus registers a vscode:// URI handler so you can open any saved profile — SSH, Serial, or Local Shell — from a terminal, a script, a browser link, or a CI job. The profile type is detected automatically from the name (or id) you give, and Nexus runs the matching connect action.
URI forms:
vscode://sentriflow.vscode-nexterminal/<name> # open the named profile (SSH / Serial / Local Shell)
vscode://sentriflow.vscode-nexterminal/<name>?sftp # SSH only: connect + open File Explorer (SFTP)
vscode://sentriflow.vscode-nexterminal/<name>?id=<uuid> # use profile id instead of name
<name> is case-insensitive and matched across all profile types; the first match is used when multiple profiles share a name (a warning suggests ?id= to disambiguate).
?id=<uuid> overrides the name for unambiguous lookup. Find a profile's id in Nexus → Settings → Export Configuration.
?sftp is SSH-only — it opens the SSH terminal and the File Explorer for SFTP browsing in one click. Requesting ?sftp on a Serial or Local Shell profile shows an error.
Open from the command line:
code --open-url "vscode://sentriflow.vscode-nexterminal/Production"
Note: Use --open-url, not --file-uri or --folder-uri — those open local files/folders and do not route to the extension's URI handler.
Shell alias (bash / zsh):
nexterm() { code --open-url "vscode://sentriflow.vscode-nexterminal/$1"; }
# Usage (works for SSH, Serial, and Local Shell profiles by name):
nexterm Production
nexterm "My Server"
nexterm "Lab Console" # a saved Serial profile
nexterm Production?sftp # SSH only
Add this to your ~/.bashrc or ~/.zshrc to make it permanent.
PowerShell function:
function nexterm($p) { code --open-url "vscode://sentriflow.vscode-nexterminal/$p" }
# Usage:
nexterm Production
nexterm "My Server"
nexterm "Production?sftp"
Add this to your PowerShell profile ($PROFILE) to make it permanent.
Export / Import Configuration
Encrypted Backup: Run Nexus: Export Backup to create a master-password-protected backup including all profiles, settings, saved credentials, the user .ssh folder, and the configured Nexus scripts folder
Share Export: Run Nexus: Export Configuration to create a sanitized export safe for sharing (credentials stripped, learned hardware identifiers removed, IDs remapped)
Import: Run Nexus: Import… — also reachable from the Connectivity Hub's ... overflow menu, the Connectivity Hub welcome view, and the Data Management section of Settings. It asks what you're importing, then opens the matching picker:
- Paste Host List from Clipboard / Host List File… — a CSV export, a device inventory, or a plain hostname list
- MobaXterm INI File… — sessions from a MobaXterm
.ini bookmarks export
- SecureCRT XML Export… / SecureCRT Sessions Folder… — sessions from SecureCRT
- Nexus Export File… — an encrypted backup or a shared config (
.json). Merge skips existing local .ssh / script files; Replace overwrites files present in the backup but does not delete extra local files.
If the file you picked doesn't match what you told the picker — say, you chose "Host List File…" but selected a MobaXterm export — Nexus names the mismatch and offers a one-click button to re-import it as the format it actually looks like, instead of a dead end.
Nexus: Import from MobaXterm, Nexus: Import from SecureCRT, and Nexus: Import Servers from List (CSV/Text) remain available in the command palette as direct shortcuts into those same pickers, for anyone who already knows exactly what they're importing.
Import from MobaXterm or SecureCRT
Power users migrating from other SSH clients can import their connection profiles directly:
- MobaXterm: choose MobaXterm INI File… and select your MobaXterm
.ini configuration file. SSH sessions are imported with their folder organization preserved.
- SecureCRT: choose SecureCRT XML Export… or SecureCRT Sessions Folder… and select the corresponding export file or
Sessions/ directory. SSH sessions are imported with their hierarchy as folder groups.
Both importers extract hostname, port, and username from each SSH session. Non-SSH sessions (RDP, Telnet, etc.) are skipped. Imported servers default to password authentication.
Import a device list (CSV / text)
For everyone else — a spreadsheet export, a device inventory, or just a list of hostnames — choose Paste Host List from Clipboard or Host List File… (.csv, .txt, .tsv, up to 2 MB and 5,000 rows; anything beyond the row cap is reported, not silently dropped).
Accepted formats:
- A header row naming columns in any order:
host/hostname/address/ip, name/label/device, user/username, port, folder/group/site.
- No header, positional:
host[,name[,username[,port[,folder]]]] — note the third field is read as a username, not a folder. A bare host,name,folder list needs a header row (e.g. host,name,folder) so the columns are matched by name instead of position.
- Shorthand in the host field:
user@host, host:port, user@host:port.
- Lines starting with
# and blank lines are ignored.
# host, name, user, port, folder
10.0.0.1, core-sw1, netadmin, 22, DC1/Core
10.0.0.2, core-sw2, netadmin, 22, DC1/Core
sw3.lab.example.com
netadmin@sw4.lab.example.com:2022
If any row omits a username you're prompted once for a default (pre-filled with your most common existing username). If the list has no folder column of its own you're then prompted for an optional folder prefix, applied to every row. A single confirm dialog then summarizes what's about to happen — how many servers, how many folders will be created, how many rows already exist and will be skipped, how many lines couldn't be parsed — before anything is written; a Show Skipped Lines button opens the unparsable rows in a scratch document without importing. Rows that already match an existing server (same host, port, and username — host compared case-insensitively) are skipped and the count is reported. Imported servers always use password authentication — switch to key-based auth afterward via Edit Server if needed.
Hand-writing an import file
Choosing Nexus Export File… also accepts a minimal hand-written JSON file — useful for one connection or a quick script, without going through any other importer:
{
"version": 2,
"servers": [
{
"id": "8400e8b0-8b3e-4b8a-9b1a-000000000001",
"name": "core-sw1",
"host": "10.0.0.1",
"port": 22,
"username": "netadmin",
"authType": "password",
"isHidden": false,
"group": "DC1/Core"
}
]
}
name, host, port, username, authType, and isHidden are required. group is optional (omit it for a top-level server), and so is id — Nexus fills one in for you if it's left blank or omitted; it just needs to be unique if you do supply it.
Development
npm install
npm run build
npm test
To package a VSIX:
npm run package:vsix
Key Settings
| Setting |
Default |
Description |
nexus.logging.sessionTranscripts |
true |
Enable session transcript logging |
nexus.logging.sessionLogDirectory |
(extension storage) |
Custom directory for session logs |
nexus.logging.terminalOutputTrace |
false |
Troubleshooting only: write every chunk of terminal output to the diagnostic log. Slows terminal output and stores session data — including anything echoed on screen, such as passwords — as plaintext on disk |
nexus.logging.maxFileSizeMb |
10 |
Max log file size before rotation |
nexus.logging.maxRotatedFiles |
1 |
Number of rotated log files to keep |
nexus.ssh.multiplexing.enabled |
true |
Share SSH connections across terminals, tunnels, and SFTP |
nexus.ssh.multiplexing.idleTimeout |
300 |
Seconds to keep idle multiplexed connection alive |
nexus.ssh.trustNewHosts |
true |
Auto-trust host keys on first connection (TOFU); prompt only on key change |
nexus.ssh.connectionTimeout |
60 |
SSH connection timeout in seconds |
nexus.ssh.keepaliveInterval |
10 |
Interval between SSH keepalive packets in seconds (0 disables keepalives) |
nexus.ssh.keepaliveCountMax |
3 |
Missed keepalive responses before the connection is treated as dead |
nexus.ssh.terminalType |
xterm-256color |
$TERM value reported to the remote shell |
nexus.ssh.proxyTimeout |
60 |
Proxy handshake timeout for SOCKS5 and HTTP CONNECT proxies |
nexus.tunnel.defaultConnectionMode |
shared |
shared or isolated SSH mode for tunnels |
nexus.tunnel.defaultBindAddress |
127.0.0.1 |
Default bind address for reverse tunnels |
nexus.tunnel.socks5HandshakeTimeout |
10 |
Dynamic tunnel SOCKS5 handshake timeout in seconds |
nexus.terminal.openLocation |
editor |
Where to open terminals: panel or editor tab |
nexus.terminal.keyboardPassthrough |
true |
Pass Ctrl+ key combinations to the terminal |
nexus.terminal.passthroughKeys |
[b,e,g,j,k,n,o,p,r,w] |
Which Ctrl+ keys to pass through when enabled |
nexus.terminal.macros.autoTrigger |
true |
Enable auto-trigger for macros with a triggerPattern; per-macro scope can limit matching to the active terminal or a matching profile |
nexus.terminal.macros.defaultCooldown |
3 |
Default cooldown in seconds for auto-trigger macros without a per-macro override |
nexus.terminal.macros.bufferLength |
2048 |
Max characters retained per terminal for auto-trigger pattern matching |
nexus.terminal.highlighting.enabled |
true |
Enable regex-based terminal highlighting; rules are edited in the Highlighting Rules editor. The IPv6 and UUID rules ship disabled — switch either on with its per-rule checkbox in the editor |
nexus.ui.showTreeDescriptions |
true |
Show connection details beside items in the Connectivity Hub |
nexus.sftp.cacheTtlSeconds |
10 |
SFTP directory listing cache TTL |
nexus.sftp.maxCacheEntries |
500 |
Maximum cached SFTP directory listings |
nexus.sftp.autoRefreshInterval |
10 |
Polling interval for file explorer (seconds); also used as the auto-mode safety net unless recursive inotify is available |
nexus.sftp.remoteWatchMode |
auto |
Remote change detection mode: auto prefers recursive inotify, polling uses interval-based refresh only |
nexus.sftp.maxOpenFileSizeMB |
5 |
Largest single file Nexus will hold in memory — opening a remote file in the editor, and transferring a file whose reported size is 0 (pseudo-files and appliances that mis-report size have to be read to the end to find out how big they are). Ordinary uploads and downloads stream and are not limited by this |
nexus.sftp.operationTimeout |
30 |
Timeout for SFTP directory and metadata operations (listing, stat, realpath, rename, mkdir, delete) |
nexus.sftp.commandTimeout |
300 |
Timeout for remote SFTP commands, file transfers, and editor file open/save; upload/download use it as an inactivity timeout rather than a total duration cap |
nexus.sftp.deleteDepthLimit |
100 |
Safety limit for recursive delete directory depth |
nexus.sftp.deleteOperationLimit |
10000 |
Safety limit for items removed by one recursive delete |
nexus.sftp.sudo.enabled |
true |
Offer to save remote files with sudo when the SSH user lacks write permission |
nexus.sftp.sudo.rememberPasswordForSession |
false |
Keep the sudo password in memory until that server disconnects or the window closes, rather than clearing it after each save; never written to disk or secret storage. Turning this off doesn't guarantee a prompt every time — the remote host's own sudo credential timestamp can skip it regardless, and a short grace window (30 seconds) after each password entry applies either way |
nexus.networkServers.engine |
rust |
Which implementation backs the embedded TFTP and DHCP services. rust (default since 2.8.205) is a native binary packaged for all six supported platforms; node is the bundled JavaScript daemon, which is also the automatic fallback if no native binary is available here — the reason is logged and the services start either way. nexus.networkServers.dhcp.allowRelayAgents is honoured by the Rust engine only. Takes effect the next time the daemon starts |
nexus.localServers.defaultMaxAutoRestarts |
5 |
How many times in a row a local server may restart automatically, for profiles that set no limit of their own. 0 means never. Five is also the hard ceiling — the setting can ask for fewer, not more |
nexus.localServers.stableRuntimeMs |
10000 |
How long a local server must run without exiting before it counts as healthy and its consecutive-restart count is cleared |
nexus.localServers.initialBackoffMs |
500 |
Delay before the first automatic restart. Each further attempt doubles it |
nexus.localServers.maxBackoffMs |
30000 |
Ceiling on the delay between automatic restarts, however far the doubling has gone |
nexus.serial.rpcTimeout |
10 |
Timeout for serial sidecar commands in seconds |
nexus.scripts.path |
.nexus/scripts |
Directory where Nexus scripts live. Absolute paths are used as-is. Relative paths resolve against the workspace root when a folder is open, otherwise the extension's global storage. Pick a folder via Nexus Settings → Scripts → Scripts Folder |
nexus.scripts.defaultTimeoutSeconds |
30 |
Default per-wait timeout in seconds for waitFor / expect / waitAny when not specified |
nexus.scripts.macroPolicy |
suspend-all |
Macro policy while a script runs: suspend-all or keep-enabled |
nexus.scripts.maxReadSizeMb |
4 |
Largest file (in MiB) a script may read via nexus.fs.readText / readJson; range 1–16. Snapshotted when a run starts |
nexus.scripts.maxRuntimeSeconds |
1800 |
Overall runtime cap in seconds. Exceeded runs are auto-stopped with reason max-runtime-exceeded; 0 disables the cap; maximum 2147483 |
nexus.scripts.maxRuntimeMs |
1800000 |
Legacy millisecond runtime cap retained for compatibility when the seconds setting is absent |
Maintainer Notes
Documentation
See docs/functional-documentation.md for detailed architecture and design documentation.
The wire contract between the extension host and the network server daemon is specified in docs/network-server-daemon-protocol.md, written so that either side can be built from it alone.
Support
Nexus Terminal is free and open source. If it saves you time, you can say thanks with a coffee — it's appreciated but never expected, and every feature stays free regardless.

Evgeny D. — evgeny@netsectech.com.au
License
Apache 2.0
| |