HA GitOps - PR-gated GitHub backup for your Home Assistant config

Repo: GitHub - askb/ha-gitops: PR-gated GitHub backup add-on for Home Assistant — every config change is a reviewable PR, validated by CI before merge. GitOps for your smart home. · GitHub


HA GitOps treats your /config like production infrastructure: nothing
force-pushes, every change becomes a reviewable pull request, and CI
validates your config against pinned Home Assistant versions - including a real
smoke boot - before it can merge.

Most config-sync App upload your files straight onto a branch - some even
force-push. That gives you a copy, not control.

Add repository to my Home Assistant

What you get here that other apps don’t

  • :repeat_button: True two-way sync - not a one-way upload. Merged PRs flow back onto
    the box on the next run. Box and repo converge on main, both directions in
    the same run (pull first, then push drift).
  • :locked: Nothing ever force-pushes - every change is an additive PR on a dated
    auto-backup/… branch. Your main history is never rewritten.
  • :white_check_mark: PR-gated, not auto-committed - drift becomes a reviewable pull
    request. Diff it, comment, merge or close. Your config never mutates main
    behind your back.
  • :rocket: CI smoke boot - the pinned HA Core container actually starts with your
    config and must answer HTTP with no Invalid config. Not just a lint — a real
    boot test. Upgrade breakage surfaces in CI, not on your Pi at 2am.
  • :abacus: HA version matrix - validates against a pinned version and a stable
    early-warning leg, so you see breakage from the next HA release before you take it.
  • :key: Secrets never leave the box - CI runs with stub secrets only. Seeded
    .gitignore excludes secrets.yaml, .storage/, databases, logs.
  • :mobile_phone: Review and merge from your phone - it’s just a GitHub PR.
  • :bar_chart: Optional status sensor - exposes last-run status back into HA.
  • :gear: Template CI workflows included - copy one file into your config repo,
    done. No pipeline to hand-build.

Why another config-backup apps?

Direct-push sync tools HA GitOps
Changes land on main Immediately, sometimes force-pushed Never - every drift becomes a PR
Review before accept No Yes - diff, comment, merge (or close)
CI validation No Yes - HA version-matrix check + smoke boot gate the merge
Bidirectional Usually one-way upload Yes - merged PRs flow back on the next run
Secrets safety gitignore defaults gitignore defaults + CI runs with stub secrets only

How it works

Every scheduled run (default daily) on your HA box:

  1. Stash local drift → pull --rebase from origin/main (picks up PRs you
    merged) → re-apply → if the live config changed, commit to a dated
    auto-backup/… branch and open a PR via the GitHub API.
  2. CI on the PR (template workflows included): yamllint + full
    frenck/action-home-assistant validation against a pinned HA version (with a
    stable early-warning leg) + a smoke boot — the pinned HA Core container
    starts with your config and must answer HTTP with no Invalid config.
    Upgrade breakage surfaces in CI, not on your Pi.
  3. You merge (from your phone, if you like). The next run rebases the merged
    state back onto the box.

Both directions go through the same run: it pulls first, then pushes drift,
so box and repo converge on main.

Install (short version)

  1. Add the repo to your App store (badge above), install
    GitOps Config Backup.
  2. Create a GitHub repo (private recommended) + a fine-grained PAT with
    Contents: read/write and Pull requests: read/write.
  3. Point the app at it, start with dry_run: true, check the log, flip to
    false.
  4. Copy the included template/workflows/validate-ha-config.yaml into your
    config repo’s .github/workflows/.
  5. (Recommended) Protect main, require the HA Config Validation check.

Security notes

  • Token lives in Supervisor-encrypted app options, never in git.
  • Seeded .gitignore excludes secrets.yaml, .storage/, databases, logs.
  • CI validates with stub secrets - your real secrets.yaml never leaves the box.
  • Nothing force-pushes or writes to your base branch after the initial import.
  • This is change tracking, not disaster recovery - pair it with HA’s native
    encrypted backups for full system state.

Feedback, issues, and PRs welcome. Would love to hear how it holds up on other
people’s setups. I’ve been using this setup in the HA config. Hopefully, this is
useful to others in the community. :slightly_smiling_face:

Apache-2.0 · GitHub - askb/ha-gitops: PR-gated GitHub backup add-on for Home Assistant — every config change is a reviewable PR, validated by CI before merge. GitOps for your smart home. · GitHub

I suggest actually reading your posts before ‘posting’ what the AI states to you in the future.
Among the weird instances where the AI is telling you to personally do something or embellish something, there is the problem that Add-ons have not been a thing for about a year now. The term was changed to Apps.

Clean up the references to Add-ons so that new users will be able to actually figure out how to load your stuff, and test the install instructions here and it your Git to make sure that everything actually functions as written.

Additionally I question how you can post your secrets on a public forum. The suggestion I think you used gitignore, which prevents those files from being pushed so they are not backed up. I may have missed some magic, if so you can elaborate, people might want to know.

Secrets safety gitignore defaults gitignore defaults + CI runs with stub secrets only

Finally, someone vibe coded this exact thing a week or 2 ago, do a search and you will find it here. (With the same questions / problems)

@Sir_Goodenough Fair points - thanks.

‘Add-on’ renamed as ‘App’: you’re right, stale terminology - cleaned up in the post and repo docs.

Secrets: no magic, you read it correctly. secrets.yaml , .storage/, databases and logs are gitignored and never pushed - so they’re not backed up either. That’s deliberate: this is config change-tracking, not disaster recovery (security notes say to pair it with HA’s native encrypted backups). The “stub secrets” part is CI-only: the validation workflow generates a dummy secrets.yaml on the runner so the HA config check and smoke boot can run against a repo containing no real secrets.

The earlier project: if you mean GithubConfigSync - related idea, different goal. It uploads files straight onto a branch via the GitHub Contents API (one-way, no review step). This one never writes to main: drift becomes a PR, CI must pass (yamllint + HA config check on pinned/stable versions + a smoke boot where the HA container actually starts with your config), and merged PRs flow back to the box next run. If you want a copy of your config in GitHub, that tool is simpler. If you want review and CI in front of your config, that’s the gap this fills.

And yes, AI helped draft the post - the setup has been running on my own box for a while, and I wanted to share what’s been working well for me, with the community. :slight_smile: