Skip to main content

ha-deploy-kit

A small, reusable library for deploying a Home Assistant custom integration's code to a running HA host over SSH, and (optionally) wiring the HA-side restart notification. The core is Home-Assistant-free and standard-library only, so a deploy script can import it without pulling in Home Assistant; the HA adapter is a separate, explicitly-imported subpackage.

One process can deploy several integrations without cross-talk: all per-consumer state lives in a frozen DeploySettings passed by argument — no module globals and no os.environ mutation.

What it does

  • Builds a content-hash inventory of your custom_components/<domain> tree and compares it to the remote tree, deploying only the changed files.
  • Leaves remote-only files untouched (never deletes on the host).
  • Streams files over SSH with an uncompressed, path-validated tar — no backups, no lock files, no rollback, no auto-restart.
  • Optionally publishes a separately-served Lovelace card.
  • Optionally raises a Home Assistant Repairs issue (via an HA service) telling the user a restart is needed. The engine never restarts HA itself; restart is opt-in and happens only when a user confirms a Repairs fix flow.

Install

Published on PyPI. Pin an exact version.

pip install "ha-deploy-kit==0.1.0"

The HA adapter needs Home Assistant, which is an optional extra:

pip install "ha-deploy-kit[ha]==0.1.0"
  • Core requires Python 3.10+ and only the standard library (plus a CA trust store: certifi/truststore).
  • The ha adapter requires the Python version Home Assistant itself requires; install it in the HA runtime, not in your deploy tooling.
  • Home Assistant integrations must pin a versioned PyPI requirement ("ha-deploy-kit==0.1.0" in manifest.json), never a git+… VCS URL — HA installs requirements in its own credential-less environment and treats URL requirements as never-satisfied, retrying every startup.

See docs/install.md for pyproject.toml, HA manifest.json, and air-gapped host instructions, and docs/releasing.md for how releases are published.

Public API

Symbol Import Purpose
DeploySettings ha_deploy_kit Frozen per-consumer settings (domain, source root, remote config, optional frontend, timeouts).
FrontendAsset ha_deploy_kit Optional served-card mapping (source_rel, published_remote).
DeployError ha_deploy_kit Raised for recoverable, sanitized deployment errors.
run(settings, argv, ssh=None, environ=None) ha_deploy_kit.cli Orchestrate end to end: compare, report, publish the changed card, deploy the changed backend, notify. Honors a REMOTE_CONFIG env override.
raise_restart_issue(base_url, token, settings) ha_deploy_kit.notify POST to the HA restart service; returns a sanitized status string.
frontend_run(settings, plan, ssh, *, check) ha_deploy_kit.frontend Deploy the card into the tree and/or publish the served copy.
ha.async_register_restart_service(hass, domain, ...) ha_deploy_kit.ha Idempotently register the restart service (empty schema). Pass fixable=True for a one-click Repairs card (pair with the fix flow).
ha.async_raise_restart_issue(hass, domain, ...) ha_deploy_kit.ha Raise the deduplicated, non-persistent restart Repairs issue.
ha.async_clear_restart_issue(hass, domain, ...) ha_deploy_kit.ha Clear the restart issue.
ha.async_create_restart_fix_flow(hass, issue_id, ...) ha_deploy_kit.ha Optional opt-in confirm-and-restart flow (shows a confirmation dialog; restart only when the user submits it).
ha.register_card_serving(hass, domain, lovelace_dir, card_url) ha_deploy_kit.ha Serve the card and register it as a frontend module.

CLI

The package installs a ha-deploy console script. It deploys by default; pass --check (or its alias --dry-run) to preview without writing anything.

ha-deploy                 # deploy changed backend files, then notify
ha-deploy --check         # compare and report only; no writes, no notify
ha-deploy --root /path/to/your/repo

The source root is resolved from --root, then HA_DEPLOY_SOURCE_ROOT, then the current directory. The domain is read from HA_DEPLOY_DOMAIN, or inferred when the root has exactly one custom_components/<domain> subdirectory.

One-liner for your own deploy script

run is fully frontend-aware, so a consumer's deploy.py is just settings + a call — no pipeline to copy. It publishes a changed card and deploys a changed backend; a frontend-only change publishes the card but never notifies a restart.

import sys
from pathlib import Path

from ha_deploy_kit import DeploySettings, FrontendAsset
from ha_deploy_kit.cli import run

settings = DeploySettings(
    domain="your_domain",
    source_root=Path(__file__).resolve().parent,
    frontend=FrontendAsset(  # omit entirely for backend-only
        source_rel="lovelace/your-card.js",
        published_remote="www/your_domain/your-card.js",
    ),
)
raise SystemExit(run(settings, sys.argv[1:]))

TARGET/HA_BASE_URL/HA_TOKEN and an optional REMOTE_CONFIG override come from .env or the process environment; run applies REMOTE_CONFIG for you.

See docs/configuration.md for settings and .env, and docs/adopting.md for a step-by-step adoption guide.

Design notes

This library deliberately differs from typical hand-rolled HA deploy scripts. Each choice below is intentional:

  • No positional target and no --restart / --no-restart / --card-only flags. The target comes from the environment; the engine never restarts HA, so there is no restart flag to pass.
  • The engine never executes a restart. It can only raise a Repairs issue; the actual restart is opt-in behind a user-confirmed fix flow.
  • A frontend-only change never notifies a backend restart. Backend and frontend are separate concerns.
  • Structured remote inventory. The remote probe returns an explicit four-field result (hashes, stale files, a missing-tree flag, published hash) rather than guessing from text.
  • Environment precedence is explicit. Process environment overrides .env; the library never mutates os.environ.
  • Path validation. Tar members are rejected if absolute, containing .., NUL, or newlines, or escaping the component directory.
  • No backups, lock files, rollback, or auto-restart, and tokens, raw bodies, and secret-bearing errors are never printed. TLS and SSH verification are never weakened.
  • Real CA trust store for the notification. The HTTPS call to Home Assistant verifies against the OS trust store via truststore (matching curl), falling back to certifi then the stdlib default — all strictly verifying (CERT_REQUIRED + hostname check). This avoids misreporting a valid cert as tls-error on platforms whose default context has no usable CA store (macOS, python.org, fresh venvs); tls-error is reserved for genuine failures.

Releases

Releases are automated: every merge to main runs semantic-release, which picks the next version from the Conventional Commit messages (fix: → patch, feat: → minor, feat!:/BREAKING CHANGE: → major; docs:/chore:/test: publish nothing) and publishes to PyPI via Trusted Publishing. Write PR titles/commits in that form. See docs/releasing.md for the one-time setup and the manual fallback.

Metadata

Release files for ha-deploy-kit 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ha-deploy-kit 0.1.3
File Size Uploaded Provenance Actions
ha_deploy_kit-0.1.3.tar.gz 44.7 kB With provenance Details for ha_deploy_kit-0.1.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ha-deploy-kit 0.1.3
File Interpreter ABI Platform Actions
ha_deploy_kit-0.1.3-py3-none-any.whl Python 3 none any Details for ha_deploy_kit-0.1.3-py3-none-any.whl

Total release size: 68.7 kB

Release files / ha_deploy_kit-0.1.3.tar.gz

Download URL ha_deploy_kit-0.1.3.tar.gz
Size 44.7 kB
Tags Source
SHA-256 checksum
How to use checksums
c1359ce7da54cbd998f05c96a69c7c4119561b76f9a2efa9208f38214af13b63
BLAKE2b-256 checksum
How to use checksums
96133afc7f8e7818150c537a2ac617d465a80cf0b245b71dcd5f873b4fa7e4ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Release files / ha_deploy_kit-0.1.3-py3-none-any.whl

Download URL ha_deploy_kit-0.1.3-py3-none-any.whl
Size 24.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c25a6195086643e91c100a2225822fd7d9dd287f2f2c50e2352568d5d8f272e2
BLAKE2b-256 checksum
How to use checksums
af4f7ff61e36bb79849bdf31d17635f0a32d9cf8786a0fdbce9f175d9a30fc69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Security for ha-deploy-kit 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ha_deploy_kit-0.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page