# Home Assistant Supervisor: the API layer that runs your home as containers

> The Python service behind Home Assistant OS, responsible for installing and updating software, network settings and hardware access. Its release notes are a running record of container hardening work.

**home-assistant/supervisor** — :house_with_garden: Home Assistant Supervisor

- Repository: https://github.com/home-assistant/supervisor
- Website: https://home-assistant.io/hassio/
- Stars: 2,235 · Forks: 808
- Language: Python
- License: Apache-2.0
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/home-assistant-supervisor

## A container operating system with an API in front

The README calls the Supervisor the first private cloud solution for home automation, which is a marketing phrase that turns out to be a fair description once you read the mechanics. Home Assistant, formerly Hass.io, is a container-based system for managing a Home Assistant Core installation and the applications around it. The system is controlled via Home Assistant, which communicates with the Supervisor, and the Supervisor provides an API to manage the installation.

The API surface named in the README is short and telling: changing network settings, and installing and updating software. That is the whole job description. Core is one container among others, add-ons are containers, and the thing that decides which version of what runs, and what the host's network looks like, is this Python service sitting underneath.

The repository is Apache-2.0 licensed, written in Python, on a main branch, not archived, last pushed on 2026-09-28. The pyproject.toml describes it more plainly than the README does, calling it an open-source private cloud OS for Home-Assistant based on HassOS, and the repository topics are docker, orchestrator, home-automation, home-assistant and python. The homepage for both this repository and the add-ons repository is the same hassio page on home-assistant.io.

## Releases move through four stages and one JSON file

The release section of the README is short and it is the most operationally useful paragraph in the file. Releases are done in stages, called channels, and the sequence is explicit.

Pull requests merge to `main`. A new build is pushed to the `dev` stage. Releases are published. A new build is pushed to the `beta` stage. The file `stable.json` is updated, and that update promotes the build previously sitting on beta to stable. That `stable.json` file does not live in this repository at all; it lives in the home-assistant/version repository, which means the decision about what stable means is made in a separate project.

The naming convention makes the cadence legible. Recent releases are 2026.09.3 on 2026-09-17, 2026.09.2 on 2026-09-15 and 2026.09.1 on 2026-09-14, so patches ship within days rather than on a monthly boundary. Three point releases in four days is a project shipping fixes as they land, which is consistent with what those releases contain.

There is also a contribution policy worth noting before writing code. The README says small changes and bug fixes can go straight through the normal flow, but for significant changes you should open an RFC first. Development instructions are on the developer documentation site rather than in the repository.

## Container hardening you can read in the notes

The most substantive thing in these releases is not features. It is a narrowing of what app containers are permitted to do, and it is specific enough to evaluate.

Release 2026.09.3 adds a feature flag to drop NET_RAW from app containers, and separately adds MKNOD, AUDIT_WRITE and SETFCAP capabilities along with a feature flag to drop those from apps. Those are Linux capabilities: NET_RAW allows raw socket access, MKNOD allows creating device nodes, SETFCAP allows changing file capabilities, and AUDIT_WRITE allows writing to the audit subsystem. Granting an add-on the ability to create device nodes is what lets a Zigbee or Z-Wave radio app reach a USB stick, so removing them is not free. Shipping them behind a feature flag is how the project manages that trade: the default can tighten while installations that need the old behavior keep working until they update their configuration.

The same release fixes two things that read like security bugs. One stops rejected AppArmor profile files from being left behind in the store directory, so a failed profile enforcement does not leave residue that later logic might pick up. Another changes AppArmor profile rejections to be modeled as API errors rather than something handled quietly inside the agent, which means a caller receives the rejection instead of a successful-looking response.

Release 2026.09.1 adds a `/time` API for setting NTP servers on Home Assistant OS and hides that new host feature from the v1 `/host/info` features field, so older clients are not offered a capability they cannot use. Release 2026.09.2 fixes the Core API proxy to forward paths byte-for-byte and to match deny rules against the decoded path. Taken together, these read as an application whose security boundary is code rather than policy document, and it is being tightened release by release.

## One container image built on s6, uv and Alpine

The Dockerfile shows how the Supervisor is packaged, and the base image line is the first thing worth noting:

```dockerfile
ARG BUILD_FROM=ghcr.io/home-assistant/base-python:3.14-alpine3.24-2026.06.1
FROM ${BUILD_FROM} AS supervisor-base
```

The build is a multi-stage one. A base stage installs Alpine packages including openssl, libpulse, yaml, git and eudev, then installs uv. A build stage copies requirements.txt and the wheels directory, and uses uv to install dependencies with bytecode compilation and no build isolation, preferring local musllinux wheels when they are present and falling back to the index when they are not. The final stage receives the source, which is why the tree has a `wheels/` directory at all.

The environment block is telling about what this process expects to supervise. `S6_SERVICES_GRACETIME` and `S6_KILL_GRACETIME` mean the container runs under the s6 process supervision suite, so the Supervisor is itself a supervised process that supervises others. `SUPERVISOR_API=http://localhost` sets its own API address. `CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1` disables legacy OpenSSL algorithms in the cryptography library, which is the kind of setting that exists because something once went wrong.

There is a `.hadolint.yaml` at the repository root, so Dockerfile linting is part of the definition of done, and a `.dockerignore` alongside it.

## Fully pinned dependencies and a Python 3.14 floor

The project requires Python 3.14 or newer, and both pyproject.toml and the Dockerfile agree on it. The dependencies are not ranges in a lockfile, they are exact pins in requirements.txt, one per line:

```text
aiodocker==0.27.0
aiohttp==3.14.3
voluptuous==0.16.0
```

There are thirty of them, and the list is short enough to read as a description of the job. aiodocker and aiodns are the Docker and DNS clients. aiohttp is the HTTP layer. attrs and awesomeversion handle object modelling and version comparison. cryptography is there for the encrypted backup path, since one release fixed supervisor config restore from encrypted backups. deepmerge merges configuration dictionaries. gitpython backs the Git-based integrations. jinja2 renders templates. pyudev watches device changes, which is how USB radio adapters are noticed. pulsectl handles audio, sentry-sdk reports errors, and securetar handles tar extraction for update archives.

The build metadata is explicit about why the pins are exact. setup.py reads requirements.txt and passes its lines straight to setuptools as dependencies, and it derives the version from a `SUPERVISOR_VERSION` constant in `supervisor/const.py` with a regex that accepts either a 40 character git SHA or a plain version string. When it finds a SHA it assembles a dev version of the form `9999.09.9.dev9999` with the SHA appended. So a build from source reports itself as a development build rather than pretending to be a release.

Around that sits ordinary Python project infrastructure: a tox.ini for test environments, a pre-commit config, codecov configuration, ruff and pylint configuration in pyproject.toml, and separate requirements_tests.txt.

## What the README declines to explain

The README is short because installation happens elsewhere. The Installation section is one sentence pointing at https://home-assistant.io/getting-started. That is the correct place for it, since the Supervisor is normally installed as part of an operating system image rather than by running anything from this repository, and the target audience is someone setting up a machine rather than someone integrating a library.

What a developer would want is on the developer documentation site, at developers.home-assistant.io/docs/supervisor/development. The repository itself is the second half of the answer, and its shape is informative. The `supervisor/` directory holds the application, `tests/` holds the test suite, `rootfs/` holds the filesystem the container manages, and `script/` holds helper scripts.

The root of the repository also documents how work on it is expected to happen. There is an AGENTS.md, a CLAUDE.md and an AI_POLICY.md, which together say something specific about this project's approach to automated contributions and to coding assistants. There is a .devcontainer/ and a .vscode/ for a defined development environment, and a .vcnignore alongside them.

What is not in the README is equally worth naming. There is no API reference, no list of endpoints beyond the passing mention of `/time` in a release note, no statement of which ports the Supervisor listens on, and no documentation of the backup format that the encrypted restore fix implies exists. Anyone integrating against this API is working from the source and the release history rather than from a specification.

## Conclusion

The Supervisor is the component you accept rather than choose: on Home Assistant OS it sits between the frontend and everything running as a container, and its API decides what gets installed and updated. Its release process is the part worth understanding, because the sequence from main to dev to beta to stable, with the promotion controlled by one file in another repository, means a given build reaches your machine on someone else's schedule. The security work in the notes is concrete rather than aspirational, with Linux capabilities dropped from app containers behind feature flags and AppArmor profiles enforced as API errors. If you run Core directly in a virtual environment instead, you are giving up the update and network management layer, and the README confirms that installing the Supervisor means going through the Home Assistant getting-started instructions rather than any command in this repository.

## FAQ

### What does the Home Assistant Supervisor do?

It manages the container-based system around a Home Assistant Core installation and exposes an API for it. The README names changing network settings and installing and updating software as the two management jobs, with Home Assistant itself acting as the control surface that talks to the Supervisor.

### How does the Supervisor release process work?

Pull requests merge to main, a build is pushed to the dev stage, releases are published, another build goes to beta, and then the stable.json file is updated, which promotes the beta build to stable. That stable.json file lives in the separate home-assistant/version repository. Recent point releases such as 2026.09.1, 2026.09.2 and 2026.09.3 shipped within days of each other.

### How does the Supervisor limit what add-on containers can do?

It works through Linux capabilities and AppArmor. Release 2026.09.3 added feature flags to drop NET_RAW from app containers and to drop MKNOD, AUDIT_WRITE and SETFCAP, while also fixing a bug that left rejected AppArmor profile files in the store directory and changing profile rejections into API errors. The flags exist because features such as Zigbee and Z-Wave radios do need device node access.

### How do I install the Home Assistant Supervisor?

The README does not give a command for it. Installation instructions are on the Home Assistant getting-started page at https://home-assistant.io/getting-started, because the Supervisor is normally installed as part of Home Assistant OS rather than from this repository. Contributor setup is separate, on the developer documentation site.

## Sources

- [home-assistant/supervisor on GitHub](https://github.com/home-assistant/supervisor)
- [License: Apache-2.0](https://github.com/home-assistant/supervisor/blob/main/LICENSE)
- [Project website](https://home-assistant.io/hassio/)
- [README](https://github.com/home-assistant/supervisor/blob/main/README.md)
- [Releases](https://github.com/home-assistant/supervisor/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/home-assistant-supervisor
