From e91a12c68901d761812a855559331b9a7462a170 Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Thu, 17 Sep 2026 13:17:44 +0200 Subject: Add most-used dev tools, sshd/firewall, bash+liquidprompt shell modules/home/dev-tools.nix provisions the developer's evidenced most- used CLI/client tooling (gh, tmux, htop, yq-go, tree-sitter, docker, docker-compose, kubectl, awscli2). modules/home/shell.nix drops zsh/ starship/direnv in favor of bash + liquidprompt, both left entirely to the user's own dotfiles for config since home-manager can't own ~/.bashrc without conflicting with it. modules/nixos/common.nix adds sshd (key-only auth) and a firewall baseline for future NixOS hosts. --- README.md | 14 ++++++-- modules/home/default.nix | 1 + modules/home/dev-tools.nix | 14 ++++++++ modules/home/shell.nix | 14 ++------ modules/nixos/common.nix | 17 ++++++++-- .../add-developer-environment/.openspec.yaml | 2 ++ .../changes/add-developer-environment/design.md | 37 ++++++++++++++++++++++ .../changes/add-developer-environment/proposal.md | 27 ++++++++++++++++ .../specs/developer-environment/spec.md | 33 +++++++++++++++++++ .../changes/add-developer-environment/tasks.md | 29 +++++++++++++++++ 10 files changed, 170 insertions(+), 18 deletions(-) create mode 100644 modules/home/dev-tools.nix create mode 100644 openspec/changes/add-developer-environment/.openspec.yaml create mode 100644 openspec/changes/add-developer-environment/design.md create mode 100644 openspec/changes/add-developer-environment/proposal.md create mode 100644 openspec/changes/add-developer-environment/specs/developer-environment/spec.md create mode 100644 openspec/changes/add-developer-environment/tasks.md diff --git a/README.md b/README.md index 13c8be2..6ac539c 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ A single Nix flake for provisioning both NixOS hosts and non-NixOS systems (any - `flake.nix` — inputs (`nixpkgs`, `home-manager`) and outputs (`nixosConfigurations`, `homeConfigurations`, `formatter`, `devShells`) - `lib/` — `mkNixos` and `mkHome` helper functions that build `nixosConfigurations` / `homeConfigurations` entries -- `modules/nixos/common.nix` — shared NixOS-only system settings applied to every NixOS host -- `modules/home/` — the shared, cross-platform home-manager profile (shell, editor, CLI tools, dotfiles). The same modules are consumed whether activated via a NixOS host's home-manager module or standalone `home-manager switch` +- `modules/nixos/common.nix` — shared NixOS-only system settings applied to every NixOS host: flakes enabled, `tom` user (bash as the login shell), locale/timezone defaults, gc policy, sshd (key-only auth) with a firewall allowing port 22 +- `modules/home/` — the shared, cross-platform home-manager profile (shell, editor, CLI tools, dev tools, dotfiles). The same modules are consumed whether activated via a NixOS host's home-manager module or standalone `home-manager switch` - `users/tom.nix` — identity/profile file consumed by both `mkNixos` and `mkHome` - `hosts/template/` — a copy-source-only NixOS host skeleton; **never** wired into `flake.nix` outputs directly (excluded from discovery by name — see below). Copy it via `scripts/bootstrap-host.sh` (or `nix run .#bootstrap-host`) when provisioning a real machine - `scripts/bootstrap-host.sh` — scaffolds a new `hosts//` from the template; exposed as `apps..bootstrap-host` @@ -53,7 +53,15 @@ home.dotfiles.repoUrl = "https://example.com/your/dotfiles.git"; `users/tom.nix` sets this to `https://git.tomvanderlee.com/dotfiles` — the feature is active as soon as this flake is activated with `home-manager switch`. -Behavior notes: an existing `~/dotfiles` checkout is never re-cloned or modified; every non-hidden top-level directory is treated as a stow package; one package's conflict with an existing file only skips that package (a warning is printed) rather than blocking the rest. Because `~/dotfiles/git/.gitconfig` is expected to be the sole source of git configuration once stowed, this repo's own `programs.git` home-manager management has been removed — `git` itself is still installed via `modules/home/cli-tools.nix` regardless of whether `repoUrl` is set. +Behavior notes: an existing `~/dotfiles` checkout is never re-cloned or modified; every non-hidden top-level directory is treated as a stow package; one package's conflict with an existing file only skips that package (a warning is printed) rather than blocking the rest. Because `~/dotfiles/git/.gitconfig` and `~/dotfiles/bash/.bashrc` are expected to be the sole sources of git and bash configuration once stowed, this repo's own `programs.git`/`programs.bash` home-manager management has been removed — `git` itself is still installed via `modules/home/cli-tools.nix`, and `bash` ships with both macOS and NixOS regardless of whether `repoUrl` is set. + +## Developer tooling + +`modules/home/dev-tools.nix` provisions the developer's most-used CLI tools: `gh`, `tmux`, `htop`, `yq-go`, `tree-sitter`, `docker`, `docker-compose`, `kubectl`, `awscli2`. The container/cloud entries (`docker`, `docker-compose`, `kubectl`, `awscli2`) are client/CLI tools only — the actual container runtime (OrbStack/Docker Desktop on macOS) and any cloud account configuration stay outside Nix's control; these just give you a consistent CLI version to talk to whatever runtime/account is already set up. + +`terraform` was considered but deliberately left out: recent versions are unfree-licensed (HashiCorp's BSL), which would require either `nixpkgs.config.allowUnfree = true` (flake-wide, not just for terraform) or substituting `opentofu`. Neither was wanted for now. + +**Shell and prompt**: bash is the primary managed shell (matching where the real shell config already lives — `~/dotfiles/bash/.bashrc`). `modules/home/shell.nix` only provisions the `liquidprompt` package; its configuration and activation are entirely owned by `~/dotfiles/liquidprompt/`, same as git and bash. There is no Nix-managed `starship` or `direnv` — both were removed; per-project environments are left entirely to your existing pyenv/nvm/rustup setup rather than a Nix-managed alternative. ## Development diff --git a/modules/home/default.nix b/modules/home/default.nix index ec32c7f..89bad9e 100644 --- a/modules/home/default.nix +++ b/modules/home/default.nix @@ -4,5 +4,6 @@ ./editor.nix ./cli-tools.nix ./dotfiles.nix + ./dev-tools.nix ]; } diff --git a/modules/home/dev-tools.nix b/modules/home/dev-tools.nix new file mode 100644 index 0000000..f98790e --- /dev/null +++ b/modules/home/dev-tools.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: +{ + home.packages = with pkgs; [ + gh + tmux + htop + yq-go + tree-sitter + docker + docker-compose + kubectl + awscli2 + ]; +} diff --git a/modules/home/shell.nix b/modules/home/shell.nix index 406206c..7e6dc85 100644 --- a/modules/home/shell.nix +++ b/modules/home/shell.nix @@ -1,14 +1,4 @@ +{ pkgs, ... }: { - programs.zsh = { - enable = true; - autosuggestion.enable = true; - syntaxHighlighting.enable = true; - }; - - programs.starship.enable = true; - - programs.direnv = { - enable = true; - nix-direnv.enable = true; - }; + home.packages = [ pkgs.liquidprompt ]; } diff --git a/modules/nixos/common.nix b/modules/nixos/common.nix index 5427414..2e70b15 100644 --- a/modules/nixos/common.nix +++ b/modules/nixos/common.nix @@ -13,11 +13,22 @@ time.timeZone = lib.mkDefault "Etc/UTC"; i18n.defaultLocale = lib.mkDefault "en_US.UTF-8"; - programs.zsh.enable = true; - users.users.tom = { isNormalUser = true; extraGroups = [ "wheel" ]; - shell = pkgs.zsh; + shell = pkgs.bash; + }; + + services.openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + PermitRootLogin = "no"; + }; + }; + + networking.firewall = { + enable = true; + allowedTCPPorts = [ 22 ]; }; } diff --git a/openspec/changes/add-developer-environment/.openspec.yaml b/openspec/changes/add-developer-environment/.openspec.yaml new file mode 100644 index 0000000..d28e909 --- /dev/null +++ b/openspec/changes/add-developer-environment/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-17 diff --git a/openspec/changes/add-developer-environment/design.md b/openspec/changes/add-developer-environment/design.md new file mode 100644 index 0000000..33fdfb9 --- /dev/null +++ b/openspec/changes/add-developer-environment/design.md @@ -0,0 +1,37 @@ +## Context + +See proposal.md - Why. This builds on the shared `modules/home` and `modules/nixos/common.nix` layers from `add-nix-flake-bootstrap`, and follows the file-ownership precedent set by `add-dotfiles-stow-bootstrap` (home-manager's `programs.git` was removed there because `~/dotfiles/git/.gitconfig` already owns `~/.gitconfig`; the same conflict now applies to `~/.bashrc` and the prompt config). Package selection is grounded in a direct exploration of this machine (Homebrew, PATH, shell configs) and `~/dotfiles`, followed by a Q&A with the user. Nix is still not installed on this machine, so nothing here can be locally evaluated or run. + +## Goals / Non-Goals + +**Goals:** +- Bring the flake's provisioned packages in line with actually-evidenced usage on the user's machine, not a generic/assumed list. +- Keep file-ownership conflicts resolved the same way as the established precedent: dotfiles wins for any file it already manages. +- Enable a sensible, secure-by-default SSH baseline for any future NixOS host, without requiring a live host to exist yet. + +**Non-Goals:** +- Managing per-project language runtime versions (node/python/rust) via Nix — pyenv/nvm/rustup already own that; per-project pinned toolchains belong in project-level flake devShells later, a separate future change. +- Replacing Mason's role in managing neovim's LSP servers/formatters/debuggers. +- Making Docker Desktop/OrbStack or any cloud account itself Nix-managed — only client/CLI tools are in scope. +- Fixing the plaintext `HOMEBREW_GITHUB_API_TOKEN` found in `~/.bash_profile` during exploration — flagged to the user, not addressed here since it's outside any file this repo manages. + +## Decisions + +**`programs.bash` is not enabled, even though bash is now the primary shell.** Enabling it would make home-manager generate and own `~/.bashrc`, directly conflicting with `~/dotfiles/bash/.bashrc` (a real Stow package containing the user's actual PATH/alias/pyenv/nvm/rustup setup). Consistent with the `~/.gitconfig` precedent, the dotfiles-owned file wins. Consequence: `programs.starship`/`programs.direnv`'s automatic shell-hook injection has nowhere to write into for bash even if those modules were kept enabled — moot here since both are removed outright per user instruction, but worth recording as the underlying reason those integrations wouldn't have worked cleanly anyway. + +**`programs.starship` and `programs.direnv` are removed outright, not left as-is.** This was an explicit correction from the user during plan review (the first draft kept them). `liquidprompt` replaces starship as the package Nix provisions, with its actual configuration and shell activation fully owned by `~/dotfiles/liquidprompt/` — matching the same "package via Nix, config via dotfiles" split already established for git. direnv was reconsidered once (the user asked why it mattered — per-project flake devShell auto-activation) and still explicitly removed after that explanation, so this is a confirmed, informed decision, not an overlooked default. + +**`yq-go` over `yq`.** nixpkgs carries both the older Python-based `yq` (a thin `jq` wrapper for YAML) and `yq-go` (mikefarah's Go-based standalone tool) under different attribute names. The Go version is what's conventionally meant by "yq" in modern Kubernetes/Terraform-adjacent workflows, which matches this user's evidenced tooling (kubectl, terraform). Picking the wrong one would be a functionally different CLI with different syntax, not just a version difference. + +**`terraform`'s nixpkgs availability is flagged as a risk, not silently assumed.** HashiCorp's BSL license change means recent nixpkgs may require `nixpkgs.config.allowUnfree = true` for `terraform`, or may have removed it in favor of `opentofu`. This can't be verified without Nix installed locally; the task list treats it as an implementation-time check rather than asserting it will just work. + +**`services.openssh.settings.PasswordAuthentication = false` and `PermitRootLogin = "no"`.** The user already has SSH keys configured (4 hosts in `~/.ssh/config`), so key-only auth costs nothing and is the standard secure default. `networking.firewall.allowedTCPPorts = [ 22 ]` is the only firewall change that actually matters (NixOS's firewall is already enabled by default) — kept alongside an explicit `enable = true` purely as visible documentation of intent. + +**A new `modules/home/dev-tools.nix` file, separate from the existing `cli-tools.nix`.** Keeps this change's additions traceable to this specific capability, matching the repo's established one-concern-per-file module convention rather than growing the original baseline file indefinitely. + +## Risks / Trade-offs + +- **No Nix-managed per-project environment activation after removing direnv** → Mitigation: this was a deliberate, explained trade-off the user confirmed twice; pyenv/nvm/rustup remain fully functional as the existing mechanism. +- **Prompt/shell integration (liquidprompt) depends entirely on the external `~/dotfiles` repo being present and correctly stowed** → Mitigation: this is exactly what the `add-dotfiles-stow-bootstrap` change already automates; no new risk introduced here, just a new consumer of that existing mechanism. +- **`terraform` may fail to evaluate without an unfree-package allowance** → Mitigation: flagged explicitly as a task-level check; if it fails, the fallback is either adding `nixpkgs.config.allowUnfree = true` or substituting `opentofu`, decided when Nix is actually available to test. +- **No local way to verify any of this evaluates or builds, since Nix isn't installed here** → Mitigation: same as every prior change — careful manual construction and package-name review now; `nix flake check` deferred until Nix is available. This remains the real acceptance gate across all changes in this repo, not any individual task checkbox. diff --git a/openspec/changes/add-developer-environment/proposal.md b/openspec/changes/add-developer-environment/proposal.md new file mode 100644 index 0000000..24b34a5 --- /dev/null +++ b/openspec/changes/add-developer-environment/proposal.md @@ -0,0 +1,27 @@ +## Why + +The flake currently ships a minimal, generic package set. The user is a software developer whose actual machine already relies on a specific set of CLI tools (git-adjacent, container/cloud tooling) and a specific shell/prompt setup that the flake doesn't reflect yet, and has no common system services (like sshd) enabled for future NixOS hosts. This change brings the flake's declared packages/services in line with real, evidenced usage. + +## What Changes + +- Add `modules/home/dev-tools.nix`: `gh`, `tmux`, `htop`, `yq-go`, `tree-sitter`, `docker`, `docker-compose`, `kubectl`, `awscli2`, `terraform` — user-level CLI/client tools, added to `modules/home/default.nix`'s imports. Container/cloud entries are client-only; the actual runtime (OrbStack/Docker Desktop) and cloud infrastructure stay outside Nix's control. +- **BREAKING**: `modules/home/shell.nix` drops `programs.zsh` (bash is now the primary managed shell), drops `programs.starship` (replaced by `liquidprompt`, already Stow-managed via the user's dotfiles), and drops `programs.direnv`/`nix-direnv` entirely — a real removal of a feature present since the first change in this repo, per explicit user instruction rather than an addition being skipped. +- `modules/home/shell.nix` adds `pkgs.liquidprompt` as a package (its config/activation stays fully owned by the user's dotfiles repo, matching the precedent already set for git and bash). +- `modules/nixos/common.nix`: `users.users.tom.shell` changes from `pkgs.zsh` to `pkgs.bash`; the `programs.zsh.enable = true` line is removed; `services.openssh` is enabled with `PasswordAuthentication = false` and `PermitRootLogin = "no"`; `networking.firewall` is set with port 22 explicitly allowed. +- Update `README.md` to document the new packages, the CLI-only caveat for docker/kubectl/awscli/terraform, the bash-primary shell switch, and that liquidprompt's config is dotfiles-owned. + +## Capabilities + +### New Capabilities +- `developer-environment`: the flake provisions a developer's most-used CLI/client tooling via home-manager and enables common baseline system services (starting with sshd + a firewall allowance) via the shared NixOS module. + +### Modified Capabilities +(none — this doesn't change any requirement from `nix-flake-bootstrap` or `dotfiles-management`; the shell/prompt/direnv changes are implementation details of the new capability's package/service set, not a change to what those other capabilities promise) + +## Impact + +- Affected code: `modules/home/dev-tools.nix` (new), `modules/home/shell.nix`, `modules/home/default.nix`, `modules/nixos/common.nix`, `README.md`. +- No live NixOS host exists yet, so the `services.openssh`/`networking.firewall` additions only take effect once a real host is scaffolded — same situation as every prior NixOS-side change in this repo. +- Nix is still not installed on this development machine, so package-name correctness (`yq-go`, `awscli2`, `tree-sitter`, `terraform`'s licensing/availability) can only be verified by manual review here, not by actually building — same constraint as every prior change. +- User-visible: anyone relying on the previously-configured `zsh`/`starship`/`direnv` home-manager setup loses it entirely once this change lands; bash + liquidprompt (dotfiles-owned) replaces it, and there is no Nix-managed per-project environment activation mechanism (direnv) after this change. +- Not in scope: a plaintext `HOMEBREW_GITHUB_API_TOKEN` was found in `~/.bash_profile` (not Nix-managed) during exploration — flagged to the user separately, not addressed by this change. diff --git a/openspec/changes/add-developer-environment/specs/developer-environment/spec.md b/openspec/changes/add-developer-environment/specs/developer-environment/spec.md new file mode 100644 index 0000000..aff76b5 --- /dev/null +++ b/openspec/changes/add-developer-environment/specs/developer-environment/spec.md @@ -0,0 +1,33 @@ +## Purpose + +Provisions the developer's most-used CLI/client tooling through the shared home-manager profile and enables common baseline system services, such as SSH access, on every NixOS host built from this flake. + +## ADDED Requirements + +### Requirement: Developer CLI tools are provisioned via the shared home profile +The shared home-manager profile SHALL include the user's evidenced most-used CLI and client tools, available identically wherever that profile is activated (standalone or via a NixOS host). + +#### Scenario: Tooling available after activation +- **WHEN** the shared home profile is activated on any supported platform +- **THEN** the provisioned developer CLI tools are available on `PATH` without any additional manual installation step + +### Requirement: Container and cloud tools are client-only +Container and cloud-related packages provisioned by this capability SHALL provide client/CLI functionality only; they SHALL NOT attempt to provide or manage the underlying runtime or service (e.g. a container engine or cloud account). + +#### Scenario: No runtime is installed or managed +- **WHEN** a container or cloud CLI tool is provisioned by the shared home profile +- **THEN** no corresponding daemon, virtual machine, or account configuration is installed or managed by this capability — the tool simply connects to whatever runtime or account is already configured on the system + +### Requirement: Shell and prompt configuration defers to the user's personal dotfiles +Where the user's personal dotfiles repository already owns a piece of shell or prompt configuration, the shared home profile SHALL provide only the underlying package, not a competing managed configuration for that same file. + +#### Scenario: Prompt tool provisioned without managed config +- **WHEN** the shared home profile provisions a prompt tool whose configuration is already owned by the user's dotfiles repository +- **THEN** the profile installs the tool's package but does not generate or manage a competing configuration file for it + +### Requirement: SSH access is enabled by default on NixOS hosts +Every NixOS host built from this flake's shared system module SHALL have an SSH server enabled, with password authentication and root login disabled, and SHALL permit inbound SSH traffic through its firewall. + +#### Scenario: SSH reachable with key-based auth only +- **WHEN** a NixOS host is built from the shared system module +- **THEN** the SSH service is enabled, password authentication and root login are disabled, and the firewall permits inbound connections on the SSH port diff --git a/openspec/changes/add-developer-environment/tasks.md b/openspec/changes/add-developer-environment/tasks.md new file mode 100644 index 0000000..5fcd5e2 --- /dev/null +++ b/openspec/changes/add-developer-environment/tasks.md @@ -0,0 +1,29 @@ +## 1. Developer CLI tools + +- [x] 1.1 Create `modules/home/dev-tools.nix` with `home.packages = with pkgs; [ gh tmux htop yq-go tree-sitter docker docker-compose kubectl awscli2 ];` — verify by reading the package list against design.md's decisions (especially `yq-go` not `yq`) (note: `terraform` omitted per task 1.3's outcome, see below) +- [x] 1.2 Add `./dev-tools.nix` to `modules/home/default.nix`'s imports — verify by grep confirming the import is present +- [x] 1.3 Check whether `terraform` evaluates cleanly under this flake's `nixpkgs` pin, or requires `nixpkgs.config.allowUnfree = true` / substitution with `opentofu` — verify by consulting nixpkgs' current licensing status for `terraform` (blocked on local verification since Nix isn't installed; record the finding or the substitution decision in this task's notes once checked) (resolved via web research, not local build: confirmed via [NixOS/nixpkgs#253470](https://github.com/NixOS/nixpkgs/issues/253470) that terraform ≥1.6.0 is unfree/BSL-licensed and requires `nixpkgs.config.allowUnfree = true`. Presented this finding plus three options — allow unfree flake-wide, substitute opentofu, or drop terraform — to the user; they chose to drop it. `terraform` is not in the final package list.) + +## 2. Shell and prompt + +- [x] 2.1 Rewrite `modules/home/shell.nix` to remove `programs.zsh`, `programs.starship`, and `programs.direnv` entirely, replacing its contents with `home.packages = [ pkgs.liquidprompt ];` — verify by reading the file and confirming none of the three removed program blocks remain +- [x] 2.2 Confirm no other file in `modules/home/` re-enables `programs.zsh`, `programs.starship`, or `programs.direnv` — verify by grepping `modules/home/` for each (grep across all of `modules/home/` found zero matches for any of the three) + +## 3. NixOS common module: shell, sshd, firewall + +- [x] 3.1 In `modules/nixos/common.nix`, change `users.users.tom.shell` from `pkgs.zsh` to `pkgs.bash`, and remove the `programs.zsh.enable = true;` line — verify by reading the file +- [x] 3.2 Add `services.openssh = { enable = true; settings = { PasswordAuthentication = false; PermitRootLogin = "no"; }; };` — verify by reading the added block +- [x] 3.3 Add `networking.firewall = { enable = true; allowedTCPPorts = [ 22 ]; };` — verify by reading the added block + +## 4. Documentation + +- [x] 4.1 Update `README.md` to document the new `modules/home/dev-tools.nix` packages, the "CLI-only, not the runtime" caveat for docker/kubectl/awscli/terraform, the bash-primary shell switch (including the sshd/firewall additions for future NixOS hosts), and that liquidprompt's configuration is entirely dotfiles-owned — verify by reading the updated sections for consistency with the actual module changes (also updated the layout bullet for `modules/nixos/common.nix` and the dotfiles-precedent note to mention bash/.bashrc alongside git/.gitconfig, and added an explicit note on why terraform was dropped) + +## 5. Validation + +- [ ] 5.1 Run `nix flake check` and confirm the updated `modules/home` and `modules/nixos/common.nix` evaluate without error, including resolving the `terraform` question from task 1.3 (blocked — Nix is not installed on this machine; run this once Nix is available, e.g. via a real install or CI — this is the real acceptance gate, not the individual checkboxes above) +- [x] 5.2 Manually trace through each spec scenario in `specs/developer-environment/spec.md` against the implemented modules, confirming each is satisfied by inspection given #5.1 cannot run locally (all 4 scenarios traced and satisfied: `dev-tools.nix` flows through the same shared `modules/home` path consumed by both `mkNixos` and `mkHome`; grep confirms no `virtualisation`/daemon config was added anywhere; `shell.nix` is package-only for liquidprompt with no competing managed config; `services.openssh` + `networking.firewall` in `common.nix` match the SSH scenario exactly) + +--- + +**Verification note:** as with every prior change, Nix is not installed on this machine, so task 5.1 (`nix flake check`) could not be executed and remains the outstanding acceptance gate — now shared across four changes in this repo. Package-name correctness (`yq-go`, `awscli2`, `tree-sitter`, `docker`, `docker-compose`, `kubectl`, `gh`, `tmux`, `htop`, `liquidprompt`) was reviewed manually but not verified against a real nixpkgs evaluation. -- cgit v1.3