Compare commits

...

5 Commits

Author SHA1 Message Date
0xWheatyz 2624e68a7c feat(nixos): auto-start UxPlay as a user systemd service
Run UxPlay under graphical-session.target so the AirPlay receiver is
discoverable as soon as the GNOME session is up, instead of requiring
a manual `uxplay` invocation per login.

Constraint: UxPlay needs the active graphical session for display + PipeWire
Rejected: system-level service | runs before user session, no display/audio access
Rejected: GNOME autostart .desktop entry | no Restart-on-failure semantics
Confidence: high
Scope-risk: narrow
Directive: keep wantedBy on graphical-session.target (not default.target) so
  the unit only runs when a desktop session is live
Not-tested: behavior on fast user switching between two desktop sessions
2026-05-24 19:49:20 -04:00
0xWheatyz 4335687f48 feat(nixos): add iOS interop (localsend, uxplay, libimobiledevice)
Adds Mac-style iPhone interop to the GNOME host:
- LocalSend for AirDrop-style file transfer (programs.localsend
  opens TCP 53317)
- UxPlay AirPlay receiver with Avahi mDNS publishing so iOS Screen
  Mirroring discovers the host; opens UxPlay's TCP 7000/7001/7100
  and UDP 6000/6001/7011
- usbmuxd + libimobiledevice + ifuse so GVfs auto-mounts iPhone
  over USB in GNOME Files

Constraint: Continuity / Handoff / Universal Clipboard / iMessage
have no FOSS impl on Linux and are out of scope
Rejected: KDE Connect | iOS app cannot send SMS or share clipboard
  due to iOS sandbox, no parity with macOS
Rejected: shairport-sync AirPlay audio receiver | user opted out
Confidence: high
Scope-risk: narrow
Directive: Avahi publish.userServices = true is required for UxPlay
  discovery; do not narrow without retesting iOS Screen Mirroring
Not-tested: behavior when networking.firewall.enable is later
  flipped to true (currently disabled at line 128)
2026-05-24 19:34:58 -04:00
0xWheatyz 44cd77e46f chore(flake): update nixpkgs-unstable lock 2026-05-24 19:24:50 -04:00
0xWheatyz 5b66eb3049 chore(claude): enable onboarding flag and allow monitor tool 2026-05-24 19:24:47 -04:00
0xWheatyz 1eddde2bdb chore(flake): update nixpkgs lock 2026-05-19 17:52:17 -04:00
3 changed files with 49 additions and 5 deletions
+42 -2
View File
@@ -105,6 +105,10 @@
adwaita-icon-theme
pkgs-unstable.claude-code # Use unstable for latest version
yubikey-manager
# iOS interop
uxplay
libimobiledevice
ifuse
];
# Some programs need SUID wrappers, can be configured further or are
@@ -116,6 +120,12 @@
pinentryPackage = pkgs.pinentry-gnome3;
};
# AirDrop-style file transfer (LocalSend)
programs.localsend = {
enable = true;
openFirewall = true;
};
# List services that you want to enable:
# Enable the OpenSSH daemon.
@@ -225,11 +235,12 @@
};
# Open firewall for Tailscale
# Open firewall for Tailscale + UxPlay AirPlay receiver
networking.firewall = {
checkReversePath = "loose";
trustedInterfaces = [ "tailscale0" "wg0" ];
allowedUDPPorts = [ config.services.tailscale.port ];
allowedTCPPorts = [ 7000 7001 7100 ];
allowedUDPPorts = [ config.services.tailscale.port 6000 6001 7011 ];
};
# Auto-connect tailscale on boot
@@ -267,6 +278,35 @@
services.pcscd.enable = true;
# iPhone USB mount (libimobiledevice)
services.usbmuxd.enable = true;
# mDNS for AirPlay receiver (UxPlay) discovery from iPhone
services.avahi = {
enable = true;
nssmdns4 = true;
openFirewall = true;
publish = {
enable = true;
addresses = true;
userServices = true;
};
};
# Auto-start UxPlay with the graphical session so iOS Screen Mirroring
# can find this host without manually launching it.
systemd.user.services.uxplay = {
description = "UxPlay AirPlay Mirror Receiver";
partOf = [ "graphical-session.target" ];
after = [ "graphical-session.target" "pipewire.service" ];
wantedBy = [ "graphical-session.target" ];
serviceConfig = {
ExecStart = "${pkgs.uxplay}/bin/uxplay";
Restart = "on-failure";
RestartSec = 5;
};
};
security.pam.services = {
login.u2fAuth = true;
sudo.u2fAuth = true;
Generated
+3 -3
View File
@@ -92,11 +92,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1776329215,
"narHash": "sha256-a8BYi3mzoJ/AcJP8UldOx8emoPRLeWqALZWu4ZvjPXw=",
"lastModified": 1779536132,
"narHash": "sha256-q+fF42iv/geEbHfgSzy3tS0FF/EyD6XTZ98E6yxiBO8=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "b86751bc4085f48661017fa226dee99fab6c651b",
"rev": "3d8f0f3f72a6cd4d93d0ad13203f2ea1cb7e1456",
"type": "github"
},
"original": {
+4
View File
@@ -271,6 +271,7 @@
home.file.".claude/settings.json" = {
text = builtins.toJSON {
hasCompletedOnboarding = true;
permissions = {
allow = [
"Edit"
@@ -283,6 +284,7 @@
"WebSearch"
"Agent"
"NotebookEdit"
"Monitor"
];
};
alwaysThinkingEnabled = true;
@@ -294,6 +296,8 @@
env = {
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
OMC_PLUGIN_ROOT = "${oh-my-claudecode}";
#ANTHROPIC_BASE_URL = "http://10.0.1.16:20128/v1";
#ANTHROPIC_AUTH_TOKEN = "sk-634d6ea8670969de-qzxian-1a74cc97";
};
teammateMode = "tmux";
};