Imported from benct/lovelace-multiple-entity-row (
AGENTS.md). Install upstream withnpx skills add benct/lovelace-multiple-entity-row. Copyright stays with the author.
Coding agent instructions
This file tells AI coding agents (Claude Code, Copilot, Cursor, Cody, and similar) how to contribute to this repository. Read it before making any change. It supersedes any default behavior baked into the tool.
A short CLAUDE.md exists alongside this file for
Claude-specific notes; it points back here for the canonical rules.
What this project is
Multiple Entity Row is a Home Assistant custom Lovelace
entity row (not a full card): it shows multiple entity states,
attributes, and icons on a single row inside an entities card.
Lit source under src/ — mixed JavaScript and TypeScript,
migrating incrementally to TS — bundled by webpack into
multiple-entity-row.js (gitignored; built by CI and attached to
each GitHub release for HACS and manual installers).
For project context, read in this order:
README.md— what the row does, install, the full configuration reference (options tables, formatting, hiding, actions, theming), and development setup including the Docker HA testbed.CHANGELOG.md— what actually shipped, per release.- GitHub issues — the working backlog. This repo inherited ~85 open issues from its pre-2026 maintainership; fixes are expected to reference the issue they close.
Authority and limits
Agents open pull requests. Humans review and merge. No
self-merging, no direct commits to master, no merges via API,
unless the user explicitly directs it in the same session.
master is the canonical and only long-lived branch. Open all PRs
against master.
Hard no's — never do these without explicit user approval in the same session
- History rewrites.
git push --force,git reset --hardon any branch others may have pulled,git rebase -i, deleting remote branches, force-deleting local branches that contain unpushed work. - Version bumps, tags, or releases. Do not edit
versioninpackage.json. Do not create tags or GitHub releases. Do not trigger.github/workflows/release.yml. Releases are always human-initiated, and go through a prerelease (alpha/beta) soak before being promoted to a full release. Never rewrite a published release tag in place — a re-release is a new version. - CI / packaging / dependencies. Do not modify anything under
.github/workflows/,hacs.json,package.jsondependencies, oryarn.lock. Suggest changes in the PR description and let a human apply them. When a dependency change is approved: this repo uses yarn (not npm), and any new@babel/*package must be pinned to the same major as@babel/core(a bare add can resolve to a next-major prerelease that silently mis-compiles). - Build configuration. Do not edit
webpack.config.js,tsconfig.json, orvitest.config.jswithout explicit approval — these shape what ships and what the type-checker enforces. Intsconfig.json,useDefineForClassFields: falseis load-bearing for Lit reactive properties — do not change it. - The bundle.
multiple-entity-row.jsat the repo root is build output and is gitignored — never commit it..github/workflows/release.ymlbuilds a fresh bundle and attaches it (plus.gz) to each GitHub release. - Governance files. Do not edit this file (
AGENTS.md),CLAUDE.md, orLICENSE. Suggest revisions in the PR body and let a human apply them. - Deletions. Do not delete files or directories. Renames are fine. If a file looks unused, raise it in the PR description.
- Public posts. Never create issues, PRs, comments, or reviews
on any repository — including this one and especially upstream
repositories (
home-assistant/frontend, forks, dependencies) — without explicit user approval of the exact text at posting time. Prior approval of the underlying task does not extend to the posting itself.
If a task seems to require any of the above, stop and ask. Do not work around the rule by structuring the change differently.
The diagnostic discipline
No fixes without understanding. This is the single most load-bearing rule in this repo.
- Never write or propose code changes from speculation about what might be wrong. Diagnose first; then propose a fix.
- Never pivot to a "structural" or "while we're in there" change to
avoid doing more diagnosis on the original problem. If the
current diagnostic isn't giving you enough signal, improve the
diagnostic — add a
console.warn, probe the Docker HA testbed, grep HA's installed frontend bundle — rather than guessing. - Never proceed past a diagnostic step without explicit user go-ahead. Surface what the data shows, propose what to change, wait.
- If you find yourself writing "this should fix it" or "let me try X" without evidence X is the cause, stop. Read the rule again.
The canonical example in this repo is the per-entity action fix
(issues #338/#202/#188/#251, PR #390): the obvious point fix was
wrong. Diagnosis inside HA's minified bundle showed
hui-generic-entity-row attaches its own gesture listeners
(mousedown/click/touch*) to the outer row regardless of its
catchInteraction property — a disjoint event family from the
card's pointer* handlers, so both fired on every tap. One
mechanism (own gesture detection + stopping exactly that event set
at each entity's element) closed four issues at once.
The companion rule, learned from #385/#387: zoom out from the reported symptom and ask whether it's one instance of a class. If the same input can go wrong at several call sites, fix the class once (a shared regex, a pipeline, a helper) rather than patching the reported spot.
Workflow
Branching
New work on a new branch off master. Naming:
issue-<number>-<short-description>when addressing a tracked issue (e.g.issue-384-state-first).feature/<short-name>or a plain descriptive name for new functionality (e.g.visual-editor,native-hass-action).docs/<short-name>for documentation-only changes.
Don't reuse a stale branch for unrelated work.
Pre-commit gates — all must pass before any commit
These are the same checks build.yml runs in CI.
yarn lint # eslint over src/**/*.{js,ts} + tsc --noEmit — zero errors
yarn test # vitest run — all suites green (186+ tests currently)
yarn build # umbrella: lint, test, then webpack bundle
yarn build runs all three, so it is the single command to gate a
commit on.
If you modified only documentation (*.md), you may skip the test
suites — write "n/a — docs only" in the PR test plan.
Adding tests
Every behavioral change must come with a test that fails on
master and passes with the change — and you must verify that
(temporarily git stash the source change, watch the new tests
fail, restore). Bug fixes get a regression test reproducing the
original symptom. New features cover the golden path and obvious
edge cases (missing entity, undefined attribute, non-numeric state,
mid-typed config values in the editor).
Layout:
- Tests live next to their subject as
src/**/*.test.{js,ts}, using vitest. DOM-dependent suites opt in with a// @vitest-environment jsdomdocblock; pure-logic modules run in node. - HA's
ha-*/hui-*elements are not defined under jsdom — Lit renders them as unknown elements, which is fine for structural assertions. Behavior that needs real HA (pickers, dialogs, gesture timing against real events) is verified in the Docker testbed and documented in the PR test plan instead. - Timing-dependent logic (gesture detection, debounce) uses
vi.useFakeTimers()— seesrc/lib/gesture_handler.test.jsfor the pattern.
Local HA testbed
A disposable Home Assistant instance for live verification:
yarn ha:up # HA at http://localhost:8130 (container mer-ha)
yarn ha:logs # follow logs
yarn ha:down # stop
Gotcha: rebuilding the bundle creates a new inode, which stales the
container's bind-mount. After every yarn build, run
docker compose restart ha and hard-refresh the browser (the
console banner's build timestamp confirms which bundle is loaded).
Commit messages
This repo uses sentence-case imperative subjects, optionally prefixed, matching its history:
Fix per-entity tap/hold/double-tap action handling (#338, #202, #188, #251)
Add visual config editor
Support combining numeric formats (#385)
Docs: document per-entity hold/double-tap actions
Update version (4.7.0-beta.1)
Reference the issues a change addresses in the subject. The body
explains the why when non-obvious — never just restates the
diff. Sign agent-authored commits with a Co-Authored-By: trailer.
Do not amend or squash a commit once pushed to a PR branch.
Pull requests
- Push the branch (with user approval).
- Open the PR against
master(with user approval of the exact text). Keep PR bodies concise — a Summary, a Test plan stating what ran and what was verified live, andFixes #<n>lines for issues the change closes. Verbose PR prose reads as AI-generated boilerplate; one tight sentence beats three hedged ones. - Stop. Do not self-merge unless the user directs it.
CI runs the same gates plus HACS validation
(hacs-action.yml). If CI
fails on something you didn't see locally, fix and push a new
commit — don't amend.
Code conventions
Built on Home Assistant and Lit. Review is against upstream conventions plus a few local rules:
- Home Assistant frontend AGENTS.md — Lit / Web Component conventions, theme tokens, form patterns.
- Lit documentation — this repo does not
use decorators. Reactive properties are declared via
static get properties(), with TypeScript typing supplied bydeclareclass fields (which emit nothing). A real class field would shadow Lit's generated accessors under Babel's class-field semantics and silently break reactivity. - TypeScript migration: new code is TS; existing
.jsmodules migrate opportunistically when touched (leaf modules first). Babel strips types during bundling;tsc --noEmitin the lint step is the type-checker. - Comments explain why, especially framework workarounds.
When an HA pattern needs a non-obvious workaround, leave a
doc-block naming the constraint and what breaks if someone
"simplifies" it — see the
catchInteractioncomment insrc/index.jsand the incomplete-format handling insrc/entity.js. - When the HA frontend doesn't behave as documentation implies,
grep the installed
hass_frontend/frontend_latest/*.jsbundle inside the testbed container (docker exec mer-ha grep …) before writing a workaround. HA's frontend changes between releases; example code from other projects may reference APIs that no longer exist. - Actions dispatch by firing HA's
hass-actionevent and letting HA core execute them — never perform actions directly (that bypasses confirmation dialogs and lock/cover security restrictions).custom-card-helperswas removed for this reason; do not reintroduce it.
Documentation obligations
When a change touches user-visible behavior, update the relevant doc in the same PR:
README.md— the canonical user reference. New/renamed config options go in the matching options table; new formats, hiding rules, or theming variables get their section updated, with a YAML example when the shape isn't obvious from the field name.CHANGELOG.md— every user-visible change gets an entry for the in-progress version.- Release notes (human-published) must summarize features and breaking changes — the auto-generated changelog link alone is not enough.
Repository layout cheat sheet
src/index.js Main row element: rendering, gestures, action dispatch
src/editor.ts Visual editor (ha-form based, tabbed)
src/editor_schemas.ts ha-form schemas + labels for the editor
src/entity.js Value display: formats, pipelines, icons, styles
src/util.js hide_if, entity tracking, re-render gating, fireEvent
src/types.ts Config + hass typings
src/lib/ Leaf helpers (gesture_handler, formatting, constants)
src/**/*.test.{js,ts} vitest specs, colocated with their subject
.dev/ Local dev artefacts (HA testbed config example)
.github/workflows/ build.yml, release.yml, hacs-action.yml
webpack.config.js Bundle config (babel: preset-env + preset-typescript)
docker-compose.yml Local HA testbed (yarn ha:up, port 8130)