This file provides guidance to Claude Code (claude.ai/code) when working with
this repository. Read docs/agents/rules.md first — those constraints are
non-negotiable and apply to all agents.
- ALWAYS run tests locally before pushing commits — never push to any remote until local tests are green
- ALWAYS verify against actual source code/repos before making assumptions about APIs, entity names, or naming patterns
- NEVER speculate about file contents or behavior - read the file or run the code first
- Before proposing any fix, show the exact code path and evidence (logs, source) that proves the root cause — do not guess at entity names, prefixes, or discovery logic
| File | When to Read |
|---|---|
docs/agents/rules.md |
Always — hard constraints |
docs/agents/architecture.md |
Before any structural change |
docs/agents/patterns.md |
Before writing new code |
docs/agents/testing.md |
Before writing or changing tests |
docs/agents/workflow.md |
Before any commit, PR, or release |
docs/agents/skill-architecture.md |
Before working on skills, the @claude-bot pipeline, or adding an integration |
docs/agents/bess-knowledge.md |
Before answering any question about BESS behavior, savings calculations, optimizer decisions, or schedule logic |
docs/agents/memory/ |
Project-specific memory (beta workflow, release train) |
BESS Manager is a Home Assistant add-on for optimizing battery energy storage systems. It provides price-based optimization, solar integration, and a web interface for managing battery schedules and monitoring energy flows.
.venv/bin/pytest -m "not slow" # fast tests (~3s, recommended)
.venv/bin/pytest -m slow # algorithm/integration tests (~30min)
.venv/bin/pytest # run all tests
.venv/bin/black . && .venv/bin/ruff check --fix . # format and lint
./scripts/quality-check.sh # full quality gatecd frontend
npm install
npm run dev # development server
npm run build # production build
npm run lint:fix # fix TypeScript issues
npm run generate-api # regenerate API client from OpenAPI specdocker-compose up -d # backend + frontend (dev)
docker compose -f docker-compose.ci.yml up -d # E2E dev with mock-HA (fast, volume mounts)
docker compose -f docker-compose.prod-test.yml up -d --build # production image smoke test
docker-compose logs -f./package-addon.shFastAPI backend (backend/app.py) runs an hourly scheduler. The core
optimization engine (core/bess/) uses dynamic programming to generate a
24-hour battery schedule from electricity spot prices and real-time sensor
data. The schedule is sent to a Growatt inverter via the Home Assistant API.
A React SPA (frontend/) provides the management interface.
GitHub issues flow through a four-stage pipeline. Each stage is a separate
workflow file with a self-contained prompt — there is no cross-stage routing
through CLAUDE.md. All stages run on anthropics/claude-code-action@v1.
| Stage | Trigger | Workflow | Cost | What it does |
|---|---|---|---|---|
| 1. Triage | issues: opened/edited (auto) |
issue-triage.yml |
~$0.05 | Classify + label only. Gates on debug log presence. |
| 2. Analyze | @claude-bot analyze (manual) |
issue-analyze.yml |
~$0.50–2 | Delegates to bess-analyst sub-agent, posts root-cause diagnosis. No code changes. |
| 3. Fix | @claude-bot fix (manual) |
issue-fix.yml |
~$1–4 | Runs the implement-issue skill in CI mode per the Stage 2 plan, opens draft PR. |
| 4. Review | @claude-bot on a PR (manual) |
pr-review.yml |
~$0.50–2 | Reviews diff against rules and checklist. |
| 5. Integrate | @claude-bot integrate (manual) |
issue-integrate.yml |
~$2–10 | Drives a new inverter/provider request through the full experimental→stable lifecycle (feature-lifecycle), one stage per invocation. |
Why gated, not auto: Stages 2 and 3 cost real money. The user explicitly triggers each one after reading the previous stage's output.
Label flow:
opened ──► bug + needs-debug-log (Stage 1: no log)
│
└─ user adds log ──► bug + ready-for-analysis (Stage 1 re-runs on edit)
│
@claude-bot analyze
▼
analyzed (Stage 2)
│
@claude-bot fix
▼
has-fix-pr (Stage 3, draft PR open)
If Stage 2 can't reach a conclusion it applies needs-human-review instead
of analyzed.
- Only the repo owner can trigger bot commands.
- Always use
ghCLI for all GitHub operations (issues, PRs, labels). - Never push directly to
main. PRs are always opened as drafts. - The bot identity is
bess-manager-claude-bot(a custom GitHub App). The official Anthropic Claude App is suspended to avoid collisions — do not unsuspend it. - Stage 2 must invoke the
bess-analystsub-agent. Skipping that step is the failure mode the previous design suffered from.
- Always release through a PR so CI runs — never push directly to a branch bypassing CI
- Always check the current published version before tagging (e.g., check GitHub releases) to avoid version collisions
- Confirm the target remote and branch BEFORE pushing releases (beta vs main, origin vs beta remote)
- Run the full test suite locally before any release tag or beta push
- Never skip the CHANGELOG.md update or version bump
beta/mainonly ever advances by fast-forward fromorigin/main— never commit directly to the beta repo. If a fix is needed on the currently-published stable version while main has moved on, use the hotfix procedure (short-livedrelease-X.Ybranch cherry-picking from main), never a direct beta commit.CHANGELOG.mdis authored once, onorigin/main, under## [Unreleased]. Beta and stable releases both consume that section (copy for beta, rename for stable) — never hand-write a beta-specific or duplicate changelog entry.
- Do NOT modify, remove, or 'clean up' items the user hasn't asked you to change
- When doing cleanup, list what you plan to change and confirm before editing
- Do not revert intentional linter changes or simplifications without explicit instruction
- After editing, list every file and symbol changed so the user can confirm nothing unrelated was touched
- Never add speculative fallbacks, defensive error handling, or "robustness" improvements beyond what was asked
- Never add a parameter, flag, default-fallback, second construction site, or extra trigger whose only job is to route around an ordering/timing/dependency problem — fix that problem directly (reorder, or reuse/expose what already exists); see
docs/agents/rules.mdDebugging Protocol step 8
The user pays per token. A long Opus session that re-reads a large context after every multi-minute wait is what runs up the bill — not the work itself.
- Default to Sonnet (set in
.claude/settings.json). Use Opus only for a genuinely hard reasoning step, say so, and drop back. Don't run routine coordination, iteration, CI-watching, or file edits on Opus. - Never spawn Opus subagents, and avoid agents for long-running watches entirely; if delegation is truly needed, use a cheap model.
- Don't hold one big session across many long CI/test waits. The prompt
cache expires after ~5 min, so each long wait forces a full uncached re-read
of the entire context. Prefer
/clearbetween unrelated chunks, or let the session sit idle rather than re-engaging every few minutes. - Don't re-dump large files or logs into context.
- Treat
implement-issueStep 8 (verify, podman-compose/mock-HA E2E) as a session boundary. Kick it off, then either let the session sit idle until it completes or/clearand resume fresh once it's done — don't stay engaged re-touching the diagnosis/TDD context through the wait.
Both layouts are first-class — either way the worktree is a normal git checkout,
so per-agent inspect / test / run (./deploy.sh, pytest, the app) works the
same. Choose by how you want to reach an agent's work:
- Sibling folders (e.g.
../bess-manager-feature/) — open cleanly in their own VS Code window; this is the go-to when you actively inspect code and run scripts per agent. They work with Agent View too: start the background session inside the sibling (it's a linked git worktree, so Claude won't relocate it). Caveat: a sibling only appears in unscopedclaude agents(or--cwd ~/GitHub), not in the project-scopedclaude agents --cwd <repo>view. - Native
.claude/worktrees/(claude agents/--worktree/EnterWorktree) — auto-created for background sessions and visible in the project-scoped Agent View. Still a real checkout:code <repo>/.claude/worktrees/<name>orcdinto it to run tests/scripts.
Find any session's worktree path by peeking/attaching it in Agent View, or via
claude agents --json (the cwd field).
- Sensors: battery SOC/power, solar production, grid import/export, pricing
- Device: Growatt inverter (TOU schedule control)
- Add-on config:
bess_manager/config.yaml(version field, HA schema) - Pricing sources: Nordpool and Octopus Energy
pyproject.toml— Black, Ruff, mypy settingsfrontend/package.json— React/TypeScript dependenciesdocker-compose.yml— development environmentbess_manager/config.yaml— HA add-on schema and current version (single source of truth)