chore: update

This commit is contained in:
kp2pml30 2026-04-12 22:38:09 +09:00
parent eaccf45596
commit d3790a167b
No known key found for this signature in database
GPG key ID: 1739F9D8BA250D04
27 changed files with 715 additions and 229 deletions

52
.gitignore vendored
View file

@ -1,3 +1,55 @@
/result /result
/result-fd
/.env /.env
/claude-docker /claude-docker
/.claude-vm
# editors
.vscode/
.idea/
.godot/
# apple
.DS_Store
.AppleDouble
.LSOverride
# build related directories
/build
target
result
zig-out
zig-build
# secrets
.env
# direnv
.envrc
.direnv
# py
__pycache__/
.pytest_cache
.mypy_cache
.ruff_cache
.coverage*
core.[0-9]*
# claude sandbox
/.bash_profile
/.bashrc
/.gitconfig
/.mcp.json
/.profile
/.ripgreprc
/.zprofile
/.zshrc
/HEAD
/config
/hooks
/objects
/refs
.claude/agents
.claude/commands
.claude/settings.json

0
.gitmodules vendored Normal file
View file

View file

@ -29,3 +29,21 @@ __pycache__/
.ruff_cache .ruff_cache
.coverage* .coverage*
core.[0-9]* core.[0-9]*
# claude sandbox
/.bash_profile
/.bashrc
/.gitconfig
/.mcp.json
/.profile
/.ripgreprc
/.zprofile
/.zshrc
/HEAD
/config
/hooks
/objects
/refs
.claude/agents
.claude/commands
.claude/settings.json

139
flake.lock generated
View file

@ -1,13 +1,52 @@
{ {
"nodes": { "nodes": {
"claude-code": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1775007163,
"narHash": "sha256-plS86OtgkWsAf/NtXc5iwxpBB+cOuyqjo5Xq2gEg8FQ=",
"owner": "sadjow",
"repo": "claude-code-nix",
"rev": "335c96551a1650e0306b756039f15c3364d2e0ac",
"type": "github"
},
"original": {
"owner": "sadjow",
"repo": "claude-code-nix",
"type": "github"
}
},
"code-flake": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1774250740,
"narHash": "sha256-xQogXLfvKA/gw3BfxwbS89sVHnoiLbCHrvwTFnOgWk8=",
"owner": "kp2pml30",
"repo": "code-flake",
"rev": "982adef5d1e5bdb4e1095aad5a635cef5d6c8510",
"type": "github"
},
"original": {
"owner": "kp2pml30",
"repo": "code-flake",
"type": "github"
}
},
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1733328505, "lastModified": 1767039857,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -17,6 +56,24 @@
} }
}, },
"flake-utils": { "flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": { "inputs": {
"systems": [ "systems": [
"kp2pml30-moe", "kp2pml30-moe",
@ -44,41 +101,40 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1758463745, "lastModified": 1773963144,
"narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", "narHash": "sha256-WzBOBfSay3GYilUfKaUa1Mbf8/jtuAiJIedx7fWuIX4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", "rev": "a91b3ea73a765614d90360580b689c48102d1d33",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-community", "owner": "nix-community",
"ref": "release-25.05", "ref": "release-25.11",
"repo": "home-manager", "repo": "home-manager",
"type": "github" "type": "github"
} }
}, },
"kp2pml30-moe": { "kp2pml30-moe": {
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils_2",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
], ],
"rust-overlay": "rust-overlay", "rust-overlay": "rust-overlay",
"systems": "systems" "systems": "systems_2"
}, },
"locked": { "locked": {
"lastModified": 1770820613, "lastModified": 1775030101,
"narHash": "sha256-I5lMXVML0491AqfSI8DUnw3mhIwCLIfQWwZwrdeRrZY=", "narHash": "sha256-huBQI29iONwcRYDQDZlce60OjbRgsd7AN1f8EGYyf+Y=",
"owner": "kp2pml30", "owner": "kp2pml30",
"repo": "kp2pml30.github.io", "repo": "kp2pml30.github.io",
"rev": "73cbd5858e7196c236029f86756119806d484612", "rev": "1deafcacbaa870308dee0467f08fa8a77a733861",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "kp2pml30", "owner": "kp2pml30",
"repo": "kp2pml30.github.io", "repo": "kp2pml30.github.io",
"rev": "73cbd5858e7196c236029f86756119806d484612",
"type": "github" "type": "github"
} }
}, },
@ -105,11 +161,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1742568034, "lastModified": 1769813415,
"narHash": "sha256-QaMEhcnscfF2MqB7flZr+sLJMMYZPnvqO4NYf9B4G38=", "narHash": "sha256-nnVmNNKBi1YiBNPhKclNYDORoHkuKipoz7EtVnXO50A=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixos-generators", "repo": "nixos-generators",
"rev": "42ee229088490e3777ed7d1162cb9e9d8c3dbb11", "rev": "8946737ff703382fda7623b9fab071d037e897d5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -126,11 +182,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1744290088, "lastModified": 1773882647,
"narHash": "sha256-/X9XVEl0EiyisNbF5srrxXRSVoRqdwExuqyspYqqEjQ=", "narHash": "sha256-VzcOcE0LLpEnyoxLuMuptZ9ZWCkSBn99bTgEQoz5Viw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NixOS-WSL", "repo": "NixOS-WSL",
"rev": "60b4904a1390ac4c89e93d95f6ed928975e525ed", "rev": "fd0eae98d1ecee31024271f8d64676250a386ee7",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -141,6 +197,22 @@
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": {
"lastModified": 1774855581,
"narHash": "sha256-YkreHeMgTCYvJ5fESV0YyqQK49bHGe2B51tH6claUh4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "15c6719d8c604779cf59e03c245ea61d3d7ab69b",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1736320768, "lastModified": 1736320768,
"narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=", "narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=",
@ -156,13 +228,13 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1770056022, "lastModified": 1773964973,
"narHash": "sha256-yvCz+Qmci1bVucXEyac3TdoSPMtjqVJmVy5wro6j/70=", "narHash": "sha256-NV/J+tTER0P5iJhUDL/8HO5MDjDceLQPRUYgdmy5wXw=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d04d8548aed39902419f14a8537006426dc1e4fa", "rev": "812b3986fd1568f7a858f97fcf425ad996ba7d25",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -174,16 +246,18 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"claude-code": "claude-code",
"code-flake": "code-flake",
"home-manager": "home-manager", "home-manager": "home-manager",
"kp2pml30-moe": "kp2pml30-moe", "kp2pml30-moe": "kp2pml30-moe",
"nixos-generators": "nixos-generators", "nixos-generators": "nixos-generators",
"nixos-wsl": "nixos-wsl", "nixos-wsl": "nixos-wsl",
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_3"
} }
}, },
"rust-overlay": { "rust-overlay": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1743682350, "lastModified": 1743682350,
@ -214,6 +288,21 @@
"repo": "default", "repo": "default",
"type": "github" "type": "github"
} }
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View file

@ -6,37 +6,33 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
home-manager = { home-manager = {
url = "github:nix-community/home-manager/release-25.05"; url = "github:nix-community/home-manager/release-25.11";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nixos-generators = { nixos-generators = {
url = "github:nix-community/nixos-generators"; url = "github:nix-community/nixos-generators";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
#vscode-server = {
# url = "github:nix-community/nixos-vscode-server";
# inputs.nixpkgs.follows = "nixpkgs";
#};
kp2pml30-moe = { kp2pml30-moe = {
url = "github:kp2pml30/kp2pml30.github.io/73cbd5858e7196c236029f86756119806d484612"; url = "github:kp2pml30/kp2pml30.github.io";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
code-flake = {
url = "github:kp2pml30/code-flake";
inputs.nixpkgs.follows = "nixpkgs";
};
claude-code.url = "github:sadjow/claude-code-nix";
}; };
outputs = inputs@{ self, nixpkgs, nixos-wsl, home-manager, nixos-generators, kp2pml30-moe, ... }: outputs = inputs@{ self, nixpkgs, nixos-wsl, home-manager, nixos-generators, kp2pml30-moe, code-flake, claude-code, ... }:
let let
rootPath = self; rootPath = self;
additionalArgs = { inherit inputs rootPath; }; additionalArgs = { inherit inputs rootPath; };
lib = nixpkgs.lib; lib = nixpkgs.lib;
in in
{ {
packages.x86_64-linux.docker-nix-node = import ./nix/docker-images/nix-node.nix {
pkgs = import nixpkgs { system = "x86_64-linux"; };
inherit lib;
rootPath = self;
};
nixosConfigurations = { nixosConfigurations = {
server = nixpkgs.lib.nixosSystem { server = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
@ -75,9 +71,8 @@
networking.hostId = "e31a5cc2"; networking.hostId = "e31a5cc2";
time.timeZone = "Asia/Tokyo"; time.timeZone = "Asia/Tokyo";
environment.systemPackages = [
# pkgs.claude-code nixpkgs.overlays = [ claude-code.overlays.default code-flake.overlays.default ];
];
}) })
./nix/hardware/mini.nix ./nix/hardware/mini.nix
@ -86,6 +81,10 @@
./nix/personal ./nix/personal
./nix/qemu.nix
./nix/xray.nix
{ {
kp2pml30 = { kp2pml30 = {
xserver = true; xserver = true;
@ -94,6 +93,11 @@
opera = true; opera = true;
steam = true; steam = true;
qemu = true;
xray-client = true;
xray-client-id = "mini";
boot.efiGrub = true; boot.efiGrub = true;
hardware.wireless = true; hardware.wireless = true;
@ -114,6 +118,8 @@
networking.hostId = "e31a5cc0"; networking.hostId = "e31a5cc0";
time.timeZone = "Asia/Yerevan"; time.timeZone = "Asia/Yerevan";
nixpkgs.overlays = [ code-flake.overlays.default ];
} }
./nix/hardware/ideapad.nix ./nix/hardware/ideapad.nix
@ -154,6 +160,26 @@
]; ];
specialArgs = additionalArgs; specialArgs = additionalArgs;
}; };
claude-vm = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
{ networking.hostId = "c1a0de00"; }
./nix/common.nix
./nix/claude-vm
./nix/personal
./nix/hardware/claude-vm.nix
];
specialArgs = additionalArgs;
};
claude-vm-installer = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./nix/claude-vm/installer.nix
];
specialArgs = additionalArgs;
};
}; };
}; };
} }

View file

@ -7,6 +7,9 @@ if status is-interactive
if command -v zoxide > /dev/null if command -v zoxide > /dev/null
zoxide init fish | source zoxide init fish | source
end end
if command -v carapace > /dev/null
carapace _carapace | source
end
end end
export GPG_TTY=(tty) export GPG_TTY=(tty)

View file

@ -0,0 +1,14 @@
source $"($nu.cache-dir)/carapace.nu"
let carapace_completer = {|spans|
carapace $spans.0 nushell ...$spans | from json
}
$env.config.completions = {
algorithm: "fuzzy"
external: {
enable: true
max_results: 100
completer: $carapace_completer
}
}

View file

@ -0,0 +1,3 @@
$env.CARAPACE_BRIDGES = 'zsh,fish,bash,inshellisense'
mkdir $"($nu.cache-dir)"
carapace _carapace nushell | save --force $"($nu.cache-dir)/carapace.nu"

29
nix/claude-vm/default.nix Normal file
View file

@ -0,0 +1,29 @@
{ pkgs, lib, ... }:
{
users.mutableUsers = false;
users.users.claude = {
isNormalUser = true;
extraGroups = [ "wheel" ];
shell = pkgs.fish;
hashedPassword = "";
};
users.users.root.hashedPassword = "";
security.sudo.wheelNeedsPassword = false;
programs.fish.enable = true;
services.openssh = {
enable = true;
settings = {
PermitRootLogin = "yes";
PermitEmptyPasswords = "yes";
};
};
networking.firewall.allowedTCPPorts = [ 22 ];
nix.settings.trusted-users = [ "root" "claude" ];
}

View file

@ -0,0 +1,64 @@
{ pkgs, lib, rootPath, modulesPath, ... }:
let
install-claude-vm = pkgs.writeShellScriptBin "install-claude-vm" ''
set -euo pipefail
DISK="/dev/vda"
echo "=== claude-vm installer ==="
echo "Target disk: $DISK"
# Partition: MBR with single root partition
echo "Partitioning..."
parted -s "$DISK" -- \
mklabel msdos \
mkpart primary ext4 1MiB 100%
# Format with label
echo "Formatting..."
mkfs.ext4 -L nixos "''${DISK}1"
# Mount
echo "Mounting..."
mount "''${DISK}1" /mnt
# Copy flake source
echo "Copying flake to /mnt/dotfiles..."
mkdir -p /mnt/dotfiles
cp -a /etc/dotfiles-src/. /mnt/dotfiles/
# Install
echo "Running nixos-install..."
nixos-install --flake /mnt/dotfiles#claude-vm --no-root-passwd --show-trace
echo "=== Installation complete! Shutting down... ==="
${pkgs.systemd}/bin/systemctl poweroff
'';
in
{
imports = [
"${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix"
];
# Serial console for -nographic QEMU
boot.kernelParams = [ "console=ttyS0,115200n8" ];
boot.loader.timeout = lib.mkForce 5;
environment.etc."dotfiles-src".source = rootPath;
environment.systemPackages = [ install-claude-vm ];
# Auto-run installer on boot
systemd.services.auto-install = {
description = "Automatic claude-vm installation";
after = [ "multi-user.target" ];
wantedBy = [ "multi-user.target" ];
path = with pkgs; [ nix nixos-install-tools util-linux coreutils git curl wget binutils e2fsprogs dosfstools parted ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${install-claude-vm}/bin/install-claude-vm";
StandardOutput = "journal+console";
StandardError = "journal+console";
};
};
}

View file

@ -1,113 +0,0 @@
{ pkgs, lib, rootPath }:
let
user = "devuser";
uid = "1000";
gid = "1000";
baseVim = rootPath + "/home/.config/nvim/base.vim";
fromGitHub = rev: repo: pkgs.vimUtils.buildVimPlugin {
pname = "${lib.strings.sanitizeDerivationName repo}";
version = rev;
src = builtins.fetchGit {
url = "https://github.com/${repo}.git";
inherit rev;
};
};
customNeovim = pkgs.neovim.override {
configure = {
customRC = builtins.readFile baseVim;
packages.myPlugins = with pkgs.vimPlugins; {
start = [
nvim-treesitter.withAllGrammars
nvim-autopairs
nerdtree
tokyonight-nvim
barbar-nvim
((fromGitHub "3587f57480b88e8009df7b36dc84e9c7ff8f2c49" "famiu/feline.nvim").overrideAttrs (old: {
doCheck = false;
}))
(fromGitHub "d63c811337b2f75de52f16efee176695f31e7fbc" "timakro/vim-yadi")
(fromGitHub "aafa5c187a15701a7299a392b907ec15d9a7075f" "nvim-tree/nvim-web-devicons")
];
};
};
};
# Create passwd/group/shadow as a package
userSetup = pkgs.runCommand "user-setup" {} ''
mkdir -p $out/etc
echo "root:x:0:0:root:/root:/bin/bash" > $out/etc/passwd
echo "${user}:x:${uid}:${gid}:${user}:/home/${user}:${pkgs.bash}/bin/bash" >> $out/etc/passwd
echo "root:x:0:" > $out/etc/group
echo "${user}:x:${gid}:" >> $out/etc/group
echo "root:!:1::::::" > $out/etc/shadow
echo "${user}:!:1::::::" >> $out/etc/shadow
mkdir -p $out/etc/nix
cat > $out/etc/nix/nix.conf <<EOF
experimental-features = nix-command flakes
EOF
mkdir -p $out/etc/sudoers.d
echo "${user} ALL=(ALL) NOPASSWD: ALL" > $out/etc/sudoers.d/${user}
chmod 440 $out/etc/sudoers.d/${user}
mkdir -p $out/tmp
chmod 1777 $out/tmp
'';
entrypoint = pkgs.writeShellScriptBin "entrypoint" ''
if ! command -v claude &> /dev/null; then
echo "Installing claude-code..."
npm install -g @anthropic-ai/claude-code
fi
exec "$@"
'';
in
pkgs.dockerTools.buildLayeredImage {
name = "nix-node";
tag = "latest";
contents = with pkgs; [
nix
nodejs
bash
coreutils
cacert
git
fish
curl
wget
htop
sudo
customNeovim
userSetup
entrypoint
];
fakeRootCommands = ''
mkdir -p ./home/${user}/.npm-global
chown -R ${uid}:${gid} ./home/${user}
mkdir -p ./usr/bin
ln -s ${pkgs.coreutils}/bin/env ./usr/bin/env
'';
enableFakechroot = true;
config = {
Entrypoint = [ "${entrypoint}/bin/entrypoint" ];
Cmd = [ "${pkgs.bash}/bin/bash" ];
User = "${user}";
WorkingDir = "/home/${user}";
Env = [
"HOME=/home/${user}"
"USER=${user}"
"NIX_PAGER=cat"
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
"NIX_CONF_DIR=/etc/nix"
"NPM_CONFIG_PREFIX=/home/${user}/.npm-global"
"PATH=/home/${user}/.npm-global/bin:/usr/bin:/bin"
];
};
}

View file

@ -0,0 +1,41 @@
{ lib, ... }:
{
imports = [
./common.nix
];
boot.initrd.availableKernelModules = [
"virtio_pci"
"virtio_blk"
"virtio_net"
"virtio_balloon"
"virtio_scsi"
"xhci_pci"
"ahci"
"usbhid"
];
boot.kernelParams = [ "console=ttyS0,115200n8" ];
boot.loader.efi.canTouchEfiVariables = lib.mkForce false;
boot.loader.grub = {
enable = true;
device = "/dev/vda";
extraConfig = ''
serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1
terminal_input serial console
terminal_output serial console
'';
};
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
fsType = "ext4";
};
services.qemuGuest.enable = true;
networking = {
hostName = "claude-vm";
useDHCP = true;
};
}

View file

@ -21,15 +21,24 @@
options = [ "fmask=0077" "dmask=0077" ]; options = [ "fmask=0077" "dmask=0077" ];
}; };
# fileSystems."/mnt/d" = { fileSystems."/mnt/d" = {
# device = "/dev/sda1"; device = "/dev/sda1";
# fsType = "exfat"; fsType = "exfat";
# options = [ options = [
# "users" "users"
# "exec" "exec"
# "nofail" "nofail"
# ]; ];
# }; };
fileSystems."/mnt/d/SteamLibrary/steamapps/compatdata" = {
device = "/home/kp2pml30/.local/share/Steam/steamapps/compatdata-d";
fsType = "none";
options = [
"bind"
"nofail"
];
};
swapDevices = [ { device = "/dev/disk/by-uuid/c68daa9f-f165-4e23-8710-2aab0ad8d282"; } ]; swapDevices = [ { device = "/dev/disk/by-uuid/c68daa9f-f165-4e23-8710-2aab0ad8d282"; } ];
@ -44,8 +53,8 @@
programs.nix-ld.enable = true; programs.nix-ld.enable = true;
home-manager.users.${config.kp2pml30.username}.programs.git.extraConfig = { home-manager.users.${config.kp2pml30.username}.programs.git.settings = {
user.signingkey = "0xCD6528BAC23E3E34!"; user.signingkey = "0x1739F9D8BA250D04!";
commit.gpgsign = true; commit.gpgsign = true;
tag.gpgSign = true; tag.gpgSign = true;
}; };

View file

@ -13,4 +13,6 @@
open = true; open = true;
nvidiaSettings = true; nvidiaSettings = true;
}; };
hardware.nvidia-container-toolkit.enable = true;
} }

View file

@ -6,6 +6,8 @@
}@args: }@args:
let let
cfg = config.kp2pml30; cfg = config.kp2pml30;
startsWith = prefix: str:
builtins.substring 0 (builtins.stringLength prefix) str == prefix;
in { in {
options.kp2pml30 = { options.kp2pml30 = {
username = lib.mkOption { username = lib.mkOption {
@ -65,22 +67,17 @@ in {
fish fish
fishPlugins.grc fishPlugins.grc
fishPlugins.bass fishPlugins.bass
nushell
carapace
python312 # needed for bass python312 # needed for bass
grc grc
]; ];
nixpkgs.config.allowUnfreePredicate = pkg: nixpkgs.config.allowUnfreePredicate = pkg:
builtins.any (x: startsWith x (pkgs.lib.getName pkg)) [ "vscode" "steam" "nvidia" ] ||
builtins.elem (pkgs.lib.getName pkg) [ builtins.elem (pkgs.lib.getName pkg) [
"anytype-heart" "anytype-heart"
"vscode"
"steam"
"steam-run"
"steam-original"
"steam-unwrapped"
"nvidia-x11"
"nvidia-settings"
"nvidia-persistenced"
"opera" "opera"
"discord" "discord"
"slack" "slack"

View file

@ -17,37 +17,49 @@ in {
./messengers-work.nix ./messengers-work.nix
]; ];
xdg.portal = { config = {
enable = true; assertions = [
extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; { assertion = cfg.kitty -> cfg.xserver; message = "kp2pml30.kitty requires kp2pml30.xserver"; }
{ assertion = cfg.vscode -> cfg.xserver; message = "kp2pml30.vscode requires kp2pml30.xserver"; }
{ assertion = cfg.opera -> cfg.xserver; message = "kp2pml30.opera requires kp2pml30.xserver"; }
{ assertion = cfg.steam -> cfg.xserver; message = "kp2pml30.steam requires kp2pml30.xserver"; }
{ assertion = cfg.messengers.personal -> cfg.xserver; message = "kp2pml30.messengers.personal requires kp2pml30.xserver"; }
{ assertion = cfg.messengers.work -> cfg.xserver; message = "kp2pml30.messengers.work requires kp2pml30.xserver"; }
];
} // lib.mkIf cfg.xserver {
xdg.portal = {
enable = true;
extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
config.common.default = "*";
};
services.flatpak.enable = true;
systemd.services.flatpak-repo = {
wantedBy = [ "multi-user.target" ];
path = [ pkgs.flatpak ];
script = ''
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
'';
};
environment.systemPackages = with pkgs; [
#anytype
flatpak
gnome-software
firefox
feh
vlc
];
fonts.enableDefaultPackages = true;
fonts.packages = with pkgs; [
noto-fonts
noto-fonts-cjk-sans
noto-fonts-cjk-sans
fira-code
fira-code-symbols
nerd-fonts.fira-code
];
}; };
services.flatpak.enable = true;
systemd.services.flatpak-repo = {
wantedBy = [ "multi-user.target" ];
path = [ pkgs.flatpak ];
script = ''
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
'';
};
environment.systemPackages = with pkgs; [
anytype
flatpak
gnome-software
nodePackages.npm
nodejs
];
fonts.enableDefaultPackages = true;
fonts.packages = with pkgs; [
noto-fonts
noto-fonts-cjk-sans
noto-fonts-cjk-sans
fira-code
fira-code-symbols
nerd-fonts.fira-code
];
} }

View file

@ -9,9 +9,9 @@ let
in lib.mkIf cfg.steam { in lib.mkIf cfg.steam {
programs.steam = { programs.steam = {
enable = true; enable = true;
remotePlay.openFirewall = false; remotePlay.openFirewall = true;
dedicatedServer.openFirewall = false; dedicatedServer.openFirewall = false;
localNetworkGameTransfers.openFirewall = false; localNetworkGameTransfers.openFirewall = true;
}; };
hardware.steam-hardware.enable = true; hardware.steam-hardware.enable = true;

View file

@ -10,15 +10,16 @@ in lib.mkIf cfg.vscode {
home-manager.users.${cfg.username} = { home-manager.users.${cfg.username} = {
programs.vscode = { programs.vscode = {
enable = true; enable = true;
package = (pkgs.vscode.overrideAttrs (oldAttrs: rec { package = pkgs.vscode.overrideAttrs (oldAttrs: {
src = (builtins.fetchTarball { buildInputs = (oldAttrs.buildInputs or []) ++ [
url = "https://update.code.visualstudio.com/1.104.1/linux-x64/stable"; pkgs.curl
sha256 = "sha256:109mdk1v323dyhzrq0444gjjhfpjxbllkqkhsapfj44ypjzdjcy8"; pkgs.openssl
}); pkgs.webkitgtk_4_1
version = "1.102.2"; pkgs.libsoup_3
})); ];
});
mutableExtensionsDir = false; mutableExtensionsDir = false;
userSettings = lib.importJSON("${rootPath}/vscode/settings.json"); profiles.default.userSettings = lib.importJSON("${rootPath}/vscode/settings.json");
# extensions = with pkgs; [ # extensions = with pkgs; [
# vscode-extensions.eamodio.gitlens # vscode-extensions.eamodio.gitlens
# vscode-extensions.editorconfig.editorconfig # vscode-extensions.editorconfig.editorconfig

View file

@ -18,7 +18,7 @@ in {
home-manager.users.${cfg.username} = { lib, ... }: { home-manager.users.${cfg.username} = { lib, ... }: {
home = { home = {
stateVersion = "24.05"; stateVersion = "25.11";
username = cfg.username; username = cfg.username;
homeDirectory = "/home/${cfg.username}"; homeDirectory = "/home/${cfg.username}";
packages = with pkgs; [ packages = with pkgs; [
@ -41,16 +41,16 @@ in {
nix.gc = { nix.gc = {
automatic = true; automatic = true;
frequency = "weekly"; dates = "weekly";
}; };
programs = { programs = {
git = { git = {
enable = true; enable = true;
userName = cfg.username;
userEmail = "kp2pml30@gmail.com";
lfs.enable = true; lfs.enable = true;
extraConfig = { settings = {
user.name = cfg.username;
user.email = "kp2pml30@gmail.com";
init.defaultBranch = "main"; init.defaultBranch = "main";
}; };
}; };
@ -60,6 +60,12 @@ in {
shellInitLast = builtins.readFile (rootPath + "/home/.config/fish/config.fish"); shellInitLast = builtins.readFile (rootPath + "/home/.config/fish/config.fish");
}; };
nushell = {
enable = true;
extraEnv = builtins.readFile (rootPath + "/home/.config/nushell/env.nu");
extraConfig = builtins.readFile (rootPath + "/home/.config/nushell/config.nu");
};
starship = { starship = {
enable = true; enable = true;
settings = { settings = {
@ -80,7 +86,50 @@ in {
}; };
}; };
dconf.settings = { xdg.desktopEntries = lib.mkIf config.kp2pml30.xserver {
yazi = {
name = "Yazi";
comment = "Terminal file manager";
exec = "kitty -- yazi %u";
terminal = false;
mimeType = [ "inode/directory" ];
categories = [ "System" "FileManager" ];
};
nvim = {
name = "Neovim";
comment = "Terminal text editor";
exec = "kitty -- nvim %F";
terminal = false;
mimeType = [ "text/plain" ];
categories = [ "Utility" "TextEditor" ];
};
};
xdg.mimeApps = lib.mkIf config.kp2pml30.xserver (let
mimeMap = desktop: types:
builtins.listToAttrs (map (t: { name = t; value = [ desktop ]; }) types);
in {
enable = true;
defaultApplications =
{ "inode/directory" = [ "yazi.desktop" ]; }
// mimeMap "nvim.desktop" [
"text/plain" "text/html" "text/css" "text/xml" "text/markdown"
"text/x-csrc" "text/x-chdr" "text/x-c++src" "text/x-c++hdr"
"text/x-python" "text/x-shellscript" "text/x-makefile"
"application/json" "application/xml" "application/x-yaml"
"application/toml" "application/javascript" "application/x-shellscript"
"application/x-nix"
]
// mimeMap "feh.desktop" [
"image/png" "image/jpeg" "image/gif" "image/webp" "image/bmp" "image/svg+xml"
]
// mimeMap "vlc.desktop" [
"video/mp4" "video/x-matroska" "video/webm" "video/x-msvideo"
"video/quicktime" "video/x-flv"
];
});
dconf.settings = lib.mkIf config.kp2pml30.xserver {
"org/gnome/desktop/interface" = { "org/gnome/desktop/interface" = {
color-scheme = "prefer-dark"; color-scheme = "prefer-dark";
}; };

View file

@ -8,6 +8,7 @@ let
cfg = config.kp2pml30; cfg = config.kp2pml30;
in { in {
config = { config = {
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
programs = { programs = {
tmux.enable = true; tmux.enable = true;
yazi.enable = true; yazi.enable = true;
@ -18,6 +19,8 @@ in {
ncdu ncdu
timewarrior timewarrior
p7zip p7zip
claude-code
lazydocker
]; ];
}; };

21
nix/qemu.nix Normal file
View file

@ -0,0 +1,21 @@
{ config
, pkgs
, lib
, ...
}:
let
cfg = config.kp2pml30;
in {
options.kp2pml30.qemu = lib.mkEnableOption "";
config = lib.mkIf cfg.qemu {
environment.systemPackages = with pkgs; [
qemu
OVMF
];
virtualisation.libvirtd.enable = true;
users.users.${cfg.username}.extraGroups = [ "libvirtd" ];
};
}

View file

@ -124,6 +124,16 @@ in lib.mkIf cfg.nginx {
root = cfg.sitePath; root = cfg.sitePath;
tryFiles = "$uri $uri/ /index.html"; tryFiles = "$uri $uri/ /index.html";
}; };
locations."/fs/" = {
root = cfg.sitePath;
tryFiles = "$uri $uri/ /fs/index.html";
};
locations."/view/" = {
root = cfg.sitePath;
tryFiles = "$uri $uri/ /view/index.html";
};
}; };
} // (if cfg.xray then { } // (if cfg.xray then {
# Xray fallback proxy servers # Xray fallback proxy servers

View file

@ -23,7 +23,7 @@ let
fi fi
# Decrypt and parse XRAY_UIDS # Decrypt and parse XRAY_UIDS
${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./secrets.yaml}" | ${pkgs.yq}/bin/yq '.XRAY_UIDS[]' -r ${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./secrets.yaml}" | ${pkgs.yq}/bin/yq '.XRAY_UIDS[].uid' -r
''; '';
xray-config-base = builtins.toFile "xray.json" (builtins.toJSON ( xray-config-base = builtins.toFile "xray.json" (builtins.toJSON (

View file

@ -1,4 +1,6 @@
U2FsdGVkX18N4BW9sin9kPVNkpbtVNoDqBAm+080vcYSS7qySHVOCfe94a7S8mh4 U2FsdGVkX18Z/nFLuSfx9e8XYdUPqLO0NOAdKcPf+WkKg7exhD+p6p+pDzaHhdHP
G5tbvoRrOFxJ+RW/WYNMsEZ7wgsJM8b9AiKPaT30BMHXriTdtai80i6xKqv9zdCb 0JzWp5p8yz/sehmSoqrXJtS7G9Y5f9gj2dLwfxLobzx4TTR/s8Hz2qVyNKu+D8hP
moGUlBSgMtqEhvAnvpYBxHQ+NtDhxw7K9UjaO7eodNp+l9PR6z+IeL29rC2DMxQc vBkNQaMJQNjPgJHsmKDnqT0zFGr0nz5GfchMbxepherBdysuwZKk7j7X0TKcgA0R
jXAjbfPa3aeSikXF0g118HbUwVJQwlXq99n/fjkJ8XOhBo/S4tWbt0U8O97VKlA6 c4v+QWYZH669dWij2Oq9P6IFE/aM420cmSXh2Ilr/MMirk/rZ3dr3Kx0JdVHaeFT
VAHU243eV0++OpvL9td7r8L9BWBS2p/5nowN5mVcUmBBBF7FrYeDaYjkoi3IXLTb
1EfrTOpIQfgm7qOqsfy1lClfrHaKPadqyIYxkuY+i/k=

View file

@ -13,7 +13,7 @@ in lib.mkIf cfg.xray {
}; };
# Ensure xray can read the certificates # Ensure xray can read the certificates
users.users.xray.extraGroups = [ "nginx" ]; users.users.xray.extraGroups = [ "certreaders" ];
# Ensure the xray service starts after ACME certificates are available # Ensure the xray service starts after ACME certificates are available
systemd.services.xray.after = [ "acme-${cfg.hostname}.service" ]; systemd.services.xray.after = [ "acme-${cfg.hostname}.service" ];

70
nix/xray.nix Normal file
View file

@ -0,0 +1,70 @@
{ config
, pkgs
, lib
, ...
}:
let
cfg = config.kp2pml30;
xray-config-base = builtins.toFile "xray-client.json" (builtins.toJSON
(builtins.fromJSON (builtins.readFile ./server/xray-client.json))
);
decryptSecrets = pkgs.writeShellScript "decrypt-secrets" ''
set -euo pipefail
source /var/lib/secrets/.env
if [ -z "''${KP2_DOTFILES_SECRET_KEY:-}" ]; then
echo "Error: KP2_DOTFILES_SECRET_KEY environment variable not set" >&2
exit 1
fi
${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./server/secrets.yaml}" | ${pkgs.yq}/bin/yq --arg id "${cfg.xray-client-id}" '.XRAY_UIDS[] | select(.id == $id) | .uid' -r
'';
generateXrayConfig = pkgs.writeShellScript "generate-xray-client-config" ''
set -euo pipefail
UUID=$(${decryptSecrets})
cat "${xray-config-base}" | \
${pkgs.jq}/bin/jq --arg uuid "$UUID" '.outbounds[0].settings.vnext[0].users[0].id = $uuid'
'';
in {
options.kp2pml30.xray-client = lib.mkEnableOption "";
options.kp2pml30.xray-client-id = lib.mkOption {
type = lib.types.str;
description = "ID to select the correct UUID from secrets";
};
config = lib.mkIf cfg.xray-client {
services.xray = {
enable = true;
settingsFile = "/run/secrets/xray-client-config.json";
};
systemd.services.xray-client-secrets = {
description = "Generate Xray client configuration";
wantedBy = [ "xray.service" ];
before = [ "xray.service" ];
serviceConfig = {
Type = "oneshot";
User = "root";
EnvironmentFile = "/var/lib/secrets/.env";
};
script = ''
mkdir -p /run/secrets
${generateXrayConfig} > /run/secrets/xray-client-config.json
chmod 444 /run/secrets/xray-client-config.json
'';
};
systemd.tmpfiles.rules = [
"d /var/lib/secrets 0750 root root -"
"d /run/secrets 0755 root root -"
];
};
}

84
scripts/run-claude-vm.sh Executable file
View file

@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -exuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FLAKE_DIR="$(dirname "$SCRIPT_DIR")"
VM_DIR="$FLAKE_DIR/.claude-vm"
DISK="$VM_DIR/disk.qcow2"
DISK_SIZE="20G"
RAM="12G"
CPUS="8"
SSH_PORT="2222"
mkdir -p "$VM_DIR"
qemu_base_args=(
-machine q35
-cpu host
-enable-kvm
-m "$RAM"
-smp "$CPUS"
-drive "file=$DISK,format=qcow2,if=virtio"
-device virtio-net-pci,netdev=net0
-netdev "user,id=net0,hostfwd=tcp::${SSH_PORT}-:22"
-nographic
-fsdev local,id=fsdev0,path=$VM_DIR/share,security_model=passthrough -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=hostshare
)
do_install() {
echo "=== Building installer ISO... ==="
ISO_PATH=$(nix build "${FLAKE_DIR}#nixosConfigurations.claude-vm-installer.config.system.build.isoImage" --no-link --print-out-paths)
ISO_FILE=$(find "$ISO_PATH/iso" -name '*.iso' | head -1)
if [ -z "$ISO_FILE" ]; then
echo "Error: ISO not found after build"
exit 1
fi
echo "ISO: $ISO_FILE"
# Create fresh disk
rm -f "$DISK"
qemu-img create -f qcow2 "$DISK" "$DISK_SIZE"
echo "=== Booting installer (fully automatic)... ==="
qemu-system-x86_64 \
"${qemu_base_args[@]}" \
-cdrom "$ISO_FILE" \
-boot d
echo "=== Installation finished. Run without --install to boot the VM. ==="
}
do_run() {
if [ ! -f "$DISK" ]; then
echo "No disk image found. Run with --install first."
exit 1
fi
echo "=== Booting claude-vm (SSH: localhost:${SSH_PORT}) ==="
qemu-system-x86_64 \
"${qemu_base_args[@]}"
}
case "${1:-}" in
--install)
do_install
;;
--run)
do_run
;;
"")
if [ ! -f "$DISK" ]; then
do_install
fi
do_run
;;
*)
echo "Usage: $0 [--install|--run]"
echo " --install Build ISO and install to disk"
echo " --run Boot installed disk"
echo " (none) Install if needed, then run"
exit 1
;;
esac