From c3f882fae8f4c1ae84deafc310357846e8b66ad1 Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Mon, 21 Sep 2026 15:57:04 +0200 Subject: Add Slack, Discord, Spotify, teams-for-linux, and Claude Code Provisions these via home-manager, scoping unfree-package access to exactly these packages and skipping any that aren't available for the current system/architecture (e.g. aarch64-linux lacks Discord/Spotify builds) instead of failing evaluation. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01BBSd4VBfoKHjE1HR3P8kmn --- .../.openspec.yaml | 2 ++ .../design.md | 42 ++++++++++++++++++++++ .../proposal.md | 26 ++++++++++++++ .../specs/desktop-applications/spec.md | 26 ++++++++++++++ .../tasks.md | 20 +++++++++++ 5 files changed, 116 insertions(+) create mode 100644 openspec/changes/add-claude-code-slack-spotify-discord-teams/.openspec.yaml create mode 100644 openspec/changes/add-claude-code-slack-spotify-discord-teams/design.md create mode 100644 openspec/changes/add-claude-code-slack-spotify-discord-teams/proposal.md create mode 100644 openspec/changes/add-claude-code-slack-spotify-discord-teams/specs/desktop-applications/spec.md create mode 100644 openspec/changes/add-claude-code-slack-spotify-discord-teams/tasks.md (limited to 'openspec/changes') diff --git a/openspec/changes/add-claude-code-slack-spotify-discord-teams/.openspec.yaml b/openspec/changes/add-claude-code-slack-spotify-discord-teams/.openspec.yaml new file mode 100644 index 0000000..563fab5 --- /dev/null +++ b/openspec/changes/add-claude-code-slack-spotify-discord-teams/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-21 diff --git a/openspec/changes/add-claude-code-slack-spotify-discord-teams/design.md b/openspec/changes/add-claude-code-slack-spotify-discord-teams/design.md new file mode 100644 index 0000000..d2cfd05 --- /dev/null +++ b/openspec/changes/add-claude-code-slack-spotify-discord-teams/design.md @@ -0,0 +1,42 @@ +## Context + +See proposal.md - Why/What Changes for motivation. Two constraints shape this design: + +- `lib/mkHome.nix` builds standalone `homeConfigurations` by passing a pre-instantiated `pkgs = inputs.nixpkgs.legacyPackages.${system}` directly into `homeManagerConfiguration`. Because `pkgs` is supplied rather than left for home-manager to construct, the home-manager `nixpkgs.config` module option has no effect there - unfree gating has to happen when `pkgs` itself is built. +- `lib/mkNixos.nix` builds NixOS hosts with `home-manager.useGlobalPkgs = true`, so the home-manager profile shares whatever `pkgs` the NixOS module system constructs - there, a `nixpkgs.config` module option set anywhere in the module list does take effect. +- No package in this repo has ever needed to vary by architecture before; `modules/home/dotfiles.nix` conditions on `isDarwin`/`isLinux` for stow directories, not on `pkgs.stdenv.hostPlatform` for a Nix package. + +## Goals / Non-Goals + +**Goals:** +- One shared mechanism for "this package isn't supported on this system, skip it" that works for both current architectures (x86_64-linux, aarch64-darwin) and any future host without per-package manual bookkeeping. +- Unfree package access scoped to exactly the packages this change needs. + +**Non-Goals:** +- Adding nix-darwin or Homebrew support for nicer macOS app delivery (tracked separately in the README). +- Standing up a real `aarch64-linux` host to test the skip behavior on - none exists in this repo today; the mechanism is verified by evaluating the existing configs and reasoning about `meta.platforms`, not by building on that architecture. + +## Decisions + +**Use `lib.meta.availableOn pkgs.stdenv.hostPlatform pkg`, filtered over a candidate list, instead of hand-written per-package platform conditionals.** +`lib.meta.availableOn` is nixpkgs' own check against a derivation's `meta.platforms`/`meta.badPlatforms`, so it stays correct automatically if nixpkgs adds or drops platform support for one of these packages later. The alternative - hardcoding e.g. `lib.optional (system == "x86_64-linux") pkgs.discord` - would silently go stale and requires knowing each package's exact supported-platform list up front. + +**Scope unfree access via `nixpkgs.config.allowUnfreePredicate` backed by a single `lib/unfree-allowlist.nix`, not blanket `allowUnfree = true`.** +Chosen explicitly over the blanket option: it names exactly `slack`, `discord`, `spotify`, `claude-code` rather than permitting any future unfree package by default, matching this repo's existing preference for minimal, explicit scoping (see `dotfiles.nix`'s platform-exclude list and its accompanying comment). The list is a single file imported by both `lib/mkHome.nix` and `lib/mkNixos.nix` so the two builders can't drift out of sync. + +**`lib/mkHome.nix` switches from `inputs.nixpkgs.legacyPackages.${system}` to `import inputs.nixpkgs { inherit system; config.allowUnfreePredicate = ...; }`.** +This is the minimal change that makes unfree gating actually take effect for standalone home-manager, per the Context constraint above. Alternative considered: leave `pkgs` as `legacyPackages` and instead set `nixpkgs.config` as a home-manager module option - rejected because home-manager ignores that option once `pkgs` is passed in directly (it would silently do nothing, which is worse than an explicit fix here). + +**`lib/mkNixos.nix` sets the same predicate via a small inline module prepended to its `modules` list**, rather than editing `modules/nixos/common.nix`. Keeping it in the builder (alongside where `mkHome.nix` does the equivalent) keeps both unfree-gating call sites next to each other and next to the shared allowlist, instead of splitting the concern across `lib/` and `modules/nixos/`. + +**`claude-code` is added to `modules/home/dev-tools.nix`, not the new `desktop-applications` capability.** +It's a CLI tool, and `developer-environment`'s existing requirement already generically covers "the shared profile SHALL include the user's evidenced most-used CLI and client tools" - no new requirement text is needed, just a package addition guarded by the same `lib.meta.availableOn` check for consistency. + +**`teams-for-linux` gets an explicit `pkgs.stdenv.hostPlatform.isLinux` guard in addition to the `availableOn` filter**, rather than relying on `availableOn` alone. +Belt-and-suspenders: the product is Linux-only by design regardless of what nixpkgs' `meta.platforms` happens to list for it, so the explicit guard keeps behavior correct even if that metadata is ever loose or changes. + +## Risks / Trade-offs + +- **No local Nix to verify eval/build** → Mitigation: tasks.md verification steps target a machine with Nix installed; this is a pre-existing gap in this environment, not new to this change. +- **`lib.meta.availableOn` trusts nixpkgs' `meta.platforms` accuracy** → Mitigation: cross-checked against current nixpkgs metadata (Slack/Discord/Spotify unfree and missing `aarch64-linux`; `claude-code` unfree and available on all four systems; `teams-for-linux` free/GPL and broadly available) before writing this design; if nixpkgs metadata is ever wrong for a package, the filter fails closed (excludes it) rather than failing the build. +- **macOS apps come from nixpkgs' darwin builds, not Homebrew casks** → Mitigation: explicitly out of scope (see Non-Goals); flagged in proposal.md's Impact section as a known limitation. diff --git a/openspec/changes/add-claude-code-slack-spotify-discord-teams/proposal.md b/openspec/changes/add-claude-code-slack-spotify-discord-teams/proposal.md new file mode 100644 index 0000000..4bb3e10 --- /dev/null +++ b/openspec/changes/add-claude-code-slack-spotify-discord-teams/proposal.md @@ -0,0 +1,26 @@ +## Why + +The shared home-manager profile currently provisions only CLI/client tooling; there is no way to get everyday desktop GUI applications (chat, communication, music) or the Claude Code CLI onto a machine built from this flake without installing them by hand outside of Nix. The user wants Claude Code, Slack, Spotify, Discord, and [teams-for-linux](https://ismaelmartinez.github.io/teams-for-linux/) declared in the config, with the understanding that several of these are unfree-licensed and some (Discord, Spotify, Slack) do not have `aarch64-linux` builds in nixpkgs today — an unsupported package must be skipped rather than break evaluation on that architecture. + +## What Changes + +- Add a new `modules/home/desktop-apps.nix` home-manager module provisioning Slack, Discord, Spotify, and teams-for-linux, filtered through `lib.meta.availableOn` so any package unsupported on the current system/architecture is silently omitted instead of failing the build; teams-for-linux is additionally restricted to Linux only. +- Add `claude-code` to the existing `modules/home/dev-tools.nix` CLI tool list, guarded the same way. +- Introduce a shared `lib/unfree-allowlist.nix` naming exactly the unfree packages this change adds (`slack`, `discord`, `spotify`, `claude-code`; teams-for-linux is GPL-licensed and needs no allowance), and wire `nixpkgs.config.allowUnfreePredicate` from it in both `lib/mkHome.nix` (standalone home-manager) and `lib/mkNixos.nix` (NixOS + home-manager), since neither currently permits any unfree package. +- **BREAKING**: none — additive only; existing configurations continue to evaluate and activate unchanged aside from gaining new optional packages. + +## Capabilities + +### New Capabilities +- `desktop-applications`: provisioning of user-facing desktop GUI applications (Slack, Discord, Spotify, teams-for-linux) through the shared home-manager profile, including the rule that a package unsupported on the current system is skipped rather than causing failure. + +### Modified Capabilities +(none — adding `claude-code` to the shared CLI toolset is already covered by `developer-environment`'s existing requirement that the shared profile "SHALL include the user's evidenced most-used CLI and client tools"; no requirement text changes.) + +## Impact + +- **Affected code**: `lib/mkHome.nix`, `lib/mkNixos.nix` (new `lib/unfree-allowlist.nix` dependency), `modules/home/default.nix` (new import), `modules/home/desktop-apps.nix` (new file), `modules/home/dev-tools.nix`. +- **Dependencies**: relies on nixpkgs' unfree-licensed `slack`, `discord`, `spotify`, `claude-code` packages and the free `teams-for-linux` package; no new flake inputs. +- **Platforms**: applies to both `homeConfigurations` (`tom@linux` = x86_64-linux, `tom@darwin` = aarch64-darwin) and any future NixOS host built via `lib/mkNixos.nix`. On `aarch64-darwin`, `teams-for-linux` is intentionally excluded (Linux-only product); on any future `aarch64-linux` host, Discord/Spotify/Slack are expected to be excluded automatically since nixpkgs does not currently build them for that platform. +- **Known limitation, out of scope**: this repo has no nix-darwin/Homebrew integration yet (tracked separately in the README as a follow-up), so on macOS these apps are provisioned from nixpkgs' darwin builds only, not Homebrew casks. +- **Verification gap**: no local Nix installation in this environment, so `nix flake check` / `home-manager build` cannot be run here; verification must happen on a machine with Nix installed (see tasks.md). diff --git a/openspec/changes/add-claude-code-slack-spotify-discord-teams/specs/desktop-applications/spec.md b/openspec/changes/add-claude-code-slack-spotify-discord-teams/specs/desktop-applications/spec.md new file mode 100644 index 0000000..ae1e6f3 --- /dev/null +++ b/openspec/changes/add-claude-code-slack-spotify-discord-teams/specs/desktop-applications/spec.md @@ -0,0 +1,26 @@ +## Purpose + +Provisions everyday desktop GUI applications (chat, communication, and music clients) through the shared home-manager profile, mirroring how `developer-environment` provisions CLI tooling but for user-facing graphical applications instead. + +## ADDED Requirements + +### Requirement: Desktop GUI applications are provisioned via the shared home profile +The shared home-manager profile SHALL include Slack, Discord, Spotify, and teams-for-linux as GUI application packages, available wherever that profile is activated and the underlying package supports the current system. + +#### Scenario: GUI app available after activation +- **WHEN** the shared home profile is activated on a system for which a given desktop application's package is supported +- **THEN** that application is available without any additional manual installation step + +### Requirement: Packages unsupported on the current system are skipped, not failed +A desktop application package that has no supported build for the currently evaluated system SHALL be omitted from the provisioned package set rather than causing profile evaluation or activation to fail. + +#### Scenario: Unsupported package excluded without failure +- **WHEN** the shared home profile is evaluated on a system for which one of the desktop application packages (e.g. an `aarch64-linux` target lacking a Discord, Spotify, or Slack build) has no supported build +- **THEN** that package is excluded from the provisioned set and the rest of the profile evaluates and activates successfully + +### Requirement: teams-for-linux is Linux-only +teams-for-linux SHALL be provisioned only on Linux systems, consistent with its scope as a Linux-only Microsoft Teams client. + +#### Scenario: Excluded on a non-Linux system +- **WHEN** the shared home profile is activated on a non-Linux system +- **THEN** teams-for-linux is not included in the provisioned package set diff --git a/openspec/changes/add-claude-code-slack-spotify-discord-teams/tasks.md b/openspec/changes/add-claude-code-slack-spotify-discord-teams/tasks.md new file mode 100644 index 0000000..82aa94f --- /dev/null +++ b/openspec/changes/add-claude-code-slack-spotify-discord-teams/tasks.md @@ -0,0 +1,20 @@ +## 1. Unfree package gating + +- [ ] 1.1 Create `lib/unfree-allowlist.nix` containing `[ "slack" "discord" "spotify" "claude-code" ]` and verify it evaluates with `nix eval --file lib/unfree-allowlist.nix` (or `nix-instantiate --eval`) +- [ ] 1.2 Update `lib/mkHome.nix` to construct `pkgs` via `import inputs.nixpkgs { inherit system; config.allowUnfreePredicate = pkg: builtins.elem (inputs.nixpkgs.lib.getName pkg) (import ./unfree-allowlist.nix); }` instead of `inputs.nixpkgs.legacyPackages.${system}`, and verify `nix flake show` still lists both `homeConfigurations` without error +- [ ] 1.3 Update `lib/mkNixos.nix` to prepend a module setting the same `nixpkgs.config.allowUnfreePredicate` (reusing `lib/unfree-allowlist.nix`), and verify `nix flake check` (or `nix eval .#nixosConfigurations` for any configured host) still evaluates without an "unfree package" error + +## 2. Desktop applications module + +- [ ] 2.1 Create `modules/home/desktop-apps.nix` with `home.packages = builtins.filter (lib.meta.availableOn pkgs.stdenv.hostPlatform) ([ pkgs.slack pkgs.discord pkgs.spotify ] ++ lib.optional pkgs.stdenv.hostPlatform.isLinux pkgs.teams-for-linux);` and verify the file evaluates standalone via `nix-instantiate --eval --strict -E 'import ./modules/home/desktop-apps.nix { pkgs = import {}; lib = (import {}).lib; }'` or equivalent +- [ ] 2.2 Add `./desktop-apps.nix` to the `imports` list in `modules/home/default.nix` and verify `home-manager build --flake .#tom@linux` and `home-manager build --flake .#tom@darwin` both evaluate successfully (run on a machine with Nix installed - not available in this environment) +- [ ] 2.3 Verify on the build output (or via `nix eval`) that `tom@darwin`'s closure excludes `teams-for-linux` while `tom@linux`'s includes it, confirming the Linux-only guard works as intended + +## 3. Claude Code CLI + +- [ ] 3.1 Add `pkgs.claude-code` to `modules/home/dev-tools.nix`'s `home.packages`, guarded with `lib.optional (lib.meta.availableOn pkgs.stdenv.hostPlatform pkgs.claude-code) pkgs.claude-code`, and verify `claude-code` appears on `PATH` after `home-manager build --flake .#tom@linux` (or `.#tom@darwin`) followed by activation on a machine with Nix installed + +## 4. End-to-end verification + +- [ ] 4.1 Run `nix flake check` on a machine with Nix installed and confirm no evaluation errors for either `homeConfigurations` entry +- [ ] 4.2 Run `statix check` and `deadnix` (already used by this repo's `devShells.default`) over the changed files and fix any findings -- cgit v1.3