| type | API Reference | |||||
|---|---|---|---|---|---|---|
| title | Headless CLI — full command tree, JSON output, and exit codes | |||||
| description | SSHub's scriptable command-line interface (src/cli) covering hosts, exec, groups, identities, tunnels, SFTP, audit, import/export/sync, and completions, with --format json support and stable exit codes 0/1/2 (plus 124 for `exec --timeout`). | |||||
| resource | src/cli/mod.rs | |||||
| tags |
|
Beyond the TUI, sshub exposes a full scriptable CLI. src/main.rs dispatches in order: askpass re-exec → db subcommand → cli::is_subcommand (cheap string check, no bootstrap) → global flags → TUI. CliContext::bootstrap() (src/cli/context.rs) loads config, opens both databases, builds the resolver and OsKeyring, and loads merged hosts — so the CLI shares all state with the TUI (data model).
Parsing is hand-rolled (src/cli/parse.rs), output DTOs in src/cli/output.rs. Conventions:
--format plain|jsonon listing/show commands (plain default).- Exit codes:
0success,1operational failure,2usage/bad flags,124whenexec --timeoutkills the run.host connectandexecpropagate the child ssh exit code. - Destructive commands refuse without
--yes;sshub db purgerequires--yes-i-am-stupid. - Unknown positional first arg exits 2 with a hint (avoids launching a full-screen TUI on a typo).
| Command | Subcommands | Notes |
|---|---|---|
host (alias list, connect) |
list show connect resolve search add edit rename delete duplicate |
add takes --name --address --port --username --group --tags; connect runs ssh/mosh as a foreground child process with inherited stdio (Command::spawn + wait), propagating its exit code; it does not use the TUI embedded-PTY session module or the (dead-code) external TerminalLauncher |
exec |
— | sshub exec <host> [--tty] [--timeout SECS] [--format plain|json] -- <command>: one non-interactive command on a saved host (src/cli/exec.rs). Reuses the connect argv (session_argv_for_entry + prepare_cli_connect_argv), then adds -T/-tt, -o RemoteCommand=none (a per-host stored remote command must not win, and a config-level one makes ssh refuse the run) and -o BatchMode=yes when no stored secret is staged, so a script can never sit on a prompt. stdio passes through, stdin inherited; --timeout spawns into its own process group and SIGKILLs the group (a ProxyJump helper would otherwise hold the pipes open). Audited as via exec, without the command string. No session transcript; mosh refused |
group (alias groups) |
list show add edit delete |
Nested groups via parent |
identity |
list show add edit delete agent-remove |
add --private-key, --password-stdin for secrets; agent-remove = ssh-add -d |
tunnel |
list show create start stop delete |
start is detached by default (PID files), --foreground runs with keep-alive (tunnels) |
sftp |
ls get put rm mkdir rename chmod |
One-shot over a direct host; no ProxyJump (sessions & SFTP) |
audit |
list stats |
`--status ok |
tags |
— | List all tags |
import / sync / export |
— | ssh config import, row refresh, `export --stdout |
completions |
bash zsh fish |
Installed by just install-completions |
db |
purge |
Deletes launcher.db + sidecars only |
Examples (from README.md):
sshub host add --name prod-web --address 10.0.0.5 --port 22 --username deploy --group prod --tags web,prod
sshub tunnel create --host prod-web --type local --local-port 8080 --remote-host localhost --remote-port 80
sshub sftp get prod-web /var/log/app.log ./app.log
sshub exec prod-web --timeout 30 -- systemctl is-active nginx
sshub audit list --status fail --days 7Per-command help: sshub <command> --help; the man page (man/sshub.1, preview with just man) covers the same surface.
- New subcommand: register in
src/cli/mod.rs(is_subcommand+run_subcommand), add a module undersrc/cli/, add its help block insrc/cli/help.rsand the section inmain.rs::print_help, list it insrc/cli/completions.rs(TOP_LEVELplus the bash/zsh/fish bodies), extend the man page, the README table and this page. - CLI smoke coverage lives in
tests/smoke/cli_commands.rs(drives the real binary viaassert_cmd) — see testing. - Keep exit codes stable; scripts depend on them.