From 59fc652eab0e8df43066d21d4f389a1355e955ca Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Tue, 9 Jun 2026 05:22:36 -0700 Subject: [PATCH] nixos: add claude-remote-control always-on service Always-on systemd user service running `claude --remote-control` in a detached tmux session (dedicated socket) pinned to /srv/dotfiles, with a claude-rc-attach alias. Enabled on railbird-sf. Ad-hoc per-directory sessions remain handled by the tmclaude shell function. Co-Authored-By: Claude Opus 4.8 (1M context) --- nixos/claude-remote-control.nix | 64 +++++++++++++++++++++++++++++++++ nixos/configuration.nix | 1 + nixos/machines/railbird-sf.nix | 1 + 3 files changed, 66 insertions(+) create mode 100644 nixos/claude-remote-control.nix diff --git a/nixos/claude-remote-control.nix b/nixos/claude-remote-control.nix new file mode 100644 index 00000000..a1c3e0bf --- /dev/null +++ b/nixos/claude-remote-control.nix @@ -0,0 +1,64 @@ +{ + pkgs, + config, + lib, + makeEnable, + ... +}: let + # Working directory the always-on session is pinned to. Ad-hoc sessions in + # other directories are handled by the `tmclaude` shell function instead. + workingDirectory = "/srv/dotfiles"; + + # Dedicated tmux socket + session name so the service owns its own tmux + # server (independent of the interactive one). Attach locally with: + # tmux -L claude-rc attach -t claude-rc + socket = "claude-rc"; + sessionName = "claude-rc"; + + # Name the session registers under for native Remote Control (phone/web). + remoteName = config.networking.hostName; + + # claude shells out to these for its tools; give the service a clean PATH. + servicePath = lib.makeBinPath (with pkgs; [ + claude-code + tmux + bashInteractive + coreutils + findutils + git + gnugrep + gnused + nix + nodejs + openssh + ripgrep + zsh + ]); +in + makeEnable config "myModules.claudeRemoteControl" false { + home-manager.users.imalison = { + systemd.user.services.claude-remote-control = { + Unit = { + Description = "Claude Code remote-control session"; + After = ["network.target"]; + }; + Service = { + # tmux new-session -d daemonizes the server and returns. + Type = "forking"; + Environment = ["PATH=${servicePath}"]; + ExecStart = lib.concatStringsSep " " [ + "${pkgs.tmux}/bin/tmux -L ${socket} new-session -d" + "-s ${sessionName} -c ${workingDirectory}" + "${pkgs.claude-code}/bin/claude --remote-control ${remoteName} --dangerously-skip-permissions" + ]; + ExecStop = "${pkgs.tmux}/bin/tmux -L ${socket} kill-server"; + Restart = "on-failure"; + RestartSec = 5; + }; + Install.WantedBy = ["default.target"]; + }; + + # Convenience: attach to the always-on session from any directory. + home.shellAliases.claude-rc-attach = "tmux -L ${socket} attach -t ${sessionName}"; + }; + } diff --git a/nixos/configuration.nix b/nixos/configuration.nix index e8605f9f..9c83e8e2 100644 --- a/nixos/configuration.nix +++ b/nixos/configuration.nix @@ -12,6 +12,7 @@ ./cache-server.nix ./cache.nix ./chrome-favicon-dbus.nix + ./claude-remote-control.nix ./code.nix ./cua.nix ./desktop.nix diff --git a/nixos/machines/railbird-sf.nix b/nixos/machines/railbird-sf.nix index 21665aa7..6224ed8d 100644 --- a/nixos/machines/railbird-sf.nix +++ b/nixos/machines/railbird-sf.nix @@ -63,6 +63,7 @@ myModules.base.enable = true; myModules.desktop.enable = true; myModules.code.enable = true; + myModules.claudeRemoteControl.enable = true; myModules.syncthing.enable = true; myModules.fonts.enable = true; myModules.plasma.enable = true;