Compare commits
2 Commits
ea3653c824
...
e463c42740
| Author | SHA1 | Date | |
|---|---|---|---|
| e463c42740 | |||
| 05544d0597 |
10
.sisyphus/boulder.json
Normal file
10
.sisyphus/boulder.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"active_plan": "/home/cschmatzler/nixos-config/.sisyphus/plans/dendritic-migration.md",
|
||||
"started_at": "2026-03-05T10:57:53.044Z",
|
||||
"session_ids": [
|
||||
"ses_34287fe8effeSATHvHUmGqZ5Fp"
|
||||
],
|
||||
"plan_name": "dendritic-migration",
|
||||
"agent": "atlas",
|
||||
"worktree_path": "/home/cschmatzler/nixos-config"
|
||||
}
|
||||
2
.sisyphus/notepads/dendritic-migration/decisions.md
Normal file
2
.sisyphus/notepads/dendritic-migration/decisions.md
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
- Do not include user aspects (e.g. `den.aspects.cschmatzler`) in host aspect `includes`. Den HM integration already applies the user aspect for each `den.hosts.<system>.<host>.users.<user>` via `den.ctx.user`; duplicating it via host `includes` leads to duplicated HM option merges (notably `types.lines` options like `programs.nushell.extraConfig`).
|
||||
3
.sisyphus/notepads/dendritic-migration/issues.md
Normal file
3
.sisyphus/notepads/dendritic-migration/issues.md
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
- Nushell `programs.nushell.extraConfig` duplication traced to Den applying the user aspect twice: it is included via host aspect `includes` (e.g. `den.aspects.tahani.includes = [ ... den.aspects.cschmatzler ... ]`) AND Den's HM integration already includes the user aspect via `den.ctx.user` (see Den `hm-integration.nix`). Result: user-aspect-provided HM config (like `den.aspects.shell.homeManager`) merges twice, so `extraConfig` contains two identical copies.
|
||||
- `dev-tools` nushell functions (e.g. `ggpull`) missing in `michael` is expected: `modules/michael.nix` does not include `den.aspects.dev-tools`.
|
||||
128
.sisyphus/notepads/dendritic-migration/learnings.md
Normal file
128
.sisyphus/notepads/dendritic-migration/learnings.md
Normal file
@@ -0,0 +1,128 @@
|
||||
- For den migration, move legacy non-flake-parts modules into `modules/_legacy/` before enabling `inputs.import-tree ./modules`; import-tree ignores underscore-prefixed paths.
|
||||
- `flake-parts` must include `inputs.nixpkgs-lib.follows = "nixpkgs"` in this repository to match den bootstrap expectations.
|
||||
- The den bootstrap works with `modules/dendritic.nix` importing `(inputs.flake-file.flakeModules.dendritic or { })` and `(inputs.den.flakeModules.dendritic or { })`, plus initial `flake-file.inputs` declarations.
|
||||
- Den host wiring uses `den.hosts.<system>.<hostname>.users.<username> = {}` declarations in `modules/hosts.nix` for each host-user pair.
|
||||
- `den.default.includes` accepts batteries directly via `den.provides.*`; this bootstrap uses `den.provides.define-user` and `den.provides.inputs'`.
|
||||
- In this flake-parts setup, declaring `options.flake.darwinConfigurations` as `lib.types.lazyAttrsOf lib.types.raw` allows multiple Darwin hosts to merge correctly.
|
||||
|
||||
## Task 3: Utility functions under _lib/ - COMPLETED
|
||||
|
||||
**What was done:**
|
||||
- Created `modules/_lib/` directory
|
||||
- Copied 5 pure function files (not NixOS modules):
|
||||
- `lib/constants.nix` → `modules/_lib/constants.nix` (14 lines)
|
||||
- `lib/build-rust-package.nix` → `modules/_lib/build-rust-package.nix` (20 lines)
|
||||
- `profiles/wallpaper.nix` → `modules/_lib/wallpaper.nix` (11 lines)
|
||||
- `profiles/open-project.nix` → `modules/_lib/open-project.nix` (10 lines)
|
||||
- `profiles/packages.nix` → `modules/_lib/packages.nix` (67 lines)
|
||||
|
||||
**Key insight:**
|
||||
- import-tree ignores paths with `/_` prefix, so `modules/_lib/` is safe for pure functions
|
||||
- These files are NOT NixOS/home-manager modules - they're utility functions that would crash import-tree if placed directly under `modules/`
|
||||
- Files were COPIED (not moved) because old locations are still referenced by existing host configs until Task 26
|
||||
|
||||
**Verification:**
|
||||
- All 5 files copied with identical content (byte-for-byte match)
|
||||
- `alejandra --check modules/_lib/` passed (formatting compliant)
|
||||
- `nix flake show` exits 0 (import-tree correctly ignores `_lib/`)
|
||||
|
||||
**Dependencies:**
|
||||
- Unblocks Task 4 (overlays need `build-rust-package.nix` from `_lib/`)
|
||||
|
||||
## Task 2: Hosts and defaults bootstrap notes
|
||||
|
||||
- Den host wiring uses `den.hosts.<system>.<hostname>.users.<username> = {}` declarations in `modules/hosts.nix` for each host-user pair.
|
||||
- `den.default.includes` accepts batteries directly via `den.provides.*`; this bootstrap uses `den.provides.define-user` and `den.provides.inputs'`.
|
||||
- In this flake-parts setup, declaring `options.flake.darwinConfigurations` as `lib.types.lazyAttrsOf lib.types.raw` allows multiple Darwin hosts to merge correctly.
|
||||
|
||||
## Task 5: Core aspect module - COMPLETED
|
||||
|
||||
**What was done:**
|
||||
- Created `modules/core.nix` as a flake-parts module defining `den.aspects.core`
|
||||
- Ported all nix settings from `profiles/core.nix` into the `os` class (applies to both nixos and darwin)
|
||||
- Updated `modules/defaults.nix` to include `den.aspects.core` in `den.default.includes`
|
||||
|
||||
**Key decisions:**
|
||||
- Used `os` class for shared settings (fish, nushell, nixpkgs.config.allowUnfree, nix package, substituters, trusted-public-keys, gc.automatic, gc.options, experimental-features)
|
||||
- Deliberately EXCLUDED `trusted-users` from core.nix (platform-specific: darwin uses "@admin", NixOS uses specific user — handled by darwin.nix and nixos-system.nix)
|
||||
- Deliberately EXCLUDED gc interval/dates (platform-specific: darwin uses `interval`, NixOS uses `dates` — handled by darwin.nix and nixos-system.nix)
|
||||
|
||||
**Verification:**
|
||||
- `modules/core.nix` created with 35 lines (exact port of profiles/core.nix settings)
|
||||
- `modules/defaults.nix` updated to include `den.aspects.core` in includes list
|
||||
- `alejandra .` formatted both files successfully
|
||||
- `nix flake show` exits 0 (flake evaluates cleanly)
|
||||
|
||||
**Dependencies:**
|
||||
- Unblocks Task 6 (darwin.nix and nixos-system.nix can now reference den.aspects.core)
|
||||
|
||||
## Task 6a: NixOS system aspect - COMPLETED
|
||||
|
||||
**What was done:**
|
||||
- Created `modules/nixos-system.nix` as a flake-parts module defining `den.aspects.nixos-system`
|
||||
- Ported NixOS-specific config from `profiles/nixos.nix` into the `nixos` class
|
||||
|
||||
**Key decisions:**
|
||||
- Used `nixos` class (not `os`) since all settings are NixOS-specific (sudo, boot, systemd-boot, users)
|
||||
- `nixos` class uses NixOS module function form `{pkgs, ...}: { ... }` to access `pkgs` for `linuxPackages_latest` and `nushell`
|
||||
- `inputs` accessed from outer flake-parts module args for `home-manager.nixosModules.home-manager` import
|
||||
- Hardcoded "cschmatzler" instead of variable interpolation (user is always the same)
|
||||
- Hardcoded SSH keys inline instead of referencing constants (simplifies dependency)
|
||||
- Deliberately EXCLUDED: system.stateVersion (in defaults.nix), sops.age.sshKeyPaths (in secrets.nix), home-manager.sharedModules/_module.args (den handles via inputs' battery)
|
||||
|
||||
**Pattern:**
|
||||
- Outer function: `{inputs, ...}:` — flake-parts module args
|
||||
- Inner class: `nixos = {pkgs, ...}: { ... }` — NixOS module function
|
||||
- `imports = [inputs.home-manager.nixosModules.home-manager]` inside the nixos class
|
||||
|
||||
**Verification:**
|
||||
- `alejandra --check .` passes (already compliant on write)
|
||||
- `nix flake show` exits 0 (both michael and tahani evaluate cleanly)
|
||||
|
||||
## Task 6b: Darwin system aspect - COMPLETED
|
||||
|
||||
**What was done:**
|
||||
- Created `modules/darwin.nix` as a flake-parts module defining `den.aspects.darwin-system`
|
||||
- Created `modules/_darwin/dock.nix` — the dock module (NixOS-style with options/config)
|
||||
- Ported profiles/darwin.nix, profiles/dock.nix, profiles/homebrew.nix, and nix-homebrew config
|
||||
|
||||
**Files created:**
|
||||
- `modules/darwin.nix` — flake-parts module with `den.aspects.darwin-system.darwin` class
|
||||
- `modules/_darwin/dock.nix` — dock options+activation script module (underscore prefix avoids import-tree)
|
||||
|
||||
**Key decisions:**
|
||||
- `darwin` class uses NixOS module function form `{pkgs, ...}: { ... }` to access `pkgs.nushell`
|
||||
- `inputs` accessed from outer flake-parts module args via closure (for nix-homebrew, home-manager, homebrew taps)
|
||||
- Dock module placed in `modules/_darwin/dock.nix` and imported via `imports = [./_darwin/dock.nix]` inside the darwin class
|
||||
- All `user` variable references replaced with hardcoded "cschmatzler"
|
||||
- Excluded: home-manager.extraSpecialArgs (den handles via batteries), system.stateVersion (in defaults.nix)
|
||||
- nix-homebrew config wired with taps from flake inputs (homebrew-core, homebrew-cask)
|
||||
|
||||
**Pattern for complex sub-modules:**
|
||||
- Use `modules/_<platform>/` prefix (underscore avoids import-tree auto-import)
|
||||
- Import from aspect class via `imports = [./_darwin/dock.nix]`
|
||||
- The inner NixOS module function captures `inputs` from outer flake-parts scope via Nix closure
|
||||
|
||||
**Verification:**
|
||||
- `alejandra .` — already compliant on write (no changes needed)
|
||||
- `nix flake show` exits 0 (flake evaluates cleanly with new aspect)
|
||||
|
||||
## Task 23: Michael aspect with absorbed gitea module - COMPLETED
|
||||
|
||||
- Created `modules/_hosts/michael/` and copied `hosts/michael/disk-config.nix` plus `hosts/michael/hardware-configuration.nix` byte-for-byte into underscore-prefixed paths so import-tree ignores them.
|
||||
- Added `modules/michael.nix` defining `den.aspects.michael` with includes `den.aspects.nixos-system`, `den.aspects.core`, and `den.aspects.cschmatzler`.
|
||||
- Inlined the full gitea/redis/litestream/caddy/restic/systemd config directly in the michael aspect and removed dependency on `options.my.gitea`.
|
||||
- Preserved intentional `lib.mkForce` overrides for litestream and restic service users/groups.
|
||||
- Replaced legacy `cfg.*` references with concrete values and SOPS paths: litestream bucket `michael-gitea-litestream`, restic bucket `michael-gitea-repositories`, endpoint `s3.eu-central-003.backblazeb2.com`, and `config.sops.secrets.michael-gitea-*.path`.
|
||||
|
||||
## Task 25: Tahani aspect with host sub-files - COMPLETED
|
||||
|
||||
- Created `modules/_hosts/tahani/` and copied `hosts/tahani/{adguardhome,cache,networking,paperless}.nix` byte-for-byte into underscore-prefixed paths so import-tree ignores host-only sub-files.
|
||||
- Added `modules/tahani.nix` defining `den.aspects.tahani` with includes `den.aspects.nixos-system`, `den.aspects.core`, and `den.aspects.cschmatzler` (network aspects intentionally deferred).
|
||||
- Ported tahani-specific NixOS settings into the aspect (`networking.hostName`, docker enablement, docker group membership for `cschmatzler`, and 16 GiB swapfile declaration).
|
||||
- Ported tahani-specific Home Manager settings into the aspect (`programs.git.settings.user.email`, zellij Nushell integration override enabled for tahani).
|
||||
- Inbox-triage systemd unit now uses `pkgs.himalaya` from overlay in `PATH` (`${pkgs.himalaya}/bin`) with `inputs'.llm-agents.packages.opencode` for `ExecStart`; no `config.home-manager.users...` lookup.
|
||||
- Verification: `alejandra .`, `alejandra --check .`, and `nix flake show` all pass; `lsp_diagnostics` is clean on all newly created tahani files.
|
||||
|
||||
- Home Manager `programs.nushell` module writes `config.nu` as a merge of: `environmentVariables` (via `load-env`), flattened `settings`, optional `configFile.text`, then `extraConfig`, then generated `shellAliases` (see HM `modules/programs/nushell.nix`). So any duplication in `config.nu` that is isolated to `extraConfig` almost always means the option value was merged multiple times (module included multiple times), not that HM writes it twice.
|
||||
- In Den, HM user contexts include both the host aspect chain and the user aspect (`den.ctx.user`). If you also include the user aspect from the host aspect `includes`, user HM config is applied twice.
|
||||
1794
.sisyphus/plans/dendritic-migration.md
Normal file
1794
.sisyphus/plans/dendritic-migration.md
Normal file
File diff suppressed because it is too large
Load Diff
93
AGENTS.md
93
AGENTS.md
@@ -12,12 +12,12 @@ nix flake check # Validate flake
|
||||
|
||||
### Remote Deployment (NixOS only)
|
||||
```bash
|
||||
colmena build # Build all NixOS hosts
|
||||
colmena apply --on <host> # Deploy to specific NixOS host (michael, tahani)
|
||||
colmena apply # Deploy to all NixOS hosts
|
||||
nix run .#deploy # Deploy to all NixOS hosts
|
||||
nix run .#deploy -- .#michael # Deploy to specific NixOS host
|
||||
nix run .#deploy -- .#tahani # Deploy to specific NixOS host
|
||||
```
|
||||
|
||||
When you're on tahani and asked to apply, that means running `colmena apply`.
|
||||
When you're on tahani and asked to apply, that means running `nix run .#deploy`.
|
||||
|
||||
### Formatting
|
||||
```bash
|
||||
@@ -32,14 +32,35 @@ alejandra . # Format all Nix files
|
||||
- **Command**: Run `alejandra .` before committing
|
||||
|
||||
### File Structure
|
||||
- **Hosts**: `hosts/<hostname>/` - Per-machine configurations
|
||||
- Darwin: `chidi`, `jason`
|
||||
- NixOS: `michael`, `tahani`
|
||||
- **Profiles**: `profiles/` - Reusable program/service configurations (imported by hosts)
|
||||
- **Modules**: `modules/` - Custom NixOS/darwin modules
|
||||
- **Lib**: `lib/` - Shared constants and utilities
|
||||
- **Modules**: `modules/` - All configuration (flake-parts modules, auto-imported by import-tree)
|
||||
- `_lib/` - Utility functions (underscore = ignored by import-tree)
|
||||
- `_darwin/` - Darwin-specific sub-modules
|
||||
- `_neovim/` - Neovim plugin configs
|
||||
- `_opencode/` - OpenCode agent/command/skill configs
|
||||
- `_hosts/` - Host-specific sub-files (disk-config, hardware, etc.)
|
||||
- **Apps**: `apps/` - Per-system app scripts (Nushell)
|
||||
- **Secrets**: `secrets/` - SOPS-encrypted secrets (`.sops.yaml` for config)
|
||||
|
||||
### Architecture
|
||||
|
||||
**Framework**: den (vic/den) — every .nix file in `modules/` is a flake-parts module
|
||||
|
||||
**Pattern**: Feature/aspect-centric, not host-centric
|
||||
|
||||
**Aspects**: `den.aspects.<name>.<class>` where class is:
|
||||
- `nixos` - NixOS-only configuration
|
||||
- `darwin` - macOS-only configuration
|
||||
- `homeManager` - Home Manager configuration
|
||||
- `os` - Applies to both NixOS and darwin
|
||||
|
||||
**Hosts**: `den.hosts.<system>.<name>` defined in `modules/hosts.nix`
|
||||
|
||||
**Defaults**: `den.default.*` defined in `modules/defaults.nix`
|
||||
|
||||
**Imports**: Auto-imported by import-tree; underscore-prefixed dirs (`_lib/`, `_darwin/`, etc.) are excluded from auto-import
|
||||
|
||||
**Deployment**: deploy-rs for NixOS hosts (michael, tahani); darwin hosts (chidi, jason) are local-only
|
||||
|
||||
### Nix Language Conventions
|
||||
|
||||
**Function Arguments**:
|
||||
@@ -48,20 +69,11 @@ alejandra . # Format all Nix files
|
||||
```
|
||||
Destructure arguments on separate lines. Use `...` to capture remaining args.
|
||||
|
||||
**Imports**:
|
||||
```nix
|
||||
../../profiles/foo.nix
|
||||
```
|
||||
Use relative paths from file location, not absolute paths.
|
||||
|
||||
**Attribute Sets**:
|
||||
```nix
|
||||
options.my.gitea = {
|
||||
enable = lib.mkEnableOption "Gitea git hosting service";
|
||||
bucket = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "S3 bucket name";
|
||||
};
|
||||
den.aspects.myfeature.os = {
|
||||
enable = true;
|
||||
config = "value";
|
||||
};
|
||||
```
|
||||
One attribute per line with trailing semicolons.
|
||||
@@ -77,7 +89,7 @@ with pkgs;
|
||||
```
|
||||
Use `with pkgs;` for package lists, one item per line.
|
||||
|
||||
**Modules**:
|
||||
**Aspect Definition**:
|
||||
```nix
|
||||
{
|
||||
config,
|
||||
@@ -86,9 +98,9 @@ Use `with pkgs;` for package lists, one item per line.
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.my.feature;
|
||||
cfg = config.den.aspects.myfeature;
|
||||
in {
|
||||
options.my.feature = {
|
||||
options.den.aspects.myfeature = {
|
||||
enable = mkEnableOption "Feature description";
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
@@ -113,22 +125,27 @@ in {
|
||||
```
|
||||
|
||||
### Naming Conventions
|
||||
- **Option names**: `my.<feature>.<option>` for custom modules
|
||||
- **Hostnames**: Lowercase, descriptive (e.g., `michael`, `tahani`)
|
||||
- **Profile files**: Descriptive, lowercase with hyphens (e.g., `homebrew.nix`)
|
||||
- **Aspect names**: `den.aspects.<name>.<class>` for feature configuration
|
||||
- **Hostnames**: Lowercase, descriptive (e.g., `michael`, `tahani`, `chidi`, `jason`)
|
||||
- **Module files**: Descriptive, lowercase with hyphens (e.g., `neovim-config.nix`)
|
||||
|
||||
### Secrets Management
|
||||
- Use SOPS for secrets (see `.sops.yaml`)
|
||||
- Never commit unencrypted secrets
|
||||
- Secrets files in `hosts/<host>/secrets.nix` import SOPS-generated files
|
||||
- Secret definitions in `modules/secrets.nix`
|
||||
|
||||
### Imports Pattern
|
||||
Host configs import:
|
||||
1. System modules (`modulesPath + "/..."`)
|
||||
2. Host-specific files (`./disk-config.nix`, `./hardware-configuration.nix`)
|
||||
3. SOPS secrets (`./secrets.nix`)
|
||||
4. Custom modules (`../../modules/*.nix`)
|
||||
5. Base profiles (`../../profiles/*.nix`)
|
||||
6. Input modules (`inputs.<module>.xxxModules.module`)
|
||||
### Aspect Composition
|
||||
Use `den.aspects.<name>.includes` to compose aspects:
|
||||
```nix
|
||||
den.aspects.myfeature.includes = [
|
||||
"other-aspect"
|
||||
"another-aspect"
|
||||
];
|
||||
```
|
||||
|
||||
Home-manager users import profiles in a similar manner.
|
||||
### Key Conventions
|
||||
- No `specialArgs` — den batteries handle input passing
|
||||
- No hostname string comparisons in shared aspects
|
||||
- Host-specific config goes in `den.aspects.<hostname>.*`
|
||||
- Shared config uses `os` class (applies to both NixOS and darwin)
|
||||
- Non-module files go in `_`-prefixed subdirs
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
HOSTNAME="${1:-$(scutil --get LocalHostName 2>/dev/null || hostname -s)}"
|
||||
def main [hostname?: string, ...rest: string] {
|
||||
let host = if ($hostname | is-empty) {
|
||||
try { scutil --get LocalHostName | str trim } catch { hostname -s | str trim }
|
||||
} else { $hostname }
|
||||
|
||||
print_info "Applying configuration for $HOSTNAME"
|
||||
print_info $"Applying configuration for ($host)"
|
||||
|
||||
nix run nix-darwin -- switch --flake ".#$HOSTNAME" "${@:2}"
|
||||
nix run nix-darwin -- switch --flake $".#($host)" ...$rest
|
||||
|
||||
print_success "Configuration applied successfully"
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
HOSTNAME="${1:-$(scutil --get LocalHostName 2>/dev/null || hostname -s)}"
|
||||
def main [hostname?: string, ...rest: string] {
|
||||
let host = if ($hostname | is-empty) {
|
||||
try { scutil --get LocalHostName | str trim } catch { hostname -s | str trim }
|
||||
} else { $hostname }
|
||||
|
||||
print_info "Building configuration for $HOSTNAME"
|
||||
print_info $"Building configuration for ($host)"
|
||||
|
||||
nix build ".#darwinConfigurations.$HOSTNAME.system" --show-trace "${@:2}"
|
||||
nix build $".#darwinConfigurations.($host).system" --show-trace ...$rest
|
||||
|
||||
if [[ -L ./result ]]; then
|
||||
unlink ./result
|
||||
fi
|
||||
if ("./result" | path exists) {
|
||||
rm ./result
|
||||
}
|
||||
|
||||
print_success "Build completed successfully"
|
||||
}
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
HOSTNAME="${1:-$(scutil --get LocalHostName 2>/dev/null || hostname -s)}"
|
||||
def main [hostname?: string, ...rest: string] {
|
||||
let host = if ($hostname | is-empty) {
|
||||
try { scutil --get LocalHostName | str trim } catch { hostname -s | str trim }
|
||||
} else { $hostname }
|
||||
|
||||
print_info "Building and switching configuration for $HOSTNAME"
|
||||
print_info $"Building and switching configuration for ($host)"
|
||||
|
||||
# Build
|
||||
print_info "Building configuration..."
|
||||
if ! nix build ".#darwinConfigurations.$HOSTNAME.system" --show-trace "${@:2}"; then
|
||||
if (nix build $".#darwinConfigurations.($host).system" --show-trace ...$rest | complete).exit_code != 0 {
|
||||
print_error "Build failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_success "Build completed"
|
||||
|
||||
# Switch
|
||||
print_info "Switching to new configuration..."
|
||||
sudo ./result/sw/bin/darwin-rebuild switch --flake ".#$HOSTNAME" "${@:2}"
|
||||
sudo ./result/sw/bin/darwin-rebuild switch --flake $".#($host)" ...$rest
|
||||
|
||||
if [[ -L ./result ]]; then
|
||||
unlink ./result
|
||||
fi
|
||||
if ("./result" | path exists) {
|
||||
rm ./result
|
||||
}
|
||||
|
||||
print_success "Build and switch completed successfully"
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
def main [] {
|
||||
print_info "Available generations:"
|
||||
darwin-rebuild --list-generations
|
||||
|
||||
echo -n "Enter generation number to rollback to: "
|
||||
read -r GEN_NUM
|
||||
let gen_num = input "Enter generation number to rollback to: "
|
||||
|
||||
if [[ -z "$GEN_NUM" ]]; then
|
||||
if ($gen_num | is-empty) {
|
||||
print_error "No generation number provided"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_warning "Rolling back to generation $GEN_NUM..."
|
||||
darwin-rebuild switch --switch-generation "$GEN_NUM"
|
||||
print_warning $"Rolling back to generation ($gen_num)..."
|
||||
darwin-rebuild switch --switch-generation $gen_num
|
||||
|
||||
print_success "Rollback to generation $GEN_NUM complete"
|
||||
print_success $"Rollback to generation ($gen_num) complete"
|
||||
}
|
||||
|
||||
17
apps/common.nu
Normal file
17
apps/common.nu
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env nu
|
||||
|
||||
export def print_info [msg: string] {
|
||||
print $"(ansi blue)[INFO](ansi reset) ($msg)"
|
||||
}
|
||||
|
||||
export def print_success [msg: string] {
|
||||
print $"(ansi green)[OK](ansi reset) ($msg)"
|
||||
}
|
||||
|
||||
export def print_error [msg: string] {
|
||||
print $"(ansi red)[ERROR](ansi reset) ($msg)"
|
||||
}
|
||||
|
||||
export def print_warning [msg: string] {
|
||||
print $"(ansi yellow)[WARN](ansi reset) ($msg)"
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[OK]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
HOSTNAME="${1:-$(hostname)}"
|
||||
def main [hostname?: string, ...rest: string] {
|
||||
let host = if ($hostname | is-empty) {
|
||||
hostname | str trim
|
||||
} else { $hostname }
|
||||
|
||||
print_info "Applying configuration for $HOSTNAME"
|
||||
print_info $"Applying configuration for ($host)"
|
||||
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
sudo nixos-rebuild switch --flake ".#$HOSTNAME" "${@:2}"
|
||||
else
|
||||
nixos-rebuild switch --flake ".#$HOSTNAME" "${@:2}"
|
||||
fi
|
||||
let euid = (id -u | str trim | into int)
|
||||
|
||||
if $euid != 0 {
|
||||
sudo nixos-rebuild switch --flake $".#($host)" ...$rest
|
||||
} else {
|
||||
nixos-rebuild switch --flake $".#($host)" ...$rest
|
||||
}
|
||||
|
||||
print_success "Configuration applied successfully"
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
HOSTNAME="${1:-$(hostname)}"
|
||||
def main [hostname?: string, ...rest: string] {
|
||||
let host = if ($hostname | is-empty) {
|
||||
hostname | str trim
|
||||
} else { $hostname }
|
||||
|
||||
print_info "Building configuration for $HOSTNAME"
|
||||
print_info $"Building configuration for ($host)"
|
||||
|
||||
nix build ".#nixosConfigurations.$HOSTNAME.config.system.build.toplevel" --show-trace "${@:2}"
|
||||
nix build $".#nixosConfigurations.($host).config.system.build.toplevel" --show-trace ...$rest
|
||||
|
||||
if [[ -L ./result ]]; then
|
||||
unlink ./result
|
||||
fi
|
||||
if ("./result" | path exists) {
|
||||
rm ./result
|
||||
}
|
||||
|
||||
print_success "Build completed successfully"
|
||||
}
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
HOSTNAME="${1:-$(hostname)}"
|
||||
def main [hostname?: string, ...rest: string] {
|
||||
let host = if ($hostname | is-empty) {
|
||||
hostname | str trim
|
||||
} else { $hostname }
|
||||
|
||||
print_info "Building and switching configuration for $HOSTNAME"
|
||||
print_info $"Building and switching configuration for ($host)"
|
||||
|
||||
# Build
|
||||
print_info "Building configuration..."
|
||||
if ! nix build ".#nixosConfigurations.$HOSTNAME.config.system.build.toplevel" --no-link "${@:2}"; then
|
||||
if (nix build $".#nixosConfigurations.($host).config.system.build.toplevel" --no-link ...$rest | complete).exit_code != 0 {
|
||||
print_error "Build failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_success "Build completed"
|
||||
|
||||
# Switch
|
||||
print_info "Switching to new configuration..."
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
sudo nixos-rebuild switch --flake ".#$HOSTNAME" "${@:2}"
|
||||
else
|
||||
nixos-rebuild switch --flake ".#$HOSTNAME" "${@:2}"
|
||||
fi
|
||||
let euid = (id -u | str trim | into int)
|
||||
|
||||
if $euid != 0 {
|
||||
sudo nixos-rebuild switch --flake $".#($host)" ...$rest
|
||||
} else {
|
||||
nixos-rebuild switch --flake $".#($host)" ...$rest
|
||||
}
|
||||
|
||||
print_success "Build and switch completed successfully"
|
||||
}
|
||||
|
||||
38
apps/x86_64-linux/rollback
Normal file → Executable file
38
apps/x86_64-linux/rollback
Normal file → Executable file
@@ -1,30 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env nu
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../common.sh"
|
||||
use ../common.nu *
|
||||
|
||||
def main [] {
|
||||
print_info "Available generations:"
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
|
||||
let euid = (id -u | str trim | into int)
|
||||
|
||||
if $euid != 0 {
|
||||
sudo nix-env --profile /nix/var/nix/profiles/system --list-generations
|
||||
else
|
||||
} else {
|
||||
nix-env --profile /nix/var/nix/profiles/system --list-generations
|
||||
fi
|
||||
}
|
||||
|
||||
echo -n "Enter generation number to rollback to: "
|
||||
read -r GEN_NUM
|
||||
let gen_num = input "Enter generation number to rollback to: "
|
||||
|
||||
if [[ -z "$GEN_NUM" ]]; then
|
||||
if ($gen_num | is-empty) {
|
||||
print_error "No generation number provided"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_warning "Rolling back to generation $GEN_NUM..."
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
sudo nix-env --profile /nix/var/nix/profiles/system --switch-generation "$GEN_NUM" && \
|
||||
print_warning $"Rolling back to generation ($gen_num)..."
|
||||
|
||||
if $euid != 0 {
|
||||
sudo nix-env --profile /nix/var/nix/profiles/system --switch-generation $gen_num
|
||||
sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
|
||||
else
|
||||
nix-env --profile /nix/var/nix/profiles/system --switch-generation "$GEN_NUM" && \
|
||||
} else {
|
||||
nix-env --profile /nix/var/nix/profiles/system --switch-generation $gen_num
|
||||
/nix/var/nix/profiles/system/bin/switch-to-configuration switch
|
||||
fi
|
||||
}
|
||||
|
||||
print_success "Rollback to generation $GEN_NUM complete"
|
||||
print_success $"Rollback to generation ($gen_num) complete"
|
||||
}
|
||||
|
||||
299
flake.lock
generated
299
flake.lock
generated
@@ -6,7 +6,7 @@
|
||||
"llm-agents",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": "systems_2"
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1771437256,
|
||||
@@ -42,12 +42,12 @@
|
||||
"bun2nix": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts_2",
|
||||
"import-tree": "import-tree",
|
||||
"import-tree": "import-tree_2",
|
||||
"nixpkgs": [
|
||||
"llm-agents",
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": "systems_3",
|
||||
"systems": "systems_4",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
@@ -64,30 +64,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"colmena": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"stable": "stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1762034856,
|
||||
"narHash": "sha256-QVey3iP3UEoiFVXgypyjTvCrsIlA4ecx6Acaz5C8/PQ=",
|
||||
"owner": "zhaofengli",
|
||||
"repo": "colmena",
|
||||
"rev": "349b035a5027f23d88eeb3bc41085d7ee29f18ed",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "zhaofengli",
|
||||
"repo": "colmena",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1765739568,
|
||||
@@ -124,6 +100,41 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"den": {
|
||||
"locked": {
|
||||
"lastModified": 1772696629,
|
||||
"narHash": "sha256-wJvv0ZAcjpHBo/MnDSEZ+Dti+daJvlxznDUgKUvkT3c=",
|
||||
"owner": "vic",
|
||||
"repo": "den",
|
||||
"rev": "94b8721bcff4940e1cce97c509d72545efa4a8e4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "vic",
|
||||
"repo": "den",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"deploy-rs": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"utils": "utils"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1770019181,
|
||||
"narHash": "sha256-hwsYgDnby50JNVpTRYlF3UR/Rrpt01OrxVuryF40CFY=",
|
||||
"owner": "serokell",
|
||||
"repo": "deploy-rs",
|
||||
"rev": "77c906c0ba56aabdbc72041bf9111b565cdd6171",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "serokell",
|
||||
"repo": "deploy-rs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"disko": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -212,14 +223,29 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-aspects": {
|
||||
"locked": {
|
||||
"lastModified": 1772679072,
|
||||
"narHash": "sha256-qrbfroFGetX5DS/n6gP6BifqGCO084b5ad8C5kwaLAk=",
|
||||
"owner": "vic",
|
||||
"repo": "flake-aspects",
|
||||
"rev": "82a472654139897fab1bcb2d96ae337fb7928800",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "vic",
|
||||
"repo": "flake-aspects",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1650374568,
|
||||
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
||||
"lastModified": 1733328505,
|
||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -228,9 +254,26 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-file": {
|
||||
"locked": {
|
||||
"lastModified": 1772677111,
|
||||
"narHash": "sha256-tFVzJ+A39OrBPK1lYlM5giUu6yl9pwjUGf6VR3b8Yho=",
|
||||
"owner": "vic",
|
||||
"repo": "flake-file",
|
||||
"rev": "f18f9bad86481621b9c378842987b172e91ca82c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "vic",
|
||||
"repo": "flake-file",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
"nixpkgs-lib": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1772408722,
|
||||
@@ -248,7 +291,7 @@
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib_2"
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1769996383,
|
||||
@@ -286,23 +329,8 @@
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
@@ -318,9 +346,9 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_6"
|
||||
"systems": "systems_7"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
@@ -339,7 +367,7 @@
|
||||
"himalaya": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"pimalaya": "pimalaya"
|
||||
},
|
||||
"locked": {
|
||||
@@ -409,6 +437,21 @@
|
||||
}
|
||||
},
|
||||
"import-tree": {
|
||||
"locked": {
|
||||
"lastModified": 1772344373,
|
||||
"narHash": "sha256-OQQ1MhB9t1J71b2wxRRTdH/Qd8UGG0p+dGspfCf5U1c=",
|
||||
"owner": "vic",
|
||||
"repo": "import-tree",
|
||||
"rev": "10fda59eee7d7970ec443b925f32a1bc7526648c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "vic",
|
||||
"repo": "import-tree",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"import-tree_2": {
|
||||
"locked": {
|
||||
"lastModified": 1763762820,
|
||||
"narHash": "sha256-ZvYKbFib3AEwiNMLsejb/CWs/OL/srFQ8AogkebEPF0=",
|
||||
@@ -441,8 +484,8 @@
|
||||
},
|
||||
"jj-starship": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1769370163,
|
||||
@@ -462,7 +505,7 @@
|
||||
"inputs": {
|
||||
"blueprint": "blueprint",
|
||||
"bun2nix": "bun2nix",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nixpkgs": "nixpkgs_4",
|
||||
"treefmt-nix": "treefmt-nix_2"
|
||||
},
|
||||
"locked": {
|
||||
@@ -524,27 +567,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"colmena",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1729742964,
|
||||
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-homebrew": {
|
||||
"inputs": {
|
||||
"brew-src": "brew-src"
|
||||
@@ -565,36 +587,21 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1736437047,
|
||||
"narHash": "sha256-JJBziecfU+56SUNxeJlDIgixJN5WYuADd+/TVd5sQos=",
|
||||
"owner": "nixos",
|
||||
"lastModified": 1743014863,
|
||||
"narHash": "sha256-jAIUqsiN2r3hCuHji80U7NNEafpIMBXiwKlSrjWMlpg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f17b95775191ea44bc426831235d87affb10faba",
|
||||
"rev": "bd3bac8bfb542dbde7ffffb6987a1a1f9d41699f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "staging-next",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1772328832,
|
||||
"narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib_2": {
|
||||
"locked": {
|
||||
"lastModified": 1769909678,
|
||||
"narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
|
||||
@@ -610,6 +617,22 @@
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1736437047,
|
||||
"narHash": "sha256-JJBziecfU+56SUNxeJlDIgixJN5WYuADd+/TVd5sQos=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f17b95775191ea44bc426831235d87affb10faba",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "staging-next",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1766840161,
|
||||
"narHash": "sha256-Ss/LHpJJsng8vz1Pe33RSGIWUOcqM1fjrehjUkdrWio=",
|
||||
@@ -625,7 +648,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1772643971,
|
||||
"narHash": "sha256-+bllfMsclzbAAPMZTm3K9G/a5lG+s6l18/AyyYLPSIE=",
|
||||
@@ -641,7 +664,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"nixpkgs_5": {
|
||||
"locked": {
|
||||
"lastModified": 1772701849,
|
||||
"narHash": "sha256-CO0mU0p/Fe5ekivxJmKO0WMA6kMOI/DbI+qEKhOxYCo=",
|
||||
@@ -657,7 +680,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_5": {
|
||||
"nixpkgs_6": {
|
||||
"locked": {
|
||||
"lastModified": 1770380644,
|
||||
"narHash": "sha256-P7dWMHRUWG5m4G+06jDyThXO7kwSk46C1kgjEWcybkE=",
|
||||
@@ -673,7 +696,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_6": {
|
||||
"nixpkgs_7": {
|
||||
"locked": {
|
||||
"lastModified": 1771923393,
|
||||
"narHash": "sha256-Fy0+UXELv9hOE8WjYhJt8fMDLYTU2Dqn3cX4BwoGBos=",
|
||||
@@ -689,7 +712,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_7": {
|
||||
"nixpkgs_8": {
|
||||
"locked": {
|
||||
"lastModified": 1765934234,
|
||||
"narHash": "sha256-pJjWUzNnjbIAMIc5gRFUuKCDQ9S1cuh3b2hKgA7Mc4A=",
|
||||
@@ -708,8 +731,8 @@
|
||||
"nixvim": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts_3",
|
||||
"nixpkgs": "nixpkgs_5",
|
||||
"systems": "systems_4"
|
||||
"nixpkgs": "nixpkgs_6",
|
||||
"systems": "systems_5"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1772402258,
|
||||
@@ -743,20 +766,27 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"colmena": "colmena",
|
||||
"darwin": "darwin",
|
||||
"den": "den",
|
||||
"deploy-rs": "deploy-rs",
|
||||
"disko": "disko",
|
||||
"flake-aspects": "flake-aspects",
|
||||
"flake-file": "flake-file",
|
||||
"flake-parts": "flake-parts",
|
||||
"himalaya": "himalaya",
|
||||
"home-manager": "home-manager",
|
||||
"homebrew-cask": "homebrew-cask",
|
||||
"homebrew-core": "homebrew-core",
|
||||
"import-tree": "import-tree",
|
||||
"jj-ryu": "jj-ryu",
|
||||
"jj-starship": "jj-starship",
|
||||
"llm-agents": "llm-agents",
|
||||
"naersk": "naersk",
|
||||
"nix-homebrew": "nix-homebrew",
|
||||
"nixpkgs": "nixpkgs_4",
|
||||
"nixpkgs": "nixpkgs_5",
|
||||
"nixpkgs-lib": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixvim": "nixvim",
|
||||
"sops-nix": "sops-nix",
|
||||
"tuicr": "tuicr",
|
||||
@@ -855,22 +885,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"stable": {
|
||||
"locked": {
|
||||
"lastModified": 1750133334,
|
||||
"narHash": "sha256-urV51uWH7fVnhIvsZIELIYalMYsyr2FCalvlRTzqWRw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "36ab78dab7da2e4e27911007033713bab534187b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
@@ -961,6 +975,21 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_7": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -1007,8 +1036,8 @@
|
||||
"tuicr": {
|
||||
"inputs": {
|
||||
"naersk": "naersk_2",
|
||||
"nixpkgs": "nixpkgs_6",
|
||||
"utils": "utils"
|
||||
"nixpkgs": "nixpkgs_7",
|
||||
"utils": "utils_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1772695807,
|
||||
@@ -1026,7 +1055,25 @@
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems_5"
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_6"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
@@ -1045,8 +1092,8 @@
|
||||
"zjstatus": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixpkgs": "nixpkgs_7",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_8",
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
|
||||
184
flake.nix
184
flake.nix
@@ -1,168 +1,58 @@
|
||||
# DO-NOT-EDIT. This file was auto-generated using github:vic/flake-file.
|
||||
# Use `nix run .#write-flake` to regenerate it.
|
||||
{
|
||||
description = "Configuration for my macOS laptops and NixOS server";
|
||||
outputs = inputs: inputs.flake-parts.lib.mkFlake {inherit inputs;} (inputs.import-tree ./modules);
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/master";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
sops-nix = {
|
||||
url = "github:Mic92/sops-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
darwin = {
|
||||
url = "github:LnL7/nix-darwin/master";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
url = "github:LnL7/nix-darwin/master";
|
||||
};
|
||||
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
|
||||
homebrew-core = {
|
||||
url = "github:homebrew/homebrew-core";
|
||||
flake = false;
|
||||
den.url = "github:vic/den";
|
||||
deploy-rs.url = "github:serokell/deploy-rs";
|
||||
disko = {
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
url = "github:nix-community/disko";
|
||||
};
|
||||
flake-aspects.url = "github:vic/flake-aspects";
|
||||
flake-file.url = "github:vic/flake-file";
|
||||
flake-parts = {
|
||||
inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
url = "github:hercules-ci/flake-parts";
|
||||
};
|
||||
himalaya.url = "github:pimalaya/himalaya";
|
||||
home-manager = {
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
url = "github:nix-community/home-manager";
|
||||
};
|
||||
homebrew-cask = {
|
||||
flake = false;
|
||||
url = "github:homebrew/homebrew-cask";
|
||||
};
|
||||
homebrew-core = {
|
||||
flake = false;
|
||||
url = "github:homebrew/homebrew-core";
|
||||
};
|
||||
nixvim.url = "github:nix-community/nixvim";
|
||||
zjstatus.url = "github:dj95/zjstatus";
|
||||
llm-agents.url = "github:numtide/llm-agents.nix";
|
||||
disko = {
|
||||
url = "github:nix-community/disko";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
colmena = {
|
||||
url = "github:zhaofengli/colmena";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
import-tree.url = "github:vic/import-tree";
|
||||
jj-ryu = {
|
||||
url = "github:dmmulroy/jj-ryu";
|
||||
flake = false;
|
||||
url = "github:dmmulroy/jj-ryu";
|
||||
};
|
||||
jj-starship.url = "github:dmmulroy/jj-starship";
|
||||
himalaya.url = "github:pimalaya/himalaya";
|
||||
llm-agents.url = "github:numtide/llm-agents.nix";
|
||||
naersk = {
|
||||
url = "github:nix-community/naersk/master";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
url = "github:nix-community/naersk/master";
|
||||
};
|
||||
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
|
||||
nixpkgs.url = "github:nixos/nixpkgs/master";
|
||||
nixpkgs-lib.follows = "nixpkgs";
|
||||
nixvim.url = "github:nix-community/nixvim";
|
||||
sops-nix = {
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
url = "github:Mic92/sops-nix";
|
||||
};
|
||||
tuicr.url = "github:agavra/tuicr";
|
||||
};
|
||||
|
||||
outputs = inputs @ {flake-parts, ...}:
|
||||
flake-parts.lib.mkFlake {inherit inputs;} (
|
||||
let
|
||||
inherit (inputs.nixpkgs) lib;
|
||||
constants = import ./lib/constants.nix;
|
||||
inherit (constants) user;
|
||||
|
||||
darwinHosts = ["chidi" "jason"];
|
||||
nixosHosts = ["michael" "tahani"];
|
||||
|
||||
overlays = import ./overlays {inherit inputs;};
|
||||
nixpkgsConfig = hostPlatform: {
|
||||
nixpkgs = {inherit hostPlatform overlays;};
|
||||
};
|
||||
in {
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
|
||||
flake.darwinConfigurations =
|
||||
lib.genAttrs darwinHosts (
|
||||
hostname:
|
||||
inputs.darwin.lib.darwinSystem {
|
||||
specialArgs = {inherit inputs user hostname constants;};
|
||||
modules = [
|
||||
inputs.home-manager.darwinModules.home-manager
|
||||
inputs.nix-homebrew.darwinModules.nix-homebrew
|
||||
(nixpkgsConfig "aarch64-darwin")
|
||||
{
|
||||
nix-homebrew = {
|
||||
inherit user;
|
||||
enable = true;
|
||||
mutableTaps = true;
|
||||
taps = {
|
||||
"homebrew/homebrew-core" = inputs.homebrew-core;
|
||||
"homebrew/homebrew-cask" = inputs.homebrew-cask;
|
||||
};
|
||||
zjstatus.url = "github:dj95/zjstatus";
|
||||
};
|
||||
}
|
||||
./hosts/${hostname}
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
flake.nixosConfigurations =
|
||||
lib.genAttrs nixosHosts (
|
||||
hostname:
|
||||
lib.nixosSystem {
|
||||
specialArgs = {inherit inputs user hostname constants;};
|
||||
modules = [
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
(nixpkgsConfig "x86_64-linux")
|
||||
./hosts/${hostname}
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
flake.colmena =
|
||||
{
|
||||
meta = {
|
||||
nixpkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;
|
||||
specialArgs = {inherit inputs user constants;};
|
||||
};
|
||||
}
|
||||
// lib.genAttrs nixosHosts (
|
||||
hostname: {
|
||||
deployment = {
|
||||
targetHost = hostname;
|
||||
targetUser = user;
|
||||
};
|
||||
imports = [
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
(nixpkgsConfig "x86_64-linux")
|
||||
{_module.args.hostname = hostname;}
|
||||
./hosts/${hostname}
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
flake.nixosModules = {
|
||||
pgbackrest = ./modules/pgbackrest.nix;
|
||||
};
|
||||
|
||||
flake.overlays = {
|
||||
default = lib.composeManyExtensions overlays;
|
||||
list = overlays;
|
||||
};
|
||||
|
||||
flake.lib = {inherit constants;};
|
||||
|
||||
perSystem = {
|
||||
pkgs,
|
||||
system,
|
||||
...
|
||||
}: let
|
||||
mkApp = name: {
|
||||
type = "app";
|
||||
program = "${(pkgs.writeShellScriptBin name ''
|
||||
PATH=${pkgs.git}/bin:$PATH
|
||||
echo "Running ${name} for ${system}"
|
||||
exec ${inputs.self}/apps/${system}/${name} "$@"
|
||||
'')}/bin/${name}";
|
||||
};
|
||||
|
||||
appNames = [
|
||||
"apply"
|
||||
"build"
|
||||
"build-switch"
|
||||
"rollback"
|
||||
];
|
||||
in {
|
||||
apps = pkgs.lib.genAttrs appNames mkApp;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
{
|
||||
pkgs,
|
||||
inputs,
|
||||
user,
|
||||
hostname,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./secrets.nix
|
||||
../../profiles/core.nix
|
||||
../../profiles/darwin.nix
|
||||
../../profiles/dock.nix
|
||||
../../profiles/homebrew.nix
|
||||
../../profiles/tailscale.nix
|
||||
inputs.sops-nix.darwinModules.sops
|
||||
];
|
||||
|
||||
networking.hostName = hostname;
|
||||
networking.computerName = hostname;
|
||||
|
||||
home-manager.users.${user} = {
|
||||
imports = [
|
||||
../../profiles/atuin.nix
|
||||
../../profiles/aerospace.nix
|
||||
../../profiles/bash.nix
|
||||
../../profiles/bat.nix
|
||||
../../profiles/direnv.nix
|
||||
../../profiles/nushell.nix
|
||||
../../profiles/fzf.nix
|
||||
../../profiles/ghostty.nix
|
||||
../../profiles/git.nix
|
||||
../../profiles/home.nix
|
||||
../../profiles/jjui.nix
|
||||
../../profiles/jujutsu.nix
|
||||
../../profiles/lazygit.nix
|
||||
../../profiles/mise.nix
|
||||
../../profiles/neovim
|
||||
../../profiles/opencode.nix
|
||||
../../profiles/claude-code.nix
|
||||
../../profiles/ripgrep.nix
|
||||
../../profiles/ssh.nix
|
||||
../../profiles/starship.nix
|
||||
../../profiles/yazi.nix
|
||||
../../profiles/zellij.nix
|
||||
../../profiles/zk.nix
|
||||
../../profiles/zoxide.nix
|
||||
../../profiles/zsh.nix
|
||||
inputs.nixvim.homeModules.nixvim
|
||||
];
|
||||
fonts.fontconfig.enable = true;
|
||||
programs.git.settings.user.email = "christoph@tuist.dev";
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
slack
|
||||
];
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{user, ...}: {
|
||||
sops.age.keyFile = "/Users/${user}/.config/sops/age/keys.txt";
|
||||
sops.age.sshKeyPaths = [];
|
||||
sops.gnupg.sshKeyPaths = [];
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
{
|
||||
inputs,
|
||||
user,
|
||||
hostname,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
./secrets.nix
|
||||
../../profiles/core.nix
|
||||
../../profiles/darwin.nix
|
||||
../../profiles/dock.nix
|
||||
../../profiles/homebrew.nix
|
||||
../../profiles/tailscale.nix
|
||||
inputs.sops-nix.darwinModules.sops
|
||||
];
|
||||
|
||||
networking.hostName = hostname;
|
||||
networking.computerName = hostname;
|
||||
|
||||
home-manager.users.${user} = {
|
||||
imports = [
|
||||
../../profiles/atuin.nix
|
||||
../../profiles/aerospace.nix
|
||||
../../profiles/bash.nix
|
||||
../../profiles/bat.nix
|
||||
../../profiles/direnv.nix
|
||||
../../profiles/nushell.nix
|
||||
../../profiles/fzf.nix
|
||||
../../profiles/ghostty.nix
|
||||
../../profiles/git.nix
|
||||
../../profiles/home.nix
|
||||
../../profiles/jjui.nix
|
||||
../../profiles/jujutsu.nix
|
||||
../../profiles/lazygit.nix
|
||||
../../profiles/mise.nix
|
||||
../../profiles/neovim
|
||||
../../profiles/opencode.nix
|
||||
../../profiles/claude-code.nix
|
||||
../../profiles/ripgrep.nix
|
||||
../../profiles/ssh.nix
|
||||
../../profiles/starship.nix
|
||||
../../profiles/yazi.nix
|
||||
../../profiles/zellij.nix
|
||||
../../profiles/zk.nix
|
||||
../../profiles/zoxide.nix
|
||||
../../profiles/zsh.nix
|
||||
inputs.nixvim.homeModules.nixvim
|
||||
];
|
||||
fonts.fontconfig.enable = true;
|
||||
programs.git.settings.user.email = "christoph@schmatzler.com";
|
||||
};
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{user, ...}: {
|
||||
sops.age.keyFile = "/Users/${user}/.config/sops/age/keys.txt";
|
||||
sops.age.sshKeyPaths = [];
|
||||
sops.gnupg.sshKeyPaths = [];
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
config,
|
||||
inputs,
|
||||
user,
|
||||
hostname,
|
||||
modulesPath,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
./disk-config.nix
|
||||
./hardware-configuration.nix
|
||||
./secrets.nix
|
||||
../../modules/gitea.nix
|
||||
../../profiles/core.nix
|
||||
../../profiles/fail2ban.nix
|
||||
../../profiles/nixos.nix
|
||||
../../profiles/openssh.nix
|
||||
../../profiles/tailscale.nix
|
||||
inputs.disko.nixosModules.disko
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
];
|
||||
|
||||
my.gitea = {
|
||||
enable = true;
|
||||
litestream = {
|
||||
bucket = "michael-gitea-litestream";
|
||||
secretFile = config.sops.secrets.michael-gitea-litestream.path;
|
||||
};
|
||||
restic = {
|
||||
bucket = "michael-gitea-repositories";
|
||||
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
|
||||
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||
};
|
||||
};
|
||||
|
||||
networking.hostName = hostname;
|
||||
|
||||
home-manager.users.${user} = {
|
||||
imports = [
|
||||
../../profiles/nushell.nix
|
||||
../../profiles/home.nix
|
||||
../../profiles/ssh.nix
|
||||
inputs.nixvim.homeModules.nixvim
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{...}: {
|
||||
sops.secrets = {
|
||||
michael-gitea-litestream = {
|
||||
sopsFile = ../../secrets/michael-gitea-litestream;
|
||||
format = "binary";
|
||||
owner = "gitea";
|
||||
group = "gitea";
|
||||
};
|
||||
michael-gitea-restic-password = {
|
||||
sopsFile = ../../secrets/michael-gitea-restic-password;
|
||||
format = "binary";
|
||||
owner = "gitea";
|
||||
group = "gitea";
|
||||
};
|
||||
michael-gitea-restic-env = {
|
||||
sopsFile = ../../secrets/michael-gitea-restic-env;
|
||||
format = "binary";
|
||||
owner = "gitea";
|
||||
group = "gitea";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
inputs,
|
||||
user,
|
||||
hostname,
|
||||
...
|
||||
}: let
|
||||
himalaya = config.home-manager.users.${user}.programs.himalaya.package;
|
||||
opencode = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.opencode;
|
||||
in {
|
||||
imports = [
|
||||
./adguardhome.nix
|
||||
./cache.nix
|
||||
./networking.nix
|
||||
./paperless.nix
|
||||
./secrets.nix
|
||||
../../profiles/core.nix
|
||||
../../profiles/nixos.nix
|
||||
../../profiles/openssh.nix
|
||||
../../profiles/tailscale.nix
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
];
|
||||
|
||||
networking.hostName = hostname;
|
||||
|
||||
home-manager.users.${user} = {
|
||||
imports = [
|
||||
../../profiles/atuin.nix
|
||||
../../profiles/bash.nix
|
||||
../../profiles/bat.nix
|
||||
../../profiles/direnv.nix
|
||||
../../profiles/nushell.nix
|
||||
../../profiles/fzf.nix
|
||||
../../profiles/git.nix
|
||||
../../profiles/himalaya.nix
|
||||
../../profiles/mbsync.nix
|
||||
../../profiles/home.nix
|
||||
../../profiles/jjui.nix
|
||||
../../profiles/jujutsu.nix
|
||||
../../profiles/lazygit.nix
|
||||
../../profiles/mise.nix
|
||||
../../profiles/neovim
|
||||
../../profiles/opencode.nix
|
||||
../../profiles/claude-code.nix
|
||||
../../profiles/ripgrep.nix
|
||||
../../profiles/ssh.nix
|
||||
../../profiles/starship.nix
|
||||
../../profiles/yazi.nix
|
||||
../../profiles/zellij.nix
|
||||
../../profiles/zk.nix
|
||||
../../profiles/zoxide.nix
|
||||
../../profiles/zsh.nix
|
||||
inputs.nixvim.homeModules.nixvim
|
||||
];
|
||||
|
||||
programs.git.settings.user.email = "christoph@schmatzler.com";
|
||||
|
||||
systemd.user.services.opencode-inbox-triage = {
|
||||
Unit = {
|
||||
Description = "OpenCode inbox triage";
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${opencode}/bin/opencode run --command inbox-triage";
|
||||
Environment = "PATH=${himalaya}/bin:${opencode}/bin:${pkgs.coreutils}/bin";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.timers.opencode-inbox-triage = {
|
||||
Unit = {
|
||||
Description = "Run OpenCode inbox triage every 10 minutes";
|
||||
};
|
||||
Timer = {
|
||||
OnCalendar = "*:0/10";
|
||||
Persistent = true;
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["timers.target"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
users.users.${user}.extraGroups = ["docker"];
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/swapfile";
|
||||
size = 16 * 1024;
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{user, ...}: {
|
||||
sops.secrets = {
|
||||
tahani-paperless-password = {
|
||||
sopsFile = ../../secrets/tahani-paperless-password;
|
||||
format = "binary";
|
||||
};
|
||||
tahani-email-password = {
|
||||
sopsFile = ../../secrets/tahani-email-password;
|
||||
format = "binary";
|
||||
owner = user;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
user,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
@@ -46,7 +45,7 @@ in {
|
||||
{path = "/System/Applications/Music.app/";}
|
||||
{path = "/System/Applications/System Settings.app/";}
|
||||
{
|
||||
path = "${config.users.users.${user}.home}/Downloads";
|
||||
path = "${config.users.users.cschmatzler.home}/Downloads";
|
||||
section = "others";
|
||||
options = "--sort name --view grid --display stack";
|
||||
}
|
||||
@@ -57,7 +56,7 @@ in {
|
||||
mkOption {
|
||||
description = "Username to apply the dock settings to";
|
||||
type = types.str;
|
||||
default = user;
|
||||
default = "cschmatzler";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -11,7 +11,6 @@ with pkgs;
|
||||
alejandra
|
||||
ast-grep
|
||||
bun
|
||||
colmena
|
||||
delta
|
||||
devenv
|
||||
dig
|
||||
0
modules/_opencode/tool/.gitkeep
Normal file
0
modules/_opencode/tool/.gitkeep
Normal file
130
modules/ai-tools.nix
Normal file
130
modules/ai-tools.nix
Normal file
@@ -0,0 +1,130 @@
|
||||
{inputs, ...}: {
|
||||
den.aspects.ai-tools.homeManager = {
|
||||
pkgs,
|
||||
inputs',
|
||||
...
|
||||
}: {
|
||||
programs.opencode = {
|
||||
enable = true;
|
||||
package = inputs'.llm-agents.packages.opencode;
|
||||
settings = {
|
||||
model = "anthropic/claude-opus-4-6";
|
||||
small_model = "anthropic/claude-haiku-4-5";
|
||||
theme = "catppuccin";
|
||||
plugin = ["oh-my-opencode@latest" "opencode-anthropic-auth@latest"];
|
||||
permission = {
|
||||
read = {
|
||||
"*" = "allow";
|
||||
"*.env" = "deny";
|
||||
"*.env.*" = "deny";
|
||||
"*.envrc" = "deny";
|
||||
"secrets/*" = "deny";
|
||||
};
|
||||
};
|
||||
agent = {
|
||||
plan = {
|
||||
model = "anthropic/claude-opus-4-6";
|
||||
};
|
||||
explore = {
|
||||
model = "anthropic/claude-haiku-4-5";
|
||||
};
|
||||
};
|
||||
instructions = [
|
||||
"CLAUDE.md"
|
||||
"AGENT.md"
|
||||
# "AGENTS.md"
|
||||
"AGENTS.local.md"
|
||||
];
|
||||
formatter = {
|
||||
mix = {
|
||||
disabled = true;
|
||||
};
|
||||
};
|
||||
mcp = {
|
||||
opensrc = {
|
||||
enabled = true;
|
||||
type = "local";
|
||||
command = ["bunx" "opensrc-mcp"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = [
|
||||
inputs'.llm-agents.packages.claude-code
|
||||
];
|
||||
|
||||
xdg.configFile = {
|
||||
"opencode/agent" = {
|
||||
source = ./_opencode/agent;
|
||||
recursive = true;
|
||||
};
|
||||
"opencode/command" = {
|
||||
source = ./_opencode/command;
|
||||
recursive = true;
|
||||
};
|
||||
"opencode/skill" = {
|
||||
source = ./_opencode/skill;
|
||||
recursive = true;
|
||||
};
|
||||
"opencode/tool" = {
|
||||
source = ./_opencode/tool;
|
||||
recursive = true;
|
||||
};
|
||||
"opencode/plugin" = {
|
||||
source = ./_opencode/plugin;
|
||||
recursive = true;
|
||||
};
|
||||
"opencode/AGENTS.md".source = ./_opencode/AGENTS.md;
|
||||
"opencode/oh-my-opencode.json".text =
|
||||
builtins.toJSON {
|
||||
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json";
|
||||
disabled_skills = ["playwright" "dev-browser"];
|
||||
git_master = {
|
||||
commit_footer = false;
|
||||
include_co_authored_by = false;
|
||||
};
|
||||
runtime_fallback = true;
|
||||
agents = {
|
||||
explore = {
|
||||
model = "opencode-go/minimax-m2.5";
|
||||
fallback_models = ["anthropic/claude-haiku-4-5"];
|
||||
};
|
||||
librarian = {
|
||||
model = "opencode-go/minimax-m2.5";
|
||||
fallback_models = ["opencode-go/glm-5"];
|
||||
};
|
||||
sisyphus = {
|
||||
fallback_models = ["opencode-go/kimi-k2.5" "opencode-go/glm-5"];
|
||||
};
|
||||
};
|
||||
categories = {
|
||||
"visual-engineering" = {
|
||||
fallback_models = ["opencode-go/glm-5" "opencode-go/kimi-k2.5"];
|
||||
};
|
||||
ultrabrain = {
|
||||
fallback_models = ["opencode-go/kimi-k2.5" "opencode-go/glm-5"];
|
||||
};
|
||||
deep = {
|
||||
fallback_models = ["opencode-go/kimi-k2.5" "opencode-go/glm-5"];
|
||||
};
|
||||
artistry = {
|
||||
fallback_models = ["opencode-go/kimi-k2.5" "opencode-go/glm-5"];
|
||||
};
|
||||
quick = {
|
||||
fallback_models = ["opencode-go/minimax-m2.5"];
|
||||
};
|
||||
"unspecified-low" = {
|
||||
fallback_models = ["opencode-go/minimax-m2.5" "opencode-go/kimi-k2.5"];
|
||||
};
|
||||
"unspecified-high" = {
|
||||
fallback_models = ["opencode-go/kimi-k2.5" "opencode-go/glm-5"];
|
||||
};
|
||||
writing = {
|
||||
fallback_models = ["opencode-go/kimi-k2.5" "opencode-go/minimax-m2.5"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
26
modules/apps.nix
Normal file
26
modules/apps.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{inputs, ...}: {
|
||||
perSystem = {
|
||||
pkgs,
|
||||
system,
|
||||
...
|
||||
}: let
|
||||
mkApp = name: {
|
||||
type = "app";
|
||||
program = "${(pkgs.writeShellScriptBin name ''
|
||||
PATH=${pkgs.git}/bin:$PATH
|
||||
echo "Running ${name} for ${system}"
|
||||
exec ${inputs.self}/apps/${system}/${name} "$@"
|
||||
'')}/bin/${name}";
|
||||
};
|
||||
appNames = ["apply" "build" "build-switch" "rollback"];
|
||||
in {
|
||||
apps =
|
||||
pkgs.lib.genAttrs appNames mkApp
|
||||
// {
|
||||
deploy = {
|
||||
type = "app";
|
||||
program = "${inputs.deploy-rs.packages.${system}.deploy-rs}/bin/deploy";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
17
modules/atuin.nix
Normal file
17
modules/atuin.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{...}: {
|
||||
den.aspects.atuin.homeManager = {...}: {
|
||||
programs.atuin = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
flags = [
|
||||
"--disable-up-arrow"
|
||||
];
|
||||
settings = {
|
||||
style = "compact";
|
||||
inline_height = 0;
|
||||
show_help = false;
|
||||
show_tabs = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
29
modules/chidi.nix
Normal file
29
modules/chidi.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{den, ...}: {
|
||||
den.aspects.chidi.includes = [
|
||||
den.aspects.darwin-system
|
||||
den.aspects.core
|
||||
den.aspects.tailscale
|
||||
den.aspects.desktop
|
||||
den.aspects.terminal
|
||||
den.aspects.atuin
|
||||
den.aspects.dev-tools
|
||||
den.aspects.neovim
|
||||
den.aspects.ai-tools
|
||||
den.aspects.zellij
|
||||
den.aspects.zk
|
||||
];
|
||||
|
||||
den.aspects.chidi.darwin = {pkgs, ...}: {
|
||||
networking.hostName = "chidi";
|
||||
networking.computerName = "chidi";
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
slack
|
||||
];
|
||||
};
|
||||
|
||||
den.aspects.chidi.homeManager = {...}: {
|
||||
fonts.fontconfig.enable = true;
|
||||
programs.git.settings.user.email = "christoph@tuist.dev";
|
||||
};
|
||||
}
|
||||
33
modules/core.nix
Normal file
33
modules/core.nix
Normal file
@@ -0,0 +1,33 @@
|
||||
{...}: {
|
||||
den.aspects.core.os = {pkgs, ...}: {
|
||||
programs.fish.enable = true;
|
||||
environment.shells = [pkgs.nushell];
|
||||
|
||||
nixpkgs = {
|
||||
config = {
|
||||
allowUnfree = true;
|
||||
};
|
||||
};
|
||||
|
||||
nix = {
|
||||
package = pkgs.nix;
|
||||
settings = {
|
||||
substituters = [
|
||||
"https://nix-community.cachix.org"
|
||||
"https://cache.nixos.org"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
};
|
||||
gc = {
|
||||
automatic = true;
|
||||
options = "--delete-older-than 30d";
|
||||
};
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
{
|
||||
pkgs,
|
||||
inputs,
|
||||
user,
|
||||
constants,
|
||||
...
|
||||
}: {
|
||||
home-manager.extraSpecialArgs = {inherit user constants inputs;};
|
||||
{inputs, ...}: {
|
||||
den.aspects.darwin-system.darwin = {pkgs, ...}: {
|
||||
imports = [
|
||||
inputs.nix-homebrew.darwinModules.nix-homebrew
|
||||
inputs.home-manager.darwinModules.home-manager
|
||||
./_darwin/dock.nix
|
||||
];
|
||||
|
||||
system = {
|
||||
primaryUser = user;
|
||||
stateVersion = constants.stateVersions.darwin;
|
||||
system.primaryUser = "cschmatzler";
|
||||
|
||||
defaults = {
|
||||
system.defaults = {
|
||||
NSGlobalDomain = {
|
||||
AppleInterfaceStyle = null;
|
||||
AppleShowAllExtensions = true;
|
||||
@@ -103,10 +100,9 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nix = {
|
||||
settings.trusted-users = ["@admin" "${user}"];
|
||||
settings.trusted-users = ["@admin" "cschmatzler"];
|
||||
gc.interval = {
|
||||
Weekday = 0;
|
||||
Hour = 2;
|
||||
@@ -114,12 +110,32 @@
|
||||
};
|
||||
};
|
||||
|
||||
users.users.${user} = {
|
||||
name = user;
|
||||
home = "/Users/${user}";
|
||||
users.users.cschmatzler = {
|
||||
name = "cschmatzler";
|
||||
home = "/Users/cschmatzler";
|
||||
isHidden = false;
|
||||
shell = pkgs.nushell;
|
||||
};
|
||||
|
||||
home-manager.useGlobalPkgs = true;
|
||||
|
||||
nix-homebrew = {
|
||||
enable = true;
|
||||
user = "cschmatzler";
|
||||
mutableTaps = true;
|
||||
taps = {
|
||||
"homebrew/homebrew-core" = inputs.homebrew-core;
|
||||
"homebrew/homebrew-cask" = inputs.homebrew-cask;
|
||||
};
|
||||
};
|
||||
|
||||
homebrew = {
|
||||
enable = true;
|
||||
casks = [
|
||||
"ghostty@tip"
|
||||
"helium-browser"
|
||||
"tidal"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
31
modules/defaults.nix
Normal file
31
modules/defaults.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
den,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
options.flake = {
|
||||
darwinConfigurations =
|
||||
lib.mkOption {
|
||||
type = lib.types.lazyAttrsOf lib.types.raw;
|
||||
default = {};
|
||||
};
|
||||
deploy =
|
||||
lib.mkOption {
|
||||
type = lib.types.lazyAttrsOf lib.types.raw;
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
den.default.nixos.system.stateVersion = "25.11";
|
||||
den.default.darwin.system.stateVersion = 6;
|
||||
den.default.homeManager.home.stateVersion = "25.11";
|
||||
|
||||
den.default.includes = [
|
||||
den.provides.define-user
|
||||
den.provides.inputs'
|
||||
];
|
||||
|
||||
den.base.user.classes = lib.mkDefault ["homeManager"];
|
||||
};
|
||||
}
|
||||
61
modules/dendritic.nix
Normal file
61
modules/dendritic.nix
Normal file
@@ -0,0 +1,61 @@
|
||||
{inputs, ...}: {
|
||||
imports = [
|
||||
inputs.den.flakeModule
|
||||
(inputs.flake-file.flakeModules.dendritic or {})
|
||||
];
|
||||
|
||||
# Declare all framework and module inputs via flake-file
|
||||
flake-file.inputs = {
|
||||
den.url = "github:vic/den";
|
||||
flake-file.url = "github:vic/flake-file";
|
||||
import-tree.url = "github:vic/import-tree";
|
||||
flake-aspects.url = "github:vic/flake-aspects";
|
||||
nixpkgs.url = "github:nixos/nixpkgs/master";
|
||||
flake-parts = {
|
||||
url = "github:hercules-ci/flake-parts";
|
||||
inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
};
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
darwin = {
|
||||
url = "github:LnL7/nix-darwin/master";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
deploy-rs.url = "github:serokell/deploy-rs";
|
||||
disko = {
|
||||
url = "github:nix-community/disko";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nix-homebrew.url = "github:zhaofengli-wip/nix-homebrew";
|
||||
homebrew-core = {
|
||||
url = "github:homebrew/homebrew-core";
|
||||
flake = false;
|
||||
};
|
||||
homebrew-cask = {
|
||||
url = "github:homebrew/homebrew-cask";
|
||||
flake = false;
|
||||
};
|
||||
nixvim.url = "github:nix-community/nixvim";
|
||||
llm-agents.url = "github:numtide/llm-agents.nix";
|
||||
# Overlay inputs
|
||||
himalaya.url = "github:pimalaya/himalaya";
|
||||
jj-ryu = {
|
||||
url = "github:dmmulroy/jj-ryu";
|
||||
flake = false;
|
||||
};
|
||||
jj-starship.url = "github:dmmulroy/jj-starship";
|
||||
zjstatus.url = "github:dj95/zjstatus";
|
||||
tuicr.url = "github:agavra/tuicr";
|
||||
naersk = {
|
||||
url = "github:nix-community/naersk/master";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
# Secrets inputs
|
||||
sops-nix = {
|
||||
url = "github:Mic92/sops-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
}
|
||||
26
modules/deploy.nix
Normal file
26
modules/deploy.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
inputs,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
flake.deploy.nodes = {
|
||||
michael = {
|
||||
hostname = "michael";
|
||||
sshUser = "cschmatzler";
|
||||
profiles.system = {
|
||||
user = "root";
|
||||
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos config.flake.nixosConfigurations.michael;
|
||||
};
|
||||
};
|
||||
tahani = {
|
||||
hostname = "tahani";
|
||||
sshUser = "cschmatzler";
|
||||
profiles.system = {
|
||||
user = "root";
|
||||
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos config.flake.nixosConfigurations.tahani;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
flake.checks.x86_64-linux = inputs.deploy-rs.lib.x86_64-linux.deployChecks config.flake.deploy;
|
||||
}
|
||||
144
modules/desktop.nix
Normal file
144
modules/desktop.nix
Normal file
@@ -0,0 +1,144 @@
|
||||
{...}: {
|
||||
den.aspects.desktop.homeManager = {...}: {
|
||||
programs.aerospace = {
|
||||
enable = true;
|
||||
launchd.enable = true;
|
||||
settings = {
|
||||
start-at-login = true;
|
||||
accordion-padding = 30;
|
||||
default-root-container-layout = "tiles";
|
||||
default-root-container-orientation = "auto";
|
||||
on-focused-monitor-changed = [
|
||||
"move-mouse monitor-lazy-center"
|
||||
];
|
||||
|
||||
workspace-to-monitor-force-assignment = {
|
||||
"1" = "main";
|
||||
"2" = "main";
|
||||
"3" = "main";
|
||||
"4" = "main";
|
||||
"5" = "main";
|
||||
"6" = "main";
|
||||
"7" = "main";
|
||||
"8" = "main";
|
||||
"9" = "secondary";
|
||||
};
|
||||
|
||||
gaps = {
|
||||
inner = {
|
||||
horizontal = 8;
|
||||
vertical = 8;
|
||||
};
|
||||
outer = {
|
||||
left = 8;
|
||||
right = 8;
|
||||
top = 8;
|
||||
bottom = 8;
|
||||
};
|
||||
};
|
||||
|
||||
on-window-detected = [
|
||||
{
|
||||
"if" = {
|
||||
"app-id" = "com.apple.systempreferences";
|
||||
};
|
||||
run = "layout floating";
|
||||
}
|
||||
{
|
||||
"if" = {
|
||||
"app-id" = "com.mitchellh.ghostty";
|
||||
};
|
||||
run = ["layout tiling" "move-node-to-workspace 3"];
|
||||
}
|
||||
{
|
||||
"if" = {
|
||||
"app-id" = "net.imput.helium";
|
||||
};
|
||||
run = "move-node-to-workspace 2";
|
||||
}
|
||||
{
|
||||
"if" = {
|
||||
"app-id" = "com.tinyspeck.slackmacgap";
|
||||
};
|
||||
run = "move-node-to-workspace 5";
|
||||
}
|
||||
{
|
||||
"if" = {
|
||||
"app-id" = "net.whatsapp.WhatsApp";
|
||||
};
|
||||
run = "move-node-to-workspace 5";
|
||||
}
|
||||
{
|
||||
"if" = {
|
||||
"app-id" = "com.tidal.desktop";
|
||||
};
|
||||
run = "move-node-to-workspace 6";
|
||||
}
|
||||
];
|
||||
|
||||
mode = {
|
||||
main.binding = {
|
||||
"alt-enter" = "exec-and-forget open -a Ghostty";
|
||||
"alt-h" = "focus left";
|
||||
"alt-j" = "focus down";
|
||||
"alt-k" = "focus up";
|
||||
"alt-l" = "focus right";
|
||||
"alt-shift-h" = "move left";
|
||||
"alt-shift-j" = "move down";
|
||||
"alt-shift-k" = "move up";
|
||||
"alt-shift-l" = "move right";
|
||||
"alt-ctrl-h" = "focus-monitor --wrap-around left";
|
||||
"alt-ctrl-j" = "focus-monitor --wrap-around down";
|
||||
"alt-ctrl-k" = "focus-monitor --wrap-around up";
|
||||
"alt-ctrl-l" = "focus-monitor --wrap-around right";
|
||||
"alt-ctrl-shift-h" = "move-node-to-monitor --focus-follows-window --wrap-around left";
|
||||
"alt-ctrl-shift-j" = "move-node-to-monitor --focus-follows-window --wrap-around down";
|
||||
"alt-ctrl-shift-k" = "move-node-to-monitor --focus-follows-window --wrap-around up";
|
||||
"alt-ctrl-shift-l" = "move-node-to-monitor --focus-follows-window --wrap-around right";
|
||||
"alt-space" = "layout tiles accordion";
|
||||
"alt-shift-space" = "layout floating tiling";
|
||||
"alt-slash" = "layout horizontal vertical";
|
||||
"alt-f" = "fullscreen";
|
||||
"alt-tab" = "workspace-back-and-forth";
|
||||
"alt-shift-tab" = "move-workspace-to-monitor --wrap-around next";
|
||||
"alt-r" = "mode resize";
|
||||
"alt-shift-semicolon" = "mode service";
|
||||
"alt-1" = "workspace 1";
|
||||
"alt-2" = "workspace 2";
|
||||
"alt-3" = "workspace 3";
|
||||
"alt-4" = "workspace 4";
|
||||
"alt-5" = "workspace 5";
|
||||
"alt-6" = "workspace 6";
|
||||
"alt-7" = "workspace 7";
|
||||
"alt-8" = "workspace 8";
|
||||
"alt-9" = "workspace 9";
|
||||
"alt-shift-1" = "move-node-to-workspace --focus-follows-window 1";
|
||||
"alt-shift-2" = "move-node-to-workspace --focus-follows-window 2";
|
||||
"alt-shift-3" = "move-node-to-workspace --focus-follows-window 3";
|
||||
"alt-shift-4" = "move-node-to-workspace --focus-follows-window 4";
|
||||
"alt-shift-5" = "move-node-to-workspace --focus-follows-window 5";
|
||||
"alt-shift-6" = "move-node-to-workspace --focus-follows-window 6";
|
||||
"alt-shift-7" = "move-node-to-workspace --focus-follows-window 7";
|
||||
"alt-shift-8" = "move-node-to-workspace --focus-follows-window 8";
|
||||
"alt-shift-9" = "move-node-to-workspace --focus-follows-window 9";
|
||||
};
|
||||
resize.binding = {
|
||||
"h" = "resize width -50";
|
||||
"j" = "resize height +50";
|
||||
"k" = "resize height -50";
|
||||
"l" = "resize width +50";
|
||||
"enter" = "mode main";
|
||||
"esc" = "mode main";
|
||||
};
|
||||
service.binding = {
|
||||
"esc" = "mode main";
|
||||
"r" = ["reload-config" "mode main"];
|
||||
"b" = ["balance-sizes" "mode main"];
|
||||
"f" = ["layout floating tiling" "mode main"];
|
||||
"backspace" = ["close-all-windows-but-current" "mode main"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
371
modules/dev-tools.nix
Normal file
371
modules/dev-tools.nix
Normal file
@@ -0,0 +1,371 @@
|
||||
{...}: {
|
||||
den.aspects.dev-tools.homeManager = {...}: let
|
||||
name = "Christoph Schmatzler";
|
||||
in {
|
||||
# Git configuration
|
||||
programs.git = {
|
||||
enable = true;
|
||||
ignores = ["*.swp"];
|
||||
settings = {
|
||||
user.name = name;
|
||||
init.defaultBranch = "main";
|
||||
core = {
|
||||
editor = "vim";
|
||||
autocrlf = "input";
|
||||
pager = "delta";
|
||||
};
|
||||
credential = {
|
||||
helper = "!gh auth git-credential";
|
||||
"https://github.com".useHttpPath = true;
|
||||
"https://gist.github.com".useHttpPath = true;
|
||||
};
|
||||
pull.rebase = true;
|
||||
rebase.autoStash = true;
|
||||
interactive.diffFilter = "delta --color-only";
|
||||
delta = {
|
||||
navigate = true;
|
||||
line-numbers = true;
|
||||
syntax-theme = "GitHub";
|
||||
side-by-side = true;
|
||||
pager = "less -FRX";
|
||||
};
|
||||
pager = {
|
||||
diff = "delta";
|
||||
log = "delta";
|
||||
show = "delta";
|
||||
};
|
||||
};
|
||||
lfs = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Git shell aliases
|
||||
home.shellAliases = {
|
||||
g = "git";
|
||||
ga = "git add";
|
||||
gaa = "git add --all";
|
||||
gapa = "git add --patch";
|
||||
gau = "git add --update";
|
||||
gav = "git add --verbose";
|
||||
gap = "git apply";
|
||||
gapt = "git apply --3way";
|
||||
gb = "git branch";
|
||||
gba = "git branch --all";
|
||||
gbd = "git branch --delete";
|
||||
gbD = "git branch --delete --force";
|
||||
gbl = "git blame -w";
|
||||
gbnm = "git branch --no-merged";
|
||||
gbr = "git branch --remote";
|
||||
gbs = "git bisect";
|
||||
gbsb = "git bisect bad";
|
||||
gbsg = "git bisect good";
|
||||
gbsn = "git bisect new";
|
||||
gbso = "git bisect old";
|
||||
gbsr = "git bisect reset";
|
||||
gbss = "git bisect start";
|
||||
gc = "git commit --verbose";
|
||||
gca = "git commit --verbose --all";
|
||||
gcam = "git commit --all --message";
|
||||
gcas = "git commit --all --signoff";
|
||||
gcasm = "git commit --all --signoff --message";
|
||||
gcb = "git checkout -b";
|
||||
gcB = "git checkout -B";
|
||||
gcf = "git config --list";
|
||||
gclean = "git clean --interactive -d";
|
||||
gcl = "git clone --recurse-submodules";
|
||||
gclf = "git clone --recursive --shallow-submodules --filter=blob:none --also-filter-submodules";
|
||||
gcm = "git checkout main";
|
||||
gcmsg = "git commit --message";
|
||||
gcn = "git commit --verbose --no-edit";
|
||||
gco = "git checkout";
|
||||
gcor = "git checkout --recurse-submodules";
|
||||
gcount = "git shortlog --summary --numbered";
|
||||
gcp = "git cherry-pick";
|
||||
gcpa = "git cherry-pick --abort";
|
||||
gcpc = "git cherry-pick --continue";
|
||||
gcs = "git commit --gpg-sign";
|
||||
gcss = "git commit --gpg-sign --signoff";
|
||||
gcssm = "git commit --gpg-sign --signoff --message";
|
||||
gcsm = "git commit --signoff --message";
|
||||
gd = "git diff";
|
||||
gdca = "git diff --cached";
|
||||
gdcw = "git diff --cached --word-diff";
|
||||
gds = "git diff --staged";
|
||||
gdw = "git diff --word-diff";
|
||||
gdt = "git diff-tree --no-commit-id --name-only -r";
|
||||
gdup = "git diff @{upstream}";
|
||||
gf = "git fetch";
|
||||
gfa = "git fetch --all --tags --prune";
|
||||
gfo = "git fetch origin";
|
||||
gg = "git gui citool";
|
||||
gga = "git gui citool --amend";
|
||||
ghh = "git help";
|
||||
gignore = "git update-index --assume-unchanged";
|
||||
gl = "git pull";
|
||||
glg = "git log --stat";
|
||||
glgp = "git log --stat --patch";
|
||||
glgg = "git log --graph";
|
||||
glgga = "git log --graph --decorate --all";
|
||||
glgm = "git log --graph --max-count=10";
|
||||
glo = "git log --oneline --decorate";
|
||||
glog = "git log --oneline --decorate --graph";
|
||||
gloga = "git log --oneline --decorate --graph --all";
|
||||
glol = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset\"";
|
||||
glola = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset\" --all";
|
||||
glols = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ar) %C(bold blue)<%an>%Creset\" --stat";
|
||||
glod = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset\"";
|
||||
glods = "git log --graph --pretty=\"%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%ad) %C(bold blue)<%an>%Creset\" --date=short";
|
||||
glum = "git pull upstream main";
|
||||
gm = "git merge";
|
||||
gma = "git merge --abort";
|
||||
gmc = "git merge --continue";
|
||||
gms = "git merge --squash";
|
||||
gmff = "git merge --ff-only";
|
||||
gmtl = "git mergetool --no-prompt";
|
||||
gmtlvim = "git mergetool --no-prompt --tool=vimdiff";
|
||||
gmum = "git merge upstream/main";
|
||||
gmom = "git merge origin/main";
|
||||
gp = "git push";
|
||||
gpd = "git push --dry-run";
|
||||
gpf = "git push --force-with-lease";
|
||||
gpod = "git push origin --delete";
|
||||
gpr = "git pull --rebase";
|
||||
gpra = "git pull --rebase --autostash";
|
||||
gprav = "git pull --rebase --autostash -v";
|
||||
gprom = "git pull --rebase origin main";
|
||||
gpromi = "git pull --rebase=interactive origin main";
|
||||
gprv = "git pull --rebase -v";
|
||||
gprum = "git pull --rebase upstream main";
|
||||
gprumi = "git pull --rebase=interactive upstream main";
|
||||
gpv = "git push --verbose";
|
||||
gpu = "git push upstream";
|
||||
gr = "git remote";
|
||||
gra = "git remote add";
|
||||
grb = "git rebase";
|
||||
grba = "git rebase --abort";
|
||||
grbc = "git rebase --continue";
|
||||
grbd = "git rebase develop";
|
||||
grbi = "git rebase --interactive";
|
||||
grbm = "git rebase main";
|
||||
grbo = "git rebase --onto";
|
||||
grbom = "git rebase origin/main";
|
||||
grbs = "git rebase --skip";
|
||||
grbum = "git rebase upstream/main";
|
||||
grev = "git revert";
|
||||
greva = "git revert --abort";
|
||||
grevc = "git revert --continue";
|
||||
grf = "git reflog";
|
||||
grh = "git reset";
|
||||
grhh = "git reset --hard";
|
||||
grhk = "git reset --keep";
|
||||
grhs = "git reset --soft";
|
||||
grm = "git rm";
|
||||
grmc = "git rm --cached";
|
||||
grmv = "git remote rename";
|
||||
grrm = "git remote remove";
|
||||
grs = "git restore";
|
||||
grset = "git remote set-url";
|
||||
grss = "git restore --source";
|
||||
grst = "git restore --staged";
|
||||
gru = "git reset --";
|
||||
grup = "git remote update";
|
||||
grv = "git remote --verbose";
|
||||
gsb = "git status --short --branch";
|
||||
gsh = "git show";
|
||||
gsi = "git submodule init";
|
||||
gsps = "git show --pretty=short --show-signature";
|
||||
gss = "git status --short";
|
||||
gst = "git status";
|
||||
gsta = "git stash push";
|
||||
gstaa = "git stash apply";
|
||||
gstall = "git stash --all";
|
||||
gstc = "git stash clear";
|
||||
gstd = "git stash drop";
|
||||
gstl = "git stash list";
|
||||
gstp = "git stash pop";
|
||||
gsts = "git stash show --patch";
|
||||
gstu = "git stash push --include-untracked";
|
||||
gsu = "git submodule update";
|
||||
gsw = "git switch";
|
||||
gswc = "git switch --create";
|
||||
gswd = "git switch develop";
|
||||
gswm = "git switch main";
|
||||
gta = "git tag --annotate";
|
||||
gts = "git tag --sign";
|
||||
gunignore = "git update-index --no-assume-unchanged";
|
||||
gwch = "git whatchanged -p --abbrev-commit --pretty=medium";
|
||||
gwt = "git worktree";
|
||||
gwta = "git worktree add";
|
||||
gwtls = "git worktree list";
|
||||
gwtmv = "git worktree move";
|
||||
gwtrm = "git worktree remove";
|
||||
lg = "lazygit";
|
||||
};
|
||||
|
||||
# Complex git aliases that require pipes/subshells — nushell `alias` can't
|
||||
# handle these, so they're defined as custom commands instead.
|
||||
programs.nushell.extraConfig = ''
|
||||
def ggpull [] { git pull origin (git branch --show-current | str trim) }
|
||||
def ggpush [] { git push origin (git branch --show-current | str trim) }
|
||||
def ggsup [] { git branch $"--set-upstream-to=origin/(git branch --show-current | str trim)" }
|
||||
def gluc [] { git pull upstream (git branch --show-current | str trim) }
|
||||
def gpsup [] { git push --set-upstream origin (git branch --show-current | str trim) }
|
||||
def gpsupf [] { git push --set-upstream origin (git branch --show-current | str trim) --force-with-lease }
|
||||
def groh [] { git reset $"origin/(git branch --show-current | str trim)" --hard }
|
||||
def --env grt [] {
|
||||
let toplevel = (do { git rev-parse --show-toplevel } | complete | get stdout | str trim)
|
||||
if ($toplevel | is-not-empty) { cd $toplevel } else { cd . }
|
||||
}
|
||||
def gfg [...pattern: string] { git ls-files | lines | where {|f| $f =~ ($pattern | str join ".*") } }
|
||||
def gignored [] { git ls-files -v | lines | where {|l| ($l | str substring 0..1) =~ "[a-z]" } }
|
||||
def gpoat [] { git push origin --all; git push origin --tags }
|
||||
def gtv [] { git tag | lines | sort }
|
||||
def gwipe [] { git reset --hard; git clean --force -df }
|
||||
def gunwip [] {
|
||||
let msg = (git rev-list --max-count=1 --format="%s" HEAD | lines | get 1)
|
||||
if ($msg | str contains "--wip--") { git reset HEAD~1 }
|
||||
}
|
||||
def gwip [] {
|
||||
git add -A
|
||||
let deleted = (git ls-files --deleted | lines)
|
||||
if ($deleted | is-not-empty) { git rm ...$deleted }
|
||||
git commit --no-verify --no-gpg-sign --message "--wip-- [skip ci]"
|
||||
}
|
||||
'';
|
||||
|
||||
# Jujutsu configuration
|
||||
programs.jujutsu = {
|
||||
enable = true;
|
||||
settings = {
|
||||
user = {
|
||||
name = name;
|
||||
email = "christoph@schmatzler.com";
|
||||
};
|
||||
git = {
|
||||
sign-on-push = true;
|
||||
subprocess = true;
|
||||
write-change-id-header = true;
|
||||
private-commits = "description(glob:'wip:*') | description(glob:'WIP:*') | description(exact:'')";
|
||||
};
|
||||
fsmonitor = {
|
||||
backend = "watchman";
|
||||
};
|
||||
ui = {
|
||||
default-command = "status";
|
||||
diff-formatter = ":git";
|
||||
pager = ["delta" "--pager" "less -FRX"];
|
||||
diff-editor = ["nvim" "-c" "DiffEditor $left $right $output"];
|
||||
movement = {
|
||||
edit = true;
|
||||
};
|
||||
};
|
||||
aliases = {
|
||||
n = ["new"];
|
||||
tug = ["bookmark" "move" "--from" "closest_bookmark(@-)" "--to" "@-"];
|
||||
stack = ["log" "-r" "stack()"];
|
||||
retrunk = ["rebase" "-d" "trunk()"];
|
||||
bm = ["bookmark"];
|
||||
gf = ["git" "fetch"];
|
||||
gp = ["git" "push"];
|
||||
};
|
||||
revset-aliases = {
|
||||
"closest_bookmark(to)" = "heads(::to & bookmarks())";
|
||||
"closest_pushable(to)" = "heads(::to & mutable() & ~description(exact:\"\") & (~empty() | merges()))";
|
||||
"mine()" = "author(\"christoph@schmatzler.com\")";
|
||||
"wip()" = "mine() ~ immutable()";
|
||||
"open()" = "mine() ~ ::trunk()";
|
||||
"current()" = "@:: & mutable()";
|
||||
"stack()" = "reachable(@, mutable())";
|
||||
};
|
||||
templates = {
|
||||
draft_commit_description = ''
|
||||
concat(
|
||||
coalesce(description, default_commit_description, "\n"),
|
||||
surround(
|
||||
"\nJJ: This commit contains the following changes:\n", "",
|
||||
indent("JJ: ", diff.stat(72)),
|
||||
),
|
||||
"\nJJ: ignore-rest\n",
|
||||
diff.git(),
|
||||
)
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Lazygit configuration
|
||||
programs.lazygit = {
|
||||
enable = true;
|
||||
settings = {
|
||||
git = {
|
||||
commit.signOff = true;
|
||||
pagers = [
|
||||
{
|
||||
delta = {
|
||||
colorArg = "always";
|
||||
pager = "DELTA_FEATURES=decorations delta --light --paging=never --line-numbers --hyperlinks --hyperlinks-file-link-format=\"lazygit-edit://{path}:{line}\"";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
gui = {
|
||||
authorColors = {
|
||||
"*" = "#7287fd";
|
||||
};
|
||||
theme = {
|
||||
activeBorderColor = [
|
||||
"#8839ef"
|
||||
"bold"
|
||||
];
|
||||
inactiveBorderColor = [
|
||||
"#6c6f85"
|
||||
];
|
||||
optionsTextColor = [
|
||||
"#1e66f5"
|
||||
];
|
||||
selectedLineBgColor = [
|
||||
"#ccd0da"
|
||||
];
|
||||
cherryPickedCommitBgColor = [
|
||||
"#bcc0cc"
|
||||
];
|
||||
cherryPickedCommitFgColor = [
|
||||
"#8839ef"
|
||||
];
|
||||
defaultFgColor = [
|
||||
"#4c4f69"
|
||||
];
|
||||
searchingActiveBorderColor = [
|
||||
"#df8e1d"
|
||||
];
|
||||
unstagedChangesColor = [
|
||||
"#d20f39"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# JJUI configuration
|
||||
programs.jjui = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Direnv configuration
|
||||
programs.direnv = {
|
||||
enable = true;
|
||||
nix-direnv.enable = true;
|
||||
};
|
||||
|
||||
# Mise configuration
|
||||
programs.mise = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
globalConfig.settings = {
|
||||
auto_install = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
54
modules/email.nix
Normal file
54
modules/email.nix
Normal file
@@ -0,0 +1,54 @@
|
||||
{...}: {
|
||||
den.aspects.email.homeManager = {pkgs, ...}: {
|
||||
programs.himalaya = {
|
||||
enable = true;
|
||||
package =
|
||||
pkgs.writeShellApplication {
|
||||
name = "himalaya";
|
||||
runtimeInputs = [pkgs.bash pkgs.coreutils pkgs.himalaya];
|
||||
text = ''
|
||||
exec env RUST_LOG="warn,imap_codec::response=error" ${pkgs.himalaya}/bin/himalaya "$@"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
programs.mbsync.enable = true;
|
||||
services.mbsync = {
|
||||
enable = true;
|
||||
frequency = "*:0/5";
|
||||
};
|
||||
|
||||
accounts.email = {
|
||||
accounts."christoph@schmatzler.com" = {
|
||||
primary = true;
|
||||
maildir.path = "christoph@schmatzler.com";
|
||||
address = "christoph@schmatzler.com";
|
||||
userName = "christoph.schmatzler@icloud.com";
|
||||
realName = "Christoph Schmatzler";
|
||||
passwordCommand = ["cat" "/run/secrets/tahani-email-password"];
|
||||
folders = {
|
||||
inbox = "INBOX";
|
||||
drafts = "Drafts";
|
||||
sent = "Sent Messages";
|
||||
trash = "Deleted Messages";
|
||||
};
|
||||
smtp = {
|
||||
host = "smtp.mail.me.com";
|
||||
port = 587;
|
||||
tls.useStartTls = true;
|
||||
};
|
||||
himalaya.enable = true;
|
||||
mbsync = {
|
||||
enable = true;
|
||||
create = "both";
|
||||
expunge = "both";
|
||||
};
|
||||
imap = {
|
||||
host = "imap.mail.me.com";
|
||||
port = 993;
|
||||
tls.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.my.gitea;
|
||||
in {
|
||||
options.my.gitea = {
|
||||
enable = mkEnableOption "Gitea git hosting service";
|
||||
|
||||
litestream = {
|
||||
bucket =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
description = "S3 bucket name for Litestream database replication";
|
||||
};
|
||||
|
||||
secretFile =
|
||||
mkOption {
|
||||
type = types.path;
|
||||
description = "Path to the environment file containing S3 credentials for Litestream";
|
||||
};
|
||||
};
|
||||
|
||||
restic = {
|
||||
bucket =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
description = "S3 bucket name for Restic repository backups";
|
||||
};
|
||||
|
||||
passwordFile =
|
||||
mkOption {
|
||||
type = types.path;
|
||||
description = "Path to the file containing the Restic repository password";
|
||||
};
|
||||
|
||||
environmentFile =
|
||||
mkOption {
|
||||
type = types.path;
|
||||
description = "Path to the environment file containing S3 credentials for Restic";
|
||||
};
|
||||
};
|
||||
|
||||
s3 = {
|
||||
endpoint =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "s3.eu-central-003.backblazeb2.com";
|
||||
description = "S3 endpoint URL";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
mkIf cfg.enable {
|
||||
networking.firewall.allowedTCPPorts = [80 443];
|
||||
|
||||
services.redis.servers.gitea = {
|
||||
enable = true;
|
||||
port = 6380;
|
||||
bind = "127.0.0.1";
|
||||
settings = {
|
||||
maxmemory = "64mb";
|
||||
maxmemory-policy = "allkeys-lru";
|
||||
};
|
||||
};
|
||||
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
path = "/var/lib/gitea/data/gitea.db";
|
||||
};
|
||||
settings = {
|
||||
server = {
|
||||
ROOT_URL = "https://git.schmatzler.com/";
|
||||
DOMAIN = "git.schmatzler.com";
|
||||
HTTP_ADDR = "127.0.0.1";
|
||||
HTTP_PORT = 3000;
|
||||
LANDING_PAGE = "explore";
|
||||
};
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
security.INSTALL_LOCK = true;
|
||||
cache = {
|
||||
ADAPTER = "redis";
|
||||
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
|
||||
ITEM_TTL = "16h";
|
||||
};
|
||||
"cache.last_commit" = {
|
||||
ITEM_TTL = "8760h";
|
||||
COMMITS_COUNT = 100;
|
||||
};
|
||||
session = {
|
||||
PROVIDER = "redis";
|
||||
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
|
||||
COOKIE_SECURE = true;
|
||||
SAME_SITE = "strict";
|
||||
};
|
||||
api.ENABLE_SWAGGER = false;
|
||||
};
|
||||
};
|
||||
|
||||
services.litestream = {
|
||||
enable = true;
|
||||
environmentFile = cfg.litestream.secretFile;
|
||||
settings = {
|
||||
dbs = [
|
||||
{
|
||||
path = "/var/lib/gitea/data/gitea.db";
|
||||
replicas = [
|
||||
{
|
||||
type = "s3";
|
||||
bucket = cfg.litestream.bucket;
|
||||
path = "gitea";
|
||||
endpoint = cfg.s3.endpoint;
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.litestream = {
|
||||
serviceConfig = {
|
||||
User = mkForce "gitea";
|
||||
Group = mkForce "gitea";
|
||||
};
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
virtualHosts."git.schmatzler.com".extraConfig = ''
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
}
|
||||
reverse_proxy localhost:3000
|
||||
'';
|
||||
};
|
||||
|
||||
services.restic.backups.gitea = {
|
||||
repository = "s3:${cfg.s3.endpoint}/${cfg.restic.bucket}";
|
||||
paths = ["/var/lib/gitea"];
|
||||
exclude = [
|
||||
"/var/lib/gitea/log"
|
||||
"/var/lib/gitea/data/gitea.db"
|
||||
"/var/lib/gitea/data/gitea.db-shm"
|
||||
"/var/lib/gitea/data/gitea.db-wal"
|
||||
];
|
||||
passwordFile = cfg.restic.passwordFile;
|
||||
environmentFile = cfg.restic.environmentFile;
|
||||
pruneOpts = [
|
||||
"--keep-daily 7"
|
||||
"--keep-weekly 4"
|
||||
"--keep-monthly 6"
|
||||
];
|
||||
timerConfig = {
|
||||
OnCalendar = "daily";
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "1h";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.restic-backups-gitea = {
|
||||
wants = ["restic-init-gitea.service"];
|
||||
after = ["restic-init-gitea.service"];
|
||||
serviceConfig = {
|
||||
User = mkForce "gitea";
|
||||
Group = mkForce "gitea";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.restic-init-gitea = {
|
||||
description = "Initialize Restic repository for Gitea backups";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network-online.target"];
|
||||
wants = ["network-online.target"];
|
||||
path = [pkgs.restic];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "gitea";
|
||||
Group = "gitea";
|
||||
RemainAfterExit = true;
|
||||
EnvironmentFile = cfg.restic.environmentFile;
|
||||
};
|
||||
script = ''
|
||||
export RESTIC_PASSWORD=$(cat ${cfg.restic.passwordFile})
|
||||
restic -r s3:${cfg.s3.endpoint}/${cfg.restic.bucket} snapshots &>/dev/null || \
|
||||
restic -r s3:${cfg.s3.endpoint}/${cfg.restic.bucket} init
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
6
modules/hosts.nix
Normal file
6
modules/hosts.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{...}: {
|
||||
den.hosts.aarch64-darwin.chidi.users.cschmatzler = {};
|
||||
den.hosts.aarch64-darwin.jason.users.cschmatzler = {};
|
||||
den.hosts.x86_64-linux.michael.users.cschmatzler = {};
|
||||
den.hosts.x86_64-linux.tahani.users.cschmatzler = {};
|
||||
}
|
||||
25
modules/jason.nix
Normal file
25
modules/jason.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{den, ...}: {
|
||||
den.aspects.jason.includes = [
|
||||
den.aspects.darwin-system
|
||||
den.aspects.core
|
||||
den.aspects.tailscale
|
||||
den.aspects.desktop
|
||||
den.aspects.terminal
|
||||
den.aspects.atuin
|
||||
den.aspects.dev-tools
|
||||
den.aspects.neovim
|
||||
den.aspects.ai-tools
|
||||
den.aspects.zellij
|
||||
den.aspects.zk
|
||||
];
|
||||
|
||||
den.aspects.jason.darwin = {...}: {
|
||||
networking.hostName = "jason";
|
||||
networking.computerName = "jason";
|
||||
};
|
||||
|
||||
den.aspects.jason.homeManager = {...}: {
|
||||
fonts.fontconfig.enable = true;
|
||||
programs.git.settings.user.email = "christoph@schmatzler.com";
|
||||
};
|
||||
}
|
||||
191
modules/michael.nix
Normal file
191
modules/michael.nix
Normal file
@@ -0,0 +1,191 @@
|
||||
{
|
||||
inputs,
|
||||
den,
|
||||
...
|
||||
}: {
|
||||
den.aspects.michael.includes = [
|
||||
den.aspects.nixos-system
|
||||
den.aspects.core
|
||||
den.aspects.openssh
|
||||
den.aspects.fail2ban
|
||||
den.aspects.tailscale
|
||||
];
|
||||
|
||||
den.aspects.michael.nixos = {
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
modulesPath,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
./_hosts/michael/disk-config.nix
|
||||
./_hosts/michael/hardware-configuration.nix
|
||||
inputs.disko.nixosModules.default
|
||||
];
|
||||
|
||||
networking.hostName = "michael";
|
||||
|
||||
sops.secrets = {
|
||||
michael-gitea-litestream = {
|
||||
sopsFile = ../secrets/michael-gitea-litestream;
|
||||
format = "binary";
|
||||
owner = "gitea";
|
||||
group = "gitea";
|
||||
};
|
||||
michael-gitea-restic-password = {
|
||||
sopsFile = ../secrets/michael-gitea-restic-password;
|
||||
format = "binary";
|
||||
owner = "gitea";
|
||||
group = "gitea";
|
||||
};
|
||||
michael-gitea-restic-env = {
|
||||
sopsFile = ../secrets/michael-gitea-restic-env;
|
||||
format = "binary";
|
||||
owner = "gitea";
|
||||
group = "gitea";
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [80 443];
|
||||
|
||||
services.redis.servers.gitea = {
|
||||
enable = true;
|
||||
port = 6380;
|
||||
bind = "127.0.0.1";
|
||||
settings = {
|
||||
maxmemory = "64mb";
|
||||
maxmemory-policy = "allkeys-lru";
|
||||
};
|
||||
};
|
||||
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
path = "/var/lib/gitea/data/gitea.db";
|
||||
};
|
||||
settings = {
|
||||
server = {
|
||||
ROOT_URL = "https://git.schmatzler.com/";
|
||||
DOMAIN = "git.schmatzler.com";
|
||||
HTTP_ADDR = "127.0.0.1";
|
||||
HTTP_PORT = 3000;
|
||||
LANDING_PAGE = "explore";
|
||||
};
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
security.INSTALL_LOCK = true;
|
||||
cache = {
|
||||
ADAPTER = "redis";
|
||||
HOST = "redis://127.0.0.1:6380/0?pool_size=100&idle_timeout=180s";
|
||||
ITEM_TTL = "16h";
|
||||
};
|
||||
"cache.last_commit" = {
|
||||
ITEM_TTL = "8760h";
|
||||
COMMITS_COUNT = 100;
|
||||
};
|
||||
session = {
|
||||
PROVIDER = "redis";
|
||||
PROVIDER_CONFIG = "redis://127.0.0.1:6380/1?pool_size=100&idle_timeout=180s";
|
||||
COOKIE_SECURE = true;
|
||||
SAME_SITE = "strict";
|
||||
};
|
||||
api.ENABLE_SWAGGER = false;
|
||||
};
|
||||
};
|
||||
|
||||
services.litestream = {
|
||||
enable = true;
|
||||
environmentFile = config.sops.secrets.michael-gitea-litestream.path;
|
||||
settings = {
|
||||
dbs = [
|
||||
{
|
||||
path = "/var/lib/gitea/data/gitea.db";
|
||||
replicas = [
|
||||
{
|
||||
type = "s3";
|
||||
bucket = "michael-gitea-litestream";
|
||||
path = "gitea";
|
||||
endpoint = "s3.eu-central-003.backblazeb2.com";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.litestream = {
|
||||
serviceConfig = {
|
||||
User = lib.mkForce "gitea";
|
||||
Group = lib.mkForce "gitea";
|
||||
};
|
||||
};
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
virtualHosts."git.schmatzler.com".extraConfig = ''
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
Referrer-Policy "strict-origin-when-cross-origin"
|
||||
}
|
||||
reverse_proxy localhost:3000
|
||||
'';
|
||||
};
|
||||
|
||||
services.restic.backups.gitea = {
|
||||
repository = "s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories";
|
||||
paths = ["/var/lib/gitea"];
|
||||
exclude = [
|
||||
"/var/lib/gitea/log"
|
||||
"/var/lib/gitea/data/gitea.db"
|
||||
"/var/lib/gitea/data/gitea.db-shm"
|
||||
"/var/lib/gitea/data/gitea.db-wal"
|
||||
];
|
||||
passwordFile = config.sops.secrets.michael-gitea-restic-password.path;
|
||||
environmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||
pruneOpts = [
|
||||
"--keep-daily 7"
|
||||
"--keep-weekly 4"
|
||||
"--keep-monthly 6"
|
||||
];
|
||||
timerConfig = {
|
||||
OnCalendar = "daily";
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "1h";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.restic-backups-gitea = {
|
||||
wants = ["restic-init-gitea.service"];
|
||||
after = ["restic-init-gitea.service"];
|
||||
serviceConfig = {
|
||||
User = lib.mkForce "gitea";
|
||||
Group = lib.mkForce "gitea";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.restic-init-gitea = {
|
||||
description = "Initialize Restic repository for Gitea backups";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network-online.target"];
|
||||
wants = ["network-online.target"];
|
||||
path = [pkgs.restic];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "gitea";
|
||||
Group = "gitea";
|
||||
RemainAfterExit = true;
|
||||
EnvironmentFile = config.sops.secrets.michael-gitea-restic-env.path;
|
||||
};
|
||||
script = ''
|
||||
export RESTIC_PASSWORD=$(cat ${config.sops.secrets.michael-gitea-restic-password.path})
|
||||
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories snapshots &>/dev/null || \
|
||||
restic -r s3:s3.eu-central-003.backblazeb2.com/michael-gitea-repositories init
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
8
modules/neovim.nix
Normal file
8
modules/neovim.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{inputs, ...}: {
|
||||
den.aspects.neovim.homeManager = {pkgs, ...}: {
|
||||
imports = [
|
||||
inputs.nixvim.homeModules.nixvim
|
||||
./_neovim/default.nix
|
||||
];
|
||||
};
|
||||
}
|
||||
67
modules/network.nix
Normal file
67
modules/network.nix
Normal file
@@ -0,0 +1,67 @@
|
||||
{...}: {
|
||||
den.aspects.openssh.nixos = {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "no";
|
||||
PasswordAuthentication = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
den.aspects.fail2ban.nixos = {
|
||||
services.fail2ban = {
|
||||
enable = true;
|
||||
maxretry = 5;
|
||||
bantime = "10m";
|
||||
bantime-increment = {
|
||||
enable = true;
|
||||
multipliers = "1 2 4 8 16 32 64";
|
||||
maxtime = "168h";
|
||||
overalljails = true;
|
||||
};
|
||||
jails = {
|
||||
sshd = {
|
||||
settings = {
|
||||
enabled = true;
|
||||
port = "ssh";
|
||||
filter = "sshd";
|
||||
maxretry = 3;
|
||||
};
|
||||
};
|
||||
gitea = {
|
||||
settings = {
|
||||
enabled = true;
|
||||
filter = "gitea";
|
||||
logpath = "/var/lib/gitea/log/gitea.log";
|
||||
maxretry = 10;
|
||||
findtime = 3600;
|
||||
bantime = 900;
|
||||
action = "iptables-allports";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."fail2ban/filter.d/gitea.local".text = ''
|
||||
[Definition]
|
||||
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
|
||||
ignoreregex =
|
||||
'';
|
||||
};
|
||||
|
||||
den.aspects.tailscale.nixos = {
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
permitCertUid = "caddy";
|
||||
useRoutingFeatures = "server";
|
||||
};
|
||||
};
|
||||
|
||||
den.aspects.tailscale.darwin = {
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
87
modules/nixos-system.nix
Normal file
87
modules/nixos-system.nix
Normal file
@@ -0,0 +1,87 @@
|
||||
{inputs, ...}: {
|
||||
den.aspects.nixos-system.nixos = {pkgs, ...}: {
|
||||
imports = [inputs.home-manager.nixosModules.home-manager];
|
||||
|
||||
security.sudo.enable = true;
|
||||
security.sudo.extraRules = [
|
||||
{
|
||||
users = ["cschmatzler"];
|
||||
commands = [
|
||||
{
|
||||
command = "/run/current-system/sw/bin/nix-env";
|
||||
options = ["NOPASSWD"];
|
||||
}
|
||||
{
|
||||
command = "/nix/store/*/bin/switch-to-configuration";
|
||||
options = ["NOPASSWD"];
|
||||
}
|
||||
{
|
||||
command = "/nix/store/*/bin/activate";
|
||||
options = ["NOPASSWD"];
|
||||
}
|
||||
{
|
||||
command = "/nix/store/*/bin/activate-rs";
|
||||
options = ["NOPASSWD"];
|
||||
}
|
||||
{
|
||||
command = "/nix/store/*/bin/wait-activate";
|
||||
options = ["NOPASSWD"];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
||||
time.timeZone = "UTC";
|
||||
|
||||
nix = {
|
||||
settings.trusted-users = ["cschmatzler"];
|
||||
gc.dates = "weekly";
|
||||
nixPath = ["nixos-config=/home/cschmatzler/.local/share/src/nixos-config:/etc/nixos"];
|
||||
};
|
||||
|
||||
boot = {
|
||||
loader = {
|
||||
systemd-boot = {
|
||||
enable = true;
|
||||
configurationLimit = 42;
|
||||
};
|
||||
efi.canTouchEfiVariables = true;
|
||||
};
|
||||
initrd.availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"ahci"
|
||||
"nvme"
|
||||
"usbhid"
|
||||
"usb_storage"
|
||||
"sd_mod"
|
||||
];
|
||||
kernelPackages = pkgs.linuxPackages_latest;
|
||||
};
|
||||
|
||||
users.users = {
|
||||
cschmatzler = {
|
||||
isNormalUser = true;
|
||||
home = "/home/cschmatzler";
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"sudo"
|
||||
"network"
|
||||
"systemd-journal"
|
||||
];
|
||||
shell = pkgs.nushell;
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfRZQ+7ejD3YHbyMTrV0gN1Gc0DxtGgl5CVZSupo5ws"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/I+/2QT47raegzMIyhwMEPKarJP/+Ox9ewA4ZFJwk/"
|
||||
];
|
||||
};
|
||||
root = {
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHfRZQ+7ejD3YHbyMTrV0gN1Gc0DxtGgl5CVZSupo5ws"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/I+/2QT47raegzMIyhwMEPKarJP/+Ox9ewA4ZFJwk/"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
home-manager.useGlobalPkgs = true;
|
||||
};
|
||||
}
|
||||
29
modules/overlays.nix
Normal file
29
modules/overlays.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{inputs, ...}: let
|
||||
overlays = [
|
||||
# himalaya
|
||||
(final: prev: {
|
||||
himalaya = inputs.himalaya.packages.${prev.stdenv.hostPlatform.system}.default;
|
||||
})
|
||||
# jj-ryu (uses build-rust-package helper)
|
||||
(final: prev: {
|
||||
jj-ryu =
|
||||
import ./_lib/build-rust-package.nix {
|
||||
inherit inputs prev;
|
||||
input = inputs.jj-ryu;
|
||||
};
|
||||
})
|
||||
# jj-starship (passes through upstream overlay)
|
||||
inputs.jj-starship.overlays.default
|
||||
# zjstatus
|
||||
(final: prev: {
|
||||
zjstatus = inputs.zjstatus.packages.${prev.stdenv.hostPlatform.system}.default;
|
||||
})
|
||||
# tuicr
|
||||
(final: prev: {
|
||||
tuicr = inputs.tuicr.defaultPackage.${prev.stdenv.hostPlatform.system};
|
||||
})
|
||||
];
|
||||
in {
|
||||
den.default.nixos.nixpkgs.overlays = overlays;
|
||||
den.default.darwin.nixpkgs.overlays = overlays;
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.my.pgbackrest;
|
||||
in {
|
||||
options.my.pgbackrest = {
|
||||
enable = mkEnableOption "pgBackRest PostgreSQL backup";
|
||||
|
||||
stanza =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "main";
|
||||
description = "Name of the pgBackRest stanza";
|
||||
};
|
||||
|
||||
secretFile =
|
||||
mkOption {
|
||||
type = types.path;
|
||||
description = "Path to the environment file containing S3 credentials and cipher passphrase";
|
||||
};
|
||||
|
||||
s3 =
|
||||
mkOption {
|
||||
type =
|
||||
types.submodule {
|
||||
options = {
|
||||
endpoint =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "s3.eu-central-003.backblazeb2.com";
|
||||
description = "S3 endpoint URL";
|
||||
};
|
||||
bucket =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
description = "S3 bucket name";
|
||||
};
|
||||
region =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "eu-central-003";
|
||||
description = "S3 region";
|
||||
};
|
||||
path =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "/backups";
|
||||
description = "Path within the S3 bucket";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = "S3 storage configuration";
|
||||
};
|
||||
|
||||
retention =
|
||||
mkOption {
|
||||
type =
|
||||
types.submodule {
|
||||
options = {
|
||||
full =
|
||||
mkOption {
|
||||
type = types.int;
|
||||
default = 7;
|
||||
description = "Number of full backups to retain";
|
||||
};
|
||||
diff =
|
||||
mkOption {
|
||||
type = types.int;
|
||||
default = 7;
|
||||
description = "Number of differential backups to retain";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = "Backup retention configuration";
|
||||
};
|
||||
|
||||
compression =
|
||||
mkOption {
|
||||
type =
|
||||
types.submodule {
|
||||
options = {
|
||||
type =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "zst";
|
||||
description = "Compression algorithm (none, gz, lz4, zst)";
|
||||
};
|
||||
level =
|
||||
mkOption {
|
||||
type = types.int;
|
||||
default = 3;
|
||||
description = "Compression level";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = "Compression configuration";
|
||||
};
|
||||
|
||||
processMax =
|
||||
mkOption {
|
||||
type = types.int;
|
||||
default = 2;
|
||||
description = "Maximum number of processes for parallel operations";
|
||||
};
|
||||
|
||||
schedule =
|
||||
mkOption {
|
||||
type =
|
||||
types.submodule {
|
||||
options = {
|
||||
full =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "daily";
|
||||
description = "OnCalendar expression for full backups";
|
||||
};
|
||||
diff =
|
||||
mkOption {
|
||||
type = types.str;
|
||||
default = "hourly";
|
||||
description = "OnCalendar expression for differential backups";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = "Backup schedule configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
mkIf cfg.enable (let
|
||||
archivePushScript =
|
||||
pkgs.writeShellScript "pgbackrest-archive-push" ''
|
||||
set -a
|
||||
source ${cfg.secretFile}
|
||||
set +a
|
||||
exec ${pkgs.pgbackrest}/bin/pgbackrest --stanza=${cfg.stanza} archive-push "$1"
|
||||
'';
|
||||
in {
|
||||
environment.systemPackages = [
|
||||
pkgs.pgbackrest
|
||||
(pkgs.writeShellScriptBin "pgbackrest-wrapper" ''
|
||||
set -a
|
||||
source ${cfg.secretFile}
|
||||
set +a
|
||||
exec ${pkgs.pgbackrest}/bin/pgbackrest "$@"
|
||||
'')
|
||||
];
|
||||
|
||||
services.postgresql.settings = {
|
||||
archive_mode = "on";
|
||||
archive_command = "${archivePushScript} %p";
|
||||
};
|
||||
|
||||
environment.etc."pgbackrest/pgbackrest.conf".text = ''
|
||||
[global]
|
||||
repo1-type=s3
|
||||
repo1-s3-endpoint=${cfg.s3.endpoint}
|
||||
repo1-s3-bucket=${cfg.s3.bucket}
|
||||
repo1-s3-region=${cfg.s3.region}
|
||||
repo1-path=${cfg.s3.path}
|
||||
repo1-retention-full=${toString cfg.retention.full}
|
||||
repo1-retention-diff=${toString cfg.retention.diff}
|
||||
repo1-cipher-type=aes-256-cbc
|
||||
compress-type=${cfg.compression.type}
|
||||
compress-level=${toString cfg.compression.level}
|
||||
process-max=${toString cfg.processMax}
|
||||
log-level-console=info
|
||||
log-level-file=detail
|
||||
log-path=/var/log/pgbackrest
|
||||
spool-path=/var/spool/pgbackrest
|
||||
|
||||
[${cfg.stanza}]
|
||||
pg1-path=/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}
|
||||
pg1-user=postgres
|
||||
'';
|
||||
|
||||
systemd.services.pgbackrest-stanza-create = {
|
||||
description = "pgBackRest Stanza Create";
|
||||
after = ["postgresql.service"];
|
||||
requires = ["postgresql.service"];
|
||||
path = [pkgs.pgbackrest];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "postgres";
|
||||
EnvironmentFile = cfg.secretFile;
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
script = ''
|
||||
pgbackrest --stanza=${cfg.stanza} stanza-create || true
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.pgbackrest-backup = {
|
||||
description = "pgBackRest Full Backup";
|
||||
after = ["postgresql.service" "pgbackrest-stanza-create.service"];
|
||||
requires = ["postgresql.service"];
|
||||
wants = ["pgbackrest-stanza-create.service"];
|
||||
path = [pkgs.pgbackrest];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "postgres";
|
||||
EnvironmentFile = cfg.secretFile;
|
||||
};
|
||||
script = ''
|
||||
pgbackrest --stanza=${cfg.stanza} backup --type=full
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.timers.pgbackrest-backup = {
|
||||
wantedBy = ["timers.target"];
|
||||
timerConfig = {
|
||||
OnCalendar = cfg.schedule.full;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "1h";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.pgbackrest-backup-diff = {
|
||||
description = "pgBackRest Differential Backup";
|
||||
after = ["postgresql.service" "pgbackrest-stanza-create.service"];
|
||||
requires = ["postgresql.service"];
|
||||
wants = ["pgbackrest-stanza-create.service"];
|
||||
path = [pkgs.pgbackrest];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "postgres";
|
||||
EnvironmentFile = cfg.secretFile;
|
||||
};
|
||||
script = ''
|
||||
pgbackrest --stanza=${cfg.stanza} backup --type=diff
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.timers.pgbackrest-backup-diff = {
|
||||
wantedBy = ["timers.target"];
|
||||
timerConfig = {
|
||||
OnCalendar = cfg.schedule.diff;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "5m";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/pgbackrest 0750 postgres postgres -"
|
||||
"d /var/log/pgbackrest 0750 postgres postgres -"
|
||||
"d /var/spool/pgbackrest 0750 postgres postgres -"
|
||||
];
|
||||
});
|
||||
}
|
||||
15
modules/secrets.nix
Normal file
15
modules/secrets.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{inputs, ...}: {
|
||||
# Import sops-nix modules into den.default per-class
|
||||
den.default.nixos.imports = [inputs.sops-nix.nixosModules.sops];
|
||||
den.default.darwin.imports = [inputs.sops-nix.darwinModules.sops];
|
||||
|
||||
# Configure NixOS SOPS defaults
|
||||
den.default.nixos.sops.age.sshKeyPaths = ["/etc/ssh/ssh_host_ed25519_key"];
|
||||
|
||||
# Configure Darwin SOPS defaults
|
||||
den.default.darwin = {
|
||||
sops.age.keyFile = "/Users/cschmatzler/.config/sops/age/keys.txt";
|
||||
sops.age.sshKeyPaths = [];
|
||||
sops.gnupg.sshKeyPaths = [];
|
||||
};
|
||||
}
|
||||
285
modules/shell.nix
Normal file
285
modules/shell.nix
Normal file
@@ -0,0 +1,285 @@
|
||||
{...}: {
|
||||
den.aspects.shell.homeManager = {
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
programs.nushell = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
show_banner = false;
|
||||
completions = {
|
||||
algorithm = "fuzzy";
|
||||
case_sensitive = false;
|
||||
};
|
||||
history = {
|
||||
file_format = "sqlite";
|
||||
};
|
||||
};
|
||||
|
||||
environmentVariables = {
|
||||
COLORTERM = "truecolor";
|
||||
COLORFGBG = "15;0";
|
||||
TERM_BACKGROUND = "light";
|
||||
EDITOR = "nvim";
|
||||
};
|
||||
|
||||
extraEnv =
|
||||
''
|
||||
$env.LS_COLORS = (${pkgs.vivid}/bin/vivid generate catppuccin-latte)
|
||||
''
|
||||
+ lib.optionalString pkgs.stdenv.isDarwin ''
|
||||
# Nushell on Darwin doesn't source /etc/zprofile or path_helper,
|
||||
# so nix-managed paths must be added explicitly.
|
||||
$env.PATH = ($env.PATH | split row (char esep) | prepend "/run/current-system/sw/bin" | prepend $"($env.HOME)/.nix-profile/bin")
|
||||
'';
|
||||
|
||||
extraConfig = ''
|
||||
# --- Catppuccin Latte Theme ---
|
||||
let theme = {
|
||||
rosewater: "#dc8a78"
|
||||
flamingo: "#dd7878"
|
||||
pink: "#ea76cb"
|
||||
mauve: "#8839ef"
|
||||
red: "#d20f39"
|
||||
maroon: "#e64553"
|
||||
peach: "#fe640b"
|
||||
yellow: "#df8e1d"
|
||||
green: "#40a02b"
|
||||
teal: "#179299"
|
||||
sky: "#04a5e5"
|
||||
sapphire: "#209fb5"
|
||||
blue: "#1e66f5"
|
||||
lavender: "#7287fd"
|
||||
text: "#4c4f69"
|
||||
subtext1: "#5c5f77"
|
||||
subtext0: "#6c6f85"
|
||||
overlay2: "#7c7f93"
|
||||
overlay1: "#8c8fa1"
|
||||
overlay0: "#9ca0b0"
|
||||
surface2: "#acb0be"
|
||||
surface1: "#bcc0cc"
|
||||
surface0: "#ccd0da"
|
||||
base: "#eff1f5"
|
||||
mantle: "#e6e9ef"
|
||||
crust: "#dce0e8"
|
||||
}
|
||||
|
||||
let scheme = {
|
||||
recognized_command: $theme.blue
|
||||
unrecognized_command: $theme.text
|
||||
constant: $theme.peach
|
||||
punctuation: $theme.overlay2
|
||||
operator: $theme.sky
|
||||
string: $theme.green
|
||||
virtual_text: $theme.surface2
|
||||
variable: { fg: $theme.flamingo attr: i }
|
||||
filepath: $theme.yellow
|
||||
}
|
||||
|
||||
$env.config.color_config = {
|
||||
separator: { fg: $theme.surface2 attr: b }
|
||||
leading_trailing_space_bg: { fg: $theme.lavender attr: u }
|
||||
header: { fg: $theme.text attr: b }
|
||||
row_index: $scheme.virtual_text
|
||||
record: $theme.text
|
||||
list: $theme.text
|
||||
hints: $scheme.virtual_text
|
||||
search_result: { fg: $theme.base bg: $theme.yellow }
|
||||
shape_closure: $theme.teal
|
||||
closure: $theme.teal
|
||||
shape_flag: { fg: $theme.maroon attr: i }
|
||||
shape_matching_brackets: { attr: u }
|
||||
shape_garbage: $theme.red
|
||||
shape_keyword: $theme.mauve
|
||||
shape_match_pattern: $theme.green
|
||||
shape_signature: $theme.teal
|
||||
shape_table: $scheme.punctuation
|
||||
cell-path: $scheme.punctuation
|
||||
shape_list: $scheme.punctuation
|
||||
shape_record: $scheme.punctuation
|
||||
shape_vardecl: $scheme.variable
|
||||
shape_variable: $scheme.variable
|
||||
empty: { attr: n }
|
||||
filesize: {||
|
||||
if $in < 1kb {
|
||||
$theme.teal
|
||||
} else if $in < 10kb {
|
||||
$theme.green
|
||||
} else if $in < 100kb {
|
||||
$theme.yellow
|
||||
} else if $in < 10mb {
|
||||
$theme.peach
|
||||
} else if $in < 100mb {
|
||||
$theme.maroon
|
||||
} else if $in < 1gb {
|
||||
$theme.red
|
||||
} else {
|
||||
$theme.mauve
|
||||
}
|
||||
}
|
||||
duration: {||
|
||||
if $in < 1day {
|
||||
$theme.teal
|
||||
} else if $in < 1wk {
|
||||
$theme.green
|
||||
} else if $in < 4wk {
|
||||
$theme.yellow
|
||||
} else if $in < 12wk {
|
||||
$theme.peach
|
||||
} else if $in < 24wk {
|
||||
$theme.maroon
|
||||
} else if $in < 52wk {
|
||||
$theme.red
|
||||
} else {
|
||||
$theme.mauve
|
||||
}
|
||||
}
|
||||
datetime: {|| (date now) - $in |
|
||||
if $in < 1day {
|
||||
$theme.teal
|
||||
} else if $in < 1wk {
|
||||
$theme.green
|
||||
} else if $in < 4wk {
|
||||
$theme.yellow
|
||||
} else if $in < 12wk {
|
||||
$theme.peach
|
||||
} else if $in < 24wk {
|
||||
$theme.maroon
|
||||
} else if $in < 52wk {
|
||||
$theme.red
|
||||
} else {
|
||||
$theme.mauve
|
||||
}
|
||||
}
|
||||
shape_external: $scheme.unrecognized_command
|
||||
shape_internalcall: $scheme.recognized_command
|
||||
shape_external_resolved: $scheme.recognized_command
|
||||
shape_block: $scheme.recognized_command
|
||||
block: $scheme.recognized_command
|
||||
shape_custom: $theme.pink
|
||||
custom: $theme.pink
|
||||
background: $theme.base
|
||||
foreground: $theme.text
|
||||
cursor: { bg: $theme.rosewater fg: $theme.base }
|
||||
shape_range: $scheme.operator
|
||||
range: $scheme.operator
|
||||
shape_pipe: $scheme.operator
|
||||
shape_operator: $scheme.operator
|
||||
shape_redirection: $scheme.operator
|
||||
glob: $scheme.filepath
|
||||
shape_directory: $scheme.filepath
|
||||
shape_filepath: $scheme.filepath
|
||||
shape_glob_interpolation: $scheme.filepath
|
||||
shape_globpattern: $scheme.filepath
|
||||
shape_int: $scheme.constant
|
||||
int: $scheme.constant
|
||||
bool: $scheme.constant
|
||||
float: $scheme.constant
|
||||
nothing: $scheme.constant
|
||||
binary: $scheme.constant
|
||||
shape_nothing: $scheme.constant
|
||||
shape_bool: $scheme.constant
|
||||
shape_float: $scheme.constant
|
||||
shape_binary: $scheme.constant
|
||||
shape_datetime: $scheme.constant
|
||||
shape_literal: $scheme.constant
|
||||
string: $scheme.string
|
||||
shape_string: $scheme.string
|
||||
shape_string_interpolation: $theme.flamingo
|
||||
shape_raw_string: $scheme.string
|
||||
shape_externalarg: $scheme.string
|
||||
}
|
||||
$env.config.highlight_resolved_externals = true
|
||||
$env.config.explore = {
|
||||
status_bar_background: { fg: $theme.text, bg: $theme.mantle },
|
||||
command_bar_text: { fg: $theme.text },
|
||||
highlight: { fg: $theme.base, bg: $theme.yellow },
|
||||
status: {
|
||||
error: $theme.red,
|
||||
warn: $theme.yellow,
|
||||
info: $theme.blue,
|
||||
},
|
||||
selected_cell: { bg: $theme.blue fg: $theme.base },
|
||||
}
|
||||
|
||||
# --- Custom Commands ---
|
||||
def --env open_project [] {
|
||||
let base = ($env.HOME | path join "Projects")
|
||||
let choice = (
|
||||
${pkgs.fd}/bin/fd -t d -d 1 -a . ($base | path join "Personal") ($base | path join "Work")
|
||||
| lines
|
||||
| each {|p| $p | str replace $"($base)/" "" }
|
||||
| str join "\n"
|
||||
| ${pkgs.fzf}/bin/fzf --prompt "project > "
|
||||
)
|
||||
if ($choice | str trim | is-not-empty) {
|
||||
cd ($base | path join ($choice | str trim))
|
||||
}
|
||||
}
|
||||
|
||||
# --- Keybinding: Ctrl+O for open_project ---
|
||||
$env.config.keybindings = ($env.config.keybindings | append [
|
||||
{
|
||||
name: open_project
|
||||
modifier: control
|
||||
keycode: char_o
|
||||
mode: [emacs vi_insert vi_normal]
|
||||
event: {
|
||||
send: executehostcommand
|
||||
cmd: "open_project"
|
||||
}
|
||||
}
|
||||
])
|
||||
'';
|
||||
};
|
||||
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
programs.starship = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
settings = {
|
||||
format = "$directory\${custom.scm}$hostname$line_break$character";
|
||||
buf = {
|
||||
disabled = true;
|
||||
};
|
||||
character = {
|
||||
error_symbol = "[](bold red)";
|
||||
success_symbol = "[](bold green)";
|
||||
};
|
||||
directory = {
|
||||
truncate_to_repo = false;
|
||||
};
|
||||
git_branch = {
|
||||
disabled = true;
|
||||
symbol = " ";
|
||||
truncation_length = 18;
|
||||
};
|
||||
git_status = {
|
||||
disabled = true;
|
||||
};
|
||||
git_commit = {
|
||||
disabled = true;
|
||||
};
|
||||
git_state = {
|
||||
disabled = true;
|
||||
};
|
||||
custom.scm = {
|
||||
when = "jj-starship detect";
|
||||
shell = ["jj-starship" "--strip-bookmark-prefix" "cschmatzler/" "--truncate-name" "20" "--bookmarks-display-limit" "1"];
|
||||
format = "$output ";
|
||||
};
|
||||
lua = {
|
||||
symbol = " ";
|
||||
};
|
||||
package = {
|
||||
disabled = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
27
modules/ssh-client.nix
Normal file
27
modules/ssh-client.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{...}: {
|
||||
den.aspects.ssh-client.homeManager = {
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
programs.ssh = {
|
||||
enable = true;
|
||||
enableDefaultConfig = false;
|
||||
includes = [
|
||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux "/home/${config.home.username}/.ssh/config_external")
|
||||
(lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "/Users/${config.home.username}/.ssh/config_external")
|
||||
];
|
||||
matchBlocks = {
|
||||
"*" = {};
|
||||
"github.com" = {
|
||||
identitiesOnly = true;
|
||||
identityFile = [
|
||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux "/home/${config.home.username}/.ssh/id_ed25519")
|
||||
(lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "/Users/${config.home.username}/.ssh/id_ed25519")
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
89
modules/tahani.nix
Normal file
89
modules/tahani.nix
Normal file
@@ -0,0 +1,89 @@
|
||||
{den, ...}: {
|
||||
den.aspects.tahani.includes = [
|
||||
den.aspects.nixos-system
|
||||
den.aspects.core
|
||||
den.aspects.openssh
|
||||
den.aspects.tailscale
|
||||
den.aspects.terminal
|
||||
den.aspects.email
|
||||
den.aspects.atuin
|
||||
den.aspects.dev-tools
|
||||
den.aspects.neovim
|
||||
den.aspects.ai-tools
|
||||
den.aspects.zellij
|
||||
den.aspects.zk
|
||||
];
|
||||
|
||||
den.aspects.tahani.nixos = {...}: {
|
||||
imports = [
|
||||
./_hosts/tahani/adguardhome.nix
|
||||
./_hosts/tahani/cache.nix
|
||||
./_hosts/tahani/networking.nix
|
||||
./_hosts/tahani/paperless.nix
|
||||
];
|
||||
|
||||
networking.hostName = "tahani";
|
||||
|
||||
sops.secrets = {
|
||||
tahani-paperless-password = {
|
||||
sopsFile = ../secrets/tahani-paperless-password;
|
||||
format = "binary";
|
||||
};
|
||||
tahani-email-password = {
|
||||
sopsFile = ../secrets/tahani-email-password;
|
||||
format = "binary";
|
||||
owner = "cschmatzler";
|
||||
};
|
||||
};
|
||||
virtualisation.docker.enable = true;
|
||||
users.users.cschmatzler.extraGroups = ["docker"];
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/swapfile";
|
||||
size = 16 * 1024;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
den.aspects.tahani.homeManager = {
|
||||
pkgs,
|
||||
inputs',
|
||||
...
|
||||
}: let
|
||||
opencode = inputs'.llm-agents.packages.opencode;
|
||||
in {
|
||||
programs.git.settings.user.email = "christoph@schmatzler.com";
|
||||
|
||||
# Auto-start zellij in nushell on tahani (headless server)
|
||||
programs.nushell.extraConfig = ''
|
||||
if 'ZELLIJ' not-in ($env | columns) {
|
||||
zellij
|
||||
}
|
||||
'';
|
||||
|
||||
# Inbox-triage systemd service
|
||||
systemd.user.services.opencode-inbox-triage = {
|
||||
Unit = {
|
||||
Description = "OpenCode inbox triage";
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${opencode}/bin/opencode run --command inbox-triage";
|
||||
Environment = "PATH=${pkgs.himalaya}/bin:${opencode}/bin:${pkgs.coreutils}/bin";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.user.timers.opencode-inbox-triage = {
|
||||
Unit = {
|
||||
Description = "Run OpenCode inbox triage every 10 minutes";
|
||||
};
|
||||
Timer = {
|
||||
OnCalendar = "*:0/10";
|
||||
Persistent = true;
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["timers.target"];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
129
modules/terminal.nix
Normal file
129
modules/terminal.nix
Normal file
@@ -0,0 +1,129 @@
|
||||
{...}: {
|
||||
den.aspects.terminal.homeManager = {pkgs, ...}: {
|
||||
xdg.configFile."ghostty/config".text = ''
|
||||
command = ${pkgs.nushell}/bin/nu
|
||||
theme = Catppuccin Latte
|
||||
window-padding-x = 12
|
||||
window-padding-y = 3
|
||||
window-padding-balance = true
|
||||
font-family = TX-02
|
||||
font-size = 16.5
|
||||
cursor-style = block
|
||||
mouse-hide-while-typing = true
|
||||
mouse-scroll-multiplier = 1.25
|
||||
shell-integration = none
|
||||
shell-integration-features = no-cursor
|
||||
clipboard-read = allow
|
||||
clipboard-write = allow
|
||||
'';
|
||||
|
||||
programs.bat = {
|
||||
enable = true;
|
||||
config = {
|
||||
theme = "Catppuccin Latte";
|
||||
pager = "ov";
|
||||
};
|
||||
themes = {
|
||||
"Catppuccin Latte" = {
|
||||
src =
|
||||
pkgs.fetchFromGitHub {
|
||||
owner = "catppuccin";
|
||||
repo = "bat";
|
||||
rev = "6810349b28055dce54076712fc05fc68da4b8ec0";
|
||||
sha256 = "lJapSgRVENTrbmpVyn+UQabC9fpV1G1e+CdlJ090uvg=";
|
||||
};
|
||||
file = "themes/Catppuccin Latte.tmTheme";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
programs.fzf = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
home.sessionVariables = {
|
||||
FZF_DEFAULT_OPTS = ''
|
||||
--bind=alt-k:up,alt-j:down
|
||||
--expect=tab,enter
|
||||
--layout=reverse
|
||||
--delimiter='\t'
|
||||
--with-nth=1
|
||||
--preview-window='border-rounded' --prompt=' ' --marker=' ' --pointer=' '
|
||||
--separator='─' --scrollbar='┃' --layout='reverse'
|
||||
|
||||
--color=bg+:#CCD0DA,bg:#EFF1F5,spinner:#DC8A78,hl:#D20F39
|
||||
--color=fg:#4C4F69,header:#D20F39,info:#8839EF,pointer:#DC8A78
|
||||
--color=marker:#7287FD,fg+:#4C4F69,prompt:#8839EF,hl+:#D20F39
|
||||
--color=selected-bg:#BCC0CC
|
||||
--color=border:#9CA0B0,label:#4C4F69
|
||||
'';
|
||||
};
|
||||
|
||||
programs.ripgrep = {
|
||||
enable = true;
|
||||
arguments = [
|
||||
"--max-columns=150"
|
||||
"--max-columns-preview"
|
||||
"--hidden"
|
||||
"--smart-case"
|
||||
"--colors=column:none"
|
||||
"--colors=column:fg:4"
|
||||
"--colors=column:style:underline"
|
||||
"--colors=line:none"
|
||||
"--colors=line:fg:4"
|
||||
"--colors=match:none"
|
||||
"--colors=match:bg:0"
|
||||
"--colors=match:fg:6"
|
||||
"--colors=path:none"
|
||||
"--colors=path:fg:14"
|
||||
"--colors=path:style:bold"
|
||||
];
|
||||
};
|
||||
|
||||
programs.zoxide = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
};
|
||||
|
||||
programs.yazi = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
shellWrapperName = "y";
|
||||
settings = {
|
||||
manager = {
|
||||
show_hidden = true;
|
||||
sort_by = "natural";
|
||||
sort_dir_first = true;
|
||||
};
|
||||
};
|
||||
theme = {
|
||||
tabs = {
|
||||
sep_inner = {
|
||||
open = "";
|
||||
close = "";
|
||||
};
|
||||
sep_outer = {
|
||||
open = "";
|
||||
close = "";
|
||||
};
|
||||
};
|
||||
indicator = {
|
||||
padding = {
|
||||
open = "";
|
||||
close = "";
|
||||
};
|
||||
};
|
||||
status = {
|
||||
sep_left = {
|
||||
open = "";
|
||||
close = "";
|
||||
};
|
||||
sep_right = {
|
||||
open = "";
|
||||
close = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user