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
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 setbuildHomeAssistantComponentuses. Do not use top-levelpkgs.python3Packages. - Manifest requirements are enforced at build time by
manifestCheckPhaseand again by HA at runtime. Every requirement must resolve to an installed dist satisfying its specifier. Exact pins (verbatim fromalexa_media_playerv5.15.7manifest.json):alexapy==1.29.25dictor>=0.1.12,<0.2wrapt>=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.7sha256-1rcZVSX1xA1Lc4qSu39MOitVEciZFhoPQy2y5+PpoAI=alexapy fetchFromGitLab v1.29.25sha256-P/hvgqZVaBJF5dbmHrDjQMC+pwV3EEhKyFIS5KmhgD4=dictor fetchPypi (sdist) 0.1.12sha256-bbSDda4eU9ye2EToWzj04/v79qTmC+yjd1Fa0URTuRs=
File Structure
Single file touched: modules/environments/home-assistant/default.nix.
- Its
letblock gainshaPython,dictor, andalexapybindings. - Its
services.home-assistant.customComponentslist gains a second entry (alexa_media) alongside the existingsourdoughentry.
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(theletblock, currently lines 9-12; and thecustomComponentslist, currently lines 29-41)
Interfaces:
-
Consumes:
pkgs.home-assistant.python3Packages(HA interpreter set),pkgs.buildHomeAssistantComponent,pkgs.fetchFromGitHub,pkgs.fetchFromGitLab. -
Produces: a second
customComponentsentry withdomain = "alexa_media". No other module consumes theseletbindings. -
Step 1: Add the supporting derivations to the
letblock
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_mediaentry tocustomComponents
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':
- Settings → Devices & Services → Add Integration → Alexa Media Player.
- Sign in with the Amazon account; complete any 2FA / app-password prompt in the UI flow.
- 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,alexapydefined in Step 1 and referenced by those exact names in Step 2; domainalexa_mediaconsistent throughout; hashes identical across plan, spec, and the verified build.