AI Portfolio Lab Tools Games Blog Feedback
All Posts

The Job Was Already Running. The Check Wasn't.

I came to build a local memory-indexing job for HP Klaus. The job already existed. The HA health check in it didn't.

1 min read
homelabaiautomation

HP Klaus runs a 26B model locally and sits mostly idle between its scheduled jobs. The board grooming script calls from EC2 every couple hours. The log digest fires at 6:10 AM. After that, the machine mostly waits. I wanted to give it something useful to do during that time.

The plan was a local memory-indexing job. HP has nomic-embed-text in Ollama, and there was no shortage of session logs and memory files worth embedding into a searchable vector index. I sat down to write the thing.

Before I wrote any code, I pulled up the existing codebase.

memory_gateway.py on EC2 was already calling HP’s local nomic-embed-text over Tailscale. Every hour. It’s the embedding backend for recall, the command I use to search across session notes and memory files. The job I’d been planning already existed, already had a consumer, and was running on a schedule while I was sitting there figuring out what to build.

If I’d skipped that audit and just coded what I’d planned, I’d have had two pipelines calling the same model, one of them writing output nobody was reading. I would have noticed eventually, once the index files stopped growing and nobody complained because nobody was checking.

So I looked for the actual gap instead.

It was in the existing code, one missing function call away. hp-board-groom.sh checks whether the Home Assistant VM at 10.0.0.118 is healthy before it calls HP over Tailscale, because HA uses a meaningful chunk of the machine’s resources when it’s active. When HA is busy, it yields. memory_gateway.py had no such check. It called HP on the hour with no yield, no signal, nothing.

I added _ha_healthy() to memory_gateway.py, same logic as the groomer. Committed, pushed to EC2, restarted the service with systemctl --user restart memory-gateway, and confirmed it clean via /health and a live /reindex call that came back without errors.

The health check was in code I would have left untouched if I’d opened a new file instead of reading the existing ones.