Initial commit: Hermes Agent skills collection

- Trading skills (OKX, dividend, lottery, quantitative)
- Creative skills (ASCII art, diagrams, video)
- Development skills (GitHub, debugging, TDD)
- Research skills (arXiv, blog monitoring)
- Productivity skills (email, documents, notes)
- MCP integration skills
- Custom user skills
This commit is contained in:
Hermes Skills Manager
2026-07-05 02:31:15 -04:00
commit 6770bc9b9d
908 changed files with 239614 additions and 0 deletions
@@ -0,0 +1,145 @@
# Hermes + TelegramForwarder Group Integration
## Problem
Forwarder sends messages to a group, but Hermes bot (also in the group) ignores them.
## Root Causes (check ALL of these)
| # | Cause | Symptom | Fix |
|---|-------|---------|-----|
| 0 | **Competing gateway process** (old OpenClaw, duplicate Hermes) | Adapter shows "connected" but `getUpdates` returns 0 without 409 conflict. No "✓ telegram connected" in logs. Group messages NEVER worked. | `ps aux \| grep gateway` → kill stale process → restart Hermes |
| 1 | Bot Privacy Mode is ON | Bot receives 0 group messages | @BotFather → /mybots → Bot Settings → Group Privacy → Turn off |
| 2 | Wrong config key `free_response_channels` | Bot sees @mentions but ignores regular messages | Use `extra.free_response_chats` (NOT top-level `free_response_channels`) |
| 3 | Group migrated to supergroup | `An invalid Peer was used` in forwarder logs | Update chat ID (see below) |
| 4 | Privacy mode not propagated | `can_read_all_group_messages=true` but bot still can't see messages | Kick bot from group, re-add it |
**⚠️ Check #0 FIRST.** A stale gateway process is invisible — the state file says "connected", no errors appear, but the adapter never actually polls. This was the actual root cause for a user whose group messages had NEVER worked for over a week (old OpenClaw Gateway PID 900 running since June 22). Always run `ps aux | grep gateway | grep -v grep` before investigating other causes.
**⚠️ Privacy mode is the #1 cause.** Even with `free_response_chats` correctly configured, if privacy mode is ON, the bot literally cannot see group messages. Fix privacy mode FIRST.
## Step-by-step
### 0. Check for Competing Gateway Processes (DO THIS FIRST)
```bash
ps aux | grep "gateway\|openclaw" | grep -v grep
```
If you see any `openclaw ... gateway` or duplicate `hermes gateway` processes → **kill them immediately**. They steal the bot token polling session.
Verify nobody else is polling:
```bash
python3 -c "
import json, urllib.request
with open('/home/openclaw/.hermes/.env') as f:
for line in f:
if line.startswith('TELEGRAM_BOT_TOKEN'):
token = line.strip().split('=',1)[1]
break
proxy = urllib.request.ProxyHandler({'http': 'http://127.0.0.1:7890', 'https': 'http://127.0.0.1:7890'})
opener = urllib.request.build_opener(proxy)
try:
req = urllib.request.Request(f'https://api.telegram.org/bot{token}/getUpdates?timeout=1')
resp = opener.open(req, timeout=5)
print(f'getUpdates: {len(json.loads(resp.read()).get(\"result\",[]))} updates — nobody polling!' )
except Exception as e:
print(f'409 Conflict — adapter IS polling (normal)' if '409' in str(e) else f'Error: {e}')
"
```
- 0 updates without 409 → broken (check for competing processes)
- 409 Conflict → normal (adapter is polling)
### 1. Disable Bot Privacy Mode (MANDATORY)
Open Telegram → @BotFather:
```
/mybots → select Hermes bot → Bot Settings → Group Privacy → Turn off
```
Do this for the Hermes bot. If the forwarder bot also needs to read messages in the group, do it for that bot too.
**After disabling, kick the bot from the group and re-add it.** The change does not apply to bots already in a group.
Verify: `curl -s --proxy http://127.0.0.1:7890 "https://api.telegram.org/bot<TOKEN>/getMe"` → `can_read_all_group_messages` must be `true`.
### 2. Find the destination group's chat_id
```bash
cd ~/TelegramForwarder
docker exec telegram-forwarder python3 -c "
import sqlite3
conn = sqlite3.connect('/app/db/forward.db')
c = conn.cursor()
c.execute('SELECT id, telegram_chat_id, name FROM chats')
for ch in c.fetchall():
print(ch)
conn.close()
"
```
The column is `telegram_chat_id` (NOT `chat_id`).
**⚠️ Supergroup IDs**: If the group was migrated, the old ID is stale. Use `-100` + `channel_id` format. To find the real channel_id:
```python
entity = await bot.get_entity(old_id)
# If entity has migrated_to:
new_id = -100 * entity.migrated_to.channel_id # e.g., -1003966251111
```
### 3. Edit Hermes config (CORRECT KEY!)
`~/.hermes/config.yaml` — add inside the `telegram:` → `extra:` section:
```yaml
telegram:
extra:
free_response_chats: '-1003966251111' # ← CORRECT key
# free_response_channels: '...' ← WRONG — code ignores this!
```
**⚠️ CRITICAL**: The Hermes source code reads `self.config.extra.get("free_response_chats")`. The top-level `free_response_channels` is a DIFFERENT field that is NOT read by the group-message processing logic. Using the wrong key = silently ignored, bot only responds to @mentions.
Multiple groups: comma-separated `'-1003966251111,-1001234567890'`
### 4. Restart Hermes
```bash
hermes gateway restart # from a separate shell, NOT inside the gateway
```
If refused ("Refusing to restart from inside the gateway"), ask the user to SSH in and run it.
## Config Field Reference
| Field | Location | Default | Purpose |
|-------|----------|---------|---------|
| `require_mention` | `telegram:` | `true` | If true, bot only responds when @mentioned in groups |
| `free_response_chats` | `telegram:extra:` | `''` | Comma-separated chat_ids exempt from @mention requirement |
| `free_response_channels` | `telegram:` | `''` | **NOT used by group message processing** — legacy field, ignore |
| `allowed_chats` | `telegram:` | `''` | If set, ONLY these chats can interact with the bot (whitelist) |
## Signal Forwarding with channel_prompts
When you want Hermes to process group messages (e.g., trading signals) and forward results to a user DM instead of replying in the group:
```yaml
telegram:
channel_prompts:
"-1003966251111": "你是交易信号处理器。收到群里的交易信号后,解析【币种】【方向】【仓位】,然后用send_message工具发送到telegram:656685714(用户DM),格式简洁:信号摘要+当前价格+建议操作+风险提示。不要在群里回复。"
```
This configures a per-group system prompt. The agent in that group session will follow these instructions instead of the default behavior.
## End-to-End Verification
After setting up the forwarding → Hermes chain, verify each link:
1. **Forwarder listening**: `docker logs telegram-forwarder 2>&1 | grep "收到新消息"` — should show messages from source channel
2. **Forwarder sending**: `docker logs telegram-forwarder 2>&1 | grep "已发送"` — should show successful sends to target group
3. **Hermes receiving**: `hermes logs 2>&1 | grep "inbound message"` — should show messages from the group (chat ID should match the group, not the user DM)
4. **Hermes responding**: Check the group for Hermes's reply
**Common failure chain**:
- Forwarder logs show "收到新消息" but no "已发送" → keyword filter issue or invalid Peer (check group ID)
- Forwarder logs show "已发送" but Hermes shows no inbound from group → privacy mode still on, or `free_response_chats` wrong key
- Hermes shows inbound but no response → check `require_mention` and `free_response_chats`
**⚠️ For testing, use a human account** (not the forwarder bot) to send messages to the source channel or directly to the group. Bot-sent messages may be filtered by Hermes.
## Pitfalls
- `free_response_chats` takes string values, not integers: `'-1003966251111'` not `-1003966251111`
- Config changes require Hermes restart to take effect
- If `allowed_chats` is set (non-empty), the group must also be in that list
- The forwarder's `handle_mode: FORWARD` uses Telegram's native forward (shows "Forwarded from"). If user wants clean copies, change to `COPY` mode.
- **Don't test by sending directly to the target group** — this bypasses the forwarding chain and proves nothing. Test by sending to the SOURCE group and verifying the full pipeline: source → forwarder → target → Hermes response.
- **Bot-to-bot messaging FAILS**: Telegram prohibits bot→bot messaging. Forward to a GROUP where both bots reside, not directly to a bot.
- **Session database locked**: If you see `sqlite3.OperationalError: database is locked`, stop the container first, edit DB, then restart.