# Nix Config

This is my personal NixOS configuration using Nix flakes. The README is mainly generated by AI for future myself because I'm forgetful.

## Architecture

This configuration uses a modular architecture built on top of `flake-parts`:

### Directory Structure

- **`/flake.nix`**: Entry point for the flake, defines `nixosConfigurations`, `darwinConfigurations`, and `deploy.nodes`.
- **`/unit`**: Modular configuration units that can be composed together.
  - `/unit/default.nix`: Collects and exports all units and presets.
  - `/unit/home/*`: Home-manager units for user-space configuration.
  - `/unit/sys/*`: System-level units (NixOS or nix-darwin).
  - `/unit/preset`: Predefined collections of units (bare, core, local, server, gui).
- **`/system`**: OS-specific system configurations.
  - `/system/shared`: Shared configuration across all systems.
  - `/system/darwin`: macOS-specific configuration.
  - `/system/nixos-desktop`: NixOS desktop configuration.
  - `/system/nixos-server`: NixOS server configuration.
- **`/machine`**: Machine-specific configurations.
  - Desktop machines: Atlas, Everest
  - Darwin machines: Fuji, Marcy
  - Servers: Colden, LUX, LAX, EWR, HEL, HND, YUL
  - Special: ProxmoxLXC (template for LXC containers), Minimum (minimal config)
- **`/secrets`**: Encrypted secrets managed with `git-crypt`.
- **`/static`**: Static files like GPG and SSH public keys.

## Key Concepts

### Units

Units (`./unit/{home/*,sys/*}`) are modules that can be imported directly. They are organized into:
- **Home units**: User-space configuration
- **System units**: OS-level configuration
- **Presets**: Pre-composed collections of units for different use cases:
  - `bare`: Minimal CLI environment
  - `core`: Essential command-line tools
  - `local`: Full local development environment, shared across local NixOS and Darwin
  - `server`: Server-optimized configuration
  - `gui`: Desktop GUI applications, some are Linux specific

### Systems

Systems (`./system/*`) import presets and system units, then add OS-specific but machine-agnostic configurations. They define the baseline for each operating system type (Darwin, NixOS Desktop, NixOS Server).

### Machines

Machines (`./machine/*`) import their corresponding system configuration and add machine-specific settings like:
- Hardware configuration
- Hostname and networking
- User accounts
- Machine-specific services

### Build Functions

The flake defines specialized builders:
- `mkDarwinSystem`: Builds macOS systems using `nix-darwin`
- `mkLinuxDesktop`: Builds NixOS desktop systems with GUI support
- `mkLinuxServer`: Builds NixOS server systems
- `mkLinuxService`: Builds specialized service containers for Proxmox LXC

## External Inputs

- **nixpkgs**: Tracks `nixpkgs-unstable`
- **home-manager**: User environment management
- **nix-darwin**: macOS support
- **flakes**: Personal package overlay
- **rust-overlay**: Rust toolchain management
- **disko**: Declarative disk partitioning
- **deploy-rs**: Remote deployment tool
- **lanzaboote**: Secure boot support
- **zen-browser**: Privacy-focused browser
- **nixos-generators**: Generate various system images (e.g., Proxmox LXC)
- **vscode-server**: Remote VS Code support

## Usage

### Local Activation

Just run `rb` anywhere.

Enter the development shell to make the pinned Infisical CLI available:

```bash
nix develop
```

Before rebuilding, `rb` fetches secrets with the Infisical CLI. Authenticate the
CLI and link this directory to a project with `infisical init` (or provide the
usual Infisical machine-identity environment variables). Dotted secret names
form the Nix attribute path: for example, `github.oauth_token` becomes
`secrets.github.oauth_token`. Infisical values override matching values from
`secrets/secrets.nix` for that evaluation only.

The equivalent flake command is:

```bash
nix run .#activate
```

Both commands stream the root-folder export into a root-owned `0600` file inside
a root-only temporary directory under `/var/run`. They invoke the rebuild with
impure evaluation and remove the file and directory afterward.

Import a JSON object into Infisical with:

```bash
printf '%s\n' '{"github":{"oauth_token":"secret"}}' \
  | ./scripts/import-infisical-secrets.sh --env prod
```

Nested objects become dotted root-level secrets, so this example writes the
Infisical secret `github.oauth_token`. Activation expands it back into a nested
Nix attribute set. Every Infisical value is stored as JSON text, including quoted
JSON strings, so activation can restore its exact type with `fromjson`. All
values are staged in permission-restricted temporary files and sent in one
`infisical secrets set` call using `name=@file` arguments.

### Remote Deployment

Remote servers are deployed using `deploy-rs`:

```bash
deploy .#<machine-name>
```

### Building Images

Generate a Proxmox LXC template:

```bash
nix build .#proxmox-lxc
```

## Notes

- Units (`./unit/{home/*,sys/*}`) are "bare" in the sense that they can output to flake directly, where Machines (`./machine/*`) are not because they are wrapped by system declarations, e.g., `nixpkgs.lib.nixosSystem`/`nix-darwin.lib.darwinSystem`.
- Units are imported in `flake.nix` as `unit.{home,sys}`, in which home units are further collected into `unit.preset.{bare,core,local,server,gui}` to form five "profiles"; all of which are passed down to systems and machines config with `specialArgs` and `home-manager.extraSpecialArgs`.
- Systems (`./system`) imports aforementioned "profiles" and `sys` units, then add machine-agnostic but os-dependent configurations.
- Machines (`./machine`) imports corresponding systems and `sys` units, then add machine-specific configurations.
- `deploy-rs` is used to push local changes to remote machines (configs live under `.#deploy.nodes`).
- Secrets are managed with `git-crypt` and keys are encoded with `base64`. Decode with `echo $KEY | base64 -d`.

### Invariants

- This config **MUST** live under `$HOME/.nix-config`
