{ config, pkgs, lib, musiclink, ... }: with lib; let cfg = config.services.musiclink; in { options.services.musiclink = { enable = mkEnableOption "MusicLink bot"; package = mkOption { type = types.package; default = musiclink; description = "The MusicLink bot package"; }; matrix = { server = mkOption { type = types.str; description = "Matrix homeserver base URL"; }; userId = mkOption { type = types.str; description = "Matrix user ID for the bot"; }; rooms = mkOption { type = types.listOf types.str; description = "Allowlisted Matrix room IDs"; }; tokenFile = mkOption { type = types.path; default = "/run/secrets/musiclink-matrix-token"; description = "Path to Matrix access token file"; }; shadow = mkOption { type = types.bool; default = false; description = "Shadow mode (log responses without sending)"; }; healthAddr = mkOption { type = types.str; default = ""; description = "Health server listen address (optional)"; }; stateStorePath = mkOption { type = types.str; default = "data/matrix-state.db"; description = "Path to Matrix sync state store"; }; }; }; config = mkIf cfg.enable { systemd.services.musiclink = { description = "MusicLink Bot"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; DynamicUser = true; StateDirectory = "musiclink"; WorkingDirectory = "/var/lib/musiclink"; LoadCredential = [ "musiclink-matrix-token:${cfg.matrix.tokenFile}" ]; ExecStartPre = pkgs.writeShellScript "generate-musiclink-config" '' set -euo pipefail MATRIX_TOKEN=$(cat $CREDENTIALS_DIRECTORY/musiclink-matrix-token) cat > /var/lib/musiclink/config.toml <