echo is a native desktop music player and Spotify client written in Rust. echo brings your entire Spotify library — liked songs, playlists, albums, and the artists you follow — plus your local music files into one fast, keyboard-friendly app, with full playback control, synced lyrics, and dynamic theming. A companion terminal client (spotify) ships in the same install for when you'd rather live in the terminal.
- Native desktop app: Built on GPUI (Zed's UI framework) for a fast, GPU-accelerated interface that runs on Windows, macOS, and Linux. Drive it with the mouse or entirely from the keyboard.
The Home page brings together quick picks, recent listening, top artists and songs, and new releases; open it with
ctrl-h(ctrl-shift-hon macOS). - Your whole library: Playlists, albums, and followed artists in one sidebar, with Top Tracks, Recently Played, and Top Artists views.
- Full playback control: Play/pause, next/previous, seek, shuffle, repeat, volume, queue, and device switching from the now-playing bar.
- Synced lyrics: Time-synced lyrics inline in the player bar or as a full-screen view.
- What's New: A feed of recent albums and singles from the artists you follow, refreshed at most every 6 hours.
- Blazing fast Liked Songs: Your entire Liked Songs library is cached locally (
~/.config/echo/cache.json) for zero-latency, rate-limit-free scrolling, even with thousands of saved tracks. - Library management: Create, rename, delete, and organize playlists into folders; reorder tracks in your own playlists.
- Local music support: Scan a local music folder, play local files, and create local playlists that can also reference Spotify tracks.
- Search: Fast global search (
ctrl-k) across the Spotify catalog and your scanned local tracks. - Dynamic theming: Ship-with themes plus live theme editing — see Themes.
- Terminal client: The same install also puts a full-featured
spotifyTUI on yourPATH— see Terminal client (TUI).
- Spotify Premium: A Spotify Premium account is required to use the Spotify Web API for playback control.
- Spotify Developer App:
- Go to the Spotify Developer Dashboard.
- Create an app and get your
Client IDandClient Secret. - Add
http://127.0.0.1:8888/callbackto your app's Redirect URIs. - echo also uses
http://127.0.0.1:8989/loginfor its internal first-party Spotify session.
One command, one install: the desktop app and the spotify terminal command.
Linux and macOS
curl -fsSL https://github.com/and2049/echo/releases/latest/download/install.sh | shWindows (PowerShell)
irm https://github.com/and2049/echo/releases/latest/download/install.ps1 | iexNeither needs administrator rights. Both put spotify on your PATH — open a new terminal afterwards — and add the desktop app to your Start menu, Launchpad, or applications menu.
| Platform | Where it lands |
|---|---|
| Windows | %LOCALAPPDATA%\Programs\echo (installed from the release MSI, x64) |
| macOS | /Applications/echo.app, with spotify linked into ~/.local/bin (Apple Silicon) |
| Linux | ~/.local/share/echo, with both commands linked into ~/.local/bin (x86_64) |
To pin a version or remove echo:
curl -fsSL https://github.com/and2049/echo/releases/latest/download/install.sh | sh -s -- --version 0.4.6
curl -fsSL https://github.com/and2049/echo/releases/latest/download/install.sh | sh -s -- --uninstall& ([scriptblock]::Create((irm https://github.com/and2049/echo/releases/latest/download/install.ps1))) -Version 0.4.6
& ([scriptblock]::Create((irm https://github.com/and2049/echo/releases/latest/download/install.ps1))) -UninstallUninstalling leaves your settings in ~/.config/echo alone.
On Linux the desktop app links against a few system libraries — on Debian/Ubuntu:
sudo apt-get install libasound2 libdbus-1-3 libssl3 \
libfontconfig1 libxkbcommon0 libxkbcommon-x11-0 libwayland-client0 libx11-xcb1A desktop install already has most of these. Rendering prefers Vulkan and falls back to
OpenGL, so libvulkan1 plus your GPU's driver is worth having but is not required.
Desktop releases install automatically in the background; turn this off in Settings or with :autoupdate off.
After the first install, echo updates itself — no reinstall, no administrator rights:
spotify upgrade # upgrade to the latest release
spotify upgrade --check # only report whether one is available
spotify upgrade 0.4.6 # move to a specific versionThe desktop app does the same from Settings → Updates → Check for updates. Both swap the binaries and bundled themes in place and ask you to restart.
Clone the repository and build using Cargo:
Linux dependencies (Ubuntu/Debian):
sudo apt-get install -y --no-install-recommends \
libasound2-dev libdbus-1-dev pkg-config libssl-dev \
libfontconfig-dev libwayland-dev libx11-xcb-dev libxkbcommon-x11-devgit clone https://github.com/and2049/echo.git
cd echo
cargo build --release -p echo-desktop -p spotify-tuiRun the desktop app or the terminal client:
./target/release/echo-desktop # desktop app
./target/release/spotify # terminal clientA bare cargo build --release (or cargo run) builds only the spotify terminal client — the workspace's default member — so name -p echo-desktop to build the desktop app.
The terminal command is
spotify— the previous name collided with the shell builtinecho. Configuration and caches still live in~/.config/echo/, so existing setups keep working after the rename. On Windows, if the official Spotify client's directory happens to be on yourPATH, make sure%USERPROFILE%\.cargo\bin(or wherever you installed this binary) comes first.
On first run, echo will prompt you to enter your Client ID and Client Secret, then open your browser to authenticate with Spotify.
The desktop app works with the mouse — click a playlist, artist, or track to open it, use the controls in the now-playing bar, and drag tracks to reorder your own playlists. It's also fully keyboard-driven. Press ? at any time for the in-app shortcut overlay, ctrl-, for settings, and t to switch themes. The keybindings mirror the terminal client below.
Navigation: j / k / ↓ / ↑ to move, gg / G to jump to first / last, ctrl-b / ctrl-f to page, ctrl-u / ctrl-d for half a page, enter / z to open, h / esc to go back, ← / → to move focus between panes, tab to switch tabs, gc to jump to the playing track.
Playback: space play/pause, [ / ] (or ctrl-← / ctrl-→) previous / next, , / . seek, - / = volume, shift-M mute, s / r shuffle / repeat, shift-D device menu, shift-L full-screen lyrics, ctrl-shift-L lyrics in the player bar, shift-F immersive view.
Library: l like/unlike, a add to playlist, shift-A track actions, q / shift-Q queue, shift-J / shift-K move a track within your own playlist, dd delete, v select a range, m pin, c / e create / rename.
Finding things: ctrl-k global search, / filter the current list, n / shift-N next / previous match, : command bar, t themes, ? help, ctrl-q quit.
Closing the window keeps echo playing: on Windows and Linux it hides to a tray icon (click it to bring the window back, or pick Quit), on macOS it stays in the Dock. Turn that off with :tray off or Settings → Window; ctrl-q always quits. Launching echo again brings the running one forward instead of starting a second copy.
The : command bar accepts the same commands as the terminal client — see Commands.
The same install also ships spotify, a full-featured terminal client with native in-terminal image rendering. It shares echo's cache, config, playback engine, and commands with the desktop app.
- Terminal image support: Renders high-quality album art and playlist covers directly in your terminal (supports Kitty, Sixel, and half-block fallbacks).
- Everything the desktop app does: the same library, search, local music, playback, and
:commands, driven entirely from the keyboard.
echo is heavily keyboard-driven.
j/korDown/Up: Move down / upgg/G: Jump to the first / last itemCtrl-b/Ctrl-forPage Up/Page Down: Move one pageCtrl-u/Ctrl-d: Move half a pageCtrl-l: Clear and fully redraw the TUIgc: Jump to the currently playing track or its available contextEnterorz: Select item / Open playlist / Play trackh/q/Esc/Backspace: Go back / Close modal / Clear searchTab: Switch tabs (e.g., Playlists ↔ Albums, Search Tracks ↔ Search Albums, artist discography All ↔ Albums ↔ Singles & EPs ↔ Appears On):: Enter Command Mode/: Search within tracklistf: Global searchn/N: Jump to next / previous search match within a list
Space: Play / Pause]/>: Next Track[/<: Previous Track,/.: Seek backward / forward by 5 seconds0: Seek to the start of the current trackM(Shift + m): Mute / restore the previous volumes: Toggle Shuffler: Toggle Repeat Mode (Off → Track → Context)=/-: Volume Up / Down (by 1%)+/_: Volume Up / Down (by 5%)D(Shift + d): Open Device Selection menuL(Shift + l): Toggle synced lyrics (a panel docked on the right in the desktop app, a full-screen modal in the terminal)Ctrl + Shift + L: Toggle condensed Synced Lyrics view
l: Like / Unlike the selected trackA(Shift + a): Open action menu for hovered track (or currently playing if not focused in track page)p: paste a cut playlist into a foldera: Add selected track to playlist / Add selected album to libraryq: Add currently hovered track to QueueQ(Shift + q): Open Queue view (the desktop app's playback-bar queue button docks the queue on the right instead)m: Pin / Unpin a playlistT(Shift + t): Toggle library thumbnails (cover art next to playlist / album names)c: Quick shortcut to create a new playliste: Quick shortcut to rename a playlist or folderv: Enter Visual mode for multi-selectiond(double press): Delete playlist/folder, or remove a track from your custom playlistx: Cut playlist (to move into a folder)J/K(Shift + j / k, desktop): Move the selected track down / up within one of your own playlists (drag-and-drop works too); requires the original sort orderR(Shift + r): Force refreshF(Shift + f, terminal): Follow / unfollow the artist whose page is open (the desktop app has a Follow button in the header)
The track action menu adapts to the source. Spotify tracks support link copying, liking, and album library actions. Local tracks support copying their absolute path and revealing the file in the platform file manager. Both sources retain album/artist navigation, playlist insertion, and queue actions where applicable.
While in Command Mode (:), you can use the following:
:search <query>: Search for tracks or albums.:newplaylist <name>: Create a new playlist.:newlocalplaylist <name>: Create a local playlist stored on this machine.:localpath <absolute-folder-path>: Set the local music folder and scan it. The path must be absolute and works on macOS, Windows, and Linux.:rescanlocal: Rescan the configured local music folder.:newfolder <name>: Create a new folder to organize playlists.:delfolder: Delete the currently selected folder.:rename <name>: Rename the currently selected playlist or folder.:sort <alpha|creator>: Sort the playlist library.:sort <original|title|artist|album|duration|added|reverse>: Sort the active track list entirely in memory.:seek <seconds|+seconds|-seconds>: Seek to an absolute position or by a relative offset.:sleep <30m|1h|off>: Pause playback after a delay (sleep timer).:mute: Mute playback or restore the previous volume.:open [spotify-url-or-uri]: Open a Spotify track, album, artist, or playlist. With no argument, read it from the clipboard.:relative <on|off|toggle>: Configure Vim-style relative line numbers in track lists.:redraw: Clear and fully redraw the TUI after unexpected terminal output.:theme <theme_name>: Switch application theme.:lang <en|zh|zh-CN>: Switch language.:album: Jump to the album of the currently selected track.:queue: Open the Queue view.:clearqueue: Clear the manually queued tracks (only while playing on this device).:vis: Toggle the audio visualizer.:visbins <number>: Set the number of audio visualizer frequency bins (5-32).:pixelate <pixels>: Enable retro 8-bit aesthetic on album covers. Set to 0 to disable, or e.g., 16 for a pixelated look.:backdrop <lights|mesh|aurora|vinyl|nebula>: Pick the moving picture behind the desktop app's immersive view (also in Settings).:tray [on|off]: Whether the desktop app's close button hides it to the tray instead of quitting (also in Settings).:thumbs [on|off]: Toggle cover-art thumbnails in the library sidebar. Covers are cached in~/.config/echo/thumbs/so they load instantly on later launches.:index <number>: Set track index base (1-indexed vs 0-indexed).:quit,:q,:qa,:wq: Exit the application.
Add a keybindings table under [library] in ~/.config/echo/config.toml to override or add semantic mappings. Single keys, modifier keys such as ctrl-f, and two-key sequences are supported. Unmapped keys keep echo's defaults.
[library.keybindings]
"s d" = "sort_duration"
"s a" = "sort_artist"
"ctrl-j" = "half_page_down"
"ctrl-k" = "half_page_up"
";" = "seek_forward"Available actions are first, last, page_up, page_down, half_page_up, half_page_down, current_context, play_pause, next, previous, shuffle, repeat, seek_backward, seek_forward, seek_start, mute, sort_original, sort_title, sort_artist, sort_album, sort_duration, sort_added, reverse_tracks, redraw, and toggle_thumbnails.
Track sorting and navigation operate on already-loaded data. They do not issue Spotify requests. Navigation history retains up to 20 in-memory views so returning to a previous track list normally does not refetch it.
Themes live in themes/*.toml as a flat list: nine base colors followed by the twelve derived colors the desktop app paints, every one explicit with a comment saying what it drives. Edit values freely, or change base colors and run python themes/generate_desktop.py to recompute the derived ones. Derived keys are optional — a missing key is computed with the formula named in its comment, and a [desktop] table is also accepted for overrides. To iterate visually, python tools/theme-preview/serve.py opens a live mock of the desktop window in the browser that repaints on every save — no rebuild needed. Colors can be edited in either direction: change the toml in your editor, or click any color in the preview's legend to adjust it with a picker that writes straight back to the file (its "recompute derived" button re-runs the generator for the current theme).
echo streams at 320 kbps and applies volume normalisation, matching the Spotify desktop app's defaults. These live under [library] in ~/.config/echo/config.toml and take effect on the next launch.
[library]
bitrate = 320 # 96, 160, or 320
normalisation = true # Even out loudness between tracks, like the Spotify app.
normalisation_pregain = 3.0 # dB added back after normalisation. Raise if playback is too quiet.Normalisation attenuates each track by its ReplayGain value, which is typically several dB on modern masters. normalisation_pregain adds that headroom back so playback lands at a comparable level to the Spotify app. The gain is applied ahead of librespot's dynamic limiter, so raising it does not clip. Setting normalisation = false skips the gain stage entirely for bit-exact full-scale output, at the cost of loudness jumps between tracks.
Volume is applied entirely client-side — Spotify streams arrive at full scale, and echo attenuates them itself, so the device's volume slider in other Spotify clients is inactive. Both Spotify and local playback use the same cubic volume curve, so a given percentage sounds the same whichever source is playing, and 100% is unity gain on both.
echo opens the output device as stereo at 44.1 kHz — librespot's native rate, so no resampling — whenever the device supports it. Devices that do not offer 44.1 kHz (most Windows endpoints default to 48 kHz) fall back to the device's own default rate.
The endpoint actually opened is written to echo-debug-audio-spotify.log in the working directory, and echo-debug-audio-local.log for local files:
device=Headphones (WH-1000XM5) channels=2 sample_rate=48000 format=F32
Local support is separate from Spotify. Use :localpath <absolute-folder-path> to choose the folder echo should scan. Supported audio extensions are mp3, wav, flac, ogg, m4a, and aac; echo scans recursively and reads title, artist, album, duration, and artwork when available. echo refreshes the configured local folder on startup and watches it for supported audio/artwork changes while running; :rescanlocal is still available as a manual fallback.
Local playlists are stored locally and are not Spotify playlists. They can contain local tracks and Spotify track references. Spotify playlists cannot contain local tracks. Local shuffle, repeat, volume, queue, and play/pause are handled by echo's local playback engine.
Embedded artwork is used when available. If a track has no embedded artwork, echo looks for folder artwork such as cover.jpg, folder.jpg, or front.png.
- Theme color rendering issues (Windows): Disable "Adjust indistinguishable text" in the Appearance settings of the Defaults profile.
- Images not rendering: Cover art is drawn with half-block cells and needs nothing from the terminal beyond truecolor support, which every modern terminal has.
- Cache desync: If your Liked Songs are out of sync with other devices, simply restart echo. It eagerly syncs your library in the background on startup.
- Local file missing: If a file was deleted or moved after scanning, run
:rescanlocalto refresh the local library. - Audio sounds mono or muffled (Bluetooth headsets): Windows exposes a Bluetooth headset as two output devices — a stereo "Headphones" (A2DP) endpoint, and a mono "Hands-Free" (HFP) endpoint capped at 16 kHz. Windows switches to Hands-Free whenever an application opens the microphone. Check
echo-debug-audio-spotify.log: if it reportschannels=1, quit whatever is holding the mic and select the stereo endpoint as your default output device. - Configuration Path:
~/.config/echo/config.toml(holds tokens and preferences),~/.config/echo/cache.json(holds liked tracks),~/.config/echo/local_library.json, and~/.config/echo/local_playlists.json.

