Files
nixos/docs/superpowers/plans/2026-07-29-alexa-media-player.md
finn.markwitz bf36f935e8 docs(home-assistant): implementation plan for alexa_media_player
Task-by-task plan with verified hashes and build-check commands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RCn8YgGQMGpauatdeTdQYf
2026-07-29 17:07:05 +02:00

9.4 KiB

Alexa Media Player Integration — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Package the alexa_media_player HACS component declaratively on jupiter's Home Assistant so HA can drive the household Echo devices (TTS/announce, media, sensors).

Architecture: Add one buildHomeAssistantComponent entry to services.home-assistant.customComponents (same pattern as the existing ha-sourdough). The component has real Python deps, so the module's let block also defines two supporting derivations built against HA's own interpreter: a new dictor package and an alexapy version bump. No HACS runtime, no YAML config — the integration is added through the HA UI after the rebuild.

Tech Stack: NixOS, pkgs.buildHomeAssistantComponent, buildPythonPackage, fetchFromGitHub/fetchFromGitLab/fetchPypi.

Global Constraints

  • Target machine: jupiter only. All edits live in modules/environments/home-assistant/default.nix.
  • Python dep derivations MUST build against Home Assistant's interpreter set — pkgs.home-assistant.python3Packages — the same set buildHomeAssistantComponent uses. Do not use top-level pkgs.python3Packages.
  • Manifest requirements are enforced at build time by manifestCheckPhase and again by HA at runtime. Every requirement must resolve to an installed dist satisfying its specifier. Exact pins (verbatim from alexa_media_player v5.15.7 manifest.json):
    • alexapy==1.29.25
    • dictor>=0.1.12,<0.2
    • wrapt>=1.14.0 (nixpkgs 1.17.2 — already satisfied)
    • packaging>=20.3 (nixpkgs 26.1 — already satisfied)
  • Pinned artifacts (all three hashes verified to build during planning):
    Artifact Fetcher Ref / version Hash
    alexa_media_player fetchFromGitHub v5.15.7 sha256-1rcZVSX1xA1Lc4qSu39MOitVEciZFhoPQy2y5+PpoAI=
    alexapy fetchFromGitLab v1.29.25 sha256-P/hvgqZVaBJF5dbmHrDjQMC+pwV3EEhKyFIS5KmhgD4=
    dictor fetchPypi (sdist) 0.1.12 sha256-bbSDda4eU9ye2EToWzj04/v79qTmC+yjd1Fa0URTuRs=

File Structure

Single file touched: modules/environments/home-assistant/default.nix.

  • Its let block gains haPython, dictor, and alexapy bindings.
  • Its services.home-assistant.customComponents list gains a second entry (alexa_media) alongside the existing sourdough entry.

No new files. The two supporting derivations are small and specific to this component, so they live inline in the module's let block next to their only consumer (files that change together live together).


Task 1: Package alexa_media_player with its Python dependencies

Files:

  • Modify: modules/environments/home-assistant/default.nix (the let block, currently lines 9-12; and the customComponents list, currently lines 29-41)

Interfaces:

  • Consumes: pkgs.home-assistant.python3Packages (HA interpreter set), pkgs.buildHomeAssistantComponent, pkgs.fetchFromGitHub, pkgs.fetchFromGitLab.

  • Produces: a second customComponents entry with domain = "alexa_media". No other module consumes these let bindings.

  • Step 1: Add the supporting derivations to the let block

Edit the let block so it reads exactly:

let
  cfg = config.my.profiles.home-assistant;
  hostName = config.networking.hostName;

  # Python deps for the alexa_media_player custom component (Task: Alexa).
  # Built against Home Assistant's own interpreter — the same set
  # buildHomeAssistantComponent uses — so HA's build-time and runtime
  # manifest-requirement checks are satisfied.
  haPython = pkgs.home-assistant.python3Packages;

  # dictor is not in nixpkgs; alexa_media_player needs dictor>=0.1.12,<0.2.
  # Pure-Python, no runtime deps, legacy setup.py.
  dictor = haPython.buildPythonPackage {
    pname = "dictor";
    version = "0.1.12";
    format = "setuptools";
    src = haPython.fetchPypi {
      pname = "dictor";
      version = "0.1.12";
      hash = "sha256-bbSDda4eU9ye2EToWzj04/v79qTmC+yjd1Fa0URTuRs=";
    };
    build-system = [ haPython.setuptools ];
    doCheck = false;
    pythonImportsCheck = [ "dictor" ];
  };

  # nixpkgs ships alexapy 1.29.22; the manifest pins ==1.29.25. Patch bump.
  # nixpkgs fetches alexapy from GitLab (keatontaylor/alexapy), tag v<version>.
  alexapy = haPython.alexapy.overridePythonAttrs (old: {
    version = "1.29.25";
    src = pkgs.fetchFromGitLab {
      owner = "keatontaylor";
      repo = "alexapy";
      tag = "v1.29.25";
      hash = "sha256-P/hvgqZVaBJF5dbmHrDjQMC+pwV3EEhKyFIS5KmhgD4=";
    };
  });
in
  • Step 2: Add the alexa_media entry to customComponents

In services.home-assistant.customComponents, immediately after the closing ) of the existing sourdough entry (current line 40) and before the list's closing ] (current line 41), add:

        (pkgs.buildHomeAssistantComponent {
          owner = "Alandtse";
          domain = "alexa_media";
          version = "5.15.7";
          src = pkgs.fetchFromGitHub {
            owner = "Alandtse";
            repo = "alexa_media_player";
            rev = "v5.15.7";
            hash = "sha256-1rcZVSX1xA1Lc4qSu39MOitVEciZFhoPQy2y5+PpoAI=";
          };
          # Every manifest requirement must be importable at a satisfying
          # version or manifestCheckPhase fails the build.
          dependencies = [
            alexapy
            dictor
            haPython.wrapt
            haPython.packaging
          ];
        })
  • Step 3: Format the file

Run: nixfmt-rfc-style modules/environments/home-assistant/default.nix Expected: exits 0, no diff surprises (re-read the file if unsure).

  • Step 4: Build the component in isolation first (fast feedback)

This is the real test: it runs manifestCheckPhase, which fails loudly if any of the four requirements is unmet. It was verified to succeed during planning.

Run:

nix build --impure --no-link --print-out-paths --expr '
  let
    pkgs = (builtins.getFlake (toString ./.)).nixosConfigurations.jupiter.pkgs;
    py = pkgs.home-assistant.python3Packages;
    dictor = py.buildPythonPackage {
      pname = "dictor"; version = "0.1.12"; format = "setuptools";
      src = py.fetchPypi { pname = "dictor"; version = "0.1.12"; hash = "sha256-bbSDda4eU9ye2EToWzj04/v79qTmC+yjd1Fa0URTuRs="; };
      build-system = [ py.setuptools ]; doCheck = false; pythonImportsCheck = [ "dictor" ];
    };
    alexapy = py.alexapy.overridePythonAttrs (old: {
      version = "1.29.25";
      src = pkgs.fetchFromGitLab { owner = "keatontaylor"; repo = "alexapy"; tag = "v1.29.25"; hash = "sha256-P/hvgqZVaBJF5dbmHrDjQMC+pwV3EEhKyFIS5KmhgD4="; };
    });
  in pkgs.buildHomeAssistantComponent {
    owner = "Alandtse"; domain = "alexa_media"; version = "5.15.7";
    src = pkgs.fetchFromGitHub { owner = "Alandtse"; repo = "alexa_media_player"; rev = "v5.15.7"; hash = "sha256-1rcZVSX1xA1Lc4qSu39MOitVEciZFhoPQy2y5+PpoAI="; };
    dependencies = [ alexapy dictor py.wrapt py.packaging ];
  }'

Expected: prints a /nix/store/...-Alandtse-alexa_media-5.15.7 path, exit 0. If it fails with <pkg><specifier> not satisfied by version ..., a dependency version drifted — re-check the manifest pin against the provided dep.

  • Step 5: Build the whole jupiter system (integration gate)

Run: nix build '.#nixosConfigurations.jupiter.config.system.build.toplevel' Expected: builds to completion, exit 0. This confirms the module edits evaluate and the component is wired into HA's package.

  • Step 6: Commit
git add modules/environments/home-assistant/default.nix
git commit -m "$(cat <<'EOF'
feat(home-assistant): add alexa_media_player custom component

Package the Alexa Media Player HACS component declaratively (v5.15.7),
so HA can drive the Echo devices (TTS/announce, media, sensors). Needs
dictor 0.1.12 (absent from nixpkgs) and an alexapy 1.29.22 -> 1.29.25
bump to satisfy the manifest's exact requirement pins; both build
against HA's interpreter. Config-flow based: add via the HA UI and sign
in with the Amazon account after rebuild.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
EOF
)"

Post-implementation (manual, by the user — not an automatable step)

After sudo nixos-rebuild switch --flake '.#jupiter':

  1. Settings → Devices & Services → Add Integration → Alexa Media Player.
  2. Sign in with the Amazon account; complete any 2FA / app-password prompt in the UI flow.
  3. Confirm media_player entities and sensors appear; test a TTS/announce service call to an Echo.

Self-Review

  • Spec coverage: goal (alexa_media_player packaging) → Task 1; alexapy bump → Step 1; dictor packaging → Step 1; component entry → Step 2; wrapt/packaging already-satisfied → included as deps in Step 2; build-time manifest check → Steps 4-5; runtime config-flow → Post-implementation. Deferred Alexa→HA scope: intentionally absent. No gaps.
  • Placeholder scan: none — every step has concrete code/commands and the verified hashes.
  • Type/name consistency: haPython, dictor, alexapy defined in Step 1 and referenced by those exact names in Step 2; domain alexa_media consistent throughout; hashes identical across plan, spec, and the verified build.