Fast orientation for AI agents working on this repo. Humans should start with CONTRIBUTING.md, which documents the architecture, conventions, test layout, and release process in full. This file complements that with quick-navigation pointers for agents starting cold; defer to CONTRIBUTING.md when in doubt.
Sections 2, 3, and 5 mirror the canonical text in pymyhondaplus/AGENTS.md — update there first, then propagate.
The unofficial PyQt6 desktop app for My Honda+ / Honda Connect Europe vehicles, distributed as PyInstaller bundles for Linux, macOS, and Windows. It consumes the pymyhondaplus library for all upstream API work and presents vehicle status, trips, geofence, and remote controls in a native GUI.
Mirrored from pymyhondaplus/AGENTS.md — update there first.
Refer to the upstream service as "the My Honda+ API" or "the Honda Connect Europe API" in code, comments, commit messages, PR descriptions, log strings, and test names — matching the framing used in the public READMEs. See CONTRIBUTING.md for the full style guide.
Mirrored from pymyhondaplus/AGENTS.md — update there first.
pymyhondaplus (Python library + CLI) is consumed by:
myhondaplus-homeassistant— Home Assistant integration, pinned==X.Y.Z(HA convention).myhondaplus-desktop— PyQt6 desktop app, pinned>=X.Y.Z.
Ownership boundaries — each concern lives in exactly one repo:
- Library owns: API request/response shapes, auth flow,
EVStatusparsing, enum normalization (charge_status,home_away,climate_temp, geofence states),VehicleCapabilitiesresolution, capability raw-API-key labels, geofence state labels, geofence error messages, library-side translations (CLI strings + thet_lib()keys consumers bridge to). - HA integration owns: entity descriptors, coordinators, config flow, services,
strings.json+translations/*.json, error-handling conventions for HA. - Desktop owns: view layer (MainWindow / widgets), controller, workers, dashboard / trip / geofence / vehicle UI, desktop
translations/*.json, PyInstaller bundling.
If a task feels like it crosses boundaries, default to "the library owns the API/parsing/canonical enums; consumers are presentation" and confirm with the maintainer before editing across repos.
Triage rule. When investigating an issue or fix in a consumer repo (HA or desktop), use the ownership boundaries above. If the symptom is in library-owned territory (API request/response shape, parsing, enum normalization, capability resolution, library-owned translation strings), the issue or PR should be opened in pymyhondaplus — even if it was first surfaced through a consumer. When in doubt, a short Python repro against the library is the fastest way to confirm.
Editing this file. Sections ## 2. Naming, ## 3. The three-repo ecosystem, and ## 5. Cross-repo workflows are mirrored verbatim from pymyhondaplus/AGENTS.md into the two consumer repos. When changing any of those sections, use identical wording across the three repos (no per-repo customization — keep it generic enough to apply everywhere) and run python scripts/check_agents_mirror.py from the HA or desktop repo before pushing. The same check enforces parity in CI and will block consumer PRs if the wording drifts.
| Task | Files |
|---|---|
| New dashboard tile | src/myhondaplus_desktop/widgets/dashboard.py; translation key in src/myhondaplus_desktop/translations/en.json (then propagate to the other 12 locales); access EVStatus as a dict (.get(), [], in) |
| New modal / dialog | new widget under src/myhondaplus_desktop/widgets/; wire it in main_screen_controller.py; translation keys; tests in tests/ |
| New worker for an API call | src/myhondaplus_desktop/workers.py (QThread subclass with finished / error signals); the controller connects them; UI mutation can be optimistic |
| New translated string | src/myhondaplus_desktop/translations/en.json (canonical) + 12 other locales; tests/test_i18n.py enforces coverage. Library-owned strings (geofence states, capability labels, geofence errors) come via i18n.t_lib(key) — do not duplicate them in desktop JSONs. |
| Bump library dep | pyproject.toml (pymyhondaplus>=X.Y.Z) and README.md must mirror the same pin; scripts/check_release_version.py enforces tag = __version__ |
| Capabilities modal change | src/myhondaplus_desktop/widgets/vehicle.py; relies on the library's caps.active_api_keys() / not_supported_api_keys() |
| Geofence widget change | src/myhondaplus_desktop/widgets/geofence.py; requires running the app, not just pytest — the tile map is a QGraphicsView rendering surface |
| New language | copy translations/en.json → translations/<lang>.json, translate the values only, keep keys + {placeholders} unchanged; the language appears automatically in the selector |
Mirrored from pymyhondaplus/AGENTS.md — update there first.
If the user's session has more than one of pymyhondaplus, myhondaplus-homeassistant, or myhondaplus-desktop loaded as a working directory, treat that as a signal that they're managing parallel work and rely on you for cross-product memory. Don't wait to be asked. When making any non-trivial change in one repo:
- Search the other loaded repo(s) for the same code path. A bug fix in HA's
sensor.pymay have a sibling inmyhondaplus-desktop/widgets/dashboard.py. A library API change has at least two consumers. - Treat design contracts as cross-cutting: capability gating (read vs command), error-handling shape, naming, polling cadences, defaults, fuel-type semantics. When one repo settles a contract, the others should align unless the divergence is intentional and stated.
- For bug fixes, audit the bug class, not just the specific symptom. If you fixed "X disappears when capability=False" in one repo, ask whether the equivalent code in the other repos has the same gate.
- For library changes, surface the consumer impact inline. Don't say "library updated, what next" — say "library changed Y; HA needs Z, desktop needs W; here are the patches."
Surface findings as part of your response, in a compact format:
- "Same pattern in
<repo>at<file:line>— proposing same fix here." - "
<repo>diverges intentionally because<reason>— keeping divergent." - "
<repo>doesn't have this code path — N/A."
The CLI in pymyhondaplus is often N/A for UI-gating questions (it's a thin pass-through that defers to Honda's API), but check before assuming.
Whenever you change behavior, contract, or storage shape that already-installed users rely on, first map what existing entries / cached state / config files look like (read past migrations, config-flow code, storage handlers) and decide whether they will break, degrade, or stay fine under the new code.
If they break or degrade, look for a silent self-heal path before writing release notes that ask users to delete and re-add or reauth. Examples: re-run discovery against API metadata on next startup; backfill missing fields from data the integration already has access to; drop stale flags that no longer reflect reality; reconcile via existing migration / _fetch_*_metadata paths.
Only escalate to "user must take action" when the code genuinely cannot fix the entry from data already available. Each forced manual step is a chance for users to drop off and an entry in the issue tracker; each silent self-heal is invisible. Bias toward fixing things automatically.
- Docs before tag. Audit narrative docs (
README.md, plusUSAGE.md/CHANGELOG.mdwhere present) against the diff before bumping the version. A new feature / service / option / flag needs documenting; a removed or renamed one must not still be described. Updating code-adjacent files (services.yaml,strings.json, locale JSON,manifest.json) is necessary but not sufficient — the README is a separate surface, and fixing it in a follow-up after the release has shipped is not OK. - Release-notes format. Every release uses the same shape: header
## X.Y.Z (YYYY-MM-DD), then only the sections that apply, in order:### Breaking,### Added,### Fixed,### Changed,### Dependencies(the last for pin changes, e.g. "Requires pymyhondaplus >= X.Y.Z"). Bullets are one line each, no em or en dashes, no mea-culpa or "should have shipped earlier" framing, no paragraph-length context.pymyhondapluskeeps these entries inCHANGELOG.mdand the GitHub release body is that section copied verbatim; HA and desktop have no changelog, so write the GitHub release body directly in the same format. - Release order is library first, then consumers. Bump
pymyhondaplus, tag, GitHub-release; then update HAmanifest.jsonrequirements(==X.Y.Z) and/or desktoppyproject.toml+README.md(>=X.Y.Z), then release each consumer. - Pin update rule: HA pins exact (Home Assistant convention); desktop pins minimum.
- Translation-drift PRs may span library + HA. When a string converges in wording, move the pair from
_KNOWN_DRIFTtoENFORCED_OVERLAPSin the same PR (HA test:tests/test_translation_drift.py). - Cross-repo change checklist: land library-owned API/parsing/auth/translation behavior in
pymyhondaplusfirst; update HA's exact pin and desktop's minimum pin only after a library release; keep consumer enum options, entity descriptors, and UI copy aligned with canonical library behavior.
EVStatuslooks like a dataclass but treat it as a dict (get/[]/in). Widgets that trygetattron it will surprise themselves.- Capability access is via
__getattr__; unknown names raiseAttributeError. Usecaps.active_api_keys()to enumerate. - Do not introduce abstractions or registries. The pattern is module-level helpers (
_card,_row); follow it. - Translation keys use dot notation (
"dashboard.battery"). Look aten.jsonbefore inventing new keys. - PyQt6, not PyQt5 — signals are
pyqtSignal. - Library-owned strings (geofence states, capability labels, geofence errors) must come through
t_lib(), not be re-typed into desktop JSONs.
- Setup:
pip install -e ".[dev]" - Use a sibling library checkout while testing integration changes:
.venv/bin/pip install -e /path/to/pymyhondaplus --no-deps - Tests:
python -m pytest - Lint:
ruff check src/ tests/ - Release version check:
python scripts/check_release_version.py X.Y.Z
Test (pytest on Python 3.11/3.12/3.13 matrix), Lint (ruff). Tag is the bare version (e.g. 2.7.0, not v2.7.0); __version__ in src/myhondaplus_desktop/__init__.py must match the tag (scripts/check_release_version.py enforces this). PyInstaller bundle workflows (build-linux.yml, build-macos.yml, build-windows.yml) run on release publish.
See CONTRIBUTING.md for the full folder tree, view/controller/worker pattern, library-coupling concern table, geofence widget notes, code style, and release process. The same guidance that applies to human contributors applies to agents.