Important
Mochi is a fork of Muse, the self-hosted Discord music bot originally created by Max Isom. It has been rebuilt on the Bun runtime with a modern toolchain (TypeScript 6, Drizzle, Biome) and is maintained under the bunkerlab-net organization.
Docker images are published to ghcr.io/bunkerlab-net/mochi.
Mochi is a self-hosted Discord music bot for small to medium servers β think a group the size of you, your friends, and their friends. It keeps Muse's feature set and rebuilds it on a current, Bun-native stack.
- π₯ Livestreams
- β© Seeking within a song/video
- πΎ Local caching for better performance
- π No vote-to-skip β playback is controlled directly
βοΈ Autoconverts playlists / artists / albums / songs from Spotify- π Plays SoundCloud tracks, sets, and user profiles directly β no API key needed
- β Users can save favorite queries for reuse
- 1οΈβ£ A single instance supports multiple guilds
- π Configurable volume controls, including optional ducking when people speak
- π Built-in
/helpthat lists every command and what it does - βοΈ Written in TypeScript, easily extendable
Mochi runs entirely on Bun β runtime, package manager, and bundler.
- Runtime: Bun
1.3.14(Node.js 24+ compatible) - Language: TypeScript 6 (strict)
- Discord: discord.js 14 +
@discordjs/voice - Database: Drizzle ORM over SQLite using Bun's built-in
bun:sqlite - Media:
ffmpeg+yt-dlp - Tooling: Biome (lint/format),
hk(git hooks)
Running Mochi needs a Discord token and a YouTube API key. Spotify and Last.fm keys are optional β Spotify keys enable Spotify URL conversion, and a Last.fm key improves autoplay recommendations:
DISCORD_TOKENβ create a 'New Application' here, then add a 'Bot'.YOUTUBE_API_KEYβ create a project, enable the YouTube Data API, and create an API key under credentials.SPOTIFY_CLIENT_IDandSPOTIFY_CLIENT_SECRET(optional) β create a Client ID here.LASTFM_API_KEY(optional) β create an API account (you only need the API key it issues). Improves autoplay recommendations; without it, autoplay falls back to YouTube mixes.
A 64-bit OS is required.
On first run Mochi logs an invite URL β open it in a browser to add Mochi to your server. Mochi DMs the server owner with setup instructions once it's added.
You can run Mochi with Docker (recommended) or from source with Bun.
Available image tags:
:latestβ the most recent release:3,:3.0,:3.0.0β semver major / minor / exact:yt-dlp-latestβ the latest release rebuilt with the newest availableyt-dlp
Replace the empty config values below:
docker run -it -v "$(pwd)/data":/data \
-e DISCORD_TOKEN='' \
-e YOUTUBE_API_KEY='' \
-e SPOTIFY_CLIENT_ID='' \
-e SPOTIFY_CLIENT_SECRET='' \
-e LASTFM_API_KEY='' \
ghcr.io/bunkerlab-net/mochi:latestThis starts Mochi and creates a data directory in your current directory for the database and cache.
You can also store tokens in an environment file and make it available to the container. By default the container reads a /config env file; customize the path with the ENV_FILE environment variable (handy for Docker secrets).
Docker Compose:
services:
mochi:
image: ghcr.io/bunkerlab-net/mochi:latest
restart: always
volumes:
- ./mochi:/data
environment:
- DISCORD_TOKEN=
- YOUTUBE_API_KEY=
- SPOTIFY_CLIENT_ID=
- SPOTIFY_CLIENT_SECRET=
- LASTFM_API_KEY=Keep the same DISCORD_TOKEN, reuse the same /data volume, and point the service at a newer image tag to upgrade in place β Mochi comes back up with the same bot identity and persisted database/cache.
Prerequisites:
- Bun
1.3.14or newer - Node.js 24 or newer
ffmpeg(4.1 or later)yt-dlpon yourPATH(or setYT_DLP_PATHto its full path)
git clone https://github.com/bunkerlab-net/mochi.git
cd mochi
cp .env.example .env # then fill in your tokens
bun install
bun start # runs pending migrations, then starts MochiFor local development, bun dev runs Mochi with file watching and auto-reload.
All settings below are environment variables (set them in your .env file or container environment).
Mochi logs through pino. Two environment variables control output:
LOG_FORMAT(defaultplain):plainfor human-readable colorized lines,jsonfor one JSON record per line, orecsfor Elastic Common Schema JSON (for log shippers).LOG_LEVEL(defaultinfo): one oftrace,debug,info,warn,error,fatal, orsilent. Operational events and failures log atinfoand above; setLOG_LEVEL=debugfor verbose per-component detail.
Mochi limits the total cache size to ~2 GB by default. Change it with CACHE_LIMIT, e.g. CACHE_LIMIT=512MB or CACHE_LIMIT=10GB.
Mochi uses yt-dlp to resolve playable YouTube and SoundCloud media URLs. The Docker image bundles it. For source installs, put yt-dlp on your PATH or set YT_DLP_PATH.
Set YT_DLP_AUTO_UPDATE=true to have Mochi attempt to update its configured yt-dlp before connecting to Discord. This works best with the Docker image's bundled virtualenv, or when YT_DLP_PATH points at a virtualenv or standalone yt-dlp executable Mochi can update.
The ghcr.io/bunkerlab-net/mochi:yt-dlp-latest image is rebuilt on a schedule from the latest release with the newest yt-dlp from PyPI. Versioned refresh tags are also published as :<mochi-version>-yt-dlp-<yt-dlp-version>.
Mochi can skip non-music segments at the start or end of a YouTube music video using SponsorBlock. It's disabled by default; enable it with ENABLE_SPONSORBLOCK=true.
Because SponsorBlock is a public service, it may be down or overloaded. When that happens, Mochi pauses SponsorBlock requests for a few minutes. Adjust the pause duration (in minutes) with SPONSORBLOCK_TIMEOUT.
When the queue runs out, Mochi keeps the music going by finding tracks similar to the one that just played (radio mode) instead of falling silent. It's on by default β toggle it per-server with /config set autoplay true|false, and check the current state with /config get autoplay.
Mochi sources similar music two ways:
- Last.fm (preferred) β when
LASTFM_API_KEYis set, Mochi uses Last.fm's similar-track recommendations and resolves them to playable YouTube videos. Create a key via a Last.fm API account; only the issued API key is needed. - YouTube mixes (fallback) β when no Last.fm key is set, or Last.fm returns nothing, Mochi seeds YouTube's auto-generated radio mix for the last track. This needs no extra configuration.
Autoplay seeds from the last track, so it only continues when that track is a YouTube source; live streams and direct HTTP streams can't be seeded.
By default Mochi shows "Online" and "Listening to music". Override it with:
BOT_STATUS:online,idle(Away), ordnd(Do Not Disturb)BOT_ACTIVITY_TYPE:PLAYING,LISTENING,WATCHING, orSTREAMINGBOT_ACTIVITY: the text that follows the activity typeBOT_ACTIVITY_URL: required when usingSTREAMINGβ a regular YouTube or Twitch stream URL
Examples
Watching a movie, Do Not Disturb:
BOT_STATUS=dnd
BOT_ACTIVITY_TYPE=WATCHING
BOT_ACTIVITY=a movie
Streaming Monstercat:
BOT_STATUS=online
BOT_ACTIVITY_TYPE=STREAMING
BOT_ACTIVITY_URL=https://www.twitch.tv/monstercat
BOT_ACTIVITY=Monstercat
If Mochi runs in many guilds (10+), you may want to register commands bot-wide instead of per guild. Set REGISTER_COMMANDS_ON_BOT=true. The trade-off: command updates can take up to an hour to propagate.
Configure Mochi to automatically duck the volume while people are speaking:
/config set reduce-vol-when-voice trueβ enable automatic volume reduction/config set reduce-vol-when-voice falseβ disable it/config set reduce-vol-when-voice-target <volume>β target volume percentage while people speak (0β100, default 20)
If ffmpeg isn't on your PATH (common on Windows), set FFMPEG_PATH to the full path of the ffmpeg executable.
The master branch is the bleeding-edge development branch and is not guaranteed to be stable. For production, run a tagged release.
Mochi is released under the MIT License. As a fork of Muse, it retains the original copyright (Β© 2020 Max Isom) alongside the fork's.
