| name | ssh-hygiene |
| description | Audit, clean up, and structure SSH config and keys. Use when user asks to "review ssh config", "clean up ssh", "check ssh keys", "add ssh host", "remove dead ssh hosts", "organize ssh keys", or any SSH configuration management task. Also triggers on mentions of ~/.ssh/config, SSH key organization, or 1Password SSH agent setup. |
SSH Hygiene
Audit and restructure ~/.ssh/ for clean, secure, 1Password-integrated SSH management.
Target Structure
~/.ssh/
config
keys/
<host-alias>.pub
known_hosts
Config Format
Host *
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
IdentitiesOnly yes
ServerAliveInterval 60
ServerAliveCountMax 3
Host <alias>
HostName <ip-or-hostname>
User <username>
IdentityFile ~/.ssh/keys/<alias>.pub
Rules:
- Never specify
Port 22 (default)
IdentityFile always points to .pub in ~/.ssh/keys/ — 1Password serves private key via agent
- No private keys on disk, all in 1Password
- 2-space indent, no trailing comments, blank line between host blocks
Workflow: Full Audit
- Read
~/.ssh/config and ls ~/.ssh/
- Run
scripts/check_hosts.sh to TCP-check port 22 on each host (3s timeout)
- Present table: host, IP, alive/dead
- Ask user which alive hosts are also no longer needed
- Rewrite config keeping only needed hosts, applying format rules
- Move/rename public keys to
~/.ssh/keys/<alias>.pub
- Delete orphaned keys (private keys on disk, keys for removed hosts)
- Verify:
ls ~/.ssh/ and ls ~/.ssh/keys/
Workflow: Add Host
- Get alias, hostname/IP, username from user
- Check if
.pub exists in ~/.ssh/ or ~/.ssh/keys/
- If missing — user must create SSH Key in 1Password, export
.pub to ~/.ssh/keys/<alias>.pub
- Append host block to config
Workflow: Remove Host
- Remove host block from config
- Delete
.pub from ~/.ssh/keys/
Common Fixes
IdentityFile pointing to private key → change to .pub
- Absolute paths in
IdentityFile → normalize to ~/.ssh/keys/<alias>.pub
IdentitiesOnly yes on individual hosts → remove (covered by Host *)
AddKeysToAgent yes on individual hosts → remove (1Password handles this)
- Missing
ServerAliveInterval in Host * → add 60/3