-
Language model (Ollama)
An 8-billion-parameter model quantised to 4 bits: about 5 GB. It only loads when asked and unloads after 5 minutes, leaving the GPU free for the rest of the PC.
- LLM locales (Ollama, Qdrant, RAG)
-
Voice (Whisper + speech)
Whisper turns voice notes into text and a local speech synthesiser answers out loud. Also on the PC's GPU.
- LLM locales (Ollama, Qdrant, RAG)
-
The 8 GB GPU
The limit behind the whole design. If the model doesn't fit, part of it runs on the CPU and speed drops from 73 to 17 tokens per second. The simulator below shows it with real measurements.
-
Me, on Element
I ask by text or voice note from the chat, wherever I am.
-
Email (read-only)
Indexed the moment it arrives (IMAP IDLE), including the text of attached PDFs. Primary inbox only: no promotions or social.
-
Calendar
The only thing Hermes writes to: it creates events from booking emails and leaves a 🗑️ to undo them with a reaction.
-
Matrix (assistant room)
My own messaging server. Hermes has its own user and verifies its device on its own: no «unverified source» warnings.
-
Hermes (the bot)
The Python program that runs the turn: it gets the message, prepares the context, calls the model, runs tools and checks the answer before sending it.
-
Persistent queue
If the GPU PC is off, the question isn't lost: it is saved to disk and answered on its own as soon as the PC is back.
-
Formatting
Turns Markdown into HTML for Element and keeps a plain-text version for notifications. Anything from outside (subjects, titles) is escaped: it's data, not markup.
-
Phase 1 · Context set by code
Instructions, today's date with a table of the next 7 days, and history trimmed to question and answer. The model doesn't know what day it is: unless told, it reasons with its training date.
-
Phase 2 · Hints from the question
If the question matches a pattern («what happened with…», «how do I get into…»), one sentence is added to that turn only. Never to the global prompt: the more general text, the worse an 8B model chooses.
-
Phase 3 · Reason only where it helps
Thinking makes a call six times slower. It's on to pick a tool and work out arguments, and when a result comes back empty or with a warning; it's off to write with the data in front of it.
- LLM locales (Ollama, Qdrant, RAG)
- Python
-
Phase 4 · Output guards
Before sending, the code compares the answer with the turn's sources: an IP or an amount that appears in none of them goes back to the model to fix. If it insists, it's sent with a warning.
-
Tools
Server status, calendar, email and three memories. The code validates arguments before running («7» becomes 7) and, if the model names a tool without calling it, asks once that it call it.
-
Server status
Monitoring and security snapshots, container inventory, ZFS and disks. Every value carries its age: if it's over 30 minutes old, the model knows.
-
The seven watchers
Backups, certificates, storage, updates, unusual usage, failed logins and network. Each named after Greek mythology, each with its own room: they only speak when they find something odd.
-
Code relay
When a question is really two («how much was the ticket for what I have on Thursday?»), the model failed 3 out of 3. Now the code takes the second step: it checks the calendar, takes the title and searches the email for it.
-
Embeddings
Turn each text into a vector of numbers so search works by meaning, not just by words.
- LLM locales (Ollama, Qdrant, RAG)
-
Qdrant (vector database)
Stores the vectors of my notes, emails, the documents I send it and our conversations. The code searches all three memories at once so the model doesn't have to guess which.
- LLM locales (Ollama, Qdrant, RAG)
-
My documentation
Homelab procedures, incidents and postmortems. Hermes reads them but never writes to them.
-
Conversation memory
Every conversation, including transcribed voice notes, is indexed: «what did I do last week with…?» has an answer.
- LLM locales (Ollama, Qdrant, RAG)