Compare commits

...

20 Commits

Author SHA1 Message Date
b9c48f9dd1 Complete migration of home-manager modules to roles
Migrate all remaining home-manager modules from home/modules/ to home/roles/
to establish a unified role-based configuration pattern. This completes the
migration started in Phase 1.

Changes:
- Phase 1-3: Migrated tmux, plasma-manager, kubectl, and emacs to roles
- Phase 4: Migrated aerospace with custom options under home.roles.aerospace.*
- Phase 5: Migrated i3+sway with shared config and override options
- Phase 6: Removed empty home/modules/ directory

All home configs now import only ./roles with role-based enable options.
Updated flake.nix machine-specific overrides to use new namespaces.

Verified with nix flake check - all configurations build successfully.
2025-12-02 14:34:11 -08:00
34351403d1 Extract aerospace configuration into reusable modules
Create both home-manager and nix-darwin modules for aerospace window
manager configuration, removing 110+ lines of duplicated config from
machine-specific files.

Changes:
- Add home/modules/aerospace module with configurable leader key
- Add modules/aerospace.nix for system-level macOS settings
- Include autoraise configuration in home module
- Update home-darwin-work.nix to use new modules
- Update johno-macbookpro configuration to use system module
- Remove inline aerospace/autoraise config and launchd agents
2025-12-01 19:02:00 -08:00
12820ce9ff [aerospace] Disable macOS Spaces mutli-display
This option is known to cause all sorts of issues with aerospace
apparently
2025-12-01 18:18:56 -08:00
0f5eb2e572 [i3+sway] Add focus child binding 2025-12-01 17:39:33 -08:00
f356c91fdb [gaming] Remove heavy build packages
dolphin-emu-primehack will be available as a pre-build in 25.11

retroarch-full -- in general I'm wondering of using steam>retroarch is a
better experience
2025-11-29 11:30:10 -08:00
6b42612135 [gaming] Use recommended steam setup
Updated to use programs.steam recommended from the NixOS wiki
2025-11-29 11:29:43 -08:00
50a8c44d10 [launchers] Add launcher wrappers for compact env
Adds a module to launch specific nixpkgs dynamically, such that they
won't be always included in the nix store
2025-11-29 11:28:04 -08:00
7011fb27a5 Update workspace button background color in waybar 2025-11-26 17:20:55 -08:00
1ff8b81f44 Add environment-specific claude-code package distribution system
Development environments now use standard nixpkgs claude-code by default.
Work environments override with custom binary distribution to bypass
corporate npm registry restrictions via Google Cloud Storage.
2025-11-26 17:20:31 -08:00
55f13dfb08 Rename claude-cli package to claude-code for consistency with nixpkgs 2025-11-26 17:20:17 -08:00
63bf19b85f [claude-code] update 2025-11-25 13:39:02 -08:00
1f9e9138ab Add automated update script for claude-cli package
Create update.sh script that fetches the latest claude-code version
and SHA256 hashes from Homebrew cask and automatically updates the
Nix package definition.

Features:
- Fetches version and all 4 platform SHA256 hashes from Homebrew
- Updates default.nix in-place using awk for reliable parsing
- Validates extracted data before updating
- Supports --dry-run mode to preview changes
- Supports --help flag for usage information
- Idempotent (safe to run multiple times)

Update README to document the automated update method as the
recommended approach, with manual update as a fallback option.
2025-11-25 13:39:02 -08:00
e218822566 Add configurable Claude Code model selection
Add allowArbitraryClaudeCodeModelSelection option to development role
to control whether model specifications are preserved in humanlayer
commands and agents. Defaults to false (strip models) for backward
compatibility. Enable on home-darwin-work to preserve model specs
for opus/sonnet selection.
2025-11-25 13:39:02 -08:00
e88f3580e9 Add thoughts directory to gitignore 2025-11-25 13:39:01 -08:00
5451e75480 Add custom claude-cli package to bypass npm registry restrictions
Create custom Nix package for Claude Code CLI that fetches directly from
Anthropic's Google Cloud Storage distribution instead of npm registry,
working around Block's Cloudflare Teams dependency confusion protection.

- Add claude-cli package with platform-specific binaries
- Include comprehensive README with update instructions
- Enable development role on work machine
- Switch from unstable.claude-code to custom.claude-cli
- Add google-cloud-sdk to work machine packages
2025-11-25 13:38:53 -08:00
fc9474a7c9 [home] Create explicit kubectl role
This allows work machines to enable development, while not including
non-work-related kubectl management stuffs.
2025-11-25 13:37:40 -08:00
20daebbd61 Add ccr and unstable codex 2025-11-24 22:16:12 -08:00
3be23304c4 [development] Fix humanlayer plugins
Removes model specification to better support Claude Code Pro plan.
Because of this, I also re-removed this role from home-darwin-work as we
can take advantage of more powerful models in that context. We will just
need to install the plugins external from nix. Eventually I can turn
this into a config option of course.

Also made sure we are installing the agents from the plugin in addition
to the commands.
2025-11-22 09:47:55 -08:00
9059a739a0 [development] Add claude code plugins 2025-11-22 09:32:54 -08:00
977125645b Remove transition documentation 2025-11-19 19:43:59 -08:00
31 changed files with 1093 additions and 722 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
result result
thoughts

View File

@@ -1,280 +0,0 @@
# Steam Deck (nix-deck) Jovian-NixOS Setup Guide
This document describes the setup for installing and maintaining NixOS with Jovian-NixOS on a Steam Deck.
## Overview
The `nix-deck` configuration provides:
- **Jovian-NixOS integration** for Steam Deck hardware support
- **Remote building** using `zix790prors` as the build host
- **SteamOS role** for easy Steam Deck UI configuration
- **Compatibility shim** for using Jovian on NixOS 25.05 stable
## Architecture
### Remote Building
The setup uses distributed builds to avoid slow compilation on the Steam Deck:
- **Build Host**: `zix790prors` (powerful desktop)
- Runs as a dedicated `nix-builder` user (not root)
- Accepts SSH connections from client machines
- Performs all heavy compilation work
- **Build Clients**: `nix-book` and `nix-deck`
- Automatically offload builds to `zix790prors`
- Fall back to local building if remote builder is unavailable
- Steam Deck heavily prefers remote (speedFactor=4)
### Jovian-NixOS Integration
- **Jovian module**: Provides Steam Deck hardware support, drivers, and Steam UI
- **Compatibility layer**: `roles/jovian-compat.nix` provides `services.logind.settings` for NixOS 25.05
- **IMPORTANT**: Remove this when upgrading to NixOS 25.11+
- An assertion will fail the build if used on 25.11+
- **SteamOS role**: `roles.desktop.steamos` abstracts Jovian configuration
```nix
roles.desktop.steamos = {
enable = true;
autoStart = false; # Set to true to boot directly to Steam UI
desktopSession = "plasmawayland";
};
```
## Initial Installation
### Prerequisites
1. Steam Deck in recovery mode or booted to a live Linux environment
2. SSH access enabled on the Steam Deck
3. SSH key set up for passwordless authentication
### Option 1: Using nixos-anywhere (Initial Install Only)
```bash
# From your main machine
nix run github:nix-community/nixos-anywhere -- \
--flake .#nix-deck \
root@<steam-deck-ip>
```
**Note**: This is only for the initial install. For updates, see below.
### Option 2: Manual Installation
1. Boot Steam Deck from NixOS installer USB
2. Partition and format the disk
3. Mount filesystems
4. Clone this repository
5. Generate hardware config:
```bash
nixos-generate-config --show-hardware-config > /tmp/hw.nix
```
6. Copy the hardware config content to `machines/nix-deck/hardware-configuration.nix`
7. Keep the `jovian.devices.steamdeck` settings in the file
8. Install:
```bash
nixos-install --flake .#nix-deck
```
## Updates and Rebuilds
### Method 1: Remote Build and Deploy (Recommended)
Build on your main machine, deploy to Steam Deck:
```bash
# From nix-book or zix790prors
nixos-rebuild switch \
--flake .#nix-deck \
--target-host root@nix-deck \
--build-host localhost
```
### Method 2: On-Device Rebuild (Uses Remote Builder)
The Steam Deck is configured to automatically use `zix790prors` as a remote builder:
```bash
# SSH into the Steam Deck
ssh root@nix-deck
# This will automatically build on zix790prors
nixos-rebuild switch --flake /path/to/nixos-configs#nix-deck
```
The build will automatically happen on `zix790prors` and be deployed locally.
## Remote Builder Setup
### On the Build Host (zix790prors)
The configuration creates a `nix-builder` user that client machines connect to:
```nix
roles.remote-build.enableBuilder = true;
```
### On Client Machines (nix-book, nix-deck)
Configure the remote builder:
```nix
roles.remote-build.builders = [{
hostName = "zix790prors";
maxJobs = 16;
speedFactor = 4; # Higher = prefer remote more
}];
```
### SSH Key Setup
1. Generate SSH key on the builder host for the `nix-builder` user:
```bash
sudo -u nix-builder ssh-keygen -t ed25519 -f /var/lib/nix-builder/.ssh/id_ed25519
```
2. Copy the public key to client machines:
```bash
# Add to /var/lib/nix-builder/.ssh/authorized_keys on zix790prors
```
3. On client machines, ensure you can connect:
```bash
ssh nix-builder@zix790prors
```
## Configuration Files
### Key Files Created/Modified
- `flake.nix` - Added Jovian input and nix-deck configuration
- `roles/jovian-compat.nix` - Compatibility shim (remove in 25.11+)
- `roles/desktop/steamos.nix` - SteamOS/Jovian role abstraction
- `roles/remote-build/default.nix` - Remote builder role
- `machines/nix-deck/configuration.nix` - Steam Deck system config
- `machines/nix-deck/hardware-configuration.nix` - Hardware config (placeholder)
### Example Configuration
```nix
# machines/nix-deck/configuration.nix
{
roles = {
desktop = {
enable = true;
wayland = true;
gaming.enable = true;
kde = true;
sddm = true;
steamos = {
enable = true;
autoStart = false; # or true to boot to Steam UI
desktopSession = "plasmawayland";
};
};
remote-build.builders = [{
hostName = "zix790prors";
maxJobs = 16;
speedFactor = 4;
}];
};
}
```
## Jovian Features
### Enabled by Default
- Steam Deck hardware support (`jovian.devices.steamdeck.enable`)
- Steam UI (`jovian.steam.enable`)
- Decky Loader plugin system (`jovian.decky-loader.enable`)
### Optional Features
Set in the hardware-configuration.nix:
```nix
jovian.devices.steamdeck = {
enable = true;
autoUpdate = false; # Auto-update BIOS/controller firmware
};
```
### Manual Firmware Updates
```bash
# BIOS update
sudo jupiter-biosupdate
# Controller update
sudo jupiter-controller-update
# Docking station (connect via USB-C first)
jupiter-dock-updater
```
## Troubleshooting
### Remote Builds Not Working
1. Check SSH connectivity:
```bash
ssh nix-builder@zix790prors
```
2. Verify builder is trusted:
```bash
# On zix790prors
nix show-config | grep trusted-users
```
3. Check build logs:
```bash
journalctl -u nix-daemon -f
```
### Jovian Not Working
1. Ensure you're on NixOS 25.05 or the compatibility layer is removed for 25.11+
2. Check Jovian is imported in flake.nix
3. Verify hardware config has `jovian.devices.steamdeck.enable = true`
### Compatibility Layer Issues
If you see an error about `jovian-compat.nix` being incompatible:
1. You're running NixOS 25.11 or later
2. Remove `./roles/jovian-compat.nix` from `flake.nix`
3. Jovian should work natively on 25.11+
## Future Upgrades
### Upgrading to NixOS 25.11
1. Update `nixpkgs` input in flake.nix to 25.11
2. Remove `./roles/jovian-compat.nix` from flake.nix imports
3. The assertion in jovian-compat.nix will prevent accidental use
4. Test the build
5. Deploy
### Switching to Unstable
If you need Jovian to follow unstable nixpkgs:
1. Edit `flake.nix`:
```nix
jovian = {
url = "github:Jovian-Experiments/Jovian-NixOS";
inputs.nixpkgs.follows = "nixpkgs-unstable";
};
```
2. This only affects Jovian packages, not your base system
## Additional Resources
- [Jovian-NixOS Documentation](https://jovian-experiments.github.io/Jovian-NixOS/)
- [Jovian Steam Deck Guide](https://jovian-experiments.github.io/Jovian-NixOS/devices/valve-steam-deck/)
- [NixOS Remote Builds](https://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html)

View File

@@ -133,7 +133,7 @@
home-manager.users.johno = { home-manager.users.johno = {
imports = [ ./home/home-laptop-compact.nix ]; imports = [ ./home/home-laptop-compact.nix ];
# Machine-specific overrides # Machine-specific overrides
home.i3_sway.extraSwayConfig = { home.roles.i3_sway.extraSwayConfig = {
output.eDP-1.scale = "1.75"; output.eDP-1.scale = "1.75";
}; };
}; };

View File

@@ -1,9 +1,30 @@
{ config, lib, pkgs, globalInputs, system, ... }: { config, lib, pkgs, globalInputs, system, ... }:
let
leader = "cmd"; # Change this to experiment with different leader keys (e.g., "cmd", "ctrl")
in
{ {
# Claude Code Package Override for Corporate Work Environment
#
# This overlay overrides the default claude-code package specifically for work environments
# where corporate network restrictions may prevent access to npm registry distributions.
#
# Context:
# - The default claude-code package (used in home environments) fetches from npm registry
# - Corporate firewalls and security policies often block npm registry access
# - Our custom claude-code package uses Google Cloud Storage distribution as a workaround
# - This maintains the same package name across environments while adapting to network constraints
#
# Environment-specific behavior:
# - Home environments: Use standard npm-distributed claude-code package
# - Work environments: Use custom binary-distributed claude-code package from GCS
#
# This approach ensures consistent tooling availability regardless of network environment
# while respecting corporate security policies.
nixpkgs.overlays = [
(final: prev: {
unstable = prev.unstable // {
claude-code = prev.custom.claude-code;
};
})
];
# Home Manager configuration for Darwin work laptop # Home Manager configuration for Darwin work laptop
# Corporate-friendly setup with essential development tools # Corporate-friendly setup with essential development tools
@@ -13,39 +34,11 @@ in
# System packages # System packages
home.packages = with pkgs; [ home.packages = with pkgs; [
autoraise google-cloud-sdk
]; ];
# Note: ghostty installed via Homebrew (managed outside of nix) # Note: ghostty installed via Homebrew (managed outside of nix)
# Auto-start autoraise on login
launchd.agents.autoraise = {
enable = true;
config = {
ProgramArguments = [
"${pkgs.autoraise}/bin/AutoRaise"
"-pollMillis" "50"
"-delay" "2"
"-focusDelay" "2"
];
RunAtLoad = true;
KeepAlive = true;
};
};
# Auto-start aerospace on login
# NOTE: In 25.11+, this can be simplified to `programs.aerospace.launchd.enable = true`
launchd.agents.aerospace = {
enable = true;
config = {
Program = "${pkgs.aerospace}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace";
RunAtLoad = true;
KeepAlive = true;
StandardOutPath = "/tmp/aerospace.log";
StandardErrorPath = "/tmp/aerospace.err.log";
};
};
# Override Darwin-incompatible settings from base role # Override Darwin-incompatible settings from base role
programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac; programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac;
@@ -127,107 +120,25 @@ in
home.shell.enableShellIntegration = true; home.shell.enableShellIntegration = true;
# TODO: Move this to its own role and/or module
programs.aerospace = {
enable = true;
userSettings.mode.main.binding = {
"${leader}-slash" = "layout tiles horizontal vertical";
"${leader}-comma" = "layout accordion horizontal vertical";
"${leader}-shift-q" = "close";
"${leader}-shift-f" = "fullscreen";
"${leader}-h" = "focus left";
"${leader}-j" = "focus down";
"${leader}-k" = "focus up";
"${leader}-l" = "focus right";
"${leader}-shift-h" = "move left";
"${leader}-shift-j" = "move down";
"${leader}-shift-k" = "move up";
"${leader}-shift-l" = "move right";
"${leader}-minus" = "resize smart -50";
"${leader}-equal" = "resize smart +50";
"${leader}-1" = "workspace 1";
"${leader}-2" = "workspace 2";
"${leader}-3" = "workspace 3";
"${leader}-4" = "workspace 4";
"${leader}-5" = "workspace 5";
"${leader}-6" = "workspace 6";
"${leader}-7" = "workspace 7";
"${leader}-8" = "workspace 8";
"${leader}-9" = "workspace 9";
"${leader}-0" = "workspace 10";
"${leader}-shift-1" = "move-node-to-workspace 1";
"${leader}-shift-2" = "move-node-to-workspace 2";
"${leader}-shift-3" = "move-node-to-workspace 3";
"${leader}-shift-4" = "move-node-to-workspace 4";
"${leader}-shift-5" = "move-node-to-workspace 5";
"${leader}-shift-6" = "move-node-to-workspace 6";
"${leader}-shift-7" = "move-node-to-workspace 7";
"${leader}-shift-8" = "move-node-to-workspace 8";
"${leader}-shift-9" = "move-node-to-workspace 9";
"${leader}-shift-0" = "move-node-to-workspace 10";
"${leader}-tab" = "workspace-back-and-forth";
"${leader}-shift-tab" = "move-workspace-to-monitor --wrap-around next";
"${leader}-enter" = ''
exec-and-forget osascript <<'APPLESCRIPT'
tell application "Ghostty"
activate
tell application "System Events"
keystroke "n" using {command down}
end tell
end tell
APPLESCRIPT
'';
"${leader}-shift-enter" = ''
exec-and-forget osascript <<'APPLESCRIPT'
tell application "Google Chrome"
set newWindow to make new window
activate
tell newWindow to set index to 1
end tell
APPLESCRIPT
'';
"${leader}-shift-e" = "exec-and-forget zsh --login -c \"emacsclient -c -n\"";
# Service mode: Deliberate aerospace window management
"${leader}-i" = "mode service";
# Passthrough mode: Temporarily disable aerospace to use macOS shortcuts
# Press Cmd-P, then use any macOS shortcut (like Cmd-K in Slack), then press Cmd-P again to exit
"${leader}-p" = "mode passthrough";
};
# Service mode: For deliberate aerospace window management operations
userSettings.mode.service.binding = {
esc = ["reload-config" "mode main"];
r = ["flatten-workspace-tree" "mode main"]; # reset layout
f = ["layout floating tiling" "mode main"]; # Toggle between floating and tiling layout
backspace = ["close-all-windows-but-current" "mode main"];
"${leader}-shift-h" = ["join-with left" "mode main"];
"${leader}-shift-j" = ["join-with down" "mode main"];
"${leader}-shift-k" = ["join-with up" "mode main"];
"${leader}-shift-l" = ["join-with right" "mode main"];
};
# Passthrough mode: All shortcuts pass through to macOS
# This mode has minimal bindings - just ways to exit back to main mode
userSettings.mode.passthrough.binding = {
esc = "mode main";
"${leader}-p" = "mode main"; # Toggle back with same key (Cmd-P)
};
};
home.roles = { home.roles = {
base.enable = true; base.enable = true;
development = {
enable = true;
allowArbitraryClaudeCodeModelSelection = true;
};
tmux.enable = true;
emacs.enable = true;
aerospace = {
enable = true;
leader = "cmd";
# Optional: Add per-machine userSettings overrides
# userSettings = {
# mode.main.binding."${leader}-custom" = "custom-command";
# };
};
}; };
imports = [ imports = [
./roles ./roles
./modules/emacs
./modules/kubectl
./modules/tmux
]; ];
} }

View File

@@ -16,6 +16,11 @@
communication.enable = true; communication.enable = true;
sync.enable = true; sync.enable = true;
kdeconnect.enable = true; kdeconnect.enable = true;
kubectl.enable = true;
tmux.enable = true;
plasma-manager.enable = true;
emacs.enable = true;
i3_sway.enable = true;
}; };
targets.genericLinux.enable = true; targets.genericLinux.enable = true;
@@ -24,10 +29,5 @@
imports = [ imports = [
./roles ./roles
./modules/emacs
./modules/i3+sway
./modules/kubectl
./modules/plasma-manager
./modules/tmux
]; ];
} }

View File

@@ -17,7 +17,19 @@
kdeconnect.enable = true; kdeconnect.enable = true;
media.enable = true; media.enable = true;
sync.enable = true; sync.enable = true;
# office.enable = false; # Excluded for storage constraints kubectl.enable = true;
tmux.enable = true;
plasma-manager.enable = true;
emacs.enable = true;
i3_sway.enable = true;
# Launcher wrappers for excluded/optional packages
launchers = {
enable = true;
packages = [
"libreoffice"
];
};
}; };
targets.genericLinux.enable = true; targets.genericLinux.enable = true;
@@ -26,11 +38,5 @@
imports = [ imports = [
./roles ./roles
./modules/emacs
./modules/i3+sway
./modules/kubectl
./modules/plasma-manager
./modules/tmux
]; ];
} }

View File

@@ -12,8 +12,12 @@
home.roles = { home.roles = {
base.enable = true; base.enable = true;
desktop.enable = true; desktop.enable = true;
tmux.enable = true;
plasma-manager.enable = true;
emacs.enable = true;
i3_sway.enable = true;
# development.enable = false; # Not needed for live USB # development.enable = false; # Not needed for live USB
# communication.enable = false; # Not needed for live USB # communication.enable = false; # Not needed for live USB
# office.enable = false; # Not needed for live USB # office.enable = false; # Not needed for live USB
# media.enable = false; # Not needed for live USB # media.enable = false; # Not needed for live USB
# sync.enable = false; # No persistent sync on live USB # sync.enable = false; # No persistent sync on live USB
@@ -26,11 +30,6 @@
imports = [ imports = [
./roles ./roles
./modules/emacs
./modules/i3+sway
./modules/kubectl
./modules/plasma-manager
./modules/tmux
]; ];
# Live USB specific overrides can go here if needed # Live USB specific overrides can go here if needed

View File

@@ -16,6 +16,10 @@
communication.enable = true; communication.enable = true;
kdeconnect.enable = true; kdeconnect.enable = true;
development.enable = true; development.enable = true;
tmux.enable = true;
plasma-manager.enable = true;
emacs.enable = true;
i3_sway.enable = true;
# office.enable = false; # Not needed for media center # office.enable = false; # Not needed for media center
# sync.enable = false; # Shared machine, no personal file sync # sync.enable = false; # Shared machine, no personal file sync
}; };
@@ -26,11 +30,6 @@
imports = [ imports = [
./roles ./roles
./modules/emacs
./modules/i3+sway
./modules/kubectl
./modules/plasma-manager
./modules/tmux
]; ];
# Media center specific overrides can go here if needed # Media center specific overrides can go here if needed

View File

@@ -1,178 +0,0 @@
{ config, lib, pkgs, ... }:
# The current KDE config can be output with the command:
# nix run github:nix-community/plasma-manager
#
# Plasma-manager options documentation
# https://nix-community.github.io/plasma-manager/options.xhtml
#
# TODO: (ambitious) Add Kmail support to plasma-manager
{
programs.plasma = {
enable = true;
overrideConfig = true;
hotkeys.commands."launch-ghostty" = {
name = "Launch Ghostty";
key = "Meta+Return";
command = "ghostty";
};
shortcuts = {
kmix = {
"decrease_microphone_volume" = "Microphone Volume Down";
"decrease_volume" = "Volume Down";
"decrease_volume_small" = "Shift+Volume Down";
"increase_microphone_volume" = "Microphone Volume Up";
"increase_volume" = "Volume Up";
"increase_volume_small" = "Shift+Volume Up";
"mic_mute" = ["Microphone Mute" "Meta+Volume Mute,Microphone Mute" "Meta+Volume Mute,Mute Microphone"];
"mute" = "Volume Mute";
};
mediacontrol = {
"mediavolumedown" = "none,,Media volume down";
"mediavolumeup" = "none,,Media volume up";
"nextmedia" = "Media Next";
"pausemedia" = "Media Pause";
"playmedia" = "none,,Play media playback";
"playpausemedia" = "Media Play";
"previousmedia" = "Media Previous";
"stopmedia" = "Media Stop";
};
ksmserver = {
"Lock Session" = ["Meta+Ctrl+Q" "Screensaver" "Screensaver,Lock Session"];
};
kwin = {
"Window Close" = "Meta+Shift+Q";
"Kill Window" = "Meta+Ctrl+Esc";
"Window Operations Menu" = "Alt+F3";
"Window Resize" = "Meta+R,,Resize Window";
"Overview" = "Meta+Ctrl+W";
"Grid View" = "Meta+G";
"Edit Tiles" = "Meta+T";
"Activate Window Demanding Attention" = "Meta+Ctrl+A";
"Show Desktop" = "Meta+Ctrl+D";
"Walk Through Windows" = "Alt+Tab";
"Walk Through Windows (Reverse)" = "Alt+Shift+Tab";
"Walk Through Windows of Current Application" = "Alt+`";
"Walk Through Windows of Current Application (Reverse)" = "Alt+~";
"Window Quick Tile Bottom" = "Meta+Down";
"Window Quick Tile Left" = "Meta+Left";
"Window Quick Tile Right" = "Meta+Right";
"Window Quick Tile Top" = "Meta+Up";
"Switch to Desktop 1" = "Meta+1";
"Switch to Desktop 2" = "Meta+2";
"Switch to Desktop 3" = "Meta+3";
"Switch to Desktop 4" = "Meta+4";
"Switch to Desktop 5" = "Meta+5";
"Switch to Desktop 6" = "Meta+6";
"Switch to Desktop 7" = "Meta+7";
"Switch to Desktop 8" = "Meta+8";
"Switch to Desktop 9" = "Meta+9";
"Switch to Desktop 10" = "Meta+0";
"Window to Desktop 1" = "Meta+!"; # Meta+Shift+1
"Window to Desktop 2" = "Meta+@"; # Meta+Shift+2
"Window to Desktop 3" = "Meta+#"; # Meta+Shift+3
"Window to Desktop 4" = "Meta+$"; # Meta+Shift+4
"Window to Desktop 5" = "Meta+%"; # Meta+Shift+5
"Window to Desktop 6" = "Meta+^"; # Meta+Shift+6
"Window to Desktop 7" = "Meta+&"; # Meta+Shift+7
"Window to Desktop 8" = "Meta+*"; # Meta+Shift+8
"Window to Desktop 9" = "Meta+("; # Meta+Shift+9
"Window to Desktop 10" = "Meta+)"; # Meta+Shift+0
"view_actual_size" = "Meta+Ctrl+=";
"view_zoom_in" = ["Meta++" "Meta+=,Meta++" "Meta+=,Zoom In"];
"view_zoom_out" = "Meta+-";
};
"org_kde_powerdevil"."Decrease Keyboard Brightness" = "Keyboard Brightness Down";
"org_kde_powerdevil"."Decrease Screen Brightness" = "Monitor Brightness Down";
"org_kde_powerdevil"."Decrease Screen Brightness Small" = "Shift+Monitor Brightness Down";
"org_kde_powerdevil"."Hibernate" = "Hibernate";
"org_kde_powerdevil"."Increase Keyboard Brightness" = "Keyboard Brightness Up";
"org_kde_powerdevil"."Increase Screen Brightness" = "Monitor Brightness Up";
"org_kde_powerdevil"."Increase Screen Brightness Small" = "Shift+Monitor Brightness Up";
"org_kde_powerdevil"."PowerDown" = "Power Down";
"org_kde_powerdevil"."PowerOff" = "Power Off";
"org_kde_powerdevil"."Sleep" = "Sleep";
"org_kde_powerdevil"."Toggle Keyboard Backlight" = "Keyboard Light On/Off";
"org_kde_powerdevil"."Turn Off Screen" = [ ];
"org_kde_powerdevil"."powerProfile" = ["Battery" "Meta+B,Battery" "Meta+B,Switch Power Profile"];
plasmashell = {
"activate application launcher" = ["Meta" "Alt+F1,Meta" "Alt+F1,Activate Application Launcher"];
"activate task manager entry 1" = "none,,";
"activate task manager entry 2" = "none,,";
"activate task manager entry 3" = "none,,";
"activate task manager entry 4" = "none,,";
"activate task manager entry 5" = "none,,";
"activate task manager entry 6" = "none,,";
"activate task manager entry 7" = "none,,";
"activate task manager entry 8" = "none,,";
"activate task manager entry 9" = "none,,";
"activate task manager entry 10" = "none,,";
"show activity switcher" = "none,,";
};
};
configFile = {
kwinrc.Desktops.Number = {
value = 10;
immutable = true;
};
# Enable KWin tiling features
kwinrc.Tiling = {
# Enable tiling functionality
"padding" = 4;
};
# Enable krohnkite plugin automatically
kwinrc.Plugins = {
krohnkiteEnabled = true;
};
kwinrc.Effect-overview = {
# Configure overview effect for better tiling workflow
BorderActivate = 9; # Top-left corner activation
};
kcminputrc.Libinput = {
AccelerationProfile = "adaptive";
PointerAcceleration = 0.5;
};
kcminputrc.Mouse = {
X11LibInputXAccelProfileFlat = false;
XLbInptAccelProfileFlat = false;
};
kdeglobals.KDE.LookAndFeelPackage = "org.kde.breezedark.desktop";
# Focus follows mouse configuration
kwinrc.Windows = {
FocusPolicy = "FocusFollowsMouse";
AutoRaise = true; # Set to true if you want windows to auto-raise on focus
AutoRaiseInterval = 750; # Delay in ms before auto-raise (if enabled)
DelayFocusInterval = 0; # Delay in ms before focus follows mouse
};
# Desktop wallpaper configuration
plasma-localerc.Formats.LANG = "en_US.UTF-8";
# Set wallpaper for all desktops
plasmarc.Wallpapers.usersWallpapers = "${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg}";
};
};
}

View File

@@ -1,52 +0,0 @@
{ config, lib, pkgs, ... }:
let
tokyo-night = pkgs.tmuxPlugins.mkTmuxPlugin {
pluginName = "tokyo-night";
rtpFilePath = "tokyo-night.tmux";
version = "1.6.1";
src = pkgs.fetchFromGitHub {
owner = "janoamaral";
repo = "tokyo-night-tmux";
rev = "d610ced20d5f602a7995854931440e4a1e0ab780";
sha256 = "sha256-17vEgkL7C51p/l5gpT9dkOy0bY9n8l0/LV51mR1k+V8=";
};
};
in
{
programs.tmux.enable = true;
programs.tmux.terminal = "tmux-direct";
programs.tmux.keyMode = "vi";
programs.tmux.escapeTime = 0;
programs.tmux.mouse = true;
programs.tmux.newSession = true;
programs.tmux.historyLimit = 50000;
programs.tmux.clock24 = true;
programs.tmux.baseIndex = 1;
programs.tmux.prefix = "M-\\\\";
programs.tmux.plugins = with pkgs; [
tmuxPlugins.cpu
tmuxPlugins.battery
tmuxPlugins.better-mouse-mode
tmuxPlugins.net-speed
tmuxPlugins.online-status
tmuxPlugins.pain-control
tmuxPlugins.tilish
tmuxPlugins.yank
{
plugin = tmuxPlugins.resurrect;
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
}
{
plugin = tmuxPlugins.continuum;
extraConfig = ''
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15' # minutes
'';
}
tokyo-night
];
}

View File

@@ -0,0 +1,200 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.home.roles.aerospace;
in
{
options.home.roles.aerospace = {
enable = mkEnableOption "AeroSpace tiling window manager for macOS";
leader = mkOption {
type = types.str;
default = "cmd";
description = "Leader key for aerospace shortcuts (e.g., 'cmd', 'ctrl', 'alt')";
example = "ctrl";
};
launchd.enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable launchd agent for auto-starting aerospace";
};
userSettings = mkOption {
type = types.attrs;
default = {};
description = ''
Additional aerospace configuration settings to merge with defaults.
Use this to override or extend the default configuration on a per-machine basis.
'';
example = literalExpression ''
{
mode.main.binding."''${leader}-custom" = "custom-command";
}
'';
};
autoraise = {
enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable autoraise (auto-focus window on hover)";
};
pollMillis = mkOption {
type = types.int;
default = 50;
description = "Polling interval in milliseconds";
};
delay = mkOption {
type = types.int;
default = 2;
description = "Delay before raising window";
};
focusDelay = mkOption {
type = types.int;
default = 2;
description = "Delay before focusing window";
};
};
};
config = mkIf cfg.enable {
# Only apply on Darwin systems
assertions = [
{
assertion = pkgs.stdenv.isDarwin;
message = "Aerospace role is only supported on macOS (Darwin) systems";
}
];
# Install aerospace package and autoraise if enabled
home.packages = [ pkgs.aerospace ]
++ optionals cfg.autoraise.enable [ pkgs.autoraise ];
# Configure aerospace with user settings
programs.aerospace.userSettings = mkMerge [
# Default configuration with leader key substitution
{
mode.main.binding = {
"${cfg.leader}-slash" = "layout tiles horizontal vertical";
"${cfg.leader}-comma" = "layout accordion horizontal vertical";
"${cfg.leader}-shift-q" = "close";
"${cfg.leader}-shift-f" = "fullscreen";
"${cfg.leader}-h" = "focus left";
"${cfg.leader}-j" = "focus down";
"${cfg.leader}-k" = "focus up";
"${cfg.leader}-l" = "focus right";
"${cfg.leader}-shift-h" = "move left";
"${cfg.leader}-shift-j" = "move down";
"${cfg.leader}-shift-k" = "move up";
"${cfg.leader}-shift-l" = "move right";
"${cfg.leader}-minus" = "resize smart -50";
"${cfg.leader}-equal" = "resize smart +50";
"${cfg.leader}-1" = "workspace 1";
"${cfg.leader}-2" = "workspace 2";
"${cfg.leader}-3" = "workspace 3";
"${cfg.leader}-4" = "workspace 4";
"${cfg.leader}-5" = "workspace 5";
"${cfg.leader}-6" = "workspace 6";
"${cfg.leader}-7" = "workspace 7";
"${cfg.leader}-8" = "workspace 8";
"${cfg.leader}-9" = "workspace 9";
"${cfg.leader}-0" = "workspace 10";
"${cfg.leader}-shift-1" = "move-node-to-workspace 1";
"${cfg.leader}-shift-2" = "move-node-to-workspace 2";
"${cfg.leader}-shift-3" = "move-node-to-workspace 3";
"${cfg.leader}-shift-4" = "move-node-to-workspace 4";
"${cfg.leader}-shift-5" = "move-node-to-workspace 5";
"${cfg.leader}-shift-6" = "move-node-to-workspace 6";
"${cfg.leader}-shift-7" = "move-node-to-workspace 7";
"${cfg.leader}-shift-8" = "move-node-to-workspace 8";
"${cfg.leader}-shift-9" = "move-node-to-workspace 9";
"${cfg.leader}-shift-0" = "move-node-to-workspace 10";
"${cfg.leader}-tab" = "workspace-back-and-forth";
"${cfg.leader}-shift-tab" = "move-workspace-to-monitor --wrap-around next";
"${cfg.leader}-enter" = ''
exec-and-forget osascript <<'APPLESCRIPT'
tell application "Ghostty"
activate
tell application "System Events"
keystroke "n" using {command down}
end tell
end tell
APPLESCRIPT
'';
"${cfg.leader}-shift-enter" = ''
exec-and-forget osascript <<'APPLESCRIPT'
tell application "Google Chrome"
set newWindow to make new window
activate
tell newWindow to set index to 1
end tell
APPLESCRIPT
'';
"${cfg.leader}-shift-e" = "exec-and-forget zsh --login -c \"emacsclient -c -n\"";
# Service mode: Deliberate aerospace window management
"${cfg.leader}-i" = "mode service";
# Passthrough mode: Temporarily disable aerospace to use macOS shortcuts
"${cfg.leader}-p" = "mode passthrough";
};
# Service mode: For deliberate aerospace window management operations
mode.service.binding = {
esc = ["reload-config" "mode main"];
r = ["flatten-workspace-tree" "mode main"]; # reset layout
f = ["layout floating tiling" "mode main"]; # Toggle between floating and tiling layout
backspace = ["close-all-windows-but-current" "mode main"];
"${cfg.leader}-shift-h" = ["join-with left" "mode main"];
"${cfg.leader}-shift-j" = ["join-with down" "mode main"];
"${cfg.leader}-shift-k" = ["join-with up" "mode main"];
"${cfg.leader}-shift-l" = ["join-with right" "mode main"];
};
# Passthrough mode: All shortcuts pass through to macOS
mode.passthrough.binding = {
esc = "mode main";
"${cfg.leader}-p" = "mode main";
};
}
cfg.userSettings
];
# Launchd agent for auto-starting aerospace
launchd.agents.aerospace = mkIf cfg.launchd.enable {
enable = true;
config = {
Program = "${pkgs.aerospace}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace";
RunAtLoad = true;
KeepAlive = true;
StandardOutPath = "/tmp/aerospace.log";
StandardErrorPath = "/tmp/aerospace.err.log";
};
};
# Launchd agent for autoraise
launchd.agents.autoraise = mkIf cfg.autoraise.enable {
enable = true;
config = {
ProgramArguments = [
"${pkgs.autoraise}/bin/AutoRaise"
"-pollMillis" (toString cfg.autoraise.pollMillis)
"-delay" (toString cfg.autoraise.delay)
"-focusDelay" (toString cfg.autoraise.focusDelay)
];
RunAtLoad = true;
KeepAlive = true;
};
};
};
}

View File

@@ -6,8 +6,15 @@
./development ./development
./gaming ./gaming
./kdeconnect ./kdeconnect
./kubectl
./launchers
./media ./media
./office ./office
./sync ./sync
./tmux
./plasma-manager
./emacs
./aerospace
./i3+sway
]; ];
} }

View File

@@ -4,22 +4,90 @@ with lib;
let let
cfg = config.home.roles.development; cfg = config.home.roles.development;
# Fetch the claude-plugins repository
# Update the rev to get newer versions of the commands
claudePluginsRepo = builtins.fetchGit {
url = "https://github.com/jeffh/claude-plugins.git";
# To update: change this to the latest commit hash
# You can find the latest commit at: https://github.com/jeffh/claude-plugins/commits/main
rev = "5e3e4d937162185b6d78c62022cbfd1c8ad42c4c";
ref = "main";
};
in in
{ {
options.home.roles.development = { options.home.roles.development = {
enable = mkEnableOption "Enable development tools and utilities"; enable = mkEnableOption "Enable development tools and utilities";
allowArbitraryClaudeCodeModelSelection = mkOption {
type = types.bool;
default = false;
description = ''
Whether to preserve model specifications in Claude Code humanlayer commands and agents.
When false (default), the model: line is stripped from frontmatter, allowing Claude Code
to use its default model selection.
When true, the model: specifications from the source files are preserved, allowing
commands to specify opus/sonnet/haiku explicitly.
'';
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
home.packages = [ home.packages = [
pkgs.unstable.claude-code pkgs.unstable.claude-code
pkgs.codex pkgs.unstable.claude-code-router
pkgs.unstable.codex
# Custom packages # Custom packages
pkgs.custom.tea-rbw pkgs.custom.tea-rbw
]; ];
programs.kubectl-secure.enable = true; # Install Claude Code humanlayer command and agent plugins
home.activation.claudeCodeCommands = lib.hm.dag.entryAfter ["writeBoundary"] ''
# Clean up old plugin-installed commands and agents to avoid duplicates
rm -f ~/.claude/commands/humanlayer:* 2>/dev/null || true
rm -f ~/.claude/agents/humanlayer:* 2>/dev/null || true
# Create directories if they don't exist
mkdir -p ~/.claude/commands
mkdir -p ~/.claude/agents
# Copy all humanlayer command files and remove model specifications
for file in ${claudePluginsRepo}/humanlayer/commands/*.md; do
if [ -f "$file" ]; then
filename=$(basename "$file" .md)
dest="$HOME/.claude/commands/humanlayer:''${filename}.md"
# Copy file and conditionally remove the "model:" line from frontmatter
${if cfg.allowArbitraryClaudeCodeModelSelection
then "cp \"$file\" \"$dest\""
else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\""
}
fi
done
# Copy all humanlayer agent files and remove model specifications
for file in ${claudePluginsRepo}/humanlayer/agents/*.md; do
if [ -f "$file" ]; then
filename=$(basename "$file" .md)
dest="$HOME/.claude/agents/humanlayer:''${filename}.md"
# Copy file and conditionally remove the "model:" line from frontmatter
${if cfg.allowArbitraryClaudeCodeModelSelection
then "cp \"$file\" \"$dest\""
else "${pkgs.gnused}/bin/sed '/^model:/d' \"$file\" > \"$dest\""
}
fi
done
$DRY_RUN_CMD echo "Claude Code humanlayer commands and agents installed successfully${
if cfg.allowArbitraryClaudeCodeModelSelection
then " (model specifications preserved)"
else " (model selection removed)"
}"
'';
# Note: modules must be imported at top-level home config # Note: modules must be imported at top-level home config
}; };

View File

@@ -3,6 +3,8 @@
with lib; with lib;
let let
cfg = config.home.roles.emacs;
doomEmacs = pkgs.fetchFromGitHub { doomEmacs = pkgs.fetchFromGitHub {
owner = "doomemacs"; owner = "doomemacs";
repo = "doomemacs"; repo = "doomemacs";
@@ -17,20 +19,23 @@ let
]; ];
# Default emacs configuration with vterm support # Default emacs configuration with vterm support
defaultEmacsPackage = defaultEmacsPackage =
if pkgs.stdenv.isDarwin if pkgs.stdenv.isDarwin
then pkgs.emacs-macport.pkgs.withPackages emacsPackages then pkgs.emacs-macport.pkgs.withPackages emacsPackages
else pkgs.emacs.pkgs.withPackages emacsPackages; else pkgs.emacs.pkgs.withPackages emacsPackages;
in in
{ {
config = { options.home.roles.emacs = {
enable = mkEnableOption "Doom Emacs with vterm and tree-sitter support";
};
config = mkIf cfg.enable {
home.packages = [ home.packages = [
pkgs.emacs-all-the-icons-fonts pkgs.emacs-all-the-icons-fonts
pkgs.fira-code pkgs.fira-code
pkgs.fontconfig pkgs.fontconfig
pkgs.graphviz pkgs.graphviz
pkgs.isort pkgs.isort
#pkgs.libvterm # native vterm library
pkgs.nerd-fonts.fira-code pkgs.nerd-fonts.fira-code
pkgs.nerd-fonts.droid-sans-mono pkgs.nerd-fonts.droid-sans-mono
pkgs.nil # nix lsp language server pkgs.nil # nix lsp language server
@@ -66,7 +71,7 @@ in
home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] '' home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
# Always remove and recreate the symlink to ensure it points to the source directory # Always remove and recreate the symlink to ensure it points to the source directory
rm -rf "${config.xdg.configHome}/doom" rm -rf "${config.xdg.configHome}/doom"
ln -sf "${config.home.homeDirectory}/nixos-configs/home/modules/emacs/doom" "${config.xdg.configHome}/doom" ln -sf "${config.home.homeDirectory}/nixos-configs/home/roles/emacs/doom" "${config.xdg.configHome}/doom"
''; '';
}; };
} }

View File

@@ -3,7 +3,7 @@
with lib; with lib;
let let
cfg = config.home.i3_sway; cfg = config.home.roles.i3_sway;
shared_config = recursiveUpdate rec { shared_config = recursiveUpdate rec {
modifier = "Mod4"; modifier = "Mod4";
@@ -14,6 +14,9 @@ let
"${shared_config.modifier}+Return" = "exec ${terminal}"; "${shared_config.modifier}+Return" = "exec ${terminal}";
"${shared_config.modifier}+Shift+q" = "kill"; "${shared_config.modifier}+Shift+q" = "kill";
"${shared_config.modifier}+a" = "focus parent";
"${shared_config.modifier}+Shift+a" = "focus child";
"${shared_config.modifier}+h" = "focus left"; "${shared_config.modifier}+h" = "focus left";
"${shared_config.modifier}+j" = "focus down"; "${shared_config.modifier}+j" = "focus down";
"${shared_config.modifier}+k" = "focus up"; "${shared_config.modifier}+k" = "focus up";
@@ -45,8 +48,6 @@ let
"${shared_config.modifier}+Shift+space" = "floating toggle"; "${shared_config.modifier}+Shift+space" = "floating toggle";
"${shared_config.modifier}+space" = "focus mode_toggle"; "${shared_config.modifier}+space" = "focus mode_toggle";
"${shared_config.modifier}+a" = "focus parent";
"${shared_config.modifier}+Shift+minus" = "move scratchpad"; "${shared_config.modifier}+Shift+minus" = "move scratchpad";
"${shared_config.modifier}+minus" = "scratchpad show"; "${shared_config.modifier}+minus" = "scratchpad show";
@@ -92,19 +93,29 @@ let
}; };
} cfg.extraSharedConfig; } cfg.extraSharedConfig;
in { in {
options.home.i3_sway = { options.home.roles.i3_sway = {
enable = mkEnableOption "i3 and Sway tiling window managers with waybar and rofi";
extraSharedConfig = mkOption { extraSharedConfig = mkOption {
type = types.attrs;
default = {}; default = {};
description = "Extra configuration shared between i3 and sway";
}; };
extraI3Config = mkOption { extraI3Config = mkOption {
type = types.attrs;
default = {}; default = {};
description = "Extra i3-specific configuration";
}; };
extraSwayConfig = mkOption { extraSwayConfig = mkOption {
type = types.attrs;
default = {}; default = {};
description = "Extra sway-specific configuration";
}; };
}; };
config = { config = mkIf cfg.enable {
# i3blocks configuration file # i3blocks configuration file
home.file.".config/i3blocks/config".text = '' home.file.".config/i3blocks/config".text = ''
# i3blocks config - replicating waybar setup # i3blocks config - replicating waybar setup
@@ -419,7 +430,7 @@ in {
#workspaces button { #workspaces button {
padding: 0 8px; padding: 0 8px;
background-color: transparent; background-color: #333333;
color: #ffffff; color: #ffffff;
border: none; border: none;
} }

View File

@@ -1,13 +1,13 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, globalInputs, system, ... }:
with lib; with lib;
let let
cfg = config.programs.kubectl-secure; cfg = config.home.roles.kubectl;
in in
{ {
options.programs.kubectl-secure = { options.home.roles.kubectl = {
enable = mkEnableOption "secure kubectl configuration with Bitwarden integration"; enable = mkEnableOption "management tools for the homelab k3s oglenet cluster with secure Bitwarden integration";
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@@ -21,29 +21,29 @@ in
programs.bash.initExtra = mkAfter '' programs.bash.initExtra = mkAfter ''
# Kubectl secure session management # Kubectl secure session management
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$" export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
kube-select() { kube-select() {
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
echo "Usage: kube-select <context-name>" echo "Usage: kube-select <context-name>"
echo "Available contexts: $(kube-list)" echo "Available contexts: $(kube-list)"
return 1 return 1
fi fi
local context="$1" local context="$1"
# Clean up any existing session first # Clean up any existing session first
kube-clear 2>/dev/null kube-clear 2>/dev/null
# Create new session directory # Create new session directory
mkdir -p "$KUBECTL_SESSION_DIR" mkdir -p "$KUBECTL_SESSION_DIR"
chmod 700 "$KUBECTL_SESSION_DIR" chmod 700 "$KUBECTL_SESSION_DIR"
# Set cleanup trap for this shell session # Set cleanup trap for this shell session
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
# Set KUBECONFIG for this session # Set KUBECONFIG for this session
export KUBECONFIG="$KUBECTL_SESSION_DIR/config" export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
# Load config from Bitwarden secure notes # Load config from Bitwarden secure notes
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
echo "Error: Could not retrieve kubectl-$context from Bitwarden" echo "Error: Could not retrieve kubectl-$context from Bitwarden"
@@ -51,37 +51,37 @@ in
kube-clear kube-clear
return 1 return 1
fi fi
# Verify the kubeconfig is valid # Verify the kubeconfig is valid
if ! kubectl config view >/dev/null 2>&1; then if ! kubectl config view >/dev/null 2>&1; then
echo "Error: Invalid kubeconfig retrieved from Bitwarden" echo "Error: Invalid kubeconfig retrieved from Bitwarden"
kube-clear kube-clear
return 1 return 1
fi fi
echo " Loaded kubectl context: $context (session: $$)" echo " Loaded kubectl context: $context (session: $$)"
echo " Config location: $KUBECONFIG" echo " Config location: $KUBECONFIG"
} }
kube-list() { kube-list() {
echo "Available kubectl contexts in Bitwarden:" echo "Available kubectl contexts in Bitwarden:"
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)" rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
} }
kube-clear() { kube-clear() {
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
unset KUBECTL_TIMEOUT_PID unset KUBECTL_TIMEOUT_PID
fi fi
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
rm -rf "$KUBECTL_SESSION_DIR" rm -rf "$KUBECTL_SESSION_DIR"
echo "Cleared kubectl session ($$)" echo "Cleared kubectl session ($$)"
fi fi
unset KUBECONFIG unset KUBECONFIG
} }
kube-status() { kube-status() {
if [[ -f "$KUBECONFIG" ]]; then if [[ -f "$KUBECONFIG" ]]; then
local current_context local current_context
@@ -89,7 +89,7 @@ in
if [[ -n "$current_context" ]]; then if [[ -n "$current_context" ]]; then
echo "Active kubectl context: $current_context" echo "Active kubectl context: $current_context"
echo "Session: $$ | Config: $KUBECONFIG" echo "Session: $$ | Config: $KUBECONFIG"
# Show cluster info # Show cluster info
local cluster_server local cluster_server
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null) cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
@@ -128,33 +128,33 @@ in
echo "Note: Kubeconfigs are stored as secure notes in Bitwarden" echo "Note: Kubeconfigs are stored as secure notes in Bitwarden"
} }
''; '';
programs.zsh.initExtra = mkAfter '' programs.zsh.initExtra = mkAfter ''
# Kubectl secure session management (zsh) # Kubectl secure session management (zsh)
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$" export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
kube-select() { kube-select() {
if [[ $# -ne 1 ]]; then if [[ $# -ne 1 ]]; then
echo "Usage: kube-select <context-name>" echo "Usage: kube-select <context-name>"
echo "Available contexts: $(kube-list)" echo "Available contexts: $(kube-list)"
return 1 return 1
fi fi
local context="$1" local context="$1"
# Clean up any existing session first # Clean up any existing session first
kube-clear 2>/dev/null kube-clear 2>/dev/null
# Create new session directory # Create new session directory
mkdir -p "$KUBECTL_SESSION_DIR" mkdir -p "$KUBECTL_SESSION_DIR"
chmod 700 "$KUBECTL_SESSION_DIR" chmod 700 "$KUBECTL_SESSION_DIR"
# Set cleanup trap for this shell session # Set cleanup trap for this shell session
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
# Set KUBECONFIG for this session # Set KUBECONFIG for this session
export KUBECONFIG="$KUBECTL_SESSION_DIR/config" export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
# Load config from Bitwarden secure notes # Load config from Bitwarden secure notes
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
echo "Error: Could not retrieve kubectl-$context from Bitwarden" echo "Error: Could not retrieve kubectl-$context from Bitwarden"
@@ -162,43 +162,37 @@ in
kube-clear kube-clear
return 1 return 1
fi fi
# Verify the kubeconfig is valid # Verify the kubeconfig is valid
if ! kubectl config view >/dev/null 2>&1; then if ! kubectl config view >/dev/null 2>&1; then
echo "Error: Invalid kubeconfig retrieved from Bitwarden" echo "Error: Invalid kubeconfig retrieved from Bitwarden"
kube-clear kube-clear
return 1 return 1
fi fi
echo " Loaded kubectl context: $context (session: $$)" echo " Loaded kubectl context: $context (session: $$)"
echo " Config location: $KUBECONFIG" echo " Config location: $KUBECONFIG"
# Optional: Set timeout cleanup
if [[ ${toString cfg.sessionTimeout} -gt 0 ]]; then
(sleep ${toString cfg.sessionTimeout}; kube-clear 2>/dev/null) &
export KUBECTL_TIMEOUT_PID=$!
fi
} }
kube-list() { kube-list() {
echo "Available kubectl contexts in Bitwarden:" echo "Available kubectl contexts in Bitwarden:"
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)" rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
} }
kube-clear() { kube-clear() {
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
unset KUBECTL_TIMEOUT_PID unset KUBECTL_TIMEOUT_PID
fi fi
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
rm -rf "$KUBECTL_SESSION_DIR" rm -rf "$KUBECTL_SESSION_DIR"
echo "Cleared kubectl session ($$)" echo "Cleared kubectl session ($$)"
fi fi
unset KUBECONFIG unset KUBECONFIG
} }
kube-status() { kube-status() {
if [[ -f "$KUBECONFIG" ]]; then if [[ -f "$KUBECONFIG" ]]; then
local current_context local current_context
@@ -206,7 +200,7 @@ in
if [[ -n "$current_context" ]]; then if [[ -n "$current_context" ]]; then
echo "Active kubectl context: $current_context" echo "Active kubectl context: $current_context"
echo "Session: $$ | Config: $KUBECONFIG" echo "Session: $$ | Config: $KUBECONFIG"
# Show cluster info # Show cluster info
local cluster_server local cluster_server
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null) cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)

View File

@@ -0,0 +1,36 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.home.roles.launchers;
# Generate a wrapper script for a package
makeLauncher = packageName: pkgs.writeShellScriptBin packageName ''
exec env NIXPKGS_ALLOW_UNFREE=1 ${pkgs.nix}/bin/nix run --impure nixpkgs#${packageName} -- "$@"
'';
# Generate all launcher scripts from the package list
launcherPackages = map makeLauncher cfg.packages;
in
{
options.home.roles.launchers = {
enable = mkEnableOption "wrapper launchers for excluded packages";
packages = mkOption {
type = types.listOf types.str;
default = [];
example = [ "steam" "libreoffice" "lutris" ];
description = ''
List of package names to create launcher wrappers for.
Each wrapper will run: NIXPKGS_ALLOW_UNFREE=1 nix run --impure nixpkgs#<package>
This is useful for occasionally running packages without permanently installing them.
'';
};
};
config = mkIf cfg.enable {
home.packages = launcherPackages;
};
}

View File

@@ -0,0 +1,188 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.home.roles.plasma-manager;
in
{
options.home.roles.plasma-manager = {
enable = mkEnableOption "KDE Plasma desktop environment configuration";
};
config = mkIf cfg.enable {
# The current KDE config can be output with the command:
# nix run github:nix-community/plasma-manager
#
# Plasma-manager options documentation
# https://nix-community.github.io/plasma-manager/options.xhtml
#
# TODO: (ambitious) Add Kmail support to plasma-manager
programs.plasma = {
enable = true;
overrideConfig = true;
hotkeys.commands."launch-ghostty" = {
name = "Launch Ghostty";
key = "Meta+Return";
command = "ghostty";
};
shortcuts = {
kmix = {
"decrease_microphone_volume" = "Microphone Volume Down";
"decrease_volume" = "Volume Down";
"decrease_volume_small" = "Shift+Volume Down";
"increase_microphone_volume" = "Microphone Volume Up";
"increase_volume" = "Volume Up";
"increase_volume_small" = "Shift+Volume Up";
"mic_mute" = ["Microphone Mute" "Meta+Volume Mute,Microphone Mute" "Meta+Volume Mute,Mute Microphone"];
"mute" = "Volume Mute";
};
mediacontrol = {
"mediavolumedown" = "none,,Media volume down";
"mediavolumeup" = "none,,Media volume up";
"nextmedia" = "Media Next";
"pausemedia" = "Media Pause";
"playmedia" = "none,,Play media playback";
"playpausemedia" = "Media Play";
"previousmedia" = "Media Previous";
"stopmedia" = "Media Stop";
};
ksmserver = {
"Lock Session" = ["Meta+Ctrl+Q" "Screensaver" "Screensaver,Lock Session"];
};
kwin = {
"Window Close" = "Meta+Shift+Q";
"Kill Window" = "Meta+Ctrl+Esc";
"Window Operations Menu" = "Alt+F3";
"Window Resize" = "Meta+R,,Resize Window";
"Overview" = "Meta+Ctrl+W";
"Grid View" = "Meta+G";
"Edit Tiles" = "Meta+T";
"Activate Window Demanding Attention" = "Meta+Ctrl+A";
"Show Desktop" = "Meta+Ctrl+D";
"Walk Through Windows" = "Alt+Tab";
"Walk Through Windows (Reverse)" = "Alt+Shift+Tab";
"Walk Through Windows of Current Application" = "Alt+`";
"Walk Through Windows of Current Application (Reverse)" = "Alt+~";
"Window Quick Tile Bottom" = "Meta+Down";
"Window Quick Tile Left" = "Meta+Left";
"Window Quick Tile Right" = "Meta+Right";
"Window Quick Tile Top" = "Meta+Up";
"Switch to Desktop 1" = "Meta+1";
"Switch to Desktop 2" = "Meta+2";
"Switch to Desktop 3" = "Meta+3";
"Switch to Desktop 4" = "Meta+4";
"Switch to Desktop 5" = "Meta+5";
"Switch to Desktop 6" = "Meta+6";
"Switch to Desktop 7" = "Meta+7";
"Switch to Desktop 8" = "Meta+8";
"Switch to Desktop 9" = "Meta+9";
"Switch to Desktop 10" = "Meta+0";
"Window to Desktop 1" = "Meta+!"; # Meta+Shift+1
"Window to Desktop 2" = "Meta+@"; # Meta+Shift+2
"Window to Desktop 3" = "Meta+#"; # Meta+Shift+3
"Window to Desktop 4" = "Meta+$"; # Meta+Shift+4
"Window to Desktop 5" = "Meta+%"; # Meta+Shift+5
"Window to Desktop 6" = "Meta+^"; # Meta+Shift+6
"Window to Desktop 7" = "Meta+&"; # Meta+Shift+7
"Window to Desktop 8" = "Meta+*"; # Meta+Shift+8
"Window to Desktop 9" = "Meta+("; # Meta+Shift+9
"Window to Desktop 10" = "Meta+)"; # Meta+Shift+0
"view_actual_size" = "Meta+Ctrl+=";
"view_zoom_in" = ["Meta++" "Meta+=,Meta++" "Meta+=,Zoom In"];
"view_zoom_out" = "Meta+-";
};
"org_kde_powerdevil"."Decrease Keyboard Brightness" = "Keyboard Brightness Down";
"org_kde_powerdevil"."Decrease Screen Brightness" = "Monitor Brightness Down";
"org_kde_powerdevil"."Decrease Screen Brightness Small" = "Shift+Monitor Brightness Down";
"org_kde_powerdevil"."Hibernate" = "Hibernate";
"org_kde_powerdevil"."Increase Keyboard Brightness" = "Keyboard Brightness Up";
"org_kde_powerdevil"."Increase Screen Brightness" = "Monitor Brightness Up";
"org_kde_powerdevil"."Increase Screen Brightness Small" = "Shift+Monitor Brightness Up";
"org_kde_powerdevil"."PowerDown" = "Power Down";
"org_kde_powerdevil"."PowerOff" = "Power Off";
"org_kde_powerdevil"."Sleep" = "Sleep";
"org_kde_powerdevil"."Toggle Keyboard Backlight" = "Keyboard Light On/Off";
"org_kde_powerdevil"."Turn Off Screen" = [ ];
"org_kde_powerdevil"."powerProfile" = ["Battery" "Meta+B,Battery" "Meta+B,Switch Power Profile"];
plasmashell = {
"activate application launcher" = ["Meta" "Alt+F1,Meta" "Alt+F1,Activate Application Launcher"];
"activate task manager entry 1" = "none,,";
"activate task manager entry 2" = "none,,";
"activate task manager entry 3" = "none,,";
"activate task manager entry 4" = "none,,";
"activate task manager entry 5" = "none,,";
"activate task manager entry 6" = "none,,";
"activate task manager entry 7" = "none,,";
"activate task manager entry 8" = "none,,";
"activate task manager entry 9" = "none,,";
"activate task manager entry 10" = "none,,";
"show activity switcher" = "none,,";
};
};
configFile = {
kwinrc.Desktops.Number = {
value = 10;
immutable = true;
};
# Enable KWin tiling features
kwinrc.Tiling = {
# Enable tiling functionality
"padding" = 4;
};
# Enable krohnkite plugin automatically
kwinrc.Plugins = {
krohnkiteEnabled = true;
};
kwinrc.Effect-overview = {
# Configure overview effect for better tiling workflow
BorderActivate = 9; # Top-left corner activation
};
kcminputrc.Libinput = {
AccelerationProfile = "adaptive";
PointerAcceleration = 0.5;
};
kcminputrc.Mouse = {
X11LibInputXAccelProfileFlat = false;
XLbInptAccelProfileFlat = false;
};
kdeglobals.KDE.LookAndFeelPackage = "org.kde.breezedark.desktop";
# Focus follows mouse configuration
kwinrc.Windows = {
FocusPolicy = "FocusFollowsMouse";
AutoRaise = true; # Set to true if you want windows to auto-raise on focus
AutoRaiseInterval = 750; # Delay in ms before auto-raise (if enabled)
DelayFocusInterval = 0; # Delay in ms before focus follows mouse
};
# Desktop wallpaper configuration
plasma-localerc.Formats.LANG = "en_US.UTF-8";
# Set wallpaper for all desktops
plasmarc.Wallpapers.usersWallpapers = "${../../wallpapers/metroid-samus-returns-kz-3440x1440.jpg}";
};
};
};
}

View File

@@ -0,0 +1,62 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.home.roles.tmux;
tokyo-night = pkgs.tmuxPlugins.mkTmuxPlugin {
pluginName = "tokyo-night";
rtpFilePath = "tokyo-night.tmux";
version = "1.6.1";
src = pkgs.fetchFromGitHub {
owner = "janoamaral";
repo = "tokyo-night-tmux";
rev = "d610ced20d5f602a7995854931440e4a1e0ab780";
sha256 = "sha256-17vEgkL7C51p/l5gpT9dkOy0bY9n8l0/LV51mR1k+V8=";
};
};
in
{
options.home.roles.tmux = {
enable = mkEnableOption "tmux terminal multiplexer with Tokyo Night theme";
};
config = mkIf cfg.enable {
programs.tmux.enable = true;
programs.tmux.terminal = "tmux-direct";
programs.tmux.keyMode = "vi";
programs.tmux.escapeTime = 0;
programs.tmux.mouse = true;
programs.tmux.newSession = true;
programs.tmux.historyLimit = 50000;
programs.tmux.clock24 = true;
programs.tmux.baseIndex = 1;
programs.tmux.prefix = "M-\\\\";
programs.tmux.plugins = with pkgs; [
tmuxPlugins.cpu
tmuxPlugins.battery
tmuxPlugins.better-mouse-mode
tmuxPlugins.net-speed
tmuxPlugins.online-status
tmuxPlugins.pain-control
tmuxPlugins.tilish
tmuxPlugins.yank
{
plugin = tmuxPlugins.resurrect;
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
}
{
plugin = tmuxPlugins.continuum;
extraConfig = ''
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15' # minutes
'';
}
tokyo-night
];
};
}

View File

@@ -1,6 +1,10 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
{ {
imports = [
../../modules/aerospace.nix
];
# Basic system configuration for macOS work laptop # Basic system configuration for macOS work laptop
system.stateVersion = 6; system.stateVersion = 6;
@@ -14,6 +18,12 @@
NSGlobalDomain.AppleShowAllExtensions = true; NSGlobalDomain.AppleShowAllExtensions = true;
}; };
# Enable aerospace system settings
services.aerospace = {
enable = true;
enableSpansDisplays = true; # Default, but shown for clarity
};
# TODO: Find a way to not duplicate this # TODO: Find a way to not duplicate this
launchd.user.envVariables = { launchd.user.envVariables = {
# DOOM Emacs environment variables # DOOM Emacs environment variables

View File

@@ -15,7 +15,7 @@
desktop = { desktop = {
enable = true; enable = true;
wayland = true; wayland = true;
gaming.enable = false; gaming.enable = true;
kde = true; kde = true;
sddm = true; sddm = true;
}; };

30
modules/aerospace.nix Normal file
View File

@@ -0,0 +1,30 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.aerospace;
in
{
options.services.aerospace = {
enable = mkEnableOption "AeroSpace window manager system configuration";
enableSpansDisplays = mkOption {
type = types.bool;
default = true;
description = ''
Configure macOS Spaces to span displays (required for aerospace multi-monitor support).
When enabled, sets com.apple.spaces.spans-displays to true.
'';
};
};
config = mkIf cfg.enable {
# Configure spaces to span displays (required for aerospace multi-monitor support)
system.defaults.CustomUserPreferences = mkIf cfg.enableSpansDisplays {
"com.apple.spaces" = {
spans-displays = true;
};
};
};
}

View File

@@ -0,0 +1,116 @@
# claude-cli
Custom Nix package for Claude Code CLI.
## Why This Package Exists
The official `claude-code` package in nixpkgs tries to fetch from npm registry, which is blocked by Block's corporate security (Cloudflare Teams dependency confusion protection). This custom package fetches directly from Anthropic's Google Cloud Storage distribution, bypassing the npm registry entirely.
## Updating to a New Version
### Automated Update (Recommended)
Run the update script to automatically fetch and update to the latest version:
```bash
cd packages/claude-cli
./update.sh
```
The script will:
- Fetch the latest version from Homebrew cask
- Update version and all SHA256 hashes in default.nix
- Show you what changed
For a dry-run to see what would change:
```bash
./update.sh --dry-run
```
After the script completes, follow the "Test the Build" steps below.
### Manual Update
If you prefer to update manually, or if the automated script fails:
#### 1. Find the Latest Version and Hashes
Check the Homebrew cask formula for the latest version info:
```bash
curl -s "https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/c/claude-code.rb" | head -50
```
This will show:
- The latest `version` number
- SHA256 hashes for all platforms (`arm64`, `x86_64`, `x86_64_linux`, `arm64_linux`)
#### 2. Update default.nix
Edit `default.nix` and update:
1. The `version` variable (line 9):
```nix
version = "2.0.51"; # Update this
```
2. All four platform sha256 hashes in the `srcs` attribute set (lines 11-27):
```nix
aarch64-darwin = {
sha256 = "..."; # Update from Homebrew cask "arm:" value
};
x86_64-darwin = {
sha256 = "..."; # Update from Homebrew cask "x86_64:" value
};
x86_64-linux = {
sha256 = "..."; # Update from Homebrew cask "x86_64_linux:" value
};
aarch64-linux = {
sha256 = "..."; # Update from Homebrew cask "arm64_linux:" value
};
```
#### 3. Test the Build
Before committing, test that the package builds successfully:
```bash
NIXPKGS_ALLOW_UNFREE=1 nix-build -E 'with import <nixpkgs> { config.allowUnfree = true; }; callPackage ./packages/claude-cli {}'
```
Verify the version:
```bash
./result/bin/claude --version
```
Clean up the test build:
```bash
rm result
```
#### 4. Deploy
Commit your changes and rebuild:
```bash
git add packages/claude-cli/
git commit -m "claude-cli: Update to version X.Y.Z"
darwin-rebuild switch --flake .#blkfv4yf49kt7
```
## Alternative: Automated Hash Fetching
If you prefer to fetch hashes automatically, you can use `nix-prefetch-url`:
```bash
# For macOS ARM64 (your current platform)
nix-prefetch-url "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/VERSION/darwin-arm64/claude"
# For other platforms, replace VERSION and adjust the platform string:
# darwin-x64, linux-x64, linux-arm64
```
This will download the file and output the SHA256 hash.

View File

@@ -0,0 +1,60 @@
{ lib
, stdenv
, fetchurl
, autoPatchelfHook
}:
let
version = "2.0.53";
srcs = {
aarch64-darwin = {
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-arm64/claude";
sha256 = "28c3ad73a20f3ae7ab23efa24d45a9791ccbe071284f1622d4e5e2b89c4a15b7";
};
x86_64-darwin = {
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-x64/claude";
sha256 = "a27f7b75a51514658640432a0afec8be130673eb7dbecc9a4d742527dd85d29a";
};
x86_64-linux = {
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-x64/claude";
sha256 = "9c4cc19e207fb6bf7ea140a1580d5ed0dd0a481af471f23614d5a140a4abf1c6";
};
aarch64-linux = {
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-arm64/claude";
sha256 = "a5d4044034f3b63c38379bc2dd4067a4dd3c8ec48965ba8e66e3623774a93b72";
};
};
src = srcs.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
in stdenv.mkDerivation {
pname = "claude-code";
inherit version;
src = fetchurl {
inherit (src) url sha256;
};
dontUnpack = true;
dontBuild = true;
nativeBuildInputs = lib.optionals stdenv.isLinux [ autoPatchelfHook ];
installPhase = ''
runHook preInstall
install -Dm755 $src $out/bin/claude
runHook postInstall
'';
meta = with lib; {
description = "Terminal-based AI coding assistant from Anthropic";
homepage = "https://www.anthropic.com/claude-code";
license = licenses.unfree;
maintainers = [ ];
platforms = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ];
mainProgram = "claude";
};
}

View File

@@ -0,0 +1,34 @@
{ lib
, buildNpmPackage
, fetchurl
, nodejs_18
}:
buildNpmPackage {
pname = "claude-cli";
version = "0.2.65";
src = fetchurl {
url = "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-0.2.65.tgz";
sha256 = "0wwaqq7k9p5aw4vqhfpdgf3da09x64q55wibqaprk6kjvn130i92";
};
npmDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Will be updated after first build
nodejs = nodejs_18;
# Don't run npm audit or other network operations during build
npmConfigHook = ''
npm config set audit false
npm config set fund false
'';
meta = with lib; {
description = "Terminal-based AI coding assistant from Anthropic (npm distribution)";
homepage = "https://www.anthropic.com/claude-code";
license = licenses.unfree;
maintainers = [ ];
platforms = platforms.all;
mainProgram = "claude";
};
}

132
packages/claude-code/update.sh Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/env bash
set -euo pipefail
DRY_RUN=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run|-n)
DRY_RUN=true
shift
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --dry-run, -n Show what would be updated without making changes"
echo " --help, -h Show this help message"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
CASK_URL="https://raw.githubusercontent.com/Homebrew/homebrew-cask/HEAD/Casks/c/claude-code.rb"
NIX_FILE="$(dirname "$0")/default.nix"
echo "Fetching latest claude-code version from Homebrew cask..."
# Fetch the cask file
CASK_CONTENT=$(curl -fsSL "$CASK_URL")
# Extract version (format: version "X.Y.Z")
NEW_VERSION=$(echo "$CASK_CONTENT" | grep -m1 'version' | sed -E 's/.*version "([^"]+)".*/\1/')
# Extract SHA256 hashes (be specific to match sha256 lines only)
SHA_ARM=$(echo "$CASK_CONTENT" | grep 'sha256 arm:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
SHA_X86_64=$(echo "$CASK_CONTENT" | grep 'x86_64:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
SHA_X86_64_LINUX=$(echo "$CASK_CONTENT" | grep 'x86_64_linux:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
SHA_ARM64_LINUX=$(echo "$CASK_CONTENT" | grep 'arm64_linux:' | sed -E 's/.*"([a-f0-9]{64})".*/\1/')
# Get current version
CURRENT_VERSION=$(grep -m1 'version = ' "$NIX_FILE" | sed -E 's/.*version = "([^"]+)".*/\1/')
# Validate extracted data
if [ -z "$NEW_VERSION" ] || [ -z "$SHA_ARM" ] || [ -z "$SHA_X86_64" ] || [ -z "$SHA_X86_64_LINUX" ] || [ -z "$SHA_ARM64_LINUX" ]; then
echo -e "${RED}Error: Failed to extract all required values from Homebrew cask${NC}"
echo "Version: $NEW_VERSION"
echo "ARM: $SHA_ARM"
echo "x86_64: $SHA_X86_64"
echo "x86_64_linux: $SHA_X86_64_LINUX"
echo "arm64_linux: $SHA_ARM64_LINUX"
exit 1
fi
# Check if update is needed
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
echo -e "${GREEN}Already up to date: $CURRENT_VERSION${NC}"
exit 0
fi
echo -e "${YELLOW}Updating from $CURRENT_VERSION to $NEW_VERSION${NC}"
if [ "$DRY_RUN" = true ]; then
echo -e "${YELLOW}DRY RUN - No changes will be made${NC}"
echo ""
echo "Would update:"
echo " Version: $CURRENT_VERSION -> $NEW_VERSION"
echo " aarch64-darwin SHA: $SHA_ARM"
echo " x86_64-darwin SHA: $SHA_X86_64"
echo " x86_64-linux SHA: $SHA_X86_64_LINUX"
echo " aarch64-linux SHA: $SHA_ARM64_LINUX"
exit 0
fi
# Update version
sed -i.tmp "s/version = \".*\";/version = \"$NEW_VERSION\";/" "$NIX_FILE"
# Update SHA256 hashes using awk for more reliable parsing
awk -v sha_arm="$SHA_ARM" -v sha_x86="$SHA_X86_64" -v sha_x86_linux="$SHA_X86_64_LINUX" -v sha_arm_linux="$SHA_ARM64_LINUX" '
/aarch64-darwin = {/ { in_arm = 1 }
/x86_64-darwin = {/ { in_x86 = 1 }
/x86_64-linux = {/ { in_x86_linux = 1 }
/aarch64-linux = {/ { in_arm_linux = 1 }
/};/ {
in_arm = 0
in_x86 = 0
in_x86_linux = 0
in_arm_linux = 0
}
/sha256 = / {
if (in_arm) {
sub(/sha256 = ".*";/, "sha256 = \"" sha_arm "\";")
} else if (in_x86) {
sub(/sha256 = ".*";/, "sha256 = \"" sha_x86 "\";")
} else if (in_x86_linux) {
sub(/sha256 = ".*";/, "sha256 = \"" sha_x86_linux "\";")
} else if (in_arm_linux) {
sub(/sha256 = ".*";/, "sha256 = \"" sha_arm_linux "\";")
}
}
{ print }
' "$NIX_FILE" > "$NIX_FILE.new"
mv "$NIX_FILE.new" "$NIX_FILE"
# Clean up temp files
rm -f "$NIX_FILE.tmp"
echo -e "${GREEN}Successfully updated to version $NEW_VERSION${NC}"
echo ""
echo "Updated SHA256 hashes:"
echo " aarch64-darwin: $SHA_ARM"
echo " x86_64-darwin: $SHA_X86_64"
echo " x86_64-linux: $SHA_X86_64_LINUX"
echo " aarch64-linux: $SHA_ARM64_LINUX"
echo ""
echo "Next steps:"
echo " 1. Review changes: git diff $NIX_FILE"
echo " 2. Test build: NIXPKGS_ALLOW_UNFREE=1 nix-build -E 'with import <nixpkgs> { config.allowUnfree = true; }; callPackage ./packages/claude-code {}'"
echo " 3. Verify version: ./result/bin/claude --version"
echo " 4. Commit: git add $NIX_FILE && git commit -m 'claude-code: Update to version $NEW_VERSION'"

View File

@@ -3,4 +3,5 @@
vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {}; vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {};
tea-rbw = pkgs.callPackage ./tea-rbw {}; tea-rbw = pkgs.callPackage ./tea-rbw {};
app-launcher-server = pkgs.callPackage ./app-launcher-server {}; app-launcher-server = pkgs.callPackage ./app-launcher-server {};
claude-code = pkgs.callPackage ./claude-code {};
} }

View File

@@ -9,21 +9,32 @@ in
config = mkMerge [ config = mkMerge [
(mkIf (cfg.enable && cfg.gaming.enable) { (mkIf (cfg.enable && cfg.gaming.enable) {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
steam
lutris lutris
moonlight moonlight
# Emulators # Emulators
dolphin-emu dolphin-emu
dolphin-emu-primehack
retroarch-full # Waiting for 25.11 where the binary build has been fixed
#dolphin-emu-primehack
# Experimenting with just using the steam version + downloading
# indiviudal cores
#retroarch-full
ryubing ryubing
]; ];
programs.steam = {
enable = true;
remotePlay.openFirewall = true;
dedicatedServer.openFirewall = true;
localNetworkGameTransfers.openFirewall = true;
};
# TODO: Remove me once dolphin-emu and dolphin-emu-primehack update # TODO: Remove me once dolphin-emu and dolphin-emu-primehack update
# dependencies to mbedtls from mbedtls_2 (which is currently) # dependencies to mbedtls from mbedtls_2 (which is currently)
# unmaintained # unmaintained
nixpkgs.config.permittedInsecurePackages = [ "mbedtls-2.28.10" ]; nixpkgs.config.permittedInsecurePackages = [ "mbedtls-2.28.10" ];
warnings = [ warnings = [
"Using insecure mbedtls-2.28.10 for Dolphin Emu - check for updates regularly" "Using insecure mbedtls-2.28.10 for Dolphin Emu - check for updates regularly"
]; ];