netssh multi opens one pane per host in a tmux window or zellij tab.
Hosts come from names, tag:TAG (NetBox and static hosts), cluster:NAME
(NetBox virtualization clusters; devices by default, --kind vm|all),
and groups from the config (@name, nested, with cycle detection).
Every pane runs netssh HOST, so lookup, rules, and jump hosts apply.
- tmux: a new window inside tmux, else a new session that is attached;
tiled layout, pane borders with the host and a [SYNC] marker.
- zellij: a generated grid layout; a new tab inside zellij, else a new
session.
- --sync broadcasts typing to all panes; netssh sync toggles it in the
current tmux window or zellij tab.
- TUI: Space marks hosts, Ctrl+A marks all, Enter opens them together.
- Configurator: multiplexer, panes per window, groups.
NetBox SearchAll gains a cluster filter (name to cluster IDs per
instance), and cache entries keep the host's cluster for completion
and an offline fallback. Panes skip the 24-hour background refresh
(checked once by multi) and get HOME/XDG paths but no NETSSH_* values,
which would expose tokens in the process list.
testenv/tests/15-multi.sh checks real tmux and zellij sessions,
including a broadcast command arriving on all three cluster nodes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the hostname resolver strategy. It connects by the NetBox name
instead of an IP, with resolver.hostname_domain appended to names
without a dot. Its position in the chain decides whether it is always
used or only as a fallback (e.g. [primary_ip, hostname]); names that
are not valid DNS hostnames fall through to the next strategy.
Add static hosts under hosts: for machines that are not in NetBox,
with address, user, port, tags, and their own SSH options. They are
checked before NetBox (by name or shortcut), never expire, survive
cache refresh and clear, and work without any NetBox configured. The
cache overlays them after every load and stores only their last use,
so they appear in completion, aliases, the TUI and its recent list.
SSH options merge global, static host, then rules; rules can match
kind: static. Manage them with netssh hosts list|add|remove and in
netssh configure, which can now also continue without NetBox.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add netssh sftp and netssh scp. Both resolve the host like a connection
does (cache, shortcuts and rewrites, instance/host, default user and
port, SSH options and rules, --jump/--no-jump, --dry-run) and get shell
completion. The per-client flag tables handle the differences from ssh:
the port is -P, -l is a bandwidth limit (the default user goes in as
-o User=), and IPv6 addresses are bracketed in host:path. All remote
scp operands must name the same host.
Add named port forwards under ssh.forwards (global, per instance, per
rule; a more specific layer replaces a forward of the same name),
netssh tunnel HOST NAME|SPEC... (ssh -N with ExitOnForwardFailure) and
netssh --forward NAME. Specs such as 8080:localhost:80 work without
configuration. Forwards are editable in netssh configure and completed
in the shell; the TUI opens SFTP with ctrl+o and a tunnel with ctrl+t.
Host resolution moves out of runSSHWrapper into resolveTarget, shared
by ssh, sftp, scp, tunnel, and the TUI.
Options added by netssh are now inserted before the first operand or
"--": after "--", ssh read them as the destination, and scp stops
reading options at the first operand.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shortcuts.rewrites applies regex replacements after the domain suffix
is stripped, e.g. ^([a-z]+)[0-9]+- -> $1 turns fsn1-bx1.hoster.de into
fsnbx1. The shortcut works for connecting (cached hosts), shell
aliases, and Tab completion, where it is offered when the full name
does not match the typed text. Rules are editable in netssh configure,
and netssh alias --test HOSTNAME shows a name's shortcut and the cached
hosts it matches.
The shortcut lookup only ran when domains or strip_hyphens were set;
it now also runs for rewrite-only configurations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After the NetBox instances, netssh configure now opens a menu with all
sections: SSH defaults, global SSH options (jump host, host key
checking, target, address family, extra args, -o options), SSH rules,
resolver & cache (including the cache file), shortcuts & command alias,
and completion.max_results. SSH options can also be set per instance.
The wizard rebuilt the config from its own fields, so re-running it
dropped global SSH options, ssh.rules and completion.max_results from
the file. It now edits a copy of the loaded config, and save validates
SSH options and rules before writing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add SSH settings that apply only to netssh connections, so
~/.ssh/config does not need global changes:
- proxy_jump (passed as -J; "none" disables an inherited jump host)
- host_key_checking: strict | accept-new | off (off prints a notice)
- target: ip (default) | name | hostname; "name" connects to the
NetBox name with -o HostName=<ip> and -o HostKeyAlias=<name>, so
`Host *.example.com` rules apply and known_hosts entries follow the
device instead of a reused IP
- address_family: any | inet | inet6
- options (-o Key=Value) and extra_args
Settings layer global -> netboxes[].ssh -> ssh.rules (match by tag,
instance, kind, or name glob). Options given on the command line
always win: -o values are inserted after the user's own, and
extra_args before them.
New wrapper flags: --jump HOST, --no-jump, and --dry-run, which prints
the final ssh command instead of connecting. The TUI uses the same
options. The setup wizard keeps all new settings when it saves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cobra's generated zsh script spawns a subshell per candidate and sends
every host through _describe, so <Tab> hangs for seconds with thousands
of cached hosts. netssh now ships its own script: subcommands and flags
go through _describe, plain hostnames through compadd. 5000 hosts
complete in ~0.08 s instead of ~4 s.
Add completion.max_results to cap the number of offered hostnames and
sort host candidates for a stable order.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- **Shortcuts**: Add hostname normalization with domain stripping and hyphen folding. Include alias generation for cached hosts.
- **Shell Hook**: Automate 24h cache refresh trigger with shell startup hook. Add install/uninstall commands for bash, zsh, and fish.
- **Wizard**: Extend setup wizard to configure shortcuts (domains, hyphen stripping) and default SSH port.
- **Cache**: Add `GetByShortcut` for resolving hosts via normalized shortcuts. Implement `NeedsRefresh` / `SetRefreshed` logic for refresh timestamps.
- **Tests**: Comprehensive unit tests for shortcuts, hook installation, cache refresh, and alias generation.
- **Docs**: Update README with shortcuts, shell hook, and default SSH port configuration.
- NetBoxConfig.TokenVersion saved to netssh.yaml by the wizard
- config.Load() auto-detects the version from the token prefix if the
field is missing (backwards-compatible with existing configs)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>