-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add Input Leap KVM and enable Tailscale on matic #1288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f35e482
dd076f0
19966ac
2e69c77
c607e9a
1f9bee2
cf9582a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ in | |
| ./git-ai | ||
| ./gomi | ||
| ./ghostty | ||
| ./input-leap | ||
| ./iterm2 | ||
| ./hammerspoon | ||
| ./jj | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { config, pkgs, ... }: | ||
| let | ||
| inherit (pkgs) lib; | ||
| inherit (pkgs.stdenv) isDarwin isLinux; | ||
| in | ||
| { | ||
| # Server config on galactica (macOS) | ||
| home.file."Library/Application Support/InputLeap/InputLeap.conf" = lib.mkIf isDarwin { | ||
| source = ./server.conf; | ||
| }; | ||
|
|
||
| # Server config on galactica (XDG fallback) | ||
| xdg.configFile."InputLeap/InputLeap.conf" = lib.mkIf isDarwin { | ||
| source = ./server.conf; | ||
| }; | ||
|
Comment on lines
+12
to
+15
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| section: screens | ||
| galactica: | ||
| matic: | ||
| end | ||
|
|
||
| section: links | ||
| galactica: | ||
| right = matic | ||
| matic: | ||
| left = galactica | ||
| end | ||
|
|
||
| section: options | ||
| keystroke(super+shift+left) = switchInDirection(left) | ||
| keystroke(super+shift+right) = switchInDirection(right) | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| # Input Leap | ||
|
|
||
| Input Leap shares keyboard and mouse between machines over the network. Traffic flows over Tailscale (WireGuard-encrypted), so Input Leap's own TLS is disabled. | ||
|
|
||
|
Comment on lines
+3
to
+4
|
||
| ## Architecture | ||
|
|
||
| | Machine | Role | Service type | | ||
| |---|---|---| | ||
| | galactica | Server (shares keyboard/mouse) | launchd agent | | ||
| | matic | Client (receives input) | systemd user service | | ||
| | kyber | Not configured (headless server) | N/A | | ||
|
|
||
| ## Config files | ||
|
|
||
| | File | Purpose | | ||
| |---|---| | ||
| | `config/input-leap/server.conf` | Screen layout and hotkeys | | ||
| | `config/input-leap/default.nix` | Deploys server config to galactica | | ||
| | `home-manager/services/input-leap/default.nix` | Server (launchd) and client (systemd) services | | ||
|
|
||
| ## Screen layout | ||
|
|
||
| ``` | ||
| [ galactica ] --right--> [ matic ] | ||
| [ matic ] --left--> [ galactica ] | ||
| ``` | ||
|
|
||
| Defined in `config/input-leap/server.conf`. Edit `right`/`left`/`up`/`down` to match physical monitor positions. | ||
|
|
||
| ## Hotkeys | ||
|
|
||
| - `Super+Shift+Left` — switch to left screen | ||
| - `Super+Shift+Right` — switch to right screen | ||
|
|
||
| ## Setup | ||
|
|
||
| ### 1. Deploy | ||
|
|
||
| **galactica:** | ||
| ```sh | ||
| make switch-galactica | ||
| ``` | ||
|
|
||
| **matic:** | ||
| ```sh | ||
| make build HOST=matic && make switch HOST=matic | ||
| ``` | ||
|
|
||
| ### 2. Verify Tailscale connectivity | ||
|
|
||
| Both machines must be on the same tailnet: | ||
|
|
||
| ```sh | ||
| tailscale ping galactica # from matic | ||
| tailscale ping matic # from galactica | ||
| ``` | ||
|
|
||
| ### 3. Services start automatically | ||
|
|
||
| - **galactica**: launchd starts `input-leaps` on `:24800` | ||
| - **matic**: systemd starts `input-leapc` connecting to `galactica:24800` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Check server logs (galactica) | ||
|
|
||
| ```sh | ||
| cat /tmp/input-leap-server.log | ||
| cat /tmp/input-leap-server.error.log | ||
| ``` | ||
|
|
||
| ### Check client logs (matic) | ||
|
|
||
| ```sh | ||
| journalctl --user -u input-leap-client -f | ||
| ``` | ||
|
|
||
| ### Restart services | ||
|
|
||
| **galactica:** | ||
| ```sh | ||
| launchctl kickstart -k gui/$(id -u)/org.nix-community.home.input-leap-server | ||
| ``` | ||
|
|
||
| **matic:** | ||
| ```sh | ||
| systemctl --user restart input-leap-client | ||
| ``` | ||
|
|
||
| ### MagicDNS not resolving | ||
|
|
||
| If `galactica` doesn't resolve from matic, use the Tailscale IP: | ||
|
|
||
| ```sh | ||
| # Get galactica's Tailscale IP | ||
| tailscale ip -4 galactica | ||
| ``` | ||
|
|
||
| Then update `home-manager/services/input-leap/default.nix` to use the IP instead of the hostname. | ||
|
|
||
| ### macOS accessibility permissions | ||
|
|
||
| Input Leap needs Accessibility permissions on macOS to control keyboard/mouse. On first run, macOS will prompt to grant access in System Settings > Privacy & Security > Accessibility. | ||
|
|
||
| ### Wayland/X11 | ||
|
|
||
| The client on matic runs under Hyprland (Wayland). Input Leap's Wayland support requires `libei`. If input doesn't work, check that `input-leap` was built with `libei` support. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # Tailscale | ||
|
|
||
| Tailscale VPN connects all machines via WireGuard tunnels with MagicDNS. | ||
|
|
||
| ## Machines | ||
|
|
||
| | Machine | OS | Method | Config location | | ||
| |---|---|---|---| | ||
| | galactica | macOS (aarch64-darwin) | Homebrew cask `tailscale-app` | `nix-darwin/config/homebrew.nix` | | ||
| | matic | NixOS (x86_64-linux) | `services.tailscale.enable` | `named-hosts/matic/default.nix` | | ||
| | kyber | Ubuntu (x86_64-linux) | Home-manager module `modules.tailscale` | `named-hosts/kyber/default.nix` | | ||
|
|
||
| ## galactica (macOS) | ||
|
|
||
| Installed as a Homebrew cask (`tailscale-app`). The CLI is also available via `home-manager/packages/default.nix` (`tailscale`). | ||
|
|
||
| Managed through the macOS menu bar app. No nix service configuration. | ||
|
|
||
| ### Setup | ||
|
|
||
| 1. `make switch-galactica` installs the app | ||
| 2. Open Tailscale from Applications and sign in | ||
|
|
||
| ## matic (NixOS) | ||
|
|
||
| Uses the native NixOS Tailscale module: | ||
|
|
||
| ```nix | ||
| # named-hosts/matic/default.nix | ||
| services.tailscale.enable = true; | ||
| ``` | ||
|
|
||
| This creates and enables the `tailscaled` systemd service automatically. | ||
|
|
||
| ### Setup | ||
|
|
||
| 1. `make build HOST=matic && make switch HOST=matic` | ||
| 2. Authenticate: | ||
|
|
||
| ```sh | ||
| sudo tailscale login | ||
| ``` | ||
|
|
||
| 3. Verify: | ||
|
|
||
| ```sh | ||
| tailscale status | ||
| ``` | ||
|
|
||
| ## kyber (Ubuntu) | ||
|
|
||
| Uses the custom home-manager module (`home-manager/modules/tailscale/`), which installs a system-level `tailscaled` service via `installSystemService`: | ||
|
|
||
| ```nix | ||
| # named-hosts/kyber/default.nix | ||
| modules.tailscale = { | ||
| enable = true; | ||
| installSystemService = true; | ||
| extraUpArgs = [ | ||
| "--reset" | ||
| "--accept-dns=false" | ||
| ]; | ||
| }; | ||
| ``` | ||
|
|
||
| DNS acceptance is disabled (`--accept-dns=false`) on kyber. | ||
|
|
||
| ### Setup | ||
|
|
||
| The initial bootstrap script (`named-hosts/kyber/setup.sh`) handles Tailscale installation: | ||
|
|
||
| ```sh | ||
| curl -fsSL https://tailscale.com/install.sh | sh | ||
| sudo systemctl enable --now tailscaled | ||
| sudo tailscale up | ||
| ``` | ||
|
|
||
| After the initial setup, subsequent rebuilds are managed via home-manager. | ||
|
|
||
| ## MagicDNS | ||
|
|
||
| With all machines on the same tailnet, they resolve each other by hostname: | ||
|
|
||
| ```sh | ||
| ping galactica | ||
| ping matic | ||
| ping kyber | ||
| ``` | ||
|
|
||
| If MagicDNS isn't working, use Tailscale IPs directly: | ||
|
|
||
| ```sh | ||
| tailscale ip -4 galactica | ||
| tailscale ip -4 matic | ||
| tailscale ip -4 kyber | ||
| ``` | ||
|
|
||
| ## Useful commands | ||
|
|
||
| ```sh | ||
| tailscale status # list connected nodes | ||
| tailscale ping <host> # check latency to a node | ||
| tailscale ip -4 <host> # get Tailscale IPv4 address | ||
| tailscale netcheck # diagnose connectivity | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| { inputs, pkgs, ... }: | ||
| let | ||
| inherit (pkgs) lib; | ||
| inherit (pkgs.stdenv) isDarwin; | ||
| inherit (inputs.host) isMatic; | ||
| in | ||
| { | ||
| # macOS: launchd agent for input-leap server | ||
| launchd.agents.input-leap-server = lib.mkIf isDarwin { | ||
| enable = true; | ||
| config = { | ||
| ProgramArguments = [ | ||
| "${pkgs.input-leap}/bin/input-leaps" | ||
| "--no-daemon" | ||
| "--config" | ||
| "${../../../config/input-leap/server.conf}" | ||
|
Comment on lines
+15
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The hardcoded relative path to the config file is fragile. Following the suggestion to pass You'll also need to update the function signature at the top of this file to accept { pkgs, configFile, ... }:
... |
||
| "--address" | ||
| ":24800" | ||
| "--disable-crypto" | ||
|
Comment on lines
+17
to
+19
|
||
| ]; | ||
| KeepAlive = true; | ||
| RunAtLoad = true; | ||
| StandardOutPath = "/tmp/input-leap-server.log"; | ||
| StandardErrorPath = "/tmp/input-leap-server.error.log"; | ||
|
Comment on lines
+23
to
+24
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Storing log files in Following the suggestion to pass the { config, pkgs, ... }:
...With this change, also remember to update the log file paths in |
||
| }; | ||
| }; | ||
|
|
||
| # Only on matic (not kyber) | ||
| systemd.user.services.input-leap-client = lib.mkIf isMatic { | ||
| Unit = { | ||
| Description = "Input Leap client (connects to galactica)"; | ||
| After = [ | ||
| "graphical-session.target" | ||
| "network-online.target" | ||
| ]; | ||
| Requires = [ "graphical-session.target" ]; | ||
|
Comment on lines
+32
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if network-online.target exists in user session context
# This target is typically system-level only
echo "=== Checking systemd user targets documentation ==="
# Search for any existing services in the repo using network-online.target in user context
rg -n "network-online.target" --type nixRepository: shunkakinoki/dotfiles Length of output: 754 🏁 Script executed: cat -n home-manager/services/input-leap/default.nixRepository: shunkakinoki/dotfiles Length of output: 1721 🏁 Script executed: cat -n home-manager/services/neverssl-keepalive/default.nixRepository: shunkakinoki/dotfiles Length of output: 1863 Add The 🔧 Suggested fix Unit = {
Description = "Input Leap client (connects to galactica)";
+ Wants = [ "network-online.target" ];
After = [
"graphical-session.target"
"network-online.target"
];
Requires = [ "graphical-session.target" ];
};🤖 Prompt for AI Agents |
||
| }; | ||
| Service = { | ||
| Type = "simple"; | ||
| ExecStart = "${pkgs.input-leap}/bin/input-leapc --no-daemon --name matic --disable-crypto galactica:24800"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The server hostname # At the top of the file
let
...
inputLeapServerHost = "galactica";
inputLeapClientName = "matic";
in
... |
||
| Restart = "on-failure"; | ||
| RestartSec = 5; | ||
| }; | ||
| Install = { | ||
| WantedBy = [ "graphical-session.target" ]; | ||
| }; | ||
| }; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isLinuxis inherited but unused in this module. Please remove the unused binding (and consider dropping/renaming other unused args likeconfigif you want to keep the module lint-clean).