Skip to main content

Unofficial sourced checks for Home Assistant custom integration repos.

Project description

HassCheck

CI

HassCheck is an unofficial CLI for Home Assistant community integration maintainers.

It checks custom integration repositories for sourced HA/HACS quality signals and produces explainable, actionable reports.

Security Review: Not performed
Official HA Tier: Not assigned
HACS Acceptance: Not guaranteed

HassCheck is not affiliated with Home Assistant, HACS, Nabu Casa, or the Open Home Foundation. It does not certify integrations, prove that an integration is safe, or guarantee HACS acceptance.

What HassCheck does

HassCheck turns scattered Home Assistant and HACS expectations into local checks that are:

  • Sourced — every finding carries a source URL and checked date.
  • Explainable — each rule has a stable ID, version, title, reason, and fix suggestion.
  • Actionable — output points maintainers toward concrete next fixes.
  • Machine-readable — JSON output is the stable contract for future GitHub Actions, badges, hosted reports, and tooling.

HassCheck starts as a local CLI. Public badges, hosted reports, and any future hub should be opt-in only.

Quick Start

pip install hasscheck
hasscheck --version
hasscheck check --path /path/to/your/integration

HassCheck runs locally — it does not publish anything unless you explicitly opt in with hasscheck publish or emit-publish: 'true' in CI.

To understand a specific finding:

hasscheck explain manifest.domain.exists

See it in action

HassCheck is designed to produce concrete next steps, not a vague score.

HassCheck demo

uv run hasscheck check --path examples/bad_integration
uv run hasscheck scaffold diagnostics --path examples/bad_integration --dry-run

See docs/demo.md for the full walkthrough or docs/recording.md to regenerate the visual demo.

How HassCheck relates to other tools

Tool Purpose HassCheck relationship
hassfest Validates Home Assistant integration metadata and compatibility expectations. Complementary. HassCheck does not replace hassfest.
HACS publishing docs Define repository structure and metadata expectations for HACS custom integrations. HassCheck turns selected expectations into sourced local checks.
Home Assistant Integration Quality Scale Official framework for graded core integrations. HassCheck reports unofficial quality signals only; it does not assign official tiers.

HassCheck is intentionally not a replacement for hassfest and does not assign Home Assistant quality tiers. It provides maintainer-facing, sourced findings that help custom integration authors improve their repositories.

HassCheck reports are exact-build signals, not blanket compatibility claims. Before consuming, summarising, or surfacing a HassCheck report anywhere downstream, read the Compatibility Claim Policy — it is the public wording contract that defines what a HassCheck verdict means and what inferences are forbidden. The rationale is recorded in ADR 0012.

Current status

Current package version: v0.13.0 — beta.

The CLI, GitHub Action, JSON report contract, rule docs, local badge generation, opt-in publishing flow, per-rule settings, report provenance block, and publish --dry-run are all shipped. 52 rules across HACS structure, manifest metadata, modern HA patterns, diagnostics, docs, tests/CI, and maintenance. Auto-generated per-rule docs page for every registered rule. Published to PyPI.

The hub at hasscheck.io is operational and accepts opt-in published reports via GitHub OIDC.

Current development focus:

  • hasscheck-web: accept schema_version 0.4.0, set provenance.verified_by at OIDC ingest
  • Upgrade Radar card on hub (v1.0 — uses ADR 0011 taxonomy)
  • Hub-verified badge endpoint (replaces self-reported committed badge JSON)

GitHub Action

Add HassCheck to any integration repository's CI with one step:

name: HassCheck

on:
  pull_request:
  push:
    branches: [main]

jobs:
  hasscheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Daily-Nerd/hasscheck@v0.13.0
        with:
          comment-pr: true
          github-token: ${{ secrets.GITHUB_TOKEN }}

Inputs:

Input Default Description
path . Repository path to inspect
no-config false Ignore hasscheck.yaml if present
comment-pr false Post findings as a PR comment
github-token '' Required when comment-pr: true
emit-badges false Generate shields.io badge JSON and upload as artifact
badges-out-dir badges Directory for badge JSON when emit-badges: 'true'
emit-publish false Publish the report to a hosted HassCheck service. Requires workflow permissions: id-token: write
publish-endpoint https://hasscheck.io Publish endpoint URL when emit-publish: 'true'

The hosted reports endpoint at hasscheck.io is operational. Publishing requires permissions: id-token: write on the workflow so HassCheck can mint a GitHub OIDC token; the hub validates the token's repository claim before accepting the report. The local CLI (without emit-publish) remains fully functional and is the recommended starting point if you don't want to publish.

Before enabling emit-publish in your CI workflow, validate the publish path locally with --dry-run:

hasscheck publish --path . --dry-run
# would publish report to: https://hasscheck.io
#   - repo slug: owner/my-integration (from git remote)
#   - schema_version: 0.4.0
#   - ruleset: hasscheck-ha-2026.5
#   - 52 rules evaluated, 3 findings
#   - oidc token: not detected
#   - endpoint resolved from: default
#   - dry-run: no network request made

--dry-run runs the full check, resolves the endpoint and detects OIDC token availability — without making any network request. Use it to confirm your configuration before the first live publish.

Outputs: exit-code0 when no FAIL findings, 1 when one or more FAIL findings.

The action uploads hasscheck-report.json as a build artifact on every run.

Badges (opt-in)

HassCheck can generate shields.io endpoint JSON files for embedding specific quality signals in your README. Badges are opt-in only and show specific signals — not vague trust claims.

Generate locally

hasscheck badge --path . --out-dir badges/

This writes per-category JSON files and a manifest.json to badges/. Commit these files to your repo.

Generate in CI

Add emit-badges: 'true' to your HassCheck action step:

- uses: Daily-Nerd/hasscheck@v0.13.0
  with:
    emit-badges: 'true'
    badges-out-dir: 'badges'

This uploads a hasscheck-badges artifact. To embed in your README, publish the JSON files somewhere publicly accessible (e.g. committed to your repo or hosted on GitHub Pages).

Embed in README

Replace OWNER/REPO/main with your repository path:

![HACS Structure](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/OWNER/REPO/main/badges/hacs_structure.json)
![Config Flow](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/OWNER/REPO/main/badges/modern_ha_patterns.json)
![Diagnostics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/OWNER/REPO/main/badges/diagnostics_repairs.json)
![Tests & CI](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/OWNER/REPO/main/badges/tests_ci.json)
![HassCheck](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/OWNER/REPO/main/badges/hasscheck.json)

Badges show the current state of your integration: Passing, Partial, or Issues. For Config Flow and Diagnostics, suffixes are Present or Missing.

HassCheck is unofficial and not affiliated with Home Assistant, HACS, or Nabu Casa. Security Review: Not performed. HACS Acceptance: Not guaranteed.

Install

pip install hasscheck

Or with uv:

uv tool install hasscheck

Requires Python ≥ 3.12.

Install for local development

This repository uses uv for dependency management.

uv sync

Run the CLI without installing globally:

.venv/bin/python -m hasscheck --help

Commands

Check a repository

.venv/bin/python -m hasscheck check --path .

Emit JSON

.venv/bin/python -m hasscheck check --path . --format json

Print the JSON schema

.venv/bin/python -m hasscheck schema

Skip config file

.venv/bin/python -m hasscheck check --path . --no-config

Explain a rule

.venv/bin/python -m hasscheck explain manifest.domain.exists

Scaffold a GitHub Actions workflow

.venv/bin/python -m hasscheck scaffold github-action --path .

Scaffold a diagnostics.py starter

.venv/bin/python -m hasscheck scaffold diagnostics --path .

Scaffold a repairs.py starter

.venv/bin/python -m hasscheck scaffold repairs --path .

Use --dry-run to preview without writing, --force to overwrite an existing file.

Configuration

HassCheck reads hasscheck.yaml at the repository root when present.

The file supports two separate kinds of user intent:

  1. Project applicability context — declare project-level facts once, so selected rules can return not_applicable without repetitive per-rule overrides.
  2. Per-rule overrides — mark specific RECOMMENDED rules as not_applicable or manual_review with a written reason.
# hasscheck.yaml
schema_version: "0.4.0"

applicability:
  supports_diagnostics: false
  has_user_fixable_repairs: false
  uses_config_flow: false

rules:
  repo.license.exists:
    status: manual_review
    reason: License decision pending before public release.

Rules for project applicability:

  • Flags only explain intentionally missing optional signals.
  • Natural pass findings still win — existing files are not hidden by stale config.
  • Correctness failures stay locked. For example, uses_config_flow: false does not hide a config_flow.py / manifest.json mismatch.
  • Applied decisions are disclosed in JSON as summary.applicability_applied and marked in terminal findings with (config).

Rules for overrides:

  • status must be not_applicable or manual_review — you cannot force a finding to pass.
  • reason is required — it is the audit trail.
  • REQUIRED rules (e.g. manifest.exists) cannot be overridden.
  • Run hasscheck explain <rule-id> to check if a rule is overridable.
  • Use --no-config to ignore hasscheck.yaml (useful for CI debugging).

See hasscheck.example.yaml in this repository for a full annotated example. See docs/architecture/config-file.md and docs/architecture/project-applicability-context.md for the design rationale.

Finding statuses

HassCheck findings use explicit statuses instead of a single global certification score.

Status Meaning
pass The signal was found.
warn The signal is missing or incomplete, but should not block every project.
fail The repository has an internally inconsistent or required metadata problem.
not_applicable The rule does not apply yet or cannot be evaluated from current context.
manual_review Human judgment is needed.

Example terminal output

HassCheck Summary

Diagnostics/Repairs: 2 / 2
Docs/Support: 1 / 1
HACS Structure: 3 / 3
Maintenance Signals: 1 / 1
Manifest Metadata: 7 / 7
Modern HA Patterns: 2 / 2
Tests/CI: 2 / 2

Overall: Informational only
Security Review: Not performed
Official HA Tier: Not assigned
HACS Acceptance: Not guaranteed

The exact category order may change as rules evolve. The JSON schema is the durable contract.

Documentation

Per-rule documentation pages with status behavior tables, fix instructions, and examples: docs/rules/.

Current rule set

HACS structure

Rule ID Signal
hacs.custom_components.exists Repository has custom_components/.
hacs.file.parseable Repository has parseable hacs.json.
brand.icon.exists Integration has custom_components/<domain>/brand/icon.png.

Manifest metadata

Rule ID Signal
manifest.exists Integration has manifest.json.
manifest.domain.exists Manifest defines domain.
manifest.domain.matches_directory Manifest domain matches the integration directory name.
manifest.name.exists Manifest defines name.
manifest.version.exists Manifest defines version.
manifest.documentation.exists Manifest defines documentation.
manifest.issue_tracker.exists Manifest defines issue_tracker.
manifest.codeowners.exists Manifest defines non-empty codeowners.
manifest.iot_class.exists Manifest declares iot_class.
manifest.iot_class.valid Manifest iot_class is a recognized value.
manifest.integration_type.exists Manifest declares integration_type.
manifest.integration_type.valid Manifest integration_type is a recognized value.
manifest.requirements.is_list Manifest requirements is a JSON array.
manifest.requirements.entries_well_formed Manifest requirements entries are valid PEP 508 specifiers.
manifest.requirements.no_git_or_url_specs Manifest requirements contains no git/URL install specs.

Modern Home Assistant patterns

Rule ID Signal
config_flow.file.exists Integration has config_flow.py.
config_flow.manifest_flag_consistent config_flow.py and manifest config_flow: true agree.
config_flow.user_step.exists config_flow.py defines async_step_user (AST inspection).
config_flow.reauth_step.exists config_flow.py defines async_step_reauth or async_step_reauth_confirm (AST inspection).
config_flow.reconfigure_step.exists config_flow.py defines async_step_reconfigure (AST inspection).
config_flow.unique_id.set config_flow.py calls async_set_unique_id (AST inspection).
config_flow.connection_test A discovery-flow step awaits a non-plumbing call (AST heuristic).
init.async_setup_entry.defined __init__.py defines async_setup_entry (AST inspection).
init.runtime_data.used __init__.py accesses entry.runtime_data (HA 2024.4+ pattern, AST inspection).
entity.unique_id.set At least one entity platform sets _attr_unique_id (AST inspection).
entity.has_entity_name.set At least one entity platform sets _attr_has_entity_name = True (AST inspection).
entity.device_info.set At least one entity platform sets _attr_device_info or returns DeviceInfo (AST inspection).

Diagnostics and repairs

Rule ID Signal
diagnostics.file.exists Integration has diagnostics.py.
diagnostics.redaction.used diagnostics.py uses async_redact_data or a local redaction helper (AST inspection).
repairs.file.exists Integration has repairs.py.

Docs and maintenance

Rule ID Signal
docs.readme.exists Repository has a README.
docs.installation.exists README contains an Installation section (HACS or manual).
docs.configuration.exists README contains a Configuration / Setup section.
docs.troubleshooting.exists README contains a Troubleshooting / FAQ / Support section.
docs.removal.exists README contains a Removal / Uninstall section.
docs.privacy.exists README addresses privacy / data / cloud / local handling.
docs.examples.exists README contains an Examples or Usage section.
docs.supported_devices.exists README lists supported devices, services, hardware, or compatibility.
docs.limitations.exists README documents limitations, caveats, or restrictions.
docs.hacs_instructions.exists README contains HACS or custom repository installation instructions.
repo.license.exists Repository has a license file.

Tests and CI

Rule ID Signal
tests.folder.exists Repository has tests/.
tests.config_flow.detected tests/ contains config flow test coverage (filename, import, or function name).
tests.setup_entry.detected tests/ references async_setup_entry or async_unload_entry.
tests.unload.detected tests/ references async_unload_entry or unload test functions.
ci.github_actions.exists Repository has .github/workflows/*.yml or .yaml.

Maintenance

Rule ID Signal
maintenance.recent_commit.detected HEAD commit is within the last 12 months (local git history).
maintenance.recent_release.detected Most recent version tag is within the last 12 months (local git tags).
maintenance.changelog.exists Repository has a changelog file (CHANGELOG.md, HISTORY.md, etc.).

JSON report contract

JSON output includes:

  • schema_version
  • tool metadata
  • project metadata
  • ruleset metadata
  • category summaries
  • config disclosure summaries (overrides_applied and applicability_applied)
  • findings with rule IDs, rule versions, statuses, applicability, source URLs, and fix suggestions

Example:

.venv/bin/python -m hasscheck check --path examples/good_integration --format json

Use hasscheck schema to inspect the full report schema.

Development

Run tests:

.venv/bin/python -m pytest -q

Run HassCheck against the good fixture:

.venv/bin/python -m hasscheck check --path examples/good_integration

Run HassCheck against the current repository:

.venv/bin/python -m hasscheck check --path .

Release process

Releases are source-only GitHub Releases created from version tags.

Before tagging a new version, make sure all version declarations match pyproject.toml:

.venv/bin/python scripts/check_version.py

Then run the release checks:

.venv/bin/python -m pytest -q
.venv/bin/python -m hasscheck check --path examples/good_integration
.venv/bin/python -m hasscheck check --path examples/good_integration --format json
.venv/bin/python -m hasscheck schema
.venv/bin/python -m hasscheck explain manifest.domain.exists

Then create and push an annotated version tag:

git tag -a vX.Y.Z -m "vX.Y.Z — short release summary"
git push origin vX.Y.Z

Pushing a tag that matches v*.*.* triggers the release workflow. The workflow creates a GitHub Release for that tag with generated notes and a source-only artifact notice.

Pushing the tag also triggers the pypi-publish job, which builds the package and publishes it to PyPI via GitHub OIDC trusted publishing (no stored tokens required).

Non-goals

HassCheck does not attempt:

  • Security certification
  • Official Home Assistant quality tier assignment
  • HACS acceptance guarantees
  • Runtime testing against physical devices
  • Full semantic correctness checks
  • Public crawling or ranking of random repositories
  • Automatic PRs to third-party repos
  • Source-code auto-detection of project applicability
  • Multi-integration repository support

Philosophy

HassCheck should say:

Automated checks found these quality signals.

Not:

This integration is certified, safe, approved, or officially ready.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hasscheck-0.15.6.tar.gz (1.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hasscheck-0.15.6-py3-none-any.whl (133.1 kB view details)

Uploaded Python 3

File details

Details for the file hasscheck-0.15.6.tar.gz.

File metadata

  • Download URL: hasscheck-0.15.6.tar.gz
  • Upload date:
  • Size: 1.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hasscheck-0.15.6.tar.gz
Algorithm Hash digest
SHA256 b4dd5b56143da5482a2c6238143a2db3a419975cce0df3a765a0cf5a0e3f7e9a
MD5 1d73d26a32a5cc6e13b531fe47e312cb
BLAKE2b-256 57ef5e4b96deb3327a39b830fe66dafc6f12f93280078aea62a67f9301de9cde

See more details on using hashes here.

Provenance

The following attestation bundles were made for hasscheck-0.15.6.tar.gz:

Publisher: release.yml on Daily-Nerd/hasscheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hasscheck-0.15.6-py3-none-any.whl.

File metadata

  • Download URL: hasscheck-0.15.6-py3-none-any.whl
  • Upload date:
  • Size: 133.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for hasscheck-0.15.6-py3-none-any.whl
Algorithm Hash digest
SHA256 30f39333730f03aac2533f56b3e881842ed773410d6694cf8d71f347f4185426
MD5 3216cb94762a43a7d25fcd8960676341
BLAKE2b-256 adc3ac26b0b12c24f915690881364f1899bb04c76c53dfe9b598bf047fbdf3a0

See more details on using hashes here.

Provenance

The following attestation bundles were made for hasscheck-0.15.6-py3-none-any.whl:

Publisher: release.yml on Daily-Nerd/hasscheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page