This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
ChoreBoard-HA-Card is a Home Assistant custom card for managing and tracking household chores. It's built as a custom Lovelace card using TypeScript, Lit web components, and Rollup for bundling.
IMPORTANT: This card requires the ChoreBoard Home Assistant Integration to be installed and configured. The card displays data from ChoreBoard sensor entities created by that integration.
The card works exclusively with the ChoreBoard integration, which creates aggregate "My Chores" sensors for each user:
Supported Sensor Naming Patterns:
sensor.choreboard_my_chores_{username}(e.g.,sensor.choreboard_my_chores_ash)sensor.{username}_my_chores(e.g.,sensor.ash_my_chores)sensor.choreboard_my_immediate_chores_{username}(excludes chores marked "complete later")sensor.{username}_my_immediate_chores
The card's visual editor auto-detects all sensor patterns above.
- Each sensor contains a list of chores in its
attributes.choresarray - Sensor state: Number of chores for that user
Each My Chores sensor has these attributes:
{
"username": "ash",
"count": 5,
"chores": [
{
"id": 123, // Chore instance ID (number)
"name": "Wash Dishes",
"due_date": "2025-12-20",
"points": "10.00", // STRING (not number) - integration returns as string
"is_overdue": false,
"status": "assigned" // "assigned", "pending", "completed", etc.
},
// ... more chores
]
}Important Data Type Notes:
points: Integration returns as string (e.g., "2.50", "10.00"), card parses to number for displaystatus: Can be "assigned", "pending", "completed" - card treats non-"completed" as active/completable
Users must install and configure the ChoreBoard integration before using this card:
- Install integration via HACS or manually
- Configure with API key and URL in Settings → Devices & Services
- Integration creates My Chores sensors for each user automatically
- Card reads chore lists from sensor attributes
- Card calls integration services to mark chores complete
Simple completion without user selection:
await this.hass.callService('choreboard', 'complete_chore', {
instance_id: chore.id, // Not entity_id!
});Claim Service:
await this.hass.callService('choreboard', 'claim_chore', {
chore_id: chore.id,
assign_to_user_id: userId, // User ID who is claiming
});Complete Service (with user selection):
await this.hass.callService('choreboard', 'mark_complete', {
chore_id: chore.id,
completed_by_user_id: userId, // User ID who completed
helpers: [helperId1, helperId2], // Optional: User IDs who helped
});- Integration fetches chore data from ChoreBoard API
- Creates/updates My Chores sensors in Home Assistant (one per user)
- Card reads sensor's
attributes.choresarray fromthis.hass.states[entity] - Card filters chores based on config (show_completed, show_overdue_only)
- User clicks "Complete" button → Card calls
choreboard.complete_chorewithinstance_id - Integration syncs changes back to ChoreBoard API
- Sensor updates automatically, card re-renders
- Integration fetches pool chores from ChoreBoard API
- Creates
sensor.pool_chores(or similar pattern) with chores in pool - Card detects pool chores by
status === "pool"or sensor pattern - Card displays "Claim" and "Complete" buttons
- Claim Action:
- User clicks "Claim" → Dialog shows available users
- User selects who to assign → Calls
claim_choreservice - Chore moves from pool to assigned
- Complete Action:
- User clicks "Complete" → Dialog shows user selection + helper selection
- User selects completer (required) and helpers (optional)
- Calls
mark_completeservice with user IDs - Points distributed according to selections
- Integration syncs to API, sensors update
Setup and Commands:
npm install # Install dependencies
npm run watch # Dev server with hot reload (http://localhost:4000)
npm run start:hass # Launch test Home Assistant (http://localhost:8123)
npm run format # Format code with Prettier
npm run build # Standard build (development)
npm run build:prod # Production build (minified)Workflow:
- Run
npm install(first time only) - Start dev server:
npm run watch - Optional: Start test HA instance:
npm run start:hass - Edit TypeScript in
src/→ changes auto-compile - Refresh HA dashboard to see updates
- Test configurations in
.hass-dev/views/choreboard-card-preview.yaml
- Lit 3.x: Lightweight web component library for building the card and editor
- TypeScript: Provides type safety and enhanced developer experience
- Rollup: Bundles all source files into a single
dist/choreboard-ha-card.jsfile - custom-card-helpers: Helper library providing Home Assistant types and utilities
src/
├── main.ts - Entry point; registers custom elements with Home Assistant
├── card.ts - Main card component (ChoreboardCard class)
├── editor.ts - Configuration editor component (ChoreboardCardEditor class)
├── claim-dialog.ts - Claim chore dialog component (v1.1.0+)
├── complete-dialog.ts - Complete chore dialog component (v1.1.0+)
└── common.ts - Shared TypeScript interfaces and constants
main.ts:
- Imports card and editor components
- Registers custom elements (
choreboard-card,choreboard-card-editor) - Registers card metadata with Home Assistant's card picker
card.ts:
- Implements
ChoreboardCardas a LitLitElement - Required methods for Home Assistant cards:
setConfig(config)- Validates configuration (requiresentityfield)set hass(hass)- Receives Home Assistant state updatesgetCardSize()- Returns card height based on chore countgetStubConfig()- Provides default configuration for card pickergetConfigElement()- Returns visual editor element (enables UI configuration)
- Key methods:
getChores()- Reads chores from sensor'sattributes.choresarraycompleteChore(chore)- Callschoreboard.complete_choreservice withinstance_idgetChoreStateClass(chore)- Determines CSS class based on status/overduegetUsername()- Extracts username from sensor attributes
- Pool Chores Methods (v1.1.0+):
isPoolChore(chore)- Detects if chore is from pool by status or sensor patterngetUsers()- Fetches ChoreBoard users from coordinator dataclaimChore(chore)- Shows claim dialog and handles claim actioncompletePoolChore(chore)- Shows complete dialog with user/helper selection
- Renders chore list with status indicators, points, due dates
- Filters chores by completion status and overdue state
- Dynamically loads dialog components when needed
editor.ts:
- Implements
ChoreboardCardEditoras a LitLitElement - Provides visual UI for:
- Selecting My Chores sensor from dropdown
- Configuring title, header visibility
- Show/hide completed chores
- Show only overdue chores
- Show/hide points
- Auto-discovers available My Chores sensors using flexible pattern matching:
sensor.choreboard_my_chores_*sensor.*_my_choressensor.choreboard_my_immediate_chores_*sensor.*_my_immediate_chores
- Dispatches
config-changedevents when configuration updates
claim-dialog.ts (v1.1.0+):
- User selection dialog for claiming pool chores
- Shows clickable list of available users
- Fires
dialog-confirmedwithuserIdon selection - Dynamically created/removed via
claimChore()method - See "Dialog Pattern and Lifecycle" section below for implementation details
complete-dialog.ts (v1.1.0+):
- User + helper selection dialog for completing pool chores
- Two sections: "Who completed" (required, single-select) and "Who helped" (optional, multi-select)
- Fires
dialog-confirmedwithuserIdandhelperIdsarray - Dynamically created/removed via
completePoolChore()method - See "Dialog Pattern and Lifecycle" section below for implementation details
common.ts:
- TypeScript interfaces:
ChoreboardCardConfig- Card configuration (requiresentity)Chore- Individual chore from sensor's chores arrayid: number- Instance ID for API callsname: string- Chore namedue_date: string- Due date in ISO formatpoints: string | number- Handles both types from integrationis_overdue?: boolean- Optional overdue flagstatus: string- Supports "assigned", "pending", "completed", "pool", etc.complete_later?: boolean- Available in immediate_chores sensordescription?: string- Optional description
MyChoresSensorAttributes- Structure of sensor's attributesusername?: string- Optional usernamechores: Chore[]- Array of chorescount: number- Number of chorestotal_chores?: number- For immediate_chores sensorcomplete_later_chores?: number- For immediate_chores sensor
User(v1.1.0+) - ChoreBoard user from integration coordinator:id: number- User ID for API callsusername: string- Login usernamedisplay_name: string- Friendly display namefirst_name: string- First namecan_be_assigned: boolean- Can receive chore assignmentseligible_for_points: boolean- Can earn pointsweekly_points: string | number- Points this weekall_time_points: string | number- Total points earnedclaims_today?: number- Optional claim count
HomeAssistantExtended- Extended Home Assistant type
- Constants:
CARD_VERSION,CARD_NAME,ELEMENT_NAME
Version 1.1.0 introduced support for pool chores - chores that are available in a shared pool and can be claimed by any user. This feature enables households to manage unassigned chores that can be picked up by anyone.
The card automatically detects pool chores using two methods:
- Status-based detection: Chores with
status === "pool" - Sensor-based detection: Chores from pool sensor entities
- Sensor entity contains "chores" but not "my_chores"
- Example patterns:
sensor.pool_chores,sensor.choreboard_pool_chores
Detection implementation in card.ts:152-159:
private isPoolChore(chore: Chore): boolean {
return (
chore.status === "pool" ||
(this.config.entity.endsWith("_chores") &&
!this.config.entity.includes("_my_chores"))
);
}Assigned Chores:
- Single "Complete" button
- No user selection required
- Directly marks chore complete for the assigned user
Pool Chores:
- Two action buttons: "Claim" and "Complete"
- Both actions require user selection via dialogs
- Claim assigns chore to selected user
- Complete allows primary user + helper selection
The card fetches ChoreBoard users from the integration's coordinator data:
private getUsers(): User[] {
if (!this.hass) return [];
// Search all ChoreBoard sensor entities for users array
for (const entityId of Object.keys(this.hass.states)) {
if (entityId.startsWith("sensor.choreboard_")) {
const state = this.hass.states[entityId];
if (state.attributes.users && Array.isArray(state.attributes.users)) {
return state.attributes.users as User[];
}
}
}
return [];
}Important: Users are stored in sensor attributes by the integration's coordinator. The card searches all ChoreBoard sensors to find the users array. This works because all sensors share the same coordinator instance.
Both claim and complete dialogs follow a consistent pattern:
1. Dynamic Import and Creation:
// Import dialog component on demand (lazy loading)
await import("./claim-dialog");
// Create dialog element
const dialog = document.createElement("claim-chore-dialog") as HTMLElement & {
users: User[];
chore: Chore;
};
// Set properties
dialog.users = users;
dialog.chore = chore;2. Event Listeners:
// Handle confirmation
dialog.addEventListener("dialog-confirmed", async (e: Event) => {
const customEvent = e as CustomEvent;
const userId = customEvent.detail.userId;
// Call service
await this.hass.callService("choreboard", "claim_chore", {
chore_id: chore.id,
assign_to_user_id: userId,
});
// Show feedback
this.showToast("Chore claimed successfully");
// Cleanup
dialog.remove();
});
// Handle cancellation
dialog.addEventListener("dialog-closed", () => {
dialog.remove();
});3. Append to DOM:
document.body.appendChild(dialog);Why This Pattern:
- Lazy loading: Dialog components only loaded when needed
- Memory efficiency: Dialogs removed after use
- Decoupling: Dialog doesn't know about parent component
- Event-driven: Communication via standard DOM events
- Reusable: Same dialog can be used by different components
User Action Sequence:
- User clicks "Claim" button on pool chore
claimChore(chore)method called- Users fetched via
getUsers() - Claim dialog dynamically imported and created
- Dialog shows list of available users
- User selects who will claim the chore
- Dialog fires
dialog-confirmedevent withuserId - Card calls
choreboard.claim_choreservice:{ chore_id: chore.id, assign_to_user_id: userId }
- Integration assigns chore to selected user
- Sensor updates, chore moves from pool to user's assigned list
- Card re-renders with updated data
Error Handling:
- Toast notification shown if users list unavailable
- Service call wrapped in try-catch
- Error toast displayed on failure
- Dialog removed regardless of success/failure
User Action Sequence:
- User clicks "Complete" button on pool chore
completePoolChore(chore)method called- Users fetched via
getUsers() - Complete dialog dynamically imported and created
- Dialog shows two-section interface:
- Section 1: "Who completed?" (required, single-select)
- Section 2: "Who helped?" (optional, multi-select)
- User selects completer (required)
- Helper section appears with remaining users
- User optionally selects helpers
- Dialog fires
dialog-confirmedevent with:{ userId: number, // Who completed helperIds: number[] // Who helped (may be empty) }
- Card calls
choreboard.mark_completeservice:{ chore_id: chore.id, completed_by_user_id: userId, helpers: helperIds }
- Integration:
- Marks chore complete
- Awards points to completer
- Awards partial points to helpers (if configured)
- Updates all affected user sensors
- Card re-renders with updated data
Important Logic:
- Selected completer is excluded from helpers list
- If user switches completer selection, they're removed from helpers
- Helper section hidden until completer selected
- Complete button disabled until completer selected
- Empty helpers array is valid (no helpers)
Dynamic imports require specific Rollup configuration:
rollup.config.mjs:
export default {
input: 'src/main.ts',
output: {
file: `dist/${outputFile}`,
format: 'es',
sourcemap: !isProduction,
inlineDynamicImports: true, // REQUIRED for dialog lazy loading
},
// ...
};Why inlineDynamicImports: true:
- Bundles dynamic imports into single output file
- Prevents creation of separate chunk files
- Simplifies deployment (single .js file)
- Compatible with HACS distribution requirements
- Home Assistant custom cards prefer single-file distribution
Without this setting:
- Rollup creates separate chunk files (e.g.,
claim-dialog-[hash].js) - HACS doesn't know which files to distribute
- Card loading may fail in production
See the "Service Calls" section under "ChoreBoard Integration" above for complete service parameter documentation. Key differences:
- Assigned chores: Use
complete_chorewithinstance_idparameter - Pool chores: Use
claim_choreormark_completewithchore_idand user selection parameters
Setup Requirements:
- ChoreBoard integration installed and configured
- Pool chores created in ChoreBoard API
- Multiple users configured in ChoreBoard
- Pool chores sensor entity available
Test Cases:
-
Pool Chore Detection:
- Verify "Claim" and "Complete" buttons appear for pool chores
- Verify single "Complete" button for assigned chores
-
Claim Dialog:
- Click "Claim" button
- Verify all users appear in dialog
- Select a user
- Verify selection highlighted
- Click "Claim" button
- Verify chore assigned to user
- Verify chore removed from pool sensor
- Verify chore appears in user's my_chores sensor
-
Complete Dialog:
- Click "Complete" button on pool chore
- Verify "Who completed?" section appears
- Verify "Complete" button disabled
- Select a user as completer
- Verify "Complete" button enabled
- Verify "Who helped?" section appears
- Verify completer not in helpers list
- Select one or more helpers
- Click "Complete" button
- Verify chore marked complete
- Verify points awarded correctly
-
Dialog Cancellation:
- Open claim dialog and click "Cancel"
- Verify dialog closes without action
- Open complete dialog and click backdrop
- Verify dialog closes without action
-
Error Handling:
- Test with no users available
- Verify error toast shown
- Test with service call failure
- Verify error toast shown
When implementing pool chores support:
- Detect pool chores via status or sensor pattern
- Fetch users from coordinator data
- Create claim dialog component
- Create complete dialog component
- Implement lazy loading with dynamic imports
- Configure Rollup with
inlineDynamicImports: true - Handle dialog events correctly
- Call correct services with correct parameters
- Show/hide UI elements based on chore type
- Add error handling and user feedback
- Clean up dialogs after use
- Test with actual ChoreBoard integration
- Document in README.md
- Update version and create release
Cards register as custom:choreboard-card and appear in Home Assistant's card picker. The card implements the Lovelace card interface with required methods.
Card configuration is stored in dashboard YAML files. Users can configure via:
- Visual editor (all options available)
- YAML editor (for advanced configuration)
Example Configuration:
type: custom:choreboard-card
title: "Ash's Chores"
entity: sensor.choreboard_my_chores_ash
actor_user_id: 5 # Optional: ChoreBoard user ID who completes chores
show_completed: false
show_overdue_only: false
show_points: true
show_header: trueRequired Field:
entity: Single My Chores sensor entity ID
Optional Fields:
title: Card title (auto-generated from username if not specified)actor_user_id: ChoreBoard user ID who completes chores (default: auto-detect from sensor) (v1.5.0+)show_completed: Show/hide completed chores (default: true)show_overdue_only: Filter to only overdue chores (default: false)show_points: Show/hide point values (default: true)show_header: Show/hide card header (default: true)
The .hass-dev/ directory contains a complete Home Assistant configuration for testing:
- configuration.yaml: Loads the card from development server (localhost:4000)
- views/choreboard-card-preview.yaml: Example dashboard showcasing different card configurations
All Home Assistant custom cards must implement:
setConfig(config): Called when card is created/updated. Validate config and throw errors for invalid configurations.set hass(hass): Called on every state change. Update card content based on new state.getCardSize(): Return integer representing card height (1 unit ≈ 50px).getStubConfig()(optional): Return default configuration for card picker.getConfigElement()(optional): Return custom editor element.
- Entry:
src/main.ts - Output:
dist/choreboard-ha-card.js - Plugins:
@rollup/plugin-typescript- Compiles TypeScript@rollup/plugin-node-resolve- Resolves node_modules imports@rollup/plugin-commonjs- Converts CommonJS to ES modules@rollup/plugin-json- Imports JSON files@rollup/plugin-terser- Minifies production buildsrollup-plugin-serve- Development server (watch mode only)
- Target: ES2020 (modern JavaScript features)
- Module: ESNext (ES modules)
- Decorators: Enabled for Lit decorators (
@customElement,@property,@state) - Strict Mode: All TypeScript strict checks enabled
- Source Maps: Generated for debugging
To publish this card to HACS (Home Assistant Community Store):
- Repository Structure: JavaScript files must be in
dist/directory - File Naming:
choreboard-ha-card.jsmatches repository name (with optionallovelace-prefix stripped) - GitHub Releases: Required for version management
- hacs.json: Metadata file in repository root
- README.md: Installation and usage documentation
{
"name": "ChoreBoard Card",
"filename": "choreboard-ha-card.js",
"render_readme": true,
"content_in_root": false
}Releases are created automatically via GitHub Actions when code is merged to main:
-
Create a semver branch with EXACT version format (no descriptive suffixes):
git checkout -b feature/1.2.0 # ✅ Correct - triggers auto-release git checkout -b bugfix/1.1.3 # ✅ Correct - triggers auto-release git checkout -b hotfix/1.0.4 # ✅ Correct - triggers auto-release # ❌ WRONG - Adding text after version prevents auto-release: git checkout -b feature/1.2.0-points-name # Will NOT trigger git checkout -b feature/1.2.0-my-feature # Will NOT trigger
Important: Branch must match
(feature|bugfix|hotfix|release)/X.Y.Zexactly. -
Make changes and create PR - commit with appropriate message prefix (see CI/CD section)
-
Merge PR to main - squash or regular merge both supported
-
Auto-release workflow runs automatically:
- Updates version in package.json, package-lock.json, and src/common.ts
- Builds production bundle (
npm run build:prod) - Commits version files + built artifacts to main
- Creates git tag (e.g.,
v1.1.3) - Creates GitHub release with assets:
- dist/choreboard-ha-card.js
- dist/choreboard-ha-card.js.map
- package.json
- package-lock.json
HACS searches for JavaScript files in this order:
dist/directory in latest release- Repository root in latest release
dist/directory on default branch- Repository root on default branch
Files must match the repository name (case-insensitive, with optional lovelace- prefix).
The project uses GitHub Actions for continuous integration and automated releases:
Runs on all pull requests and pushes to non-main branches:
- Installs dependencies
- Checks code formatting with Prettier
- Builds both development and production versions
- Validates build output exists
- Validates JSON configuration files (hacs.json, package.json)
- Checks for required files
- Uploads build artifacts for inspection
Trigger: Pull requests and pushes to any branch except main
Automatically creates releases when code is merged to main:
- Builds production version
- Determines version bump type from commit message:
major:orbreaking:→ Major version bump (1.0.0 → 2.0.0)feat:orfeature:orminor:→ Minor version bump (1.0.0 → 1.1.0)- All other commits → Patch version bump (1.0.0 → 1.0.1)
- Updates version in package.json and src/common.ts
- Creates git tag (e.g., v1.0.0)
- Generates changelog from commit messages
- Creates GitHub release with built files attached
- Attaches dist/choreboard-ha-card.js and source maps to release
Trigger: Push to main branch
Validates HACS compatibility:
- Runs HACS action to validate repository structure
- Checks plugin category requirements
- Runs daily to catch any issues
Trigger: Push, pull requests, and daily schedule
To control automatic version bumping, use these commit message prefixes:
major:orbreaking:- Major version bump (1.0.0 → 2.0.0)feat:orfeature:orminor:- Minor version bump (1.0.0 → 1.1.0)- Any other prefix - Patch version bump (1.0.0 → 1.0.1)
Note: See "HACS Publishing" section for detailed release process.
After every successful build on CI:
- Artifacts are uploaded with 7-day retention
- Can be downloaded from Actions tab → Workflow run → Artifacts section
- Useful for testing builds from pull requests
The actor configuration feature allows users to specify which ChoreBoard user will be recorded as completing chores when clicking the "Complete" button on assigned chores. This is useful for scenarios where one person manages chores on behalf of another (e.g., parents managing children's chores).
Configuration Field:
actor_user_id?: numberinChoreboardCardConfig(src/common.ts:21)- Optional field storing the ChoreBoard user ID who will complete chores
- Defaults to undefined (auto-detect from sensor)
Core Logic (src/card.ts):
-
getActorUserId() (lines 663-682):
- Returns configured
actor_user_idif set and valid - Validates actor exists in users list
- Falls back to
getCurrentUserId()if actor invalid or not configured - Logs warning if configured actor not found
- Returns configured
-
getActorDisplayName() (lines 684-690):
- Returns display name of configured actor
- Used for toast messages and badge display
- Returns null if no actor configured
-
isUsingCustomActor() (lines 692-697):
- Determines if actor differs from sensor owner
- Controls visibility of actor badge
- Returns false if no actor or actor matches sensor user
-
completeChore() (lines 164-196):
- Calls
getActorUserId()instead ofgetCurrentUserId() - Shows enhanced toast message with actor name
- Format: "Marked '[chore]' as complete (by [actor])"
- Calls
Visual Editor (src/editor.ts):
-
Actor Dropdown (lines 100-137):
- Populated with all ChoreBoard users via
getUsers() - Shows "Use sensor's user (auto-detect)" as default option
- Displays
user.display_name (@username)for clarity - Validation warning if selected user no longer exists
- Populated with all ChoreBoard users via
-
actorChanged() Handler (lines 435-455):
- Removes
actor_user_idfrom config when "auto-detect" selected - Sets
actor_user_idwhen specific user selected - Triggers
configChanged()to persist
- Removes
Visual Indicators:
-
Actor Badge (src/card.ts:940-945):
- Orange badge in card header: "Acting as: [Name]"
- Only visible when
isUsingCustomActor()returns true - Uses
--warning-colortheme variable
-
Validation Warning (src/editor.ts:124-136):
- Appears in editor if configured actor no longer exists
- Orange border with alert icon
- Prompts user to choose another or use auto-detect
- Parent/Guardian Management: Parents can complete chores on behalf of children while viewing the child's chore list
- Shared Kiosks: Tablet devices configured with specific actors for multi-user households
- Caretaker Interfaces: Guardians managing chores for those they care for
- Multi-User Devices: Shared devices where one person manages multiple users' chores
actor_user_idis optional - existing configurations work unchanged- Falls back to
getCurrentUserId()when not configured (preserves existing behavior) - Graceful degradation if configured actor is deleted
- No breaking changes to existing functionality
- Actor dropdown populates with all ChoreBoard users
- "Auto-detect" option removes
actor_user_idfrom config - Selecting a user sets
actor_user_idcorrectly - Actor badge appears only when actor differs from sensor owner
- Completion toast shows actor name when using custom actor
- Validation warning appears for invalid/deleted actors
- Fallback to sensor user works when actor invalid
- Pool chores unaffected (still show user selection dialogs)
- Builds successfully (development and production)
- Add property to
ChoreboardCardConfiginterface insrc/common.ts - Update
card.ts:- Add to
setConfig()default values - Use in
getChores()orrender()method for filtering/display - Update
getStubConfig()if needed
- Add to
- Update
editor.ts:- Add input/checkbox/select for the option
- Add event handler method (e.g.,
showXxxChanged) - Update render to include new option
- Update README.md configuration documentation
Example: Adding a "show_assignee" option:
// 1. Add to interface (src/common.ts)
show_assignee?: boolean;
// 2. Set default (src/card.ts - setConfig)
this.config = { show_assignee: true, ...config };
// 3. Use in render (src/card.ts)
${this.config.show_assignee ? html`<span>${chore.assignee}</span>` : ""}
// 4. Add editor toggle (src/editor.ts)
<input type="checkbox" ?checked=${this.config.show_assignee !== false}
@change=${this.showAssigneeChanged} />
// 5. Handle change event (src/editor.ts)
private showAssigneeChanged(ev: Event): void {
this.config = { ...this.config, show_assignee: (ev.target as HTMLInputElement).checked };
this.configChanged();
}- Design feature requirements
- Update TypeScript interfaces in
src/common.ts(e.g., add toChoreinterface) - Implement in
card.ts:- Add methods for new functionality
- Update
getChores()for filtering logic - Update
render()for display - Add event handlers for user interactions
- Add visual editor controls in
editor.ts(if applicable) - Add test cases to
.hass-dev/views/choreboard-card-preview.yaml - Update README.md with examples
- Run tests and verify in development Home Assistant instance
// Read chores from sensor attributes
const chores = this.hass.states[this.config.entity].attributes.chores || [];
// Filter by status/overdue
const filtered = chores.filter(chore =>
(!this.config.show_completed && chore.status === "completed") ? false : true
);
// Call service with instance_id (not entity_id)
await this.hass.callService("choreboard", "complete_chore", { instance_id: chore.id });- TypeScript Errors: Check
tsconfig.jsonand runnpm run build - Runtime Errors: Check browser console in Home Assistant frontend
- Card Not Loading: Verify development server is running and configuration.yaml has correct URL
- Styles Not Applying: Check CSS in
card.tsstatic styles getter
If Rollup watch mode stops working or shows errors:
- Restart
npm run watch - Check for syntax errors in TypeScript files
- Verify all imports are correct
- Use Prettier for formatting:
npm run format - Follow TypeScript strict mode conventions
- Use Lit decorators for reactive properties
- Prefer functional programming patterns
- Keep components focused and single-responsibility
Home Assistant doesn't load all custom cards at startup. Cards are loaded on-demand when dashboards are accessed.
- Card receives Home Assistant state via
hassproperty - State updates trigger
set hass(hass)method - Use Lit's
@statedecorator for internal component state - Use
@propertydecorator for properties passed from configuration
- Use CSS custom properties (CSS variables) for theming
- Home Assistant provides theme variables:
--primary-color,--secondary-text-color, etc. - Card should work with both light and dark themes
- Avoid hardcoded colors
Manual testing workflow:
- Start watch mode:
npm run watch - Start HA instance:
npm run start:hass - Complete initial HA setup wizard (first run only)
- Navigate to ChoreBoard Dev dashboard
- Test each example configuration
- Verify card behavior with different configurations
- Test in both light and dark themes
The card follows these architectural principles:
- Single Source of Truth: Each user has one My Chores sensor containing all their chores
- Attribute-Based Data: Chores are stored in sensor's
attributes.choresarray, not as separate entities - Instance ID for Actions: Use chore's
idfield (instance_id) for service calls, not entity_id - Client-Side Filtering: Card filters chores by status/overdue on the client side
- Auto-Discovery: Editor auto-discovers My Chores sensors by flexible pattern matching
- Type Flexibility: Card handles both string and number point values from integration
Note: For migration from v1.0.0 or earlier versions, see MIGRATION_GUIDE.md for detailed migration steps and breaking changes.
- Home Assistant Custom Card Documentation
- Lit Documentation
- HACS Plugin Publishing
- custom-card-helpers
- ChoreBoard Integration Source
- Always use EXACT semver branch format for releases:
feature/1.2.0,bugfix/1.0.2,hotfix/1.0.3- ✅ Correct:
feature/1.2.0,bugfix/1.1.3 - ❌ Wrong:
feature/1.2.0-points-name,feature/1.2.0-my-feature(will NOT trigger auto-release) - For non-release feature branches, use descriptive names:
feature/add-dark-mode,fix/button-alignment
- ✅ Correct:
- Test with actual ChoreBoard integration sensors, not mock data
- Verify complete button calls correct service with instance_id
- Test filtering options: show_completed, show_overdue_only
- Ensure card works with both light and dark themes
- Always let me know if a something needs to be fixed or implemented to accplish a goal in either the backend or the integration