{"id":13563745,"url":"https://github.com/charmbracelet/wishlist","last_synced_at":"2025-04-03T20:31:34.681Z","repository":{"id":37078150,"uuid":"444063538","full_name":"charmbracelet/wishlist","owner":"charmbracelet","description":"The SSH directory ✨","archived":false,"fork":false,"pushed_at":"2025-03-31T09:36:27.000Z","size":669,"stargazers_count":1211,"open_issues_count":12,"forks_count":27,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-03-31T10:23:22.224Z","etag":null,"topics":["hacktoberfest","ssh"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charmbracelet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-03T13:04:30.000Z","updated_at":"2025-03-31T09:36:29.000Z","dependencies_parsed_at":"2023-02-05T00:16:23.396Z","dependency_job_id":"c70fabe5-6dbd-4290-bdd2-52cce1703470","html_url":"https://github.com/charmbracelet/wishlist","commit_stats":{"total_commits":350,"total_committers":14,"mean_commits":25.0,"dds":"0.44285714285714284","last_synced_commit":"e390097512679eda19847a0f7f09cc4be6dbb411"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmbracelet%2Fwishlist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmbracelet%2Fwishlist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmbracelet%2Fwishlist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charmbracelet%2Fwishlist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charmbracelet","download_url":"https://codeload.github.com/charmbracelet/wishlist/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247074706,"owners_count":20879304,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","ssh"],"created_at":"2024-08-01T13:01:22.859Z","updated_at":"2025-04-03T20:31:34.386Z","avatar_url":"https://github.com/charmbracelet.png","language":"Go","funding_links":[],"categories":["Go","\u003ca name=\"networking\"\u003e\u003c/a\u003eNetworking","Applications"],"sub_categories":["Networking and File Transfer"],"readme":"# Wishlist\n\n\u003cp\u003e\n    \u003ca href=\"https://github.com/charmbracelet/wishlist/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/release/charmbracelet/wishlist.svg\" alt=\"Latest Release\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pkg.go.dev/github.com/charmbracelet/wishlist?tab=doc\"\u003e\u003cimg src=\"https://godoc.org/github.com/golang/gddo?status.svg\" alt=\"GoDoc\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/charmbracelet/wishlist/actions\"\u003e\u003cimg src=\"https://github.com/charmbracelet/wishlist/workflows/build/badge.svg\" alt=\"Build Status\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://nightly.link/charmbracelet/wishlist/workflows/nightly/main\"\u003e\u003cimg src=\"https://shields.io/badge/-Nightly%20Builds-orange?logo=hackthebox\u0026logoColor=fff\u0026style=appveyor\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nThe SSH directory ✨\n\n![Gif](https://vhs.charm.sh/vhs-3YDAKLasKh7IgWNTkHKrHB.gif)\n\nWith Wishlist you can have a single entry point for multiple SSH endpoints,\nwhether they are [Wish](https://github.com/charmbracelet/wish) apps or not.\n\nAs a server, it can be used to start multiple SSH apps within a single package\nand list them over SSH.\nYou can list apps provided elsewhere, too.\n\nYou can also use the `wishlist` command to list and connect to servers in your\n`~/.ssh/config` or in a YAML configuration file.\n\n## Installation\n\nUse your fave package manager:\n\n```bash\n# macOS or Linux\nbrew install charmbracelet/tap/wishlist\n\n# Arch Linux (btw)\nyay -S wishlist-bin\n# or\nyay -S wishlist\n\n# Windows (with winget)\nwinget install wishlist\n\n# Windows (with Scoop)\nscoop bucket add charm https://github.com/charmbracelet/scoop-bucket.git\nscoop install wishlist\n\n# Nix\nnix-env -iA nixpkgs.wishlist\n\n# Debian/Ubuntu\nsudo mkdir -p /etc/apt/keyrings\ncurl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg\necho \"deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *\" | sudo tee /etc/apt/sources.list.d/charm.list\nsudo apt update \u0026\u0026 sudo apt install wishlist\n\n# Fedora/RHEL\necho '[charm]\nname=Charm\nbaseurl=https://repo.charm.sh/yum/\nenabled=1\ngpgcheck=1\ngpgkey=https://repo.charm.sh/yum/gpg.key' | sudo tee /etc/yum.repos.d/charm.repo\nsudo yum install wishlist\n```\n\nOr download a pre-compiled binary or package from the [releases][releases] page.\n\nOr just build it yourself (requires Go 1.19+):\n\n```bash\ngit clone https://github.com/charmbracelet/wishlist.git\ncd wishlist\ngo build ./cmd/wishlist/\n```\n\n[releases]: https://github.com/charmbracelet/wishlist/releases\n\n## Usage\n\n### CLI\n\n#### Remote\n\nIf you just want a directory of existing servers, you can use the `wishlist` CLI\nand a YAML config file. You can also just run it without any arguments to list\nthe servers in your `~/.ssh/config`. To start wishlist in server mode, you'll\nneed to use the `serve` subcommand:\n\n```sh\nwishlist serve\n```\n\nCheck the [example config file](/_example/config.yaml) file as well as\n`wishlist server --help` for details.\n\n#### Local\n\nIf you want to explore your `~/.ssh/config`, you can run wishlist in local mode\nwith:\n\n```sh\nwishlist\n```\n\nNote that not all options are supported at this moment. Check the\n[commented example config](/_example/config) for reference.\n\n### Library\n\nWishlist is also available as a library, which allows you to start several apps\nwithin the same process.\nCheck out the `_example` folder for a working example.\n\n## Auth\n\n### Local mode\n\nWhen running in local mode, wishlist will first see if the current endpoint has\nan `IdentityFile` specified.\nIf so, it'll try to use that.\nIf not, it'll see if there's a SSH Agent available, and use it.\nOtherwise, it'll try the common key names in `~/.ssh`.\n\n### Server mode\n\nWhen running as a server, wishlist will first try to forward the current SSH\nAgent.\nIf there's no agent, it'll create or use an existing ed25519 key present in\n`.wishlist/client_ed25519`.\nPassword authentication is not supported at this moment.\n\n### Agent forwarding example\n\n```sh\neval (ssh-agent)\nssh-add -k # adds all your pubkeys\nssh-add -l # should list the added keys\n\nssh \\\n  -o 'ForwardAgent=yes' \\             # forwards the agent\n  -o 'UserKnownHostsFile=/dev/null' \\ # do not add to ~/.ssh/known_hosts, optional\n  -p 2222 \\                           # port\n  foo.bar \\                           # host\n  -t list                             # optional, app name\n```\n\nYou can also add this to your `~/.ssh/config`, for instance:\n\n```sshconfig\nHost wishlist\n\tHostName foo.bar\n\tPort 2222\n\tForwardAgent yes\n\tUserKnownHostsFile /dev/null\n```\n\n## Discovery\n\nWishlist can discover endpoints using Zeroconf, SRV Records, and [Tailscale][].\n\nYou can find a brief explanation and examples of all of them bellow.\n\nRun `wishlist --help` to see all the options.\n\n[Tailscale]: http://tailscale.com\n\n### Tailscale\n\nYou can configure Wishlist to find all nodes in your **tailnet** and add them\nas endpoints:\n\n```bash\nwishlist --tailscale.net=your_tailnet_name --tailscale.key=tskey-api-abc123...\n```\n\nYou can use the [Hints](#hints) to change the connection settings.\n\n#### OAuth authentication\n\nTailscale API keys expire after 90 days. If you want something that doesn't\nrequire you to intervene every couple of months, use OAuth Clients:\n\nCreate a client [here](https://login.tailscale.com/admin/settings/oauth).\nThe only scope needed is `devices:read`.\n\nInstead of using `--tailscale.key` (or `$TAILSCALE_KEY`), set\n`--tailscale.client.id` and `--tailscale.client.secret` (or\n`$TAILSCALE_CLIENT_ID` and `$TAILSCALE_CLIENT_SECRET`, respectively).\n\n### Zeroconf/Avahi/mDNS/Bonjour\n\nYou can enable this using the `--zeroconf.enabled` flag:\n\n```bash\nwishlist --zeroconf.enabled\n```\n\nOptionally, you can also specify a timeout with `--zeroconf.timeout` and, which\ndomain to look for with `--zeroconf.domain`.\n\nWishlist will look for `_ssh._tcp` services in the given domain.\n\nYou can use the [Hints](#hints) to change the connection settings.\n\n### SRV records\n\nYou can set Wishlist up to find nodes from DNS `SRV` records:\n\n```bash\nwishlist --srv.domain example.com\n```\n\nBy default, Wishlist will set the name of the endpoint to the `SRV` target.\nYou can, however, customize that with a `TXT` record in the following format:\n\n```txt\nwishlist.name full.address:22=thename\n```\n\nSo, in this case, a `SRV` record pointing to `full.address` on port `22` will\nget the name `thename`.\n\n### Hints\n\nYou can use the `hints` key in the YAML configuration file to hint settings into\ndiscovered endpoints.\n\nCheck the [example configuration file](/_example/config.yaml) to learn\nwhat options are available.\n\nIf you're using a SSH configuration file as the Wishlist configuration file,\nit'll try to match the hosts with the rules in the given configuration.\nOtherwise, the services will simply be added to the list.\n\nThe difference is that if a hints themselves won't show in the TUI, as of hosts\nin the SSH configuration will.\n\n## Running it\n\nWishlist will read and store all its information in a `.wishlist` folder in the\ncurrent working directory:\n\n- the server keys\n- the client keys\n- known hosts\n- config files\n\nConfig files may be provided in either YAML or SSH Config formats:\n\n- [example YAML](/_example/config.yaml)\n- [example SSH config](/_example/config)\n\nThe config files are tried in the following order:\n\n- the `-config` flag in either YAML or SSH config formats\n- `.wishlist/config.yaml`\n- `.wishlist/config.yml`\n- `.wishlist/config`\n- `[[user config dir]]/wishlist/config.yaml`[^1]\n- `[[user config dir]]/wishlist/config.yml`[^1]\n- `[[user config dir]]/wishlist/config`[^1]\n- `$HOME/.ssh/config`\n- `/etc/ssh/ssh_config`\n\n[^1]:\n    i.e. `[[user config dir]]`: On Unix systems, it will be `$XDG_CONFIG_HOME`\n    as specified by\n    https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html\n    if non-empty, else `$HOME/.config`. On Darwin, it will be\n    `$HOME/Library/Application Support`. On Windows, it will be `%AppData%`.\n    On Plan 9, it will be `$home/lib`.\n\nThe first one that is loaded and parsed without errors will be used. This means\nthat if you have your common used hosts in your `~/.ssh/config`, you can simply\nrun `wishlist` and get it running right away. It also means that if you don't\nwant that, you can pass a path to `-config`, and it can be either a YAML, or a\nSSH config file.\n\n### Using the binary\n\n```sh\nwishlist\n```\n\n### Using Docker\n\n```sh\nmkdir .wishlist\n$EDITOR .wishlist/config.yaml # either an YAML or a SSH config\ndocker run \\\n  -p 2222:22 \\\n  -v $PWD/.wishlist:/.wishlist \\\n  docker.io/charmcli/wishlist:latest\n```\n\n### Supported SSH Options\n\nNot all SSH options are currently supported.\nHere's a list of the ones that are:\n\n- `User`\n- `Hostname`\n- `Port`\n- `IdentityFiles`\n- `ForwardAgent`\n- `RequestTTY`\n- `RemoteCommand`\n- `SendEnv`\n- `SetEnv`\n- `ConnectTimeout`\n- `Include`\n- `PreferredAuthentications`\n- `ProxyJump`\n\n## Acknowledgments\n\nThe gif above shows a lot of [Maas Lalani’s](https://github.com/maaslalani) [confeTTY](https://github.com/maaslalani/confetty).\n\n## Feedback\n\nWe’d love to hear your thoughts on this project. Feel free to drop us a note!\n\n- [Twitter](https://twitter.com/charmcli)\n- [The Fediverse](https://mastodon.social/@charmcli)\n- [Discord](https://charm.sh/chat)\n\n## License\n\n[MIT](/LICENSE)\n\n---\n\nPart of [Charm](https://charm.sh).\n\n\u003ca href=\"https://charm.sh/\"\u003e\u003cimg alt=\"The Charm logo\" src=\"https://stuff.charm.sh/charm-badge.jpg\" width=\"400\"\u003e\u003c/a\u003e\n\n\u003c!--prettier-ignore--\u003e\nCharm热爱开源 • Charm loves open source\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharmbracelet%2Fwishlist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcharmbracelet%2Fwishlist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharmbracelet%2Fwishlist/lists"}