Architecture Overview
Architecture Overview
Section titled βArchitecture OverviewβArchitecture of the Personal Digital Estate. Human-readable Mermaid diagrams are the source for human understanding; formal C4 diagrams stay in the appendix as an agent-facing exception.
Topic index
Section titled βTopic indexβ| # | Topic | Where documented |
|---|---|---|
| 1 | Interaction channels | How Francois talks to the estate |
| 2 | CLI workflow | Interaction channels β Work vs Home vs Hermes contexts |
| 3 | Delivery modes | Delivery workflow β branch-review / autonomous / auto-commit |
| 4 | GitHub auth | Quick reference β fine-grained PAT, scoped per-repo |
| 5 | PAT expiry | SOUL.md cron table β weekly check, Telegram alert at 7 days |
| 6 | Security model | ADR-0007 β plaintext .env + OS hardening |
| 7 | Drive mounts | SSOT split + CONTEXT.md glossary β 3 rclone mounts |
| 8 | LLM routing | SOUL.md LLM routing β local / free / premium tiers |
| 9 | VPS agnosticism | ADR-0008 β DRP, daily encrypted GitHub backup + weekly offline copy, 60-min rebuild |
| 10 | Dashboard access | ADR-0006 + Network topology β CF Tunnel + Access email OTP |
| 11 | Secrets management | ADR-0007 β threat model, upgrade triggers |
| 12 | Disaster recovery | ADR-0008 β RTO/RPO, encrypted backup/decrypt procedure |
| 13 | Hermes updates | SOUL.md cron table β notify-only, manual upgrade |
| 14 | Monitoring & health | CONTEXT.md glossary + SOUL.md cron table β Uptime Kuma at health.ducatillon.net |
The Big Picture β Who uses what?
Section titled βThe Big Picture β Who uses what?βflowchart TB subgraph people ["π₯ People"] F["π§βπ» Francois\nM1Max Β· Pixel 9A Β· M3Pro"] D["π© Djuly\nPhone"] K["π§π¦ Kids\nPhones/tablets"] end
subgraph perso ["π Personal Digital Estate"]
subgraph telegram_block ["π¬ Telegram"] TG["Telegram Bot"] end
subgraph vps ["π₯οΈ Agent Host β Hostinger VPS KVM2"] H["π€ Hermes Agent\nπ Unified Project Radar\npersonal day one Β· family/pro roadmap"] UK["π Uptime Kuma\nhealth.ducatillon.net"] end
subgraph perso_google ["βοΈ Google (Personal account)"] GD["π Personal Google Drive\nPARA: Projects Β· Areas\nResources Β· Archive\n(Knowledge Vault β SSOT)"] GP["π· Google Photos"] end
subgraph cloudflare ["π Cloudflare"] SITES["π 6 Static Sites\nnotes Β· strata Β· locationyeu\nchateaudebourgon Β· sommelier-arena Β· docs"] end
subgraph perso_tools ["π§ Personal Tools"] BW["π Bitwarden\nCredentials"] GH_PERSO["π GitHub (perso)\nPrivate repos\nhugo-air Β· strata Β· arch-wiki"] OR["π§ OpenRouter\nFree + Premium LLMs"] end
subgraph backup_block ["πΎ Backup"] HD["ποΈ External HD\nWeekly"] GH_BACKUP["π Private GitHub repo\nEncrypted Hermes backups\nDaily"] end
end
subgraph pro ["π’ Professional Boundary β Decathlon"] SSO["π Company SSO"] PRO_SOURCES["π Professional sources\nRoadmap only\nno VPS token day one"] GH_PRO["π GitHub (pro)\nDecathlon org repos"] MISSION["π― Pro Mission\n(north star β being written)\nHR ladder Β· career path"] end
%% People β Personal Estate F -- "chat, ask, delegate" --> TG D -- "chat, ask" --> TG TG -- "messages" --> H
F -- "web dashboard\nhermes.ducatillon.net" --> H
%% Hermes β Personal tools H -- "read/write\n.md notes" --> GD H -- "LLM inference" --> OR H -- "read/write code\n(with approval)" --> GH_PERSO H -. "no direct token\non Agent Host" .-> GH_PRO
%% Francois β Personal tools F -- "edit .md (VSCode)\nedit .gdoc (browser)" --> GD F -- "push code" --> GH_PERSO F -- "manage sites" --> SITES D -- "shared docs" --> GD K -- "photos, storage" --> GP F -- "photos" --> GP
F -- "all credentials\n(all devices)" --> BW H -- "reads API keys\nfrom ~/.hermes/.env\n(copied from Bitwarden)" --> BW
GH_PERSO -- "auto-deploy\non push" --> SITES
H -. "daily encrypted\nstate backup" .-> GH_BACKUP GH_BACKUP -. "weekly offline copy" .-> HD F -- "manual weekly\nnon-Hermes backup" --> HD
%% Pro/Perso bridges (cross the boundary) F -- "daily work\n(via SSO)" --> SSO SSO --> PRO_SOURCES SSO --> GH_PRO PRO_SOURCES -. "roadmap only:\nno VPS token day one" .-> H GH_PRO -. "no VPS token\nday one" .-> H MISSION -. "guides priorities\nin Unified Radar" .-> H F -. "skills flow both ways:\nDDD Β· C4 Β· AI context" .-> pro
style perso fill:#e8f5e9,stroke:#2e7d32 style pro fill:#fff3e0,stroke:#e65100How the boundary works: Francois decides which project lives in which PARA β by instinct and judgment, not by technical rule. A perso PARA project (like this architecture wiki) can deliver career value; a pro PARA skill (like DDD) can flow into personal projects. The boundary is a human routing decision. Day one, Hermes reads Francoisβs personal sources only on the VPS; Djuly and pro source access remain roadmap until there are approved boundary-safe patterns. The target remains a Unified Project Radar β one prioritized view mixing pro and perso, guided by the Pro Mission.
Inside the Agent Host β What Hermes is made of
Section titled βInside the Agent Host β What Hermes is made ofβflowchart LR subgraph inputs ["π₯ Inputs"] TG["π¬ Telegram\nFrancois + Djuly"] WEB["π Web Dashboard\nhermes.ducatillon.net\nport 9119"] end
subgraph hermes ["π€ Hermes Agent (VPS)"] GW["πͺ Gateway\nhermes-gateway systemd\nRoutes: Telegram Β· Web Β· CLI"] CORE["π§ Core Agent\nReasoning Β· tool calling\ndelegation"] DASH["π Dashboard\nport 9119 β Sessions Β· Logs\nCron Β· Analytics Β· Skills Β· Chat\nNo web secret editing day one"] ROUTER["π 9router\nport 3000 (nginx β 80)\nModel router Β· multi-provider\nusage stats"] MEM["πΎ Memory\nSQLite + FTS5\npersistent cross-session"] SK["β‘ Skills\nLearned procedures\nself-improving"] STATE["βοΈ Config\n~/.hermes/\nSOUL.md Β· config.yaml\ncron jobs Β· .env"] end
subgraph data ["π¦ Data Access"] BRIDGE["π Drive Bridge\nrclone mount\n/mnt/gdrive/"] GHUB["π GitHub MCP\nread/write code\n(with approval)"] end
subgraph external ["βοΈ External"] GD_PERSO["π Personal Google Drive\nKnowledge Vault (read/write)"] OR["π§ OpenRouter\nFree model (default)\nPremium model (on-demand)"] BW["π Bitwarden\nAPI keys & secrets"] end
subgraph backup_agent ["πΎ Backup"] HD["ποΈ External HD\nWeekly offline copy"] GH_BACKUP["π Private GitHub repo\nDaily encrypted state"] end
TG -- "messages" --> GW WEB -- "messages" --> DASH DASH -- "embedded Chat\n(PTY/WebSocket)" --> GW GW -- "routes to" --> CORE CORE -- "remembers" --> MEM CORE -- "uses & improves" --> SK CORE -- "reads config" --> STATE CORE -- "reads/writes files" --> BRIDGE CORE -- "reads/writes code\n(with approval)" --> GHUB CORE -- "LLM calls" --> ROUTER ROUTER -- "routes to\nproviders" --> OR CORE -- "reads ~/.hermes/.env" --> STATE BRIDGE -- "Personal Drive API\nread/write with caching" --> GD_PERSO MEM -. "backed up daily\nencrypted" .-> GH_BACKUP SK -. "backed up daily\nencrypted" .-> GH_BACKUP STATE -. "backed up daily\nencrypted" .-> GH_BACKUP GH_BACKUP -. "weekly copy" .-> HDNetwork topology β How traffic flows
Section titled βNetwork topology β How traffic flowsβflowchart LR subgraph home ["π Home / Mobile"] BROWSER["π Browser\n(any device)"] TG_APP["π¬ Telegram App"] SSH_CLIENT["π SSH\n(M1Max only)"] end
subgraph cloudflare ["βοΈ Cloudflare Edge (global CDN)"] CF_ACCESS["π Cloudflare Access\nEmail OTP gate"] CF_PAGES["π Cloudflare Pages\ndocs.ducatillon.net\n(static Astro site)"] CF_TUNNEL_EP["π Tunnel Endpoint\nhermes.ducatillon.net"] CF_DNS_R["π·οΈ DNS\n*.ducatillon.net"] end
subgraph telegram_cloud ["π¬ Telegram Cloud"] TG_API["Telegram Bot API\n(forwards messages)"] end
subgraph github_cloud ["π GitHub"] GH_REPO["fducat18/docs.ducatillon.net\n(SSOT β .md files)"] GH_PAGES_HOOK["Webhook\n(on push β deploy)"] end
subgraph hostinger ["π₯οΈ Hostinger Datacenter (Lithuania/NL)"] subgraph vps ["Agent Host VPS β KVM2"] CLOUDFLARED["cloudflared daemon\n(outbound tunnel)"] HERMES_GW["hermes-gateway\nport 9119 (dashboard)\nTelegram webhook"] NGINX["nginx\nport 80 β 9router:3000"] UFW["π§± UFW Firewall\nonly port 22 inbound"] end end
%% User β Cloudflare BROWSER -- "HTTPS\ndocs.ducatillon.net" --> CF_ACCESS CF_ACCESS -- "β
authenticated" --> CF_PAGES BROWSER -- "HTTPS\nhermes.ducatillon.net" --> CF_ACCESS CF_ACCESS -- "β
authenticated" --> CF_TUNNEL_EP
%% Cloudflare β VPS (tunnel is OUTBOUND from VPS) CF_TUNNEL_EP -. "tunnel\n(VPS initiated)" .-> CLOUDFLARED CLOUDFLARED -- "localhost:9119" --> HERMES_GW
%% Telegram flow TG_APP -- "message" --> TG_API TG_API -- "webhook POST\n(via Cloudflare Tunnel)" --> HERMES_GW
%% SSH (direct, only inbound port) SSH_CLIENT -- "port 22\n(key-based only)" --> UFW UFW -- "allowed" --> vps
%% GitHub β Cloudflare Pages GH_REPO -- "push event" --> GH_PAGES_HOOK GH_PAGES_HOOK -- "build & deploy" --> CF_PAGES
%% Hermes β GitHub (outbound) HERMES_GW -- "GitHub MCP\n(reads .md)" --> GH_REPO
%% Styling style hostinger fill:#e3f2fd,stroke:#1565c0 style cloudflare fill:#fff3e0,stroke:#e65100 style home fill:#e8f5e9,stroke:#2e7d32Key security properties of this topology:
- Zero inbound ports on VPS (except SSH/22) β Cloudflare Tunnel is outbound-only
- All web traffic authenticated β Cloudflare Access (email OTP) gates both
hermes.ducatillon.netanddocs.ducatillon.net - Telegram webhook secured β delivered through the same tunnel, not a public endpoint
- VPS β Internet β the VPS has its own public IP in Hostingerβs datacenter; it doesnβt use your home internet at all
- Docs site independent β if VPS dies, docs.ducatillon.net stays up (Cloudflare Pages is separate infrastructure)
- SSOT is GitHub β both Cloudflare Pages and Hermes (via MCP) read from the same repo
How things connect β The data flow
Section titled βHow things connect β The data flowβflowchart TB subgraph perso_boundary ["π Personal Digital Estate"]
subgraph devices ["π± Devices"] M1["π₯οΈ MAC PERSO M1Max\nVSCode Β· Google Drive Desktop\nWeb browser Β· Git"] PX["π± Pixel 9A\nMarkor Β· Telegram\nGoogle Drive Β· Web browser"] end
subgraph google_drive ["π Google Drive β Single Source of Truth"] PARA["π PARA Structure\nProjects Β· Areas Β· Resources Β· Archive"] MD[".md notes\nEdited in VSCode / Markor"] GDOC[".gdoc .gsheet\nCollaboration Hub"] end
subgraph vps ["π₯οΈ Agent Host"] H["π€ Hermes Agent"] RCL["π rclone mount\n/mnt/gdrive/"] end
subgraph github_block ["π GitHub (Private repos)"] GH_SITES["π¦ Site repos\nnotes Β· strata Β· locationyeu\nchateaudebourgon Β· sommelier-arena"] GH_ARCH["π¦ Architecture wiki repo\n(this repo β docs.ducatillon.net)"] end
subgraph backup_block ["πΎ Backup"] HD["ποΈ External HD\nWeekly"] end
end
subgraph pro_boundary ["π’ Professional Boundary β Decathlon"] M3["π₯οΈ Decathlon M3Pro\nβ οΈ Managed device\nWeb browser Β· Telegram desktop"] PRO_SOURCES["π Professional sources\nRoadmap only\nno VPS token day one"] SSO["π Company SSO"] end
subgraph cloudflare ["π Cloudflare"] TUNNEL["π Tunnel\nNo open ports"] ACCESS["π Access\nEmail OTP"] PAGES["π Pages\n6 sites"] CF_DNS["π·οΈ DNS + CDN + SSL"] end
subgraph dns ["π·οΈ Domain Registrar"] PH["PlanetHoster"] end
%% MAC PERSO connections M1 -- "Google Drive Desktop\nsync" --> google_drive M1 -- "git push" --> github_block M1 -- "web browser:\nhermes dashboard\ndocs Β· sites" --> cloudflare M1 -- "weekly backup" --> HD
%% Pixel connections PX -- "Google Drive app\n+ Markor" --> google_drive PX -- "Telegram" --> H PX -- "web browser:\nsites Β· docs" --> cloudflare
%% Decathlon M3Pro connections (crosses boundary) M3 -- "Telegram desktop" --> H M3 -- "web browser:\nhermes dashboard\ndocs Β· sites" --> cloudflare M3 -. "read-only\npersonal files" .-> google_drive M3 -- "daily work" --> PRO_SOURCES SSO -- "gates access to" --> PRO_SOURCES
%% Professional reference is roadmap only; no professional token on the Agent Host day one PRO_SOURCES -. "roadmap:\napproved reference only" .-> google_drive
%% Agent Host connections RCL -- "mounts as\nlocal filesystem" --> google_drive H -- "reads/writes via\n/mnt/gdrive/" --> RCL H -- "reads/writes code\n(with approval)" --> github_block
%% Cloudflare connections H -- "dashboard via" --> TUNNEL TUNNEL --> ACCESS ACCESS -- "authenticated\ntraffic" --> H
github_block -- "auto-deploy\non push" --> PAGES
PH -- "nameservers\ndelegated to" --> CF_DNS CF_DNS -- "routes to" --> PAGES CF_DNS -- "routes to" --> TUNNEL
%% Backup connections google_drive -. "weekly snapshot" .-> HD H -. "weekly state backup" .-> HD H -. "daily encrypted\nstate backup" .-> GH_BACKUPQuick reference β What lives where
Section titled βQuick reference β What lives whereβ| Location | Whatβs there | Accessed by |
|---|---|---|
| Google Drive | PARA documents: .md notes, .gdocs, .gsheets (NO code projects) | Francois (all devices), Hermes via day-one Personal Drive Bridge. Djuly/pro mounts are roadmap only. |
| GitHub (perso) | Code projects + architecture wiki (fducat18, SSH) | Francois (git from M1Max), Hermes via HERMES_GITHUB_CODE_PAT (selected repos only; branch-review), Cloudflare Pages |
| GitHub (pro) | Decathlon org repos (francoiducat, SSH) | Francois only (git from M3Pro). Hermes has no pro GitHub token on the Agent Host; it can reason over approved Professional Reference Material only. |
| Hostinger VPS | Hermes Agent (hermes-gateway systemd), Dashboard (port 9119), 9router (port 3000/80), Drive Bridge (rclone), Uptime Kuma (health.ducatillon.net β estate-critical monitoring) | Francois (SSH + dashboard + health page), Djuly (Telegram) |
| Cloudflare | 6 websites, DNS, CDN, Tunnel, Access auth | Public (sites), Francois (dashboard + docs) |
| Bitwarden | All passwords, API keys, SSH keys | Francois (all devices), Hermes (reads API keys) |
| External HD | Weekly backups: photos, vault, Hermes state, Bitwarden | Francois (manual) |
| Private GitHub backup repo | Daily encrypted Hermes state archives only; no plaintext secrets | Agent Host (systemd timer with HERMES_BACKUP_GITHUB_PAT scoped only to this repo), Francois (decrypts with private key from Bitwarden) |
| Google Photos | Family photos (outside Hermes scope) | Francois, Djuly, Kids |
Interaction channels β How Francois talks to the estate
Section titled βInteraction channels β How Francois talks to the estateβ| Context | Tool | Where it runs | What it accesses | When |
|---|---|---|---|---|
| Work (Decathlon M3Pro) | Copilot CLI | Locally on M3Pro | Local files, Pro GitHub | Coding during work hours. Hermes not involved. |
| Home β coding | Pi CLI | Locally on M1Max | Local files, Personal GitHub | Personal project coding. Hermes optional. |
| Home β estate work (preferred) | SSH β hermes --tui | On VPS | Full context: SOUL, memory, Drive Bridge, skills, sessions | The primary channel for estate work. Full Hermes brain. |
| Mobile / async | Telegram | Phone / desktop app | Hermes on VPS | Quick questions, triage, reminders β even while coding locally in another terminal. |
| Visual / config | Web dashboard | Browser β VPS (via CF Tunnel) | Same as Hermes + visual UI | Analytics, logs, cron review, session history, config. |
Key insight: Telegram is the glue channel. When coding locally (Copilot CLI or Pi CLI), Francois can ask Hermes a quick question via Telegram without leaving his terminal workflow. No SSH needed for simple lookups β just open Telegram in another window or on his phone.
Which channel for which need?
| Need | Best channel | Why |
|---|---|---|
| Quick question while coding locally | Telegram | Zero friction, async, any device |
| Deep estate work session | SSH β hermes --tui | Full TUI, long conversation, complex tasks |
| Review analytics / logs / config | Web dashboard | Visual, charts, bulk config |
| βFix this bug on repo Xβ (autonomous) | Telegram | Fire-and-forget β Hermes clones, fixes, pushes branch, CI validates. See autonomous delivery below. |
Where things live β the SSOT split
Section titled βWhere things live β the SSOT splitβ| Content type | SSOT | Why | Hermes access |
|---|---|---|---|
| Documents, notes, .gdoc, .gsheet, small scripts | Google Drive (PARA) | Lightweight, syncs to all devices | Drive Bridge (rclone) |
| Projects with heavy deps (node_modules, venv, dist/) | GitHub | Build artifacts would kill Drive sync | GitHub MCP (read/write with approval) |
| Graduation trigger | First npm install or python -m venv | Thatβs when thousands of files appear | β |
| Google Drive PARA β Code project link | README in PARA folder | Points to GitHub repo URL | Reads both sides |
How Hermes produces code β the delivery workflow
Section titled βHow Hermes produces code β the delivery workflowβflowchart LR F["π§βπ» Francois\n'Fix the date bug\non locationyeu'"] H["π€ Hermes Agent"] GH["π GitHub\n(fducat18)"] TG["π¬ Telegram\nnotification"]
F -- "1. request via\nTelegram / CLI / dashboard" --> H H -- "2. clone / branch\n3. fix code\n4. push branch\n5. create PR" --> GH H -- "6. π 'PR ready\nfor review' + link" --> TG TG -- "7. Francois reviews\nmerges or requests changes" --> GHThe flow:
- Francois asks Hermes for a script, feature, or fix (Telegram, SSH CLI, or dashboard)
- Hermes writes the code on the VPS
- Hermes pushes to a branch on GitHub and creates a PR
- Hermes notifies Francois via Telegram: ββ PR ready β [link]. Summary: fixed date format in locationyeu. CI status: passing.β
- Francois reviews when convenient (GitHub web, or
git pulllocally) - Francois merges (or asks Hermes to revise via Telegram)
What Hermes can NOT do autonomously: push to main, delete branches, force-push, create/delete repos. All destructive actions require explicit approval.
Autonomous delivery (guardrailed)
Section titled βAutonomous delivery (guardrailed)βFor repos with sufficient guardrails, Francois can ask Hermes via Telegram to fix a bug in full autonomy:
flowchart LR F["π§βπ» Francois\nTelegram: 'fix the\nbroken date format\non locationyeu'"] H["π€ Hermes Agent"] GH["π GitHub"] CI["βοΈ CI\nGH Actions"]
F -- "1. fire-and-forget\nrequest" --> H H -- "2. clone / branch\n3. fix code\n4. push branch" --> GH GH -- "5. PR triggers\nCI pipeline" --> CI CI -- "6. E2E + lint +\nhealth checks" --> GH GH -- "7. β
all green?\nauto-merge" --> GH H -- "8. reports result\nback to Francois" --> FPrerequisites for autonomous mode (per-repo):
- β E2E tests covering the affected area
- β GitHub Actions CI pipeline (lint + test + build)
- β
Branch protection rules on
main(require CI pass) - β Health checks / smoke tests post-deploy
- β Francois has explicitly enabled autonomous mode for this repo
Without these guardrails, Hermes falls back to branch-review mode (push branch, wait for human review). The βcareful assistantβ rule is the default β autonomous is the earned exception.
| Scenario | Where Hermes writes | How Francois reviews |
|---|---|---|
| Quick script (one-off utility) | New file in existing repo branch | GitHub web or git pull |
| Feature on existing project | Branch on the projectβs repo | git pull + local testing |
| New project bootstrap | Creates new repo (with approval) | git clone locally |
| Config/automation (VPS) | Directly on VPS filesystem | Reviews via Telegram/dashboard before applying |
Appendix β Formal C4 Model
Section titled βAppendix β Formal C4 ModelβFormal C4 diagrams for agent consumption and technical reference. They intentionally duplicate the human-readable Mermaid views in a more structured notation, even when the result is too dense for human reading.
C4 Level 1 β System Context
Section titled βC4 Level 1 β System ContextβC4Context title Personal Digital Estate β System Context (C4 Level 1)
Person(francois, "Francois", "Estate owner. MAC PERSO M1Max, Pixel 9A, Decathlon M3Pro (read-only)") Person(djuly, "Djuly (wife)", "Telegram access to Hermes. Collaboration Hub user") Person(kids, "Kids", "Family Identity users. Google Drive / Photos")
Enterprise_Boundary(estate, "Personal Digital Estate") { System(hermes, "Hermes Agent", "Self-hosted AI assistant. Telegram + web dashboard. Reads/writes knowledge, tracks projects, drafts content") System(sites, "Static Sites", "6 websites on Cloudflare Pages: notes, strata, locationyeu, chateaudebourgon, sommelier-arena, docs") }
System_Ext(google, "Google", "Drive (Knowledge Vault SSOT), Photos, Docs, Sheets") System_Ext(cloudflare, "Cloudflare", "DNS, CDN, Pages hosting, Tunnel, Access (email OTP)") System_Ext(github, "GitHub", "Private repos: site source code, architecture wiki") System_Ext(openrouter, "OpenRouter", "LLM provider: free models default, premium on-demand") System_Ext(hostinger, "Hostinger", "VPS KVM2: Agent Host") System_Ext(planethoster, "PlanetHoster", "Domain Registrar") System_Ext(bitwarden, "Bitwarden", "Credential Vault: passwords, API keys, SSH keys") System_Ext(decathlon, "Decathlon (Professional Boundary)", "Company SSO, pro Google Drive/GitHub; no Agent Host token day one") System_Ext(telegram, "Telegram", "Messaging gateway for Hermes")
Rel(francois, hermes, "Chats via Telegram & web dashboard") Rel(francois, sites, "Manages & publishes content") Rel(francois, google, "Reads/writes docs, .md notes, photos") Rel(djuly, hermes, "Chats via Telegram") Rel(djuly, google, "Collaboration Hub: shared docs") Rel(kids, google, "Family storage & photos")
Rel(hermes, google, "Reads/writes Knowledge Vault via Drive Bridge") Rel(hermes, openrouter, "LLM inference (free + premium models)") Rel(hermes, github, "Reads/writes code (with approval) via MCP") Rel(sites, cloudflare, "Deployed & served via Cloudflare Pages") Rel(sites, github, "Built from private repos (CI/CD)") Rel(hermes, hostinger, "Runs on VPS KVM2") Rel(hermes, telegram, "Gateway: receives/sends messages") Rel(cloudflare, planethoster, "DNS delegation from registrar") Rel(hermes, cloudflare, "Dashboard exposed via Tunnel + Access") Rel(francois, decathlon, "Read-only Professional Reference Material") Rel(francois, bitwarden, "All credentials (all devices)") Rel(hermes, bitwarden, "Reads API keys & secrets")C4 Level 2 β Container
Section titled βC4 Level 2 β ContainerβC4Container title Personal Digital Estate β Container Diagram (C4 Level 2)
Person(francois, "Francois", "M1Max / Pixel 9A / M3Pro (read-only)") Person(djuly, "Djuly", "Telegram")
System_Ext(google_drive, "Google Drive", "Knowledge Vault SSOT") System_Ext(google_photos, "Google Photos", "Family photos (outside agent scope)") System_Ext(openrouter, "OpenRouter", "Free + premium LLMs") System_Ext(telegram_api, "Telegram API", "Bot gateway") System_Ext(github_api, "GitHub", "Private repos + MCP") System_Ext(decathlon_sources, "Decathlon sources", "Professional Reference Material; no Agent Host token day one")
Container_Boundary(vps, "Agent Host (Hostinger VPS KVM2)") { Container(hermes_core, "Hermes Agent", "Python, NousResearch/hermes-agent", "AI assistant: memory, skills, learning loop, cron scheduler") Container(hermes_gateway, "Hermes Gateway", "Python", "Multi-platform messaging: Telegram, web dashboard") Container(drive_bridge, "Drive Bridge", "rclone FUSE mount", "Mounts Google Drive as /mnt/gdrive for local filesystem access") Container(hermes_memory, "Hermes Memory", "SQLite + FTS5", "Persistent memory, session search, user model") Container(hermes_skills, "Hermes Skills", "YAML + Python", "Learned skills from experience, self-improving") ContainerDb(hermes_state, "Hermes State", "Config + data", "~/.hermes/ β config.yaml, .env, SOUL.md, cron jobs") }
Container_Boundary(cloudflare_b, "Cloudflare") { Container(cf_pages, "Cloudflare Pages", "Static hosting", "6 sites: notes, strata, locationyeu, chateaudebourgon, sommelier-arena, docs") Container(cf_tunnel, "Cloudflare Tunnel", "cloudflared", "Zero-trust tunnel to VPS, no open ports") Container(cf_access, "Cloudflare Access", "Email OTP", "Auth for hermes.ducatillon.net + docs.ducatillon.net") Container(cf_dns, "Cloudflare DNS", "DNS + CDN + SSL", "All domains: *.ducatillon.net, locationyeu.com, chateaudebourgon.com") }
Container_Boundary(devices, "Devices") { Container(mac_perso, "MAC PERSO M1Max", "macOS", "VSCode (.md editing), Google Drive Desktop, primary dev machine") Container(pixel, "Pixel 9A", "Android", "Markor (.md editing), Telegram (Hermes), Google Drive, Aegis (2FA target)") Container(mac_pro, "Decathlon M3Pro", "macOS (managed)", "Google Drive web + Telegram only. No direct vault access") }
Container_Boundary(backup_b, "Backup") { ContainerDb(ext_hd, "External HD", "Weekly offline backup", "Google Photos export, Knowledge Vault snapshot, encrypted Hermes archive, Bitwarden export") ContainerDb(github_backup, "Private GitHub backup repo", "Daily encrypted backup", "Hermes state archives encrypted with age") }
Rel(francois, hermes_gateway, "Telegram + web dashboard (hermes.ducatillon.net)") Rel(djuly, hermes_gateway, "Telegram") Rel(hermes_gateway, hermes_core, "Routes messages to agent") Rel(hermes_core, drive_bridge, "Reads/writes .md notes via /mnt/gdrive") Rel(drive_bridge, google_drive, "rclone: Google Drive API with local caching") Rel(hermes_core, openrouter, "LLM inference (model routing: free default, premium on-demand)") Rel(hermes_core, hermes_memory, "Persists knowledge across sessions") Rel(hermes_core, hermes_skills, "Creates and improves skills from experience") Rel(hermes_core, github_api, "Reads/writes code (with approval) via MCP") Rel(hermes_gateway, telegram_api, "Sends/receives messages") Rel(hermes_gateway, cf_tunnel, "Dashboard exposed via tunnel") Rel(cf_tunnel, cf_access, "Auth gate: email OTP") Rel(cf_pages, github_api, "Auto-deploy on push") Rel(cf_dns, cf_pages, "Routes *.ducatillon.net to Pages")
Rel(mac_perso, google_drive, "Google Drive Desktop sync") Rel(mac_perso, github_api, "Git push (site source, architecture repo)") Rel(pixel, google_drive, "Google Drive app + Markor") Rel(pixel, telegram_api, "Hermes via Telegram") Rel(mac_pro, google_drive, "Google Drive web (read-only personal files)") Rel(mac_pro, telegram_api, "Hermes via Telegram desktop") Rel(mac_pro, decathlon_sources, "Professional work sources")
Rel(hermes_core, github_backup, "Daily encrypted state backup via systemd timer") Rel(github_backup, ext_hd, "Weekly offline copy") Rel(francois, ext_hd, "Manual weekly backup: photos, vault, Bitwarden")