# Home Assistant Operating System — Administrator & Developer Guide

## 1. Architecture Overview

Home Assistant Operating System (HAOS) is a Buildroot-based Linux distribution purpose-built to host the Home Assistant ecosystem. It provides a minimal, hardened, and fully managed OS that boots directly into a Docker-based service stack running the Home Assistant Supervisor, Core, and add-ons.

### Design Philosophy

HAOS is not a general-purpose Linux distribution. It is an appliance OS:

- The root filesystem is read-only (squashfs/erofs)
- User data lives on a separate data partition (`/mnt/data`)
- Configuration persistence uses bind mounts from the data partition to `/etc` paths
- System updates are atomic A/B slot swaps via RAUC — no package manager
- All user-facing services (Home Assistant, add-ons) run as Docker containers
- The OS handles only hardware, networking, storage, and container orchestration

### Architecture Diagram

```text
┌─────────────────────────────────────────────────────────────┐
│                        User Browser                         │
│                    homeassistant.local:8123                  │
└──────────────────────────┬──────────────────────────────────┘
                           │
┌──────────────────────────┴──────────────────────────────────┐
│                    Docker (containerd)                       │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐│
│  │  Supervisor   │ │     Core     │ │   Add-ons (DNS,     ││
│  │  (hassio_     │ │  (home-      │ │   Audio, CLI,       ││
│  │  supervisor)  │ │  assistant)  │ │   Observer, etc.)   ││
│  └──────┬───────┘ └──────────────┘ └──────────────────────┘│
│         │  manages all containers                           │
└─────────┼───────────────────────────────────────────────────┘
          │
┌─────────┴───────────────────────────────────────────────────┐
│                  HAOS (Buildroot Linux)                      │
│  ┌────────────┐ ┌──────────────┐ ┌────────────────────────┐│
│  │ systemd    │ │ NetworkMgr   │ │ RAUC (OTA updates)     ││
│  │ services   │ │ (networking) │ │ A/B slot management    ││
│  └────────────┘ └──────────────┘ └────────────────────────┘│
│  ┌────────────┐ ┌──────────────┐ ┌────────────────────────┐│
│  │ AppArmor   │ │ os-agent     │ │ zRAM / swap           ││
│  │ (security) │ │ (D-Bus API)  │ │ (memory management)   ││
│  └────────────┘ └──────────────┘ └────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
          │
┌─────────┴───────────────────────────────────────────────────┐
│                   Disk Partition Layout                      │
│  boot │ kernel.0 │ system.0 │ kernel.1 │ system.1 │ data   │
│  (FAT)│  (A)     │  (A)     │  (B)     │  (B)     │ (ext4) │
└─────────────────────────────────────────────────────────────┘
```

### Component Inventory

| Component | Path / Package | Role |
|---|---|---|
| Buildroot | `buildroot/` (git submodule) | Cross-compilation build system |
| Buildroot External | `buildroot-external/` | HAOS-specific packages, configs, overlays |
| Board Support | `buildroot-external/board/` | Per-hardware boot config, kernel configs, hooks |
| Package Definitions | `buildroot-external/package/` | Custom packages (os-agent, hassio, drivers, etc.) |
| Root FS Overlay | `buildroot-external/rootfs-overlay/` | Systemd units, config files, shell scripts |
| Kernel Configs | `buildroot-external/kernel/` | Kernel fragment configs per version |
| OTA/RAUC | `buildroot-external/ota/` | RAUC system config, signing certificates, hooks |
| Image Generation | `buildroot-external/genimage/` | Disk image layout configs |
| Boot Configuration | `buildroot-external/bootloader/` | U-Boot config, MBR images |
| Build Configs | `buildroot-external/configs/` | Buildroot defconfigs per board |
| Patches | `buildroot-external/patches/` | Patches for upstream packages (Docker, systemd, GRUB, etc.) |
| Build Scripts | `buildroot-external/scripts/` | Post-build, post-image, and utility scripts |
| Tests | `tests/` | Smoke tests and Supervisor integration tests (labgrid + pytest) |
| Container Scripts | `scripts/` | Development helpers (enter.sh, update scripts) |

### Technology Stack

| Layer | Technology | Version / Notes |
|---|---|---|
| Build system | Buildroot | Git submodule, cross-compilation |
| Init system | systemd | PID 1, service management, journald |
| Container runtime | Docker + containerd | Containerd snapshotter backend |
| Networking | NetworkManager | Wi-Fi, Ethernet, VLAN, mDNS |
| DNS | systemd-resolved | Stub resolver, per-link DNS |
| OTA updates | RAUC | A/B slots, signed bundles, hooks |
| Bootloader | U-Boot (ARM) / GRUB (x86) | Per-board configuration |
| Security | AppArmor | Profiles for Supervisor containers |
| Filesystem | squashfs/erofs (system), ext4 (data) | Read-only system, read-write data |
| Memory | zRAM + swap file | Configurable sizes |
| D-Bus agent | os-agent | Host API for Supervisor communication |
| USB disk management | udisks2 | Data disk operations |

> [!NOTE]
> HAOS uses Buildroot (not Yocto/OpenEmbedded). Buildroot produces a complete cross-compiled root filesystem image from source. The `buildroot/` directory is a git submodule pinned to a specific Buildroot release, and `buildroot-external/` contains all HAOS customizations using Buildroot's external tree mechanism (`BR2_EXTERNAL`).

---

## 2. System Requirements

### Build Requirements

Building HAOS requires a Linux host (or Docker on any platform):

| Requirement | Minimum |
|---|---|
| OS | Linux (Ubuntu 22.04+ recommended) or Docker |
| Disk | 50+ GB free space |
| RAM | 4+ GB |
| Tools | `make`, `gcc`, `git`, `docker` (for containerized builds) |

The repository includes a `Dockerfile` for reproducible builds and a `Makefile` with board-specific targets.

### Test Requirements

The test suite (`tests/`) requires:

| Package | Version | Purpose |
|---|---|---|
| `labgrid` | 25.0.1 | Hardware/VM test automation framework |
| `pytest-dependency` | 0.6.1 | Test ordering and dependency chains |
| `pytest-timeout` | 2.4.0 | Per-test timeout enforcement |
| Python | 3.x (`.python-version` in `tests/`) | Test runner |

### Target Hardware Requirements

| Board Category | RAM | Storage | Architecture |
|---|---|---|---|
| Raspberry Pi 3/4/5 | 1–8 GB | 32+ GB SD/eMMC/NVMe | aarch64 |
| ODROID (C2/C4/M1/M1S/N2) | 2–4 GB | 32+ GB SD/eMMC | aarch64 |
| Khadas VIM3 | 2–4 GB | 32+ GB SD/eMMC | aarch64 |
| NabuCasa Green | 4 GB | 32 GB eMMC | aarch64 |
| Generic x86-64 | 2+ GB | 32+ GB SSD/NVMe | x86_64 |
| OVA (VM) | 2+ GB allocated | 32+ GB virtual disk | x86_64 |

---

## 3. Configuration Reference

### Partition Layout

HAOS uses a fixed partition scheme created by genimage during the build:

| Partition | Label | Filesystem | Mount Point | Purpose |
|---|---|---|---|---|
| Boot | `hassos-boot` | FAT32 | `/mnt/boot` | Bootloader, kernel, DTBs, config.txt |
| Kernel A | `hassos-kernel0` | raw | — | Kernel image (slot A) |
| System A | `hassos-system0` | squashfs/erofs | `/` (when active) | Root filesystem (slot A) |
| Kernel B | `hassos-kernel1` | raw | — | Kernel image (slot B) |
| System B | `hassos-system1` | squashfs/erofs | `/` (when active) | Root filesystem (slot B) |
| Bootstate | — | raw | — | RAUC boot status tracking |
| Overlay | `hassos-overlay` | ext4 | `/mnt/overlay` | Persistent overlay for `/etc` |
| Data | `hassos-data` | ext4 | `/mnt/data` | User data, Docker, add-ons, backups |

> [!IMPORTANT]
> The partition table type varies by board: GPT for UEFI systems (`hdimage-gpt.cfg`), hybrid MBR/GPT for some ARM boards (`hdimage-hybrid.cfg`), and pure MBR for legacy boards (`hdimage-mbr.cfg`). The genimage configs in `buildroot-external/genimage/` define the exact layout for each type.

### Disk Image Generation Configs

| Config File | Purpose |
|---|---|
| `genimage/genimage.cfg` | Top-level image assembly |
| `genimage/hdimage-gpt.cfg` | GPT partition table layout |
| `genimage/hdimage-hybrid.cfg` | Hybrid MBR/GPT layout |
| `genimage/hdimage-mbr.cfg` | MBR partition table layout |
| `genimage/images-boot.cfg` | Boot partition image |
| `genimage/images-os.cfg` | OS (system) partition image |
| `genimage/image-raucb-spl.cfg` | RAUC bundle with SPL |
| `genimage/image-raucb-nospl.cfg` | RAUC bundle without SPL |

### Systemd Service Units

HAOS defines a comprehensive set of systemd services in `buildroot-external/rootfs-overlay/usr/lib/systemd/system/`:

#### Core OS Services

| Unit | Type | Purpose |
|---|---|---|
| `hassos-config.service` | oneshot | Reads and applies user configuration from `/mnt/config` |
| `hassos-data.service` | oneshot | Initializes data partition structure |
| `hassos-expand.service` | oneshot | Expands data partition to fill disk on first boot |
| `hassos-overlay.service` | oneshot | Sets up persistent overlay for `/etc` |
| `hassos-persists.service` | oneshot | Persists certain runtime state across reboots |
| `hassos-supervisor.service` | service | Starts the Home Assistant Supervisor container |
| `hassos-apparmor.service` | oneshot | Loads AppArmor profiles |
| `hassos-bind.target` | target | Ordering target for bind mounts |
| `hassos-hardware.target` | target | Ordering target for hardware readiness |
| `hassos-zram.target` | target | Ordering target for zRAM setup |
| `hassos-user-rules-udev-trigger.service` | oneshot | Re-triggers udev for user-supplied rules |

#### Data and Storage Services

| Unit | Type | Purpose |
|---|---|---|
| `mnt-boot.mount` | mount | Mounts boot partition to `/mnt/boot` |
| `mnt-config.mount` | mount | Mounts config partition to `/mnt/config` |
| `mnt-data.mount` | mount | Mounts data partition to `/mnt/data` |
| `mnt-overlay.mount` | mount | Mounts overlay partition to `/mnt/overlay` |
| `var.mount` | mount | Mounts `/var` from data partition |
| `var-lib-docker.mount` | mount | Bind-mounts Docker data directory |
| `var-lib-bluetooth.mount` | mount | Bind-mounts Bluetooth state |
| `var-lib-NetworkManager.mount` | mount | Bind-mounts NetworkManager state |
| `var-lib-systemd.mount` | mount | Bind-mounts systemd persistent state |
| `var-log-journal.mount` | mount | Bind-mounts journal log directory |
| `root-.docker.mount` | mount | Bind-mounts Docker config for root |
| `root-.ssh.mount` | mount | Bind-mounts SSH config for root |
| `haos-data-disk-detach.service` | oneshot | Safely detaches external data disk |
| `haos-swapfile.service` | oneshot | Creates and activates swap file |
| `mnt-data-swapfile.swap` | swap | Swap file unit |

#### Persistent Bind Mounts

| Unit | Purpose |
|---|---|
| `etc-default.mount` | Persists `/etc/default` from data partition |
| `etc-dropbear.mount` | Persists Dropbear SSH host keys |
| `etc-hostname.mount` | Persists hostname |
| `etc-hosts.mount` | Persists hosts file |
| `etc-modprobe.d.mount` | Persists modprobe configuration |
| `etc-sysctl.d.mount` | Persists sysctl settings |
| `etc-systemd-timesyncd.conf.mount` | Persists time sync configuration |
| `etc-udev-rules.d.mount` | Persists user udev rules |
| `etc-usb_modeswitch.d.mount` | Persists USB modeswitch config |

#### Memory Management Services

| Unit | Type | Purpose |
|---|---|---|
| `zram-tmp.service` | oneshot | Creates zRAM-backed `/tmp` |
| `zram-var.service` | oneshot | Creates zRAM-backed `/var` |
| `haos-mglru.service` | oneshot | Enables Multi-Generation LRU for improved memory reclaim |
| `haos-swapfile.service` | oneshot | Manages swap file creation and activation |

#### Other Services

| Unit | Type | Purpose |
|---|---|---|
| `docker-prepare.service` | oneshot | Pre-start Docker preparation |
| `ha-cli@.service` | template | Home Assistant CLI service template |
| `haos-bt-cache.service` | oneshot | Bluetooth device cache management |
| `haos-bt-cache.timer` | timer | Timer for Bluetooth cache service |
| `haos-wipe.service` | oneshot | Factory reset / data wipe |
| `raucdb-update.service` | oneshot | Updates RAUC database |
| `systemd-journal-gatewayd.socket` | socket | Journal gateway for Supervisor log access |

> [!NOTE]
> Many upstream systemd services have drop-in overrides in subdirectories (e.g., `docker.service.d/`, `NetworkManager.service.d/`). These customize behavior without modifying the original unit files. For example, `docker.service.d/hassos.conf` sets Docker dependencies and resource limits, and `docker.service.d/failure.conf` configures restart behavior on failure.

### Systemd Presets

The file `buildroot-external/rootfs-overlay/usr/lib/systemd/system-preset/70-haos.preset` controls which services are enabled by default at boot.

### System Configuration Files

| File | Format | Purpose |
|---|---|---|
| `/etc/fstab` | fstab | Static filesystem mount table |
| `/etc/resolv.conf` | resolv | DNS resolver (stub to systemd-resolved) |
| `/etc/motd` | text | Message of the day for console login |
| `/etc/input-event-daemon.conf` | ini | Input event daemon configuration |
| `/etc/NetworkManager/NetworkManager.conf` | ini | NetworkManager main configuration |
| `/etc/bluetooth/main.conf` | ini | Bluetooth daemon configuration |
| `/etc/containerd/config.toml` | TOML | Containerd runtime configuration |
| `/etc/docker/daemon.json` | JSON | Docker daemon configuration |
| `/etc/systemd/coredump.conf` | ini | Core dump handling configuration |
| `/etc/systemd/journald.conf` | ini | Journal logging configuration |
| `/etc/systemd/logind.conf` | ini | Login manager configuration |
| `/etc/systemd/resolved.conf` | ini | DNS resolution configuration |
| `/etc/systemd/timesyncd.conf` | ini | Time synchronization configuration |

### Sysctl Settings

| File | Key Settings |
|---|---|
| `/usr/lib/sysctl.d/10-printk.conf` | Kernel print level tuning |
| `/usr/lib/sysctl.d/15-swappiness.conf` | Swap aggressiveness tuning |
| `/usr/lib/sysctl.d/20-network.conf` | Network buffer and connection tuning |
| `/usr/lib/sysctl.d/30-cp15barrier.conf` | ARM CP15 barrier workaround |
| `/usr/lib/sysctl.d/60-otbr-ancillary-buffer.conf` | OpenThread Border Router buffer tuning |

### System Configuration Overrides

| File | Purpose |
|---|---|
| `/usr/lib/systemd/system.conf.d/etc-environment-overrides.conf` | Environment variable overrides for all services |
| `/usr/lib/systemd/system.conf.d/watchdog.conf` | Hardware watchdog configuration |

### Tmpfiles Configuration

| File | Purpose |
|---|---|
| `/etc/tmpfiles.d/data.conf` | Data partition directory structure |
| `/etc/tmpfiles.d/nm.conf` | NetworkManager runtime directories |
| `/etc/tmpfiles.d/overlay.conf` | Overlay partition structure |

> [!TIP]
> To understand the full boot sequence, trace the systemd dependency chain starting from `hassos-data.service` → `hassos-expand.service` → `hassos-overlay.service` → `hassos-config.service` → `hassos-supervisor.service`. The bind mount units depend on `hassos-bind.target`, ensuring data is available before services that need persistent state.

---

## 4. Deployment & Scaling

### Building HAOS Images

#### Containerized Build (Recommended)

The repository includes a `Dockerfile` and `Makefile` for reproducible builds:

```bash
make <board_target>
```

Where `<board_target>` is one of the defconfig names in `buildroot-external/configs/`:

| Target | Board |
|---|---|
| `rpi3_64` | Raspberry Pi 3 (64-bit) |
| `rpi4_64` | Raspberry Pi 4 (64-bit) |
| `rpi5_64` | Raspberry Pi 5 (64-bit) |
| `yellow` | Home Assistant Yellow |
| `green` | NabuCasa Green |
| `odroid_c2` | ODROID-C2 |
| `odroid_c4` | ODROID-C4 |
| `odroid_m1` | ODROID-M1 |
| `odroid_m1s` | ODROID-M1S |
| `odroid_n2` | ODROID-N2/N2+ |
| `khadas_vim3` | Khadas VIM3 |
| `generic_x86_64` | Generic x86-64 (UEFI) |
| `generic_aarch64` | Generic AArch64 (UEFI) |
| `ova` | OVA (Virtual Machine) |

#### Build Process Flow

```text
make <target>
  → Docker container with Buildroot toolchain
    → BR2_EXTERNAL=buildroot-external
      → buildroot-external/configs/<target>_defconfig
        → Cross-compile kernel, packages, root filesystem
          → buildroot-external/scripts/post-build.sh
            → Root filesystem overlay applied
          → buildroot-external/scripts/post-image.sh
            → genimage creates disk image
            → RAUC bundle created (.raucb)
            → hassos-hook.sh (board-specific post-processing)
              → Compressed image (.img.xz) output
```

#### Development Shell

Enter the Buildroot build environment interactively:

```bash
scripts/enter.sh
```

This launches a Docker container with the build environment mounted, allowing direct access to Buildroot's `make menuconfig`, `make linux-menuconfig`, and other build system commands.

### Board Support Architecture

Each supported board has a directory under `buildroot-external/board/` containing:

| File | Purpose |
|---|---|
| `meta` | Board metadata (name, architecture, image type) |
| `cmdline.txt` | Kernel command line parameters |
| `hassos-hook.sh` | Build hook for board-specific image processing |
| `kernel.config` | Board-specific kernel configuration fragment |
| `uboot.config` | U-Boot configuration (ARM boards) |
| `uboot-boot.ush` / `uboot-boot64.ush` | U-Boot boot scripts |
| `boot-env.txt` | U-Boot environment variables |
| `config.txt` | Raspberry Pi firmware configuration (RPi boards only) |
| `grub.cfg` | GRUB configuration (x86 boards only) |

> [!NOTE]
> The `hassos-hook.sh` script for each board implements two functions: `hassos_pre_image()` (copies bootloader, DTBs, and firmware to the boot partition) and `hassos_post_image()` (post-processing like xz compression). The Raspberry Pi hook additionally enables 64-bit mode in `config.txt` for 64-bit board targets.

### Raspberry Pi-Specific Configuration

The Raspberry Pi boards use a shared base configuration with per-variant overrides:

```text
buildroot-external/board/raspberrypi/
├── config.txt              ← Shared RPi firmware config
├── cmdline.txt             ← Shared kernel command line
├── hassos-hook.sh          ← Shared build hook
├── kernel.config           ← Shared kernel config fragment
├── uboot-boot.ush          ← U-Boot script (32-bit)
├── uboot-boot64.ush        ← U-Boot script (64-bit)
├── uboot.config            ← U-Boot config
├── rpi3-64/meta            ← RPi 3 metadata
├── rpi4-64/meta            ← RPi 4 metadata
├── rpi5-64/                ← RPi 5 (has own cmdline, config, hook)
│   ├── cmdline.txt
│   ├── config.txt
│   ├── hassos-hook.sh
│   └── rootfs-overlay/usr/lib/rauc/
│       ├── cmdline.sh      ← RAUC cmdline update hook
│       └── rpi-tryboot.sh  ← RPi 5 tryboot mechanism
└── yellow/                 ← HA Yellow (CM4/CM5 carrier board)
    ├── config.txt
    ├── cmdline.txt
    ├── patches/            ← Yellow-specific kernel & U-Boot patches
    └── rootfs-overlay/     ← Yellow firmware (brcmfmac)
```

> [!IMPORTANT]
> The Raspberry Pi 5 uses a different boot mechanism (`tryboot`) instead of U-Boot for slot switching. The `rpi-tryboot.sh` RAUC hook script manages this. This is why `rpi5-64` has its own `hassos-hook.sh` separate from the shared RPi hook.

---

## 5. Operations

### OTA Update System (RAUC)

HAOS uses [RAUC](https://rauc.io/) for over-the-air updates with an A/B partition scheme.

#### RAUC Configuration

The RAUC system configuration template is at `buildroot-external/ota/system.conf.gtpl` and defines:

- Slot definitions (kernel.0, kernel.1, system.0, system.1)
- Keyring for bundle signature verification
- Status file location for boot tracking
- Bundle format and compatibility string

#### Signing Infrastructure

| File | Purpose |
|---|---|
| `buildroot-external/ota/rel-ca.pem` | Release signing CA certificate |
| `buildroot-external/ota/dev-ca.pem` | Development signing CA certificate |
| `buildroot-external/ota/provisioning-ca.pem` | Provisioning CA certificate |
| `buildroot-external/ota/manifest.raucm.gtpl` | RAUC manifest template |
| `buildroot-external/ota/rauc-hook` | RAUC installation hook script |
| `buildroot-external/scripts/rauc.sh` | RAUC bundle creation script |
| `buildroot-external/scripts/generate-signing-key.sh` | Key generation utility |

> [!WARNING]
> RAUC bundles are cryptographically signed. The three CA certificates (release, development, provisioning) form a trust chain. Only bundles signed with a trusted key are accepted for installation. Modifying or removing these certificates will break the OTA update mechanism.

#### Update Flow

```text
1. Supervisor checks version.home-assistant.io for updates
2. Downloads .raucb bundle for the board
3. RAUC verifies bundle signature against trusted CA chain
4. RAUC installs kernel + system to INACTIVE slot (A→B or B→A)
5. RAUC marks new slot as primary boot target
6. System reboots into new slot
7. If boot succeeds → new slot marked "good"
8. If boot fails → bootloader falls back to previous "good" slot
```

### Service Management

#### Supervisor Lifecycle

The Supervisor is managed by `hassos-supervisor.service`, which:

1. Depends on Docker being ready
2. Runs `/usr/sbin/hassos-supervisor` to start the Supervisor container
3. The Supervisor then manages all other containers (Core, add-ons, plugins)

The Supervisor container is tagged as `ghcr.io/home-assistant/{arch}-hassio-supervisor:latest` during the build process by `buildroot-external/package/hassio/dind-import-containers.sh`.

#### Key OS Scripts

| Script | Path | Purpose |
|---|---|---|
| `hassos-supervisor` | `/usr/sbin/hassos-supervisor` | Starts/manages the Supervisor container |
| `hassos-config` | `/usr/sbin/hassos-config` | Applies user configuration from `/mnt/config` |
| `hassos-cli` | `/usr/sbin/hassos-cli` | Host-level CLI entry point |
| `hassos-apparmor` | `/usr/libexec/hassos-apparmor` | Loads AppArmor profiles |
| `hassos-data` | `/usr/libexec/hassos-data` | Initializes data partition structure |
| `hassos-expand` | `/usr/libexec/hassos-expand` | Expands data partition to fill disk |
| `hassos-overlay` | `/usr/libexec/hassos-overlay` | Sets up persistent overlay |
| `hassos-persists` | `/usr/libexec/hassos-persists` | Persists runtime state |
| `hassos-zram` | `/usr/libexec/hassos-zram` | Configures zRAM devices |
| `haos-swapfile` | `/usr/libexec/haos-swapfile` | Manages swap file |
| `haos-wipe` | `/usr/libexec/haos-wipe` | Factory reset handler |
| `haos-freeze-hook` | `/usr/libexec/haos-freeze-hook` | Filesystem freeze hook for backups |
| `haos-data-disk-detach` | `/usr/libexec/haos-data-disk-detach` | Safe external disk detach |
| `docker-prepare` | `/usr/libexec/docker-prepare` | Pre-Docker startup preparation |
| `docker-disk-check` | `/usr/libexec/docker-disk-check` | Docker disk space monitoring |
| `raucdb-update` | `/usr/libexec/raucdb-update` | RAUC database maintenance |

> [!TIP]
> The boot sequence flows: `hassos-data.service` (initialize data) → `hassos-expand.service` (expand partition) → `hassos-overlay.service` (overlay setup) → bind mounts → `hassos-config.service` (apply config) → `docker-prepare.service` → `docker.service` → `hassos-supervisor.service`. Tracing this chain is essential for debugging boot failures.

### Container Image Pre-loading

During the build, HAOS pre-loads Docker container images into the data partition to enable offline first boot. The process is managed by three scripts in `buildroot-external/package/hassio/`:

1. **`fetch-container-image.sh`** — Downloads container images using `skopeo` with architecture-aware selection and retry logic (3 retries with exponential backoff). Uses file locking to prevent race conditions during parallel downloads.

2. **`dind-import-containers.sh`** — Runs inside a Docker-in-Docker container during the build. Loads pre-fetched OCI archives into the Docker daemon and tags the Supervisor image with the expected naming convention.

3. **`create-data-partition.sh`** — Creates and populates the data partition image:
   - Creates a 1280 MB ext4 image labeled `hassos-data`
   - Mounts and populates with Docker images via DinD
   - Sets up initial AppArmor profiles from `version.home-assistant.io`
   - Writes the updater channel configuration (`updater.json`)
   - Creates the `.docker-use-containerd-snapshotter` marker file

> [!NOTE]
> The data partition image created during build contains pre-loaded container images so the system can boot without internet. The initial size is 1280 MB but is expanded to fill the disk on first boot by `hassos-expand.service`.

### Monitoring and Health

The test suite validates these health indicators that administrators should also monitor:

- **No failed systemd units:** `systemctl list-units --state=failed` should report 0 failures
- **No systemd dependency cycles:** Check `journalctl -b0 | grep 'ordering cycle'`
- **Kernel not tainted:** `cat /proc/sys/kernel/tainted` should be `0`
- **Network connectivity:** `nmcli network connectivity check` should report `full`
- **No AppArmor denies:** `journalctl -t audit | grep DENIED` should return empty
- **Supervisor health:** `ha resolution healthcheck` should pass with no unhealthy/unsupported entries
- **RAUC slot status:** `rauc status` should show active slot with correct version and no warnings

---

## 6. Performance

### Memory Management

HAOS implements several memory optimization strategies:

#### zRAM

Two zRAM devices are configured by `hassos-zram` (`/usr/libexec/hassos-zram`):

| Device | Mount | Purpose |
|---|---|---|
| `zram-tmp` | `/tmp` | Compressed in-memory temporary storage |
| `zram-var` | `/var` | Compressed in-memory variable data |

zRAM provides transparent compression of temporary data, reducing disk I/O and extending the effective memory capacity on memory-constrained devices.

#### Multi-Generation LRU (MGLRU)

The `haos-mglru.service` enables the Multi-Generation LRU page reclaim algorithm, which improves memory management efficiency compared to the traditional LRU, particularly beneficial for systems running many containerized services.

#### Swap File

The swap file at `/mnt/data/swapfile` provides additional virtual memory. The size is managed by `haos-swapfile.service` reading `/etc/default/haos-swapfile`. Swap aggressiveness is tuned via `/usr/lib/sysctl.d/15-swappiness.conf`.

### Docker Optimization

- **Containerd snapshotter backend:** Enabled when the `.docker-use-containerd-snapshotter` marker exists on the data partition, improving container layer handling
- **journald logging:** Docker uses `journald` as the log driver, eliminating separate log files and enabling unified log access through `journalctl`
- **overlay2 storage driver:** Efficient copy-on-write filesystem for container layers
- **Resource limits:** Docker service drop-ins in `docker.service.d/resource.conf` configure resource constraints

---

## 7. Security

### AppArmor

HAOS uses AppArmor to provide mandatory access control for containerized services. The `hassos-apparmor.service` loads profiles at boot via `/usr/libexec/hassos-apparmor`. AppArmor profiles for the Supervisor are downloaded from `version.home-assistant.io` during the build and stored at `/mnt/data/supervisor/apparmor/`.

> [!WARNING]
> AppArmor denies indicate a container attempted an operation outside its allowed profile. Check `journalctl -t audit | grep DENIED` to diagnose. Persistent denies after updates may indicate a profile mismatch — the Supervisor manages profile updates automatically.

### Filesystem Protection

- **Read-only root:** The system partition is squashfs/erofs, preventing runtime modification
- **Persistent overlay:** Only `/etc` changes persist via the overlay partition
- **Bind mounts:** Specific directories (`/var/lib/docker`, `/var/lib/bluetooth`, etc.) are bind-mounted from the data partition, isolating persistent state
- **Separate data partition:** User data, Docker containers, and add-ons live on a separate ext4 partition, preventing system corruption from data issues

### OTA Update Security

- **Signed bundles:** All RAUC update bundles are cryptographically signed
- **Certificate chain:** Three-tier CA (release, development, provisioning) for different deployment stages
- **Verification on install:** RAUC validates the bundle signature before writing to disk
- **Rollback protection:** Failed boots automatically revert to the last known-good slot

### Network Security

- **mDNS only:** The system is discoverable via mDNS (`.local`) only, not via LLMNR
- **Dropbear SSH:** Minimal SSH server with persistent host keys via bind mount, configured via drop-in overrides for security hardening
- **NTP dispatcher:** The NetworkManager dispatcher (`10-ntp`) ensures time synchronization updates when network state changes, preventing time-skew-based attacks

### Docker Security

- **AppArmor profiles per container:** Managed by the Supervisor
- **Container isolation:** Each add-on runs in its own container with defined capabilities
- **Docker daemon patches:** HAOS applies custom patches to Docker (in `buildroot-external/patches/docker-engine/`) including:
  - Respecting explicit AppArmor profiles on privileged containers
  - Protecting bridge subnets from direct external access

> [!CAUTION]
> The Docker engine patches in `buildroot-external/patches/docker-engine/` modify upstream Docker behavior. Patch `0002-bridge-protect-bridge-subnet-from-direct-external-ac.patch` adds firewall rules to prevent external access to the Docker bridge subnet. Removing this patch would expose container networks to the local network.

---

## 8. Developer Internals

### Repository Structure

```text
home-assistant/operating-system/
├── Dockerfile                  ← Build container definition
├── Makefile                    ← Board-specific build targets
├── README.md                   ← Project overview
├── .gitmodules                 ← Buildroot submodule reference
├── .hadolint.yaml              ← Dockerfile linter config (ignores DL3008)
├── buildroot/                  ← Buildroot (git submodule)
├── buildroot-external/         ← HAOS customization layer
│   ├── Config.in               ← Kconfig menu for HAOS packages
│   ├── external.desc           ← Buildroot external descriptor
│   ├── external.mk             ← Buildroot external makefile
│   ├── busybox.config          ← BusyBox configuration
│   ├── meta                    ← Project metadata
│   ├── board/                  ← Per-board configurations
│   │   ├── arm-uefi/           ← Generic ARM UEFI boards
│   │   ├── hardkernel/         ← ODROID boards
│   │   ├── khadas/             ← Khadas VIM boards
│   │   ├── nabucasa/           ← NabuCasa Green
│   │   ├── pc/                 ← x86-64 and OVA
│   │   └── raspberrypi/        ← RPi 3/4/5/Yellow
│   ├── bootloader/             ← MBR images, U-Boot config
│   ├── configs/                ← Buildroot defconfigs
│   ├── genimage/               ← Disk image layout configs
│   ├── kernel/                 ← Kernel config fragments
│   ├── ota/                    ← RAUC config, CA certs, hooks
│   ├── package/                ← Custom packages
│   │   ├── bluetooth-rtl8723/  ← RTL8723 Bluetooth driver
│   │   ├── eq3_char_loop/      ← eQ-3 HomeMatic kernel module
│   │   ├── gasket/             ← Google Coral TPU driver
│   │   ├── generic_raw_uart/   ← Generic raw UART driver
│   │   ├── hailo-pci/          ← Hailo AI accelerator PCI driver
│   │   ├── hailo8-firmware/    ← Hailo-8 firmware blobs
│   │   ├── hardkernel-boot/    ← Hardkernel bootloader
│   │   ├── hassio/             ← Supervisor container pre-loading
│   │   ├── khadas-boot/        ← Khadas bootloader
│   │   ├── lxd-guest-agent/    ← LXD VM guest agent
│   │   ├── os-agent/           ← Home Assistant OS Agent
│   │   ├── pi-bluetooth/       ← Raspberry Pi Bluetooth
│   │   ├── qemu-guest-agent/   ← QEMU VM guest agent
│   │   ├── rockchip-blobs/     ← Rockchip binary firmware
│   │   ├── rpi-eeprom/         ← RPi EEPROM update tools
│   │   ├── rpi-rf-mod/         ← RPi RF module (HomeMatic)
│   │   ├── rtl88x2bu/          ← Realtek Wi-Fi driver
│   │   ├── tempio/             ← Template I/O (host tool)
│   │   ├── udisks2/            ← UDisks2 (patched for HAOS)
│   │   ├── vcgencmd/           ← VideoCore GPU command tool
│   │   └── xe-guest-utilities/ ← Xen VM guest utilities
│   ├── patches/                ← Patches for upstream packages
│   │   ├── docker-engine/      ← Docker security patches
│   │   ├── grub2/              ← GRUB enhancements
│   │   ├── libglib2/           ← GLib journal logging fix
│   │   ├── linux/              ← Kernel patches (IPv6 reachability)
│   │   ├── network-manager/    ← NM connectivity check fix
│   │   ├── rauc/               ← RAUC journal logging
│   │   ├── systemd/            ← systemd patches (hostname, journal, time)
│   │   ├── uboot/              ← U-Boot string-to-env command
│   │   └── uboot-tools/        ← fw_printenv lock file path
│   ├── rootfs-overlay/         ← Files overlaid onto root filesystem
│   │   ├── etc/                ← Configuration files
│   │   ├── mnt/                ← Mount point placeholders
│   │   └── usr/                ← Services, scripts, rules
│   └── scripts/                ← Build and utility scripts
├── Documentation/              ← Kernel version docs
├── scripts/                    ← Developer helper scripts
└── tests/                      ← Smoke and Supervisor tests
```

### Package System

HAOS custom packages follow the Buildroot package convention:

| File | Purpose |
|---|---|
| `Config.in` | Kconfig menu entry (dependencies, help text) |
| `<package>.mk` | Buildroot makefile (download, build, install rules) |
| `<package>.hash` | SHA256 hash for source verification |
| Patches (`0001-*.patch`) | Applied to upstream source during build |

Each package's `.mk` file defines:
- `*_VERSION` — upstream version to download
- `*_SITE` — download URL or GitHub repository
- `*_DEPENDENCIES` — build-time dependencies
- `*_INSTALL_TARGET_CMDS` — installation commands

#### Notable Custom Packages

**os-agent** (`buildroot-external/package/os-agent/`): The Home Assistant OS Agent provides a D-Bus interface for the Supervisor to communicate with the host OS. It handles OS operations like network management, disk operations, and system information queries.

**hassio** (`buildroot-external/package/hassio/`): Not a single binary but a set of build-time scripts that pre-load the Supervisor and plugin container images into the data partition. Contains `create-data-partition.sh`, `dind-import-containers.sh`, and `fetch-container-image.sh`.

**udisks2** (`buildroot-external/package/udisks2/`): UDisks2 patched for HAOS with three patches:
1. Allow explicitly disabling libsystemd-login
2. Isolate authorization-specific functions
3. Make polkit dependency optional

These patches enable UDisks2 to run without a full login/session manager or polkit daemon.

**Guest Agents**: Three guest agent packages support different virtualization platforms:
- `qemu-guest-agent` — for KVM/QEMU VMs
- `lxd-guest-agent` — for LXC/LXD containers
- `xe-guest-utilities` — for Xen/XCP-ng VMs

### Upstream Patches

HAOS patches several upstream packages to customize behavior:

| Package | Patches | Purpose |
|---|---|---|
| Docker Engine | 2 | AppArmor profile respect on privileged containers; bridge subnet protection |
| systemd | 8 | Hostname on read-only `/etc`, journal gateway boots endpoint, time sync delay, environment variable paths |
| GRUB2 | 2 | `file_env` command for loading vars from files; legacy loader for broken Intel NUCs |
| Linux kernel | 1 | IPv6 reachability test explicit enable option |
| NetworkManager | 1 | Restrict connectivity check to per-link DNS lookups |
| RAUC | 1 | Add `SYSLOG_IDENTIFIER` to structured logs |
| U-Boot | 1 | String-to-environment-variable read command |
| U-Boot tools | 1 | Use `/run` as default lock file location for `fw_printenv` |
| libglib2 | 1 | Add `SYSLOG_IDENTIFIER` to structured logs |

### Kernel Configuration

Kernel configuration uses a layered fragment approach:

1. **Board-specific config** (`buildroot-external/board/<board>/kernel.config`) — architecture and hardware-specific settings
2. **Version fragments** (`buildroot-external/kernel/v6.12.y/`) — per-kernel-version features:

| Fragment | Purpose |
|---|---|
| `hassos.config` | Core HAOS kernel features |
| `docker.config` | Docker/container support (cgroups, namespaces, overlay) |
| `device-support.config` | Hardware device drivers |
| `device-support-pci.config` | PCI device support |
| `device-support-wireless.config` | Wireless/Bluetooth drivers |
| `device-support-wireless-pci.config` | PCIe wireless adapters |

Additional board-specific kernel patches are applied from `buildroot-external/board/<board>/patches/linux/`.

> [!NOTE]
> The script `buildroot-external/scripts/check-dotconfig.py` (using the vendored `kconfiglib.py`) validates that all kernel config fragments are correctly applied to the final `.config`. This prevents silent config regressions.

### Build Scripts

| Script | Purpose |
|---|---|
| `buildroot-external/scripts/post-build.sh` | Runs after root filesystem build — applies overlays, generates configs |
| `buildroot-external/scripts/post-image.sh` | Runs after image creation — calls genimage, creates RAUC bundles |
| `buildroot-external/scripts/rootfs-layer.sh` | Root filesystem layering helper |
| `buildroot-external/scripts/hdd-image.sh` | HDD/SSD image creation for x86 |
| `buildroot-external/scripts/rauc.sh` | RAUC bundle creation and signing |
| `buildroot-external/scripts/name.sh` | Version/name generation for build artifacts |
| `scripts/enter.sh` | Enter the Docker build environment |
| `scripts/entry.sh` | Docker container entry point |
| `scripts/update-dtb.sh` | Update device tree blobs |
| `scripts/update-firmware-rpi.sh` | Update RPi firmware files |
| `scripts/update-kernel-rpi.sh` | Update RPi kernel |
| `scripts/update-kernel-upstream.sh` | Update upstream kernel |
| `scripts/check-kernel-patches.sh` | Verify kernel patches apply cleanly |

### Testing Strategy

HAOS uses [labgrid](https://labgrid.readthedocs.io/) for hardware-in-the-loop testing, combined with pytest.

#### Test Architecture

```text
pytest
  └── labgrid (test automation framework)
       ├── ShellDriver (serial/SSH console interaction)
       ├── qemu-strategy.yaml (QEMU VM target definition)
       └── qemu_shell_strategy.py (QEMU-specific strategy)
```

Tests interact with a running HAOS instance (real hardware or QEMU VM) via shell commands, using `shell.run_check()` for command execution and `shell_json()` for JSON-parsed output.

#### Test Suites

**Smoke Tests** (`tests/smoke_test/`):

| Test | What It Validates |
|---|---|
| `test_init` | System boots, containers running, `ha os info` responds |
| `test_rauc_status` | RAUC reports `kernel.0` as primary, version matches, no warnings |
| `test_dmesg` | Kernel messages captured (diagnostic) |
| `test_supervisor_logs` | Supervisor logs accessible |
| `test_landing_page` | HTTP GET to `localhost:8123` returns HTML |
| `test_systemctl_status` | All systemd units status captured |
| `test_systemctl_check_no_failed` | Zero failed systemd units |
| `test_systemctl_no_cycles` | No systemd dependency ordering cycles |
| `test_host_connectivity` | Host can reach `checkonline.home-assistant.io`, `nmcli` reports full connectivity |
| `test_supervisor_connectivity` | Supervisor container can reach internet via docker0 bridge |
| `test_hassio_connectivity` | CLI container can reach internet via hassio bridge |
| `test_custom_swap_size` | Custom `SWAPSIZE` in `/etc/default/haos-swapfile` correctly applied after reboot |
| `test_no_swap` | `SWAPSIZE=0` correctly disables swap with no service failures |
| `test_kernel_not_tainted` | `/proc/sys/kernel/tainted` is `0` |

**Offline Test** (`tests/smoke_test/test_offline.py`):

| Test | What It Validates |
|---|---|
| `test_ha_runs_offline` | Home Assistant starts and serves the landing page without internet access |

**OS Update Tests** (`tests/smoke_test/test_os_update.py`):

| Test | What It Validates |
|---|---|
| `test_init` | System boots and Supervisor reaches latest version |
| `test_os_update` | OS updates to latest stable via `ha os update`, system reboots to new version |
| `test_boot_other_slot` | Boot slot switch works, system runs on previous version |

**Supervisor Tests** (`tests/supervisor_test/`):

| Test | What It Validates |
|---|---|
| `test_start_supervisor` | Supervisor starts, responds to ping, Core installs |
| `test_check_supervisor` | Supervisor and network info APIs respond correctly |
| `test_update_components` | All components (supervisor, audio, cli, dns, observer, multicast) can update |
| `test_supervisor_is_updated` | Supervisor version matches latest |
| `test_app_install` | Core SSH add-on installs and starts |
| `test_supervisor_errors` | Resolution center health check passes, no unhealthy/unsupported entries |
| `test_create_backup` | Backup creation succeeds |
| `test_app_uninstall` | Core SSH add-on uninstalls cleanly |
| `test_restart_supervisor` | Supervisor restarts and returns to healthy state |
| `test_restore_backup` | Backup restore recovers add-on state |
| `test_restore_ssl_directory` | Backup restore recovers specific folder (ssl) |
| `test_no_apparmor_denies` | No AppArmor DENIED entries in audit log |
| `test_kernel_not_tainted` | Kernel remains untainted after full test suite |

#### Running Tests

```bash
cd tests
pip install -r requirements.txt
pytest --lg-env qemu-strategy.yaml smoke_test/
pytest --lg-env qemu-strategy.yaml supervisor_test/
```

> [!TIP]
> The `test_init` test disables auto-updates before running the suite by setting `auto_update: false` in `/mnt/data/supervisor/updater.json` and restarting `hassos-supervisor.service`. This prevents background updates from interfering with test assertions.

### Udev Rules

| Rule File | Purpose |
|---|---|
| `/usr/lib/udev/rules.d/80-hotplug-cpu.rules` | Hot-plug CPU management |
| `/usr/lib/udev/rules.d/99-com.rules` | RPi community device rules |
| `rpi-rf-mod/82-rpi-rf-mod-leds.rules` | RPi RF module LED control |

### mDNS / DNS-SD

The file `/usr/lib/systemd/dnssd/workstation.dnssd` registers the system as a workstation service via DNS-SD, enabling automatic discovery on the local network.

### Known Issues and Community Feedback

Based on GitHub issues tracked for this project:

| Issue | Status | Impact |
|---|---|---|
| [#2142](https://github.com/home-assistant/operating-system/issues/2142) | Open | Bluetooth in VirtualBox/Proxmox VMs |
| [#2988](https://github.com/home-assistant/operating-system/issues/2988) | Open | LAN DNS resolution broken |
| [#4642](https://github.com/home-assistant/operating-system/issues/4642) | Open | Improve systemd shutdown ordering |
| [#4481](https://github.com/home-assistant/operating-system/issues/4481) | Open | Smarter default swap size formula |
| [#4121](https://github.com/home-assistant/operating-system/issues/4121) | Open | Python logging to systemd-journald |
| [#4631](https://github.com/home-assistant/operating-system/issues/4631) | Open | RPi EEPROM update feature |
| [#4604](https://github.com/home-assistant/operating-system/issues/4604) | Open | Better support for OS forks |
| [#4223](https://github.com/home-assistant/operating-system/issues/4223) | Open | CH341 serial driver not loading |

### Contributing

Development documentation is hosted at [developers.home-assistant.io/docs/operating-system/](https://developers.home-assistant.io/docs/operating-system/). The documentation source is in a separate repository: [home-assistant/developers.home-assistant](https://github.com/home-assistant/developers.home-assistant/).

The kernel versions used in the current branch are documented in `Documentation/kernel.md`.

---

## 9. Integration Points

### Home Assistant Supervisor

The Supervisor communicates with the OS through:

- **os-agent** — D-Bus interface for host operations (network, disk, system info)
- **Docker socket** — Container lifecycle management
- **journald** — Centralized logging via `systemd-journal-gatewayd`
- **`/mnt/data`** — Shared data volume for add-on storage, backups, configuration

### Virtualization Guest Agents

HAOS includes guest agent packages for major virtualization platforms:

| Platform | Agent | Service Unit |
|---|---|---|
| KVM/QEMU | `qemu-guest-agent` | `qemu-guest.service` |
| LXC/LXD | `lxd-guest-agent` | `lxd-agent.service` |
| Xen/XCP-ng | `xe-guest-utilities` | `xe-daemon.service` |

These agents provide host-guest communication for operations like graceful shutdown, filesystem freeze, and guest information reporting.

### Hardware Acceleration

HAOS includes drivers for hardware accelerators:

| Device | Package | Purpose |
|---|---|---|
| Google Coral TPU | `gasket` | Coral Edge TPU PCI driver for ML inference |
| Hailo-8 | `hailo-pci` + `hailo8-firmware` | Hailo AI accelerator for ML inference |

### Home Automation Hardware

| Device | Package | Purpose |
|---|---|---|
| eQ-3 HomeMatic | `eq3_char_loop` | Kernel module for HomeMatic CCU communication |
| RPI-RF-MOD | `rpi-rf-mod` | Raspberry Pi radio frequency module (HomeMatic) |
| Generic Raw UART | `generic_raw_uart` | Raw UART access for radio modules |
| Raspberry Pi Bluetooth | `pi-bluetooth` | RPi-specific Bluetooth initialization |
| RTL8723 Bluetooth | `bluetooth-rtl8723` | Realtek Bluetooth driver |
| RTL88x2BU Wi-Fi | `rtl88x2bu` | Realtek USB Wi-Fi driver |

---

_Generated May 2026 from home-assistant/operating-system at a0b3eb6. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
