This post documents my setup: a Hermes Agent running on a Raspberry Pi with multiple Telegram bot profiles, each assigned to its own topic within a single supergroup. The entire system integrates with an Obsidian vault for persistent note storage and git-backed sync.

Hardware Foundation

Raspberry Pi 4 running Raspberry Pi OS Lite (no desktop):

# After flashing Pi OS Lite to SD card, enable SSH before first boot
touch /bootfs/ssh

# First login
ssh pi@<ip-address>
sudo raspi-config
# → Interface Options → SSH: Enable
# → Localisation → Timezone: Asia/Singapore

# Static IP via router DHCP reservation recommended for reliable access

Essential packages:

sudo apt update && sudo apt install -y git curl vim htop net-tools

Hermes Agent Installation

# Clone and install
git clone https://github.com/nousresearch/hermes-agent.git ~/.hermes/hermes-agent
cd ~/.hermes/hermes-agent
python3 -m venv venv
source venv/bin/activate
pip install -e .

# Initial setup — configures LLM provider and creates ~/.hermes/.env
hermes setup

Obsidian Vault Integration

The Hermes vault is at ~/obsidian/Hermes/. The agent accesses notes directly through file system tools. The vault uses git for sync:

# Clone the vault
git clone --recurse-submodules git@github.com:teezhiyao/obsidian.git ~/obsidian

Sync Script

Sync runs via a script at ~/obsidian/sync.sh:

#!/bin/bash
cd ~/obsidian
git pull --recurse-submodules
git add -A
git commit -m "Auto-sync $(date +%Y-%m-%d_%H:%M)"
git push --recurse-submodules=on-demand

Auto-Sync on a Schedule

The sync script can be run on a fixed interval using cron. On the Raspberry Pi:

crontab -e

Add a line to run every 30 minutes:

*/30 * * * * /home/pi/obsidian/sync.sh

Adjust the interval based on your needs — every 15 minutes for active writing, hourly for casual use. Note that frequent writes can wear out SD cards on a Pi, so consider running sync on a schedule that balances freshness with longevity.

Syncing on Android (GitSync App)

The Obsidian Git community plugin is not stable on mobile. Instead, use the GitSync app for regular syncing:

  1. Install GitSync from the Play Store
  2. Configure it with your GitHub SSH keys and repo URL
  3. Set a sync schedule (e.g. every 30–60 minutes)
  4. It handles pull, commit, and push automatically

This keeps your vault files synced without relying on any Obsidian plugin — GitSync works at the filesystem level.

Syncing on PC (Obsidian Git Plugin)

On desktop, the Obsidian Git community plugin is stable and recommended:

  1. Open Obsidian → Settings → Community plugins → Browse
  2. Search for “Obsidian Git” and install
  3. Configure it to run backup/push on a schedule (e.g. every 60 minutes) or manually via command palette

Alternative: Obsidian Sync

Instead of git-based syncing, Obsidian Sync is an official subscription service that syncs your vault end-to-end encrypted across all devices. It’s a simpler setup with no SSH keys, git repos, or third-party apps to manage — at the cost of a monthly subscription, and it keeps your notes off GitHub entirely if that’s a concern.

Multi-Profile Telegram Bot Setup

Architecture

ComponentDetails
HostRaspberry Pi 4 (Raspberry Pi OS Lite)
LLMDeepSeek v4 Flash (primary), GPT-4.1 / Copilot (fallback)
InterfaceTelegram (direct messages + supergroup topics)
Profilesdefault (personal), work, qa-planner, blog

Profile Layout

Each Hermes profile is a separate gateway instance with its own Telegram bot token, configuration, and personality. Profiles live under ~/.hermes/profiles/<name>/.

~/.hermes/
├── .env                          # Root env (not read by profile gateways)
├── auth.json                     # Global credential pool
├── config.yaml                   # Root config
└── profiles/
    ├── default/                  # Personal assistant
    │   ├── config.yaml
    │   ├── .env                  # TELEGRAM_BOT_TOKEN + API keys
    │   └── auth.json             # Credential pool
    ├── work/
    │   ├── config.yaml
    │   ├── .env
    │   └── auth.json
    ├── qa-planner/
    │   └── ...
    └── blog/
        └── ...

DM vs Group Group Strategy

Frequently used bots run via direct messages — the bot responds to DMs without any topic filtering. Less frequently used bots are placed in a dedicated supergroup with Topics enabled, each restricted to its own topic.

This avoids cluttering your DM list with bots you rarely talk to, while keeping your primary bot easily accessible via DM.

Which bots use DM vs group:

ProfileInteraction ModeRationale
default (Personal)DMDaily use, quick questions, personal assistant
workDMRegular work queries
qa-plannerGroup topic (QA)Used less often, specialized persona
blogGroup topic (Blog)Used sporadically, content-focused

Creating a Bot via @BotFather

1. Open @BotFather on Telegram
2. Send /newbot
3. Enter display name (e.g. "BlogBot")
4. Enter username ending in "bot" (e.g. "YourBlogBot")
5. Copy the token (format: 1234567890:ABCdefGHIjklmNOPqrstUVwxyz)
6. (Optional) Set profile picture: /setuserpic
7. Disable privacy mode: /mybots → select bot → Bot Settings → Group Privacy → Turn off

Disabling privacy mode is required for the bot to read all messages in a group, not just replies to its own messages.

Creating a New Profile

Clone an existing working profile as a template:

cp -r ~/.hermes/profiles/work ~/.hermes/profiles/<new-profile-name>

Critical — shared API keys in .env:

Each profile gateway reads only its own .env file. The global ~/.hermes/.env is never read by profile gateways. Verify that shared API keys are present:

grep -E '^(DEEPSEEK_|COPILOT_|OPENROUTER_|FIRECRAWL_)' ~/.hermes/profiles/<new-profile-name>/.env

If missing, copy from a working profile:

grep -E '^(DEEPSEEK_|COPILOT_|ANTHROPIC_|OPENROUTER_|FIRECRAWL_)' \
  ~/.hermes/profiles/work/.env >> ~/.hermes/profiles/<new-profile-name>/.env

Set the Telegram bot token:

# Replace with the token from @BotFather
sed -i 's/TELEGRAM_BOT_TOKEN=.*/TELEGRAM_BOT_TOKEN=<your-token>/' \
  ~/.hermes/profiles/<new-profile-name>/.env

# Verify the token works
curl -s "https://api.telegram.org/bot<your-token>/getMe"

Create SOUL.md for personality:

# SOUL

You are a [role]. [One-sentence description of what you do].

Set up a skill for new-profile creation:

The telegram-topic-setup skill at ~/.hermes/skills/autonomous-ai-agents/telegram-topic-setup/SKILL.md automates the entire process:

# Load the skill in a Hermes chat session:
# /skill telegram-topic-setup
# Then tell the agent: "Create a new profile called <name> with bot token <token>"

The skill documents:

  • Profile cloning steps
  • Credential restoration procedures
  • Topic routing configuration
  • Gateway installation and startup
  • Common troubleshooting scenarios

To create a new skill:

hermes skill new <skill-name> --description "<description>"
# Or create ~/.hermes/skills/<category>/<skill-name>/SKILL.md manually

Topic Routing Setup

Enabling Forum Mode

  1. Create a Telegram supergroup
  2. Go to Group Settings → Topics → Enable
  3. Create topics for each profile category

Finding Thread IDs

After adding bots to the group with privacy mode off:

  1. Send a test message in each topic
  2. Check the gateway logs for the session batch key:
grep "agent:main:telegram:group:" ~/.hermes/profiles/<name>/logs/gateway.log | head -5

The thread ID appears in the format:

agent:main:telegram:group:-1003961507518:{thread_id}

The General topic always has thread_id=1.

Configuring ignored_threads

Each profile’s config.yaml needs allowed_chats and ignored_threads under the telegram section:

telegram:
  reactions: false
  allowed_chats: '-1003961507518'
  ignored_threads: '1,4,5,75'   # Comma-separated thread IDs to ignore

The ignored_threads list contains every thread ID EXCEPT the bot’s own topic. When a message arrives from an ignored thread, it is silently dropped. DMs are not affected.

Example — 4-bot setup:

ProfileTopicthread_idignored_threadsIgnores
defaultPersonal411,4,5,75General, Work, QA, Blog
workWork41,5,41,75General, QA, Personal, Blog
qa-plannerQA51,4,41,75General, Work, Personal, Blog
blogBlog751,4,5,41General, Work, QA, Personal

When adding a new bot, update ALL existing profiles’ ignored_threads to include the new topic’s thread ID. Otherwise existing bots respond in the new topic.

Starting the Gateway

# Using Hermes CLI
hermes gateway start --profile <profile-name>

# Or via systemctl directly (avoids CLI timeout)
systemctl --user start hermes-gateway-<profile-name>.service

# Verify
hermes gateway status
# ✓ default — PID 13262
# ✓ work — PID 14151
# ✓ qa-planner — PID 14172
# ✓ blog — PID 15433

Session Management

Each topic maintains its own conversation history, keyed by:

agent:main:telegram:group:{chat_id}:{thread_id}
  • Topics start with independent contexts
  • Memory (user preferences, saved facts) is shared across all sessions within the same profile
  • The bot auto-resumes the correct session when you message in the same topic again

Sync Flow

Obsidian (any device) → git commit + push → GitHub → RPi sync script → local vault on RPi → Hermes reads files

The RPi sync script pulls changes hourly on manual trigger. The sync script also commits and pushes any changes Hermes makes to the vault (notes, task updates, etc.).

Using Cronjobs: Eisenhower Matrix Task Management

The agent can be scheduled to check in on your Eisenhower Matrix daily, keeping tasks current without manual overhead.

The matrix lives at Hermes/Notes/Eisenhower-Matrix.md in the vault with four quadrants (Q1–Q4), a backlog section, and separate 👔 WORK / 🧑 PERSONAL domains. Completed items auto-archive to Completed-Task-Tracking.md at week end.

Creating the Cronjob

hermes cron create \
  --schedule "0 18 * * 1-5" \
  --name "Eisenhower Check-in" \
  --prompt "Read 📊 Hermes/Notes/Eisenhower-Matrix.md from the obsidian vault. Review the matrix, check what's due, then ask me: what I accomplished today, what's pending, and what to promote from the backlog into active quadrants. Update the file with my changes and the new 'Last updated' date."

The cronjob runs at 6 PM on weekdays. The agent reads the matrix, asks what’s done or new, and writes updates back — moving ✅ items to Done, promoting backlog tasks, and adjusting dates.

Manual Usage

In any agent session, just say:

Check 📊 Eisenhower-Matrix.md in the vault for today's priorities.

Blog Content Management via Agent

The Hermes Agent doubles as a content assistant. The blog profile bot (topic-restricted in the supergroup) handles blog writing and editing, but any profile can help draft and manage content since they all share the vault.

How It Works

Blog posts live at Hermes/Personal/Blog/content/posts/ as markdown files with Hugo frontmatter:

---
title: "Post Title"
date: 2025-05-16
categories: [category]
tags: [tag1, tag2]
---

Draft material goes in Hermes/Personal/Blog/drafts/ — ideas, outlines, and in-progress writing. When a draft is ready, the agent can:

  • Expand a draft outline into a full post
  • Format frontmatter correctly for Hugo/Toha
  • Suggest tags and categories based on existing posts
  • Stage the file in content/posts/
  • Commit and push to the blog’s standalone git repo for GitHub Pages deployment

Example Workflow

  1. Drop a note or idea in drafts/Draft-Info.md
  2. Ask the agent: “Turn the Eisenhower Matrix draft into a section in the Multi-Profile post”
  3. The agent reads the draft, formats it properly, and inserts it into the right post file
  4. Agent commits the change and pushes to the blog repo

This turns the agent into a lightweight editorial assistant — capture ideas any time, and let the bot handle formatting and publishing.

Key Commands Reference

TaskCommand
Create bot@BotFather → /newbot
Disable privacy@BotFather → /mybots → select bot → Bot Settings → Group Privacy → Off
Clone profilecp -r ~/.hermes/profiles/<src> ~/.hermes/profiles/<dst>
Start gatewayhermes gateway start --profile <name>
Check statushermes gateway status
View logstail -f ~/.hermes/profiles/<name>/logs/gateway.log
Find thread IDgrep 'group:-1003961507518:' ~/.hermes/profiles/<name>/logs/gateway.log
Sync vaultcd ~/obsidian && ./sync.sh
Verify bot tokencurl -s "https://api.telegram.org/bot<token>/getMe"

Optional: Sub-Repo Pattern for Modular Content

Separate git repos can live inside the vault for modular management. For example, this blog lives at Hermes/Personal/Blog/ as a standalone Jekyll site with its own GitHub Pages deployment:

# The blog has its own .git repo nested inside the main vault
ls ~/obsidian/Hermes/Personal/Blog/.git
# It's initialized separately, not as a git submodule of the vault

This allows the blog profile agent to edit blog content while personal notes stay in their own repository. Other candidates for this pattern include project documentation, configuration files, or per-project repos.


FAQ

Credential Pool is Empty After Cloning a Profile

Problem: After cloning a profile with cp -r ~/.hermes/profiles/work ~/.hermes/profiles/<name>, the new profile’s auth.json may have empty credential pools. The gateway starts but can’t authenticate with any LLM provider.

Fix: Copy the global credential pool to the new profile:

cp ~/.hermes/auth.json ~/.hermes/profiles/<new-profile-name>/auth.json

Then restart the gateway:

hermes gateway restart --profile <new-profile-name>

Starting Hermes Gateway on System Boot

To have your Hermes gateway profiles start automatically when the Raspberry Pi boots up:

Step 1 — Enable user linger (so services run even when no one is SSH’d in):

sudo loginctl enable-linger $USER

Step 2 — Install each profile as a systemd service:

source ~/.hermes/hermes-agent/venv/bin/activate
hermes --profile <name> gateway install

This creates a systemd user service at ~/.config/systemd/user/hermes-gateway-<name>.service.

Step 3 — Enable the service to start on boot:

systemctl --user enable hermes-gateway-<name>.service

Step 4 — Start it now:

systemctl --user start hermes-gateway-<name>.service

Repeat steps 2–4 for each profile (default, work, qa-planner, blog, etc.).

Verify all are running:

systemctl --user status hermes-gateway-*.service

Prompt Template for Setting Up a New Bot Profile

If you’re using Hermes Agent, you can ask your bot to create a new profile by loading the relevant skill and describing what you need. Here’s a reusable prompt:

Load the telegram-topic-setup skill and create a new Hermes profile called <name>. Use the Telegram bot token <token> from @BotFather. Clone from the work profile. Set it up with topic routing in the existing supergroup and configure ignored_threads so it only responds in its own topic.

You can save this as a note in your Obsidian vault and paste it whenever you need a new bot. The agent will:

  1. Clone the profile from the source
  2. Restore API keys from the source .env
  3. Set the Telegram bot token
  4. Copy the credential pool
  5. Create a SOUL.md with the role description
  6. Configure topic routing and ignored_threads
  7. Start the gateway