Turn chores into a game your kids actually want to play.
A Home Assistant integration for family chore management with smart rewards.
Kids don't naturally love chores. But they do love games, progress bars, and earning things. Choremander turns daily responsibilities into a reward system that actually motivates.
- Visual progress toward goals keeps kids engaged
- Immediate feedback (points, sounds, celebrations) reinforces positive behavior
- Clear expectations - kids know exactly what's required and what they'll earn
Not all chores are equal. Some are easy (brush teeth), others take effort (homework, practice). With Choremander:
- Weight points by difficulty - Give 1 star for easy tasks, 5 stars for harder ones
- Harder chores = faster rewards - Kids learn that putting in effort pays off
- No gaming the system - Smart pricing means you can't just spam easy chores to win
- Per-child or shared - Define rewards for one kid or assign to multiple
- Smart pricing per child - Even shared rewards calculate costs individually based on each child's chores and completion rates
- Control the pace - Set how many days a reward should take to earn; the system calculates the rest
- Jackpot rewards - Pool stars from all kids toward big family goals (vacation, museum trip, etc.)
- HACS → Integrations → ⋮ menu → Custom repositories
- Add
https://github.com/vinnybad/choremanderas an Integration - Search "Choremander" and install
- Restart Home Assistant
- Settings → Devices & Services → Add Integration → "Choremander"
- Choose your points currency (Stars, Coins, Bucks, etc.)
- Click Configure on the integration to manage everything:
| Feature | Description |
|---|---|
| Points | Stars earned for completion |
| Time of Day | Morning, Afternoon, Evening, Night, or Anytime |
| Due Days | The weekdays the chore falls on - bins on Mondays, piano on Tuesdays and Thursdays. Leave it empty and the chore falls every day, which is what every chore did before this existed |
| Completion % Per Month | Of the days it is due, how often it actually gets done (100 = every time) - used for smart reward pricing |
| Daily Limit | How many times per day the chore can be completed |
| Requires Approval | Parent must approve before points are awarded |
A chore on due days only shows up on its days: on a Tuesday the child card shows Tuesday's chores and nothing else. Children can also take turns on a shared chore - alternating each time it comes round, or a week each - and a single day can be handed to somebody else without disturbing the pattern ("Maya covers this Saturday"). Turns and one-off swaps are edited from the Schedule Card, which shows the whole rota a week at a time.
| Type | Description |
|---|---|
| Dynamic (default) | Cost auto-calculated: Days to Goal × expected daily earnings (based on each chore's points and completion rate) |
| Fixed | Toggle "Override Point Value" to set a manual cost |
| Jackpot | Pool stars from ALL assigned children toward one big family reward |
Cards auto-register when the integration loads. Just add them to your Lovelace dashboard - no manual resource configuration needed!
The easiest way to add Choremander cards:
- Edit your dashboard and click Add Card
- Search for the card (e.g., "choremander-child-card") or scroll to find it under "Custom"
- Alternatively, add a Manual card and enter the card type (e.g.,
custom:choremander-child-card) - The card will show a configuration interface - enter the entity that card reads (see below)
- Fill in any additional options (child selection, time of day, etc.) and save
Most cards read sensor.choremander_overview. Four read their own sensor
instead, because the data they need is too large to carry on the overview one:
| Card | Entity |
|---|---|
| Approvals Card | sensor.pending_approvals |
| Activity Card | sensor.choremander_activity |
| Streak Card | sensor.choremander_streaks |
| Schedule Card | sensor.choremander_schedule |
| Everything else | sensor.choremander_overview |
Picking the wrong one is not silent — the card says which entity it reads rather than drawing an empty card.
Tip: If the card shows an error after adding, click on it to open the configuration panel. This is normal - it just needs to be configured!
Versions before this fix could delete the Lovelace resources belonging to your other custom cards (issue #2). Choremander registered its own cards before Home Assistant had finished loading the resource list, and saving that half-loaded list overwrote everything else in it - on every restart, which is why re-adding the entries by hand never stuck.
That no longer happens. If you were affected, Choremander looks for the cards your dashboards still reference but can no longer load, and offers to put them back: go to Settings → System → Repairs. It shows you exactly which resources it would restore before changing anything, and leaves alone anything you have already re-added yourself. Reload your browser afterwards.
You can also restore them by hand under Settings → Dashboards → ⋮ → Resources.
If you use Lovelace in YAML mode, add these resources to your configuration.yaml:
lovelace:
resources:
- url: /choremander/choremander-child-card.js
type: module
- url: /choremander/choremander-rewards-card.js
type: module
- url: /choremander/choremander-approvals-card.js
type: module
- url: /choremander/choremander-points-card.js
type: module
- url: /choremander/choremander-reorder-card.js
type: module
- url: /choremander/choremander-activity-card.js
type: module
- url: /choremander/choremander-streak-card.js
type: module
- url: /choremander/choremander-schedule-card.js
type: module| Card | For | Description |
|---|---|---|
| Child Card | Kids | Kid-friendly chore completion interface |
| Rewards Card | Kids | View available rewards and progress |
| Streak Card | Kids | Day streaks, recent activity and milestones |
| Approvals Card | Parents | Approve or reject completed chores |
| Points Card | Parents | Manually add/remove points |
| Reorder Card | Parents | Organize chore display order per child |
| Activity Card | Parents | Timeline of everything that happened |
| Schedule Card | Parents | Which days each chore falls on and whose turn it is |
Tip: Create separate dashboards - one for kids (Child + Rewards + Streak) and one for parents (Approvals + Points + Activity).
Kid-friendly interface with big colorful buttons and celebration sounds. This is the primary way children interact with their chores.
Visual Editor: Add custom:choremander-child-card, then configure the entity (sensor.choremander_overview), select a child, and optionally filter by time of day.
YAML Example
type: custom:choremander-child-card
entity: sensor.choremander_overview
child_id: a8c8376a
time_category: morning # Optional: morning, afternoon, evening, night, anytime
title: My Chores # Optional
density: compact # Optional: default, cozy, compact
show_header: false # Optional: hide the avatar / name / balance strip
schedule_entity: sensor.choremander_schedule # Optional: whose turn it is todayOptions
| Option | Default | Description |
|---|---|---|
entity |
required | The sensor.choremander_overview entity |
child_id |
required | Which child the card is for |
time_category |
anytime |
morning, afternoon, evening, night, anytime or all |
schedule_entity |
sensor.choremander_schedule |
The sensor that says whose turn each chore is on each day. Point it at an entity that does not exist to ignore schedules entirely. YAML only - the visual editor does not ask for it |
What the card shows today. A chore that has a schedule rule is shown to whichever child the schedule says is on it today, and that chore's own Assigned To is not consulted - so a one-off cover ("Maya takes Saturday") or a turn that lands on a sibling appears on that child's card even though the chore belongs to someone else. A chore with no rule behaves exactly as it always did: it shows for whoever it is assigned to, every day. If the schedule sensor is missing or unavailable, every chore falls back to Assigned To.
Day off. When a child has nothing scheduled today the card says "Day off"
along with the next day they are actually on something ("Next chores tomorrow!",
"Next chores Monday!", or nothing at all if no day in the published fortnight has
anything for them). That is judged across all of the child's chores rather than
only the ones this card's time_category shows, so a morning card and an evening
card on the same dashboard never disagree about whether it is a rest day. A child
who has simply finished everything still gets "All Done!".
The same card at each density — the chores and the child are identical, only
the option differs:
What that adds up to on a phone. Same dashboard, one screen:
Layout options
| Option | Values | Default | What it does |
|---|---|---|---|
density |
default, cozy, compact |
default |
How much space each chore takes. compact fits roughly twice as many chores on a phone screen. |
show_header |
bool | true |
The avatar, name and star balance across the top. Turn off if you show the balance elsewhere. |
show_avatar |
bool | true |
Just the round avatar. |
show_title |
bool | true |
The "Morning Chores" heading. |
show_numbers |
bool | true |
The coloured number badge on each chore. |
show_chore_points |
bool | true |
The star value under each chore name. |
animations |
bool | true |
The floating avatar and spinning stars. Celebrations still play. |
Tap targets do not shrink with density: a chore row stays at least 56px tall and the checkbox at least 40px at every setting, because the whole row is the button and it is a small child doing the tapping. The card also honours your operating system's "reduce motion" setting on its own.
Shows all available rewards with progress bars. Displays dynamic pricing indicators and jackpot status.
Visual Editor: Add custom:choremander-rewards-card, configure the entity, and optionally filter to a specific child.
YAML Example
type: custom:choremander-rewards-card
entity: sensor.choremander_overview
child_id: 6ddfca70 # Optional: filter to specific child
density: compact # Optional: default, cozy, compact
animations: false # Optional: stop the shimmer and jackpot shineHow many days in a row each child has kept going, a strip of dots for the recent days they were active, and the milestones they have reached. Streaks are worked out from the chores that were actually approved, so the number and the dots can never tell different stories.
A day counts once, however many chores were done in it, and a streak stays alive until a whole working day has been missed - so it does not appear to collapse the moment the clock passes midnight.
A day the schedule asked nothing of a child is a day off, not a missed day. It draws as a hollow dot and the streak steps straight over it, so a child whose chores fall on weekdays keeps their streak through the weekend instead of losing it every Saturday. Doing a chore anyway still counts as an active day and wins over the day off. Households with no schedules have no days off at all, and the strip looks exactly as it always did.
Visual Editor: Add custom:choremander-streak-card and pick the streaks
entity.
YAML Example
type: custom:choremander-streak-card
entity: sensor.choremander_streaks
title: Streaks
child_id: a8c8376a # optional: one child instead of the whole family
streak_days: 14
achievements: nextOptions
| Option | Default | Description |
|---|---|---|
entity |
required | The sensor.choremander_streaks entity |
title |
Streaks |
Header text |
child_id |
all | Show one child instead of the whole family |
streak_days |
14 |
Days in the dot strip, up to 30 |
achievements |
next |
next (earned plus one to aim for), earned, all or none |
show_avatar |
true |
Show each child's avatar |
density |
default |
default, cozy or compact |
animations |
true |
Scales up today's dot |
Review and approve (or reject) completed chores that require parent approval. Shows pending items grouped by time of day.
Visual Editor: Add custom:choremander-approvals-card and configure the
entity (sensor.pending_approvals). This card reads its own sensor, not the
overview one — pointed anywhere else it shows "All caught up!" no matter what is
waiting.
YAML Example
type: custom:choremander-approvals-card
entity: sensor.pending_approvalsManually add bonus points (great job today!) or remove points (consequences). Useful for situations outside the normal chore flow.
Visual Editor: Add custom:choremander-points-card and configure the entity.
YAML Example
type: custom:choremander-points-card
entity: sensor.choremander_overviewDrag-and-drop interface to organize the order chores appear for each child. Customize the experience per kid.
Visual Editor: Add custom:choremander-reorder-card, configure the entity, and select a child.
YAML Example
type: custom:choremander-reorder-card
entity: sensor.choremander_overview
child_id: a8c8376aA timeline of everything that has happened: chores done and approved, rewards claimed, and the bonuses and penalties you handed out - with the reason you gave for each. Answers "why does she have that many stars?" without guesswork.
Chores waiting on your approval appear too, marked as such, showing what they are worth rather than a change that has not happened yet.
Visual Editor: Add custom:choremander-activity-card and pick the activity
entity. Everything else is optional.
YAML Example
type: custom:choremander-activity-card
entity: sensor.choremander_activity
title: Activity
child_id: a8c8376a # optional: one child instead of the whole family
max_items: 20
density: compactOptions
| Option | Default | Description |
|---|---|---|
entity |
required | The sensor.choremander_activity entity |
title |
Activity |
Header text |
child_id |
all | Show only one child's activity |
max_items |
20 |
Events to show. The integration keeps the most recent 40 |
show_filters |
true |
Chips to narrow to chores, rewards or bonuses |
show_relative_time |
true |
"20m ago" for recent events instead of a clock time |
density |
default |
default, cozy or compact |
animations |
true |
Hover and press transitions on the filter chips |
A week of the family rota: one row per scheduled chore, one column per day, and whoever is on it in each cell. Arrows page between this week and next, which are the two weeks the integration resolves.
Whose turn it is is worked out by the integration from the chore's rule and the date, so the card never has to guess - and asking twice always gives the same answer.
Click a cell to change who is on that chore, and pick whether it applies to just that date or to every one of that weekday - the same choice a calendar asks when you edit a repeating event. Click a chore's name to open its rule: the days it falls on, whether the children take turns and in what order, and the date the turns are counted from. It opens showing what is stored, and sends only the fields you actually change - so saving a dialog you did not touch calls nothing at all, and moving a Saturday cannot quietly rewrite the rotation.
A cell is dashed and carries a dot when the rule names that particular day: a one-off swap on that date, or a standing swap on that weekday. A rotation is never marked, because a chore due Mondays that changes hands each week is supposed to differ between the two Mondays - marking it would say you had overridden the very thing the rotation is doing for you.
Chores with no rule at all are on every day, for whoever they are assigned to - which is how every chore behaved before schedules existed. They are not in the grid; the picker underneath it is how you give one days of its own.
Visual Editor: Add custom:choremander-schedule-card and pick the schedule
entity. The names come from sensor.choremander_overview, which is also where
the chores that are not on a schedule yet are read from.
YAML Example
type: custom:choremander-schedule-card
entity: sensor.choremander_schedule
chores_entity: sensor.choremander_overview
title: Weekly Schedule
density: compact # Optional: default, cozy, compactOptions
| Option | Default | Description |
|---|---|---|
entity |
required | The sensor.choremander_schedule entity |
chores_entity |
sensor.choremander_overview |
Where chore and child names come from, and the chores not yet scheduled |
title |
Weekly Schedule |
Header text |
density |
default |
default, cozy or compact - how much room the grid takes up |
The card reads window_start, days, chores and rules from the schedule
sensor, and says which entity it needs rather than drawing if any of them is
missing. rules is on that list because every override field replaces its stored
value wholesale: a card that saved an edit against a payload carrying no rules
would delete the swaps it could not see.
Note: Most cards read the
sensor.choremander_overviewentity. The Activity Card readssensor.choremander_activity, the Streak Card readssensor.choremander_streaksand the Schedule Card readssensor.choremander_schedule- all are created for you. Child-specific cards also need a child selection.
If density does not get you where you want, the Child, Rewards, Activity,
Streak and Schedule cards expose every size as a CSS custom property. Set one
anywhere above the card - a Home Assistant theme, or a card_mod block on a
single card - and it wins over the built-in value.
# In your theme, applying to every Choremander card at once
my_theme:
chm-chore-min-height: 48px
chm-chore-name-font-size: 1rem
chm-card-background: "linear-gradient(135deg, #11998e 0%, #38ef7d 100%)"# Or with card_mod, on one card only
type: custom:choremander-child-card
entity: sensor.choremander_overview
child_id: a8c8376a
card_mod:
style: |
:host {
--chm-chore-radius: 4px;
--chm-color-purple: #e91e63;
}Child Card properties
| Property | Default |
|---|---|
--chm-card-background |
linear-gradient(135deg, #667eea 0%, #764ba2 100%) |
--chm-card-radius |
24px |
--chm-header-padding |
20px 24px |
--chm-avatar-size / --chm-avatar-icon-size |
70px / 50px |
--chm-name-font-size |
clamp(1.2rem, 5vw, 2rem) |
--chm-balance-padding / --chm-balance-radius |
12px 16px / 20px |
--chm-chores-padding / --chm-chores-gap / --chm-chores-min-height |
24px / 20px / 200px |
--chm-title-font-size / --chm-title-icon-size |
1.8rem / 36px |
--chm-chore-padding / --chm-chore-min-height |
20px 24px / 80px |
--chm-chore-radius / --chm-chore-border-width |
24px / 4px |
--chm-chore-name-font-size / --chm-chore-points-font-size |
1.5rem / 1.2rem |
--chm-badge-size / --chm-badge-font-size |
42px / 1.5rem |
--chm-checkbox-size / --chm-checkbox-icon-size |
44px / 28px |
--chm-color-pink, -purple, -blue, -green, -yellow, -orange, -red, -cyan |
the built-in palette |
Rewards Card properties
| Property | Default |
|---|---|
--chm-header-padding / --chm-header-title-font-size |
16px 20px / 1.3rem |
--chm-content-padding / --chm-content-gap |
16px / 12px |
--chm-reward-padding / --chm-reward-gap / --chm-reward-radius |
16px / 16px / 12px |
--chm-cost-badge-min-width / --chm-cost-badge-padding |
70px / 12px 8px |
--chm-cost-value-font-size / --chm-cost-label-font-size |
1.4rem / 0.65rem |
--chm-reward-name-font-size / --chm-reward-desc-font-size |
1.15rem / 0.9rem |
--chm-progress-height / --chm-jackpot-progress-height |
14px / 18px |
--chm-reward-icon-size / --chm-reward-icon-glyph-size |
44px / 24px |
Activity Card properties
| Property | Default |
|---|---|
--chm-header-padding / --chm-header-icon-size |
16px 20px / 32px |
--chm-header-title-font-size |
1.4rem |
--chm-activity-filters-padding / --chm-activity-chip-font-size |
12px 20px 4px / 0.85rem |
--chm-activity-feed-padding |
8px 20px 16px |
--chm-activity-day-label-margin / --chm-activity-day-label-font-size |
16px 0 8px / 0.75rem |
--chm-activity-event-padding / --chm-activity-event-gap |
10px 0 / 12px |
--chm-activity-event-min-height |
56px |
--chm-activity-icon-size / --chm-activity-icon-glyph-size |
40px / 22px |
--chm-activity-text-font-size / --chm-activity-meta-font-size |
0.95rem / 0.78rem |
--chm-activity-points-font-size / --chm-activity-points-icon-size |
0.95rem / 16px |
--chm-color-green, -red, -orange, -purple, -blue, -cyan |
the event colours |
Streak Card properties
| Property | Default |
|---|---|
--chm-header-padding / --chm-header-icon-size |
16px 20px / 32px |
--chm-streak-child-padding / --chm-streak-top-gap |
16px 20px / 14px |
--chm-streak-avatar-size / --chm-streak-avatar-glyph-size |
52px / 30px |
--chm-streak-name-font-size / --chm-streak-sub-font-size |
1.1rem / 0.9rem |
--chm-streak-count-font-size / --chm-streak-best-font-size |
1.9rem / 1.1rem |
--chm-streak-dot-size / --chm-streak-dot-gap |
12px / 5px |
--chm-streak-badge-size / --chm-streak-badge-padding / --chm-streak-badge-radius |
66px / 8px 6px / 12px |
--chm-streak-badge-emoji-size / --chm-streak-badge-label-size |
1.5rem / 0.68rem |
--chm-streak-rest |
var(--secondary-text-color, #757575) - the day-off dot |
--chm-color-orange / --chm-color-green |
the fire and today colours |
Schedule Card properties
| Property | Default |
|---|---|
--chm-header-padding / --chm-header-icon-size |
16px 20px / 28px |
--chm-schedule-grid-padding / --chm-schedule-grid-gap |
12px 16px 4px / 4px |
--chm-schedule-cell-min-height / --chm-schedule-cell-padding |
40px / 4px 2px |
--chm-schedule-day-head-font-size / --chm-schedule-chore-font-size |
0.75rem / 1rem |
--chm-schedule-initials-size / --chm-schedule-initials-font-size |
22px / 0.72rem |
--chm-schedule-add-padding |
12px 16px 16px |
--chm-schedule-marker / --chm-schedule-today |
the swap and today colours |
If you set both, the density option wins - it is the more specific instruction.
To restyle a card that also uses a density, target :host([density="compact"])
in your card_mod block.
The goal: every reward should take a predictable amount of time to earn - not random guessing.
If you set "Family Movie Night" to cost 500 stars, how long does that take? A week? A month? You'd have to manually calculate based on all assigned chores... and recalculate every time you add or change one.
You set Days to Goal (e.g., 14 days). Choremander does the math:
- Looks at each chore's point value, how often it comes round, and expected completion rate
- Calculates how many points the child should earn per day
- Sets the reward cost so it takes exactly that many days
Daily Expected Points = Sum of (Chore Points × Days On ÷ 7 × Completion %)
Reward Cost = Daily Expected Points × Days to Goal
Days On is how many days a week the chore is that child's - which is the whole
reason a rota does not distort prices. Bins on Mondays are worth a seventh of
bins every day. A chore two children take turns on gives each of them half its
days. Without that factor a Mon/Wed/Fri chore was priced as though it happened
every day, and every reward it fed into cost two to four times what it should
have, silently.
A chore with no Due Days falls every day, so the factor is exactly 1 and the price is the number Choremander has always calculated - which is every chore in every household that has not set a schedule.
Choremander counts the days the child is actually named on the chore over the next four weeks rather than reading Due Days off the rule. Rotations and one-off swaps move days between children, and counting is the only reading that survives all of them.
Here's the key insight: completion rate matters.
If a child only does "Homework" 60% of the time but "Brush teeth" 100% of the time, the pricing reflects that. Kids who consistently do the harder chores will hit their goals faster than kids who only do the easy ones.
The incentive: Want that reward sooner? Do the challenging stuff, not just the minimum.
| Behavior | Result |
|---|---|
| Only does easy daily chores | Earns rewards at the expected pace |
| Tackles harder/optional chores | Earns rewards faster than expected |
| Skips difficult chores | Falls behind the expected pace |
For big family goals (vacation, museum trip), enable Jackpot mode. All children's stars pool together toward one shared reward - teamwork!
- Two dashboards: One for kids (Child + Rewards), one for parents (Approvals + Points)
- Weekly chores: Give them Due Days rather than a low Completion % - the pricing already divides by how often a chore comes round, and doing both discounts it twice
- Completion %: Only about the days a chore is due. Set it lower for the ones that realistically get skipped
- All data is local: Nothing leaves your Home Assistant instance
A full local environment is included: a real Home Assistant in Docker with seeded family data, plus three test layers that run against it. Nothing touches your real Home Assistant instance.
See docs/TESTING.md for the complete guide.
- Docker and Docker Compose
- Python 3.13 and Node 20+ (only if you want to run the test suites)
make install # venv, Python deps, Node deps, Chromium
make up # start Home Assistant and wait until Choremander loads
make verify # lint + unit tests + API e2e + browser e2emake up is fully non-interactive: it starts the container, completes
onboarding over the REST API, creates the dev user, and blocks until the
integration has actually loaded. Log in at http://localhost:8123 with
dev / dev.
Three dashboards are pre-configured in the sidebar:
| URL | Contents |
|---|---|
/krishna |
Kid dashboard — chores, progress, rewards |
/radha |
Kid dashboard |
/parent |
Approvals, points management, chore reorder - plus Activity, Streaks, Schedule and Misconfigured views along the top |
# After changing Python files:
make restart # restarts and waits until it is serving again
# After changing JS card files, just hard refresh the browser (Cmd+Shift+R)
make test # fast unit tests, no container needed
make e2e # API-driven tests against the live container
make browser # Playwright tests driving the real cards
make browser-headed # ...and watch them run
make logs # follow filtered container logs
make shell # shell inside the container
make seed # restore the seeded family data
make reset # wipe all generated state
make down # stopRun make help for the full list.
The dev environment comes with:
- 3 kids: Krishna (25 stars), Radha (15 stars) and Meera (8 stars)
- 11 chores:
- Krishna and Radha: Make Bed, Brush Teeth (AM/PM), Tidy Room
- Krishna only: Feed the Dog, Do Homework
- Radha only: Water the Plants, Practice Piano
- Meera: Feed the Fish, Take Out the Bins, and Wash the Dishes with Krishna
- 3 of those chores are on a schedule, which is what the Schedule Card has to
draw:
- Feed the Fish falls Monday to Saturday, and is Meera's - so Meera has Sundays off, which is what puts a "Day off 🎉" on her card and a muted day-off dot on her streak strip
- Take Out the Bins falls on Mondays and Thursdays, also Meera's
- Wash the Dishes falls on Wednesdays and Saturdays with Krishna and Meera taking turns - which lands Krishna on every Wednesday and Meera on every Saturday, fixed there by the default counting-from date
- The other eight carry no rule at all, so they are on every day for whoever they are assigned to. That is the reading the whole feature rests on: no rule never means "off"
The rules sit on chores nothing else asserts against, deliberately. The browser specs treat the everyday visibility of Water the Plants and Tidy Room as a fixture invariant, and scheduling those two made three of them fail on most weekdays - correctly, since the card is right to hide a chore that is not yours today.
- 5 rewards:
- 30 Min Screen Time (dynamic pricing, 7 days) - shared
- New Video Game (50 stars, fixed) - Krishna only
- New Book (30 stars, fixed) - Radha only
- Family Movie Night (jackpot, 14 days) - shared
- Trip to the Zoo (jackpot, 30 days) - shared
License: MIT






