This document provides practical guidance for Claude Code (Claude-powered coding assistant) when working with the HSEM repository.
Note: This is a quick reference guide. For comprehensive rules, constraints, and standards,
please refer to AGENTS.md.
- Read AGENTS.md first — Understand the project's constraints, security rules, and Home Assistant compliance requirements
- Verify Python 3.14 — Ensure you're using Python 3.14 (see
.python-version) - Create a worktree and feature branch — Use format:
feat/<issue-number>-<description>, in its own worktree under/workspaces/worktrees(see Shared checkout below) - Make focused changes — Solve one issue at a time
- Run quality checks —
./scripts/quality.sh lint,./scripts/quality.sh typing,./scripts/quality.sh quality,./scripts/quality.sh test - Submit PR for review — Do not merge without explicit permission
-
One Issue Per Session
- Focus on a single GitHub issue at a time
- Do not combine multiple issues in one session
- Reference issue number in commits and PR description
-
Preserve Existing Behavior
- Do not refactor unrelated code
- Do not modify planner logic or safety features unless specifically requested
- Do not reformat entire directories unless required for tooling setup
- Keep changes focused and minimal
-
Code Quality
- Run
./scripts/quality.sh lintbefore committing (ruff format + ruff check + prettier) - Run
./scripts/quality.sh typingafter lint (mypy type checking) - Run
./scripts/quality.sh qualityafter typing (pyright + vulture) - Run
./scripts/quality.sh testto run tests with coverage before opening a PR - Include type hints for all public functions
- Write docstrings for all public modules, classes, and functions
- Write tests for new functionality
- Follow PEP 8 and PEP 257
- See
CODE_QUALITY_STANDARDS.mdfor full standards and conventions
- Run
CRITICAL: Check for Code Duplication FIRST
When implementing a utility or helper function:
- Search first: Check if similar functionality exists in
utils/misc.pyor other utils modules - If used 2+ times: The function MUST live in utils, NOT in multiple modules
- Never duplicate: Create the function in the appropriate utils module, then import it everywhere
- DRY Principle: Do not repeat utility logic across multiple files
Example of WRONG approach (creates duplicates):
- Create
_convert_months_to_int()inflows/months.py - Create
_convert_month_list_to_int()inworking_mode_sensor.py - ❌ Result: Two functions doing the same thing in different places
Example of CORRECT approach:
- Create
convert_months_to_int()inutils/misc.py(centralized, public) - Import it in
flows/months.py:from custom_components.hsem.utils.misc import convert_months_to_int - Import it in
working_mode_sensor.py:from custom_components.hsem.utils.misc import convert_months_to_int - ✅ Result: Single source of truth, easier to maintain
Common mistake to avoid:
- Don't create private versions (
_function_name) in multiple modules thinking they're isolated - Private functions should still be centralized if used in 2+ places
Never use == or != to compare floating-point values.
- In production code: use an epsilon guard instead of exact equality.
abs(x) > 1e-9instead ofx != 0abs(a - b) < 1e-9instead ofa == b
- In tests: always use
pytest.approx()for any assertion involvingfloat.assert result == pytest.approx(0.0)✅assert result == 0.0❌
- Integer-valued comparisons (
== 0on a sum ofintweights) are fine; only float literals and float-typed variables are subject to this rule.
Before touching any planner code, read docs/planner-spec.md — it is the single source
of truth for planner semantics.
Rules:
- Read the spec first — applies to engine, cost function, SoC simulation, candidate generation, slot population, and safety gates.
- Verify consistency — every change must satisfy the invariants listed under Invariants for tests in the spec (energy balance, SoC bounds, cost identity, terminal-SoC accounting, safety gate behaviour).
- Update the spec when a change intentionally alters planner semantics. Spec and implementation must never diverge silently.
- Add or update tests covering the affected invariants for every planner change.
- Definition of Done for planner work: spec updated (if needed) + invariant tests passing.
Quick checklist before opening a planner PR:
-
docs/planner-spec.mdread and understood - Energy balance holds for every slot
- SoC stays within configured bounds
-
winner.cost == final_output.cost(no post-selection mutation) - Terminal SoC affects cost (emptying the battery is not free)
- No-action baseline includes normal PV/battery self-consumption
- Read-only / degraded / dry-run gates block hardware writes
- Spec updated if semantics changed
- Tests added or updated
HSEM ships English, Danish, German, and Spanish
(custom_components/hsem/translations/{en,da,de,es}.json). en.json is the
source of truth. Any new or changed user-facing string (entity name,
config/options flow label, selector option, error, service) must be added to
all four files in the same PR — activate the hsem-translation-sync skill
and run ./scripts/quality.sh translations (or python3 scripts/validate_translations.py
directly) before opening the PR; it must report 0 missing/stale/placeholder-mismatch
keys. This check is also enforced by CI (lint-and-test.yml) and by ./scripts/quality.sh all.
The main checkout at /workspaces/hsem is shared between agent sessions (Claude Code,
Zed agents, Copilot) running in the same devcontainer. An agent must never switch, pull,
rebase or reset it: doing so moves the branch and files under another session mid-task
(issue #1122). Every task gets its own git worktree under /workspaces/worktrees, created
by the hsem-pre-flight skill, and all edits, quality gates, commits and pushes run from
there. Don't use git stash: the stash stack is shared by every worktree.
# 1. Ensure you're on Python 3.14
python --version # Should show 3.14.x
# 2. Create a worktree with a feature branch (never switch /workspaces/hsem itself)
git -C /workspaces/hsem fetch origin
git -C /workspaces/hsem worktree add /workspaces/worktrees/hsem-<issue-number> \
-b feat/<issue-number>-<description> origin/main
cd /workspaces/worktrees/hsem-<issue-number>
# 3. Make your changes and write tests
# 4. Format and lint (REQUIRED)
./scripts/quality.sh lint
# 5. Type check (REQUIRED)
./scripts/quality.sh typing
# 6. Quality checks (REQUIRED)
./scripts/quality.sh quality
# 7. Run tests (REQUIRED)
./scripts/quality.sh test
# 8. Verify changes
git status
# 9. Commit with conventional commit format
git commit -m "feat(scope): description - Fixes #<ISSUE_NUMBER>"
# 10. Push the branch (local git over SSH)
git push origin feat/<issue-number>-<description>
# 11. Create the PR with the `gh` CLI, passing the body via --body-file:
# gh pr create --base main --title "feat(scope): ..." --body-file pr.mdGitHub operations: use the
ghCLI. It is installed and authenticated in the devcontainer (/usr/bin/gh). GitHub MCP tools are not present in every session, so never assume they exist — check, and fall back togh. Preferrtk gh ...to cut output tokens. Pass PR/issue bodies via--body-file, never as an inline shell argument. Localgit(add/commit/checkout/push) is unchanged.
Whenever you push additional commits to a branch that already has an open PR:
- Update the PR title if the scope or description has changed.
- Update the PR body to reflect all changes made so far — new files, behaviour changes, additional tests, and any newly satisfied acceptance criteria.
- Tick off completed items in any checklist inside the PR description.
- Never leave the PR description stale after follow-up commits.
- Use
gh pr edit <n> --title ... --body-file <path>(or theupdate_pull_requestMCP tool when the session has it). Always pass the body via--body-fileso multiline markdown survives intact — never inline it as a single shell argument.
Ensure your changes follow Home Assistant integration standards:
- Architecture: Use config entries, setup/unload flows, and platform forwarding patterns
- Entities: Implement entity model conventions (state, availability, device info, unique IDs, naming)
- Data Updates: Use
DataUpdateCoordinatorfor periodic polling when needed - Configuration: Maintain
config_flow, diagnostics, and translations as needed - Quality: Target at least Silver quality, aim for Gold
- Tests: Add tests for setup flows, coordinator behavior, and entity state handling
See AGENTS.md → Home Assistant Compliance section for detailed requirements.
REQUIRED before every commit:
# Step 1: Format and lint (MUST be done)
./scripts/quality.sh lint
# Step 2: Type checking
./scripts/quality.sh typing
# Step 3: Quality checks (pyright + vulture)
./scripts/quality.sh quality
# Step 4: Run tests with coverage
./scripts/quality.sh test
# Step 5: Translations — if any user-facing string changed
./scripts/quality.sh translations
# Step 6: Verify no unintended changes
git status
# Step 7: Use pre-commit hooks (optional, but recommended)
pre-commit run --all-filesIf any of these checks fail, fix them before committing. Do not submit a PR with formatting or linting issues.
Always include type hints and docstrings:
def calculate_consumption_prediction(
historical_data: list[float],
weights: dict[str, float],
) -> float:
"""
Calculate predicted consumption based on historical data and weights.
Args:
historical_data: List of historical consumption values in kWh.
weights: Dictionary mapping time windows to weight factors.
Returns:
Predicted consumption value in kWh.
Raises:
ValueError: If historical_data is empty or weights contain invalid values.
"""
if not historical_data:
raise ValueError("historical_data cannot be empty")
return sum(val * weights.get(str(i), 0) for i, val in enumerate(historical_data))- Target: Python 3.14 (required - see
.python-version) - Syntax: Use modern Python 3.14+ syntax (union operator
|, walrus operator, etc.) - Style: Follow PEP 8 and PEP 257 (enforced by ruff)
- Formatting: Use f-strings for string formatting
- Paths: Prefer
pathliboveros.path - Type Annotations: Use explicit type hints in function signatures
- Code Quality: Write code that passes ruff checks without warnings
Write tests for all new functions and features:
# Run all tests
pytest tests/
# Run with coverage
pytest tests/ --cov=hsem --cov-report=html
# Run specific test file
pytest tests/test_module.py
# Run specific test
pytest tests/test_module.py::test_function_nameTest guidelines:
- Use pytest as the test framework
- Place tests in the
tests/directory following the same structure as the source - Use meaningful test names that describe what is being tested
- Test edge cases: missing data, unavailable entities, invalid values
- Test async and concurrent operations for race conditions
✅ Focus on the specific issue assigned ✅ Use Python 3.14 and pass all ruff quality checks ✅ Write
clear, maintainable code with type hints ✅ Include tests for new features and behavior changes ✅
Format and lint code before every commit (ruff format . then ruff check . --fix) ✅ Ask for
clarification if requirements are unclear ✅ Document complex logic with comments ✅ Keep commits
atomic and focused ✅ Reference AGENTS.md for comprehensive rules
❌ Submitting a PR without running ./scripts/quality.sh all first ❌ Ignoring lint warnings or errors
❌ Using Python versions other than 3.14 ❌ Refactoring unrelated code ❌ Changing planner or safety
features without explicit issue ❌ Reformatting code outside your changes ❌ Adding new dependencies
without justification ❌ Changing logging levels or sensitive output ❌ Modifying configuration
without issue requirement ❌ Committing secrets, API keys, or credentials ❌ Merging PRs without
explicit permission
- Never commit credentials, API keys, or tokens
- Never log sensitive information in plaintext
- Load secrets from environment variables or secure storage
- Document required environment variables
- See
AGENTS.md→ Security Constraints for details
- General rules and constraints: See
AGENTS.md - Home Assistant requirements: See
AGENTS.md→ Home Assistant Compliance - Python version issues: Ensure you're using Python 3.14 from
.python-version - Lint/format errors: Run
./scripts/quality.sh lintto auto-fix most issues - Unclear requirements: Stop and ask for clarification before implementing
- Design decisions: Refer to
docs/directory for architecture notes - Code quality: When in doubt, run the full pre-commit checklist
Always prefix commands with rtk. If RTK has a dedicated filter, it uses it. If not, it passes through unchanged. This means RTK is always safe to use.
Important: Even in command chains with &&, use rtk:
# ❌ Wrong
git add . && git commit -m "msg" && git push
# ✅ Correct
rtk git add . && rtk git commit -m "msg" && rtk git pushrtk cargo build # Cargo build output
rtk cargo check # Cargo check output
rtk cargo clippy # Clippy warnings grouped by file (80%)
rtk tsc # TypeScript errors grouped by file/code (83%)
rtk lint # ESLint/Biome violations grouped (84%)
rtk prettier --check # Files needing format only (70%)
rtk next build # Next.js build with route metrics (87%)rtk cargo test # Cargo test failures only (90%)
rtk go test # Go test failures only (90%)
rtk jest # Jest failures only (99.5%)
rtk vitest # Vitest failures only (99.5%)
rtk playwright test # Playwright failures only (94%)
rtk pytest # Python test failures only (90%)
rtk rake test # Ruby test failures only (90%)
rtk rspec # RSpec test failures only (60%)
rtk test <cmd> # Generic test wrapper - failures onlyrtk git status # Compact status
rtk git log # Compact log (works with all git flags)
rtk git diff # Compact diff (80%)
rtk git show # Compact show (80%)
rtk git add # Ultra-compact confirmations (59%)
rtk git commit # Ultra-compact confirmations (59%)
rtk git push # Ultra-compact confirmations
rtk git pull # Ultra-compact confirmations
rtk git branch # Compact branch list
rtk git fetch # Compact fetch
rtk git stash # Compact stash
rtk git worktree # Compact worktreeNote: Git passthrough works for ALL subcommands, even those not explicitly listed.
rtk gh pr view <num> # Compact PR view (87%)
rtk gh pr checks # Compact PR checks (79%)
rtk gh run list # Compact workflow runs (82%)
rtk gh issue list # Compact issue list (80%)
rtk gh api # Compact API responses (26%)rtk pnpm list # Compact dependency tree (70%)
rtk pnpm outdated # Compact outdated packages (80%)
rtk pnpm install # Compact install output (90%)
rtk npm run <script> # Compact npm script output
rtk npx <cmd> # Compact npx command output
rtk prisma # Prisma without ASCII art (88%)
rtk uv run <cmd> # Compact uv project command outputrtk ls <path> # Tree format, compact (65%)
rtk read <file> # Code reading with filtering (60%)
rtk grep <pattern> # Search grouped by file (75%). Format flags (-c, -l, -L, -o, -Z) run raw.
rtk find <pattern> # Find grouped by directory (70%)rtk err <cmd> # Filter errors only from any command
rtk log <file> # Deduplicated logs with counts
rtk json <file> # JSON structure without values
rtk deps # Dependency overview
rtk env # Environment variables compact
rtk summary <cmd> # Smart summary of command output
rtk diff # Ultra-compact diffsrtk docker ps # Compact container list
rtk docker images # Compact image list
rtk docker logs <c> # Deduplicated logs
rtk kubectl get # Compact resource list
rtk kubectl logs # Deduplicated pod logsrtk curl <url> # Compact HTTP responses (70%)
rtk wget <url> # Compact download output (65%)rtk gain # View token savings statistics
rtk gain --history # View command history with savings
rtk discover # Analyze Claude Code sessions for missed RTK usage
rtk proxy <cmd> # Run command without filtering (for debugging)
rtk init # Add RTK instructions to CLAUDE.md
rtk init --global # Add RTK to ~/.claude/CLAUDE.md| Category | Commands | Typical Savings |
|---|---|---|
| Tests | vitest, playwright, cargo test | 90-99% |
| Build | next, tsc, lint, prettier | 70-87% |
| Git | status, log, diff, add, commit | 59-80% |
| GitHub | gh pr, gh run, gh issue | 26-87% |
| Package Managers | pnpm, npm, npx | 70-90% |
| Files | ls, read, grep, find | 60-75% |
| Infrastructure | docker, kubectl | 85% |
| Network | curl, wget | 65-70% |
Overall average: 60-90% token reduction on common development operations.