Compare commits
333 Commits
fix-kodi-w
...
bead/nixos
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e5b11e55d | |||
| 1ba1a8fc9d | |||
| 009b84656f | |||
| ef4e4509d3 | |||
| cd6b528692 | |||
| 3914b54c73 | |||
| 9aa74258f9 | |||
| 64dda20aa4 | |||
| ac01548e89 | |||
| bb7f79843b | |||
| c1d6663a36 | |||
| 3cf4403ffa | |||
| 4e6123de9a | |||
| 19ee298b71 | |||
| 537f7831a7 | |||
| bf0d16fe1a | |||
| 858b6009ae | |||
| 40b323dcfd | |||
| 60bd89b02c | |||
| 5a5de7353b | |||
| e25aa7acab | |||
| 4a284de8a1 | |||
| 7be694ef66 | |||
| 0ccfc30c73 | |||
| dab96a1c50 | |||
| 7898def044 | |||
| 4ce48313f6 | |||
| 2c70504c43 | |||
| a22c7fec28 | |||
| ef3e9b8c82 | |||
| 0590dad71e | |||
| c81594af01 | |||
| 6f999882d3 | |||
| 8bb20bf05e | |||
| c480bcdd1d | |||
| 05fed3ede1 | |||
| 0a9de8d159 | |||
| 055d6ab421 | |||
| d5c6342b84 | |||
| e04dacdf65 | |||
| 7d74917bdc | |||
| 5a4ab71849 | |||
| bcebf9b376 | |||
| 0f76939983 | |||
| a1da2f5cc1 | |||
| 175da48170 | |||
| ac956ef48c | |||
| 0c1190f39c | |||
| 00f05d1bb2 | |||
| 4e6c6ab81d | |||
| 04e1a8563c | |||
| 7278dc8306 | |||
| 066eea2999 | |||
| 80633142fb | |||
| 3029e3d9a8 | |||
| 3483e26bce | |||
| b3add6ddf8 | |||
| 89994e3fc8 | |||
| 0e9671a45f | |||
| f4078970b2 | |||
| 0ae4d84ca2 | |||
| 7c877fde84 | |||
| d53286e04c | |||
| bc42c4dc77 | |||
| 445b0cd558 | |||
| 6d9686f14b | |||
| 4164832eea | |||
| 585f9ef5c7 | |||
| ade60ba5ec | |||
| 48fb7cdada | |||
| 2d8cfe75a0 | |||
| 385fd798de | |||
| fe6558e0c1 | |||
| b9c48f9dd1 | |||
| 34351403d1 | |||
| 12820ce9ff | |||
| 0f5eb2e572 | |||
| f356c91fdb | |||
| 6b42612135 | |||
| 50a8c44d10 | |||
| 7011fb27a5 | |||
| 1ff8b81f44 | |||
| 55f13dfb08 | |||
| 63bf19b85f | |||
| 1f9e9138ab | |||
| e218822566 | |||
| e88f3580e9 | |||
| 5451e75480 | |||
| fc9474a7c9 | |||
| 20daebbd61 | |||
| 3be23304c4 | |||
| 9059a739a0 | |||
| 977125645b | |||
| a9772259f0 | |||
| 4f6d65316a | |||
| 0b8e3bf527 | |||
| d3c906134b | |||
| 30b616dd93 | |||
| c9252c42c2 | |||
| fa7cb55c78 | |||
| 2283b0a6df | |||
| 4ea9437bb0 | |||
| d0760a22bd | |||
| f67a12c29a | |||
| fc8a43504d | |||
| 4a73b3a5ae | |||
| be68202523 | |||
| 608fed35ab | |||
| c2e2dd8675 | |||
| 5750f737f1 | |||
| c27518e0dc | |||
| 7f318edc4d | |||
| f995240153 | |||
| d62bae0ddb | |||
| 79ae42f41d | |||
| 0c15aad5c0 | |||
| d87793d39b | |||
| fad6e61aac | |||
| 1bc65ceb51 | |||
| bda76c6abc | |||
| c42e09e972 | |||
| 4d986c0b48 | |||
| 4e3fdd78d2 | |||
| d3703fc5a9 | |||
| 35c2ebb592 | |||
| 569ac528a5 | |||
| 6cc8fa4f5d | |||
| 67a82f14fd | |||
| 4b68e3f051 | |||
| 81a3657759 | |||
| 32e1b81034 | |||
| 6f00c72540 | |||
| d26007aa61 | |||
| 1caa8bba3e | |||
| d3cb09040a | |||
| 4bfacffa17 | |||
| a6961f05ca | |||
| b75c43257b | |||
| 63d741e55e | |||
| 9ed3ad8fb8 | |||
| 330cd6f92b | |||
| 3b9d9ed60b | |||
| 2a017f584b | |||
| 47c4e0097e | |||
| 2b7cf66e69 | |||
| eed88a9ac0 | |||
| c02b74cce4 | |||
| 1132dda8a0 | |||
| 2696262ed3 | |||
| 40ac30c78f | |||
| ac986e37e7 | |||
| d3664fcf9d | |||
| 5591087be1 | |||
| 09a701989c | |||
| 62dbf84b4b | |||
| 81799cd6d2 | |||
| 35d965e432 | |||
| 2c4e6cc060 | |||
| 5c6dba77f0 | |||
| a6effa3944 | |||
| 0d53b86fcb | |||
| 6bf5c502d8 | |||
| 05592a9ec2 | |||
| 923aaf9e95 | |||
| 23b1c450a2 | |||
| a65a8e9af7 | |||
| 56b1111f54 | |||
| 6bf0a37533 | |||
| 396c8e0318 | |||
| b359acfcf0 | |||
| 455181365a | |||
| 06dd292524 | |||
| 8924fdbc6d | |||
| 671dc229de | |||
| 14cdee1468 | |||
| c6276c9758 | |||
| 31880e21e8 | |||
| 3d95995ebc | |||
| fb9dd66cf4 | |||
| a90b30eb1c | |||
| b22a4952e5 | |||
| 32f70d46b2 | |||
| d76e9e73f5 | |||
| 53504ffde3 | |||
| e5be1b5675 | |||
| 878962ad41 | |||
| 6d5eadcf6a | |||
| c323d1301b | |||
| 6cdbd2e300 | |||
| f0bf2f2d8c | |||
| 9d6abce8cc | |||
| 68f63db930 | |||
| 2e39984d14 | |||
| 9fed36e6ee | |||
| 38a8997448 | |||
| a3c8995422 | |||
| b9bb5d387f | |||
| e3aff80a97 | |||
| 574c8e6482 | |||
| 0f59a558cd | |||
| 14b7de30f6 | |||
| 8b676203e7 | |||
| beeb7acefd | |||
| a512d9bc06 | |||
| cc3d398963 | |||
| f757ea7271 | |||
| 64149713d2 | |||
| 88b413e0af | |||
| c5070eb4bf | |||
| 6b4dc1e6b7 | |||
| aadd8c7b6c | |||
| f8d145b495 | |||
| 9232d46f6a | |||
| b2b34fc05f | |||
| aa4dacb3af | |||
| 6dc4d6956a | |||
| be83fc566f | |||
| 485df44aea | |||
| 4861128de6 | |||
| 9fe7cfbbfc | |||
| 741e3a67d6 | |||
| 22254eb1f3 | |||
| 79dde1a0fe | |||
| f4b3c36a4e | |||
| 1fa7a2689c | |||
| c08c5e2486 | |||
| ecaa6dcb83 | |||
| 7729ff7434 | |||
| 52c110a505 | |||
| d5997575df | |||
| 57bc35101e | |||
| 6b09b1b0bc | |||
| 1851743a21 | |||
| c6d787f9f5 | |||
| f4a8f9d614 | |||
| 1e01d44f2f | |||
| 39dbe6644c | |||
| 870e1073dc | |||
| c1f132026a | |||
| 5650125d7e | |||
| 6536213bd0 | |||
| a0ce3b810e | |||
| abbcfebc97 | |||
| 495aba3fef | |||
| f9bcec74d3 | |||
| 97c4d7035c | |||
| 8abd331619 | |||
| aca0afa0dc | |||
| 1d0b3a0367 | |||
| 50f9defdd5 | |||
| d71d7a1ffb | |||
| ee511f6ab8 | |||
| e3dd0bdb30 | |||
| 10300ed10b | |||
| 8e72ef71d2 | |||
| d6e031efd0 | |||
| 16fa4a641c | |||
| 7a5ec23cc5 | |||
| ff1124fbe6 | |||
| 53088f9536 | |||
| 68c04b43fd | |||
| efbfffbb61 | |||
| 0e1a67b980 | |||
| 7d6e294340 | |||
| 8690a0289d | |||
| e95f56e240 | |||
| 2dffbb0a98 | |||
| 2ceaf78825 | |||
| e164097f36 | |||
| d1605e386d | |||
| 4a41533ba8 | |||
| 9d45449fce | |||
| 877bc2c739 | |||
| cd6e028142 | |||
| 421b27f76f | |||
| 1f4a72d28c | |||
| a8f19af989 | |||
| d4b0fe5b9e | |||
| 09cff42222 | |||
| 0183e7c823 | |||
| 29cdd1e239 | |||
| 7ced8f11ba | |||
| 244b7c0888 | |||
| 80744bcbf1 | |||
| 56d03f4228 | |||
| 32d0c7fa5a | |||
| 1c2aae93b7 | |||
| 0ab6562694 | |||
| 986ee06a46 | |||
| 34abaeeec9 | |||
| 11638cfa1b | |||
| 1ce431b0e5 | |||
| 98ef9b1443 | |||
| 4c779663df | |||
| e2bb87fcf1 | |||
| ef47c5dc9a | |||
| 7da089daa3 | |||
| 8134d7cb33 | |||
| 24f1a64f3c | |||
| 19531074ca | |||
| a30c130f21 | |||
| e088ee2dc8 | |||
| 366a7e2ea3 | |||
| 9116e44dfe | |||
| e3ef710bdb | |||
| e1a804cfed | |||
| ec59936012 | |||
| 844d17a855 | |||
| b19dc65c6d | |||
| 6db2c78e0b | |||
| 475aafa33e | |||
| 09562f0af9 | |||
| ae543d9628 | |||
| c7716d2bca | |||
| 54cf339d52 | |||
| b9097e91d5 | |||
| abf8fe9ad2 | |||
| 926b47f07f | |||
| 749ef988f1 | |||
| dfa91d327f | |||
| 37c455d75e | |||
| c0d7d934f3 | |||
| cb91f69c49 | |||
| bc6378cb22 | |||
| a13676311a | |||
| ec57592715 | |||
| 051c223eb7 | |||
| 6030f6ea42 | |||
| df77fd5c74 | |||
| 458bcb4cdf | |||
| 40e10bab34 | |||
| 3477a3480f | |||
| d2ae7f8e11 |
39
.beads/.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# SQLite databases
|
||||
*.db
|
||||
*.db?*
|
||||
*.db-journal
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
|
||||
# Daemon runtime files
|
||||
daemon.lock
|
||||
daemon.log
|
||||
daemon.pid
|
||||
bd.sock
|
||||
sync-state.json
|
||||
last-touched
|
||||
|
||||
# Local version tracking (prevents upgrade notification spam after git ops)
|
||||
.local_version
|
||||
|
||||
# Legacy database files
|
||||
db.sqlite
|
||||
bd.db
|
||||
|
||||
# Worktree redirect file (contains relative path to main repo's .beads/)
|
||||
# Must not be committed as paths would be wrong in other clones
|
||||
redirect
|
||||
|
||||
# Merge artifacts (temporary files from 3-way merge)
|
||||
beads.base.jsonl
|
||||
beads.base.meta.json
|
||||
beads.left.jsonl
|
||||
beads.left.meta.json
|
||||
beads.right.jsonl
|
||||
beads.right.meta.json
|
||||
|
||||
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
|
||||
# They would override fork protection in .git/info/exclude, allowing
|
||||
# contributors to accidentally commit upstream issue databases.
|
||||
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
|
||||
# are tracked by git by default since no pattern above ignores them.
|
||||
0
.beads/.sync.lock
Normal file
81
.beads/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Beads - AI-Native Issue Tracking
|
||||
|
||||
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
||||
|
||||
## What is Beads?
|
||||
|
||||
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
||||
|
||||
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Essential Commands
|
||||
|
||||
```bash
|
||||
# Create new issues
|
||||
bd create "Add user authentication"
|
||||
|
||||
# View all issues
|
||||
bd list
|
||||
|
||||
# View issue details
|
||||
bd show <issue-id>
|
||||
|
||||
# Update issue status
|
||||
bd update <issue-id> --status in_progress
|
||||
bd update <issue-id> --status done
|
||||
|
||||
# Sync with git remote
|
||||
bd sync
|
||||
```
|
||||
|
||||
### Working with Issues
|
||||
|
||||
Issues in Beads are:
|
||||
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
|
||||
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
||||
- **Branch-aware**: Issues can follow your branch workflow
|
||||
- **Always in sync**: Auto-syncs with your commits
|
||||
|
||||
## Why Beads?
|
||||
|
||||
✨ **AI-Native Design**
|
||||
- Built specifically for AI-assisted development workflows
|
||||
- CLI-first interface works seamlessly with AI coding agents
|
||||
- No context switching to web UIs
|
||||
|
||||
🚀 **Developer Focused**
|
||||
- Issues live in your repo, right next to your code
|
||||
- Works offline, syncs when you push
|
||||
- Fast, lightweight, and stays out of your way
|
||||
|
||||
🔧 **Git Integration**
|
||||
- Automatic sync with git commits
|
||||
- Branch-aware issue tracking
|
||||
- Intelligent JSONL merge resolution
|
||||
|
||||
## Get Started with Beads
|
||||
|
||||
Try Beads in your own projects:
|
||||
|
||||
```bash
|
||||
# Install Beads
|
||||
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
||||
|
||||
# Initialize in your repo
|
||||
bd init
|
||||
|
||||
# Create your first issue
|
||||
bd create "Try out Beads"
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
||||
- **Quick Start Guide**: Run `bd quickstart`
|
||||
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
||||
|
||||
---
|
||||
|
||||
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
||||
62
.beads/config.yaml
Normal file
@@ -0,0 +1,62 @@
|
||||
# Beads Configuration File
|
||||
# This file configures default behavior for all bd commands in this repository
|
||||
# All settings can also be set via environment variables (BD_* prefix)
|
||||
# or overridden with command-line flags
|
||||
|
||||
# Issue prefix for this repository (used by bd init)
|
||||
# If not set, bd init will auto-detect from directory name
|
||||
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
|
||||
# issue-prefix: ""
|
||||
|
||||
# Use no-db mode: load from JSONL, no SQLite, write back after each command
|
||||
# When true, bd will use .beads/issues.jsonl as the source of truth
|
||||
# instead of SQLite database
|
||||
# no-db: false
|
||||
|
||||
# Disable daemon for RPC communication (forces direct database access)
|
||||
# no-daemon: false
|
||||
|
||||
# Disable auto-flush of database to JSONL after mutations
|
||||
# no-auto-flush: false
|
||||
|
||||
# Disable auto-import from JSONL when it's newer than database
|
||||
# no-auto-import: false
|
||||
|
||||
# Enable JSON output by default
|
||||
# json: false
|
||||
|
||||
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
|
||||
# actor: ""
|
||||
|
||||
# Path to database (overridden by BEADS_DB or --db)
|
||||
# db: ""
|
||||
|
||||
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
|
||||
# auto-start-daemon: true
|
||||
|
||||
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
|
||||
# flush-debounce: "5s"
|
||||
|
||||
# Git branch for beads commits (bd sync will commit to this branch)
|
||||
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
|
||||
# This setting persists across clones (unlike database config which is gitignored).
|
||||
# Can also use BEADS_SYNC_BRANCH env var for local override.
|
||||
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
|
||||
sync-branch: "beads-sync"
|
||||
|
||||
# Multi-repo configuration (experimental - bd-307)
|
||||
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
|
||||
# repos:
|
||||
# primary: "." # Primary repo (where this database lives)
|
||||
# additional: # Additional repos to hydrate from (read-only)
|
||||
# - ~/beads-planning # Personal planning repo
|
||||
# - ~/work-planning # Work planning repo
|
||||
|
||||
# Integration settings (access with 'bd config get/set')
|
||||
# These are stored in the database, not in this file:
|
||||
# - jira.url
|
||||
# - jira.project
|
||||
# - linear.url
|
||||
# - linear.api-key
|
||||
# - github.org
|
||||
# - github.repo
|
||||
0
.beads/interactions.jsonl
Normal file
4
.beads/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"database": "beads.db",
|
||||
"jsonl_export": "sync_base.jsonl"
|
||||
}
|
||||
0
.beads/sync_base.jsonl
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
# Use bd merge for beads JSONL files
|
||||
.beads/issues.jsonl merge=beads
|
||||
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
result
|
||||
thoughts
|
||||
|
||||
21
.goosehints
Normal file
@@ -0,0 +1,21 @@
|
||||
NixOS Configurations Repository
|
||||
================================
|
||||
|
||||
Overview:
|
||||
---------
|
||||
This repository hosts modular and reproducible NixOS configurations managed via Nix flakes. It is structured to separate concerns across machine-specific setups, common roles, and custom packages.
|
||||
|
||||
Directory Structure:
|
||||
----------------------
|
||||
• packages/ - Custom Nix packages leveraged across various configurations.
|
||||
• roles/ - Role-based configurations (e.g., kodi, bluetooth) each with its own module (default.nix) for inclusion in machine setups.
|
||||
• machines/ - Machine-specific configurations (e.g., nix-book, z790prors, boxy, wixos) including configuration.nix and hardware-configuration.nix tailored for each hardware.
|
||||
• home/ - Home-manager configurations for personal environments and application settings (e.g., home-nix-book.nix, home-z790prors.nix).
|
||||
|
||||
Design Principles:
|
||||
------------------
|
||||
• Modularity: Clear separation between roles, machines, and packages allows for flexible and reusable configurations.
|
||||
• Declarative & Reproducible: Using Nix flakes guarantees a fully declarative setup that can be effortlessly reproduced across systems.
|
||||
• Scalability: The structure is designed to accommodate adding new roles or machines with minimal disruption to existing configurations.
|
||||
|
||||
This file serves as a concise guide for navigating and understanding the repository from an advanced Nix perspective. Further documentation can be found within the respective directories or individual README files where applicable.
|
||||
11
.sops.yaml
@@ -1,11 +0,0 @@
|
||||
keys:
|
||||
- &admin_johno age1ls6a033d4p4u8h4rwazjwt8w4c4xg73wq0mdnm64jajxzcz4k9asvjnks3
|
||||
- &host_z790prors age12l5u7sw59u5pkwp83qm8t3ff7uv0ld2c9k3zh5j4ame9k2szcynqu7ftqe
|
||||
- &host_nixbook age1fa3zqavfmqk4ssa22yne9td90gyqv9q5a8y0s8jp3xak8q7p3yjqyn7rkg
|
||||
creation_rules:
|
||||
- path_regex: secrets/[^/]+\.(yaml|json|env|ini)$
|
||||
key_groups:
|
||||
- age:
|
||||
- *admin_johno
|
||||
- *host_z790prors
|
||||
- *host_nixbook
|
||||
229
AGENTS.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Repository Overview
|
||||
|
||||
This is a NixOS configuration repository using flakes, managing multiple machines and home-manager configurations. The repository follows a modular architecture with reusable "roles" that can be composed for different machines.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Flake Structure
|
||||
- **flake.nix**: Main entry point defining inputs (nixpkgs, home-manager, plasma-manager, etc.) and outputs for multiple NixOS configurations
|
||||
- **Machines**: `nix-book`, `boxy`, `wixos` (WSL configuration), `zix790prors`, `live-usb`, `johno-macbookpro` (Darwin/macOS)
|
||||
- **Home configurations**: Standalone home-manager configuration for user `johno`
|
||||
|
||||
### Directory Structure
|
||||
- `machines/`: Machine-specific configurations with hardware-configuration.nix
|
||||
- `roles/`: Modular system configurations (audio, bluetooth, desktop, users, etc.)
|
||||
- `home/`: Home Manager configurations and user-specific modules
|
||||
- `home/modules/`: User environment modules (emacs, i3+sway, plasma-manager, tmux)
|
||||
- `packages/`: Custom package definitions
|
||||
|
||||
### Role-Based Configuration System
|
||||
The repository uses a custom "roles" system where each role is a NixOS module with enable options:
|
||||
- `roles.desktop`: Desktop environment with sub-options for X11, Wayland, KDE, gaming, SDDM
|
||||
- `roles.audio`: Audio configuration
|
||||
- `roles.bluetooth`: Bluetooth support
|
||||
- `roles.users`: User account management
|
||||
- `roles.virtualisation`: Virtualization setup
|
||||
- `roles.kodi`: Kodi media center
|
||||
- `roles.nvidia`: NVIDIA GPU configuration
|
||||
- `roles.printing`: Printing support (CUPS)
|
||||
- `roles.spotifyd`: Spotify daemon
|
||||
- `roles.btrfs`: Btrfs filesystem configuration
|
||||
- `roles.nfs-mounts`: NFS mount configuration
|
||||
- `roles.darwin`: macOS-specific configurations
|
||||
|
||||
Example role usage in machine configuration:
|
||||
```nix
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
gaming = true;
|
||||
kde = true;
|
||||
wayland = true;
|
||||
};
|
||||
users.enable = true;
|
||||
};
|
||||
```
|
||||
|
||||
### Home-Manager Role System
|
||||
The repository also uses a modular home-manager role system for user-space configuration:
|
||||
|
||||
**Available Home Roles:**
|
||||
- `home.roles.base`: Core CLI tools, git, ssh, bash, rbw (enabled everywhere)
|
||||
- `home.roles.desktop`: GUI applications, Firefox, KDE services
|
||||
- `home.roles.office`: LibreOffice, OpenSCAD (heavy packages)
|
||||
- `home.roles.media`: VLC, Jellyfin, Moonlight (media consumption)
|
||||
- `home.roles.development`: Custom packages, kubectl, development tools
|
||||
- `home.roles.communication`: Element, Nextcloud Talk, Google cookie tools
|
||||
- `home.roles.sync`: Syncthing service and tray (for file synchronization)
|
||||
- `home.roles.kdeconnect`: KDE Connect for device integration
|
||||
- `home.roles.gaming`: Gaming applications (future expansion)
|
||||
|
||||
**Role-Based Home Configurations:**
|
||||
- `home-desktop.nix`: Full-featured desktop for development workstations
|
||||
- `home-media-center.nix`: Living room media consumption and gaming setup (boxy)
|
||||
- `home-laptop-compact.nix`: Essential tools only, excludes office/media for storage constraints (nix-book)
|
||||
- `home-live-usb.nix`: Minimal setup for live environments, no persistent services
|
||||
- `home-darwin-work.nix`: macOS work laptop configuration
|
||||
|
||||
**Machine-Specific Role Usage:**
|
||||
- **nix-book**: Compact laptop → excludes office/media roles due to SSD space constraints
|
||||
- **boxy**: Living room media center → optimized for media consumption, excludes sync/office (shared machine)
|
||||
- **zix790prors**: All-purpose workstation → full desktop experience with all roles enabled
|
||||
- **wixos**: WSL2 development → full desktop experience, inherits from zix790prors Windows host
|
||||
- **live-usb**: Temporary environment → only base + desktop roles, no persistent services
|
||||
- **johno-macbookpro**: macOS work laptop → Darwin-specific configuration with development tools
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Building and Switching Configurations
|
||||
|
||||
**NixOS (Linux):**
|
||||
```bash
|
||||
# Build and switch to a specific machine configuration
|
||||
sudo nixos-rebuild switch --flake .#<hostname>
|
||||
|
||||
# Build without switching
|
||||
nixos-rebuild build --flake .#<hostname>
|
||||
|
||||
# Build home-manager configuration only
|
||||
home-manager switch --flake .#johno
|
||||
```
|
||||
|
||||
**Darwin (macOS):**
|
||||
```bash
|
||||
# Build and switch to Darwin configuration
|
||||
darwin-rebuild switch --flake .#johno-macbookpro
|
||||
|
||||
# Build without switching
|
||||
darwin-rebuild build --flake .#johno-macbookpro
|
||||
```
|
||||
|
||||
### Available Machine Configurations
|
||||
- `nix-book`: Compact laptop with storage constraints, uses `home/home-laptop-compact.nix`
|
||||
- `boxy`: Shared living room media center/gaming desktop with AMD GPU, uses `home/home-media-center.nix`
|
||||
- `zix790prors`: Powerful all-purpose workstation (gaming, 3D modeling, development), dual-boots Windows 11 with shared btrfs /games partition, uses `home/home-desktop.nix`
|
||||
- `wixos`: WSL2 development environment running in Windows partition of zix790prors, uses `home/home-desktop.nix`
|
||||
- `live-usb`: Bootable ISO configuration, uses `home/home-live-usb.nix`
|
||||
- `johno-macbookpro`: macOS work laptop, uses `home/home-darwin-work.nix`
|
||||
|
||||
### Flake Operations
|
||||
```bash
|
||||
# Update flake inputs
|
||||
nix flake update
|
||||
|
||||
# Check flake
|
||||
nix flake check
|
||||
|
||||
# Show flake info
|
||||
nix flake show
|
||||
```
|
||||
|
||||
### Bootstrap New Machine
|
||||
Use the provided bootstrap script:
|
||||
```bash
|
||||
sudo ./bootstrap.sh <hostname>
|
||||
```
|
||||
This script pulls from the remote git repository and applies the configuration.
|
||||
|
||||
### Build Live USB ISO
|
||||
Use the provided script to build a bootable ISO:
|
||||
```bash
|
||||
./build-liveusb.sh
|
||||
```
|
||||
Creates an ISO suitable for Ventoy and other USB boot tools in `./result/iso/`.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Adding New Machines
|
||||
|
||||
**NixOS:**
|
||||
1. Create new directory in `machines/<hostname>/`
|
||||
2. Add `configuration.nix` with role assignments
|
||||
3. Include hardware-configuration.nix (generated by nixos-generate-config)
|
||||
4. Add nixosConfiguration to flake.nix outputs
|
||||
|
||||
**Darwin (macOS):**
|
||||
1. Create new directory in `machines/<hostname>/`
|
||||
2. Add `configuration.nix` with Darwin role assignments
|
||||
3. Add darwinConfiguration to flake.nix outputs
|
||||
|
||||
### Adding New Roles
|
||||
1. Create directory in `roles/<role-name>/`
|
||||
2. Create `default.nix` with module definition using mkEnableOption
|
||||
3. Add role import to `roles/default.nix`
|
||||
4. Configure role options in machine configurations
|
||||
|
||||
### Home Manager Modules
|
||||
- Located in `home/modules/`
|
||||
- Each module has its own `default.nix`
|
||||
- Imported in main home configuration files
|
||||
|
||||
## Key Configuration Details
|
||||
|
||||
- **Experimental features**: nix-command and flakes are enabled
|
||||
- **User**: Primary user is `johno` with trusted-user privileges
|
||||
- **Locale**: en_US.UTF-8, America/Los_Angeles timezone
|
||||
- **SSH**: OpenSSH enabled on all configurations
|
||||
- **Garbage collection**: Automatic, deletes older than 10 days
|
||||
- **Unfree packages**: Allowed globally
|
||||
|
||||
## Issue Tracking (Gitea)
|
||||
|
||||
**Tea CLI for Gitea:**
|
||||
```bash
|
||||
# Note: When using tea CLI, you must specify --repo johno/nixos-configs
|
||||
# The CLI doesn't automatically detect the repo from git remote
|
||||
|
||||
# List all issues (open by default)
|
||||
tea issues --repo johno/nixos-configs
|
||||
|
||||
# List closed issues
|
||||
tea issues --repo johno/nixos-configs --state closed
|
||||
|
||||
# View specific issue
|
||||
tea issue --repo johno/nixos-configs 2
|
||||
|
||||
# Create new issue
|
||||
tea issues create --repo johno/nixos-configs --title "Issue title" --body "Description"
|
||||
|
||||
# Add comment to issue
|
||||
tea comment --repo johno/nixos-configs 2 "Comment text"
|
||||
|
||||
# Close issue (note: 'issues' is plural, issue number comes last)
|
||||
tea issues close --repo johno/nixos-configs 2
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Sudo access**: Claude Code does not have sudo access. Ask the user to run elevated commands like `sudo nixos-rebuild switch`
|
||||
|
||||
## Landing the Plane (Session Completion)
|
||||
|
||||
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
||||
|
||||
**MANDATORY WORKFLOW:**
|
||||
|
||||
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
||||
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
||||
3. **Update issue status** - Close finished work, update in-progress items
|
||||
4. **PUSH TO REMOTE** - This is MANDATORY:
|
||||
```bash
|
||||
git pull --rebase
|
||||
bd sync
|
||||
git push
|
||||
git status # MUST show "up to date with origin"
|
||||
```
|
||||
5. **Clean up** - Clear stashes, prune remote branches
|
||||
6. **Verify** - All changes committed AND pushed
|
||||
7. **Hand off** - Provide context for next session
|
||||
|
||||
**CRITICAL RULES:**
|
||||
- Work is NOT complete until `git push` succeeds
|
||||
- NEVER stop before pushing - that leaves work stranded locally
|
||||
- NEVER say "ready to push when you are" - YOU must push
|
||||
- If push fails, resolve and retry until it succeeds
|
||||
11
bootstrap.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
# bootstrap.sh
|
||||
# Usage: sudo ./bootstrap.sh <hostname>
|
||||
set -euo pipefail
|
||||
|
||||
NEW_HOSTNAME="${1:?missing hostname}"
|
||||
FLAKE_URI="git+https://git.johnogle.info/johno/nixos-configs.git#${NEW_HOSTNAME}"
|
||||
|
||||
export NIX_CONFIG="experimental-features = nix-command flakes"
|
||||
nixos-rebuild switch --flake "$FLAKE_URI"
|
||||
|
||||
19
build-liveusb.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Build Live USB ISO from flake configuration
|
||||
# Creates an uncompressed ISO suitable for Ventoy and other USB boot tools
|
||||
|
||||
set -e
|
||||
|
||||
echo "Building Live USB ISO..."
|
||||
nix build .#nixosConfigurations.live-usb.config.system.build.isoImage --show-trace
|
||||
|
||||
if [ -f "./result/iso/"*.iso ]; then
|
||||
iso_file=$(ls ./result/iso/*.iso)
|
||||
echo "✅ Build complete!"
|
||||
echo "📁 ISO location: $iso_file"
|
||||
echo "💾 Ready for Ventoy or dd to USB"
|
||||
else
|
||||
echo "❌ Build failed - no ISO file found"
|
||||
exit 1
|
||||
fi
|
||||
303
flake.lock
generated
@@ -1,5 +1,80 @@
|
||||
{
|
||||
"nodes": {
|
||||
"beads": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unstable"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767911810,
|
||||
"narHash": "sha256-0L4ATr01UsmBC0rSW62VIMVVSUihAQu2+ZOoHk9BQnA=",
|
||||
"owner": "steveyegge",
|
||||
"repo": "beads",
|
||||
"rev": "28ff9fe9919a9665a0f00f5b3fcd084b43fb6cc3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "steveyegge",
|
||||
"repo": "beads",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1765121682,
|
||||
"narHash": "sha256-4VBOP18BFeiPkyhy9o4ssBNQEvfvv1kXkasAYd0+rrA=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"google-cookie-retrieval": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1761423376,
|
||||
"narHash": "sha256-pMy3cnUFfue4vz/y0jx71BfcPGxZf+hk/DtnzWvfU0c=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "a1f695665771841a988afc965526cbf99160cd77",
|
||||
"revCount": 11,
|
||||
"type": "git",
|
||||
"url": "https://git.johnogle.info/johno/google-cookie-retrieval.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.johnogle.info/johno/google-cookie-retrieval.git"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -7,26 +82,148 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1728041527,
|
||||
"narHash": "sha256-03liqiJtk9UP7YQHW4r8MduKCK242FQzud8iWvvlK+o=",
|
||||
"lastModified": 1767514898,
|
||||
"narHash": "sha256-ONYqnKrPzfKEEPChoJ9qPcfvBqW9ZgieDKD7UezWPg4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "509dbf8d45606b618e9ec3bbe4e936b7c5bc6c1e",
|
||||
"rev": "7a06e8a2f844e128d3b210a000a62716b6040b7f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "release-25.11",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager-unstable": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unstable"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767556355,
|
||||
"narHash": "sha256-RDTUBDQBi9D4eD9iJQWtUDN/13MDLX+KmE+TwwNUp2s=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "f894bc4ffde179d178d8deb374fcf9855d1a82b7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "master",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"jovian": {
|
||||
"inputs": {
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unstable"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1767082077,
|
||||
"narHash": "sha256-2tL1mRb9uFJThUNfuDm/ehrnPvImL/QDtCxfn71IEz4=",
|
||||
"owner": "Jovian-Experiments",
|
||||
"repo": "Jovian-NixOS",
|
||||
"rev": "efd4b22e6fdc6d7fb4e186ae333a4b74e03da440",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Jovian-Experiments",
|
||||
"repo": "Jovian-NixOS",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-darwin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1765066094,
|
||||
"narHash": "sha256-0YSU35gfRFJzx/lTGgOt6ubP8K6LeW0vaywzNNqxkl4=",
|
||||
"owner": "nix-darwin",
|
||||
"repo": "nix-darwin",
|
||||
"rev": "688427b1aab9afb478ca07989dc754fa543e03d5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-darwin",
|
||||
"ref": "nix-darwin-25.11",
|
||||
"repo": "nix-darwin",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"jovian",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1729697500,
|
||||
"narHash": "sha256-VFTWrbzDlZyFHHb1AlKRiD/qqCJIripXKiCSFS8fAOY=",
|
||||
"owner": "zhaofengli",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "e418aeb728b6aa5ca8c5c71974e7159c2df1d8cf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "zhaofengli",
|
||||
"ref": "matrix-name",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-wsl": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": "nixpkgs"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1765841014,
|
||||
"narHash": "sha256-55V0AJ36V5Egh4kMhWtDh117eE3GOjwq5LhwxDn9eHg=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NixOS-WSL",
|
||||
"rev": "be4af8042e7a61fa12fda58fe9a3b3babdefe17b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "main",
|
||||
"repo": "NixOS-WSL",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1727802920,
|
||||
"narHash": "sha256-HP89HZOT0ReIbI7IJZJQoJgxvB2Tn28V6XS3MNKnfLs=",
|
||||
"lastModified": 1765472234,
|
||||
"narHash": "sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2fbfb1d73d239d2402a8fe03963e37aab15abe8b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1767379071,
|
||||
"narHash": "sha256-EgE0pxsrW9jp9YFMkHL9JMXxcqi/OoumPJYwf+Okucw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "27e30d177e57d912d614c88c622dcfdb2e6e6515",
|
||||
"rev": "fb7944c166a3b630f177938e478f0378e64ce108",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -36,47 +233,95 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1725762081,
|
||||
"narHash": "sha256-vNv+aJUW5/YurRy1ocfvs4q/48yVESwlC/yHzjkZSP8=",
|
||||
"owner": "NixOS",
|
||||
"lastModified": 1767480499,
|
||||
"narHash": "sha256-8IQQUorUGiSmFaPnLSo2+T+rjHtiNWc+OAzeHck7N48=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "dc454045f5b5d814e5862a6d057e7bb5c29edc05",
|
||||
"rev": "30a3c519afcf3f99e2c6df3b359aec5692054d92",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.05",
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-25.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"plasma-manager": {
|
||||
"inputs": {
|
||||
"home-manager": [
|
||||
"home-manager"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1763909441,
|
||||
"narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "plasma-manager",
|
||||
"rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "plasma-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"plasma-manager-unstable": {
|
||||
"inputs": {
|
||||
"home-manager": [
|
||||
"home-manager-unstable"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unstable"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1763909441,
|
||||
"narHash": "sha256-56LwV51TX/FhgX+5LCG6akQ5KrOWuKgcJa+eUsRMxsc=",
|
||||
"owner": "nix-community",
|
||||
"repo": "plasma-manager",
|
||||
"rev": "b24ed4b272256dfc1cc2291f89a9821d5f9e14b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "plasma-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"beads": "beads",
|
||||
"google-cookie-retrieval": "google-cookie-retrieval",
|
||||
"home-manager": "home-manager",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"sops-nix": "sops-nix"
|
||||
"home-manager-unstable": "home-manager-unstable",
|
||||
"jovian": "jovian",
|
||||
"nix-darwin": "nix-darwin",
|
||||
"nixos-wsl": "nixos-wsl",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||
"plasma-manager": "plasma-manager",
|
||||
"plasma-manager-unstable": "plasma-manager-unstable"
|
||||
}
|
||||
},
|
||||
"sops-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1727423009,
|
||||
"narHash": "sha256-+4B/dQm2EnORIk0k2wV3aHGaE0WXTBjColXjj7qWh10=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "127a96f49ddc377be6ba76964411bab11ae27803",
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
|
||||
266
flake.nix
@@ -2,66 +2,282 @@
|
||||
description = "A very basic flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
|
||||
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
|
||||
|
||||
sops-nix = {
|
||||
url = "github:Mic92/sops-nix";
|
||||
nix-darwin = {
|
||||
url = "github:nix-darwin/nix-darwin/nix-darwin-25.11";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
url = "github:nix-community/home-manager/release-25.11";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
home-manager-unstable = {
|
||||
url = "github:nix-community/home-manager/master";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, ... } @ inputs: let
|
||||
baseModules = [
|
||||
plasma-manager = {
|
||||
url = "github:nix-community/plasma-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.home-manager.follows = "home-manager";
|
||||
};
|
||||
|
||||
plasma-manager-unstable = {
|
||||
url = "github:nix-community/plasma-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
inputs.home-manager.follows = "home-manager-unstable";
|
||||
};
|
||||
|
||||
google-cookie-retrieval = {
|
||||
url = "git+https://git.johnogle.info/johno/google-cookie-retrieval.git";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
jovian = {
|
||||
url = "github:Jovian-Experiments/Jovian-NixOS";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
};
|
||||
|
||||
beads = {
|
||||
url = "github:steveyegge/beads";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, nixpkgs-unstable, nixos-wsl, ... } @ inputs: let
|
||||
nixosModules = [
|
||||
./roles
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
] ++ [
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
unstable = import nixpkgs-unstable {
|
||||
system = prev.stdenv.hostPlatform.system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
custom = prev.callPackage ./packages {};
|
||||
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
|
||||
})
|
||||
];
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.sharedModules = [
|
||||
inputs.plasma-manager.homeModules.plasma-manager
|
||||
];
|
||||
home-manager.extraSpecialArgs = {
|
||||
globalInputs = inputs;
|
||||
};
|
||||
}
|
||||
];
|
||||
in {
|
||||
nixosConfigurations.z790prors-nix = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
specialArgs = { inherit inputs; };
|
||||
modules = baseModules ++ [
|
||||
./machines/z790prors/configuration.nix
|
||||
# Modules for unstable-based systems (like nix-deck)
|
||||
nixosModulesUnstable = [
|
||||
./roles
|
||||
] ++ [
|
||||
inputs.home-manager-unstable.nixosModules.home-manager
|
||||
inputs.jovian.nixosModules.jovian
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-z790prors.nix;
|
||||
home-manager.extraSpecialArgs.customPkgs =
|
||||
nixpkgs.legacyPackages."${system}".callPackage ./packages {};
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
unstable = import nixpkgs-unstable {
|
||||
system = prev.stdenv.hostPlatform.system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
custom = prev.callPackage ./packages {};
|
||||
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
|
||||
})
|
||||
];
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.sharedModules = [
|
||||
inputs.plasma-manager-unstable.homeModules.plasma-manager
|
||||
];
|
||||
home-manager.extraSpecialArgs = {
|
||||
globalInputs = inputs;
|
||||
};
|
||||
}
|
||||
];
|
||||
darwinModules = [
|
||||
./roles/darwin.nix
|
||||
] ++ [
|
||||
inputs.home-manager.darwinModules.home-manager
|
||||
{
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
unstable = import nixpkgs-unstable {
|
||||
system = prev.stdenv.hostPlatform.system;
|
||||
config.allowUnfree = true;
|
||||
overlays = [
|
||||
# Override claude-code in unstable to use our custom GCS-based build
|
||||
# (needed for corporate networks that block npm registry)
|
||||
(ufinal: uprev: {
|
||||
claude-code = prev.custom.claude-code or (prev.callPackage ./packages {}).claude-code;
|
||||
})
|
||||
];
|
||||
};
|
||||
custom = prev.callPackage ./packages {};
|
||||
# Compatibility: bitwarden renamed to bitwarden-desktop in unstable
|
||||
bitwarden-desktop = prev.bitwarden-desktop or prev.bitwarden;
|
||||
})
|
||||
];
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.extraSpecialArgs = {
|
||||
globalInputs = inputs;
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
in {
|
||||
nixosConfigurations.nix-book = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = baseModules ++ [
|
||||
modules = nixosModules ++ [
|
||||
./machines/nix-book/configuration.nix
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-nix-book.nix;
|
||||
home-manager.extraSpecialArgs.customPkgs =
|
||||
nixpkgs.legacyPackages."${system}".callPackage ./packages {};
|
||||
home-manager.users.johno = {
|
||||
imports = [ ./home/home-laptop-compact.nix ];
|
||||
# Machine-specific overrides
|
||||
home.roles.i3_sway.extraSwayConfig = {
|
||||
output.eDP-1.scale = "1.75";
|
||||
};
|
||||
};
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
nixosConfigurations.boxy = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = baseModules ++ [
|
||||
modules = nixosModules ++ [
|
||||
./machines/boxy/configuration.nix
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-default.nix;
|
||||
home-manager.extraSpecialArgs.customPkgs =
|
||||
nixpkgs.legacyPackages."${system}".callPackage ./packages {};
|
||||
home-manager.users.johno = import ./home/home-media-center.nix;
|
||||
home-manager.users.kodi = import ./home/home-kodi.nix;
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
nixosConfigurations.wixos = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = nixosModules ++ [
|
||||
nixos-wsl.nixosModules.default
|
||||
./machines/wixos/configuration.nix
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-desktop.nix;
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
nixosConfigurations.zix790prors = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = nixosModules ++ [
|
||||
./machines/zix790prors/configuration.nix
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-desktop.nix;
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Live USB ISO configuration
|
||||
nixosConfigurations.live-usb = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = nixosModules ++ [
|
||||
./machines/live-usb/configuration.nix
|
||||
{
|
||||
home-manager.users.nixos = import ./home/home-live-usb.nix;
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Steam Deck configuration (using unstable for better Jovian compatibility)
|
||||
nixosConfigurations.nix-deck = nixpkgs-unstable.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = nixosModulesUnstable ++ [
|
||||
./machines/nix-deck/configuration.nix
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-desktop.nix;
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# ZFS/NFS server configuration
|
||||
nixosConfigurations.john-endesktop = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
modules = nixosModules ++ [
|
||||
./machines/john-endesktop/configuration.nix
|
||||
# Minimal server - no home-manager needed
|
||||
];
|
||||
};
|
||||
|
||||
# Darwin/macOS configurations
|
||||
darwinConfigurations."blkfv4yf49kt7" = inputs.nix-darwin.lib.darwinSystem rec {
|
||||
system = "aarch64-darwin";
|
||||
modules = darwinModules ++ [
|
||||
./machines/johno-macbookpro/configuration.nix
|
||||
{
|
||||
home-manager.users.johno = import ./home/home-darwin-work.nix;
|
||||
home-manager.extraSpecialArgs = { inherit system; };
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Flake apps
|
||||
apps = nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" ] (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
commonDeps = [ pkgs.curl pkgs.jq pkgs.nix pkgs.git pkgs.gnused pkgs.gnugrep pkgs.coreutils pkgs.gawk ];
|
||||
|
||||
update-doomemacs = pkgs.writeShellScriptBin "update-doomemacs" ''
|
||||
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||
${builtins.readFile ./scripts/update-doomemacs.sh}
|
||||
'';
|
||||
|
||||
update-claude-code = pkgs.writeShellScriptBin "update-claude-code" ''
|
||||
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||
${builtins.readFile ./packages/claude-code/update.sh}
|
||||
'';
|
||||
|
||||
rotate-wallpaper = pkgs.writeShellScriptBin "rotate-wallpaper" ''
|
||||
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||
${builtins.readFile ./scripts/rotate-wallpaper.sh}
|
||||
'';
|
||||
|
||||
upgrade = pkgs.writeShellScriptBin "upgrade" ''
|
||||
export PATH="${pkgs.lib.makeBinPath commonDeps}:$PATH"
|
||||
${builtins.readFile ./scripts/upgrade.sh}
|
||||
'';
|
||||
in {
|
||||
update-doomemacs = {
|
||||
type = "app";
|
||||
program = "${update-doomemacs}/bin/update-doomemacs";
|
||||
};
|
||||
update-claude-code = {
|
||||
type = "app";
|
||||
program = "${update-claude-code}/bin/update-claude-code";
|
||||
};
|
||||
rotate-wallpaper = {
|
||||
type = "app";
|
||||
program = "${rotate-wallpaper}/bin/rotate-wallpaper";
|
||||
};
|
||||
upgrade = {
|
||||
type = "app";
|
||||
program = "${upgrade}/bin/upgrade";
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
123
home/home-darwin-work.nix
Normal file
@@ -0,0 +1,123 @@
|
||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for Darwin work laptop
|
||||
# Corporate-friendly setup with essential development tools
|
||||
|
||||
home.username = lib.mkForce "johno";
|
||||
home.homeDirectory = lib.mkForce "/Users/johno";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# System packages
|
||||
home.packages = with pkgs; [
|
||||
google-cloud-sdk
|
||||
];
|
||||
|
||||
# Note: ghostty installed via Homebrew (managed outside of nix)
|
||||
|
||||
# Override Darwin-incompatible settings from base role
|
||||
programs.rbw.settings.pinentry = lib.mkForce pkgs.pinentry_mac;
|
||||
|
||||
# Disable Home Manager from managing shell RC files
|
||||
# topsoil/compost will manage these files instead
|
||||
programs.bash.enable = lib.mkForce false;
|
||||
programs.zsh.enable = lib.mkForce false;
|
||||
|
||||
# Create a local nix integration file that topsoil-managed configs can source
|
||||
home.file.".nix-integration.sh" = {
|
||||
text = ''
|
||||
# Source Home Manager session variables (nix paths, environment, etc.)
|
||||
if [ -e /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh ]; then
|
||||
. /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh
|
||||
fi
|
||||
|
||||
# Setup bash completions from nix profiles
|
||||
if [[ ! -v BASH_COMPLETION_VERSINFO ]] && [ -n "$NIX_PROFILES" ]; then
|
||||
for profile in $NIX_PROFILES; do
|
||||
if [ -f "$profile/etc/profile.d/bash_completion.sh" ]; then
|
||||
. "$profile/etc/profile.d/bash_completion.sh"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# command-not-found handler
|
||||
command_not_found_handle() {
|
||||
local p=/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite
|
||||
if [ -n "$NIX_PROFILES" ]; then
|
||||
for profile in $NIX_PROFILES; do
|
||||
if [ -x "$profile/bin/command-not-found" ] && [ -f "$p" ]; then
|
||||
"$profile/bin/command-not-found" "$@"
|
||||
return $?
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo "$1: command not found" >&2
|
||||
return 127
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
home.file.".nix-integration.zsh" = {
|
||||
text = ''
|
||||
# Source Home Manager session variables (nix paths, environment, etc.)
|
||||
if [ -e /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh ]; then
|
||||
. /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh
|
||||
fi
|
||||
|
||||
# Setup zsh completions from nix profiles
|
||||
typeset -U path cdpath fpath manpath
|
||||
for profile in ''${(z)NIX_PROFILES}; do
|
||||
fpath+=($profile/share/zsh/site-functions $profile/share/zsh/$ZSH_VERSION/functions $profile/share/zsh/vendor-completions)
|
||||
done
|
||||
autoload -U compinit && compinit
|
||||
|
||||
# command-not-found handler
|
||||
command_not_found_handler() {
|
||||
local p=/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite
|
||||
if [ -n "$NIX_PROFILES" ]; then
|
||||
for profile in ''${(z)NIX_PROFILES}; do
|
||||
if [ -x "$profile/bin/command-not-found" ] && [ -f "$p" ]; then
|
||||
"$profile/bin/command-not-found" "$@"
|
||||
return $?
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo "$1: command not found" >&2
|
||||
return 127
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# Keep SSH and Git disabled to avoid conflicts with work environment
|
||||
programs.ssh.enable = lib.mkForce false;
|
||||
programs.git.enable = lib.mkForce false;
|
||||
programs.rbw.enable = lib.mkForce false;
|
||||
|
||||
home.shell.enableShellIntegration = true;
|
||||
|
||||
home.roles = {
|
||||
base.enable = true;
|
||||
development = {
|
||||
enable = true;
|
||||
allowArbitraryClaudeCodeModelSelection = true;
|
||||
};
|
||||
tmux.enable = true;
|
||||
emacs.enable = true;
|
||||
aerospace = {
|
||||
enable = true;
|
||||
leader = "cmd";
|
||||
ctrlShortcuts.enable = true;
|
||||
sketchybar.enable = true;
|
||||
# Optional: Add per-machine userSettings overrides
|
||||
# userSettings = {
|
||||
# mode.main.binding."${leader}-custom" = "custom-command";
|
||||
# };
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
./roles/base-darwin
|
||||
];
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
{ pkgs, customPkgs, ... }:
|
||||
|
||||
{
|
||||
# Home Manager needs a bit of information about you and the paths it should
|
||||
# manage.
|
||||
home.username = "johno";
|
||||
home.homeDirectory = "/home/johno";
|
||||
|
||||
# This value determines the Home Manager release that your configuration is
|
||||
# compatible with. This helps avoid breakage when a new Home Manager release
|
||||
# introduces backwards incompatible changes.
|
||||
#
|
||||
# You should not change this value, even if you update Home Manager. If you do
|
||||
# want to update the value, then make sure to first check the Home Manager
|
||||
# release notes.
|
||||
home.stateVersion = "24.05"; # Please read the comment before changing.
|
||||
|
||||
# The home.packages option allows you to install Nix packages into your
|
||||
# environment.
|
||||
home.packages = [
|
||||
# # Adds the 'hello' command to your environment. It prints a friendly
|
||||
# # "Hello, world!" when run.
|
||||
# pkgs.hello
|
||||
|
||||
# # It is sometimes useful to fine-tune packages, for example, by applying
|
||||
# # overrides. You can do that directly here, just don't forget the
|
||||
# # parentheses. Maybe you want to install Nerd Fonts with a limited number of
|
||||
# # fonts?
|
||||
# (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; })
|
||||
|
||||
# # You can also create simple shell scripts directly inside your
|
||||
# # configuration. For example, this adds a command 'my-hello' to your
|
||||
# # environment:
|
||||
# (pkgs.writeShellScriptBin "my-hello" ''
|
||||
# echo "Hello, ${config.home.username}!"
|
||||
# '')
|
||||
|
||||
pkgs.bitwarden
|
||||
pkgs.dunst
|
||||
pkgs.element-desktop
|
||||
pkgs.fd
|
||||
#pkgs.fluffychat # security vulnerability in current version
|
||||
pkgs.gzip
|
||||
pkgs.htop
|
||||
pkgs.jellyfin-media-player
|
||||
pkgs.keepassxc
|
||||
pkgs.killall
|
||||
pkgs.kitty
|
||||
pkgs.less
|
||||
pkgs.moonlight-qt
|
||||
pkgs.ncdu
|
||||
pkgs.pandoc
|
||||
pkgs.pinentry-qt
|
||||
#pkgs.pytest
|
||||
pkgs.shellcheck
|
||||
pkgs.solaar # Logitech management software
|
||||
pkgs.tmux
|
||||
pkgs.waybar
|
||||
pkgs.wofi
|
||||
pkgs.vlc
|
||||
|
||||
customPkgs.nextcloudTalkDesktop
|
||||
];
|
||||
|
||||
# Home Manager is pretty good at managing dotfiles. The primary way to manage
|
||||
# plain files is through 'home.file'.
|
||||
home.file = {
|
||||
# # Building this configuration will create a copy of 'dotfiles/screenrc' in
|
||||
# # the Nix store. Activating the configuration will then make '~/.screenrc' a
|
||||
# # symlink to the Nix store copy.
|
||||
# ".screenrc".source = dotfiles/screenrc;
|
||||
|
||||
# # You can also set the file content immediately.
|
||||
# ".gradle/gradle.properties".text = ''
|
||||
# org.gradle.console=verbose
|
||||
# org.gradle.daemon.idletimeout=3600000
|
||||
# '';
|
||||
|
||||
};
|
||||
|
||||
# Home Manager can also manage your environment variables through
|
||||
# 'home.sessionVariables'. These will be explicitly sourced when using a
|
||||
# shell provided by Home Manager. If you don't want to manage your shell
|
||||
# through Home Manager then you have to manually source 'hm-session-vars.sh'
|
||||
# located at either
|
||||
#
|
||||
# ~/.nix-profile/etc/profile.d/hm-session-vars.sh
|
||||
#
|
||||
# or
|
||||
#
|
||||
# ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
|
||||
#
|
||||
# or
|
||||
#
|
||||
# /etc/profiles/per-user/johno/etc/profile.d/hm-session-vars.sh
|
||||
#
|
||||
home.sessionVariables = {
|
||||
};
|
||||
|
||||
home.sessionPath = [
|
||||
];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
imports = [
|
||||
./modules/emacs
|
||||
./modules/lutris
|
||||
./modules/i3+sway
|
||||
];
|
||||
|
||||
programs.bash.enable = true;
|
||||
|
||||
nix = {
|
||||
gc = {
|
||||
automatic = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Let Home Manager install and manage itself.
|
||||
programs.home-manager.enable = true;
|
||||
|
||||
programs.command-not-found.enable = true;
|
||||
|
||||
programs.firefox = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
programs.git = {
|
||||
enable = true;
|
||||
userName = "John Ogle";
|
||||
userEmail = "john@ogle.fyi";
|
||||
extraConfig = {
|
||||
safe.directory = "/etc/nixos";
|
||||
};
|
||||
};
|
||||
|
||||
programs.gpg.enable = true;
|
||||
|
||||
services.gpg-agent = {
|
||||
enable = true;
|
||||
enableSshSupport = true;
|
||||
defaultCacheTtl = 1800;
|
||||
pinentryPackage = pkgs.pinentry-qt;
|
||||
};
|
||||
|
||||
programs.jq.enable = true;
|
||||
|
||||
programs.k9s.enable = true;
|
||||
|
||||
programs.neovim = {
|
||||
enable = true;
|
||||
viAlias = true;
|
||||
vimAlias = true;
|
||||
};
|
||||
|
||||
programs.rbw = {
|
||||
enable = true;
|
||||
settings = {
|
||||
email = "john@johnogle.info";
|
||||
base_url = "https://bitwarden.johnogle.info";
|
||||
pinentry = pkgs.pinentry-qt;
|
||||
};
|
||||
};
|
||||
|
||||
programs.spotify-player.enable = true;
|
||||
|
||||
programs.ssh = {
|
||||
enable = true;
|
||||
addKeysToAgent = "yes";
|
||||
matchBlocks = {
|
||||
"nucdeb1" = {
|
||||
hostname = "nucdeb1.oglehome";
|
||||
user = "root";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.home-manager.autoUpgrade = {
|
||||
enable = true;
|
||||
frequency = "weekly";
|
||||
};
|
||||
|
||||
services.kdeconnect = {
|
||||
enable = true;
|
||||
indicator = true;
|
||||
package = pkgs.kdePackages.kdeconnect-kde;
|
||||
};
|
||||
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
tray = {
|
||||
enable = true;
|
||||
command = "syncthingtray --wait";
|
||||
};
|
||||
};
|
||||
|
||||
xdg.enable = true;
|
||||
}
|
||||
36
home/home-desktop.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{ pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for full desktop experience
|
||||
home.username = "johno";
|
||||
home.homeDirectory = "/home/johno";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# Enable all desktop roles for full-featured experience
|
||||
home.roles = {
|
||||
"3d-printing".enable = true;
|
||||
base.enable = true;
|
||||
desktop.enable = true;
|
||||
emacs.enable = true;
|
||||
email.enable = true;
|
||||
i3_sway.enable = true;
|
||||
office.enable = true;
|
||||
media.enable = true;
|
||||
development.enable = true;
|
||||
communication.enable = true;
|
||||
sync.enable = true;
|
||||
kdeconnect.enable = true;
|
||||
kubectl.enable = true;
|
||||
tmux.enable = true;
|
||||
plasma-manager.enable = true;
|
||||
};
|
||||
|
||||
targets.genericLinux.enable = true;
|
||||
home.sessionVariables = {};
|
||||
home.sessionPath = [];
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
./roles/base-linux
|
||||
];
|
||||
}
|
||||
28
home/home-kodi.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for kodi user on boxy
|
||||
# Focused on media center volume control via Home Assistant
|
||||
|
||||
home.username = "kodi";
|
||||
home.homeDirectory = "/home/kodi";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# Enable minimal roles for kodi user
|
||||
home.roles = {
|
||||
base.enable = true;
|
||||
plasma-manager-kodi.enable = true;
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
kdePackages.kconfig
|
||||
];
|
||||
|
||||
targets.genericLinux.enable = true;
|
||||
home.sessionVariables = {};
|
||||
home.sessionPath = [];
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
];
|
||||
}
|
||||
44
home/home-laptop-compact.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for compact laptop setups
|
||||
# Optimized for space-constrained environments
|
||||
|
||||
home.username = "johno";
|
||||
home.homeDirectory = "/home/johno";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# Enable essential roles only (exclude heavy office/media packages)
|
||||
home.roles = {
|
||||
base.enable = true;
|
||||
desktop.enable = true;
|
||||
development.enable = true;
|
||||
communication.enable = true;
|
||||
email.enable = true;
|
||||
kdeconnect.enable = true;
|
||||
media.enable = true;
|
||||
sync.enable = true;
|
||||
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;
|
||||
home.sessionVariables = {};
|
||||
home.sessionPath = [];
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
./roles/base-linux
|
||||
];
|
||||
}
|
||||
37
home/home-live-usb.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for live USB environments
|
||||
# Minimal setup without persistent services
|
||||
|
||||
home.username = "nixos";
|
||||
home.homeDirectory = "/home/nixos";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# Enable minimal roles only (no sync or kdeconnect for live environment)
|
||||
home.roles = {
|
||||
base.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
|
||||
# communication.enable = false; # Not needed for live USB
|
||||
# office.enable = false; # Not needed for live USB
|
||||
# media.enable = false; # Not needed for live USB
|
||||
# sync.enable = false; # No persistent sync on live USB
|
||||
# kdeconnect.enable = false; # No device integration on live USB
|
||||
};
|
||||
|
||||
targets.genericLinux.enable = true;
|
||||
home.sessionVariables = {};
|
||||
home.sessionPath = [];
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
./roles/base-linux
|
||||
];
|
||||
|
||||
# Live USB specific overrides can go here if needed
|
||||
}
|
||||
37
home/home-media-center.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{ pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for media center setups
|
||||
# Optimized for living room media consumption and gaming
|
||||
|
||||
home.username = "johno";
|
||||
home.homeDirectory = "/home/johno";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# Enable media center focused roles
|
||||
home.roles = {
|
||||
base.enable = true;
|
||||
desktop.enable = true;
|
||||
media.enable = true;
|
||||
communication.enable = true;
|
||||
kdeconnect.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
|
||||
# sync.enable = false; # Shared machine, no personal file sync
|
||||
};
|
||||
|
||||
targets.genericLinux.enable = true;
|
||||
home.sessionVariables = {};
|
||||
home.sessionPath = [];
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
./roles/base-linux
|
||||
];
|
||||
|
||||
# Media center specific overrides can go here if needed
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./home-default.nix
|
||||
./modules/hyprland/nix-book.nix
|
||||
];
|
||||
|
||||
home.i3_sway.extraSwayConfig = {
|
||||
output.eDP-1.scale = "1.75";
|
||||
};
|
||||
}
|
||||
24
home/home-server.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{ pkgs, globalInputs, system, ... }:
|
||||
|
||||
{
|
||||
# Home Manager configuration for servers (minimal with development tools)
|
||||
home.username = "johno";
|
||||
home.homeDirectory = "/home/johno";
|
||||
home.stateVersion = "24.05";
|
||||
|
||||
# Minimal roles for server with development capability
|
||||
home.roles = {
|
||||
base.enable = true;
|
||||
development.enable = true;
|
||||
tmux.enable = true;
|
||||
};
|
||||
|
||||
targets.genericLinux.enable = true;
|
||||
home.sessionVariables = {};
|
||||
home.sessionPath = [];
|
||||
|
||||
imports = [
|
||||
./roles
|
||||
./roles/base-linux
|
||||
];
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./home-default.nix
|
||||
./modules/hyprland/z790prors.nix
|
||||
];
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
doomSync = (let
|
||||
git = pkgs.git;
|
||||
in ''
|
||||
export PATH=${pkgs.emacs}/bin:${git}/bin:$PATH
|
||||
${config.xdg.configHome}/emacs/bin/doom sync -u -j $((`nproc`/4*3))
|
||||
'');
|
||||
in {
|
||||
config = {
|
||||
home.packages = [
|
||||
pkgs.emacs-all-the-icons-fonts
|
||||
pkgs.fontconfig
|
||||
pkgs.graphviz
|
||||
pkgs.isort
|
||||
pkgs.nerdfonts
|
||||
pkgs.nil # nix lsp language server
|
||||
pkgs.nixfmt-rfc-style
|
||||
(pkgs.ripgrep.override {withPCRE2 = true;})
|
||||
pkgs.pipenv
|
||||
pkgs.poetry
|
||||
pkgs.python3
|
||||
];
|
||||
|
||||
fonts.fontconfig.enable = true;
|
||||
|
||||
home.file = {
|
||||
".config/emacs" = {
|
||||
source = fetchGit {
|
||||
url = "https://github.com/doomemacs/doomemacs.git";
|
||||
# When updating me, remember to run `doom sync`
|
||||
rev = "5ad99220b86ae1bf421861dfad24492d768ac4d9";
|
||||
};
|
||||
# We need to use recursive mode here or else doom fails to sync for
|
||||
# some reason related to the permissions on the synced path. I'm not
|
||||
# quite sure of everything that's going on here.
|
||||
recursive = true;
|
||||
|
||||
# Because `recursive = true` will cause this to sync every single
|
||||
# activation, we turn this off here.
|
||||
#
|
||||
# There's probably a way we could do better detection of this within
|
||||
# our onChange shell?
|
||||
#
|
||||
# onChange = doomSync;
|
||||
};
|
||||
};
|
||||
|
||||
home.sessionVariables = {
|
||||
DOOMLOCALDIR = "${config.xdg.dataHome}/doom";
|
||||
EDITOR = "emacs -nw";
|
||||
};
|
||||
|
||||
home.sessionPath = [
|
||||
"${config.xdg.configHome}/emacs/bin"
|
||||
];
|
||||
|
||||
xdg.configFile."doom" = {
|
||||
source = ./doom;
|
||||
# Sync doom if we updated the config
|
||||
onChange = doomSync;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Place your private configuration here! Remember, you do not need to run 'doom
|
||||
;; sync' after modifying this file!
|
||||
|
||||
|
||||
;; Some functionality uses this to identify you, e.g. GPG configuration, email
|
||||
;; clients, file templates and snippets. It is optional.
|
||||
;; (setq user-full-name "John Doe"
|
||||
;; user-mail-address "john@doe.com")
|
||||
|
||||
;; Doom exposes five (optional) variables for controlling fonts in Doom:
|
||||
;;
|
||||
;; - `doom-font' -- the primary font to use
|
||||
;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable)
|
||||
;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for
|
||||
;; presentations or streaming.
|
||||
;; - `doom-symbol-font' -- for symbols
|
||||
;; - `doom-serif-font' -- for the `fixed-pitch-serif' face
|
||||
;;
|
||||
;; See 'C-h v doom-font' for documentation and more examples of what they
|
||||
;; accept. For example:
|
||||
;;
|
||||
;;(setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light)
|
||||
;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13))
|
||||
;;
|
||||
;; If you or Emacs can't find your font, use 'M-x describe-font' to look them
|
||||
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
|
||||
;; refresh your font settings. If Emacs still can't find your font, it likely
|
||||
;; wasn't installed correctly. Font issues are rarely Doom issues!
|
||||
|
||||
;; There are two ways to load a theme. Both assume the theme is installed and
|
||||
;; available. You can either set `doom-theme' or manually load a theme with the
|
||||
;; `load-theme' function. This is the default:
|
||||
(setq doom-theme 'doom-one)
|
||||
|
||||
;; This determines the style of line numbers in effect. If set to `nil', line
|
||||
;; numbers are disabled. For relative line numbers, set this to `relative'.
|
||||
(setq display-line-numbers-type t)
|
||||
|
||||
;; If you use `org' and don't want your org files in the default location below,
|
||||
;; change `org-directory'. It must be set before org loads!
|
||||
(setq org-directory "~/org/")
|
||||
(after! org
|
||||
(setq org-agenda-span 'week
|
||||
org-agenda-files `(,org-directory ,(concat org-directory "roam/"))
|
||||
org-log-done 'time
|
||||
org-agenda-custom-commands '(("n" "Agenda"
|
||||
((agenda "")
|
||||
(tags-todo "-someday-recurring")))
|
||||
("s" "Someday Items"
|
||||
((tags-todo "+someday"))))
|
||||
org-todo-keywords '((sequence "TODO(t)" "IN-PROGRESS(p)" "WAIT(w)" "|" "DONE(d)" "KILL(k)"))
|
||||
org-journal-file-type 'weekly
|
||||
org-journal-file-format "%Y-%m-%d.org"
|
||||
org-capture-templates
|
||||
'(("t" "Todo" entry (file+headline "~/org/todo.org" "Inbox")
|
||||
"* TODO %? \n %i \n%a" :prepend t))))
|
||||
|
||||
;; (use-package! org-caldav
|
||||
;; :defer t
|
||||
;; :config
|
||||
;; (setq org-caldav-url "https://nextcloud.johnogle.info/remote.php/dav/calendars/johno"
|
||||
;; org-caldav-calendar-id "personal"
|
||||
;; org-icalendar-timezone "America/Los_Angeles"
|
||||
;; org-caldav-inbox "~/org/calendar.org"
|
||||
;; org-caldav-files nil
|
||||
;; org-caldav-sync-direction 'cal->org))
|
||||
|
||||
|
||||
;; Whenever you reconfigure a package, make sure to wrap your config in an
|
||||
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
|
||||
;;
|
||||
;; (after! PACKAGE
|
||||
;; (setq x y))
|
||||
;;
|
||||
;; The exceptions to this rule:
|
||||
;;
|
||||
;; - Setting file/directory variables (like `org-directory')
|
||||
;; - Setting variables which explicitly tell you to set them before their
|
||||
;; package is loaded (see 'C-h v VARIABLE' to look up their documentation).
|
||||
;; - Setting doom variables (which start with 'doom-' or '+').
|
||||
;;
|
||||
;; Here are some additional functions/macros that will help you configure Doom.
|
||||
;;
|
||||
;; - `load!' for loading external *.el files relative to this one
|
||||
;; - `use-package!' for configuring packages
|
||||
;; - `after!' for running code after a package has loaded
|
||||
;; - `add-load-path!' for adding directories to the `load-path', relative to
|
||||
;; this file. Emacs searches the `load-path' when you load packages with
|
||||
;; `require' or `use-package'.
|
||||
;; - `map!' for binding new keys
|
||||
;;
|
||||
;; To get information about any of these functions/macros, move the cursor over
|
||||
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
|
||||
;; This will open documentation for it, including demos of how they are used.
|
||||
;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces,
|
||||
;; etc).
|
||||
;;
|
||||
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
|
||||
;; they are implemented.
|
||||
@@ -1,94 +0,0 @@
|
||||
{ inputs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hyprpaper.nix
|
||||
];
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
plugins = [ inputs.hy3.packages.x86_64-linux.hy3 ];
|
||||
settings = {
|
||||
"$mod" = "SUPER";
|
||||
"$terminal" = "kitty";
|
||||
"$fileManager" = "dolphin";
|
||||
"$menu" = "wofi --show drun";
|
||||
|
||||
exec-once = [
|
||||
"waybar"
|
||||
"dunst"
|
||||
];
|
||||
|
||||
xwayland = {
|
||||
force_zero_scaling = true;
|
||||
};
|
||||
|
||||
input = {
|
||||
kb_layout = "us";
|
||||
kb_options = "caps:escape";
|
||||
follow_mouse = 1;
|
||||
touchpad.natural_scroll = false;
|
||||
};
|
||||
|
||||
windowrulev2 = [
|
||||
# I can guess, but I should figure out what this actually does
|
||||
"suppressevent maximize, class:.*"
|
||||
];
|
||||
|
||||
general.layout = "hy3";
|
||||
|
||||
bind =
|
||||
[
|
||||
"SHIFT_$mod, Q, killactive"
|
||||
"SHIFT_$mod, M, exit"
|
||||
|
||||
"$mod, D, exec, $menu"
|
||||
"$mod, Return, exec, $terminal"
|
||||
|
||||
"$mod, H, hy3:movefocus, l"
|
||||
"$mod, L, hy3:movefocus, r"
|
||||
"$mod, K, hy3:movefocus, u"
|
||||
"$mod, J, hy3:movefocus, d"
|
||||
|
||||
"SHIFT_$mod, H, hy3:movewindow, l"
|
||||
"SHIFT_$mod, L, hy3:movewindow, r"
|
||||
"SHIFT_$mod, K, hy3:movewindow, u"
|
||||
"SHIFT_$mod, J, hy3:movewindow, d"
|
||||
|
||||
"$mod, V, hy3:makegroup, opposite"
|
||||
"$mod, W, hy3:changegroup, toggletab"
|
||||
|
||||
"$mod, A, hy3:changefocus, raise"
|
||||
"SHIFT_$mod, A, hy3:changefocus, lower"
|
||||
|
||||
"$mod, M, fullscreen, 0"
|
||||
"$mod, E, hy3:expand, expand"
|
||||
"SHIFT_$mod, E, hy3:expand, base"
|
||||
|
||||
"$mod, Q, hy3:warpcursor"
|
||||
]
|
||||
++ (
|
||||
# workspaces
|
||||
# binds $mod + [shift +] {1..10} to [move to] workspace {1..10}
|
||||
builtins.concatLists (builtins.genList (
|
||||
x: let
|
||||
ws = let
|
||||
c = (x + 1) / 10;
|
||||
in
|
||||
builtins.toString (x + 1 - (c * 10));
|
||||
in [
|
||||
"$mod, ${ws}, workspace, ${toString (x + 1)}"
|
||||
"$mod SHIFT, ${ws}, hy3:movetoworkspace, ${toString (x + 1)}"
|
||||
]
|
||||
)
|
||||
10)
|
||||
);
|
||||
|
||||
bindm =
|
||||
[
|
||||
"$mod, mouse:272, movewindow"
|
||||
"$mod, mouse:273, resizewindow"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
services.hyprpaper = {
|
||||
enable = true;
|
||||
settings = {
|
||||
ipc = "on";
|
||||
splash = false;
|
||||
preload = [
|
||||
"${config.xdg.dataHome}/wallpaper.jpg"
|
||||
];
|
||||
wallpaper = [
|
||||
",${config.xdg.dataHome}/wallpaper.jpg"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
xdg.dataFile."wallpaper.jpg" = {
|
||||
source = ./wallpaper.jpg;
|
||||
};
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
wayland.windowManager.hyprland.settings.monitor = ",preferred,2880x1800@90.00Hz,1.33333";
|
||||
}
|
||||
|
Before Width: | Height: | Size: 842 KiB |
@@ -1,16 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
wayland.windowManager.hyprland.settings.monitor = "DP-1,3440x1440@164.90,0x0,1.33333,vrr,1";
|
||||
wayland.windowManager.hyprland.settings.env = [
|
||||
"LIBVA_DRIVER_NAME,nvidia"
|
||||
"XDG_SESSION_TYPE,wayland"
|
||||
"GBM_BACKEND,nvidia-drm"
|
||||
"__GLX_VENDOR_LIBRARY_NAME,nvidia"
|
||||
"NVD_BACKEND,direct"
|
||||
"ELECTRON_OZONE_PLATFORM_HINT,auto"
|
||||
"NIXOS_OZONE_WL,1"
|
||||
];
|
||||
|
||||
wayland.windowManager.hyprland.settings.cursor.no_hardware_cursors = true;
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.i3_sway;
|
||||
i3_cfg = config.xsession.windowManager.i3.config;
|
||||
|
||||
shared_config = recursiveUpdate {
|
||||
modifier = "Mod4";
|
||||
terminal = "kitty";
|
||||
defaultWorkspace = "workspace number 1";
|
||||
|
||||
keybindings = {
|
||||
"${shared_config.modifier}+Return" = "exec ${i3_cfg.terminal}";
|
||||
"${shared_config.modifier}+Shift+q" = "kill";
|
||||
"${shared_config.modifier}+d" = "exec ${i3_cfg.menu}";
|
||||
|
||||
"${shared_config.modifier}+h" = "focus left";
|
||||
"${shared_config.modifier}+j" = "focus down";
|
||||
"${shared_config.modifier}+k" = "focus up";
|
||||
"${shared_config.modifier}+l" = "focus right";
|
||||
|
||||
"${shared_config.modifier}+Shift+h" = "move left";
|
||||
"${shared_config.modifier}+Shift+j" = "move down";
|
||||
"${shared_config.modifier}+Shift+k" = "move up";
|
||||
"${shared_config.modifier}+Shift+l" = "move right";
|
||||
|
||||
"${shared_config.modifier}+Left" = "focus left";
|
||||
"${shared_config.modifier}+Down" = "focus down";
|
||||
"${shared_config.modifier}+Up" = "focus up";
|
||||
"${shared_config.modifier}+Right" = "focus right";
|
||||
|
||||
"${shared_config.modifier}+Shift+Left" = "move left";
|
||||
"${shared_config.modifier}+Shift+Down" = "move down";
|
||||
"${shared_config.modifier}+Shift+Up" = "move up";
|
||||
"${shared_config.modifier}+Shift+Right" = "move right";
|
||||
|
||||
#"${shared_config.modifier}+h" = "split h";
|
||||
"${shared_config.modifier}+v" = "split v";
|
||||
"${shared_config.modifier}+f" = "fullscreen toggle";
|
||||
|
||||
"${shared_config.modifier}+s" = "layout stacking";
|
||||
"${shared_config.modifier}+w" = "layout tabbed";
|
||||
"${shared_config.modifier}+e" = "layout toggle split";
|
||||
|
||||
"${shared_config.modifier}+Shift+space" = "floating toggle";
|
||||
"${shared_config.modifier}+space" = "focus mode_toggle";
|
||||
|
||||
"${shared_config.modifier}+a" = "focus parent";
|
||||
|
||||
"${shared_config.modifier}+Shift+minus" = "move scratchpad";
|
||||
"${shared_config.modifier}+minus" = "scratchpad show";
|
||||
|
||||
"${shared_config.modifier}+1" = "workspace number 1";
|
||||
"${shared_config.modifier}+2" = "workspace number 2";
|
||||
"${shared_config.modifier}+3" = "workspace number 3";
|
||||
"${shared_config.modifier}+4" = "workspace number 4";
|
||||
"${shared_config.modifier}+5" = "workspace number 5";
|
||||
"${shared_config.modifier}+6" = "workspace number 6";
|
||||
"${shared_config.modifier}+7" = "workspace number 7";
|
||||
"${shared_config.modifier}+8" = "workspace number 8";
|
||||
"${shared_config.modifier}+9" = "workspace number 9";
|
||||
"${shared_config.modifier}+0" = "workspace number 10";
|
||||
|
||||
"${shared_config.modifier}+Shift+1" =
|
||||
"move container to workspace number 1";
|
||||
"${shared_config.modifier}+Shift+2" =
|
||||
"move container to workspace number 2";
|
||||
"${shared_config.modifier}+Shift+3" =
|
||||
"move container to workspace number 3";
|
||||
"${shared_config.modifier}+Shift+4" =
|
||||
"move container to workspace number 4";
|
||||
"${shared_config.modifier}+Shift+5" =
|
||||
"move container to workspace number 5";
|
||||
"${shared_config.modifier}+Shift+6" =
|
||||
"move container to workspace number 6";
|
||||
"${shared_config.modifier}+Shift+7" =
|
||||
"move container to workspace number 7";
|
||||
"${shared_config.modifier}+Shift+8" =
|
||||
"move container to workspace number 8";
|
||||
"${shared_config.modifier}+Shift+9" =
|
||||
"move container to workspace number 9";
|
||||
"${shared_config.modifier}+Shift+0" =
|
||||
"move container to workspace number 10";
|
||||
|
||||
"${shared_config.modifier}+Shift+c" = "reload";
|
||||
"${shared_config.modifier}+Shift+r" = "restart";
|
||||
|
||||
"${shared_config.modifier}+r" = "mode resize";
|
||||
|
||||
"XF86MonBrightnessUp" = "exec brightnessctl s +5%";
|
||||
"XF86MonBrightnessDown" = "exec brightnessctl s 5%-";
|
||||
};
|
||||
} cfg.extraSharedConfig;
|
||||
in {
|
||||
options.home.i3_sway = {
|
||||
extraSharedConfig = mkOption {
|
||||
default = {};
|
||||
};
|
||||
extraI3Config = mkOption {
|
||||
default = {};
|
||||
};
|
||||
extraSwayConfig = mkOption {
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
xsession.windowManager.i3 = let
|
||||
base_i3_config = recursiveUpdate shared_config {
|
||||
keybindings = {
|
||||
"${shared_config.modifier}+Shift+e" =
|
||||
"exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'";
|
||||
};
|
||||
};
|
||||
in {
|
||||
enable = true;
|
||||
config = recursiveUpdate base_i3_config cfg.extraI3Config;
|
||||
};
|
||||
|
||||
wayland.windowManager.sway = let
|
||||
base_sway_config = recursiveUpdate shared_config {
|
||||
keybindings = {
|
||||
"${shared_config.modifier}+Shift+e" =
|
||||
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";
|
||||
};
|
||||
input = {
|
||||
"type:keyboard" = {
|
||||
xkb_options = "caps:escape";
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
enable = true;
|
||||
config = recursiveUpdate base_sway_config cfg.extraSwayConfig;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
home.packages = [
|
||||
pkgs.gamescope
|
||||
pkgs.lutris
|
||||
pkgs.mangohud
|
||||
];
|
||||
}
|
||||
22
home/roles/3d-printing/default.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles."3d-printing";
|
||||
in
|
||||
{
|
||||
options.home.roles."3d-printing" = {
|
||||
enable = mkEnableOption "Enable 3D printing applications and tools";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
# 3D Slicing Software
|
||||
orca-slicer # G-code generator for 3D printers (Bambu, Prusa, Voron, etc.)
|
||||
|
||||
# 3D Modeling Software
|
||||
openscad-unstable # 3D parametric model compiler (nightly build)
|
||||
];
|
||||
};
|
||||
}
|
||||
727
home/roles/aerospace/default.nix
Normal file
@@ -0,0 +1,727 @@
|
||||
{ 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";
|
||||
};
|
||||
};
|
||||
|
||||
enableSpansDisplays = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Configure macOS Spaces to span displays (required for aerospace multi-monitor support).
|
||||
Sets com.apple.spaces.spans-displays to true.
|
||||
|
||||
NOTE: This was previously set at the system level in modules/aerospace.nix,
|
||||
but has been moved to home-manager for better modularity.
|
||||
'';
|
||||
};
|
||||
|
||||
ctrlShortcuts = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Remap common macOS Cmd shortcuts to Ctrl equivalents for all operations.
|
||||
This makes macOS behave more like Linux.
|
||||
|
||||
Shortcuts remapped globally:
|
||||
- Ctrl+N: New Window
|
||||
- Ctrl+T: New Tab
|
||||
- Ctrl+W: Close Tab
|
||||
- Ctrl+S: Save / Save As
|
||||
- Ctrl+O: Open
|
||||
- Ctrl+F: Find
|
||||
- Ctrl+H: Find and Replace
|
||||
- Ctrl+P: Print
|
||||
- Ctrl+C/V/X: Copy/Paste/Cut
|
||||
- Ctrl+Z: Undo
|
||||
|
||||
NOTE: Terminal emulators like Ghostty require per-app overrides (configured separately)
|
||||
to preserve Ctrl+C as SIGINT instead of Copy.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
sketchybar = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable SketchyBar status bar";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Only apply on Darwin systems
|
||||
assertions = [
|
||||
{
|
||||
assertion = pkgs.stdenv.isDarwin;
|
||||
message = "Aerospace role is only supported on macOS (Darwin) systems";
|
||||
}
|
||||
];
|
||||
|
||||
# Configure macOS preferences via targets.darwin.defaults
|
||||
targets.darwin.defaults = mkMerge [
|
||||
# Spaces span displays (required for multi-monitor aerospace)
|
||||
(mkIf cfg.enableSpansDisplays {
|
||||
"com.apple.spaces" = {
|
||||
spans-displays = true;
|
||||
};
|
||||
})
|
||||
|
||||
# Ctrl shortcuts to make macOS behave more like Linux
|
||||
(mkIf cfg.ctrlShortcuts.enable {
|
||||
NSGlobalDomain.NSUserKeyEquivalents = {
|
||||
# Window/Tab operations
|
||||
"New Window" = "^n";
|
||||
"New Tab" = "^t";
|
||||
"Close Tab" = "^w";
|
||||
# File operations
|
||||
"Save" = "^s";
|
||||
"Save As…" = "^$s"; # Ctrl+Shift+S
|
||||
"Open" = "^o";
|
||||
"Open…" = "^o";
|
||||
# Find operations
|
||||
"Find" = "^f";
|
||||
"Find…" = "^f";
|
||||
"Find and Replace" = "^h";
|
||||
"Find and Replace…" = "^h";
|
||||
# Print
|
||||
"Print" = "^p";
|
||||
"Print…" = "^p";
|
||||
# Clipboard operations
|
||||
"Copy" = "^c";
|
||||
"Paste" = "^v";
|
||||
"Cut" = "^x";
|
||||
# Undo/Redo
|
||||
"Undo" = "^z";
|
||||
"Redo" = "^$z"; # Ctrl+Shift+Z
|
||||
};
|
||||
})
|
||||
|
||||
# Ghostty-specific overrides to preserve terminal behavior
|
||||
# Remap clipboard operations back to Cmd (macOS default) so Ctrl+C remains SIGINT
|
||||
(mkIf cfg.ctrlShortcuts.enable {
|
||||
"com.mitchellh.ghostty".NSUserKeyEquivalents = {
|
||||
# Remap back to Cmd for clipboard operations
|
||||
"Copy" = "@c"; # Cmd+C
|
||||
"Paste" = "@v"; # Cmd+V
|
||||
"Cut" = "@x"; # Cmd+X
|
||||
"Undo" = "@z"; # Cmd+Z
|
||||
"Redo" = "@$z"; # Cmd+Shift+Z
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
# Install aerospace package and optional tools if enabled
|
||||
home.packages = [ pkgs.aerospace ]
|
||||
++ optionals cfg.autoraise.enable [ pkgs.autoraise ]
|
||||
++ optionals cfg.sketchybar.enable [ pkgs.sketchybar pkgs.sketchybar-app-font ];
|
||||
|
||||
# Enable and configure aerospace
|
||||
programs.aerospace.enable = true;
|
||||
programs.aerospace.launchd.enable = cfg.launchd.enable;
|
||||
programs.aerospace.userSettings = mkMerge [
|
||||
# Default configuration with leader key substitution
|
||||
{
|
||||
# Disable normalizations for i3-like behavior
|
||||
enable-normalization-flatten-containers = false;
|
||||
enable-normalization-opposite-orientation-for-nested-containers = false;
|
||||
|
||||
mode.main.binding = {
|
||||
"${cfg.leader}-w" = "layout accordion horizontal"; # tabbed
|
||||
"${cfg.leader}-s" = "layout accordion vertical"; # stacking
|
||||
"${cfg.leader}-e" = "layout tiles horizontal vertical"; # tiles, toggles orientation
|
||||
"${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}-r" = "mode resize";
|
||||
"${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";
|
||||
};
|
||||
|
||||
# Resize mode: For window resizing operations
|
||||
mode.resize.binding = {
|
||||
h = "resize width -50";
|
||||
j = "resize height +50";
|
||||
k = "resize height -50";
|
||||
l = "resize width +50";
|
||||
|
||||
minus = "resize smart -50";
|
||||
equal = "resize smart +50";
|
||||
|
||||
esc = "mode main";
|
||||
enter = "mode main";
|
||||
};
|
||||
|
||||
# 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";
|
||||
};
|
||||
|
||||
# SketchyBar integration - notify bar of workspace changes
|
||||
exec-on-workspace-change = mkIf cfg.sketchybar.enable [
|
||||
"/bin/bash" "-c"
|
||||
"${pkgs.sketchybar}/bin/sketchybar --trigger aerospace_workspace_change FOCUSED=$AEROSPACE_FOCUSED_WORKSPACE PREV=$AEROSPACE_PREV_WORKSPACE"
|
||||
];
|
||||
}
|
||||
# Gaps configuration - prevent windows from overlapping SketchyBar
|
||||
(mkIf cfg.sketchybar.enable {
|
||||
gaps = {
|
||||
outer = {
|
||||
top = 0;
|
||||
bottom = 38;
|
||||
left = 0;
|
||||
right = 0;
|
||||
};
|
||||
};
|
||||
})
|
||||
cfg.userSettings
|
||||
];
|
||||
|
||||
# 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;
|
||||
};
|
||||
};
|
||||
|
||||
# SketchyBar configuration
|
||||
home.file.".config/sketchybar/sketchybarrc" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
onChange = "${pkgs.sketchybar}/bin/sketchybar --reload";
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
# Plugin directory
|
||||
PLUGIN_DIR="$HOME/.config/sketchybar/plugins"
|
||||
|
||||
# Colors - i3/sway theme with exact color matching
|
||||
# Focused window/workspace color from i3/sway
|
||||
FOCUSED=0xff285577
|
||||
|
||||
# Background colors matching i3blocks bar
|
||||
BAR_BG=0xff333333 # Dark gray
|
||||
ITEM_BG=0xff333333 # Dark gray matching bar
|
||||
|
||||
# Text colors
|
||||
TEXT=0xffffffff # White text
|
||||
GRAY=0xff888888 # Muted text for inactive items
|
||||
|
||||
# Accent colors for warnings
|
||||
WARNING=0xffff9900
|
||||
CRITICAL=0xff900000
|
||||
|
||||
# Configure the bar appearance
|
||||
${pkgs.sketchybar}/bin/sketchybar --bar \
|
||||
position=bottom \
|
||||
height=30 \
|
||||
color=$BAR_BG \
|
||||
border_width=0 \
|
||||
corner_radius=0 \
|
||||
padding_left=10 \
|
||||
padding_right=10 \
|
||||
shadow=off \
|
||||
topmost=on \
|
||||
sticky=on
|
||||
|
||||
# Set default properties for all items
|
||||
# Using monospace font to match waybar's Fira Code styling
|
||||
${pkgs.sketchybar}/bin/sketchybar --default \
|
||||
updates=when_shown \
|
||||
icon.font="Fira Code:Regular:13.0" \
|
||||
icon.color=$TEXT \
|
||||
icon.padding_left=4 \
|
||||
icon.padding_right=4 \
|
||||
label.font="Fira Code:Regular:13.0" \
|
||||
label.color=$TEXT \
|
||||
label.padding_left=4 \
|
||||
label.padding_right=4 \
|
||||
padding_left=4 \
|
||||
padding_right=4 \
|
||||
background.corner_radius=0 \
|
||||
background.height=30
|
||||
|
||||
# Register aerospace workspace change event
|
||||
${pkgs.sketchybar}/bin/sketchybar --add event aerospace_workspace_change
|
||||
|
||||
# Create workspace indicators for workspaces 1-10
|
||||
for sid in 1 2 3 4 5 6 7 8 9 10; do
|
||||
# Display "0" for workspace 10
|
||||
if [ "$sid" = "10" ]; then
|
||||
display="0"
|
||||
else
|
||||
display="$sid"
|
||||
fi
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item space.$sid left \
|
||||
--subscribe space.$sid aerospace_workspace_change \
|
||||
--set space.$sid \
|
||||
drawing=on \
|
||||
update_freq=2 \
|
||||
width=32 \
|
||||
background.color=$ITEM_BG \
|
||||
background.corner_radius=0 \
|
||||
background.height=30 \
|
||||
background.drawing=on \
|
||||
icon="$display" \
|
||||
icon.padding_left=13 \
|
||||
icon.padding_right=11 \
|
||||
icon.align=center \
|
||||
label.drawing=off \
|
||||
click_script="${pkgs.aerospace}/bin/aerospace workspace $sid" \
|
||||
script="$PLUGIN_DIR/aerospace.sh $sid"
|
||||
done
|
||||
|
||||
# System monitoring modules (right side)
|
||||
# Note: Items added to 'right' appear in reverse order (last added = leftmost)
|
||||
# Adding in reverse to get: disk | cpu | memory | battery | volume | calendar
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item calendar right \
|
||||
--set calendar \
|
||||
icon="📅" \
|
||||
update_freq=30 \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
script="$PLUGIN_DIR/calendar.sh"
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item volume right \
|
||||
--set volume \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
script="$PLUGIN_DIR/volume.sh" \
|
||||
--subscribe volume volume_change
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item battery right \
|
||||
--set battery \
|
||||
update_freq=120 \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
script="$PLUGIN_DIR/battery.sh" \
|
||||
--subscribe battery system_woke power_source_change
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item memory right \
|
||||
--set memory \
|
||||
update_freq=5 \
|
||||
icon="🐏" \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
script="$PLUGIN_DIR/memory.sh"
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item cpu right \
|
||||
--set cpu \
|
||||
update_freq=2 \
|
||||
icon="🧠" \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
script="$PLUGIN_DIR/cpu.sh"
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --add item disk right \
|
||||
--set disk \
|
||||
update_freq=60 \
|
||||
icon="💾" \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
script="$PLUGIN_DIR/disk.sh"
|
||||
|
||||
# Menu bar extras / system tray items (rightmost)
|
||||
# Note: Requires Screen Recording permission for SketchyBar in System Settings
|
||||
# Use 'sketchybar --query default_menu_items' to discover available items
|
||||
|
||||
# Bluetooth
|
||||
${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,Bluetooth" right \
|
||||
--set "Control Center,Bluetooth" \
|
||||
alias.update_freq=1 \
|
||||
padding_left=0 \
|
||||
padding_right=0
|
||||
|
||||
# WiFi
|
||||
${pkgs.sketchybar}/bin/sketchybar --add alias "Control Center,WiFi" right \
|
||||
--set "Control Center,WiFi" \
|
||||
alias.update_freq=1 \
|
||||
padding_left=0 \
|
||||
padding_right=0
|
||||
|
||||
# Add other menu bar apps as discovered
|
||||
# Common examples:
|
||||
# - Cloudflare WARP: --add alias "Cloudflare WARP,Item-0" right
|
||||
# - Notion Calendar: --add alias "Notion Calendar,Item-0" right
|
||||
# Run 'sketchybar --query default_menu_items' to find exact names
|
||||
|
||||
# Update the bar
|
||||
${pkgs.sketchybar}/bin/sketchybar --update
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar aerospace workspace plugin
|
||||
home.file.".config/sketchybar/plugins/aerospace.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
# Colors
|
||||
FOCUSED_COLOR=0xff285577
|
||||
ITEM_BG=0xff333333
|
||||
TEXT=0xffffffff
|
||||
GRAY=0xff555555
|
||||
|
||||
# Get the currently focused workspace directly from aerospace
|
||||
# Trim whitespace to ensure clean comparison
|
||||
FOCUSED=$(${pkgs.aerospace}/bin/aerospace list-workspaces --focused | tr -d ' \n\r')
|
||||
|
||||
# Get list of empty workspaces
|
||||
EMPTY_WORKSPACES=$(${pkgs.aerospace}/bin/aerospace list-workspaces --monitor all --empty)
|
||||
|
||||
# Get workspace number - from $1 if provided (event-triggered), otherwise extract from $NAME (routine update)
|
||||
# $NAME is always available (e.g., "space.1", "space.2", etc.)
|
||||
# $1 is only available when called via event trigger with positional argument
|
||||
if [ -n "$1" ]; then
|
||||
WORKSPACE_NUM=$(echo "$1" | tr -d ' \n\r')
|
||||
else
|
||||
# Extract number from item name: "space.1" -> "1", "space.10" -> "10"
|
||||
WORKSPACE_NUM=$(echo "$NAME" | sed 's/space\.//')
|
||||
fi
|
||||
|
||||
# Check if workspace has windows (is NOT empty)
|
||||
IS_EMPTY=false
|
||||
if echo "$EMPTY_WORKSPACES" | grep -q "^$WORKSPACE_NUM$"; then
|
||||
IS_EMPTY=true
|
||||
fi
|
||||
|
||||
# Check if this workspace is focused
|
||||
IS_FOCUSED=false
|
||||
if [ "$WORKSPACE_NUM" = "$FOCUSED" ]; then
|
||||
IS_FOCUSED=true
|
||||
fi
|
||||
|
||||
# Determine display value (workspace 10 displays as "0")
|
||||
if [ "$WORKSPACE_NUM" = "10" ]; then
|
||||
DISPLAY="0"
|
||||
else
|
||||
DISPLAY="$WORKSPACE_NUM"
|
||||
fi
|
||||
|
||||
# Determine visibility and styling
|
||||
# Always show focused workspace (even if empty) with fixed width
|
||||
# Hide non-focused empty workspaces by setting width to 0 (collapsed)
|
||||
# Show non-focused non-empty workspaces with fixed width and inactive styling
|
||||
|
||||
if [ "$IS_FOCUSED" = "true" ]; then
|
||||
# Focused workspace - always show with focused styling and bold font
|
||||
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||
drawing=on \
|
||||
icon="$DISPLAY" \
|
||||
width=32 \
|
||||
icon.padding_left=13 \
|
||||
icon.padding_right=11 \
|
||||
icon.align=center \
|
||||
background.color=$FOCUSED_COLOR \
|
||||
background.drawing=on \
|
||||
icon.color=$TEXT \
|
||||
icon.font="Fira Code:Bold:13.0"
|
||||
elif [ "$IS_EMPTY" = "true" ]; then
|
||||
# Empty workspace (not focused) - hide by collapsing width and clearing content
|
||||
# Using width=0 with drawing=on so updates=when_shown continues to run the script
|
||||
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||
drawing=on \
|
||||
icon="" \
|
||||
label="" \
|
||||
width=0 \
|
||||
icon.padding_left=0 \
|
||||
icon.padding_right=0 \
|
||||
background.drawing=off
|
||||
else
|
||||
# Non-empty workspace (not focused) - show with inactive styling and white text
|
||||
${pkgs.sketchybar}/bin/sketchybar --set space.$WORKSPACE_NUM \
|
||||
drawing=on \
|
||||
icon="$DISPLAY" \
|
||||
width=32 \
|
||||
icon.padding_left=13 \
|
||||
icon.padding_right=11 \
|
||||
icon.align=center \
|
||||
background.color=$ITEM_BG \
|
||||
background.drawing=on \
|
||||
icon.color=$TEXT \
|
||||
icon.font="Fira Code:Regular:13.0"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar CPU monitoring plugin
|
||||
home.file.".config/sketchybar/plugins/cpu.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
CORE_COUNT=$(sysctl -n machdep.cpu.thread_count)
|
||||
CPU_INFO=$(ps -eo pcpu,user)
|
||||
CPU_SYS=$(echo "$CPU_INFO" | grep -v $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}")
|
||||
CPU_USER=$(echo "$CPU_INFO" | grep $(whoami) | sed "s/[^ 0-9\.]//g" | awk "{sum+=\$1} END {print sum/(100.0 * $CORE_COUNT)}")
|
||||
CPU_PERCENT="$(echo "$CPU_SYS $CPU_USER" | awk '{printf "%.0f\n", ($1 + $2)*100}')"
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$CPU_PERCENT%"
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar memory monitoring plugin
|
||||
# Shows actual memory pressure (excludes file cache/inactive pages)
|
||||
home.file.".config/sketchybar/plugins/memory.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
# Use awk for all arithmetic to avoid bash integer overflow on large RAM systems
|
||||
# Memory pressure = Anonymous (app memory) + Wired + Compressor RAM
|
||||
# - Anonymous pages: app-allocated memory (heap, stack) - matches Activity Monitor's "App Memory"
|
||||
# - Wired: kernel/system memory that can't be paged out
|
||||
# - Pages occupied by compressor: actual RAM used by compressor (NOT "stored in compressor")
|
||||
TOTAL_RAM=$(sysctl -n hw.memsize)
|
||||
MEMORY_PERCENT=$(vm_stat | awk -v total_ram="$TOTAL_RAM" '
|
||||
/page size of/ { page_size = $8 }
|
||||
/Anonymous pages/ { anon = $3 + 0 }
|
||||
/Pages wired/ { wired = $4 + 0 }
|
||||
/Pages occupied by compressor/ { compressor = $5 + 0 }
|
||||
END {
|
||||
used = (anon + wired + compressor) * page_size
|
||||
printf "%.0f", used / total_ram * 100
|
||||
}
|
||||
')
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$MEMORY_PERCENT%"
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar disk monitoring plugin
|
||||
home.file.".config/sketchybar/plugins/disk.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
DISK_USAGE=$(df -H / | grep -v Filesystem | awk '{print $5}')
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$DISK_USAGE"
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar battery monitoring plugin
|
||||
home.file.".config/sketchybar/plugins/battery.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
PERCENTAGE=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1)
|
||||
CHARGING=$(pmset -g batt | grep 'AC Power')
|
||||
|
||||
if [ "$PERCENTAGE" = "" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Select icon based on battery level
|
||||
case ''${PERCENTAGE} in
|
||||
9[0-9]|100) ICON="🔋"
|
||||
;;
|
||||
[6-8][0-9]) ICON="🔋"
|
||||
;;
|
||||
[3-5][0-9]) ICON="🔋"
|
||||
;;
|
||||
[1-2][0-9]) ICON="🔋"
|
||||
;;
|
||||
*) ICON="🪫"
|
||||
esac
|
||||
|
||||
# Show charging icon if connected to power
|
||||
if [[ $CHARGING != "" ]]; then
|
||||
ICON="⚡"
|
||||
fi
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="''${PERCENTAGE}%"
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar volume monitoring plugin
|
||||
home.file.".config/sketchybar/plugins/volume.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$SENDER" = "volume_change" ]; then
|
||||
VOLUME=$(osascript -e "output volume of (get volume settings)")
|
||||
MUTED=$(osascript -e "output muted of (get volume settings)")
|
||||
|
||||
if [ "$MUTED" = "true" ]; then
|
||||
ICON="🔇"
|
||||
LABEL=""
|
||||
else
|
||||
case $VOLUME in
|
||||
[6-9][0-9]|100) ICON="🔊"
|
||||
;;
|
||||
[3-5][0-9]) ICON="🔉"
|
||||
;;
|
||||
*) ICON="🔈"
|
||||
esac
|
||||
LABEL="$VOLUME%"
|
||||
fi
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --set $NAME icon="$ICON" label="$LABEL"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
# SketchyBar calendar/clock plugin
|
||||
home.file.".config/sketchybar/plugins/calendar.sh" = mkIf cfg.sketchybar.enable {
|
||||
executable = true;
|
||||
text = ''
|
||||
#!/bin/bash
|
||||
|
||||
${pkgs.sketchybar}/bin/sketchybar --set $NAME label="$(date '+%Y-%m-%d %H:%M')"
|
||||
'';
|
||||
};
|
||||
|
||||
# Launchd agent for auto-starting sketchybar
|
||||
launchd.agents.sketchybar = mkIf cfg.sketchybar.enable {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [ "${pkgs.sketchybar}/bin/sketchybar" ];
|
||||
RunAtLoad = true;
|
||||
KeepAlive = true;
|
||||
StandardOutPath = "/tmp/sketchybar.log";
|
||||
StandardErrorPath = "/tmp/sketchybar.err.log";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
11
home/roles/base-darwin/default.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
# Base imports for Darwin home configurations
|
||||
# Includes Darwin-specific roles that only work on macOS
|
||||
imports = [
|
||||
../aerospace
|
||||
];
|
||||
|
||||
# Override to use -d instead of --delete-older-than on Darwin due to launchd bug
|
||||
# https://github.com/nix-community/home-manager/issues/7211
|
||||
nix.gc.options = "-d";
|
||||
}
|
||||
8
home/roles/base-linux/default.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
# Base imports for Linux home configurations
|
||||
# Includes Linux-specific roles that require Linux-only home-manager modules
|
||||
imports = [
|
||||
../plasma-manager
|
||||
../i3+sway
|
||||
];
|
||||
}
|
||||
95
home/roles/base/default.nix
Normal file
@@ -0,0 +1,95 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.base;
|
||||
in
|
||||
{
|
||||
options.home.roles.base = {
|
||||
enable = mkEnableOption "Enable base CLI tools and essential programs";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
fd
|
||||
glances
|
||||
gzip
|
||||
htop
|
||||
killall
|
||||
less
|
||||
ncdu
|
||||
shellcheck
|
||||
tmux
|
||||
tree
|
||||
];
|
||||
|
||||
# Automatic garbage collection for user profile (home-manager generations).
|
||||
# This complements system-level gc which only cleans system generations.
|
||||
# - Linux: Uses --delete-older-than to keep 10-day rollback window
|
||||
# - Darwin: Overridden to use -d in base-darwin role to avoid launchd bug
|
||||
# (https://github.com/nix-community/home-manager/issues/7211)
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
randomizedDelaySec = mkIf pkgs.stdenv.isLinux "14m";
|
||||
options = lib.mkDefault "--delete-older-than 10d";
|
||||
};
|
||||
|
||||
# Essential programs everyone needs
|
||||
programs.bash = {
|
||||
enable = true;
|
||||
initExtra = ''
|
||||
codex() {
|
||||
local key
|
||||
key="$(rbw get openai-api-key-codex)"
|
||||
OPENAI_API_KEY="$key" command codex "$@"
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
programs.home-manager.enable = true;
|
||||
programs.command-not-found.enable = true;
|
||||
|
||||
programs.git = {
|
||||
enable = true;
|
||||
settings = {
|
||||
user.name = "John Ogle";
|
||||
user.email = "john@ogle.fyi";
|
||||
safe.directory = "/etc/nixos";
|
||||
};
|
||||
};
|
||||
|
||||
programs.jq.enable = true;
|
||||
|
||||
programs.neovim = {
|
||||
enable = true;
|
||||
viAlias = true;
|
||||
vimAlias = true;
|
||||
};
|
||||
|
||||
programs.ssh = {
|
||||
enable = true;
|
||||
enableDefaultConfig = false;
|
||||
matchBlocks = {
|
||||
"*" = {
|
||||
addKeysToAgent = "yes";
|
||||
};
|
||||
"nucdeb1" = {
|
||||
hostname = "nucdeb1.oglehome";
|
||||
user = "root";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
programs.rbw = {
|
||||
enable = true;
|
||||
settings = {
|
||||
email = "john@johnogle.info";
|
||||
base_url = "https://bitwarden.johnogle.info";
|
||||
pinentry = pkgs.pinentry-qt;
|
||||
};
|
||||
};
|
||||
|
||||
# Note: modules must be imported at top-level home config
|
||||
};
|
||||
}
|
||||
25
home/roles/communication/default.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.communication;
|
||||
in
|
||||
{
|
||||
options.home.roles.communication = {
|
||||
enable = mkEnableOption "Enable communication and messaging applications";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [
|
||||
# Communication apps
|
||||
pkgs.element-desktop
|
||||
# Re-enabled in 25.11 after security issues were resolved
|
||||
pkgs.fluffychat
|
||||
pkgs.nextcloud-talk-desktop
|
||||
|
||||
# For logging back into google chat
|
||||
globalInputs.google-cookie-retrieval.packages.${system}.default
|
||||
];
|
||||
};
|
||||
}
|
||||
23
home/roles/default.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
# Shared roles that work across all platforms (Linux, Darwin, etc.)
|
||||
# Platform-specific roles are imported via base-linux or base-darwin
|
||||
# in each home configuration file
|
||||
imports = [
|
||||
./3d-printing
|
||||
./base
|
||||
./communication
|
||||
./desktop
|
||||
./development
|
||||
./email
|
||||
./gaming
|
||||
./kdeconnect
|
||||
./kubectl
|
||||
./launchers
|
||||
./media
|
||||
./office
|
||||
./plasma-manager-kodi
|
||||
./sync
|
||||
./tmux
|
||||
./emacs
|
||||
];
|
||||
}
|
||||
199
home/roles/desktop/default.nix
Normal file
@@ -0,0 +1,199 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.desktop;
|
||||
in
|
||||
{
|
||||
options.home.roles.desktop = {
|
||||
enable = mkEnableOption "Enable desktop GUI applications and utilities";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
# Desktop applications
|
||||
bitwarden-desktop
|
||||
dunst
|
||||
keepassxc
|
||||
unstable.ghostty
|
||||
|
||||
# Desktop utilities
|
||||
feh # Image viewer and wallpaper setter for X11
|
||||
rofi # Application launcher for X11
|
||||
solaar # Logitech management software
|
||||
waybar
|
||||
wofi # Application launcher for Wayland
|
||||
xdg-utils # XDG utilities for opening files/URLs with default applications
|
||||
|
||||
# System utilities with GUI components
|
||||
(snapcast.override { pulseaudioSupport = true; })
|
||||
|
||||
# KDE tiling window management
|
||||
kdePackages.krohnkite # Dynamic tiling extension for KWin 6
|
||||
|
||||
# KDE PIM applications for email, calendar, and contacts
|
||||
kdePackages.kmail
|
||||
kdePackages.kmail-account-wizard
|
||||
kdePackages.kmailtransport
|
||||
kdePackages.korganizer
|
||||
kdePackages.kaddressbook
|
||||
kdePackages.kontact
|
||||
|
||||
# KDE System components needed for proper integration
|
||||
kdePackages.kded
|
||||
kdePackages.systemsettings
|
||||
kdePackages.kmenuedit
|
||||
|
||||
# Desktop menu support
|
||||
kdePackages.plasma-desktop # Contains applications.menu
|
||||
|
||||
# KDE Online Accounts support
|
||||
kdePackages.kaccounts-integration
|
||||
kdePackages.kaccounts-providers
|
||||
kdePackages.signond
|
||||
|
||||
# KDE Mapping
|
||||
kdePackages.marble # Virtual globe and world atlas
|
||||
|
||||
# KDE Productivity
|
||||
kdePackages.kate # Advanced text editor with syntax highlighting
|
||||
kdePackages.okular # Universal document viewer (PDF, ePub, etc.)
|
||||
kdePackages.spectacle # Screenshot capture utility
|
||||
kdePackages.filelight # Visual disk usage analyzer
|
||||
|
||||
# KDE Multimedia
|
||||
kdePackages.gwenview # Image viewer and basic editor
|
||||
kdePackages.elisa # Music player
|
||||
|
||||
# KDE System Utilities
|
||||
kdePackages.ark # Archive manager (zip, tar, 7z, etc.)
|
||||
kdePackages.yakuake # Drop-down terminal emulator
|
||||
];
|
||||
|
||||
programs.firefox = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
programs.spotify-player.enable = true;
|
||||
|
||||
services.gnome-keyring = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# rbw vault unlock on login and resume from suspend
|
||||
systemd.user.services.rbw-unlock-on-login = {
|
||||
Unit = {
|
||||
Description = "Unlock rbw vault at login";
|
||||
After = [ "graphical-session.target" ];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.rbw}/bin/rbw unlock";
|
||||
Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent";
|
||||
# KillMode = "process" prevents systemd from killing the rbw-agent daemon
|
||||
# when this oneshot service completes. The agent is spawned by rbw unlock
|
||||
# and needs to persist after the service exits.
|
||||
KillMode = "process";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.services.rbw-unlock-on-resume = {
|
||||
Unit = {
|
||||
Description = "Unlock rbw vault after resume from suspend";
|
||||
After = [ "suspend.target" ];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.rbw}/bin/rbw unlock";
|
||||
Environment = "RBW_AGENT=${pkgs.rbw}/bin/rbw-agent";
|
||||
# KillMode = "process" prevents systemd from killing the rbw-agent daemon
|
||||
# when this oneshot service completes. The agent is spawned by rbw unlock
|
||||
# and needs to persist after the service exits.
|
||||
KillMode = "process";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "suspend.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
# KDE environment variables for proper integration
|
||||
home.sessionVariables = {
|
||||
QT_QPA_PLATFORMTHEME = "kde";
|
||||
KDE_SESSION_VERSION = "6";
|
||||
};
|
||||
|
||||
xdg = {
|
||||
enable = true;
|
||||
|
||||
# Ensure desktop files are made available for discovery
|
||||
desktopEntries = {}; # This creates the desktop files directory structure
|
||||
|
||||
mimeApps = {
|
||||
enable = true;
|
||||
associations.added = {
|
||||
# Ensure associations are properly registered
|
||||
"text/html" = "firefox.desktop";
|
||||
"x-scheme-handler/http" = "firefox.desktop";
|
||||
"x-scheme-handler/https" = "firefox.desktop";
|
||||
};
|
||||
defaultApplications = {
|
||||
# Web browsers
|
||||
"text/html" = "firefox.desktop";
|
||||
"x-scheme-handler/http" = "firefox.desktop";
|
||||
"x-scheme-handler/https" = "firefox.desktop";
|
||||
"x-scheme-handler/about" = "firefox.desktop";
|
||||
"x-scheme-handler/unknown" = "firefox.desktop";
|
||||
|
||||
# Documents
|
||||
"application/pdf" = "okular.desktop";
|
||||
"text/plain" = "kate.desktop";
|
||||
"text/x-tex" = "kate.desktop";
|
||||
"text/x-c" = "kate.desktop";
|
||||
"text/x-python" = "kate.desktop";
|
||||
"application/x-shellscript" = "kate.desktop";
|
||||
|
||||
# Images
|
||||
"image/png" = "gwenview.desktop";
|
||||
"image/jpeg" = "gwenview.desktop";
|
||||
"image/jpg" = "gwenview.desktop";
|
||||
"image/gif" = "gwenview.desktop";
|
||||
"image/bmp" = "gwenview.desktop";
|
||||
"image/tiff" = "gwenview.desktop";
|
||||
"image/webp" = "gwenview.desktop";
|
||||
|
||||
# Archives
|
||||
"application/zip" = "ark.desktop";
|
||||
"application/x-tar" = "ark.desktop";
|
||||
"application/x-compressed-tar" = "ark.desktop";
|
||||
"application/x-7z-compressed" = "ark.desktop";
|
||||
"application/x-rar" = "ark.desktop";
|
||||
|
||||
# Audio
|
||||
"audio/mpeg" = "elisa.desktop";
|
||||
"audio/mp4" = "elisa.desktop";
|
||||
"audio/flac" = "elisa.desktop";
|
||||
"audio/ogg" = "elisa.desktop";
|
||||
"audio/wav" = "elisa.desktop";
|
||||
|
||||
# Email
|
||||
"message/rfc822" = "kmail.desktop";
|
||||
"x-scheme-handler/mailto" = "kmail.desktop";
|
||||
|
||||
# Calendar
|
||||
"text/calendar" = "korganizer.desktop";
|
||||
"application/x-vnd.akonadi.calendar.event" = "korganizer.desktop";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Fix for KDE applications.menu file issue on Plasma 6
|
||||
# KDE still looks for applications.menu but Plasma 6 renamed it to plasma-applications.menu
|
||||
xdg.configFile."menus/applications.menu".source = "${pkgs.kdePackages.plasma-workspace}/etc/xdg/menus/plasma-applications.menu";
|
||||
|
||||
# Note: modules must be imported at top-level home config
|
||||
};
|
||||
}
|
||||
116
home/roles/development/default.nix
Normal file
@@ -0,0 +1,116 @@
|
||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.development;
|
||||
|
||||
# Fetch the claude-plugins repository (for humanlayer commands/agents)
|
||||
# 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
|
||||
{
|
||||
options.home.roles.development = {
|
||||
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 {
|
||||
home.packages = [
|
||||
globalInputs.beads.packages.${system}.default
|
||||
pkgs.unstable.claude-code
|
||||
pkgs.unstable.claude-code-router
|
||||
pkgs.unstable.codex
|
||||
|
||||
# Custom packages
|
||||
pkgs.custom.tea-rbw
|
||||
pkgs.custom.perles
|
||||
];
|
||||
|
||||
# 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
|
||||
|
||||
# Copy local skills from this repo
|
||||
for file in ${./skills}/*.md; do
|
||||
if [ -f "$file" ]; then
|
||||
filename=$(basename "$file" .md)
|
||||
dest="$HOME/.claude/commands/''${filename}.md"
|
||||
cp "$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)"
|
||||
} + local skills"
|
||||
'';
|
||||
|
||||
# Set up beads Claude Code integration (hooks for SessionStart/PreCompact)
|
||||
# This uses the CLI + hooks approach which is recommended over MCP for Claude Code
|
||||
home.activation.claudeCodeBeadsSetup = lib.hm.dag.entryAfter ["writeBoundary" "claudeCodeCommands"] ''
|
||||
# Run bd setup claude to install hooks into ~/.claude/settings.json
|
||||
# This is idempotent - safe to run multiple times
|
||||
${globalInputs.beads.packages.${system}.default}/bin/bd setup claude 2>/dev/null || true
|
||||
|
||||
$DRY_RUN_CMD echo "Claude Code beads integration configured (hooks installed)"
|
||||
'';
|
||||
|
||||
# Note: modules must be imported at top-level home config
|
||||
};
|
||||
}
|
||||
198
home/roles/development/skills/parallel_beads.md
Normal file
@@ -0,0 +1,198 @@
|
||||
---
|
||||
description: Orchestrate parallel bead processing with worktrees, PRs, and reviews
|
||||
---
|
||||
|
||||
# Parallel Beads Workflow
|
||||
|
||||
This skill orchestrates parallel bead processing using subagents. Each bead gets its own worktree, implementation, PR, and review.
|
||||
|
||||
## Phase 1: Selection
|
||||
|
||||
1. **Get ready beads**: Run `bd ready` to list all beads with no blockers
|
||||
2. **Present selection**: Use `AskUserQuestion` with `multiSelect: true` to let the user choose which beads to work on
|
||||
- Include bead ID and title for each option
|
||||
- Allow selection of multiple beads
|
||||
|
||||
Example:
|
||||
```
|
||||
AskUserQuestion with:
|
||||
- question: "Which beads do you want to work on in parallel?"
|
||||
- multiSelect: true
|
||||
- options from bd ready output
|
||||
```
|
||||
|
||||
## Phase 2: Parallel Implementation
|
||||
|
||||
For each selected bead, launch a subagent using the Task tool. All subagents should be launched in parallel (single message with multiple Task tool calls).
|
||||
|
||||
### Subagent Instructions Template
|
||||
|
||||
Each implementation subagent should receive these instructions:
|
||||
|
||||
```
|
||||
Work on bead [BEAD_ID]: [BEAD_TITLE]
|
||||
|
||||
1. **Create worktree**:
|
||||
- Branch name: `bead/[BEAD_ID]`
|
||||
- Worktree path: `~/wt/[REPO_NAME]/[BEAD_ID]`
|
||||
- Command: `git worktree add -b bead/[BEAD_ID] ~/wt/[REPO_NAME]/[BEAD_ID]`
|
||||
|
||||
2. **Review the bead requirements**:
|
||||
- Run `bd show [BEAD_ID]` to understand the acceptance criteria
|
||||
- Note any external issue references (GitHub issues, Linear tickets, etc.)
|
||||
|
||||
3. **Implement the changes**:
|
||||
- Work in the worktree directory
|
||||
- Complete all acceptance criteria listed in the bead
|
||||
- Run any relevant tests or checks
|
||||
|
||||
4. **Commit and push**:
|
||||
- Stage all changes: `git add -A`
|
||||
- Create a descriptive commit message
|
||||
- Push the branch: `git push -u origin bead/[BEAD_ID]`
|
||||
|
||||
5. **Create a PR**:
|
||||
- Detect hosting provider from origin URL: `git remote get-url origin`
|
||||
- If URL contains `github.com`, use `gh`; otherwise use `tea` (Gitea/Forgejo)
|
||||
- PR title: "[BEAD_ID] [BEAD_TITLE]"
|
||||
- PR body must include:
|
||||
- Reference to bead ID: "Implements bead: [BEAD_ID]"
|
||||
- Any external issue references from the bead (e.g., "Closes #123")
|
||||
- Summary of changes
|
||||
- For GitHub (`gh`):
|
||||
```bash
|
||||
gh pr create --title "[BEAD_ID] [BEAD_TITLE]" --body "$(cat <<'EOF'
|
||||
## Summary
|
||||
[Brief description of changes]
|
||||
|
||||
## Bead Reference
|
||||
Implements bead: [BEAD_ID]
|
||||
|
||||
## External Issues
|
||||
[Any linked issues from the bead]
|
||||
|
||||
## Changes
|
||||
- [List of changes made]
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
- For Gitea (`tea`):
|
||||
```bash
|
||||
tea pr create --head bead/[BEAD_ID] --base main \
|
||||
--title "[BEAD_ID] [BEAD_TITLE]" \
|
||||
--description "## Summary
|
||||
[Brief description of changes]
|
||||
|
||||
## Bead Reference
|
||||
Implements bead: [BEAD_ID]
|
||||
|
||||
## External Issues
|
||||
[Any linked issues from the bead]
|
||||
|
||||
## Changes
|
||||
- [List of changes made]"
|
||||
```
|
||||
|
||||
6. **Report results**:
|
||||
- Return: PR URL, bead ID, success/failure status
|
||||
- If blocked or unable to complete, explain what's blocking progress
|
||||
```
|
||||
|
||||
### Launching Subagents
|
||||
|
||||
Use `subagent_type: "general-purpose"` for implementation subagents. Launch all selected beads' subagents in a single message for parallel execution:
|
||||
|
||||
```
|
||||
<Task calls for each selected bead - all in one message>
|
||||
```
|
||||
|
||||
Collect results from all subagents before proceeding.
|
||||
|
||||
## Phase 3: Parallel Review
|
||||
|
||||
After all implementation subagents complete, launch review subagents for each PR.
|
||||
|
||||
### Review Subagent Instructions Template
|
||||
|
||||
```
|
||||
Review PR for bead [BEAD_ID]
|
||||
|
||||
1. **Detect hosting provider**: Run `git remote get-url origin` - if it contains `github.com` use `gh`, otherwise use `tea`
|
||||
|
||||
2. **Read the PR**:
|
||||
- For GitHub: `gh pr view [PR_NUMBER] --json title,body,additions,deletions,files`
|
||||
- For Gitea: `tea pr view [PR_NUMBER]`
|
||||
- View the diff: `git diff main...bead/[BEAD_ID]`
|
||||
|
||||
3. **Review against acceptance criteria**:
|
||||
- Run `bd show [BEAD_ID]` to get the acceptance criteria
|
||||
- Verify each criterion is addressed
|
||||
|
||||
4. **Leave review comments**:
|
||||
- For GitHub: `gh pr review [PR_NUMBER] --comment --body "[COMMENTS]"`
|
||||
- For Gitea: `tea pr review [PR_NUMBER] --comment "[COMMENTS]"`
|
||||
- Include:
|
||||
- Acceptance criteria checklist (which are met, which might be missing)
|
||||
- Code quality observations
|
||||
- Suggestions for improvement
|
||||
|
||||
5. **Return summary**:
|
||||
- Overall assessment (ready to merge / needs changes)
|
||||
- Key findings
|
||||
```
|
||||
|
||||
Launch all review subagents in parallel.
|
||||
|
||||
## Phase 4: Cleanup and Summary
|
||||
|
||||
After reviews complete:
|
||||
|
||||
1. **Clean up worktrees**:
|
||||
```bash
|
||||
git worktree remove ~/wt/[REPO_NAME]/[BEAD_ID] --force
|
||||
```
|
||||
Do this for each bead's worktree.
|
||||
|
||||
2. **Provide final summary**:
|
||||
Present a table or list with:
|
||||
- Bead ID
|
||||
- PR URL
|
||||
- Status (success / failed / blocked)
|
||||
- Review summary
|
||||
- Any failures or blockers encountered
|
||||
|
||||
Example output:
|
||||
```
|
||||
## Parallel Beads Summary
|
||||
|
||||
| Bead | PR | Status | Review |
|
||||
|------|-----|--------|--------|
|
||||
| beads-abc | #123 | Success | Approved |
|
||||
| beads-xyz | #124 | Success | Needs changes |
|
||||
| beads-123 | - | Failed | Blocked by missing dependency |
|
||||
|
||||
### Failures/Blockers
|
||||
- beads-123: Could not complete because [reason]
|
||||
|
||||
### Next Steps
|
||||
- Review PRs that need changes
|
||||
- Address blockers for failed beads
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
- **Subagent failures**: If a subagent fails or times out, note it in the summary but continue with other beads
|
||||
- **PR creation failures**: Report the error but continue with reviews of successful PRs
|
||||
- **Worktree conflicts**: If a worktree already exists, ask the user if they want to remove it or skip that bead
|
||||
|
||||
## Resource Limits
|
||||
|
||||
- Consider limiting concurrent subagents to 3-5 to avoid overwhelming system resources
|
||||
- If user selects more beads than the limit, process them in batches
|
||||
|
||||
## Notes
|
||||
|
||||
- This workflow integrates with the beads system (`bd` commands)
|
||||
- Worktrees are created in `~/wt/[REPO_NAME]/` by convention
|
||||
- Each bead gets its own isolated branch and worktree
|
||||
- PRs automatically reference the bead ID for traceability
|
||||
77
home/roles/emacs/default.nix
Normal file
@@ -0,0 +1,77 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.emacs;
|
||||
|
||||
doomEmacs = pkgs.fetchFromGitHub {
|
||||
owner = "doomemacs";
|
||||
repo = "doomemacs";
|
||||
rev = "38d94da67dc84897a4318714dcc48494c016d8c4";
|
||||
sha256 = "sha256-Uc6qONH3jjUVDgW+pPBCGC7mh88ZY05u1y37fQrsxq0=";
|
||||
};
|
||||
|
||||
# Shared emacs packages
|
||||
emacsPackages = epkgs: [
|
||||
epkgs.vterm
|
||||
epkgs.treesit-grammars.with-all-grammars
|
||||
];
|
||||
|
||||
# Default emacs configuration with vterm support
|
||||
defaultEmacsPackage =
|
||||
if pkgs.stdenv.isDarwin
|
||||
then pkgs.emacs-macport.pkgs.withPackages emacsPackages
|
||||
else pkgs.emacs.pkgs.withPackages emacsPackages;
|
||||
in
|
||||
{
|
||||
options.home.roles.emacs = {
|
||||
enable = mkEnableOption "Doom Emacs with vterm and tree-sitter support";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [
|
||||
pkgs.emacs-all-the-icons-fonts
|
||||
pkgs.fira-code
|
||||
pkgs.fontconfig
|
||||
pkgs.graphviz
|
||||
pkgs.isort
|
||||
pkgs.nerd-fonts.fira-code
|
||||
pkgs.nerd-fonts.droid-sans-mono
|
||||
pkgs.nil # nix lsp language server
|
||||
pkgs.nixfmt-rfc-style
|
||||
(pkgs.ripgrep.override {withPCRE2 = true;})
|
||||
pkgs.pipenv
|
||||
pkgs.poetry
|
||||
pkgs.python3
|
||||
];
|
||||
|
||||
programs.emacs = {
|
||||
enable = true;
|
||||
package = defaultEmacsPackage;
|
||||
};
|
||||
|
||||
fonts.fontconfig.enable = true;
|
||||
|
||||
# Mount emacs and tree-sitter grammars from nix store
|
||||
home.file = {
|
||||
"${config.xdg.configHome}/emacs".source = doomEmacs;
|
||||
};
|
||||
|
||||
home.sessionPath = [
|
||||
"${config.xdg.configHome}/emacs/bin"
|
||||
];
|
||||
|
||||
home.sessionVariables = {
|
||||
DOOMDIR = "${config.xdg.configHome}/doom";
|
||||
DOOMLOCALDIR = "${config.xdg.dataHome}/doom";
|
||||
};
|
||||
|
||||
# TODO: Use mkOutOfStoreSymlink instead?
|
||||
home.activation.doomConfig = lib.hm.dag.entryAfter ["writeBoundary"] ''
|
||||
# Always remove and recreate the symlink to ensure it points to the source directory
|
||||
rm -rf "${config.xdg.configHome}/doom"
|
||||
ln -sf "${config.home.homeDirectory}/nixos-configs/home/roles/emacs/doom" "${config.xdg.configHome}/doom"
|
||||
'';
|
||||
};
|
||||
}
|
||||
250
home/roles/emacs/doom/config.el
Normal file
@@ -0,0 +1,250 @@
|
||||
;;; $DOOMDIR/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Place your private configuration here! Remember, you do not need to run 'doom
|
||||
;; sync' after modifying this file!
|
||||
|
||||
|
||||
;; Some functionality uses this to identify you, e.g. GPG configuration, email
|
||||
;; clients, file templates and snippets. It is optional.
|
||||
;; (setq user-full-name "John Doe"
|
||||
;; user-mail-address "john@doe.com")
|
||||
|
||||
;; Doom exposes five (optional) variables for controlling fonts in Doom:
|
||||
;;
|
||||
;; - `doom-font' -- the primary font to use
|
||||
;; - `doom-variable-pitch-font' -- a non-monospace font (where applicable)
|
||||
;; - `doom-big-font' -- used for `doom-big-font-mode'; use this for
|
||||
;; presentations or streaming.
|
||||
;; - `doom-symbol-font' -- for symbols
|
||||
;; - `doom-serif-font' -- for the `fixed-pitch-serif' face
|
||||
;;
|
||||
;; See 'C-h v doom-font' for documentation and more examples of what they
|
||||
;; accept. For example:
|
||||
;;
|
||||
;;(setq doom-font (font-spec :family "Fira Code" :size 12 :weight 'semi-light)
|
||||
;; doom-variable-pitch-font (font-spec :family "Fira Sans" :size 13))
|
||||
;;
|
||||
;; If you or Emacs can't find your font, use 'M-x describe-font' to look them
|
||||
;; up, `M-x eval-region' to execute elisp code, and 'M-x doom/reload-font' to
|
||||
;; refresh your font settings. If Emacs still can't find your font, it likely
|
||||
;; wasn't installed correctly. Font issues are rarely Doom issues!
|
||||
(setq doom-font (font-spec :family "Fira Code" :size 16))
|
||||
|
||||
;; Auto-install nerd-icons fonts if they're missing
|
||||
(defun my/ensure-nerd-icons-fonts ()
|
||||
"Check if nerd-icons fonts are installed and install them if missing."
|
||||
(when (display-graphic-p)
|
||||
(unless (find-font (font-spec :name "Symbols Nerd Font Mono"))
|
||||
(when (fboundp 'nerd-icons-install-fonts)
|
||||
(nerd-icons-install-fonts t)))))
|
||||
|
||||
(add-hook 'doom-init-ui-hook #'my/ensure-nerd-icons-fonts)
|
||||
|
||||
;; There are two ways to load a theme. Both assume the theme is installed and
|
||||
;; available. You can either set `doom-theme' or manually load a theme with the
|
||||
;; `load-theme' function. This is the default:
|
||||
(setq doom-theme 'doom-tokyo-night)
|
||||
|
||||
;; This determines the style of line numbers in effect. If set to `nil', line
|
||||
;; numbers are disabled. For relative line numbers, set this to `relative'.
|
||||
(setq display-line-numbers-type t)
|
||||
|
||||
;; If you use `org' and don't want your org files in the default location below,
|
||||
;; change `org-directory'. It must be set before org loads!
|
||||
(setq org-directory "~/org/")
|
||||
(after! org
|
||||
(setq org-agenda-span 'week
|
||||
org-agenda-start-with-log-mode t
|
||||
my-agenda-dirs '("projects" "roam")
|
||||
org-agenda-files (cons org-directory (mapcan (lambda (x) (directory-files-recursively
|
||||
(expand-file-name x org-directory)
|
||||
"\.org$"))
|
||||
my-agenda-dirs))
|
||||
org-log-done 'time
|
||||
org-agenda-custom-commands '(("n" "Agenda"
|
||||
((agenda "")
|
||||
(tags-todo "-someday-recurring")))
|
||||
("s" "Someday Items"
|
||||
((tags-todo "+someday"))))
|
||||
org-todo-keywords '((sequence "TODO(t)" "IN-PROGRESS(p)" "WAIT(w)" "|" "DONE(d)" "KILL(k)"))
|
||||
org-journal-file-type 'weekly
|
||||
org-journal-file-format "%Y-%m-%d.org"
|
||||
org-capture-templates
|
||||
'(("t" "Todo" entry (file+headline "~/org/todo.org" "Inbox")
|
||||
"* TODO %? \n %i \n%a" :prepend t)))
|
||||
;; Make blocked tasks more visible in agenda (they have subtasks to do!)
|
||||
(custom-set-faces!
|
||||
'(org-agenda-dimmed-todo-face :foreground "#bb9af7" :weight normal)))
|
||||
|
||||
(map! :after org-agenda
|
||||
:map org-agenda-mode-map
|
||||
:localleader
|
||||
(:prefix ("v" . "view")
|
||||
"d" #'org-agenda-day-view
|
||||
"w" #'org-agenda-week-view))
|
||||
|
||||
;; (use-package! org-caldav
|
||||
;; :defer t
|
||||
;; :config
|
||||
;; (setq org-caldav-url "https://nextcloud.johnogle.info/remote.php/dav/calendars/johno"
|
||||
;; org-caldav-calendar-id "personal"
|
||||
;; org-icalendar-timezone "America/Los_Angeles"
|
||||
;; org-caldav-inbox "~/org/calendar.org"
|
||||
;; org-caldav-files nil
|
||||
;; org-caldav-sync-direction 'cal->org))
|
||||
|
||||
(defun my/get-rbw-password (alias)
|
||||
"Return the password for ALIAS via rbw, unlocking the vault only if needed."
|
||||
(let* ((cmd (format "rbw get %s 2>&1" alias))
|
||||
(output (shell-command-to-string cmd)))
|
||||
(string-trim output)))
|
||||
|
||||
(after! gptel
|
||||
:config
|
||||
(setq! gptel-api-key (my/get-rbw-password "openai-api-key-chatgpt-el")
|
||||
gptel-default-mode 'org-mode
|
||||
gptel-use-tools t
|
||||
gptel-confirm-tool-calls 'always
|
||||
gptel-include-reasoning 'ignore
|
||||
gptel-model "qwen3:30b")
|
||||
|
||||
;; Set default backend to be Ollama-Local
|
||||
(setq! gptel-backend
|
||||
(gptel-make-ollama "Ollama-Local"
|
||||
:host "localhost:11434"
|
||||
:stream t
|
||||
:models '(deepseek-r1 deepseek-r1-fullctx qwen3:30b qwen3:4b llama3.1 qwen2.5-coder mistral-nemo gpt-oss)))
|
||||
|
||||
;; Define custom tools
|
||||
(gptel-make-tool
|
||||
:name "run_shell_command"
|
||||
:description "Execute shell commands and return output. Use this to run system commands, check file contents, or perform system operations."
|
||||
:function (lambda (command)
|
||||
(condition-case err
|
||||
(shell-command-to-string command)
|
||||
(error (format "Error running command: %s" (error-message-string err)))))
|
||||
:args (list '(:name "command" :type "string" :description "Shell command to execute")))
|
||||
|
||||
(gptel-make-tool
|
||||
:name "read_file"
|
||||
:description "Read the contents of a file and return as text"
|
||||
:function (lambda (filepath)
|
||||
(condition-case err
|
||||
(with-temp-buffer
|
||||
(insert-file-contents (expand-file-name filepath))
|
||||
(buffer-string))
|
||||
(error (format "Error reading file %s: %s" filepath (error-message-string err)))))
|
||||
:args (list '(:name "filepath" :type "string" :description "Path to the file to read")))
|
||||
|
||||
(gptel-make-tool
|
||||
:name "list_directory"
|
||||
:description "List contents of a directory"
|
||||
:function (lambda (dirpath)
|
||||
(condition-case err
|
||||
(mapconcat 'identity
|
||||
(directory-files (expand-file-name dirpath) nil "^[^.]")
|
||||
"\n")
|
||||
(error (format "Error listing directory %s: %s" dirpath (error-message-string err)))))
|
||||
:args (list '(:name "dirpath" :type "string" :description "Directory path to list"))))
|
||||
|
||||
(use-package! claude-code-ide
|
||||
:commands (claude-code-ide-menu claude-code-ide-open-here)
|
||||
:init
|
||||
(map! :leader
|
||||
(:prefix ("o" . "open")
|
||||
:desc "Claude Code IDE" "c" #'claude-code-ide-menu))
|
||||
:config
|
||||
(claude-code-ide-emacs-tools-setup)
|
||||
(setq claude-code-ide-cli-path "claude"
|
||||
claude-code-ide-cli-extra-flags "--dangerously-skip-permissions"
|
||||
claude-code-ide-focus-claude-after-ediff t
|
||||
claude-code-ide-focus-on-open t
|
||||
claude-code-ide-show-claude-window-in-ediff t
|
||||
claude-code-ide-switch-tab-on-ediff t
|
||||
claude-code-ide-use-ide-diff t
|
||||
claude-code-ide-use-side-window t
|
||||
claude-code-ide-window-height 20
|
||||
claude-code-ide-window-side 'right
|
||||
claude-code-ide-window-width 90))
|
||||
|
||||
(after! gptel
|
||||
(require 'gptel-tool-library)
|
||||
(setq gptel-tool-library-use-maybe-safe t
|
||||
gptel-tool-library-use-unsafe t)
|
||||
(dolist (module '("bbdb" "buffer" "elisp" "emacs" "gnus" "os" "search-and-replace" "url"))
|
||||
(gptel-tool-library-load-module module)))
|
||||
|
||||
;; mu4e email configuration
|
||||
;; Add NixOS mu4e to load-path (installed via mu.mu4e package)
|
||||
(when-let ((mu-path (executable-find "mu")))
|
||||
(add-to-list 'load-path
|
||||
(expand-file-name "../share/emacs/site-lisp/mu4e"
|
||||
(file-name-directory mu-path))))
|
||||
|
||||
(after! mu4e
|
||||
;; User identity
|
||||
(setq user-mail-address "john@ogle.fyi"
|
||||
user-full-name "John Ogle")
|
||||
|
||||
;; Maildir location (no account prefix - single account)
|
||||
(setq mu4e-maildir "~/Mail"
|
||||
mu4e-attachment-dir "~/Downloads")
|
||||
|
||||
;; Folder config (matches ~/Mail/INBOX, ~/Mail/Sent, etc.)
|
||||
(setq mu4e-sent-folder "/Sent"
|
||||
mu4e-drafts-folder "/Drafts"
|
||||
mu4e-trash-folder "/Trash"
|
||||
mu4e-refile-folder "/Archive")
|
||||
|
||||
;; Shortcuts for common folders
|
||||
(setq mu4e-maildir-shortcuts
|
||||
'((:maildir "/INBOX" :key ?i)
|
||||
(:maildir "/Archive" :key ?a)
|
||||
(:maildir "/Sent" :key ?s)
|
||||
(:maildir "/Trash" :key ?t)))
|
||||
|
||||
;; Behavior settings
|
||||
(setq mu4e-get-mail-command "mbsync -a"
|
||||
mu4e-update-interval 300 ; 5 minutes (matches systemd timer)
|
||||
mu4e-change-filenames-when-moving t ; required for mbsync
|
||||
mu4e-headers-date-format "%Y-%m-%d"
|
||||
mu4e-headers-time-format "%H:%M")
|
||||
|
||||
;; Sending mail via msmtp
|
||||
(setq message-send-mail-function 'message-send-mail-with-sendmail
|
||||
sendmail-program (executable-find "msmtp")
|
||||
message-sendmail-envelope-from 'header
|
||||
mail-envelope-from 'header
|
||||
mail-specify-envelope-from t))
|
||||
|
||||
;; Whenever you reconfigure a package, make sure to wrap your config in an
|
||||
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
|
||||
;;
|
||||
;; (after! PACKAGE
|
||||
;; (setq x y))
|
||||
;;
|
||||
;; The exceptions to this rule:
|
||||
;;
|
||||
;; - Setting file/directory variables (like `org-directory')
|
||||
;; - Setting variables which explicitly tell you to set them before their
|
||||
;; package is loaded (see 'C-h v VARIABLE' to look up their documentation).
|
||||
;; - Setting doom variables (which start with 'doom-' or '+').
|
||||
;;
|
||||
;; Here are some additional functions/macros that will help you configure Doom.
|
||||
;;
|
||||
;; - `load!' for loading external *.el files relative to this one
|
||||
;; - `use-package!' for configuring packages
|
||||
;; - `after!' for running code after a package has loaded
|
||||
;; - `add-load-path!' for adding directories to the `load-path', relative to
|
||||
;; this file. Emacs searches the `load-path' when you load packages with
|
||||
;; `require' or `use-package'.
|
||||
;; - `map!' for binding new keys
|
||||
;;
|
||||
;; To get information about any of these functions/macros, move the cursor over
|
||||
;; the highlighted symbol at press 'K' (non-evil users must press 'C-c c k').
|
||||
;; This will open documentation for it, including demos of how they are used.
|
||||
;; Alternatively, use `C-h o' to look up a symbol (functions, variables, faces,
|
||||
;; etc).
|
||||
;;
|
||||
;; You can also try 'gd' (or 'C-c c d') to jump to their definition and see how
|
||||
;; they are implemented.
|
||||
@@ -33,7 +33,7 @@
|
||||
doom ; what makes DOOM look the way it does
|
||||
doom-dashboard ; a nifty splash screen for Emacs
|
||||
;;doom-quit ; DOOM quit-message prompts when you quit Emacs
|
||||
(emoji +unicode) ; 🙂
|
||||
;;(emoji +unicode) ; 🙂
|
||||
hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW
|
||||
;;indent-guides ; highlighted indent columns
|
||||
;;ligatures ; ligatures and symbols to make your code pretty again
|
||||
@@ -45,7 +45,7 @@
|
||||
(popup +defaults) ; tame sudden yet inevitable temporary windows
|
||||
;;tabs ; a tab bar for Emacs
|
||||
;;treemacs ; a project drawer, like neotree but cooler
|
||||
;;unicode ; extended unicode support for various languages
|
||||
unicode ; extended unicode support for various languages
|
||||
(vc-gutter +pretty) ; vcs diff in the fringe
|
||||
vi-tilde-fringe ; fringe tildes to mark beyond EOB
|
||||
;;window-select ; visually switch windows
|
||||
@@ -59,7 +59,7 @@
|
||||
;;(format +onsave) ; automated prettiness
|
||||
;;god ; run Emacs commands without modifier keys
|
||||
;;lispy ; vim for lisp, for people who don't like vim
|
||||
;;multiple-cursors ; editing in many places at once
|
||||
multiple-cursors ; editing in many places at once
|
||||
;;objed ; text object editing for the innocent
|
||||
;;parinfer ; turn lisp into python, sort of
|
||||
;;rotate-text ; cycle region at point between text candidates
|
||||
@@ -77,7 +77,7 @@
|
||||
;;eshell ; the elisp shell that works everywhere
|
||||
;;shell ; simple shell REPL for Emacs
|
||||
;;term ; basic terminal emulator for Emacs
|
||||
;;vterm ; the best terminal emulation in Emacs
|
||||
vterm ; the best terminal emulation in Emacs
|
||||
|
||||
:checkers
|
||||
syntax ; tasing you for every semicolon you forget
|
||||
@@ -94,6 +94,7 @@
|
||||
;;editorconfig ; let someone else argue about tabs vs spaces
|
||||
;;ein ; tame Jupyter notebooks with emacs
|
||||
(eval +overlay) ; run code, run (also, repls)
|
||||
llm ; When I said you needed friends, I didn't mean...
|
||||
lookup ; navigate your code and its documentation
|
||||
lsp ; M-x vscode
|
||||
magit ; a git porcelain for Emacs
|
||||
@@ -108,7 +109,7 @@
|
||||
|
||||
:os
|
||||
(:if (featurep :system 'macos) macos) ; improve compatibility with macOS
|
||||
;;tty ; improve the terminal Emacs experience
|
||||
tty ; improve the terminal Emacs experience
|
||||
|
||||
:lang
|
||||
;;agda ; types of types of types of types...
|
||||
@@ -149,7 +150,7 @@
|
||||
;;lua ; one-based indices? one-based indices
|
||||
markdown ; writing docs for people to ignore
|
||||
;;nim ; python + lisp at the speed of c
|
||||
(nix +tree-sitter +lsp) ; I hereby declare "nix geht mehr!"
|
||||
(nix +tree-sitter) ; I hereby declare "nix geht mehr!"
|
||||
;;ocaml ; an objective camel
|
||||
(org +roam2) ; organize your plain life in plain text
|
||||
;;php ; perl's insecure younger brother
|
||||
@@ -175,7 +176,7 @@
|
||||
;;zig ; C, but simpler
|
||||
|
||||
:email
|
||||
;;(mu4e +org +gmail)
|
||||
(mu4e +org)
|
||||
;;notmuch
|
||||
;;(wanderlust +gmail)
|
||||
|
||||
@@ -50,3 +50,12 @@
|
||||
;; (unpin! t)
|
||||
|
||||
;; (package! org-caldav)
|
||||
|
||||
(package! gptel :recipe (:nonrecursive t))
|
||||
|
||||
(package! claude-code-ide
|
||||
:recipe (:host github :repo "manzaltu/claude-code-ide.el"))
|
||||
|
||||
(package! gptel-tool-library
|
||||
:recipe (:host github :repo "aard-fi/gptel-tool-library"
|
||||
:files ("*.el")))
|
||||
123
home/roles/email/default.nix
Normal file
@@ -0,0 +1,123 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.email;
|
||||
in
|
||||
{
|
||||
options.home.roles.email = {
|
||||
enable = mkEnableOption "Enable email with mu4e, mbsync, and msmtp";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
isync # provides mbsync for IMAP sync
|
||||
msmtp # for SMTP sending
|
||||
mu # email indexer for mu4e
|
||||
mu.mu4e # mu4e elisp files for Emacs
|
||||
openssl # for certificate management
|
||||
];
|
||||
|
||||
# Ensure Mail directory exists
|
||||
home.file."Mail/.keep".text = "";
|
||||
|
||||
# mbsync configuration
|
||||
home.file.".mbsyncrc".text = ''
|
||||
# IMAP Account Configuration
|
||||
IMAPAccount proton
|
||||
Host proton.johnogle.info
|
||||
Port 143
|
||||
User john@ogle.fyi
|
||||
PassCmd "${pkgs.rbw}/bin/rbw get proton.johnogle.info"
|
||||
TLSType STARTTLS
|
||||
AuthMechs PLAIN
|
||||
|
||||
# Remote Storage
|
||||
IMAPStore proton-remote
|
||||
Account proton
|
||||
|
||||
# Local Storage
|
||||
MaildirStore proton-local
|
||||
Path ~/Mail/
|
||||
Inbox ~/Mail/INBOX
|
||||
SubFolders Verbatim
|
||||
|
||||
# Channel Configuration - Main (excludes Sent)
|
||||
Channel proton-main
|
||||
Far :proton-remote:
|
||||
Near :proton-local:
|
||||
Patterns * !Sent
|
||||
Create Both
|
||||
Expunge Both
|
||||
SyncState *
|
||||
|
||||
# Channel Configuration - Sent (pull only)
|
||||
Channel proton-sent
|
||||
Far :proton-remote:Sent
|
||||
Near :proton-local:Sent
|
||||
Create Near
|
||||
Expunge Near
|
||||
Sync Pull
|
||||
SyncState *
|
||||
|
||||
# Group both channels
|
||||
Group proton
|
||||
Channel proton-main
|
||||
Channel proton-sent
|
||||
'';
|
||||
|
||||
# msmtp configuration
|
||||
home.file.".msmtprc".text = ''
|
||||
# Default settings
|
||||
defaults
|
||||
auth plain
|
||||
tls on
|
||||
tls_starttls on
|
||||
tls_trust_file /etc/ssl/certs/ca-certificates.crt
|
||||
logfile ${config.home.homeDirectory}/.msmtp.log
|
||||
|
||||
# Proton mail account
|
||||
account proton
|
||||
host proton.johnogle.info
|
||||
port 25
|
||||
from john@ogle.fyi
|
||||
user john@ogle.fyi
|
||||
passwordeval rbw get proton.johnogle.info
|
||||
|
||||
# Set default account
|
||||
account default : proton
|
||||
'';
|
||||
|
||||
# Systemd service for mail sync
|
||||
systemd.user.services.mbsync = {
|
||||
Unit = {
|
||||
Description = "Mailbox synchronization service";
|
||||
After = [ "network-online.target" ];
|
||||
Wants = [ "network-online.target" ];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.bash}/bin/bash -c 'mkdir -p ~/Mail && ${pkgs.isync}/bin/mbsync -a && (${pkgs.mu}/bin/mu info >/dev/null 2>&1 || ${pkgs.mu}/bin/mu init --maildir ~/Mail --personal-address=john@ogle.fyi) && ${pkgs.mu}/bin/mu index'";
|
||||
Environment = "PATH=${pkgs.rbw}/bin:${pkgs.coreutils}/bin";
|
||||
StandardOutput = "journal";
|
||||
StandardError = "journal";
|
||||
};
|
||||
};
|
||||
|
||||
# Systemd timer for automatic sync
|
||||
systemd.user.timers.mbsync = {
|
||||
Unit = {
|
||||
Description = "Mailbox synchronization timer";
|
||||
};
|
||||
Timer = {
|
||||
OnBootSec = "2min";
|
||||
OnUnitActiveSec = "5min";
|
||||
Unit = "mbsync.service";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
20
home/roles/gaming/default.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.gaming;
|
||||
in
|
||||
{
|
||||
options.home.roles.gaming = {
|
||||
enable = mkEnableOption "Enable gaming applications and tools";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
# Gaming applications would go here
|
||||
# This role is created for future expansion
|
||||
# moonlight-qt is currently in media role but could be moved here
|
||||
];
|
||||
};
|
||||
}
|
||||
496
home/roles/i3+sway/default.nix
Normal file
@@ -0,0 +1,496 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.i3_sway;
|
||||
wallpaperConfig = import ../../wallpapers;
|
||||
currentWallpaper = builtins.elemAt wallpaperConfig.wallpapers wallpaperConfig.currentIndex;
|
||||
|
||||
shared_config = recursiveUpdate rec {
|
||||
modifier = "Mod4";
|
||||
terminal = "ghostty";
|
||||
defaultWorkspace = "workspace number 1";
|
||||
|
||||
keybindings = {
|
||||
"${shared_config.modifier}+Return" = "exec ${terminal}";
|
||||
"${shared_config.modifier}+Shift+Return" = "exec ${cfg.browser}";
|
||||
"${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}+j" = "focus down";
|
||||
"${shared_config.modifier}+k" = "focus up";
|
||||
"${shared_config.modifier}+l" = "focus right";
|
||||
|
||||
"${shared_config.modifier}+Shift+h" = "move left";
|
||||
"${shared_config.modifier}+Shift+j" = "move down";
|
||||
"${shared_config.modifier}+Shift+k" = "move up";
|
||||
"${shared_config.modifier}+Shift+l" = "move right";
|
||||
|
||||
"${shared_config.modifier}+Left" = "focus left";
|
||||
"${shared_config.modifier}+Down" = "focus down";
|
||||
"${shared_config.modifier}+Up" = "focus up";
|
||||
"${shared_config.modifier}+Right" = "focus right";
|
||||
|
||||
"${shared_config.modifier}+Shift+Left" = "move left";
|
||||
"${shared_config.modifier}+Shift+Down" = "move down";
|
||||
"${shared_config.modifier}+Shift+Up" = "move up";
|
||||
"${shared_config.modifier}+Shift+Right" = "move right";
|
||||
|
||||
#"${shared_config.modifier}+h" = "split h";
|
||||
"${shared_config.modifier}+v" = "split v";
|
||||
"${shared_config.modifier}+Shift+f" = "fullscreen toggle";
|
||||
|
||||
"${shared_config.modifier}+s" = "layout stacking";
|
||||
"${shared_config.modifier}+w" = "layout tabbed";
|
||||
"${shared_config.modifier}+e" = "layout toggle split";
|
||||
|
||||
"${shared_config.modifier}+Shift+space" = "floating toggle";
|
||||
"${shared_config.modifier}+space" = "focus mode_toggle";
|
||||
|
||||
"${shared_config.modifier}+Shift+minus" = "move scratchpad";
|
||||
"${shared_config.modifier}+minus" = "scratchpad show";
|
||||
|
||||
"${shared_config.modifier}+1" = "workspace number 1";
|
||||
"${shared_config.modifier}+2" = "workspace number 2";
|
||||
"${shared_config.modifier}+3" = "workspace number 3";
|
||||
"${shared_config.modifier}+4" = "workspace number 4";
|
||||
"${shared_config.modifier}+5" = "workspace number 5";
|
||||
"${shared_config.modifier}+6" = "workspace number 6";
|
||||
"${shared_config.modifier}+7" = "workspace number 7";
|
||||
"${shared_config.modifier}+8" = "workspace number 8";
|
||||
"${shared_config.modifier}+9" = "workspace number 9";
|
||||
"${shared_config.modifier}+0" = "workspace number 10";
|
||||
|
||||
"${shared_config.modifier}+Shift+1" =
|
||||
"move container to workspace number 1";
|
||||
"${shared_config.modifier}+Shift+2" =
|
||||
"move container to workspace number 2";
|
||||
"${shared_config.modifier}+Shift+3" =
|
||||
"move container to workspace number 3";
|
||||
"${shared_config.modifier}+Shift+4" =
|
||||
"move container to workspace number 4";
|
||||
"${shared_config.modifier}+Shift+5" =
|
||||
"move container to workspace number 5";
|
||||
"${shared_config.modifier}+Shift+6" =
|
||||
"move container to workspace number 6";
|
||||
"${shared_config.modifier}+Shift+7" =
|
||||
"move container to workspace number 7";
|
||||
"${shared_config.modifier}+Shift+8" =
|
||||
"move container to workspace number 8";
|
||||
"${shared_config.modifier}+Shift+9" =
|
||||
"move container to workspace number 9";
|
||||
"${shared_config.modifier}+Shift+0" =
|
||||
"move container to workspace number 10";
|
||||
|
||||
"${shared_config.modifier}+Shift+c" = "reload";
|
||||
"${shared_config.modifier}+Shift+r" = "restart";
|
||||
|
||||
"${shared_config.modifier}+r" = "mode resize";
|
||||
|
||||
"XF86MonBrightnessUp" = "exec ddcutil setvcp 10 + 5";
|
||||
"XF86MonBrightnessDown" = "exec ddcutil setvcp 10 - 5";
|
||||
};
|
||||
} cfg.extraSharedConfig;
|
||||
in {
|
||||
options.home.roles.i3_sway = {
|
||||
enable = mkEnableOption "i3 and Sway tiling window managers with waybar and rofi";
|
||||
|
||||
browser = mkOption {
|
||||
type = types.str;
|
||||
default = "firefox --new-window";
|
||||
description = "Browser to use for new window keybinding";
|
||||
};
|
||||
|
||||
extraSharedConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Extra configuration shared between i3 and sway";
|
||||
};
|
||||
|
||||
extraI3Config = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Extra i3-specific configuration";
|
||||
};
|
||||
|
||||
extraSwayConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Extra sway-specific configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# i3blocks configuration file
|
||||
home.file.".config/i3blocks/config".text = ''
|
||||
# i3blocks config - replicating waybar setup
|
||||
separator_block_width=15
|
||||
markup=pango
|
||||
|
||||
[disk]
|
||||
command=df -h / | awk 'NR==2 {print "💾 " $5}'
|
||||
interval=30
|
||||
separator=true
|
||||
|
||||
[cpu]
|
||||
command=top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print "🧠 " int(100 - $1) "%"}'
|
||||
interval=2
|
||||
separator=true
|
||||
|
||||
[memory]
|
||||
command=free | awk 'NR==2 {printf "🐏 %.0f%%\n", $3*100/$2}'
|
||||
interval=5
|
||||
separator=true
|
||||
|
||||
[pulseaudio]
|
||||
command=${pkgs.writeShellScript "i3blocks-pulseaudio" ''
|
||||
volume=$(pactl get-sink-volume @DEFAULT_SINK@ | grep -Po '\d+%' | head -1)
|
||||
muted=$(pactl get-sink-mute @DEFAULT_SINK@ | grep -o 'yes')
|
||||
if [ "$muted" = "yes" ]; then
|
||||
echo "🔇"
|
||||
else
|
||||
vol_num=''${volume%\%}
|
||||
if [ $vol_num -le 33 ]; then
|
||||
echo "🔈 $volume"
|
||||
elif [ $vol_num -le 66 ]; then
|
||||
echo "🔉 $volume"
|
||||
else
|
||||
echo "🔊 $volume"
|
||||
fi
|
||||
fi
|
||||
''}
|
||||
interval=1
|
||||
signal=10
|
||||
separator=true
|
||||
|
||||
[backlight]
|
||||
command=${pkgs.writeShellScript "i3blocks-backlight" ''
|
||||
if command -v ddcutil &>/dev/null; then
|
||||
# Handle mouse scroll events
|
||||
case $BLOCK_BUTTON in
|
||||
4) ddcutil setvcp 10 + 5 ;; # Scroll up - increase brightness
|
||||
5) ddcutil setvcp 10 - 5 ;; # Scroll down - decrease brightness
|
||||
esac
|
||||
|
||||
# Display current brightness
|
||||
brightness=$(ddcutil getvcp 10 2>/dev/null | grep -oP 'current value =\s*\K\d+')
|
||||
if [ -n "$brightness" ]; then
|
||||
echo "☀️ $brightness%"
|
||||
fi
|
||||
fi
|
||||
''}
|
||||
interval=5
|
||||
separator=true
|
||||
|
||||
[network]
|
||||
command=${pkgs.writeShellScript "i3blocks-network" ''
|
||||
if iwgetid -r &>/dev/null; then
|
||||
ssid=$(iwgetid -r)
|
||||
signal=$(grep "^\s*w" /proc/net/wireless | awk '{print int($3 * 100 / 70)}')
|
||||
echo "📶 $ssid ($signal%)"
|
||||
else
|
||||
ip=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
if [ -n "$ip" ]; then
|
||||
echo "🔌 $ip"
|
||||
else
|
||||
echo "❌"
|
||||
fi
|
||||
fi
|
||||
''}
|
||||
interval=5
|
||||
separator=true
|
||||
|
||||
[battery]
|
||||
command=${pkgs.writeShellScript "i3blocks-battery" ''
|
||||
if [ -d /sys/class/power_supply/BAT0 ]; then
|
||||
capacity=$(cat /sys/class/power_supply/BAT0/capacity)
|
||||
status=$(cat /sys/class/power_supply/BAT0/status)
|
||||
|
||||
if [ "$status" = "Charging" ]; then
|
||||
echo "⚡ $capacity%"
|
||||
else
|
||||
echo "🔋 $capacity%"
|
||||
fi
|
||||
fi
|
||||
''}
|
||||
interval=10
|
||||
separator=true
|
||||
|
||||
[time]
|
||||
command=date '+%Y-%m-%d %H:%M'
|
||||
interval=1
|
||||
separator=false
|
||||
'';
|
||||
|
||||
xsession.windowManager.i3 = let
|
||||
base_i3_config = recursiveUpdate shared_config {
|
||||
bars = [{
|
||||
position = "bottom";
|
||||
statusCommand = "${pkgs.i3blocks}/bin/i3blocks";
|
||||
trayOutput = "primary"; # Enable system tray on primary output
|
||||
fonts = {
|
||||
names = [ "Fira Code" "monospace" ];
|
||||
size = 11.0;
|
||||
};
|
||||
colors = {
|
||||
background = "#000000";
|
||||
statusline = "#ffffff";
|
||||
separator = "#666666";
|
||||
|
||||
# Workspace button colors (matching waybar)
|
||||
focusedWorkspace = {
|
||||
border = "#285577";
|
||||
background = "#285577";
|
||||
text = "#ffffff";
|
||||
};
|
||||
activeWorkspace = {
|
||||
border = "#5f676a";
|
||||
background = "#5f676a";
|
||||
text = "#ffffff";
|
||||
};
|
||||
inactiveWorkspace = {
|
||||
border = "#222222";
|
||||
background = "#222222";
|
||||
text = "#888888";
|
||||
};
|
||||
urgentWorkspace = {
|
||||
border = "#900000";
|
||||
background = "#900000";
|
||||
text = "#ffffff";
|
||||
};
|
||||
};
|
||||
}];
|
||||
keybindings = shared_config.keybindings // {
|
||||
"${shared_config.modifier}+d" = "exec rofi -show drun";
|
||||
"${shared_config.modifier}+Shift+e" =
|
||||
"exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'";
|
||||
};
|
||||
startup = [
|
||||
# GNOME polkit authentication agent
|
||||
{
|
||||
command = "/run/current-system/sw/libexec/polkit-gnome-authentication-agent-1";
|
||||
always = false;
|
||||
notification = false;
|
||||
}
|
||||
# Picom compositor for smooth rendering and no tearing (important for Nvidia)
|
||||
{
|
||||
command = "picom --backend glx -b";
|
||||
always = false;
|
||||
notification = false;
|
||||
}
|
||||
# NetworkManager system tray applet
|
||||
{
|
||||
command = "nm-applet";
|
||||
always = false;
|
||||
notification = false;
|
||||
}
|
||||
# Set wallpaper with feh
|
||||
{
|
||||
command = "feh ${currentWallpaper.feh} ${currentWallpaper.file}";
|
||||
always = false;
|
||||
notification = false;
|
||||
}
|
||||
];
|
||||
};
|
||||
in {
|
||||
enable = true;
|
||||
config = recursiveUpdate base_i3_config cfg.extraI3Config;
|
||||
};
|
||||
|
||||
wayland.windowManager.sway = let
|
||||
base_sway_config = recursiveUpdate shared_config {
|
||||
bars = []; # Disable default bar, use waybar instead
|
||||
keybindings = shared_config.keybindings // {
|
||||
"${shared_config.modifier}+d" = "exec wofi --show drun";
|
||||
"${shared_config.modifier}+Shift+e" =
|
||||
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";
|
||||
};
|
||||
input = {
|
||||
"type:keyboard" = {
|
||||
xkb_options = "caps:escape";
|
||||
};
|
||||
"type:touchpad" = {
|
||||
tap = "enabled";
|
||||
tap_button_map = "lrm";
|
||||
drag = "enabled";
|
||||
natural_scroll = "disabled";
|
||||
dwt = "enabled";
|
||||
};
|
||||
};
|
||||
output = {
|
||||
"*" = {
|
||||
bg = "${currentWallpaper.file} ${currentWallpaper.sway}";
|
||||
};
|
||||
};
|
||||
startup = [
|
||||
# Launch waybar status bar
|
||||
{
|
||||
command = "waybar";
|
||||
always = false;
|
||||
}
|
||||
];
|
||||
};
|
||||
in {
|
||||
enable = true;
|
||||
extraOptions = [ "--unsupported-gpu" ];
|
||||
config = recursiveUpdate base_sway_config cfg.extraSwayConfig;
|
||||
};
|
||||
|
||||
programs.waybar = {
|
||||
enable = true;
|
||||
systemd.enable = false; # Don't auto-start via systemd - only launch in sway
|
||||
settings = {
|
||||
mainBar = {
|
||||
layer = "top";
|
||||
position = "bottom";
|
||||
height = 30;
|
||||
spacing = 4;
|
||||
|
||||
modules-left = [ "sway/workspaces" "sway/mode" ];
|
||||
modules-center = [ ];
|
||||
modules-right = [ "disk" "cpu" "memory" "pulseaudio" "custom/backlight-ddc" "backlight" "network" "battery" "tray" "clock" ];
|
||||
|
||||
"sway/workspaces" = {
|
||||
disable-scroll = true;
|
||||
all-outputs = true;
|
||||
};
|
||||
|
||||
"clock" = {
|
||||
format = "{:%Y-%m-%d %H:%M}";
|
||||
tooltip-format = "<tt><small>{calendar}</small></tt>";
|
||||
calendar = {
|
||||
mode = "year";
|
||||
mode-mon-col = 3;
|
||||
weeks-pos = "right";
|
||||
on-scroll = 1;
|
||||
format = {
|
||||
months = "<span color='#ffead3'><b>{}</b></span>";
|
||||
days = "<span color='#ecc6d9'><b>{}</b></span>";
|
||||
weeks = "<span color='#99ffdd'><b>W{}</b></span>";
|
||||
weekdays = "<span color='#ffcc66'><b>{}</b></span>";
|
||||
today = "<span color='#ff6699'><b><u>{}</u></b></span>";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
"disk" = {
|
||||
interval = 30;
|
||||
format = "💾 {percentage_used}%";
|
||||
path = "/";
|
||||
tooltip-format = "Used: {used} / {total} ({percentage_used}%)\nFree: {free} ({percentage_free}%)";
|
||||
};
|
||||
|
||||
"cpu" = {
|
||||
format = "🧠 {usage}%";
|
||||
tooltip = false;
|
||||
};
|
||||
|
||||
"memory" = {
|
||||
format = "🐏 {percentage}%";
|
||||
tooltip-format = "RAM: {used:0.1f}G / {total:0.1f}G";
|
||||
};
|
||||
|
||||
"pulseaudio" = {
|
||||
format = "{icon} {volume}%";
|
||||
format-muted = "🔇";
|
||||
format-icons = {
|
||||
headphone = "🎧";
|
||||
default = [ "🔈" "🔉" "🔊" ];
|
||||
};
|
||||
on-click = "pavucontrol";
|
||||
};
|
||||
|
||||
"backlight" = {
|
||||
format = "☀️ {percent}%";
|
||||
tooltip = false;
|
||||
};
|
||||
|
||||
"custom/backlight-ddc" = {
|
||||
exec = pkgs.writeShellScript "waybar-backlight-ddc" ''
|
||||
if command -v ddcutil &>/dev/null; then
|
||||
# Display current brightness
|
||||
brightness=$(ddcutil getvcp 10 --brief 2>/dev/null | awk '{print $4}')
|
||||
if [ -n "$brightness" ]; then
|
||||
echo "☀️ $brightness%"
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
interval = 5;
|
||||
format = "{}";
|
||||
on-scroll-up = "ddcutil setvcp 10 + 5 2>/dev/null &";
|
||||
on-scroll-down = "ddcutil setvcp 10 - 5 2>/dev/null &";
|
||||
tooltip = false;
|
||||
};
|
||||
|
||||
"network" = {
|
||||
format-wifi = "📶 {essid} ({signalStrength}%)";
|
||||
format-ethernet = "🔌 {ipaddr}";
|
||||
format-disconnected = "❌";
|
||||
tooltip-format = "{ifname}: {ipaddr}/{cidr}";
|
||||
};
|
||||
|
||||
"battery" = {
|
||||
states = {
|
||||
warning = 30;
|
||||
critical = 15;
|
||||
};
|
||||
format = "{icon} {capacity}%";
|
||||
format-charging = "⚡ {capacity}%";
|
||||
format-icons = [ "🪫" "🔋" "🔋" "🔋" "🔋" ];
|
||||
};
|
||||
|
||||
"tray" = {
|
||||
spacing = 10;
|
||||
};
|
||||
};
|
||||
};
|
||||
style = ''
|
||||
* {
|
||||
padding: 0 4px;
|
||||
font-family: "Fira Code", monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#workspaces button {
|
||||
padding: 0 8px;
|
||||
background-color: #333333;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
#workspaces button.focused {
|
||||
background-color: #285577;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#workspaces button.visible {
|
||||
background-color: #5f676a;
|
||||
}
|
||||
|
||||
#workspaces button.urgent {
|
||||
background-color: #900000;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
programs.rofi = {
|
||||
enable = true;
|
||||
theme = "solarized";
|
||||
extraConfig = {
|
||||
modi = "drun,run,window";
|
||||
show-icons = true;
|
||||
drun-display-format = "{name}";
|
||||
disable-history = false;
|
||||
hide-scrollbar = true;
|
||||
display-drun = " Apps";
|
||||
display-run = " Run";
|
||||
display-window = " Windows";
|
||||
sidebar-mode = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
20
home/roles/kdeconnect/default.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.kdeconnect;
|
||||
in
|
||||
{
|
||||
options.home.roles.kdeconnect = {
|
||||
enable = mkEnableOption "Enable KDE Connect for device integration";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.kdeconnect = {
|
||||
enable = true;
|
||||
indicator = true;
|
||||
package = pkgs.kdePackages.kdeconnect-kde;
|
||||
};
|
||||
};
|
||||
}
|
||||
243
home/roles/kubectl/default.nix
Normal file
@@ -0,0 +1,243 @@
|
||||
{ config, lib, pkgs, globalInputs, system, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.kubectl;
|
||||
in
|
||||
{
|
||||
options.home.roles.kubectl = {
|
||||
enable = mkEnableOption "management tools for the homelab k3s oglenet cluster with secure Bitwarden integration";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
kubectl
|
||||
kubernetes-helm
|
||||
];
|
||||
|
||||
programs.k9s.enable = true;
|
||||
|
||||
programs.bash.initExtra = mkAfter ''
|
||||
# Kubectl secure session management
|
||||
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
|
||||
|
||||
kube-select() {
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: kube-select <context-name>"
|
||||
echo "Available contexts: $(kube-list)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local context="$1"
|
||||
|
||||
# Clean up any existing session first
|
||||
kube-clear 2>/dev/null
|
||||
|
||||
# Create new session directory
|
||||
mkdir -p "$KUBECTL_SESSION_DIR"
|
||||
chmod 700 "$KUBECTL_SESSION_DIR"
|
||||
|
||||
# Set cleanup trap for this shell session
|
||||
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
|
||||
|
||||
# Set KUBECONFIG for this session
|
||||
export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
|
||||
|
||||
# Load config from Bitwarden secure notes
|
||||
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
|
||||
echo "Error: Could not retrieve kubectl-$context from Bitwarden"
|
||||
echo "Make sure the entry exists with name: kubectl-$context"
|
||||
kube-clear
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify the kubeconfig is valid
|
||||
if ! kubectl config view >/dev/null 2>&1; then
|
||||
echo "Error: Invalid kubeconfig retrieved from Bitwarden"
|
||||
kube-clear
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "✓ Loaded kubectl context: $context (session: $$)"
|
||||
echo " Config location: $KUBECONFIG"
|
||||
}
|
||||
|
||||
kube-list() {
|
||||
echo "Available kubectl contexts in Bitwarden:"
|
||||
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
|
||||
}
|
||||
|
||||
kube-clear() {
|
||||
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
|
||||
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
|
||||
unset KUBECTL_TIMEOUT_PID
|
||||
fi
|
||||
|
||||
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
|
||||
rm -rf "$KUBECTL_SESSION_DIR"
|
||||
echo "Cleared kubectl session ($$)"
|
||||
fi
|
||||
|
||||
unset KUBECONFIG
|
||||
}
|
||||
|
||||
kube-status() {
|
||||
if [[ -f "$KUBECONFIG" ]]; then
|
||||
local current_context
|
||||
current_context=$(kubectl config current-context 2>/dev/null)
|
||||
if [[ -n "$current_context" ]]; then
|
||||
echo "Active kubectl context: $current_context"
|
||||
echo "Session: $$ | Config: $KUBECONFIG"
|
||||
|
||||
# Show cluster info
|
||||
local cluster_server
|
||||
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
|
||||
if [[ -n "$cluster_server" ]]; then
|
||||
echo "Cluster: $cluster_server"
|
||||
fi
|
||||
else
|
||||
echo "No active context in current session"
|
||||
fi
|
||||
else
|
||||
echo "No kubectl session active in this shell"
|
||||
echo "Use 'kube-select <context>' to start a session"
|
||||
fi
|
||||
}
|
||||
|
||||
# Helper function to show available commands
|
||||
kube-help() {
|
||||
echo "Secure kubectl session management commands:"
|
||||
echo ""
|
||||
echo "Session management:"
|
||||
echo " kube-select <context> - Load kubeconfig from Bitwarden"
|
||||
echo " kube-status - Show current session status"
|
||||
echo " kube-clear - Clear current session"
|
||||
echo ""
|
||||
echo "Configuration management:"
|
||||
echo " kube-list - List available contexts in Bitwarden"
|
||||
echo ""
|
||||
echo "Help:"
|
||||
echo " kube-help - Show this help"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " kube-select prod # Loads from secure note"
|
||||
echo " kubectl get pods"
|
||||
echo " kube-clear"
|
||||
echo ""
|
||||
echo "Note: Kubeconfigs are stored as secure notes in Bitwarden"
|
||||
}
|
||||
'';
|
||||
|
||||
programs.zsh.initExtra = mkAfter ''
|
||||
# Kubectl secure session management (zsh)
|
||||
export KUBECTL_SESSION_DIR="/dev/shm/kubectl-$$"
|
||||
|
||||
kube-select() {
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: kube-select <context-name>"
|
||||
echo "Available contexts: $(kube-list)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local context="$1"
|
||||
|
||||
# Clean up any existing session first
|
||||
kube-clear 2>/dev/null
|
||||
|
||||
# Create new session directory
|
||||
mkdir -p "$KUBECTL_SESSION_DIR"
|
||||
chmod 700 "$KUBECTL_SESSION_DIR"
|
||||
|
||||
# Set cleanup trap for this shell session
|
||||
trap "rm -rf '$KUBECTL_SESSION_DIR' 2>/dev/null" EXIT
|
||||
|
||||
# Set KUBECONFIG for this session
|
||||
export KUBECONFIG="$KUBECTL_SESSION_DIR/config"
|
||||
|
||||
# Load config from Bitwarden secure notes
|
||||
if ! rbw get "kubectl-$context" > "$KUBECONFIG" 2>/dev/null; then
|
||||
echo "Error: Could not retrieve kubectl-$context from Bitwarden"
|
||||
echo "Make sure the entry exists with name: kubectl-$context"
|
||||
kube-clear
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify the kubeconfig is valid
|
||||
if ! kubectl config view >/dev/null 2>&1; then
|
||||
echo "Error: Invalid kubeconfig retrieved from Bitwarden"
|
||||
kube-clear
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "✓ Loaded kubectl context: $context (session: $$)"
|
||||
echo " Config location: $KUBECONFIG"
|
||||
}
|
||||
|
||||
kube-list() {
|
||||
echo "Available kubectl contexts in Bitwarden:"
|
||||
rbw search kubectl- 2>/dev/null | grep "^kubectl-" | sed 's/^kubectl-/ - /' || echo " (none found or rbw not accessible)"
|
||||
}
|
||||
|
||||
kube-clear() {
|
||||
if [[ -n "$KUBECTL_TIMEOUT_PID" ]]; then
|
||||
kill "$KUBECTL_TIMEOUT_PID" 2>/dev/null
|
||||
unset KUBECTL_TIMEOUT_PID
|
||||
fi
|
||||
|
||||
if [[ -d "$KUBECTL_SESSION_DIR" ]]; then
|
||||
rm -rf "$KUBECTL_SESSION_DIR"
|
||||
echo "Cleared kubectl session ($$)"
|
||||
fi
|
||||
|
||||
unset KUBECONFIG
|
||||
}
|
||||
|
||||
kube-status() {
|
||||
if [[ -f "$KUBECONFIG" ]]; then
|
||||
local current_context
|
||||
current_context=$(kubectl config current-context 2>/dev/null)
|
||||
if [[ -n "$current_context" ]]; then
|
||||
echo "Active kubectl context: $current_context"
|
||||
echo "Session: $$ | Config: $KUBECONFIG"
|
||||
|
||||
# Show cluster info
|
||||
local cluster_server
|
||||
cluster_server=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}' 2>/dev/null)
|
||||
if [[ -n "$cluster_server" ]]; then
|
||||
echo "Cluster: $cluster_server"
|
||||
fi
|
||||
else
|
||||
echo "No active context in current session"
|
||||
fi
|
||||
else
|
||||
echo "No kubectl session active in this shell"
|
||||
echo "Use 'kube-select <context>' to start a session"
|
||||
fi
|
||||
}
|
||||
|
||||
# Helper function to show available commands
|
||||
kube-help() {
|
||||
echo "Secure kubectl session management commands:"
|
||||
echo ""
|
||||
echo "Session management:"
|
||||
echo " kube-select <context> - Load kubeconfig from Bitwarden"
|
||||
echo " kube-status - Show current session status"
|
||||
echo " kube-clear - Clear current session"
|
||||
echo ""
|
||||
echo "Configuration management:"
|
||||
echo " kube-list - List available contexts in Bitwarden"
|
||||
echo ""
|
||||
echo "Help:"
|
||||
echo " kube-help - Show this help"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " kube-select prod # Loads from secure note"
|
||||
echo " kubectl get pods"
|
||||
echo " kube-clear"
|
||||
echo ""
|
||||
echo "Note: Kubeconfigs are stored as secure notes in Bitwarden"
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
36
home/roles/launchers/default.nix
Normal 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;
|
||||
};
|
||||
}
|
||||
27
home/roles/media/default.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.media;
|
||||
in
|
||||
{
|
||||
options.home.roles.media = {
|
||||
enable = mkEnableOption "Enable media and multimedia applications";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
# Media players and streaming
|
||||
# Using delfin instead of jellyfin-media-player to avoid qtwebengine security issues
|
||||
# For full Jellyfin features, use web interface at http://jellyfin-server:8096
|
||||
delfin
|
||||
moonlight-qt
|
||||
vlc
|
||||
|
||||
# Spotify client
|
||||
# Using unstable version for better authentication support
|
||||
unstable.ncspot
|
||||
];
|
||||
};
|
||||
}
|
||||
22
home/roles/office/default.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.office;
|
||||
in
|
||||
{
|
||||
options.home.roles.office = {
|
||||
enable = mkEnableOption "Enable office applications and document processing tools";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
# Office suite
|
||||
libreoffice
|
||||
|
||||
# CAD/Design tools
|
||||
openscad-unstable
|
||||
];
|
||||
};
|
||||
}
|
||||
199
home/roles/plasma-manager-kodi/default.nix
Normal file
@@ -0,0 +1,199 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.plasma-manager-kodi;
|
||||
|
||||
# Define the volume control scripts as derivations
|
||||
volumeUpScript = pkgs.writeShellScript "avr-volume-up" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Configuration
|
||||
HA_URL="https://home-assistant.johnogle.info"
|
||||
ENTITY_ID="media_player.denon_avr_s970h_2"
|
||||
MAX_RETRIES=3
|
||||
|
||||
# Read token from KDE Wallet and strip whitespace
|
||||
TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]')
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Send volume up command with retry logic
|
||||
for i in $(seq 1 $MAX_RETRIES); do
|
||||
RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"entity_id\": \"$ENTITY_ID\"}" \
|
||||
"$HA_URL/api/services/media_player/volume_up" 2>&1)
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Wait before retry (except on last attempt)
|
||||
if [ $i -lt $MAX_RETRIES ]; then
|
||||
sleep 0.5
|
||||
fi
|
||||
done
|
||||
|
||||
# All retries failed
|
||||
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to increase volume after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
'';
|
||||
|
||||
volumeDownScript = pkgs.writeShellScript "avr-volume-down" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Configuration
|
||||
HA_URL="https://home-assistant.johnogle.info"
|
||||
ENTITY_ID="media_player.denon_avr_s970h_2"
|
||||
MAX_RETRIES=3
|
||||
|
||||
# Read token from KDE Wallet and strip whitespace
|
||||
TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]')
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Send volume down command with retry logic
|
||||
for i in $(seq 1 $MAX_RETRIES); do
|
||||
RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"entity_id\": \"$ENTITY_ID\"}" \
|
||||
"$HA_URL/api/services/media_player/volume_down" 2>&1)
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Wait before retry (except on last attempt)
|
||||
if [ $i -lt $MAX_RETRIES ]; then
|
||||
sleep 0.5
|
||||
fi
|
||||
done
|
||||
|
||||
# All retries failed
|
||||
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to decrease volume after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
'';
|
||||
|
||||
volumeMuteScript = pkgs.writeShellScript "avr-volume-mute" ''
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Configuration
|
||||
HA_URL="https://home-assistant.johnogle.info"
|
||||
ENTITY_ID="media_player.denon_avr_s970h_2"
|
||||
MAX_RETRIES=3
|
||||
|
||||
# Read token from KDE Wallet and strip whitespace
|
||||
TOKEN=$(${pkgs.kdePackages.kwallet}/bin/kwallet-query -r ha_avr_token kdewallet -f Passwords 2>/dev/null | tr -d '[:space:]')
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to retrieve Home Assistant token from KDE Wallet"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current mute state
|
||||
STATE_RESPONSE=$(${pkgs.curl}/bin/curl -s -H "Authorization: Bearer $TOKEN" \
|
||||
"$HA_URL/api/states/$ENTITY_ID")
|
||||
|
||||
CURRENT_MUTE=$(echo "$STATE_RESPONSE" | ${pkgs.jq}/bin/jq -r '.attributes.is_volume_muted // false')
|
||||
|
||||
# Toggle: if currently muted (true), unmute (false), and vice versa
|
||||
if [ "$CURRENT_MUTE" = "true" ]; then
|
||||
NEW_MUTE="false"
|
||||
NOTIFY_MSG="Unmuted"
|
||||
else
|
||||
NEW_MUTE="true"
|
||||
NOTIFY_MSG="Muted"
|
||||
fi
|
||||
|
||||
# Send mute toggle command with retry logic
|
||||
for i in $(seq 1 $MAX_RETRIES); do
|
||||
RESPONSE=$(${pkgs.curl}/bin/curl -s -w "\n%{http_code}" -X POST \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"entity_id\": \"$ENTITY_ID\", \"is_volume_muted\": $NEW_MUTE}" \
|
||||
"$HA_URL/api/services/media_player/volume_mute" 2>&1)
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
|
||||
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Wait before retry (except on last attempt)
|
||||
if [ $i -lt $MAX_RETRIES ]; then
|
||||
sleep 0.5
|
||||
fi
|
||||
done
|
||||
|
||||
# All retries failed
|
||||
${pkgs.libnotify}/bin/notify-send -u critical "Volume Control Error" "Failed to toggle mute after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.home.roles.plasma-manager-kodi = {
|
||||
enable = mkEnableOption "KDE Plasma volume control for kodi user via Home Assistant";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
programs.plasma = {
|
||||
enable = true;
|
||||
overrideConfig = true;
|
||||
|
||||
# Disable default kmix volume shortcuts to prevent conflicts
|
||||
shortcuts.kmix = {
|
||||
"increase_volume" = "none";
|
||||
"decrease_volume" = "none";
|
||||
"mute" = "none";
|
||||
};
|
||||
|
||||
# Define custom volume control commands with key bindings
|
||||
hotkeys.commands = {
|
||||
"volume-up-avr" = {
|
||||
name = "Volume Up AVR";
|
||||
key = "Volume Up";
|
||||
command = toString volumeUpScript;
|
||||
};
|
||||
|
||||
"volume-down-avr" = {
|
||||
name = "Volume Down AVR";
|
||||
key = "Volume Down";
|
||||
command = toString volumeDownScript;
|
||||
};
|
||||
|
||||
"volume-mute-avr" = {
|
||||
name = "Mute Toggle AVR";
|
||||
key = "Volume Mute";
|
||||
command = toString volumeMuteScript;
|
||||
};
|
||||
};
|
||||
|
||||
# KDE Settings customization
|
||||
configFile = {
|
||||
# Session restore settings
|
||||
"ksmserverrc"."General"."loginMode" = "emptySession";
|
||||
|
||||
# Screen locking settings
|
||||
"kscreenlockerrc"."Daemon"."Autolock" = false;
|
||||
"kscreenlockerrc"."Daemon"."LockOnResume" = false;
|
||||
|
||||
# Theme settings
|
||||
"kdeglobals"."KDE"."LookAndFeelPackage" = "org.kde.breezedark.desktop";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
190
home/roles/plasma-manager/default.nix
Normal file
@@ -0,0 +1,190 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.plasma-manager;
|
||||
wallpaperConfig = import ../../wallpapers;
|
||||
currentWallpaper = builtins.elemAt wallpaperConfig.wallpapers wallpaperConfig.currentIndex;
|
||||
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 = "${currentWallpaper.file}";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
22
home/roles/sync/default.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.home.roles.sync;
|
||||
in
|
||||
{
|
||||
options.home.roles.sync = {
|
||||
enable = mkEnableOption "Enable file synchronization services";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = with pkgs; [
|
||||
syncthingtray
|
||||
];
|
||||
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
62
home/roles/tmux/default.nix
Normal 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
|
||||
];
|
||||
};
|
||||
}
|
||||
45
home/wallpapers/default.nix
Normal file
@@ -0,0 +1,45 @@
|
||||
# Wallpaper rotation system
|
||||
# The currentIndex is incremented by `nix run .#rotate-wallpaper`
|
||||
# and gets committed as part of `nix run .#upgrade`
|
||||
{
|
||||
currentIndex = 1; # Index into wallpapers list
|
||||
|
||||
wallpapers = [
|
||||
{
|
||||
name = "metroid-samus-returns";
|
||||
file = ./metroid-samus-returns-kz-3440x1440.jpg;
|
||||
sway = "fill";
|
||||
feh = "--bg-fill";
|
||||
}
|
||||
{
|
||||
name = "metroid3_map";
|
||||
file = ./metroid3_map.gif;
|
||||
sway = "fit";
|
||||
feh = "--bg-max";
|
||||
}
|
||||
{
|
||||
name = "super-metroid-gunship-cavern";
|
||||
file = ./super-metroid-gunship-cavern.jpg;
|
||||
sway = "fit";
|
||||
feh = "--bg-max";
|
||||
}
|
||||
{
|
||||
name = "super-metroid-samus-statue";
|
||||
file = ./super-metroid-samus-statue.png;
|
||||
sway = "fit";
|
||||
feh = "--bg-max";
|
||||
}
|
||||
{
|
||||
name = "metroid-samus-action-4k";
|
||||
file = ./metroid-samus-action-4k.jpg;
|
||||
sway = "fit";
|
||||
feh = "--bg-max";
|
||||
}
|
||||
{
|
||||
name = "metroid-creature-minimalist";
|
||||
file = ./metroid-creature-minimalist.jpg;
|
||||
sway = "fit";
|
||||
feh = "--bg-max";
|
||||
}
|
||||
];
|
||||
}
|
||||
BIN
home/wallpapers/metroid-creature-minimalist.jpg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
home/wallpapers/metroid-samus-action-4k.jpg
Normal file
|
After Width: | Height: | Size: 9.2 MiB |
BIN
home/wallpapers/metroid-samus-returns-kz-3440x1440.jpg
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
home/wallpapers/metroid3_map.gif
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
home/wallpapers/super-metroid-gunship-cavern.jpg
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
home/wallpapers/super-metroid-samus-statue.png
Normal file
|
After Width: | Height: | Size: 5.8 MiB |
@@ -2,7 +2,7 @@
|
||||
# your system. Help is available in the configuration.nix(5) man page, on
|
||||
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
|
||||
|
||||
{ lib, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
@@ -14,23 +14,42 @@ with lib;
|
||||
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
bluetooth.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
gaming.enable = true;
|
||||
kde = true;
|
||||
sddm = true;
|
||||
wayland = true;
|
||||
};
|
||||
kodi = {
|
||||
enable = true;
|
||||
autologin = true;
|
||||
wayland = true;
|
||||
jellyfinScaleFactor = 1.0;
|
||||
};
|
||||
nfs-mounts.enable = true;
|
||||
users.enable = true;
|
||||
};
|
||||
|
||||
# Enable KDE Wallet PAM integration for auto-unlock
|
||||
security.pam.services.sddm = {
|
||||
kwallet = {
|
||||
enable = true;
|
||||
package = pkgs.kdePackages.kwallet-pam;
|
||||
};
|
||||
};
|
||||
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
networking.hostName = "boxy"; # Define your hostname.
|
||||
|
||||
services.xserver.videoDrivers = [ "amdgpu" ];
|
||||
hardware.graphics.enable = true;
|
||||
|
||||
services.displayManager.enable = mkForce false;
|
||||
hardware.graphics.enable32Bit = true;
|
||||
# RADV (AMD's Vulkan driver) is now enabled by default, amdvlk was removed
|
||||
|
||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "thunderbolt" "usb_storage" "usbhid" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.initrd.kernelModules = [ "amdgpu" ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
|
||||
424
machines/john-endesktop/MIGRATION_PLAN.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# Migration Plan: Arch Linux to NixOS on john-endesktop (ZFS/NFS Server)
|
||||
|
||||
## Overview
|
||||
This document outlines the plan to migrate the john-endesktop server from Arch Linux to NixOS while maintaining the existing ZFS pools and NFS exports that serve your k3s cluster.
|
||||
|
||||
## Current System State
|
||||
|
||||
### Hardware
|
||||
- **Boot disk**: nvme0n1
|
||||
- nvme0n1p3: 1000M EFI partition (UUID: F5C6-D570)
|
||||
- nvme0n1p4: 120GB ext4 / (current Arch root)
|
||||
- nvme0n1p5: 810GB - **Target for NixOS** (being removed from media pool)
|
||||
- **Network**: enp0s31f6 @ 10.0.0.43/24 (DHCP)
|
||||
|
||||
### ZFS Pools
|
||||
- **media**: ~3.5TB JBOD pool (2 drives after nvme0n1p5 removal)
|
||||
- wwn-0x50014ee2ba653d70-part2
|
||||
- ata-WDC_WD20EZBX-00AYRA0_WD-WX62D627X7Z8-part2
|
||||
- Contains: /media/media/nix (bind mounted to /nix on Arch)
|
||||
- NFS: Shared to 10.0.0.0/24 via ZFS sharenfs property
|
||||
|
||||
- **swarmvols**: 928GB mirror pool - **PRODUCTION DATA**
|
||||
- wwn-0x5002538f52707e2d-part2
|
||||
- wwn-0x5002538f52707e81-part2
|
||||
- Contains: iocage jails and k3s persistent volumes
|
||||
- NFS: Shared to 10.0.0.0/24 via ZFS sharenfs property
|
||||
- Backed up nightly to remote borg
|
||||
|
||||
### Services
|
||||
- NFS server exporting /media and /swarmvols to k3s cluster
|
||||
- ZFS managing pools with automatic exports via sharenfs property
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Before Starting
|
||||
1. ✅ Ensure nvme0n1p5 removal from media pool is complete
|
||||
```bash
|
||||
ssh 10.0.0.43 "zpool status media"
|
||||
# Should show no "removing" devices
|
||||
```
|
||||
|
||||
2. ✅ Verify recent backups exist
|
||||
```bash
|
||||
# Verify swarmvols backup is recent (< 24 hours)
|
||||
# Check your borg backup system
|
||||
```
|
||||
|
||||
3. ✅ Notify k3s cluster users of planned maintenance window
|
||||
- NFS shares will be unavailable during migration
|
||||
- Estimate: 30-60 minutes downtime
|
||||
|
||||
4. ✅ Build NixOS configuration from your workstation
|
||||
```bash
|
||||
cd ~/nixos-configs
|
||||
nix build .#nixosConfigurations.john-endesktop.config.system.build.toplevel
|
||||
```
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Phase 1: Prepare NixOS Installation Media
|
||||
|
||||
1. **Download NixOS minimal ISO**
|
||||
```bash
|
||||
wget https://channels.nixos.org/nixos-25.11/latest-nixos-minimal-x86_64-linux.iso
|
||||
```
|
||||
|
||||
2. **Create bootable USB**
|
||||
```bash
|
||||
# Identify USB device (e.g., /dev/sdb)
|
||||
lsblk
|
||||
# Write ISO to USB
|
||||
sudo dd if=latest-nixos-minimal-x86_64-linux.iso of=/dev/sdX bs=4M status=progress
|
||||
sudo sync
|
||||
```
|
||||
|
||||
### Phase 2: Backup and Shutdown
|
||||
|
||||
1. **On the server, verify ZFS pool status**
|
||||
```bash
|
||||
ssh 10.0.0.43 "zpool status"
|
||||
ssh 10.0.0.43 "zfs list"
|
||||
```
|
||||
|
||||
2. **Export ZFS pools cleanly**
|
||||
```bash
|
||||
ssh 10.0.0.43 "sudo zpool export media"
|
||||
ssh 10.0.0.43 "sudo zpool export swarmvols"
|
||||
```
|
||||
|
||||
3. **Shutdown Arch Linux**
|
||||
```bash
|
||||
ssh 10.0.0.43 "sudo shutdown -h now"
|
||||
```
|
||||
|
||||
### Phase 3: Install NixOS
|
||||
|
||||
1. **Boot from NixOS USB**
|
||||
- Insert USB drive
|
||||
- Power on and select USB in boot menu
|
||||
|
||||
2. **Connect to network**
|
||||
```bash
|
||||
# If DHCP doesn't work automatically:
|
||||
sudo systemctl start dhcpcd
|
||||
ip a # Verify you have 10.0.0.43 or another IP
|
||||
```
|
||||
|
||||
3. **Enable SSH for remote installation (recommended)**
|
||||
```bash
|
||||
# Set password for nixos user
|
||||
sudo passwd nixos
|
||||
# Start SSH
|
||||
sudo systemctl start sshd
|
||||
# From your workstation:
|
||||
ssh nixos@10.0.0.43
|
||||
```
|
||||
|
||||
4. **Partition nvme0n1p5 with btrfs**
|
||||
```bash
|
||||
# Verify the device is clear
|
||||
lsblk
|
||||
sudo wipefs -a /dev/nvme0n1p5
|
||||
|
||||
# Create btrfs filesystem
|
||||
sudo mkfs.btrfs -L nixos /dev/nvme0n1p5
|
||||
|
||||
# Mount and create subvolumes
|
||||
sudo mount /dev/nvme0n1p5 /mnt
|
||||
sudo btrfs subvolume create /mnt/@
|
||||
sudo btrfs subvolume create /mnt/@home
|
||||
sudo btrfs subvolume create /mnt/@nix
|
||||
sudo btrfs subvolume create /mnt/@log
|
||||
sudo umount /mnt
|
||||
|
||||
# Mount root subvolume
|
||||
sudo mount -o subvol=@,compress=zstd,noatime /dev/nvme0n1p5 /mnt
|
||||
|
||||
# Create mount points
|
||||
sudo mkdir -p /mnt/{boot,home,nix,var/log}
|
||||
|
||||
# Mount other subvolumes
|
||||
sudo mount -o subvol=@home,compress=zstd,noatime /dev/nvme0n1p5 /mnt/home
|
||||
sudo mount -o subvol=@nix,compress=zstd,noatime /dev/nvme0n1p5 /mnt/nix
|
||||
sudo mount -o subvol=@log,compress=zstd,noatime /dev/nvme0n1p5 /mnt/var/log
|
||||
|
||||
# Mount EFI partition
|
||||
sudo mount /dev/nvme0n1p3 /mnt/boot
|
||||
```
|
||||
|
||||
5. **Import ZFS pools**
|
||||
```bash
|
||||
# Import pools (should be visible)
|
||||
sudo zpool import
|
||||
|
||||
# Import with force if needed due to hostid
|
||||
sudo zpool import -f media
|
||||
sudo zpool import -f swarmvols
|
||||
|
||||
# Verify pools are mounted
|
||||
zfs list
|
||||
ls -la /media /swarmvols
|
||||
```
|
||||
|
||||
6. **Generate initial hardware configuration**
|
||||
```bash
|
||||
sudo nixos-generate-config --root /mnt
|
||||
```
|
||||
|
||||
7. **Get the new root filesystem UUID**
|
||||
```bash
|
||||
blkid /dev/nvme0n1p5
|
||||
# Note the UUID for updating hardware-configuration.nix
|
||||
/dev/nvme0n1p5: LABEL="nixos" UUID="5f4ad025-bfab-4aed-a933-6638348059e5" UUID_SUB="4734d820-7b8a-4b7f-853a-026021c1d204" BLOCK_SIZE="4096" TYPE="btrfs" PARTLABEL="data" PARTUUID="9ea025df-cdb7-48fd-b5d4-37cd5d8588eb"
|
||||
```
|
||||
|
||||
8. **Copy your NixOS configuration to the server**
|
||||
```bash
|
||||
# From your workstation:
|
||||
scp -r ~/nixos-configs/machines/john-endesktop/* nixos@10.0.0.43:/tmp/
|
||||
|
||||
# On server:
|
||||
sudo mkdir -p /mnt/etc/nixos
|
||||
sudo cp /tmp/configuration.nix /mnt/etc/nixos/
|
||||
sudo cp /tmp/hardware-configuration.nix /mnt/etc/nixos/
|
||||
|
||||
# Edit hardware-configuration.nix to update the root filesystem UUID
|
||||
sudo nano /mnt/etc/nixos/hardware-configuration.nix
|
||||
# Change: device = "/dev/disk/by-uuid/CHANGE-THIS-TO-YOUR-UUID";
|
||||
# To: device = "/dev/disk/by-uuid/[UUID from blkid]";
|
||||
```
|
||||
|
||||
9. **Install NixOS**
|
||||
```bash
|
||||
sudo nixos-install
|
||||
|
||||
# Set root password when prompted
|
||||
# Set user password
|
||||
sudo nixos-install --no-root-passwd
|
||||
```
|
||||
|
||||
10. **Reboot into NixOS**
|
||||
```bash
|
||||
sudo reboot
|
||||
# Remove USB drive
|
||||
```
|
||||
|
||||
### Phase 4: Post-Installation Verification
|
||||
|
||||
1. **Boot into NixOS and verify system**
|
||||
```bash
|
||||
ssh johno@10.0.0.43
|
||||
|
||||
# Check NixOS version
|
||||
nixos-version
|
||||
|
||||
# Verify hostname
|
||||
hostname # Should be: john-endesktop
|
||||
```
|
||||
|
||||
2. **Verify ZFS pools imported correctly**
|
||||
```bash
|
||||
zpool status
|
||||
zpool list
|
||||
zfs list
|
||||
|
||||
# Check for hostid mismatch warnings (should be gone)
|
||||
# Verify both pools show ONLINE status
|
||||
```
|
||||
|
||||
3. **Verify NFS exports are active**
|
||||
```bash
|
||||
sudo exportfs -v
|
||||
systemctl status nfs-server
|
||||
|
||||
# Should see /media and /swarmvols exported to 10.0.0.0/24
|
||||
```
|
||||
|
||||
4. **Test NFS mount from another machine**
|
||||
```bash
|
||||
# From a k3s node or your workstation:
|
||||
sudo mount -t nfs 10.0.0.43:/swarmvols /mnt
|
||||
ls -la /mnt
|
||||
sudo umount /mnt
|
||||
|
||||
sudo mount -t nfs 10.0.0.43:/media /mnt
|
||||
ls -la /mnt
|
||||
sudo umount /mnt
|
||||
```
|
||||
|
||||
5. **Verify ZFS sharenfs properties preserved**
|
||||
```bash
|
||||
zfs get sharenfs media
|
||||
zfs get sharenfs swarmvols
|
||||
|
||||
# Should show: sec=sys,mountpoint,no_subtree_check,no_root_squash,rw=@10.0.0.0/24
|
||||
```
|
||||
|
||||
6. **Check swap device**
|
||||
```bash
|
||||
swapon --show
|
||||
free -h
|
||||
# Should show /dev/zvol/media/swap
|
||||
```
|
||||
|
||||
### Phase 5: Restore k3s Cluster Access
|
||||
|
||||
1. **Restart k3s nodes or remount NFS shares**
|
||||
```bash
|
||||
# On each k3s node:
|
||||
sudo systemctl restart k3s # or k3s-agent
|
||||
```
|
||||
|
||||
2. **Verify k3s pods have access to persistent volumes**
|
||||
```bash
|
||||
# On k3s master:
|
||||
kubectl get pv
|
||||
kubectl get pvc
|
||||
# Check that volumes are bound and accessible
|
||||
```
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If something goes wrong during migration, you can roll back to Arch Linux:
|
||||
|
||||
### Quick Rollback (If NixOS won't boot)
|
||||
|
||||
1. **Boot from NixOS USB (or Arch USB)**
|
||||
|
||||
2. **Import ZFS pools**
|
||||
```bash
|
||||
sudo zpool import -f media
|
||||
sudo zpool import -f swarmvols
|
||||
```
|
||||
|
||||
3. **Start NFS manually (temporary)**
|
||||
```bash
|
||||
sudo mkdir -p /media /swarmvols
|
||||
sudo systemctl start nfs-server
|
||||
sudo exportfs -o rw,sync,no_subtree_check,no_root_squash 10.0.0.0/24:/media
|
||||
sudo exportfs -o rw,sync,no_subtree_check,no_root_squash 10.0.0.0/24:/swarmvols
|
||||
sudo exportfs -v
|
||||
```
|
||||
This will restore k3s cluster access immediately while you diagnose.
|
||||
|
||||
4. **Boot back into Arch Linux**
|
||||
```bash
|
||||
# Reboot and select nvme0n1p4 (Arch) in GRUB/boot menu
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
5. **Verify Arch boots and services start**
|
||||
```bash
|
||||
ssh johno@10.0.0.43
|
||||
zpool status
|
||||
systemctl status nfs-server
|
||||
```
|
||||
|
||||
### Full Rollback (If needed)
|
||||
|
||||
1. **Follow Quick Rollback steps above**
|
||||
|
||||
2. **Re-add nvme0n1p5 to media pool (if desired)**
|
||||
```bash
|
||||
# Only if you want to restore the original configuration
|
||||
sudo zpool add media /dev/nvme0n1p5
|
||||
```
|
||||
|
||||
3. **Clean up NixOS partition**
|
||||
```bash
|
||||
# If you want to reclaim nvme0n1p5 for other uses
|
||||
sudo wipefs -a /dev/nvme0n1p5
|
||||
```
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
### Data Safety
|
||||
- ✅ **swarmvols** (production): Mirrored + nightly borg backups
|
||||
- ⚠️ **media** (important): JBOD - no redundancy, but not catastrophic
|
||||
- ✅ **NixOS install**: Separate partition, doesn't touch ZFS pools
|
||||
- ✅ **Arch Linux**: Remains bootable on nvme0n1p4 until verified
|
||||
|
||||
### Service Continuity
|
||||
- Downtime: 30-60 minutes expected
|
||||
- k3s cluster: Will reconnect automatically when NFS returns
|
||||
- Rollback time: < 10 minutes to restore Arch
|
||||
|
||||
### Testing Approach
|
||||
1. Test NFS exports from NixOS live environment before installation
|
||||
2. Test single NFS mount from k3s node before full cluster restart
|
||||
3. Keep Arch Linux boot option until 24-48 hours of stable NixOS operation
|
||||
|
||||
## Post-Migration Tasks
|
||||
|
||||
After successful migration and 24-48 hours of stable operation:
|
||||
|
||||
1. **Update k3s NFS mounts (if needed)**
|
||||
- Verify no hardcoded references to old system
|
||||
|
||||
2. **Optional: Repurpose Arch partition**
|
||||
```bash
|
||||
# After you're confident NixOS is stable
|
||||
# You can wipe nvme0n1p4 and repurpose it
|
||||
```
|
||||
|
||||
3. **Update documentation**
|
||||
- Update infrastructure docs with NixOS configuration
|
||||
- Document any deviations from this plan
|
||||
|
||||
4. **Consider setting up NixOS remote deployment**
|
||||
```bash
|
||||
# From your workstation:
|
||||
nixos-rebuild switch --target-host johno@10.0.0.43 --flake .#john-endesktop
|
||||
```
|
||||
|
||||
## Timeline
|
||||
|
||||
- **Preparation**: 1-2 hours (testing config build, downloading ISO)
|
||||
- **Migration window**: 1-2 hours (installation + verification)
|
||||
- **Verification period**: 24-48 hours (before removing Arch)
|
||||
- **Total**: ~3 days from start to declaring success
|
||||
|
||||
## Emergency Contacts
|
||||
|
||||
- Borg backup location: [Document your borg repo location]
|
||||
- K3s cluster nodes: [Document your k3s nodes]
|
||||
- Critical services on k3s: [Document what's running that depends on these NFS shares]
|
||||
|
||||
## Checklist
|
||||
|
||||
Pre-migration:
|
||||
- [x] nvme0n1p5 removal from media pool complete
|
||||
- [x] Recent backup verified (< 24 hours)
|
||||
- [x] Maintenance window scheduled
|
||||
- [x] NixOS ISO downloaded
|
||||
- [x] Bootable USB created
|
||||
- [x] NixOS config builds successfully
|
||||
|
||||
During migration:
|
||||
- [ ] ZFS pools exported
|
||||
- [ ] Arch Linux shutdown cleanly
|
||||
- [ ] Booted from NixOS USB
|
||||
- [ ] nvme0n1p5 formatted with btrfs
|
||||
- [ ] Btrfs subvolumes created
|
||||
- [ ] ZFS pools imported
|
||||
- [ ] NixOS installed
|
||||
- [ ] Root password set
|
||||
|
||||
Post-migration:
|
||||
- [ ] NixOS boots successfully
|
||||
- [ ] ZFS pools mounted automatically
|
||||
- [ ] NFS server running
|
||||
- [ ] NFS exports verified
|
||||
- [ ] Test mount from k3s node successful
|
||||
- [ ] k3s cluster reconnected
|
||||
- [ ] Persistent volumes accessible
|
||||
- [ ] No hostid warnings in zpool status
|
||||
- [ ] Arch Linux still bootable (for rollback)
|
||||
|
||||
Final verification (after 24-48 hours):
|
||||
- [ ] All services stable
|
||||
- [ ] No unexpected issues
|
||||
- [ ] Performance acceptable
|
||||
- [ ] Ready to remove Arch partition (optional)
|
||||
- [ ] Ready to remove /swarmvols/media-backup (optional)
|
||||
112
machines/john-endesktop/configuration.nix
Normal file
@@ -0,0 +1,112 @@
|
||||
# NixOS configuration for john-endesktop (ZFS/NFS server)
|
||||
# Migrated from Arch Linux to provide ZFS pools via NFS to k3s cluster
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
# Boot configuration
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
# ZFS support
|
||||
boot.supportedFilesystems = [ "zfs" ];
|
||||
boot.zfs.forceImportRoot = false;
|
||||
boot.zfs.extraPools = [ "media" "swarmvols" ];
|
||||
|
||||
# Set ZFS hostid to match current system (from Arch Linux)
|
||||
# This resolves the hostid mismatch warnings
|
||||
networking.hostId = "007f0101";
|
||||
|
||||
# Hostname
|
||||
networking.hostName = "john-endesktop";
|
||||
|
||||
# Network configuration - using DHCP on enp0s31f6
|
||||
networking.useDHCP = false;
|
||||
networking.interfaces.enp0s31f6.useDHCP = true;
|
||||
|
||||
# NFS Server configuration
|
||||
services.nfs.server = {
|
||||
enable = true;
|
||||
|
||||
# NFS protocol versions
|
||||
# v3 for broader compatibility, v4 for better performance
|
||||
exports = ''
|
||||
# These are managed by ZFS sharenfs properties
|
||||
# but we enable the NFS server here
|
||||
'';
|
||||
};
|
||||
|
||||
# Enable NFS4 with proper configuration
|
||||
services.rpcbind.enable = true;
|
||||
|
||||
# Firewall configuration for NFS
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [
|
||||
111 # rpcbind
|
||||
2049 # nfs
|
||||
4000 # nfs callback
|
||||
4001 # nlockmgr
|
||||
4002 # mountd
|
||||
20048 # mountd
|
||||
];
|
||||
allowedUDPPorts = [
|
||||
111 # rpcbind
|
||||
2049 # nfs
|
||||
4000 # nfs callback
|
||||
4001 # nlockmgr
|
||||
4002 # mountd
|
||||
20048 # mountd
|
||||
];
|
||||
# Allow NFS from local network
|
||||
extraCommands = ''
|
||||
iptables -A nixos-fw -p tcp -s 10.0.0.0/24 -j ACCEPT
|
||||
iptables -A nixos-fw -p udp -s 10.0.0.0/24 -j ACCEPT
|
||||
'';
|
||||
};
|
||||
|
||||
# ZFS maintenance
|
||||
services.zfs = {
|
||||
autoScrub = {
|
||||
enable = true;
|
||||
interval = "monthly";
|
||||
};
|
||||
trim = {
|
||||
enable = true;
|
||||
interval = "weekly";
|
||||
};
|
||||
};
|
||||
|
||||
# Basic system packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
vim
|
||||
git
|
||||
htop
|
||||
tmux
|
||||
zfs
|
||||
];
|
||||
|
||||
# Enable SSH
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "no";
|
||||
PasswordAuthentication = true;
|
||||
};
|
||||
};
|
||||
|
||||
# User configuration
|
||||
roles.users.enable = true;
|
||||
|
||||
# Time zone
|
||||
time.timeZone = "America/Los_Angeles"; # Adjust as needed
|
||||
|
||||
# NixOS version
|
||||
system.stateVersion = "25.11";
|
||||
}
|
||||
63
machines/john-endesktop/hardware-configuration.nix
Normal file
@@ -0,0 +1,63 @@
|
||||
# Hardware configuration for john-endesktop
|
||||
# This file should be regenerated after NixOS installation using:
|
||||
# nixos-generate-config --show-hardware-config
|
||||
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
# Boot configuration
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# File systems - these will need to be updated after installation
|
||||
# The nvme0n1p5 partition will be formatted as btrfs for NixOS root
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=@" "compress=zstd" "noatime" ];
|
||||
};
|
||||
|
||||
fileSystems."/home" = {
|
||||
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=@home" "compress=zstd" "noatime" ];
|
||||
};
|
||||
|
||||
fileSystems."/nix" = {
|
||||
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=@nix" "compress=zstd" "noatime" ];
|
||||
};
|
||||
|
||||
fileSystems."/var/log" = {
|
||||
device = "/dev/disk/by-uuid/5f4ad025-bfab-4aed-a933-6638348059e5";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=@log" "compress=zstd" "noatime" ];
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
# This should match your current EFI partition
|
||||
device = "/dev/disk/by-uuid/F5C6-D570";
|
||||
fsType = "vfat";
|
||||
options = [ "fmask=0022" "dmask=0022" ];
|
||||
};
|
||||
|
||||
# ZFS pools - these are imported by ZFS, not managed by fileSystems
|
||||
# The pools should be imported automatically via boot.zfs.extraPools
|
||||
# /media and /swarmvols will be mounted by ZFS
|
||||
|
||||
# No swap needed - 23GB RAM is sufficient for this NFS/ZFS server
|
||||
swapDevices = [ ];
|
||||
|
||||
# CPU microcode
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
|
||||
# Networking
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
}
|
||||
23
machines/johno-macbookpro/configuration.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Basic system configuration for macOS work laptop
|
||||
system.stateVersion = 6;
|
||||
|
||||
# Set primary user for nix-darwin
|
||||
system.primaryUser = "johno";
|
||||
|
||||
# System preferences (can be expanded later)
|
||||
system.defaults = {
|
||||
dock.autohide = true;
|
||||
finder.AppleShowAllExtensions = true;
|
||||
NSGlobalDomain.AppleShowAllExtensions = true;
|
||||
};
|
||||
|
||||
# TODO: Find a way to not duplicate this
|
||||
launchd.user.envVariables = {
|
||||
# DOOM Emacs environment variables
|
||||
DOOMDIR = "/Users/johno/.config/doom";
|
||||
DOOMLOCALDIR = "/Users/johno/.local/doom";
|
||||
};
|
||||
}
|
||||
91
machines/live-usb/configuration.nix
Normal file
@@ -0,0 +1,91 @@
|
||||
# Live USB ISO configuration for recovery and installation
|
||||
{ pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
# Use minimal installation CD as base
|
||||
(modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix")
|
||||
];
|
||||
|
||||
# Use roles structure for consistent configuration
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
bluetooth.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
kde = true;
|
||||
x11 = true;
|
||||
wayland = true;
|
||||
sddm = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Allow unfree packages for broader hardware support
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
# Essential packages for system recovery and installation
|
||||
environment.systemPackages = with pkgs; [
|
||||
# Text editors
|
||||
neovim
|
||||
nano
|
||||
|
||||
# System tools
|
||||
git
|
||||
curl
|
||||
wget
|
||||
htop
|
||||
tree
|
||||
lsof
|
||||
strace
|
||||
|
||||
# Filesystem tools
|
||||
btrfs-progs
|
||||
e2fsprogs
|
||||
xfsprogs
|
||||
ntfs3g
|
||||
dosfstools
|
||||
|
||||
# Network tools
|
||||
networkmanager
|
||||
wirelesstools
|
||||
|
||||
# Hardware tools
|
||||
pciutils
|
||||
usbutils
|
||||
smartmontools
|
||||
|
||||
# Archive tools
|
||||
unzip
|
||||
p7zip
|
||||
|
||||
# Development tools (for quick fixes)
|
||||
gcc
|
||||
binutils
|
||||
];
|
||||
|
||||
# Enable NetworkManager for easy wifi setup
|
||||
networking.networkmanager.enable = true;
|
||||
# Disable wireless networking (conflicts with NetworkManager)
|
||||
networking.wireless.enable = false;
|
||||
|
||||
# Enable SSH daemon for remote access
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "yes";
|
||||
PasswordAuthentication = true;
|
||||
};
|
||||
};
|
||||
|
||||
# ISO customization
|
||||
isoImage = {
|
||||
volumeID = "NIXOS-LIVE";
|
||||
};
|
||||
|
||||
# Enable some useful services
|
||||
services.udisks2.enable = true; # For mounting USB drives
|
||||
|
||||
# Hardware support
|
||||
hardware.enableAllFirmware = true;
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
}
|
||||
@@ -12,9 +12,21 @@
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
bluetooth.enable = true;
|
||||
desktop.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
wayland = true;
|
||||
gaming.enable = true;
|
||||
kde = true;
|
||||
sddm = true;
|
||||
};
|
||||
nfs-mounts.enable = true;
|
||||
printing.enable = true;
|
||||
remote-build.builders = [{
|
||||
hostName = "zix790prors";
|
||||
maxJobs = 16;
|
||||
speedFactor = 3;
|
||||
}];
|
||||
spotifyd.enable = true;
|
||||
users = {
|
||||
enable = true;
|
||||
extraGroups = [ "video" ];
|
||||
@@ -27,14 +39,30 @@
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
boot.initrd.luks.devices."luks-b614167b-9045-4234-a441-ac6f60a96d81".device = "/dev/disk/by-uuid/b614167b-9045-4234-a441-ac6f60a96d81";
|
||||
|
||||
services.logind.settings.Login = {
|
||||
HandleLidSwitch = "suspend-then-hibernate";
|
||||
HandlePowerKey = "hibernate";
|
||||
HandlePowerKeyLongPress = "poweroff";
|
||||
};
|
||||
systemd.sleep.extraConfig = ''
|
||||
HibernateDelaySec=30m
|
||||
SuspendState=mem
|
||||
'';
|
||||
|
||||
networking.hostName = "nix-book"; # Define your hostname.
|
||||
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
||||
|
||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
|
||||
# Enable networking
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
# WireGuard setup
|
||||
networking.wg-quick.interfaces = {
|
||||
ogleNet = {
|
||||
configFile = "/root/Oglehome-VPN-johno-nixbook.conf";
|
||||
};
|
||||
};
|
||||
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; [
|
||||
|
||||
@@ -10,15 +10,27 @@
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "vmd" "nvme" "sdhci_pci" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.initrd.luks.devices."luks-4126fbd4-bd09-4ece-af0d-6fff414c21b3".device = "/dev/disk/by-uuid/4126fbd4-bd09-4ece-af0d-6fff414c21b3";
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/bd396529-e2c4-47cb-b844-8d6ed841f81a";
|
||||
fsType = "ext4";
|
||||
roles.btrfs = {
|
||||
enable = true;
|
||||
filesystems."/dev/disk/by-uuid/223a44e5-91e2-4272-830e-129166042a1d" = {
|
||||
mountpoints = {
|
||||
"/" = {
|
||||
compression = "zstd";
|
||||
extraOptions = [ "noatime" ];
|
||||
};
|
||||
};
|
||||
scrub.enable = true;
|
||||
deduplication = {
|
||||
enable = true;
|
||||
hashTableSizeMB = 32;
|
||||
verbosity = "err";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
boot.initrd.luks.devices."luks-4126fbd4-bd09-4ece-af0d-6fff414c21b3".device = "/dev/disk/by-uuid/4126fbd4-bd09-4ece-af0d-6fff414c21b3";
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/7A0B-CF88";
|
||||
@@ -29,6 +41,7 @@
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/ec1f70ea-27b6-4646-ad3b-eac41bd83e3e"; }
|
||||
];
|
||||
zramSwap.enable = true;
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
|
||||
223
machines/nix-book/nixbook-btrfs-migration.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# NixBook ext4 to btrfs Migration Guide
|
||||
|
||||
## Overview
|
||||
This guide converts your nixbook machine from ext4 to btrfs with zstd compression and beesd deduplication while preserving your LUKS encryption and all data.
|
||||
|
||||
## Current System Info
|
||||
- **Hostname**: nix-book
|
||||
- **Root filesystem**: ext4 on `/dev/disk/by-uuid/bd396529-e2c4-47cb-b844-8d6ed841f81a`
|
||||
- **Encryption**: LUKS with two devices configured
|
||||
- **Current usage**: 138GB used / 225GB total (65% full)
|
||||
- **Free space**: 76GB available (sufficient for conversion)
|
||||
|
||||
## Pre-Migration Checklist
|
||||
|
||||
### 1. Create Full System Backup (CRITICAL)
|
||||
```bash
|
||||
# Boot from NixOS live USB
|
||||
# Mount encrypted filesystem
|
||||
cryptsetup luksOpen /dev/disk/by-uuid/4126fbd4-bd09-4ece-af0d-6fff414c21b3 luks-nixbook
|
||||
mount /dev/mapper/luks-nixbook /mnt
|
||||
|
||||
# Create backup to external drive (adjust target as needed)
|
||||
rsync -avxHAX --progress /mnt/ /path/to/backup/nixbook-backup/
|
||||
```
|
||||
|
||||
### 2. Verify Configuration Changes
|
||||
The following files have been updated for btrfs:
|
||||
- `machines/nix-book/configuration.nix` - Added beesd service
|
||||
- `machines/nix-book/hardware-configuration.nix` - Changed fsType to btrfs with compression
|
||||
|
||||
## Migration Process
|
||||
|
||||
### Phase 1: Boot to Live Environment
|
||||
1. **Create NixOS live USB**:
|
||||
```bash
|
||||
# Download latest NixOS ISO
|
||||
# Flash to USB drive
|
||||
dd if=nixos-minimal-xx.xx-x86_64-linux.iso of=/dev/sdX bs=4M status=progress
|
||||
```
|
||||
|
||||
2. **Boot from live USB** and ensure you can access the encrypted drives
|
||||
|
||||
### Phase 2: Filesystem Conversion
|
||||
3. **Unlock LUKS volumes**:
|
||||
```bash
|
||||
cryptsetup luksOpen /dev/disk/by-uuid/4126fbd4-bd09-4ece-af0d-6fff414c21b3 luks-nixbook
|
||||
cryptsetup luksOpen /dev/disk/by-uuid/b614167b-9045-4234-a441-ac6f60a96d81 luks-nixbook2
|
||||
```
|
||||
|
||||
4. **Check filesystem before conversion**:
|
||||
```bash
|
||||
fsck.ext4 -f /dev/mapper/luks-nixbook
|
||||
```
|
||||
|
||||
5. **Convert ext4 to btrfs** (this preserves all data):
|
||||
```bash
|
||||
# Install btrfs-progs if not available
|
||||
nix-shell -p btrfs-progs
|
||||
|
||||
# Convert the filesystem (takes 15-45 minutes depending on data)
|
||||
btrfs-convert /dev/mapper/luks-nixbook
|
||||
|
||||
# Verify conversion succeeded
|
||||
mount /dev/mapper/luks-nixbook /mnt
|
||||
ls -la /mnt # Should show your normal filesystem
|
||||
btrfs filesystem show /mnt
|
||||
```
|
||||
|
||||
6. **Get new filesystem UUID** (may have changed):
|
||||
```bash
|
||||
blkid /dev/mapper/luks-nixbook
|
||||
# Note the new UUID if it changed
|
||||
```
|
||||
|
||||
### Phase 3: Configuration Update
|
||||
7. **Mount and chroot into system**:
|
||||
```bash
|
||||
mount -o compress=zstd,noatime /dev/mapper/luks-nixbook /mnt
|
||||
mount /dev/disk/by-uuid/7A0B-CF88 /mnt/boot
|
||||
nixos-enter --root /mnt
|
||||
```
|
||||
|
||||
8. **Update hardware-configuration.nix** if UUID changed:
|
||||
```bash
|
||||
# Edit /etc/nixos/hardware-configuration.nix if needed
|
||||
# Update the UUID in fileSystems."/" section
|
||||
```
|
||||
|
||||
9. **Rebuild system with btrfs configuration**:
|
||||
```bash
|
||||
cd /home/johno/nixos-configs
|
||||
nixos-rebuild switch --flake .#nix-book
|
||||
```
|
||||
|
||||
### Phase 4: Enable Compression and Deduplication
|
||||
10. **Reboot into new btrfs system**:
|
||||
```bash
|
||||
exit # Exit chroot
|
||||
umount -R /mnt
|
||||
reboot
|
||||
```
|
||||
|
||||
11. **Verify btrfs is working**:
|
||||
```bash
|
||||
mount | grep btrfs
|
||||
btrfs filesystem usage /
|
||||
```
|
||||
|
||||
12. **Enable and start beesd**:
|
||||
```bash
|
||||
systemctl status beesd-root
|
||||
systemctl start beesd-root
|
||||
systemctl enable beesd-root
|
||||
```
|
||||
|
||||
13. **Force compression on existing files** (optional but recommended):
|
||||
```bash
|
||||
# This will compress existing files with zstd
|
||||
btrfs filesystem defragment -r -czstd /
|
||||
```
|
||||
|
||||
## Post-Migration Verification
|
||||
|
||||
### Check System Health
|
||||
```bash
|
||||
# Verify btrfs health
|
||||
btrfs scrub start /
|
||||
btrfs scrub status /
|
||||
|
||||
# Check compression effectiveness
|
||||
compsize /
|
||||
|
||||
# Monitor beesd deduplication
|
||||
journalctl -u beesd-root -f
|
||||
|
||||
# Check filesystem usage
|
||||
btrfs filesystem usage /
|
||||
df -h /
|
||||
```
|
||||
|
||||
### Performance Monitoring
|
||||
```bash
|
||||
# Monitor beesd hash table
|
||||
ls -lh /.beeshash
|
||||
|
||||
# Check compression ratio over time
|
||||
compsize /home /nix /var
|
||||
```
|
||||
|
||||
## Expected Benefits
|
||||
|
||||
### Space Savings
|
||||
- **Compression**: 20-30% reduction in disk usage from zstd
|
||||
- **Deduplication**: Additional 10-20% savings on duplicate files
|
||||
- **Combined**: Potentially 30-40% total space savings
|
||||
|
||||
### Performance Impact
|
||||
- **Compression**: Minimal CPU overhead, often improves I/O performance
|
||||
- **Deduplication**: Background process, minimal impact during normal use
|
||||
- **Overall**: Should be neutral to positive performance impact
|
||||
|
||||
## Rollback Plan (Emergency)
|
||||
|
||||
If something goes wrong:
|
||||
|
||||
1. **Boot from live USB**
|
||||
2. **Restore from backup**:
|
||||
```bash
|
||||
cryptsetup luksOpen /dev/disk/by-uuid/4126fbd4-bd09-4ece-af0d-6fff414c21b3 luks-nixbook
|
||||
mkfs.ext4 /dev/mapper/luks-nixbook
|
||||
mount /dev/mapper/luks-nixbook /mnt
|
||||
rsync -avxHAX --progress /path/to/backup/nixbook-backup/ /mnt/
|
||||
```
|
||||
3. **Restore original hardware-configuration.nix** with ext4 settings
|
||||
4. **Rebuild and reboot**
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**"Device busy" during conversion**:
|
||||
- Ensure no processes are accessing the filesystem
|
||||
- Check with `lsof` and `fuser`
|
||||
|
||||
**UUID changed after conversion**:
|
||||
- Update hardware-configuration.nix with new UUID
|
||||
- Regenerate initrd: `nixos-rebuild switch`
|
||||
|
||||
**Beesd service fails to start**:
|
||||
- Check disk space for hash table
|
||||
- Verify filesystem is btrfs: `mount | grep btrfs`
|
||||
- Check logs: `journalctl -u beesd-root`
|
||||
|
||||
**Boot issues after conversion**:
|
||||
- Boot from live USB
|
||||
- Check /boot partition is mounted correctly
|
||||
- Verify LUKS UUIDs match in configuration
|
||||
- Rebuild bootloader: `nixos-rebuild switch --install-bootloader`
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Regular Tasks
|
||||
```bash
|
||||
# Monthly scrub (checks for corruption)
|
||||
btrfs scrub start /
|
||||
|
||||
# Monitor compression effectiveness
|
||||
compsize /
|
||||
|
||||
# Check beesd deduplication status
|
||||
systemctl status beesd-root
|
||||
```
|
||||
|
||||
### Space Management
|
||||
```bash
|
||||
# Balance filesystem (defragments and optimizes)
|
||||
btrfs balance start -dusage=50 /
|
||||
|
||||
# Check for space issues
|
||||
btrfs filesystem usage /
|
||||
```
|
||||
|
||||
This migration preserves all your data while gaining the benefits of modern btrfs features including transparent compression and automatic deduplication.
|
||||
41
machines/nix-deck/configuration.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
../../roles/desktop/steamos.nix
|
||||
];
|
||||
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
bluetooth.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
wayland = true;
|
||||
gaming.enable = true;
|
||||
kde = true;
|
||||
steamos = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
desktopSession = "plasma";
|
||||
};
|
||||
};
|
||||
remote-build.builders = [{
|
||||
hostName = "zix790prors";
|
||||
maxJobs = 16;
|
||||
speedFactor = 4; # Prefer remote heavily on Steam Deck
|
||||
}];
|
||||
users = {
|
||||
enable = true;
|
||||
extraGroups = [ "video" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Bootloader
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
networking.hostName = "nix-deck";
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
system.stateVersion = "25.05";
|
||||
}
|
||||
51
machines/nix-deck/hardware-configuration.nix
Normal file
@@ -0,0 +1,51 @@
|
||||
# Hardware configuration for Steam Deck (nix-deck)
|
||||
# Generated from nixos-generate-config on 2025-11-17
|
||||
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
# Steam Deck specific hardware configuration (Jovian)
|
||||
jovian.devices.steamdeck = {
|
||||
enable = true;
|
||||
autoUpdate = false; # Set to true if you want automatic firmware updates
|
||||
};
|
||||
|
||||
# Kernel modules detected by nixos-generate-config
|
||||
boot.initrd.availableKernelModules = [
|
||||
"nvme"
|
||||
"xhci_pci"
|
||||
"usb_storage"
|
||||
"uas"
|
||||
"usbhid"
|
||||
"sd_mod"
|
||||
"sdhci_pci"
|
||||
];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# IMPORTANT: Update these filesystem configurations based on your actual partition layout
|
||||
# The configuration below is a placeholder - adjust according to how you partitioned the disk
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-label/nixos";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-label/boot";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices = [{
|
||||
device = "/swapfile";
|
||||
size = 8192; # 8GB swap file
|
||||
}];
|
||||
|
||||
# AMD CPU microcode updates
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
62
machines/wixos/configuration.nix
Normal file
@@ -0,0 +1,62 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page, on
|
||||
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
|
||||
|
||||
# NixOS-WSL specific options are documented on the NixOS-WSL repository:
|
||||
# https://github.com/nix-community/NixOS-WSL
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
];
|
||||
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
wayland = true;
|
||||
};
|
||||
users.enable = true;
|
||||
};
|
||||
|
||||
networking.hostName = "wixos";
|
||||
|
||||
wsl.enable = true;
|
||||
wsl.defaultUser = "johno";
|
||||
wsl.startMenuLaunchers = true;
|
||||
wsl.useWindowsDriver = true;
|
||||
wsl.wslConf.network.hostname = "wixos";
|
||||
wsl.wslConf.user.default = "johno";
|
||||
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
|
||||
extraPackages = with pkgs; [
|
||||
mesa
|
||||
libvdpau-va-gl
|
||||
libva-vdpau-driver
|
||||
];
|
||||
};
|
||||
environment.sessionVariables = {
|
||||
LD_LIBRARY_PATH = [
|
||||
"/usr/lib/wsl/lib"
|
||||
"/run/opengl-driver/lib"
|
||||
];
|
||||
};
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true;
|
||||
nvidiaSettings = true;
|
||||
open = true;
|
||||
package = config.boot.kernelPackages.nvidiaPackages.latest;
|
||||
};
|
||||
|
||||
# This value determines the NixOS release from which the default
|
||||
# settings for stateful data, like file locations and database versions
|
||||
# on your system were taken. It's perfectly fine and recommended to leave
|
||||
# this value at the release version of the first install of this system.
|
||||
# Before changing this value read the documentation for this option
|
||||
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||
system.stateVersion = "24.05"; # Did you read the comment?
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page
|
||||
# and in the NixOS manual (accessible by running ‘nixos-help’).
|
||||
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ # Include the results of the hardware scan.
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
x11Only = true;
|
||||
};
|
||||
kodi.enable = true;
|
||||
nfs-mounts.enable = true;
|
||||
printing.enable = true;
|
||||
spotifyd.enable = true;
|
||||
users = {
|
||||
enable = true;
|
||||
extraGroups = [ "input" "libvirtd" ];
|
||||
kids = true;
|
||||
};
|
||||
virtualisation.enable = true;
|
||||
};
|
||||
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.grub.useOSProber = true;
|
||||
|
||||
networking = {
|
||||
hostName = "z790prors-nix"; # Define your hostname.
|
||||
domain = "oglehome";
|
||||
defaultGateway = "10.0.0.1";
|
||||
nameservers = [ "10.0.0.1" ];
|
||||
|
||||
# The global useDHCP flag is deprecated, therefore explicitly set to false here.
|
||||
# Per-interface useDHCP will be mandatory in the future, so this generated config
|
||||
# replicates the default behaviour.
|
||||
useDHCP = false;
|
||||
|
||||
interfaces.enp3s0.ipv4.addresses = [{
|
||||
address = "10.0.0.37";
|
||||
prefixLength = 24;
|
||||
}];
|
||||
};
|
||||
|
||||
# TODO: Figure out something with this
|
||||
nix.settings.secret-key-files = /root/cache-priv-key.pem;
|
||||
|
||||
# This value determines the NixOS release from which the default
|
||||
# settings for stateful data, like file locations and database versions
|
||||
# on your system were taken. It‘s perfectly fine and recommended to leave
|
||||
# this value at the release version of the first install of this system.
|
||||
# Before changing this value read the documentation for this option
|
||||
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
|
||||
system.stateVersion = "21.11"; # Did you read the comment?
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [
|
||||
"nvidia"
|
||||
"nvidia_modeset"
|
||||
"nvidia_uvm"
|
||||
"nvidia_drm"
|
||||
];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
hardware.graphics.enable = true;
|
||||
services.xserver.videoDrivers = ["nvidia"];
|
||||
services.xserver.screenSection = ''Option "metamodes" "3440x1440_165 +0+0"'';
|
||||
services.xserver.enableTearFree = true;
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true;
|
||||
powerManagement.enable = false;
|
||||
powerManagement.finegrained = false;
|
||||
open = false;
|
||||
nvidiaSettings = true;
|
||||
package = config.boot.kernelPackages.nvidiaPackages.production;
|
||||
};
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/8d996d13-6d55-4524-83a2-6f6fb47a09ea";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/7445-C336";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
fileSystems."/arch" =
|
||||
{ device = "/dev/disk/by-label/endeavouros";
|
||||
fsType = "btrfs";
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
31
machines/zix790prors/README.org
Normal file
@@ -0,0 +1,31 @@
|
||||
* zix790prors
|
||||
|
||||
The re-birthed NixOS install of my 2024/2025 gaming pc / workstation.
|
||||
|
||||
** Specs
|
||||
- **CPU:** Intel Core i7-14700K (20 cores, 28 threads, up to 5.6 GHz)
|
||||
- **Memory:** 64 GB RAM
|
||||
- **Storage:**
|
||||
- 4TB NVMe SSD (main drive with dual-boot partitions)
|
||||
- Windows 11 partition (NTFS)
|
||||
- NixOS /nix/store partition (btrfs)
|
||||
- Shared /games partition (btrfs, accessible from both Windows and NixOS)
|
||||
- **GPU:** NVIDIA GeForce RTX 4070 Ti
|
||||
- **Boot:** UEFI with 100MB EFI System Partition
|
||||
|
||||
This is a powerful all-purpose workstation optimized for gaming, 3D modeling, and development. It dual-boots Windows 11 with a shared btrfs /games partition accessible from both operating systems.
|
||||
*** Validation
|
||||
Given the above specs, I want to run shell commands to validate them for accuracy. Use the run_shell_command tool to get the results required to complete this validation. Do not return to the user until you have exhausted your self-serve options for accomplishing your task.
|
||||
|
||||
** BIOS Settings
|
||||
|
||||
**2025-09-08**
|
||||
|
||||
I underclocked the CPU today. I set the cpu/cache voltage offset to -50mV and lowered the P-Core multiplier from 56x to 50x. I was able to run Intel XTU benchmarks and the CPU stayed around 80C without any throttling kicking in, whereas before it would bounce around various cores at 100C with lots of throttling taking place.
|
||||
|
||||
My goals for this change are:
|
||||
- CPU longevity
|
||||
- Fan noise
|
||||
- Addressing various apps that say 100C is a "critical temperature" (though I believe the CPU is rated for up to 110C)
|
||||
|
||||
I'm leaving some performance on the table, but it almost feels like the default settings for this CPU were to effectively be overclocked.
|
||||
96
machines/zix790prors/configuration.nix
Normal file
@@ -0,0 +1,96 @@
|
||||
# Edit this configuration file to define what should be installed on
|
||||
# your system. Help is available in the configuration.nix(5) man page, on
|
||||
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
|
||||
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
#./virtual-surround.nix
|
||||
];
|
||||
|
||||
roles = {
|
||||
audio.enable = true;
|
||||
bluetooth.enable = true;
|
||||
desktop = {
|
||||
enable = true;
|
||||
gaming = {
|
||||
enable = true;
|
||||
};
|
||||
kde = true;
|
||||
sddm = true;
|
||||
wayland = true;
|
||||
x11 = true;
|
||||
};
|
||||
nfs-mounts.enable = true;
|
||||
nvidia.enable = true;
|
||||
printing.enable = true;
|
||||
remote-build.enableBuilder = true;
|
||||
users.enable = true;
|
||||
virtualisation.enable = true;
|
||||
};
|
||||
|
||||
# Use the systemd-boot EFI boot loader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.systemd-boot.configurationLimit = 20;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.timeout = 10;
|
||||
|
||||
networking.hostName = "zix790prors"; # Define your hostname.
|
||||
|
||||
# Enable networking
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
# Fix dual boot clock sync - tell Linux to use local time for hardware clock
|
||||
time.hardwareClockInLocalTime = true;
|
||||
|
||||
# NVIDIA Graphics configuration
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.graphics.enable = true;
|
||||
hardware.graphics.enable32Bit = true;
|
||||
|
||||
# Set DP-0 as primary display with 164.90Hz refresh rate
|
||||
services.xserver.displayManager.sessionCommands = ''
|
||||
${pkgs.xorg.xrandr}/bin/xrandr --output DP-0 --mode 3440x1440 --rate 164.90 --primary
|
||||
'';
|
||||
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true;
|
||||
nvidiaSettings = true;
|
||||
package = pkgs.linuxPackages.nvidiaPackages.stable;
|
||||
open = true;
|
||||
|
||||
# For gaming performance
|
||||
powerManagement.enable = false;
|
||||
powerManagement.finegrained = false;
|
||||
};
|
||||
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
acceleration = "cuda";
|
||||
loadModels = [ "gpt-oss" "deepseek-r1" "qwen3:30b" ];
|
||||
};
|
||||
|
||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||
#
|
||||
# Most users should NEVER change this value after the initial install, for any reason,
|
||||
# even if you've upgraded your system to a new NixOS release.
|
||||
#
|
||||
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
|
||||
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
|
||||
# to actually do that.
|
||||
#
|
||||
# This value being lower than the current NixOS release does NOT mean your system is
|
||||
# out of date, out of support, or vulnerable.
|
||||
#
|
||||
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
|
||||
# and migrated your data accordingly.
|
||||
#
|
||||
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
|
||||
system.stateVersion = "25.11"; # Did you read the comment?
|
||||
|
||||
}
|
||||
57
machines/zix790prors/hardware-configuration.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/11C1-EB58";
|
||||
fsType = "vfat";
|
||||
options = [ "fmask=0077" "dmask=0077" ];
|
||||
};
|
||||
|
||||
roles.btrfs = {
|
||||
enable = true;
|
||||
filesystems."/dev/disk/by-uuid/ec22734b-d1a3-4c99-8c6f-86f6a8d79007" = {
|
||||
mountpoints = {
|
||||
"/" = {
|
||||
compression = "zstd";
|
||||
extraOptions = [ "noatime" ];
|
||||
};
|
||||
};
|
||||
scrub.enable = true;
|
||||
deduplication = {
|
||||
enable = true;
|
||||
hashTableSizeMB = 128;
|
||||
verbosity = "err";
|
||||
};
|
||||
};
|
||||
filesystems."/dev/disk/by-uuid/4f9844ac-c1ad-4426-8eb3-21f2306345fb" = {
|
||||
mountpoints = {
|
||||
"/games" = {
|
||||
extraOptions = [ "noatime" ];
|
||||
};
|
||||
};
|
||||
scrub.enable = true;
|
||||
deduplication = {
|
||||
enable = true;
|
||||
hashTableSizeMB = 256;
|
||||
verbosity = "err";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
132
machines/zix790prors/virtual-surround.nix
Normal file
@@ -0,0 +1,132 @@
|
||||
# Virtual 4.1 surround sound setup
|
||||
# Routes FL/FR to AmazonBasics USB speaker, RL/RR to Fosi BT20A PRO Bluetooth speaker
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
services.pipewire.extraConfig.pipewire."10-virtual-surround" = {
|
||||
"context.objects" = [
|
||||
{
|
||||
factory = "adapter";
|
||||
args = {
|
||||
"factory.name" = "support.null-audio-sink";
|
||||
"node.name" = "virtual_surround_sink";
|
||||
"node.description" = "Virtual 4.1 Surround (AmazonBasics + Fosi)";
|
||||
"media.class" = "Audio/Sink";
|
||||
"audio.position" = [ "FL" "FR" "RL" "RR" "LFE" ];
|
||||
"monitor.channel-volumes" = true;
|
||||
};
|
||||
}
|
||||
];
|
||||
"context.modules" = [
|
||||
{
|
||||
name = "libpipewire-module-loopback";
|
||||
args = {
|
||||
"node.description" = "Route Front to AmazonBasics";
|
||||
"capture.props" = {
|
||||
"node.name" = "route_front_capture";
|
||||
"audio.position" = [ "FL" "FR" ];
|
||||
"stream.dont-remix" = true;
|
||||
"node.passive" = true;
|
||||
};
|
||||
"playback.props" = {
|
||||
"node.name" = "route_front_playback";
|
||||
"node.target" = "alsa_output.usb-C-Media_Electronics_Inc._AmazonBasics_Professional_Mic_2-00.analog-stereo";
|
||||
"audio.position" = [ "FL" "FR" ];
|
||||
"stream.dont-remix" = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "libpipewire-module-loopback";
|
||||
args = {
|
||||
"node.description" = "Route Rear to Fosi Audio";
|
||||
"capture.props" = {
|
||||
"node.name" = "route_rear_capture";
|
||||
"audio.position" = [ "RL" "RR" ];
|
||||
"stream.dont-remix" = true;
|
||||
"node.passive" = true;
|
||||
};
|
||||
"playback.props" = {
|
||||
"node.name" = "route_rear_playback";
|
||||
"node.target" = "bluez_output.F4_4E_FD_FB_58_62.1";
|
||||
"audio.position" = [ "FL" "FR" ];
|
||||
"stream.dont-remix" = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "libpipewire-module-loopback";
|
||||
args = {
|
||||
"node.description" = "Route Subwoofer to AmazonBasics";
|
||||
"capture.props" = {
|
||||
"node.name" = "route_lfe_capture";
|
||||
"audio.position" = [ "LFE" ];
|
||||
"stream.dont-remix" = true;
|
||||
"node.passive" = true;
|
||||
};
|
||||
"playback.props" = {
|
||||
"node.name" = "route_lfe_playback";
|
||||
"node.target" = "alsa_output.usb-C-Media_Electronics_Inc._AmazonBasics_Professional_Mic_2-00.analog-stereo";
|
||||
"audio.position" = [ "MONO" ];
|
||||
"stream.dont-remix" = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Systemd services to fix PipeWire loopback routing for virtual surround
|
||||
systemd.user.services.pipewire-surround-link = {
|
||||
description = "Link virtual surround sink to loopback captures";
|
||||
after = [ "pipewire.service" "wireplumber.service" ];
|
||||
requires = [ "pipewire.service" "wireplumber.service" ];
|
||||
wantedBy = [ "pipewire.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = false;
|
||||
ExecStart = pkgs.writeShellScript "surround-link" ''
|
||||
sleep 2
|
||||
# Disconnect wrong connections
|
||||
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX0 route_front_capture:input_FL 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX1 route_front_capture:input_FR 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX0 route_rear_capture:input_RL 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX1 route_rear_capture:input_RR 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link -d alsa_input.pci-0000_00_1f.3.pro-input-2:capture_AUX0 route_lfe_capture:input_LFE 2>/dev/null || true
|
||||
# Create correct connections
|
||||
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_FL route_front_capture:input_FL 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_FR route_front_capture:input_FR 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_RL route_rear_capture:input_RL 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_RR route_rear_capture:input_RR 2>/dev/null || true
|
||||
${pkgs.pipewire}/bin/pw-link virtual_surround_sink:monitor_LFE route_lfe_capture:input_LFE 2>/dev/null || true
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.services.pipewire-surround-link-check = {
|
||||
description = "Check and fix surround sink links";
|
||||
after = [ "pipewire.service" "wireplumber.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = pkgs.writeShellScript "surround-link-check" ''
|
||||
if ${pkgs.pipewire}/bin/pw-cli ls Node 2>/dev/null | grep -q "bluez_output.F4_4E_FD_FB_58_62"; then
|
||||
if ${pkgs.pipewire}/bin/pw-link -l 2>/dev/null | grep -q "route_front_capture:input_FL.*alsa_input"; then
|
||||
${pkgs.systemd}/bin/systemctl --user start pipewire-surround-link.service
|
||||
fi
|
||||
if ! ${pkgs.pipewire}/bin/pw-link -l 2>/dev/null | grep -q "virtual_surround_sink:monitor_FL.*route_front_capture"; then
|
||||
${pkgs.systemd}/bin/systemctl --user start pipewire-surround-link.service
|
||||
fi
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.timers.pipewire-surround-link-check = {
|
||||
description = "Periodically check surround sink links";
|
||||
wantedBy = [ "default.target" ];
|
||||
timerConfig = {
|
||||
OnStartupSec = "10s";
|
||||
OnUnitActiveSec = "10s";
|
||||
Unit = "pipewire-surround-link-check.service";
|
||||
};
|
||||
};
|
||||
}
|
||||
176
packages/app-launcher-server/app-launcher-server.py
Normal file
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from urllib.parse import urlparse
|
||||
import psutil
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Allowlisted applications that can be launched
|
||||
ALLOWED_APPS = {
|
||||
'firefox': 'firefox',
|
||||
'kodi': 'kodi'
|
||||
}
|
||||
|
||||
def is_app_running(app_name):
|
||||
"""Check if an application is already running, returns (is_running, pid)"""
|
||||
command = ALLOWED_APPS.get(app_name)
|
||||
if not command:
|
||||
return False, None
|
||||
|
||||
logger.debug(f"Looking for processes related to app '{app_name}' (command: '{command}')")
|
||||
|
||||
for proc in psutil.process_iter(['name', 'cmdline', 'pid']):
|
||||
try:
|
||||
proc_name = proc.info['name']
|
||||
cmdline = proc.info['cmdline'] or []
|
||||
|
||||
logger.debug(f"Checking process PID {proc.info['pid']}: name='{proc_name}', cmdline={cmdline}")
|
||||
|
||||
# Check multiple patterns for the application:
|
||||
# 1. Process name exactly matches command
|
||||
# 2. Process name contains the command (e.g., "kodi.bin" contains "kodi")
|
||||
# 3. Command line starts with the command
|
||||
# 4. Command line contains the wrapped version (e.g., ".kodi-wrapped")
|
||||
# 5. Any command line argument ends with the command executable
|
||||
|
||||
matches = False
|
||||
match_reason = ""
|
||||
|
||||
if proc_name == command:
|
||||
matches = True
|
||||
match_reason = f"exact process name match: '{proc_name}'"
|
||||
elif command in proc_name:
|
||||
matches = True
|
||||
match_reason = f"process name contains command: '{proc_name}' contains '{command}'"
|
||||
elif cmdline and cmdline[0] == command:
|
||||
matches = True
|
||||
match_reason = f"exact cmdline match: '{cmdline[0]}'"
|
||||
elif cmdline and cmdline[0].endswith('/' + command):
|
||||
matches = True
|
||||
match_reason = f"cmdline path ends with command: '{cmdline[0]}'"
|
||||
elif cmdline and any(f'.{command}-wrapped' in arg for arg in cmdline):
|
||||
matches = True
|
||||
match_reason = f"wrapped command in cmdline: {cmdline}"
|
||||
elif cmdline and any(f'{command}.bin' in arg for arg in cmdline):
|
||||
matches = True
|
||||
match_reason = f"binary command in cmdline: {cmdline}"
|
||||
|
||||
if matches:
|
||||
logger.info(f"Found running {app_name} process: PID {proc.info['pid']} ({match_reason})")
|
||||
return True, proc.info['pid']
|
||||
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
||||
continue
|
||||
|
||||
logger.debug(f"No running process found for {app_name}")
|
||||
return False, None
|
||||
|
||||
class AppLauncherHandler(BaseHTTPRequestHandler):
|
||||
def log_message(self, format, *args):
|
||||
logger.info(format % args)
|
||||
|
||||
def do_GET(self):
|
||||
if self.path == '/':
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
response = {
|
||||
'status': 'running',
|
||||
'available_apps': list(ALLOWED_APPS.keys()),
|
||||
'usage': 'POST /launch/<app_name> to launch an application'
|
||||
}
|
||||
self.wfile.write(json.dumps(response, indent=2).encode())
|
||||
else:
|
||||
self.send_error(404)
|
||||
|
||||
def do_POST(self):
|
||||
parsed_path = urlparse(self.path)
|
||||
path_parts = parsed_path.path.strip('/').split('/')
|
||||
|
||||
if len(path_parts) == 2 and path_parts[0] == 'launch':
|
||||
app_name = path_parts[1]
|
||||
self.launch_app(app_name)
|
||||
else:
|
||||
self.send_error(404, "Invalid endpoint. Use /launch/<app_name>")
|
||||
|
||||
def launch_app(self, app_name):
|
||||
if app_name not in ALLOWED_APPS:
|
||||
self.send_error(400, f"Application '{app_name}' not allowed. Available apps: {list(ALLOWED_APPS.keys())}")
|
||||
return
|
||||
|
||||
command = ALLOWED_APPS[app_name]
|
||||
|
||||
# Check if app is already running
|
||||
is_running, existing_pid = is_app_running(app_name)
|
||||
if is_running:
|
||||
logger.info(f"Application {app_name} is already running (PID: {existing_pid}), skipping launch")
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
response = {
|
||||
'status': 'success',
|
||||
'message': f'{app_name} is already running',
|
||||
'pid': existing_pid,
|
||||
'already_running': True
|
||||
}
|
||||
self.wfile.write(json.dumps(response).encode())
|
||||
return
|
||||
|
||||
try:
|
||||
# Launch the application in the background
|
||||
# Ensure we have the proper environment for GUI apps
|
||||
env = os.environ.copy()
|
||||
|
||||
logger.info(f"Launching application: {command}")
|
||||
process = subprocess.Popen(
|
||||
[command],
|
||||
env=env,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True
|
||||
)
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'application/json')
|
||||
self.end_headers()
|
||||
response = {
|
||||
'status': 'success',
|
||||
'message': f'Successfully launched {app_name}',
|
||||
'pid': process.pid,
|
||||
'already_running': False
|
||||
}
|
||||
self.wfile.write(json.dumps(response).encode())
|
||||
|
||||
except FileNotFoundError:
|
||||
logger.error(f"Application not found: {command}")
|
||||
self.send_error(500, f"Application '{app_name}' not found on system")
|
||||
except Exception as e:
|
||||
logger.error(f"Error launching {command}: {e}")
|
||||
self.send_error(500, f"Failed to launch {app_name}: {str(e)}")
|
||||
|
||||
def main():
|
||||
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8081
|
||||
|
||||
server = HTTPServer(('0.0.0.0', port), AppLauncherHandler)
|
||||
logger.info(f"App launcher server starting on port {port}")
|
||||
logger.info(f"Available applications: {list(ALLOWED_APPS.keys())}")
|
||||
|
||||
try:
|
||||
server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Server shutting down...")
|
||||
server.server_close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
10
packages/app-launcher-server/default.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{ pkgs }:
|
||||
|
||||
let
|
||||
python = pkgs.python3.withPackages (ps: with ps; [
|
||||
psutil
|
||||
]);
|
||||
in
|
||||
pkgs.writeShellScriptBin "app-launcher-server" ''
|
||||
exec ${python}/bin/python3 ${./app-launcher-server.py} "$@"
|
||||
''
|
||||
116
packages/claude-code/README.md
Normal 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.
|
||||
60
packages/claude-code/default.nix
Normal file
@@ -0,0 +1,60 @@
|
||||
{ lib
|
||||
, stdenv
|
||||
, fetchurl
|
||||
, autoPatchelfHook
|
||||
}:
|
||||
|
||||
let
|
||||
version = "2.0.76";
|
||||
|
||||
srcs = {
|
||||
aarch64-darwin = {
|
||||
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-arm64/claude";
|
||||
sha256 = "b76f6d4d09233e67295897b0a1ed2e22d7afa406431529d8b1b532b63b8cbcbd";
|
||||
};
|
||||
x86_64-darwin = {
|
||||
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/darwin-x64/claude";
|
||||
sha256 = "9d94582f0af5d2201f1c907bf24ff8d216104b897ee0b24795a6c081f40e08d7";
|
||||
};
|
||||
x86_64-linux = {
|
||||
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-x64/claude";
|
||||
sha256 = "5dcdb480f91ba0df0bc8bd6aff148d3dfd3883f0899eeb5b9427a8b0abe7a687";
|
||||
};
|
||||
aarch64-linux = {
|
||||
url = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/${version}/linux-arm64/claude";
|
||||
sha256 = "f64a994c8e5bfb84d7242cebbec75d6919db2ee46d50b8fc7a88d5066db193f9";
|
||||
};
|
||||
};
|
||||
|
||||
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";
|
||||
};
|
||||
}
|
||||
34
packages/claude-code/npm.nix
Normal 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";
|
||||
};
|
||||
}
|
||||
133
packages/claude-code/update.sh
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/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"
|
||||
REPO_ROOT="${REPO_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
||||
NIX_FILE="$REPO_ROOT/packages/claude-code/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'"
|
||||
@@ -1,4 +1,8 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
nextcloudTalkDesktop = pkgs.callPackage ./nextcloud-talk-desktop {};
|
||||
vulkanHDRLayer = pkgs.callPackage ./vulkan-hdr-layer {};
|
||||
tea-rbw = pkgs.callPackage ./tea-rbw {};
|
||||
app-launcher-server = pkgs.callPackage ./app-launcher-server {};
|
||||
claude-code = pkgs.callPackage ./claude-code {};
|
||||
perles = pkgs.callPackage ./perles {};
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
{ lib
|
||||
, stdenv
|
||||
, fetchzip
|
||||
, autoPatchelfHook
|
||||
|
||||
, nss
|
||||
, cairo
|
||||
, xorg
|
||||
, libxkbcommon
|
||||
, alsa-lib
|
||||
, at-spi2-core
|
||||
, mesa
|
||||
, pango
|
||||
, libdrm
|
||||
, vivaldi-ffmpeg-codecs
|
||||
, gtk3
|
||||
, libGL
|
||||
, libglvnd
|
||||
, systemd
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "nextcloud-talk-desktop";
|
||||
version = "0.29.0";
|
||||
|
||||
# Building from source would require building also building Server and Talk components
|
||||
# See https://github.com/nextcloud/talk-desktop?tab=readme-ov-file#%EF%B8%8F-prerequisites
|
||||
src = fetchzip {
|
||||
url = "https://github.com/nextcloud-releases/talk-desktop/releases/download/v${finalAttrs.version}/Nextcloud.Talk-linux-x64-${finalAttrs.version}.zip";
|
||||
hash = "sha256-fBIeNv8tfrVTFExLQDBPhIazvbsJ7a76+W9G0cuQDlw=";
|
||||
stripRoot = false;
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ autoPatchelfHook ];
|
||||
|
||||
buildInputs = [
|
||||
nss
|
||||
cairo
|
||||
alsa-lib
|
||||
at-spi2-core
|
||||
pango
|
||||
libdrm
|
||||
libxkbcommon
|
||||
gtk3
|
||||
vivaldi-ffmpeg-codecs
|
||||
mesa
|
||||
libGL
|
||||
libglvnd
|
||||
] ++ (with xorg; [libX11 libXcomposite libXdamage libXrandr libXfixes libXcursor]);
|
||||
|
||||
# Required to launch the application and proceed past the zygote_linux fork() process
|
||||
# Fixes `Zygote could not fork`
|
||||
runtimeDependencies = [ systemd ];
|
||||
|
||||
preInstall = ''
|
||||
mkdir -p $out/bin
|
||||
mkdir -p $out/opt
|
||||
|
||||
cp -r $src/* $out/opt/
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
# Link the application in $out/bin away from contents of `preInstall`
|
||||
ln -s "$out/opt/Nextcloud Talk-linux-x64/Nextcloud Talk" $out/bin/${finalAttrs.pname}
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Nextcloud Talk Desktop Client Preview";
|
||||
homepage = "https://github.com/nextcloud/talk-desktop";
|
||||
changelog = "https://github.com/nextcloud/talk-desktop/blob/${finalAttrs.version}/CHANGELOG.md";
|
||||
license = licenses.agpl3Only;
|
||||
maintainers = with maintainers; [ kashw2 ];
|
||||
mainProgram = finalAttrs.pname;
|
||||
};
|
||||
})
|
||||
26
packages/perles/default.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{ lib, buildGoModule, fetchFromGitHub }:
|
||||
|
||||
buildGoModule rec {
|
||||
pname = "perles";
|
||||
version = "unstable-2025-01-09";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "zjrosen";
|
||||
repo = "perles";
|
||||
rev = "main";
|
||||
hash = "sha256-JgRayb4+mJ1r0AtdnQfqAw2+QRte+licsfZOaRgYqcs=";
|
||||
};
|
||||
|
||||
vendorHash = "sha256-R7UWTdBuPteneRqxrWK51nqLtZwDsqQoMAcohN4fyak=";
|
||||
|
||||
# Tests require a real git repository context
|
||||
doCheck = false;
|
||||
|
||||
meta = with lib; {
|
||||
description = "A TUI for the Beads issue tracking system with BQL query language";
|
||||
homepage = "https://github.com/zjrosen/perles";
|
||||
license = licenses.mit;
|
||||
maintainers = [ ];
|
||||
mainProgram = "perles";
|
||||
};
|
||||
}
|
||||
58
packages/tea-rbw/default.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
pkgs.writeShellScriptBin "tea" ''
|
||||
set -euo pipefail
|
||||
|
||||
# Check if tea config directory exists and has authentication
|
||||
TEA_CONFIG_DIR="''${XDG_CONFIG_HOME:-$HOME/.config}/tea"
|
||||
TEA_CONFIG_FILE="$TEA_CONFIG_DIR/config.yml"
|
||||
|
||||
# Function to setup tea authentication with rbw
|
||||
setup_tea_auth() {
|
||||
echo "Tea authentication not found. Setting up with rbw..."
|
||||
|
||||
# Check if rbw is available
|
||||
if ! command -v rbw &> /dev/null; then
|
||||
echo "Error: rbw is not available. Please ensure rbw is installed and configured."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Try to get the token from rbw
|
||||
echo "Attempting to retrieve Gitea token from rbw..."
|
||||
echo "Please enter the rbw entry name for your Gitea token:"
|
||||
read -r rbw_entry
|
||||
|
||||
if ! token=$(rbw get "$rbw_entry" 2>/dev/null); then
|
||||
echo "Error: Failed to retrieve token from rbw entry '$rbw_entry'"
|
||||
echo "Available rbw entries:"
|
||||
rbw list 2>/dev/null || echo "Failed to list rbw entries"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prompt for Gitea URL
|
||||
echo "Please enter your Gitea URL (e.g., https://git.example.com):"
|
||||
read -r gitea_url
|
||||
|
||||
# Create tea config directory if it doesn't exist
|
||||
mkdir -p "$TEA_CONFIG_DIR"
|
||||
|
||||
# Setup tea login
|
||||
if ! ${pkgs.tea}/bin/tea login add --name "default" --url "$gitea_url" --token "$token"; then
|
||||
echo "Error: Failed to setup tea authentication"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Tea authentication setup complete!"
|
||||
}
|
||||
|
||||
# Check if tea is already configured
|
||||
if [[ ! -f "$TEA_CONFIG_FILE" ]]; then
|
||||
setup_tea_auth
|
||||
elif ! ${pkgs.tea}/bin/tea whoami &>/dev/null; then
|
||||
echo "Tea config exists but authentication failed. Re-running setup..."
|
||||
setup_tea_auth
|
||||
fi
|
||||
|
||||
# Execute tea with all provided arguments
|
||||
exec ${pkgs.tea}/bin/tea "$@"
|
||||
''
|
||||
34
packages/vulkan-hdr-layer/default.nix
Normal file
@@ -0,0 +1,34 @@
|
||||
{ lib, stdenv, fetchFromGitHub, meson, pkg-config, vulkan-loader, ninja, writeText, vulkan-headers, vulkan-utility-libraries, jq, libX11, libXrandr, libxcb, wayland, wayland-scanner }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "vulkan-hdr-layer";
|
||||
version = "63d2eec";
|
||||
|
||||
src = (fetchFromGitHub {
|
||||
owner = "Zamundaaa";
|
||||
repo = "VK_hdr_layer";
|
||||
rev = "869199cd2746e7f69cf19955153080842b6dacfc";
|
||||
fetchSubmodules = true;
|
||||
hash = "sha256-xfVYI+Aajmnf3BTaY2Ysg5fyDO6SwDFGyU0L+F+E3is=";
|
||||
}).overrideAttrs (_: {
|
||||
GIT_CONFIG_COUNT = 1;
|
||||
GIT_CONFIG_KEY_0 = "url.https://github.com/.insteadOf";
|
||||
GIT_CONFIG_VALUE_0 = "git@github.com:";
|
||||
});
|
||||
|
||||
nativeBuildInputs = [ vulkan-headers meson ninja pkg-config jq ];
|
||||
|
||||
buildInputs = [ vulkan-headers vulkan-loader vulkan-utility-libraries libX11 libXrandr libxcb wayland wayland-scanner ];
|
||||
|
||||
# Help vulkan-loader find the validation layers
|
||||
setupHook = writeText "setup-hook" ''
|
||||
addToSearchPath XDG_DATA_DIRS @out@/share
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Layers providing Vulkan HDR";
|
||||
homepage = "https://github.com/Zamundaaa/VK_hdr_layer";
|
||||
platforms = platforms.linux;
|
||||
license = licenses.mit;
|
||||
};
|
||||
}
|
||||
@@ -13,6 +13,7 @@ in
|
||||
config = mkIf cfg.enable
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
easyeffects
|
||||
paprefs
|
||||
pavucontrol
|
||||
pulsemixer
|
||||
@@ -22,11 +23,19 @@ in
|
||||
enable = true;
|
||||
pulse.enable = true;
|
||||
};
|
||||
hardware.pulseaudio.package = pkgs.pulseaudioFull;
|
||||
hardware.pulseaudio.extraConfig = "
|
||||
|
||||
services.pulseaudio = {
|
||||
package = pkgs.pulseaudioFull;
|
||||
extraConfig = ''
|
||||
load-module module-combine-sink
|
||||
load-module module-switch-on-connect
|
||||
";
|
||||
'';
|
||||
};
|
||||
|
||||
services.squeezelite = {
|
||||
#enable = true;
|
||||
pulseAudio = true;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
173
roles/btrfs/default.nix
Normal file
@@ -0,0 +1,173 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.roles.btrfs;
|
||||
in
|
||||
{
|
||||
options.roles.btrfs = {
|
||||
enable = mkEnableOption "Enable btrfs filesystem management";
|
||||
|
||||
filesystems = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
# Filesystem-level maintenance options
|
||||
scrub = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable automatic scrubbing for this filesystem";
|
||||
};
|
||||
interval = mkOption {
|
||||
type = types.str;
|
||||
default = "weekly";
|
||||
description = "Scrub interval (systemd timer format)";
|
||||
};
|
||||
};
|
||||
deduplication = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable beesd deduplication for this filesystem";
|
||||
};
|
||||
hashTableSizeMB = mkOption {
|
||||
type = types.int;
|
||||
default = 1024;
|
||||
description = "Hash table size in MB (should be multiple of 16)";
|
||||
};
|
||||
verbosity = mkOption {
|
||||
type = types.str;
|
||||
default = "info";
|
||||
description = "Logging verbosity level";
|
||||
};
|
||||
};
|
||||
balance = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable periodic balance operations";
|
||||
};
|
||||
interval = mkOption {
|
||||
type = types.str;
|
||||
default = "monthly";
|
||||
description = "Balance interval (systemd timer format)";
|
||||
};
|
||||
dataUsage = mkOption {
|
||||
type = types.int;
|
||||
default = 50;
|
||||
description = "Data usage threshold for balance";
|
||||
};
|
||||
metadataUsage = mkOption {
|
||||
type = types.int;
|
||||
default = 50;
|
||||
description = "Metadata usage threshold for balance";
|
||||
};
|
||||
};
|
||||
|
||||
# Mountpoint-based configuration
|
||||
mountpoints = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
subvolume = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Subvolume name. If null, uses default subvolume.";
|
||||
};
|
||||
compression = mkOption {
|
||||
type = types.str;
|
||||
default = "zstd";
|
||||
description = "Compression algorithm (zstd, lzo, lz4, none)";
|
||||
};
|
||||
autodefrag = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable automatic defragmentation";
|
||||
};
|
||||
extraOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Additional mount options";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
description = "Mountpoint configurations for this filesystem";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = {};
|
||||
description = "Btrfs filesystems configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = with pkgs; [
|
||||
btrfs-progs
|
||||
compsize
|
||||
];
|
||||
|
||||
# Generate fileSystems configuration from mountpoints
|
||||
fileSystems = mkMerge (flatten (mapAttrsToList (device: fsCfg:
|
||||
mapAttrsToList (mountpoint: mountCfg:
|
||||
{
|
||||
${mountpoint} = {
|
||||
device = device;
|
||||
fsType = "btrfs";
|
||||
options =
|
||||
(optional (mountCfg.subvolume != null) "subvol=${mountCfg.subvolume}") ++
|
||||
[ "compress=${mountCfg.compression}" ] ++
|
||||
(optional mountCfg.autodefrag "autodefrag") ++
|
||||
mountCfg.extraOptions;
|
||||
};
|
||||
}
|
||||
) fsCfg.mountpoints
|
||||
) cfg.filesystems));
|
||||
|
||||
# Configure scrub service using NixOS built-in
|
||||
services.btrfs.autoScrub = mkIf (any (fs: fs.scrub.enable) (attrValues cfg.filesystems)) {
|
||||
enable = true;
|
||||
interval = "weekly"; # TODO: Make this configurable per filesystem
|
||||
fileSystems = attrNames (filterAttrs (_: fs: fs.scrub.enable) cfg.filesystems);
|
||||
};
|
||||
|
||||
# Configure beesd for filesystems with deduplication enabled
|
||||
services.beesd.filesystems = mapAttrs' (device: fsCfg:
|
||||
nameValuePair (replaceStrings ["/"] ["_"] (replaceStrings ["-"] ["_"] device)) {
|
||||
spec = device;
|
||||
hashTableSizeMB = fsCfg.deduplication.hashTableSizeMB;
|
||||
verbosity = fsCfg.deduplication.verbosity;
|
||||
}
|
||||
) (filterAttrs (_: fs: fs.deduplication.enable) cfg.filesystems);
|
||||
|
||||
# Custom balance services for filesystems with balance enabled
|
||||
systemd.services = mkMerge (mapAttrsToList (device: fsCfg: mkIf fsCfg.balance.enable {
|
||||
"btrfs-balance-${replaceStrings ["/"] ["-"] (replaceStrings ["-"] ["_"] device)}" = {
|
||||
description = "Balance btrfs filesystem ${device}";
|
||||
script = ''
|
||||
${pkgs.btrfs-progs}/bin/btrfs balance start \
|
||||
-dusage=${toString fsCfg.balance.dataUsage} \
|
||||
-musage=${toString fsCfg.balance.metadataUsage} \
|
||||
${device}
|
||||
'';
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
Nice = 19;
|
||||
IOSchedulingClass = "idle";
|
||||
};
|
||||
};
|
||||
}) cfg.filesystems);
|
||||
|
||||
# Balance timers
|
||||
systemd.timers = mkMerge (mapAttrsToList (device: fsCfg: mkIf fsCfg.balance.enable {
|
||||
"btrfs-balance-${replaceStrings ["/"] ["-"] (replaceStrings ["-"] ["_"] device)}" = {
|
||||
description = "Periodic balance for ${device}";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = fsCfg.balance.interval;
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
}) cfg.filesystems);
|
||||
};
|
||||
}
|
||||