Joe’s System Map
Snapshot: 1 November 2026. This explains the current architecture rather than proposing changes. Live configuration and service inventories take precedence over older setup notes. No passwords, API keys, private MCP route identifiers or personal document contents are included.
1. The system in one picture
JOE
phone / Telegram / browser / Portal / Index Ring
|
+-------------------+----------------------+
| | |
Internet services Home network Remote access
Google, Telegram, 192.168.0.0/24 Cloudflare / Tailscale
model providers, | |
Backblaze B2 +-----------+----------+
| |
| +-------------+--------------+
| | |
| UBUNTU VM HA PI
| 192.168.0.182 192.168.0.155
| on Proxmox Home Assistant OS
| | |
+---------- Hermes / Rootbeet <----MCP----> HA Core
| Mnemosyne memory Automations
| Workspace files MQTT broker
| Scheduled scripts Zigbee2MQTT
| Docker applications ESPHome / Matter
| Frigate / recognition Beetroot standby
| Web dashboards HA backups
| | |
+-------- encrypted B2 backups ---------------+
(uploaded by VM jobs)The VM does most computing and administrative work. The Pi owns home automation and radio-connected devices. The cloud supplies communications, online accounts, remote access and the large language models. The standby agent gives you a second point of contact if the VM fails, but it is not a complete replacement for the VM’s applications.
Arrows mean a configured or documented relationship. They do not mean every path was exercised end to end during this mapping.
2. Physical and operating-system layers
The Proxmox host and Ubuntu VM
Existing recovery documentation identifies the main guest as VM 101 on Proxmox. This mapping directly verified the guest, not the hypervisor’s hardware or configuration.
The guest currently reports:
- Ubuntu 26.04.1 LTS, KVM/QEMU virtual machine.
- LAN address
192.168.0.182, tailnet address100.96.95.65. - Four virtual CPUs, exposed model AMD Ryzen 7 6800H.
- Around 22 GiB guest RAM, from the earlier same-day memory check.
- Root filesystem
/dev/sda2: 32 GiB filesystem, 22 GiB used. - Data filesystem
/dev/sdb2mounted at/data: 314 GiB filesystem, 248 GiB used at collection time.
The operating-system hostname is joe. Notes often call it joe-host. Those names refer to this same guest in this document.
There are two storage ceilings: free space inside the VM’s filesystems, and allocation in the Proxmox thin pool underneath its virtual disks. A healthy-looking guest filesystem does not prove the thin pool has room. The thin-pool watchdog exists to watch the second ceiling. The same-day watchdog sample was 86.39% pool allocation and 93.49% for the monitored LV. These are allocation figures, not the guest’s df percentage.
The Home Assistant Pi
The HA host is 192.168.0.155. Live SSH reported aarch64. Existing hardware documentation identifies it as a Raspberry Pi 4 Model B with 4 GB RAM. Hardware identity and RAM capacity were not re-read in this mapping.
HA Core currently reports version 2026.10.4 and timezone Europe/London. Its Supervisor manages applications alongside Core. These applications are containers, but they belong to HAOS rather than the VM’s Portainer installation.
Devices that are clients, not servers
Your phone, Portal Go / Mini / Plus, cameras, Zigbee sensors, ESPHome devices and coffee tablet provide input or display output. They are not interchangeable with either server. Turning a Portal screen off does not stop the dashboard server, HA or Hermes. The screenctl user service on the VM sends screen-control events through ADB.
3. What runs where
Docker versus systemd
You have two ways of running software on the VM:
- Docker containers: packaged applications with their own filesystem and network context. Compose files describe their containers, ports, volumes and dependencies. Portainer provides the management interface.
- systemd user services: ordinary programs supervised by Linux under Joe’s account. Hermes, shared Chrome, the LLM shim, memory bridges and several web apps use this route.
A container’s localhost is that container. 127.0.0.1 on the VM is the VM. Docker services on the same network can use container DNS names. A host port such as 8001 forwards traffic into a container’s different internal port, such as Paperless’s 8000.
Current inventory: 45 VM containers, 44 running and one exited. The exited container is tei-embeddings, associated with the retired knowledge-indexing setup. Presence of an exited container is not a reason to restart it.
Live Compose labels mostly point at /home/joe/stacks/<number>/docker-compose.yml. This supersedes older notes saying every definition lives only inside Portainer’s volume. The Piper container still labels its definition under /data/compose/37/. A label records deployment provenance, not proof that an old file is still accessible or authoritative.
Main VM application groups
- Assistant and chat: Hermes gateway, Open WebUI, a separate Codex Telegram bridge, Pally-to-Hermes bridge, tool servers and Open Terminal.
- Documents: Paperless, PostgreSQL, Valkey queue, Tika, Gotenberg and Zettelrobbe AI tagging. Stirling PDF is a separate document utility.
- Photos: Immich server, PostgreSQL, Redis and machine-learning worker.
- Saved web material: Karakeep (containers still named
hoarder_*), its Chrome worker and Meilisearch index. - Research: Open Notebook with SurrealDB, plus a GPT Researcher MCP service.
- Personal apps: Actual Budget, Mealie, tracker editor, finance, health, tennis, fossil, solar and Pulse dashboards. Some are containers and some user services.
- Home support: Frigate, face-identification service, doorbell event page, Portal dashboard, Whisper and Piper speech services.
- Network and operations: AdGuard, Nginx Proxy Manager, Cloudflared, Tailscale, Portainer, Uptime Kuma and Healthchecks.
- Credentials: Vaultwarden, used through browser/vault tools and local
rbwhelpers where configured.
Pi applications verified live
Supervisor listed 14 installed applications, 13 started and one in error:
- Terminal & SSH and Advanced SSH & Web Terminal.
- Mosquitto MQTT broker.
- Zigbee2MQTT.
- ESPHome Device Builder.
- Home Assistant MCP Server.
- Home-Assistant-Matter-Hub.
- Piper and Speech-to-Phrase.
- Tailscale.
- Google Drive Backup.
- Studio Code Server.
- Hermes Standby (Beetroot).
- The Supervisor-managed Cloudflared app is in
error.
Important distinction: SSH also found a separate running cloudflared-ha container on the Pi. Therefore the errored Supervisor app does not establish that the Pi has no tunnel connector. The VM has its own running cloudflared container too. Both connectors must be considered when tracing intermittent public access. This pass did not compare the two live ingress configurations.
4. What happens when you message the assistant
Telegram message
-> Hermes gateway on VM
-> session history + instructions + relevant memory/skills
-> selected cloud model
-> model requests tools as needed
-> local file / shell / browser / MCP / app API
-> tool result returns to model
-> Hermes delivers reply to TelegramThe model is the reasoning component. Hermes provides the session, tools, permissions, platform integration and execution loop. A model cannot inspect your files just because it knows their names. Hermes has to read them through a tool and put the relevant output into the model’s context.
The current main configuration selects gpt-6.1-sol-900k through openai-codex. A configuration is a routing intention. A session can retain a route or use a configured fallback, so actual model/billing records are the evidence of who answered a particular turn.
Delegated workers
The parent can give independent assignments to smaller agents. Each gets its own brief and conversation context, and returns findings to the parent. They share access to this machine, so instructions such as “read only” are not a filesystem sandbox. Their claims need checking.
Current worker pin: nvidia/nemotron-3-ultra-550b-a55b:free through OpenRouter. The route was verified with a real HTTP 200 response reporting cost zero, and with the completed three-worker review. Provider and model are pinned without an explicit endpoint override so Hermes resolves the matching credentials.
The parent and workers are different model routes. Changing one does not change the other.
MCP and ordinary scripts
MCP is a standard interface for exposing tools. Your HA MCP server lets Hermes read entities and call supported HA operations. Other connectors expose Google Workspace, Google Health, coffee-machine or Pally functions. A configured connector is not proof its login works.
Ordinary scripts can also call app APIs directly. This is why the scheduled Gmail pipeline can keep using IMAP even if the interactive Google Workspace OAuth grant has expired.
The config includes enabled Era and Pally integrations, but this mapping did not establish Era’s current OAuth health. GBrain’s retired MCP configuration was removed on 1 Nov 2026.
5. The three kinds of memory and records
Conversation history
Hermes stores messages and tool activity in its session databases, including ~/.hermes/state.db. Session search retrieves what was said or done. This is an event record, not a curated statement that every old claim is still true.
Mnemosyne durable memory
Mnemosyne stores facts, preferences, relationships, working memories and episodic summaries in SQLite. The active provider uses:
/home/joe/.mnemobrain/data/mnemosyne/mnemosyne.db
The legacy-looking Hermes path is an alias in this installation, as previously checked. Mnemosyne is loaded inside Hermes for native conversational memory. Separate MCP/proxy services also expose memory tooling to other clients. They are interfaces to the memory system, not automatically separate brains.
Retrieval combines keyword search and local vector embeddings. The same-day diagnostic showed active vector hits, no empty recalls in its 63-call retained window, and SQLite integrity OK. Embeddings are numerical search indexes, not another cloud chat model. Native recall can work while the remote consolidation provider is unavailable.
Nightly mnemosyne-sleep uses an LLM to consolidate eligible older working memories. It is currently blocked by OpenDesign’s HTTP 402 response, by Joe’s decision to wait. The script stops before pre-purge or consolidation rather than silently falling back. That blocks this maintenance operation, not ordinary memory recall.
Workspace files and skills
/home/joe/workspace holds canonical task state, registers, records, source CSVs and notes. It is a symlink to a dated directory under Downloads. Apps bind-mount that real location. Neither a Downloads name nor a symlink means these are disposable files.
The distinctions are:
- Trackers: current commitments. Completed active tasks are removed.
- Registers: standing records such as bills, subscriptions and parcels.
- Raw sources: documents, measurements, session notes. Preserved as records.
- Compiled notes: maintained summaries, indexes and interpretations of sources.
- Skills (
~/.hermes/skills): procedures for doing recurring kinds of work. - Instructions/profile: compact standing context governing the assistant’s behaviour.
The wiki uses Markdown links and wiki-links. Its graph is generated from those links. Lint checks structure and format, not whether two factual claims contradict each other.
GBrain’s retired runtime has been removed (1 Nov 2026). Its MCP entry, service files, Node/Bun dependencies and original data directory were moved out of their live locations; the verified portable export and raw retirement archive remain under ~/.hermes/backups/simplification-20261030/memory-migration/. Mnemosyne’s shared parent directory and Python environment remain intact. The separate, stopped TEI container was not removed because exclusive GBrain ownership was not established.
6. The AI provider arrangement
Hermes main session ----------------------> Codex subscription route
Delegated workers ------------------------> OpenRouter free NVIDIA route
Local application requests
-> llm-shim on VM
:8765 plain
:8650 structured output
:8655 vision / HA conversation
:8766 quiet consolidation
-> configured default: OpenDesignThe shim gives local applications an OpenAI-compatible interface. Profiles adapt requests for different consumers. The structured profile handles output-format differences, vision handles image-request requirements, and quiet applies bounded retries and reasoning settings suited to consolidation.
The live TOML default is opendesign. This does not mean every LLM call on your system goes to OpenDesign. Hermes/Codex, workers/OpenRouter and browser clients have independent settings. Nor does it prove every application is using the shim correctly: app-internal settings can hold their own endpoints.
OpenDesign’s quota problem can affect descriptions, tagging or consolidation while the underlying local applications continue working. A functioning Paperless archive, for example, does not require that every AI-tagging request succeed.
7. Home automation and voice
Device control
Zigbee sensor/button
-> Zigbee coordinator + Zigbee2MQTT on Pi
-> Mosquitto MQTT broker on Pi
-> HA entity / event
-> HA automation
-> target light, fan, blind, notification or helper
Wi-Fi / ESPHome / cloud-connected device
-> appropriate HA integration
-> same entity and automation layerMQTT is the message bus. HA is the system that interprets device states and runs home rules. Hermes can inspect or operate HA through MCP, but everyday motion-light rules should not need a cloud language model or a Telegram turn.
The live HA inventory included 63 automation entities. Entity counts are not device counts: one physical sensor can expose occupancy, battery, illuminance, settings and diagnostic entities.
HA also integrates Trading 212, EcoFlow, Fuse Energy, Nest, Home Connect, Reolink, media devices, calendars and presence. These add information and controls to HA, even when the underlying source is a cloud service.
Voice and Portal clients
Portal / voice satellite
-> HA Assist pipeline
-> speech recognition (faster-whisper service on VM)
-> local intent or selected conversation engine
local home command -> HA
Hermes request -> Hermes on VM
configured LLM conversation -> cloud through shim
-> Piper speech synthesis
-> speakerHA currently has three Assist pipelines: Home Assistant, Focused local assistant and Hermes. All list faster-whisper and Piper, with local intents preferred. The default is the pipeline named Home Assistant. Individual satellites may select another pipeline, so the global default alone does not tell you which agent answered a particular Portal request.
There are speech applications on the Pi as well as Whisper/Piper containers on the VM. Those are alternative endpoints available to pipelines, not proof every utterance passes through both. This pass did not resolve each Piper integration to its host endpoint.
The Portal dashboard itself is served by the VM on port 8640. Its screen-control helper is another VM service. The physical screens remain HA-integrated devices.
Coffee machine
The Decenza app/tablet communicates with the DE1 machine. Your integration setup includes Decenza MCP and DE1 entities in HA. Commands can therefore enter through the tablet/app, HA or assistant tooling. A brokered HA command and a Bluetooth machine connection are different links. A failure in the tablet-to-machine link cannot be fixed by merely proving the HA entity exists.
8. Cameras, recognition and doorbell notifications
Reolink doorbell / garden camera
-> network video streams
-> Frigate on VM (:5000, restream :8554)
recording + object events
-> MQTT on Pi
-> HA notification automations
Frigate event/frame
-> face identification service on VM
-> identity / Frigate label / event snapshot
-> HA notification rules
-> phone notification
-> optional LLM Vision description through shim
Event state -> doorbell page (:8657)
Email parcel scan -> HA parcel context -> notification wordingFrigate now runs in Docker on the VM, with host-mounted configuration at /home/joe/frigate/config and media at /home/joe/frigate/media. Older descriptions placing Frigate on the Pi are obsolete.
The documented alert design filters for the property’s zone, waits for identity, suppresses known household members when enabled, and handles physical doorbell-button presses separately. Description and alert are separate automations. The documented image source is an event-specific file on HA, avoiding a delayed request describing an unrelated live frame.
The current face-identification user service was verified running. The exact automation gate order and timing above come from the 29 October pipeline reference, not a new playback test. This map did not trigger a visitor or send a test notification.
9. Index Ring capture
Index Ring -> Bluetooth -> phone app
-> HTTPS webhook through Cloudflare
-> ringbearer on VM (:8787)
structured house command -> HA action
general note -> local transcription -> Telegram -> Hermes
archive -> every-minute health capture scannerThe bridge archives accepted captures under /home/joe/ringbearer/docker/data. The archive, rather than a successful container healthcheck, proves a note arrived at the server. The phone-to-internet leg is outside the server’s visibility.
Some house gestures and recognised phrases take the direct HA path rather than asking the assistant to reason. The scanner also recognises explicitly structured health captures and files them into their authoritative records. General prose still needs interpretation. A successful Telegram forward is not proof that downstream filing happened.
The ring path uses the internet even when the resulting house action is local. It should not be confused with an entirely offline Zigbee button.
10. Documents, email and research
Document archive
PDF / scan / selected email attachment
-> Paperless ingest / consume folder
-> queue (Valkey)
-> document conversion and text extraction (Gotenberg / Tika as needed)
-> Paperless media files + PostgreSQL metadata
-> optional AI tagging (Zettelrobbe)
-> Paperless search / assistant retrieval
-> scheduled document mirror to Google DrivePaperless is the document-management application. PostgreSQL holds its metadata and relationships. Its media volume holds document files. The queue coordinates work. Tika and Gotenberg are supporting converters, not separate document archives. Zettelrobbe enriches classification. Stirling PDF provides manual PDF manipulation separately.
The Google Drive document mirror is a second document location. It is distinct from a whole-system backup and from the workspace’s derived Markdown document notes.
Email and drafts
The scheduled register scan uses email to maintain bills/subscriptions and surface selected anomalies. Parcel context is a separate scan. Scheduled scripts have narrow responsibilities and do not imply a general agent reads and acts on all mail.
The draft-preparer uses email-draft-imap.py: deterministic collection and thread checks, LLM judgement/prose, then IMAP append to Gmail Drafts. Drafts are for review. Sending remains a separate authorised action. Interactive Google Workspace tools use their own OAuth-based connector.
Some script headers still mention retired email-tracker-watch. No such current cron is present. It is not drawn here as an active email-to-task pipeline.
Research and saved pages
- SearXNG supplies local metasearch.
- Shared Chrome is the browser attached to by browser tooling and scheduled portal/booking tasks.
- Camofox and the
mcpobridge provide additional browser tooling. - Karakeep stores saved web material with a Chrome fetcher and Meilisearch index.
- Open Notebook has its own SurrealDB-backed research workspace.
- GPT Researcher is exposed through an MCP service.
These are different stores with different jobs. A saved Karakeep page is not automatically a Mnemosyne fact, a Paperless document or an Open Notebook source. This mapping does not establish an automatic sync among them.
11. Finance, health and dashboards
Finance
Trading 212 -> HA integrations / sensors
-> daily investment capture and refresh scripts
-> finance trackers + permanent investment-history.csv
-> exported dashboard data -> finance web app (:8656)
Bank transaction exports -> finance import/query workflow
-> transaction-derived records
Manual pension/cash updates -> relevant source trackersDaily ISA/GIA values are automated. The refresh script explicitly leaves manual pension and cash sources alone. A current dashboard therefore does not imply every underlying account is live-connected. Actual Budget is an additional budgeting application with its own data store, not automatically the sole authority for every finance tracker.
The CSV history retains investment snapshots independently of HA’s recorder retention.
Health
Google Health -> Google Health MCP -> daily-health-sync
-> health-daily.csv / tracker
-> recovery calculations and export scripts
-> health dashboard (:8654)
Mood entered in PWA -> CouchDB wellness database
-> health export -> durable Markdown mirror / dashboard
Structured Index Ring health capture
-> health-capture scanner
-> BP source CSV or anxiety log -> readable viewsYour biometric pipeline uses Google Health MCP, not the retired HA Google Health integration. Mood data uses CouchDB. BP readings have an append-only CSV source. These are separate inputs merged for presentation.
The live schedule is authoritative over old script-header times. It currently lists daily sync at 08:45, export at 08:50, and recovery at 08:55. That is a schedule description, not proof that every view contains same-run recovery results.
Dashboards are views
Pulse reads generated system-status data. The finance and health sites read exports. Tracker/todo editors operate on workspace state. Tennis and fossil apps are local-first tools, with CouchDB available for device synchronisation where configured.
The static chat site’s source/deployment is covered by the source-code backup runbook, but its live browser-side model setting was not inspected in this pass. Do not assume it shares Hermes’s current model.
12. Network access and trust boundaries
On the home LAN
AdGuard handles DNS at the VM’s 192.168.0.182:53. It can block unwanted names and apply local rewrites. Nginx Proxy Manager accepts HTTP/HTTPS and routes configured local names to services. DNS answers “which address?”, while a reverse proxy answers “which application at that address?”.
A service bound to 0.0.0.0 accepts connections on the VM’s applicable interfaces, subject to firewall/routing. A loopback-bound service accepts local host connections. Neither fact alone establishes internet exposure.
Through Cloudflare
remote browser -> Cloudflare DNS / edge / applicable Access policy
-> outbound Cloudflare Tunnel connector
-> configured local originThe VM tunnel’s active ingress maps the domain and selected paths to HA, private MCP bridges, Vaultwarden, Ringbearer, sync endpoints and application subdomains. The detailed public origin inventory is appended below, with private route identifiers removed.
Cloudflare Access is an authentication layer for routes where configured. API/webhook paths can use different application authentication. A redirect to an Access login proves the edge policy answered. It does not prove the final local application is healthy.
Through Tailscale
Tailscale provides a private network route between enrolled devices. The VM currently has a Tailscale container and tailnet interface, and the Pi has the Tailscale app. This corrects older notes claiming Tailscale was only on the Pi. This map did not revalidate advertised subnet routes or all peer states.
Secrets
Vaultwarden is the password vault. Local helpers and selected credential files supply integrations without putting values into chat. Browser vault tooling fills credentials at the relevant site. The model should receive operation results, not passwords or payment details.
The system is locally hosted, but it is not fully private or offline: requested context can go to cloud models, messages pass through Telegram, integrations contact Google/vendor APIs, and public access passes through Cloudflare. Local hosting determines where files and processes live, not where every request travels.
13. Scheduled work and daily rhythm
Hermes currently holds 101 job definitions, 100 enabled. Most run Python/bash scripts with no agent. Three established agent-job exceptions are email draft preparation, daily fact extraction and cron failure triage. Script-only jobs can still call an LLM API internally, as memory consolidation does.
job definition in cron/jobs.json
-> scheduler in Hermes gateway
-> script or agent execution
-> output file + execution record
-> local record or Telegram deliveryEmpty output is intentionally quiet for many jobs. deliver: local keeps output on the machine. Telegram/origin delivers according to the job’s settings. Neither silence nor a last-success flag proves a producer made a fresh usable artifact.
Selected current slots, UK local scheduling:
- 02:45 Hermes state archive producer.
- 03:00 memory consolidation, fact extraction and cron-output housekeeping.
- 03:10 Mnemosyne backup.
- 03:30 Immich B2 backup.
- 03:35 whole-system B2 mirror.
- 04:00 Docker stack updater.
- 07:00 tracker validation, wiki graph/lint and parcel context.
- 07:05 Git snapshots.
- 07:30 HA snapshot transfer to B2.
- 08:00 task digest and solar dashboard publication.
- 08:45 onwards health pipeline.
- 12:00 / 18:00 email register scan, followed at 12:30 / 18:30 by draft preparation.
- Evening investment capture/refresh and 21:00 timed-task closeout.
- Sunday 21:00 Open WebUI backup, 21:05 homelab volume backup.
- Frequent watchdogs and syncs run throughout the day.
The complete job inventory below preserves each configured schedule expression. Intervals, one-shot dates and compound cron expressions should be read literally rather than flattened into an approximate daily timetable.
14. Monitoring and standby
There are several layers because they answer different questions:
- Docker healthchecks: does an individual container’s configured probe pass?
- Uptime Kuma: can monitored endpoints answer from the monitor’s network?
- Healthchecks: did a scheduled producer send its expected heartbeat?
- Specific watchdog scripts: disk space, thin pool, HA responsiveness, Zigbee liveness/function, backup freshness and other domain checks.
- Disk circuit breaker: a running user service intended to intervene on dangerous write growth.
- Beetroot on the Pi: monitors the main VM from another host.
Live Pi job definitions have only three enabled standby jobs: peer-watch, cloudflared-ha-watch and bathroom-fan-watch. The many mirrored primary job definitions are disabled, avoiding duplicate work and messages.
Rootbeet pushes workspace and skills one way to Beetroot every 15 minutes. Memories are deliberately not synchronised. Beetroot keeps its own host-specific memory and configuration. Files edited only on the standby can be overwritten by the next primary push.
A monitor on the VM cannot alert if the entire VM and its communication path are dead. The Pi improves that separation, but both machines still share household power/network dependencies. This is resilience across hosts, not independence from every home outage.
15. Storage, backups and restoration
Where the durable data is
- Workspace Markdown, CSVs and app source: beneath the resolved workspace tree.
- Hermes config, sessions, schedules, scripts, skills and operational state:
~/.hermes. - Mnemosyne: its SQLite data directory.
- Docker named volumes: currently beneath
/data/var/lib/docker/volumes/on the VM. - Bind-mounted app data: explicit host paths such as Frigate’s media/config and Ringbearer’s archive.
- HA state and apps: on the Pi’s HAOS-managed storage.
- Some PWA data: local device storage plus CouchDB where sync is configured.
Restarting a container generally retains its attached volumes. Recreating one retains only data placed in persistent volumes/bind mounts. The container’s writable layer is not a substitute for a mapped data directory.
Backup chain
Hermes files/databases -> local archives + Git bundles ----+
Docker named volumes -> weekly homelab archives -----------+
Open WebUI -> dedicated weekly archive -------------------+
Mnemosyne -> dedicated database/config archive ------------+-> system-b2-backup
Workspace -> file mirror ---------------------------------+ -> rclone crypt -> B2
Live Compose/app source -> source-code archive ------------+
Host configuration -> capture archive --------------------+
Immich originals -> separate nightly encrypted library mirror -> B2
Immich PostgreSQL -> logical dumps ----------------------------> B2
HA snapshot producer on Pi -> ha-b2-backup stream ---------------> B2The immich-crypt: remote is a client-side encryption layer over B2. Its name is historical: it carries whole-system backups as well as photos. system-backups/, library/ and db/ are prefixes within this layout, not necessarily separate B2 buckets.
The recovery runbook documents:
immich-crypt:
system-backups/
workspace/ hermes/ homelab/ source-code/
owui/ mnemosyne/ host/ state/
ha-backups/
library/
db/
heartbeats/Photo policy: Google Photos remains Joe’s primary photo copy, with Immich an additional copy. This map does not establish a continuous Google-Photos-to-Immich sync. The stopped Takeout import pipeline must not be drawn as active.
The Pi also has a Google Drive Backup app. Its documented backup excludes the standby Hermes app. That copy must not be assumed to reconstruct Beetroot.
What the backup evidence does and does not establish
Git gives local change history. Git bundles and archives preserve selected history/data offsite. A one-way standby sync helps availability, but can propagate deletions or bad edits. A mirror can propagate deletions too. These are different protections.
The runbook records a source-code archive scratch restore with all 372 files matched on 28 October. It explicitly does not claim a complete clean-host or whole-service restoration rehearsal. This mapping did not perform a new restore.
Encrypted recovery needs the rclone configuration and crypt secrets before downloading encrypted backups. A copy of those same secrets inside the encrypted backup cannot unlock itself. The runbook documents an independent copy on Beetroot, while noting that losing both hosts remains an unproven bootstrap case.
Start with RESTORE.md for recovery. Do not restore an old database over a live service simply to see whether an archive opens.
16. What fails when a component is unavailable
| Component unavailable | Expected effect from the mapped dependencies |
|---|---|
| A cloud model provider | Its AI requests fail or use deliberately configured fallbacks. Local files, ordinary app functions and HA’s native rules can continue. |
| Internet / home broadband | Telegram, remote cloud models, Google/vendor APIs, public Ring webhook and remote Cloudflare access are affected. Local HA/Zigbee rules can still run if their devices and Pi remain up. |
| Hermes gateway | Assistant turns and Hermes-scheduled jobs stop. Separate systemd services, Docker applications and HA automations can continue. |
| Ubuntu VM | Main assistant, VM apps, Frigate, VM speech services, exports, DNS service and VM-owned backup jobs stop. Pi-native HA rules can continue, but dependent VM endpoints fail. |
| HA Pi | Home automations, MQTT/Zigbee integration and HA MCP fail. Frigate can remain running on the VM, but its MQTT-to-HA notification path is affected. Beetroot is also lost. |
| Cloudflare tunnel | Public tunnel routes fail. LAN access and functioning Tailscale routes are separate paths. |
| AdGuard on VM | Devices using it for DNS can lose name resolution even if internet connectivity still exists. Direct IP access and clients using other resolvers may differ. |
| Shared Chrome | Browser-based case monitoring, booking and browser tooling are affected. IMAP scans and ordinary API integrations need not be. |
| A dashboard web server | Its view is unavailable. The underlying tracker, database or HA automation can remain intact. |
| Proxmox host or its storage | The Ubuntu VM is affected regardless of its guest free space. Pi survives only if its own power/storage/network remain available. |
These are dependency expectations, not outage simulations performed today.
17. How to navigate it without memorising everything
- Something in the house: start with HA entity/automation, then MQTT/device integration, then physical device.
- A failed scheduled task: start with the exact job’s output record, then the script and its dependencies.
- A forgotten fact or decision: session history for the exchange, Mnemosyne for durable memory, workspace for canonical records.
- A missing document: Paperless ingestion and media/metadata, then the Drive mirror if relevant.
- A wrong dashboard number: trace its export back to its CSV/tracker/API source. Fix the producer rather than editing a generated view.
- An app cannot be reached: separate DNS, proxy/tunnel, host port, container/service and application/database.
- A lost voice note: Ringbearer capture archive first, then its forwarding/filing records. An absent capture cannot diagnose what happened on the phone.
- A server lost:
RESTORE.md, independent encryption credentials, staged recovery and verification before startup.
18. Evidence and limits
Sources inspected: live Docker inspect inventory, systemd user-service list and selected unit definitions, current Hermes config with whitelisted non-secret fields, live LLM-shim TOML, live Cloudflare ingress with private route identifiers redacted, current jobs.json, HA Core/MCP app/integration/Assist inventories, read-only SSH container/standby job listing, pipeline script headers/source and the existing recovery/ownership documents.
Same-day verified health details are also recorded in the full-stack-audit skill’s 1 November baseline. Old skill prose is used only for explicitly documented relationships, not treated as current deployment evidence.
Not newly verified: physical hypervisor inventory, every device/room mapping, every app’s internal AI settings, current Cloudflare Access policy per route, Pi tunnel ingress parity, all Tailscale advertised routes, all PWA sync endpoints, individual satellite pipeline selection, end-to-end voice/visitor tests or full disaster recovery. A running service and a configured arrow are different levels of evidence.
19. Live service and schedule appendices
The inventories below are generated from the collected snapshot. Private routes are named by function and no credential values are included.
A. All VM containers
Published ports show host bindings. Empty means no published host port, not absence of an internal service. Volume names are persistent Docker stores.
actual
- Status: running. Image:
actualbudget/actual-server:latest. - Project:
actual. - Published:
0.0.0.0:5006 → 5006/tcp;:::5006 → 5006/tcp. - Networks:
actual_default. - Persistent mappings: actual_actual-data → /data.
adguard
- Status: running. Image:
adguard/adguardhome:latest. - Project:
adguard. - Published:
0.0.0.0:3002 → 3000/tcp;0.0.0.0:8080 → 80/tcp;192.168.0.182:53 → 53/tcp;192.168.0.182:53 → 53/udp;:::3002 → 3000/tcp;:::8080 → 80/tcp. - Networks:
adguard_default. - Persistent mappings: adguard_adguard_conf → /opt/adguardhome/conf; adguard_adguard_work → /opt/adguardhome/work.
camofox
- Status: running. Image:
camofox-browser:latest. - Project:
16. - Published:
127.0.0.1:9377 → 9377/tcp. - Networks:
16_default. - Persistent mappings: 16_camofox-data → /data.
cloudflared
- Status: running. Image:
cloudflare/cloudflared:latest. - Project:
no Compose label. - Published: none.
- Networks:
host. - Persistent mappings: cloudflared-config → /etc/cloudflared.
couchdb
- Status: running. Image:
couchdb:3. - Project:
couchdb. - Published:
0.0.0.0:5984 → 5984/tcp;:::5984 → 5984/tcp. - Networks:
couchdb_default. - Persistent mappings: couchdb_couchdb_data → /opt/couchdb/data.
doorbell-web
- Status: running. Image:
python:3.11-slim. - Project:
doorbell. - Published:
0.0.0.0:8657 → 8657/tcp;:::8657 → 8657/tcp. - Networks:
doorbell_default. - Persistent mappings: /home/joe/.hermes/scripts/doorbell-web.py → /app/doorbell-web.py; /home/joe/.hermes/state → /state.
fossil-log
- Status: running. Image:
python:3.11-slim. - Project:
fossil-log. - Published:
0.0.0.0:8644 → 8644/tcp;:::8644 → 8644/tcp. - Networks:
fossil-log_default. - Persistent mappings: /home/joe/Downloads/workspace-20260625T191839Z-3-001/workspace/workspace/fossil-log → /app.
frigate
- Status: running. Image:
ghcr.io/blakeblackshear/frigate:0.18.0. - Project:
frigate. - Published:
0.0.0.0:5000 → 5000/tcp;0.0.0.0:8554 → 8554/tcp;:::5000 → 5000/tcp;:::8554 → 8554/tcp. - Networks:
frigate_default. - Persistent mappings: /etc/localtime → /etc/localtime; /home/joe/frigate/media → /media/frigate; /home/joe/frigate/config → /config.
gptr-mcp
- Status: running. Image:
gptr-mcp:latest. - Project:
gptr-mcp. - Published:
127.0.0.1:8933 → 8000/tcp. - Networks:
open-webui_default. - Persistent mappings: none recorded.
gws_mcp
- Status: running. Image:
workspace-mcp:local. - Project:
gws_mcp. - Published:
127.0.0.1:8010 → 8000/tcp. - Networks:
open-webui_default. - Persistent mappings: /home/joe/.hermes/mcp-servers/google_workspace_mcp/client_secret.json → /app/client_secret.json; gws_mcp_creds → /app/store_creds.
healthchecks
- Status: running. Image:
healthchecks/healthchecks:latest. - Project:
healthchecks. - Published:
0.0.0.0:8652 → 8000/tcp;:::8652 → 8000/tcp. - Networks:
healthchecks_default. - Persistent mappings: healthchecks_healthchecks_data → /data.
hoarder_app
- Status: running. Image:
ghcr.io/hoarder-app/hoarder:release. - Project:
hoarder. - Published:
0.0.0.0:8649 → 3000/tcp;:::8649 → 3000/tcp. - Networks:
hoarder_default. - Persistent mappings: hoarder_hoarder-data → /data.
hoarder_chrome
- Status: running. Image:
ghcr.io/karakeep-app/karakeep-chrome:release. - Project:
hoarder. - Published: none.
- Networks:
hoarder_default. - Persistent mappings: none recorded.
hoarder_meilisearch
- Status: running. Image:
getmeili/meilisearch:latest. - Project:
hoarder. - Published: none.
- Networks:
hoarder_default. - Persistent mappings: hoarder_hoarder-meili → /meili_data.
immich_machine_learning
- Status: running. Image:
ghcr.io/immich-app/immich-machine-learning:v3. - Project:
immich. - Published: none.
- Networks:
immich_default. - Persistent mappings: immich_model-cache → /cache.
immich_postgres
- Status: running. Image:
ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23. - Project:
immich. - Published: none.
- Networks:
immich_default. - Persistent mappings: immich_immich-postgres → /var/lib/postgresql/data.
immich_redis
- Status: running. Image:
docker.io/valkey/valkey:9@sha256:8e8d64b405ce18f41b8e5ee20aa4687a8ed0022d1298f2ce31cdcf3a76e09411. - Project:
immich. - Published: none.
- Networks:
immich_default. - Persistent mappings: none recorded.
immich_server
- Status: running. Image:
ghcr.io/immich-app/immich-server:v3. - Project:
immich. - Published:
0.0.0.0:2283 → 2283/tcp;:::2283 → 2283/tcp. - Networks:
immich_default. - Persistent mappings: immich_immich-library → /data; /etc/localtime → /etc/localtime.
mcpo
- Status: running. Image:
mcpo-camofox:latest. - Project:
17. - Published:
127.0.0.1:8932 → 8000/tcp. - Networks:
camofox_default,open-webui_default. - Persistent mappings: none recorded.
mealie
- Status: running. Image:
hkotel/mealie:latest. - Project:
mealie. - Published:
0.0.0.0:8648 → 9000/tcp;:::8648 → 9000/tcp. - Networks:
mealie_default. - Persistent mappings: mealie_mealie-data → /app/data.
nextchat-webdav
- Status: running. Image:
sigoden/dufs. - Project:
nextchat-webdav. - Published:
0.0.0.0:8300 → 5000/tcp;:::8300 → 5000/tcp. - Networks:
nextchat-webdav_default. - Persistent mappings: /home/joe/nextchat-sync → /data.
nginx-proxy-manager-npm-1
- Status: running. Image:
jc21/nginx-proxy-manager:latest. - Project:
nginx-proxy-manager. - Published:
0.0.0.0:80 → 80/tcp;0.0.0.0:81 → 81/tcp;192.168.0.182:443 → 443/tcp;:::80 → 80/tcp;:::81 → 81/tcp. - Networks:
nginx-proxy-manager_default. - Persistent mappings: nginx-proxy-manager_npm-data → /data; nginx-proxy-manager_npm-letsencrypt → /etc/letsencrypt.
open-notebook-open_notebook-1
- Status: running. Image:
lfnovo/open_notebook:v1-latest. - Project:
open-notebook. - Published:
0.0.0.0:8502 → 8502/tcp;127.0.0.1:5055 → 5055/tcp;:::8502 → 8502/tcp. - Networks:
open-notebook_default. - Persistent mappings: open-notebook_notebook-data → /app/data.
open-notebook-surrealdb-1
- Status: running. Image:
surrealdb/surrealdb:v2. - Project:
open-notebook. - Published: none.
- Networks:
open-notebook_default. - Persistent mappings: 3c46a65756f22bd96f75e63eeb2bccc4b6213bef37b1e662c592332b372d3646 → /logs; open-notebook_surreal-data → /mydata; 967da7d1740e5e33614c21a717dfce0d6f2b8037d3bbc68cda08d3152aba745d → /data.
open-terminal
- Status: running. Image:
ghcr.io/open-webui/open-terminal:latest. - Project:
45. - Published:
127.0.0.1:8900 → 8000/tcp. - Networks:
open-webui_default. - Persistent mappings: open-terminal → /home/user.
open-webui
- Status: running. Image:
ghcr.io/open-webui/open-webui:v0.11.4. - Project:
open-webui. - Published:
0.0.0.0:3000 → 8080/tcp;:::3000 → 8080/tcp. - Networks:
open-webui_default. - Persistent mappings: open-webui_open-webui-data → /app/backend/data.
paperless-broker-1
- Status: running. Image:
docker.io/valkey/valkey:9-alpine. - Project:
paperless. - Published: none.
- Networks:
paperless_default. - Persistent mappings: paperless_redisdata → /data.
paperless-db-1
- Status: running. Image:
docker.io/library/postgres:18. - Project:
paperless. - Published: none.
- Networks:
paperless_default. - Persistent mappings: paperless_pgdata → /var/lib/postgresql.
paperless-gotenberg-1
- Status: running. Image:
docker.io/gotenberg/gotenberg:8.34. - Project:
paperless. - Published: none.
- Networks:
paperless_default. - Persistent mappings: none recorded.
paperless-tika-1
- Status: running. Image:
docker.io/apache/tika:latest. - Project:
paperless. - Published: none.
- Networks:
paperless_default. - Persistent mappings: none recorded.
paperless-webserver-1
- Status: running. Image:
ghcr.io/paperless-ngx/paperless-ngx:latest. - Project:
paperless. - Published:
0.0.0.0:8001 → 8000/tcp;:::8001 → 8000/tcp. - Networks:
paperless_default. - Persistent mappings: /home/joe/stacks/12/consume → /usr/src/paperless/consume; paperless_data → /usr/src/paperless/data; /home/joe/stacks/12/export → /usr/src/paperless/export; paperless_media → /usr/src/paperless/media.
portainer
- Status: running. Image:
portainer/portainer-ce:2.39.2. - Project:
portainer. - Published:
0.0.0.0:8000 → 8000/tcp;0.0.0.0:9000 → 9000/tcp;0.0.0.0:9443 → 9443/tcp;:::8000 → 8000/tcp;:::9000 → 9000/tcp;:::9443 → 9443/tcp. - Networks:
portainer_default. - Persistent mappings: portainer_data → /data; /var/run/docker.sock → /var/run/docker.sock.
portal-dash
- Status: running. Image:
python:3.11-slim. - Project:
portal-dash. - Published:
0.0.0.0:8640 → 8640/tcp;:::8640 → 8640/tcp. - Networks:
portal-dash_default. - Persistent mappings: /home/joe/Downloads/workspace-20260625T191839Z-3-001/workspace/workspace/portal-dash → /app; /home/joe/.hermes/ha-token → /run/secrets/ha-token.
ringbearer
- Status: running. Image:
ringbearer:local. - Project:
ringbearer. - Published:
127.0.0.1:8787 → 8787/tcp;192.168.0.182:8787 → 8787/tcp. - Networks:
ringbearer_default. - Persistent mappings: /home/joe/ringbearer/docker/data → /data.
searxng
- Status: running. Image:
searxng/searxng:latest. - Project:
searxng. - Published:
0.0.0.0:8081 → 8080/tcp;:::8081 → 8080/tcp. - Networks:
searxng_default. - Persistent mappings: searxng_searxng-data → /etc/searxng; e2c935784fd6c3a7248c16df88429b2d8717dc64aeecba7c855a30225d8dc616 → /var/cache/searxng.
solar
- Status: running. Image:
python:3.11-slim. - Project:
solar. - Published:
0.0.0.0:8658 → 8658/tcp;:::8658 → 8658/tcp. - Networks:
solar_default. - Persistent mappings: /home/joe/Downloads/workspace-20260625T191839Z-3-001/workspace/workspace/solar-site → /app.
stirling_pdf
- Status: running. Image:
ghcr.io/stirling-tools/s-pdf:latest. - Project:
stirling. - Published:
0.0.0.0:8647 → 8080/tcp;:::8647 → 8080/tcp. - Networks:
stirling_default. - Persistent mappings: /data/stirling/pipeline → /pipeline; /etc/localtime → /etc/localtime; stirling_stirling-configs → /configs; /data/stirling/storage → /storage.
tailscale
- Status: running. Image:
tailscale/tailscale:latest. - Project:
tailscale. - Published: none.
- Networks:
host. - Persistent mappings: tailscale-state → /var/lib/tailscale.
tei-embeddings
- Status: exited. Image:
ghcr.io/huggingface/text-embeddings-inference:cpu-1.8. - Project:
tei-embeddings. - Published: none.
- Networks:
tei-embeddings_default. - Persistent mappings: /data/models/tei → /data.
tracker-app
- Status: running. Image:
tracker-app-tracker-app. - Project:
tracker-app. - Published:
0.0.0.0:8643 → 8643/tcp;:::8643 → 8643/tcp. - Networks:
tracker-app_default. - Persistent mappings: /home/joe/Downloads/workspace-20260625T191839Z-3-001/workspace/workspace → /root/workspace; /home/joe/.hermes/scripts → /root/scripts.
uptime-kuma
- Status: running. Image:
louislam/uptime-kuma:2. - Project:
uptime-kuma. - Published:
0.0.0.0:3001 → 3001/tcp;:::3001 → 3001/tcp. - Networks:
camofox_default,open-webui_default,playwright-mcp_default,uptime-kuma_default. - Persistent mappings: uptime-kuma_uptime-kuma-data → /app/data.
vaultwarden-vaultwarden-1
- Status: running. Image:
vaultwarden/server:latest. - Project:
vaultwarden. - Published:
0.0.0.0:8383 → 80/tcp;:::8383 → 80/tcp. - Networks:
vaultwarden_default. - Persistent mappings: vaultwarden_vw-data → /data.
wyoming-piper
- Status: running. Image:
rhasspy/wyoming-piper:latest. - Project:
wyoming-piper. - Published:
0.0.0.0:10301 → 10200/tcp;:::10301 → 10200/tcp. - Networks:
wyoming-piper_default. - Persistent mappings: wyoming-piper_wyoming-piper-data → /data.
wyoming-whisper
- Status: running. Image:
rhasspy/wyoming-whisper:latest. - Project:
wyoming-whisper. - Published:
0.0.0.0:10300 → 10300/tcp;:::10300 → 10300/tcp. - Networks:
wyoming-whisper_default. - Persistent mappings: wyoming-whisper_wyoming-whisper-data → /data.
zettelrobbe
- Status: running. Image:
admonstrator/zettelrobbe:latest. - Project:
zettelrobbe. - Published:
0.0.0.0:8651 → 3000/tcp;:::8651 → 3000/tcp. - Networks:
zettelrobbe_default. - Persistent mappings: zettelrobbe_zettelrobbe_data → /app/data.
B. All main Hermes job definitions
This is the primary profile only. The Pi standby has separate ownership and predominantly disabled mirrored definitions.
| Job | Enabled | Execution | Schedule | Delivery |
|---|
| ani-threshold-check | yes | script: ani-threshold-check.py | once at 2027-03-01 09:00 | origin |
| b2-immich-status | yes | script: b2-immich-status.py | 0 9,15,21 * * * | telegram:5833220727 |
| backup-freshness-watch | yes | script: backup-freshness-watch.py | 40 9 * * * | origin |
| backup-integrity-check | yes | script: backup-integrity-check.py | 30 9 1 * * | origin |
| beetroot-sync | yes | script: beetroot-sync.py | */15 * * * * | telegram:5833220727 |
| beetroot-watch | yes | script: beetroot-watch.py | */30 * * * * | telegram:5833220727 |
| case-watch | yes | script: case-watch/case-watch.sh | 10 9 * * * | origin |
| cf-tunnel-route-audit | yes | script: cf-tunnel-route-audit.py | 15 6 * * * | origin |
| clubspark-monday-book | yes | script: clubspark-book-monday.py | 5,35 0 * * 5,6 | origin |
| cron-failure-triage | yes | agent + cron-failure-snapshot.py | 0 */4 * * * | local |
| cron-health-check | yes | script: cron-health-check.py | 0 10 * * 1 | origin |
| cron-incident-reconcile | yes | script: cron-incident-reconcile.py | every day at 6:20am | local |
| cron-output-prune | yes | script: cron-output-prune.py | 0 3 * * * | local |
| Daily finance refresh (ISA/GIA from HA) | yes | script: daily-finance-refresh.py | 40 18 * * * | origin |
| Daily investment gains (ISA/GIA cost basis) | yes | script: daily-investment-gains.py | 10 18 * * * | origin |
| daily-fact-extraction | yes | agent | 0 3 * * * | local |
| daily-health-sync | yes | script: daily-health-sync.py | 45 8 * * * | origin |
| daily-tick | yes | script: daily-tick.py | 0 8 * * * | origin |
| disk-growth-snapshot | yes | script: disk-growth-snapshot.py | 15 5 * * * | telegram:5833220727 |
| disk-health | yes | script: disk-health.py | 30 4 * * * | origin |
| docker-stack-updater | yes | script: docker-stack-updater.py | 0 4 * * * | origin |
| doorbell-backfill | yes | script: doorbell-backfill.py | every 120m | local |
| doorbell-health | yes | script: doorbell-health.py | 45 7 * * * | origin |
| doorbell-learn | yes | script: doorbell-learn.py | 50 4 * * * | origin |
| doorbell-observations | yes | script: doorbell-observations.py | */10 * * * * | origin |
| doorbell-prune | yes | script: doorbell-prune.py | 30 4 * * * | local |
| doorbell-weekly-report | yes | script: doorbell-weekly-report.sh | 25 9 * * 0 | origin |
| drive-token-watch | yes | script: drive-token.py | 50 7 * * * | origin |
| email-draft-preparer | yes | agent | 30 12,18 * * * | local |
| email-register-scan | yes | script: email-scanner.py | 0 12,18 * * * | origin |
| finance-export | yes | script: finance-export.sh | 55 8 * * * | local |
| garden-camera-clock | yes | script: garden-camera-clock.py | 15 3 * * * | origin |
| google-store-credit-reminder | yes | script: remind-google-store-credit.py | once at 2027-04-24 09:00 | origin |
| gws-token-watch | yes | script: gws-token-watch.py | 5 9 * * * | origin |
| ha-b2-backup | yes | script: ha-b2-backup.py | 30 7 * * * | origin |
| ha-cache-refresh | yes | script: ha-cache-refresh.py | 0 6 * * * | origin |
| ha-health-watch | yes | script: ha-health-watch.py | */30 * * * * | origin |
| health-export | yes | script: health-export.py | 50 8 * * * | origin |
| health-recovery | yes | script: health-recovery.py | 55 8 * * * | local |
| hermes-state-backup | yes | script: hermes-state-backup.py | 45 2 * * * | origin |
| homelab-backup | yes | script: homelab-backup.py | 5 21 * * 0 | origin |
| homelab-backup-integrity | yes | script: homelab-backup-integrity.py | 15 10 * * 1 | origin |
| hubitat-hadb-sync | yes | script: hubitat-hadb-sync.py | 20 6 * * * | origin |
| illness-watchdog | yes | script: illness-watchdog.py | 15 9 * * * | origin |
| immich-album-refresh | yes | script: immich-album-refresh.py | 30 9 * * 0 | telegram:5833220727 |
| immich-b2-backup | yes | script: immich-b2-backup.py | 30 3 * * * | origin |
| index-health-capture | yes | script: health-capture-watch.py | every 1m | local |
| investment-history-log | yes | script: investment-history-log.py | 35 18 * * * | origin |
| investment-monthly-reminder | yes | script: investment-monthly-reminder.py | 0 9 22-28 * 0 | origin |
| kidney-chase | yes | script: kidney-chase.py | 0 9 * * * | origin |
| lifestage-export-reminder | yes | script: lifestage-export-reminder.py | 0 9 1 * * | origin |
| lpr-arrival-check | yes | script: lpr-arrival-check.py | */15 * * * * | origin |
| mealie-weekly | yes | script: mealie-weekly.py | 30 7 * * 4 | local |
| memory-hygiene-check | yes | script: memory-hygiene-check.py | 0 9 1 * * | origin |
| memory-provider-watch | yes | script: memory-provider-watch.py | 23 */3 * * * | origin |
| mnemosyne-backup | yes | script: mnemosyne-backup.py | 10 3 * * * | local |
| mnemosyne-contamination-watch | yes | script: mnemosyne-contamination-watch.py | every day at 22:40 | origin |
| mnemosyne-sleep | yes | script: mnemosyne-sleep.py | 0 3 * * * | local |
| mortgage-position-log | yes | script: mortgage-position.py | 0 8 1 * * | telegram:5833220727 |
| mortgage-remortgage-brief | yes | script: mortgage-remortgage-brief.py | once at 2028-02-29 08:05 | telegram:5833220727 |
| noah-kahan-ticket-watch | yes | script: noah-kahan-ticket-watch.py | every 360m | origin |
| owui-backup | yes | script: owui-backup.py | 0 21 * * 0 | origin |
| owui-browser-defaults | yes | script: owui-browser-defaults-sync.py | 0 * * * * | local |
| owui-health | yes | script: owui-health.py | 15 21 * * 0 | origin |
| owui-memory-sync | yes | script: owui-memory-sync.py | every 15m | local |
| owui-usage-report | yes | script: owui-usage-report.py | 45 9 1 * * | origin |
| Paperless ai-processed auto-heal | yes | script: paperless-ai-processed-watch.py | 17 */6 * * * | origin |
| paperless-drive-sync | yes | script: paperless-drive-sync.py | 15 4 * * * | origin |
| paperless-ingest | yes | script: paperless-ingest.py | 0 9 * * * | origin |
| paperless-tag-watch | yes | script: paperless-tag-dupe-watch.py | 30 8 * * * | origin |
| parcel-crew | yes | script: parcel-crew.py | 0 7 * * * | local |
| pool-hygiene | yes | script: pool-hygiene.sh | 40 4 * * 0 | telegram |
| rag-inventory-check | yes | script: rag-inventory-check.py | 30 20 * * 0 | origin |
| rbw-vault-watch | yes | script: rbw-vault-watch.sh | 45 8 * * * | origin |
| reminder-checker | yes | script: reminder-checker.py | 0 9 * * 0 | telegram:5833220727 |
| renewal-watchdog | yes | script: renewal-watchdog.py | 0 9 * * 1 | origin |
| ringbridge-watch | yes | script: ringbridge-watch.py | 25 9 * * * | origin |
| root-disk-cap | yes | script: root-disk-cap.py | */5 * * * * | telegram:5833220727 |
| root-disk-tripwire | yes | script: root-disk-tripwire.py | 2-57/5 * * * * | telegram:5833220727 |
| session-store-prune | yes | script: session-prune.py | 0 9 1 1,4,7,10 * | origin |
| solar-dashboard-data | yes | script: solar-publish.py | 0 8 * * * | local |
| solar-track | yes | script: solar-track.py | 0 8 1 * * | origin |
| stabilisation-b2-verify | no | script: stabilisation-b2-verify.py | once at 2026-10-31 05:30 | telegram:5833220727 |
| sync-docs-to-rag | yes | script: sync-docs-to-rag.py | 15 7 * * * | origin |
| system-b2-backup | yes | script: system-b2-backup.py | 35 3 * * * | origin |
| system-status | yes | script: system-status.py | */5 * * * * | origin |
| t212-record-watch | yes | script: t212-record-watch.sh | 20 8-20 * * 1-5 | origin |
| t212-sipp-api-watch | yes | script: t212-sipp-api-watch.py | 0 8 1 * * | telegram:5833220727 |
| t212-true-return-daily | yes | script: t212-true-return.py | 25 18 * * * | origin |
| thin-pool-watch | yes | script: thin-pool-watch.py | */5 * * * * | telegram |
| timed-close-of-day | yes | script: timed-close-of-day.py | 0 21 * * * | telegram:5833220727 |
| tracker-intake-merge | yes | script: tracker-intake-merge.py | every 30m | origin |
| tracker-validation | yes | script: system-validate.py | 0 7 * * * | origin |
| weekly-housekeeping | yes | script: weekly-housekeeping.py | 0 20 * * 0 | telegram:5833220727 |
| wiki-graph-refresh | yes | script: wiki-graph-refresh.py | 0 7 * * * | local |
| workspace-git-commit | yes | script: git-auto-commit.sh | 5 7 * * * | origin |
| zigbee-availability-publish | yes | script: zigbee-availability-publish.py | every 15m | local |
| zigbee-budget-calibrate | yes | script: zigbee-budget-calibrate.py | 50 9 1 * * | local |
| zigbee-function-audit | yes | script: zigbee-function-audit.sh | 40 7 * * * | origin |
| zigbee-health-watch | yes | script: zigbee-health-watch.py | 20 8 * * * | origin |
| zigbee-weekly-report | yes | script: zigbee-weekly-report.sh | 20 9 * * 0 | origin |
C. VM Cloudflare ingress
Configured forwarding, not an authenticated end-to-end test. The separate Pi connector also exists and has not been compared here.
| Host / path | Local origin |
|---|
| 00000041.xyz [private bridge route redacted] | http://192.168.0.182:8671 |
| 00000041.xyz [private bridge route redacted] | http://192.168.0.155:9583 |
| 00000041.xyz ^/vault | http://127.0.0.1:8383 |
| 00000041.xyz ^/ringbearer/webhook$ | http://127.0.0.1:8787 |
| 00000041.xyz ^/nextchat-sync | http://127.0.0.1:8300 |
| 00000041.xyz | http://192.168.0.155:8123 |
| pulse.00000041.xyz | http://127.0.0.1:8645 |
| owui.00000041.xyz | http://127.0.0.1:3000 |
| paperless.00000041.xyz | http://127.0.0.1:8001 |
| kuma.00000041.xyz | http://127.0.0.1:3001 |
| portainer.00000041.xyz | https://127.0.0.1:9443 |
| tennis.00000041.xyz | http://127.0.0.1:8646 |
| fossil.00000041.xyz | http://127.0.0.1:8644 |
| solar.00000041.xyz | http://127.0.0.1:8658 |
| sun.00000041.xyz | http://127.0.0.1:8658 |
| health.00000041.xyz | http://127.0.0.1:8654 |
| finance.00000041.xyz | http://127.0.0.1:8656 |
| immich.00000041.xyz | http://127.0.0.1:2283 |
| stirling.00000041.xyz | http://127.0.0.1:8647 |
| mealie.00000041.xyz | http://127.0.0.1:8648 |
| hoarder.00000041.xyz | http://127.0.0.1:8649 |
| notebook.00000041.xyz | http://127.0.0.1:8502 |
| doorbell.00000041.xyz | http://127.0.0.1:8657 |
| frigate.00000041.xyz | http://127.0.0.1:5000 |
| todo.00000041.xyz | http://127.0.0.1:8659 |
| catch-all | http_status:404 |