MCPcopy Index your code
hub / github.com/TimothyYe/skm

github.com/TimothyYe/skm @v0.9.3

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.9.3 ↗ · + Follow
302 symbols 1,136 edges 41 files 95 documented · 31%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

MIT licensed LICENSE Build Status Go Report Card Go Reference

SKM is a simple and powerful SSH Keys Manager. It helps you to manage your multiple SSH keys easily!

中文版 README

Features

  • Create, List, Delete your SSH key(s)
  • Manage all your SSH keys by alias names
  • Choose and set a default SSH key
  • Display public key via alias name
  • Copy any SSH key to a remote host (with optional --key, --pick, --dry-run)
  • Rename SSH key alias name
  • Backup and restore all your SSH keys
  • Import an existing key pair from anywhere on disk
  • Export a single key as a (optionally encrypted) bundle
  • Inspect a key with fingerprint and info
  • Add / rotate / remove a key's passphrase
  • Diagnose your environment with skm doctor
  • Audit stored keys for weak strength, missing passphrases, and age with skm audit
  • Publish a public key to GitHub, GitLab, or Bitbucket with skm publish
  • Soft-delete to a recoverable trash, with skm trash list|restore|empty
  • Prompt UI (with fuzzy search) for SSH key selection across multiple commands
  • Customized SSH key store path
  • Pluggable hooks on post-use, post-create, pre-delete, post-copy events (per-key and global)

Installation

Homebrew

Starting from v0.8.9, skm has been officially submitted to the homebrew-core repository, so you can install it directly on both macOS and Linux:

brew install skm

If you previously installed skm through the old tap, please remove it first to avoid conflicts:

bash brew uninstall skm brew untap timothyye/tap brew install skm

Using Go

go get github.com/TimothyYe/skm/cmd/skm

Manual Installation

Download it from releases and extact it to /usr/bin or your PATH directory.

Usage

% skm

SKM V0.8.8
https://github.com/TimothyYe/skm

NAME:
   SKM - Manage your multiple SSH keys easily

USAGE:
   skm [global options] command [command options] [arguments...]

VERSION:
   0.8.8

COMMANDS:
     init, i          Initialize SSH keys store for the first time use.
     create, c        Create a new SSH key.
     ls, l            List all the available SSH keys.
     use, u           Set specific SSH key as default by its alias name.
     delete, d        Delete specific SSH key by alias name.
     rename, rn       Rename SSH key alias name to a new one.
     copy, cp         Copy SSH public key to a remote host.
     display, dp      Display the current SSH public key or specific SSH public key by alias name.
     backup, b        Backup all SSH keys to an archive file.
     restore, r       Restore SSH keys from an existing archive file.
     import, im       Import an existing SSH key pair (or an skm export bundle) into the store.
     export, ex       Export a single key as a tar.gz bundle (optionally encrypted).
     fingerprint, fp  Print the SHA256 fingerprint of an SSH key.
     info, in         Show detailed information about an SSH key.
     passphrase, pp   Add, rotate, or remove the passphrase on an SSH key.
     publish, pub     Upload an SSH public key to GitHub, GitLab, or Bitbucket.
     doctor, dr       Run diagnostics against the SKM environment, agent, and stored keys.
     audit, au        Audit stored keys for weak strength, missing passphrases, and age.
     cache            Add your SSH to SSH agent cache via alias name.
     help, h          Shows a list of commands or help for one command.

GLOBAL OPTIONS:
   --store-path value   Path where SKM should store its profiles (default: "/Users/timothy/.skm")
   --ssh-path value     Path to a .ssh folder (default: "/Users/timothy/.ssh")
   --restic-path value  Path to the restic binary
   --help, -h           show help
   --version, -v        print the version

For the first time use

You should initialize the SSH key store for the first time use:

% skm init

✔ SSH key store initialized!

So, where are my SSH keys? SKM will create SSH key store at $HOME/.skm and put all the SSH keys in it.

NOTE: If you already have id_rsa & id_rsa.pub key pairs in $HOME/.ssh, SKM will move them to $HOME/.skm/default

Create a new SSH key

Supported key types: ed25519 (default), rsa, ed25519-sk, ecdsa-sk. The -sk variants are FIDO2 hardware-backed keys and require ssh-keygen 8.2+ plus a security key (YubiKey, Solo, etc.) plugged in at creation time.

% skm create prod -C "abc@abc.com"
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/timothy/.skm/prod/id_ed25519.
Your public key has been saved in /Users/timothy/.skm/prod/id_ed25519.pub.
...
✔ SSH key [prod] created!

Other examples:

skm create old -t rsa -b 4096           # RSA (minimum 3072 bits enforced)
skm create yubi -t ed25519-sk           # hardware-backed; prompts for PIN + touch

RSA keys below 3072 bits are rejected — skm audit flags those as weak, so create and audit agree on what's safe. Use ssh-keygen directly if you need a smaller key for testing.

List SSH keys

By default ls shows alias, key type, and comment in three columns; the active default key is marked with ->. Use -l / --long for the full table with bits, fingerprint, agent status, and the modification date.

% skm ls

✔ Found 3 SSH key(s)!

->  default  [ssh-ed25519]  [work@laptop]
    dev      [ssh-ed25519]  [dev]
    prod     [ssh-rsa]      [prod]

% skm ls -l

✔ Found 3 SSH key(s)!

  ALIAS    TYPE     BITS  FINGERPRINT                                         AGENT  CREATED     COMMENT
* default  ed25519  256   SHA256:pFsC7J7L9L08f3w8uP6ozRaGW5Dg8CdEkP8iVj7++pw  yes    2026-05-16  work@laptop
  dev      ed25519  256   SHA256:7dFJEj7WGAL8rn9AqLNYdoTQrqgv00kdnqJlufvxgg4  -      2026-05-12  dev
  prod     rsa      4096  SHA256:DEyhI38hQ5WYABdx9SrJuhqrIyLvfRcZTtzXARuyn0k  -      2026-05-01  prod

Other useful flags:

skm ls -q              # quiet — just the alias names, default marked with ->
skm ls --json          # machine-readable output for scripting
skm ls -t ed25519      # filter by key type

Set default SSH key

% skm use dev
Now using SSH key: dev

Prompt UI for key selection

You can just type skm use, then a prompt UI will help you to choose the right SSH key:

Display public key

% skm display

Or display specific SSH public key by alias name:

% skm display prod

Delete a SSH key

% skm delete prod

Please confirm to delete SSH key [prod] [y/n]: y
✔ SSH key [prod] moved to trash (restore with: skm trash restore prod-20260521150412)

By default a delete moves the alias into the store's trash so it can be recovered. Pass multiple aliases to batch-delete; missing aliases are reported and skipped. -y / --yes skips the confirmation, --purge hard-deletes (skipping the trash):

% skm delete -y staging legacy old-laptop
% skm delete --purge --yes ancient

Recover a deleted SSH key

% skm trash list
NAME                       ALIAS    DELETED
prod-20260521150412        prod     2026-05-21 15:04:12

% skm trash restore prod-20260521150412
✔ Restored [prod-20260521150412] as alias [prod]

You can pass either the trash entry name (prod-20260521150412) or just the alias (prod); the latter works when only one trashed entry matches. If the original alias is already taken, pass --as <new-alias>. Empty the trash with skm trash empty (prompts for confirmation; -y to skip).

Copy SSH public key to a remote host

By default the currently active key is pushed:

% skm cp timothy@example.com

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/Users/timothy/.skm/default/id_rsa.pub"
...
✔  SSH key copied to remote host

Useful flags:

skm cp --key work timothy@example.com         # push a specific key, not the default
skm cp --pick timothy@example.com             # interactively choose the key
skm cp -p 2222 timothy@example.com            # non-default SSH port
skm cp timothy@[2001:db8::1]:2222             # IPv6 hosts work too
skm cp --dry-run timothy@example.com          # preview the ssh-copy-id command

Rename a SSH key with a new alias name

% skm rn test tmp
✔  SSH key [test] renamed to [tmp]

Backup SSH keys

Backup all your SSH keys to a tarball in $HOME.

% skm backup

a .
a ./default/id_rsa
a ./default/id_rsa.pub
…
✔  All SSH keys backup to: /Users/timothy/skm-20260521221544.tar.gz
⚠ This bundle contains UNENCRYPTED private keys. If it leaves this
  machine, anyone with the file can use your keys. Re-run with
  --encrypt to produce an encrypted archive.

The default tar contains your private keys in the clear. To produce an encrypted bundle (AES-256-CBC via openssl, same envelope as skm export --encrypt), pass --encrypt:

% skm backup --encrypt
enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:
✔  All SSH keys backup to: /Users/timothy/skm-20260521221544.tar.gz.enc
  Decrypt with: openssl enc -d -aes-256-cbc -pbkdf2 -in /Users/timothy/skm-20260521221544.tar.gz.enc -out skm-20260521221544.tar.gz

For scripted use, pass --password-file <path> to read the passphrase from a file instead of prompting.

Restic-backed backups (local or cloud)

If you have restic installed, SKM can use it to produce encrypted, deduplicated, snapshot-style backups that can target local disk, S3, Cloudflare R2, Backblaze B2, SFTP, and any other backend restic supports. Run the one-time interactive setup first:

% skm backup --restic --init
Configuring restic backup for SKM.
Examples:
  Local:  /Users/me/.skm-backups
  S3:     s3:s3.amazonaws.com/my-bucket/skm
  R2:     s3:https://<account>.r2.cloudflarestorage.com/my-bucket/skm
  SFTP:   sftp:user@host:/data/skm
  B2:     b2:my-bucket/skm

For S3, R2, and B2, set the relevant credential env vars (e.g.
AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) before running backup.

✔ Restic repository initialized at s3:https://abc.r2.cloudflarestorage.com/skm
⚠ IMPORTANT: store the restic password somewhere OTHER than this machine.
  If this laptop is lost and the password only lives in ~/.skm-backups.passwd,
  the backup will be unrecoverable.

Then run repeat backups:

% skm backup --restic
✔  Backup to s3:https://abc.r2.cloudflarestorage.com/skm complete

Restic encrypts every chunk client-side before upload, so the remote destination never sees plaintext. The R2/S3 credentials and the restic password are independent secrets — losing the credentials means re-issuing them; losing the restic password means the backup is unrecoverable.

Restore SSH keys

% skm restore ~/skm-20260521221544.tar.gz
✔  All SSH keys restored to /Users/timothy/.skm

.enc bundles are auto-detected and decrypted before extraction:

% skm restore ~/skm-20260521221544.tar.gz.enc
enter AES-256-CBC decryption password:
✔  All SSH keys restored to /Users/timothy/.skm

For restic-backed backups, pick a snapshot to restore:

% skm restore --restic --restic-snapshot $SNAPSHOT
✔  Backup restored to /Users/$USER/.skm

Omit --restic-snapshot and SKM will list the available snapshots.

Import an existing key

Pull an existing key pair from anywhere on disk into the SKM store. The matching half of the pair is inferred from the .pub suffix; the key type is detected from the public key's header.

% skm import --alias work ~/old-laptop/.ssh/id_ed25519
✔ Imported ed25519 key as [work]

skm import also accepts an skm export bundle (.tar.gz, .tgz, or .tar.gz.enc). For encrypted bundles, openssl prompts for the passphrase.

% skm import ~/skm-work-20260516193629.tar.gz.enc
enter aes-256-cbc decryption password:
✔ Imported bundle as [work]

Useful flags:

skm import --alias newname bundle.tar.gz      # rename the alias on the way in
skm import --move ~/old/id_ed25519            # remove the source after a successful copy

Note: put --alias / --move before the path argument — flags placed after the path are not parsed, and SKM will error out with a hint if it sees one.

Export a single key

Bundle one alias into a portable archive that you can move to another machine and import there. The archive contains the private key, the public key, and any hook file under that alias.

% skm export work
✔ Exported [work] to /Users/timothy/skm-work-20260516193629.tar.gz

Add --encrypt to wrap the bundle with openssl enc -aes-256-cbc -pbkdf2, which prompts for a passphrase:

% skm export --encrypt work
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
✔ Exported [work] to /Users/timothy/skm-work-20260516193629.tar.gz.enc

You can also specify the output path:

```bash

Extension points exported contracts — how you extend this code

Publisher (Interface)
Publisher uploads a single SSH public key to a provider and reports whether the same key is already published (compared [3 …
internal/publishers/publishers.go

Core symbols most depended-on inside this repo

LoadSSHKeys
called by 28
internal/utils/utils.go
Execute
called by 25
internal/utils/utils.go
MustGetEnvironment
called by 23
internal/utils/utils.go
Name
called by 18
internal/publishers/publishers.go
RunHook
called by 12
internal/utils/utils.go
PrivateKey
called by 10
internal/models/key_type.go
ParsePath
called by 9
internal/utils/utils.go
ListTrash
called by 8
internal/utils/trash.go

Shape

Function 256
Method 24
Struct 19
TypeAlias 2
Interface 1

Languages

Go100%

Modules by API surface

internal/actions/actions_test.go44 symbols
internal/utils/utils_test.go34 symbols
internal/utils/utils.go20 symbols
internal/actions/doctor.go15 symbols
pkg/lib/restic.go14 symbols
internal/publishers/publishers_test.go13 symbols
internal/actions/list.go13 symbols
internal/actions/import.go13 symbols
internal/actions/audit.go12 symbols
pkg/lib/restic_test.go9 symbols
internal/publishers/publishers.go9 symbols
internal/actions/hook.go9 symbols

For agents

$ claude mcp add skm \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact