import { Link } from 'react-router' import { Button } from '@/components/ui/button' import { Code } from '@/components/ui/inline-code' import { Cols, Eyebrow, PageHead, Prose, Section, SectionHead, } from '@/components/ui/layout' import { Callout, Panel } from '@/components/ui/panel' import { Terminal } from '@/components/ui/terminal' import { LINKS } from '@/lib/links' const GLOBAL_KEYS: readonly (readonly [string, string])[] = [ ['s', 'search the network'], ['Space', 'select a result'], ['Enter', 'download / send'], ['b', "browse the owner's files"], ['c', 'chat rooms'], ['m', 'compose a private message'], ['i', 'inbox (unread counter)'], ['/', 'filter the current list'], ['a / A', 'select all / none'], ['1–3', 'focus a pane'], ['q', 'quit'], ] const ROOM_KEYS: readonly (readonly [string, string])[] = [ ['Enter', 'join room / send message'], ['Tab · ⇧Tab', 'switch between open rooms'], ['x', 'leave the active room'], ['l', 'back to the room list'], ['↑ ↓', 'select a member'], ['b', "browse the member's files"], ['m', 'message the member'], ] const PANES: readonly { num?: number; title: string; body: string }[] = [ { num: 1, title: 'Searches', body: 'Your queries and how many results each returned. Press s to search the network; each search keeps its own result set.', }, { num: 2, title: 'Results', body: 'Files from the network: size, user, bitrate, speed, free slots. Space selects, Enter queues a download.', }, { num: 3, title: 'Downloads / Uploads', body: 'Live transfers in both directions with progress and speed: queued, active, complete, failed.', }, { title: 'Info', body: 'Everything about the selected file: user, size, path, bitrate, length, queue position, free slots.', }, ] const KeyRow = ({ combo, description }: { combo: string; description: string }) => (
cargo install, the binary is on your
PATH.
On first run soulseek-rs shows a login screen: sign in with an existing Soulseek account or register a new one, right in the TUI. Your password is stored in the OS keychain, not in plain text.
Downloads land in a conventional folder by default, and your TUI state (searches, downloads, rooms) is saved and restored across restarts.
1–3 to focus
one; the focused pane’s legend turns green.
{pane.body}
The command groups: search, get,{' '}
download, browse, room,{' '}
message, serve, user,{' '}
whoami, shares, config,{' '}
portmap, skills. Records are tab-separated fields,
one per line, or NDJSON with --json.
No TTY, no daemon. search --json pipes through jq{' '}
into download --stdin. Every ending has its own exit code: 4 found
nothing, 3 could not reach the server, 6 the transfer died.
portmap tests whether your router will let peers connect back,
worth running once.{' '}
More on being reachable
soulseek-rs skills install writes a SKILL.md into
every coding agent on the machine — Claude Code and opencode today,{' '}
--dir for anything else. After it lands you describe the
outcome instead of the pipeline: “mirror that peer’s FLAC
folder”, “watch this room for an hour and save anything
mentioning the label”.
It carries what --help cannot: the JSON keys of every record,
that exit 4 means widen the query rather than retry it, that remote paths go
back byte-identical, and that --follow never returns so an agent
passes --duration. Run it again after an upgrade to update it;{' '}
skills uninstall takes it back out.
If both you and a peer are behind routers with no forwarded port, browsing that peer can’t work, that’s a fundamental Soulseek/peer-to-peer limitation, not a bug.
Deeper docs live where they stay current: the full README on GitHub, and the generated API reference for the library on docs.rs.