fleet hosts — picker for SSH'ing into fleet-configured machines¶
fleet hosts is the TV-style picker for the fleet inventory at
~/.config/fleet/machines.toml. It mirrors the
ssh-config cable
(tv ssh-config) but reads fleet's TOML instead of ~/.ssh/config, so hosts
with explicit hostname / user / port / identity_file (no ssh_alias)
are reachable too.
Sister tools: fleet exec for cross-host ad-hoc commands,
fleet pueue for queue probing,
fleet chezmoi apply for the deploy workflow.
All four read the same inventory via scripts/fleet/apply.py:load_hosts().
Install¶
Deployed automatically by chezmoi:
~/.dotfiles/bin/fleet— the umbrella binary (dispatchesfleet hosts)~/.config/television/cable/fleet-hosts.toml— the TV channel~/.local/share/chezmoi/scripts/fleet/hosts.py— the implementation (resolved at runtime viachezmoi source-path, so the cable / binary find the latest version even on hosts where you haven't runchezmoi applyyet)
No separate install step. tv (television) is pulled in by the devtools role
and is what powers the picker UX.
Three entry points¶
| Form | What it does |
|---|---|
tv fleet-hosts |
Open the picker directly via television. Enter → SSH. |
fleet hosts |
Same picker via the fleet umbrella (execs tv fleet-hosts). |
fleet hosts NAME |
Skip the picker — SSH straight into NAME. |
fleet hosts --list |
Plain host names, one per line. Scriptable. |
fleet hosts --list-tsv |
name<TAB>target<TAB>kind (the cable's source). |
fleet hosts --list-json |
Full inventory as JSON (plain passwords redacted). |
fleet hosts --describe N |
Multi-section preview block for N (the cable's preview). |
fleet hosts --probe N |
BatchMode SSH probe of N (the cable's Alt+T action). |
Direct invocation (fleet hosts NAME) uses os.execvp("ssh", ...), so your
terminal becomes the SSH session — no wrapper subprocess, no lost TTY
attributes. Behaviour matches Enter inside the picker.
local = true hosts are hidden from --list-tsv (you can't SSH into
yourself). They still appear in --list / --list-json for scripts that
want the full inventory. --include-local overrides for --list-tsv too.
Keybindings (inside the picker)¶
| Key | Action |
|---|---|
Enter |
SSH into the selected host (fleet hosts NAME) |
Alt+T |
BatchMode SSH probe — does passwordless login actually work? |
Alt+S |
fleet chezmoi status --hosts NAME (readiness probe for one host) |
Alt+I |
fleet info --hosts NAME (OS / CPU / memory / disk snapshot) |
Alt+P |
fleet pueue --hosts NAME (queue summary for one host) |
Ctrl+/ |
Toggle preview panel (TV builtin) |
The Alt+ namespace is used (rather than Ctrl+letter) to avoid collisions
with tmux's root-table bindings — see
CLAUDE.md keybinding rule.
Preview pane contents¶
fleet hosts --describe NAME (which the cable shells out to for every
cursor move) prints four sections:
# host: lab-box (defined in: /Users/dwlee/.config/fleet/machines.toml)
connection:
ssh_alias lab-box
user (from ssh_config)
hostname (from ssh_config)
port (from ssh_config)
identity_file (from ssh_config)
fleet metadata:
local false
no_root_machine false
chezmoi_path auto
password_source bitwarden (item=ssh-lab-box-sudo)
ssh_login_password_source none
extra_env (none)
ssh -G 'lab-box' (resolved by ssh_config):
hostname 192.0.2.42
user dwlee
port 22
identityfile /Users/dwlee/.ssh/id_ed25519
proxyjump bastion.example.com
local key check (offline):
[OK] /Users/dwlee/.ssh/id_ed25519
- The
ssh -Gblock is omitted for hosts that don't use anssh_alias— for those, the explicit fields in theconnection:section already are the resolved values. - Both
password_sourceandssh_login_password_sourcedeliberately redacttype = "plain"values. The TOML file itself is 0600, but the preview output scrolls into logs / screenshots; the type label suffices for triage.
Subset selection from the picker¶
TV is single-select. For multi-host fan-out, drop back to the underlying
fleet commands with explicit --hosts:
fleet hosts --list # see what's available
fleet exec --hosts self,ts_nas -- pueue --version
fleet info --hosts production_a,production_b
Ctrl+E/multi-select pickers are out of scope here — see the
plan file
for the future-work list.
Exit codes¶
| Mode | Exit code |
|---|---|
--list* / --describe / picker (no SSH happened) |
0 |
fleet hosts NAME (passes to ssh) |
whatever ssh returned |
fleet hosts NAME on a local = true host |
0 (no-op) |
fleet hosts NAME on an unknown host |
2 |
--probe NAME |
0 = passwordless OK; 255 = unreachable / auth fail; other = remote command failed |
Picker fallback when tv missing, user aborts |
0 if empty input, 130 on Ctrl-C, 2 on bad index |
Troubleshooting¶
tv fleet-hostsshows no rows: runfleet hosts --list-tsvdirectly. If output is empty, every host haslocal = true(picker hides them). Override withfleet hosts --list-tsv --include-local.fleet hosts NAMEprompts for password:fleet hosts NAMEitself is a real interactivesshprocess (viaos.execvp), so it happily handles a password prompt on its own. The symptom matters for the other fleet subcommands (fleet chezmoi status/apply,fleet exec/tmux/info/pueue) — those use asyncssh and default to non-interactive key/agent auth only, so a password prompt there means the connection will fail. Fix withssh-copy-id, agent forwarding, or the 1Password SSH agent where possible; if the remote flatly disallows pubkey auth, set the opt-inssh_login_password_sourcefield instead — same fix asfleet chezmoi applyunreachable hosts.- Preview pane shows
(ssh -G unavailable or returned nothing): the alias isn't in~/.ssh/config(or its includes). Either add it, or switch the host entry to explicithostname/user/portfields. - Alt+S/I/P hangs: the underlying
fleet chezmoi status/fleet info/fleet pueueis making one SSH connection — usually fast, but a slow remote will block the picker. Press Enter at the[Press Enter to exit]prompt to return.
Cross-file invariants¶
Adding new actions, flags, or output schemas requires touching:
scripts/fleet/hosts.py— primary implementationdot_dotfiles/bin/executable_fleet— USAGE block +_dispatch_hostsdot_config/television/cable/fleet-hosts.toml— picker bindings + previewdocs/this_repo/fleet-apply.md— subcommand rowdocs/tools/fleet-hosts.md— this page
_ssh_argv() in hosts.py mirrors the precedence of _connect_kwargs() in
apply.py (ssh_alias wins over explicit fields). If you change one,
update the other.
The password_source_arg redaction rule for type = "plain" lives in two
places: _cmd_describe() (preview text) and _cmd_list_json() (JSON
dump). Both must stay in sync.