hermes-kanban-obsidian-integration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHermes Kanban Obsidian Integration
Hermes看板与Obsidian集成
Overview
概述
Hermes Kanban Bridge is an Obsidian plugin that exposes a REST API (default port 27124) allowing Hermes agents to manage Kanban boards inside your Obsidian vault. Boards are stored as Markdown files with YAML frontmatter, rendered visually by the obsidian-kanban community plugin.
Architecture:
- Hermes Agent → HTTP REST API → hermes-kanban-bridge plugin → Obsidian Vault API → Markdown files → obsidian-kanban visual renderer
Key Features:
- Break goals into structured Kanban boards via API
- Move cards, update metadata, query state in real-time
- Daily standups and weekly review rituals
- Fully local, no cloud dependencies
- Visual board rendering in Obsidian
Hermes Kanban Bridge是一款Obsidian插件,它提供REST API(默认端口27124),允许Hermes agents管理Obsidian库内的看板。看板以带有YAML前置元数据的Markdown文件存储,由obsidian-kanban社区插件进行可视化渲染。
架构:
- Hermes Agent → HTTP REST API → hermes-kanban-bridge插件 → Obsidian Vault API → Markdown文件 → obsidian-kanban可视化渲染器
核心功能:
- 通过API将目标拆解为结构化看板
- 实时移动卡片、更新元数据、查询状态
- 每日站会与每周回顾流程
- 完全本地化,无云端依赖
- 在Obsidian中可视化渲染看板
Installation
安装
Automated Install (Recommended)
自动安装(推荐)
bash
undefinedbash
undefinedClone the repository
Clone the repository
git clone https://github.com/GumbyEnder/hermes-kanban.git
cd hermes-kanban
git clone https://github.com/GumbyEnder/hermes-kanban.git
cd hermes-kanban
Edit install script to set your vault path
Edit install script to set your vault path
export VAULT_PATH="/path/to/your/ObsidianVault"
export VAULT_PATH="/path/to/your/ObsidianVault"
Run automated installer
Run automated installer
bash hermes-kanban-install.sh
The script installs:
1. hermes-kanban-bridge plugin (REST API server)
2. obsidian-kanban plugin (visual renderer)
3. Registers both in vault's community-plugins.jsonbash hermes-kanban-install.sh
该脚本会安装:
1. hermes-kanban-bridge插件(REST API服务器)
2. obsidian-kanban插件(可视化渲染器)
3. 在库的community-plugins.json中注册这两个插件Manual Installation
手动安装
Build the plugin:
bash
cd plugin
npm install
npm run buildCopy to vault:
bash
VAULT="/path/to/your/vault"
mkdir -p "$VAULT/.obsidian/plugins/hermes-kanban-bridge"
cp main.js manifest.json "$VAULT/.obsidian/plugins/hermes-kanban-bridge/"Install obsidian-kanban renderer:
bash
KANBAN_DIR="$VAULT/.obsidian/plugins/obsidian-kanban"
mkdir -p "$KANBAN_DIR"
TAG="2.0.51"
for f in main.js manifest.json styles.css; do
curl -sL "https://github.com/obsidian-community/obsidian-kanban/releases/download/$TAG/$f" -o "$KANBAN_DIR/$f"
doneEnable plugins in Obsidian:
- Reload Obsidian
- Settings → Community Plugins → disable Safe Mode
- Enable "Hermes Kanban Bridge" and "Kanban"
- Verify notice: "Hermes Kanban Bridge started on port 27124"
Install Hermes skills:
bash
mkdir -p ~/.hermes/profiles/$HERMES_PROFILE/skills/productivity
cp skills/*.md ~/.hermes/profiles/$HERMES_PROFILE/skills/productivity/构建插件:
bash
cd plugin
npm install
npm run build复制到库中:
bash
VAULT="/path/to/your/vault"
mkdir -p "$VAULT/.obsidian/plugins/hermes-kanban-bridge"
cp main.js manifest.json "$VAULT/.obsidian/plugins/hermes-kanban-bridge/"安装obsidian-kanban渲染器:
bash
KANBAN_DIR="$VAULT/.obsidian/plugins/obsidian-kanban"
mkdir -p "$KANBAN_DIR"
TAG="2.0.51"
for f in main.js manifest.json styles.css; do
curl -sL "https://github.com/obsidian-community/obsidian-kanban/releases/download/$TAG/$f" -o "$KANBAN_DIR/$f"
done在Obsidian中启用插件:
- 重新加载Obsidian
- 设置 → 社区插件 → 关闭安全模式
- 启用"Hermes Kanban Bridge"和"Kanban"
- 确认提示:"Hermes Kanban Bridge已在端口27124启动"
安装Hermes技能:
bash
mkdir -p ~/.hermes/profiles/$HERMES_PROFILE/skills/productivity
cp skills/*.md ~/.hermes/profiles/$HERMES_PROFILE/skills/productivity/Configuration
配置
Plugin Settings (Obsidian → Settings → Hermes Kanban Bridge):
| Setting | Default | Description |
|---|---|---|
| Port | 27124 | Local REST API port |
| Board folder | Kanban | Vault folder for boards |
| Trust mode | confirm | |
| Enable server | on | Toggle REST API |
Network Configuration for Remote Access:
If Hermes runs on a different machine, use Tailscale/LAN IP instead of localhost.
Windows firewall rule:
powershell
netsh advfirewall firewall add rule name="Hermes Kanban Bridge" dir=in action=allow protocol=TCP localport=27124Verify listening on all interfaces:
powershell
netstat -ano | findstr 27124插件设置(Obsidian → 设置 → Hermes Kanban Bridge):
| 设置项 | 默认值 | 描述 |
|---|---|---|
| 端口 | 27124 | 本地REST API端口 |
| 看板文件夹 | Kanban | 存储看板的库文件夹 |
| 信任模式 | confirm | |
| 启用服务器 | on | 切换REST API开关 |
远程访问网络配置:
如果Hermes运行在另一台机器上,请使用Tailscale/局域网IP而非localhost。
Windows防火墙规则:
powershell
netsh advfirewall firewall add rule name="Hermes Kanban Bridge" dir=in action=allow protocol=TCP localport=27124验证是否监听所有接口:
powershell
netstat -ano | findstr 27124Should show: TCP 0.0.0.0:27124 LISTENING
应显示:TCP 0.0.0.0:27124 LISTENING
undefinedundefinedREST API Reference
REST API参考
Base URL: (or remote IP)
http://localhost:27124基础URL: (或远程IP)
http://localhost:27124Health Check
健康检查
bash
curl http://localhost:27124/healthbash
curl http://localhost:27124/health{"ok":true,"status":"running","port":27124,"version":"1.0.0"}
{"ok":true,"status":"running","port":27124,"version":"1.0.0"}
undefinedundefinedCreate Board
创建看板
bash
curl -X POST http://localhost:27124/boards \
-H "Content-Type: application/json" \
-d '{
"name": "Q3 Launch",
"columns": ["Backlog", "In Progress", "Review", "Done"]
}'bash
curl -X POST http://localhost:27124/boards \
-H "Content-Type: application/json" \
-d '{
"name": "Q3 Launch",
"columns": ["Backlog", "In Progress", "Review", "Done"]
}'{"success":true,"board_id":"Q3-Launch","path":"Kanban/Q3-Launch.md"}
{"success":true,"board_id":"Q3-Launch","path":"Kanban/Q3-Launch.md"}
undefinedundefinedAdd Card
添加卡片
bash
curl -X POST http://localhost:27124/boards/Q3-Launch/cards \
-H "Content-Type: application/json" \
-d '{
"title": "Design landing page",
"column": "Backlog",
"metadata": {
"priority": "high",
"assignee": "alice"
}
}'bash
curl -X POST http://localhost:27124/boards/Q3-Launch/cards \
-H "Content-Type: application/json" \
-d '{
"title": "Design landing page",
"column": "Backlog",
"metadata": {
"priority": "high",
"assignee": "alice"
}
}'{"success":true,"card_id":"card-001"}
{"success":true,"card_id":"card-001"}
undefinedundefinedMove Card
移动卡片
bash
curl -X PATCH http://localhost:27124/boards/Q3-Launch/cards/card-001 \
-H "Content-Type: application/json" \
-d '{
"column": "In Progress"
}'bash
curl -X PATCH http://localhost:27124/boards/Q3-Launch/cards/card-001 \
-H "Content-Type: application/json" \
-d '{
"column": "In Progress"
}'{"success":true}
{"success":true}
undefinedundefinedQuery Board State
查询看板状态
bash
undefinedbash
undefinedGet all cards
获取所有卡片
{"cards":[{"id":"card-001","title":"Design landing page","column":"In Progress",...}]}
{"cards":[{"id":"card-001","title":"Design landing page","column":"In Progress",...}]}
Filter by column
按列筛选
Filter by metadata
按元数据筛选
undefinedundefinedDaily Standup
每日站会
bash
curl -X POST http://localhost:27124/rituals/standup \
-H "Content-Type: application/json" \
-d '{
"board_id": "Q3-Launch"
}'bash
curl -X POST http://localhost:27124/rituals/standup \
-H "Content-Type: application/json" \
-d '{
"board_id": "Q3-Launch"
}'{"summary":"3 cards in progress, 2 blocked, 5 completed yesterday"}
{"summary":"3 cards in progress, 2 blocked, 5 completed yesterday"}
undefinedundefinedWeekly Review
每周回顾
bash
curl -X POST http://localhost:27124/rituals/weekly-review \
-H "Content-Type: application/json" \
-d '{
"board_id": "Q3-Launch"
}'bash
curl -X POST http://localhost:27124/rituals/weekly-review \
-H "Content-Type: application/json" \
-d '{
"board_id": "Q3-Launch"
}'{"summary":"12 cards completed this week, velocity: 2.4 cards/day"}
{"summary":"12 cards completed this week, velocity: 2.4 cards/day"}
undefinedundefinedPython Client Usage
Python客户端使用示例
python
import requests
import os
BASE_URL = os.getenv("HERMES_KANBAN_URL", "http://localhost:27124")
class KanbanClient:
def __init__(self, base_url=BASE_URL):
self.base = base_url
def health_check(self):
"""Verify server is running"""
r = requests.get(f"{self.base}/health")
return r.json()
def create_board(self, name, columns):
"""Create new Kanban board"""
r = requests.post(
f"{self.base}/boards",
json={"name": name, "columns": columns}
)
return r.json()
def add_card(self, board_id, title, column, metadata=None):
"""Add card to board"""
payload = {"title": title, "column": column}
if metadata:
payload["metadata"] = metadata
r = requests.post(
f"{self.base}/boards/{board_id}/cards",
json=payload
)
return r.json()
def move_card(self, board_id, card_id, new_column):
"""Move card between columns"""
r = requests.patch(
f"{self.base}/boards/{board_id}/cards/{card_id}",
json={"column": new_column}
)
return r.json()
def query_cards(self, board_id, filters=None):
"""Query cards with optional filters"""
params = filters or {}
r = requests.get(
f"{self.base}/boards/{board_id}/cards",
params=params
)
return r.json()
def daily_standup(self, board_id):
"""Run daily standup ritual"""
r = requests.post(
f"{self.base}/rituals/standup",
json={"board_id": board_id}
)
return r.json()python
import requests
import os
BASE_URL = os.getenv("HERMES_KANBAN_URL", "http://localhost:27124")
class KanbanClient:
def __init__(self, base_url=BASE_URL):
self.base = base_url
def health_check(self):
"""Verify server is running"""
r = requests.get(f"{self.base}/health")
return r.json()
def create_board(self, name, columns):
"""Create new Kanban board"""
r = requests.post(
f"{self.base}/boards",
json={"name": name, "columns": columns}
)
return r.json()
def add_card(self, board_id, title, column, metadata=None):
"""Add card to board"""
payload = {"title": title, "column": column}
if metadata:
payload["metadata"] = metadata
r = requests.post(
f"{self.base}/boards/{board_id}/cards",
json=payload
)
return r.json()
def move_card(self, board_id, card_id, new_column):
"""Move card between columns"""
r = requests.patch(
f"{self.base}/boards/{board_id}/cards/{card_id}",
json={"column": new_column}
)
return r.json()
def query_cards(self, board_id, filters=None):
"""Query cards with optional filters"""
params = filters or {}
r = requests.get(
f"{self.base}/boards/{board_id}/cards",
params=params
)
return r.json()
def daily_standup(self, board_id):
"""Run daily standup ritual"""
r = requests.post(
f"{self.base}/rituals/standup",
json={"board_id": board_id}
)
return r.json()Example usage
Example usage
client = KanbanClient()
client = KanbanClient()
Verify connection
Verify connection
print(client.health_check())
print(client.health_check())
Create board
Create board
board = client.create_board(
name="Product Roadmap",
columns=["Ideas", "Planned", "In Development", "Shipped"]
)
board_id = board["board_id"]
board = client.create_board(
name="Product Roadmap",
columns=["Ideas", "Planned", "In Development", "Shipped"]
)
board_id = board["board_id"]
Add cards
Add cards
client.add_card(
board_id,
"Implement dark mode",
"Planned",
metadata={"priority": "medium", "estimate": "3d"}
)
client.add_card(
board_id,
"Implement dark mode",
"Planned",
metadata={"priority": "medium", "estimate": "3d"}
)
Query blocked items
Query blocked items
blocked = client.query_cards(board_id, {"status": "blocked"})
print(f"Blocked cards: {len(blocked['cards'])}")
blocked = client.query_cards(board_id, {"status": "blocked"})
print(f"Blocked cards: {len(blocked['cards'])}")
Run standup
Run standup
standup = client.daily_standup(board_id)
print(standup["summary"])
undefinedstandup = client.daily_standup(board_id)
print(standup["summary"])
undefinedBoard Markdown Format
看板Markdown格式
Boards are stored as Markdown with YAML frontmatter:
markdown
---
kanban-plugin: board
---看板以带有YAML前置元数据的Markdown文件存储:
markdown
---
kanban-plugin: board
---Backlog
Backlog
- Design landing page #high @alice
- Set up CI/CD pipeline #medium @bob
- Design landing page #high @alice
- Set up CI/CD pipeline #medium @bob
In Progress
In Progress
- Implement authentication #high @alice
- Started: 2026-05-15
- Blocked: waiting on API keys
- Implement authentication #high @alice
- Started: 2026-05-15
- Blocked: waiting on API keys
Review
Review
- Write user documentation #low @carol
- Write user documentation #low @carol
Done
Done
- Initialize project repository
- Completed: 2026-05-14
**Important:** The `kanban-plugin: board` frontmatter triggers visual rendering. Without it, boards display as plain Markdown.- Initialize project repository
- Completed: 2026-05-14
**重要提示:** `kanban-plugin: board`前置元数据会触发可视化渲染。如果没有该元数据,看板会以纯Markdown列表形式显示。Common Patterns
常见模式
Breaking Down a Project
项目拆解
python
def break_down_project(client, project_name, tasks):
"""Create board and populate with tasks"""
board = client.create_board(
name=project_name,
columns=["Backlog", "In Progress", "Review", "Done"]
)
board_id = board["board_id"]
for task in tasks:
client.add_card(
board_id,
task["title"],
"Backlog",
metadata=task.get("metadata", {})
)
return board_idpython
def break_down_project(client, project_name, tasks):
"""Create board and populate with tasks"""
board = client.create_board(
name=project_name,
columns=["Backlog", "In Progress", "Review", "Done"]
)
board_id = board["board_id"]
for task in tasks:
client.add_card(
board_id,
task["title"],
"Backlog",
metadata=task.get("metadata", {})
)
return board_idUsage
Usage
tasks = [
{"title": "Research competitors", "metadata": {"priority": "high"}},
{"title": "Draft wireframes", "metadata": {"priority": "medium"}},
{"title": "Set up analytics", "metadata": {"priority": "low"}}
]
board_id = break_down_project(client, "Market Analysis", tasks)
undefinedtasks = [
{"title": "Research competitors", "metadata": {"priority": "high"}},
{"title": "Draft wireframes", "metadata": {"priority": "medium"}},
{"title": "Set up analytics", "metadata": {"priority": "low"}}
]
board_id = break_down_project(client, "Market Analysis", tasks)
undefinedAutomated Workflow Progression
自动化工作流推进
python
def progress_workflow(client, board_id):
"""Move cards through workflow automatically"""
# Get all cards in Review
cards = client.query_cards(board_id, {"column": "Review"})
for card in cards["cards"]:
# Check if ready to move (example: all subtasks done)
if card_is_complete(card):
client.move_card(board_id, card["id"], "Done")
print(f"Completed: {card['title']}")
def card_is_complete(card):
"""Example validation logic"""
metadata = card.get("metadata", {})
return metadata.get("reviewed", False) and metadata.get("tests_passing", False)python
def progress_workflow(client, board_id):
"""Move cards through workflow automatically"""
# Get all cards in Review
cards = client.query_cards(board_id, {"column": "Review"})
for card in cards["cards"]:
# Check if ready to move (example: all subtasks done)
if card_is_complete(card):
client.move_card(board_id, card["id"], "Done")
print(f"Completed: {card['title']}")
def card_is_complete(card):
"""Example validation logic"""
metadata = card.get("metadata", {})
return metadata.get("reviewed", False) and metadata.get("tests_passing", False)Daily Ritual Integration
每日流程集成
python
import schedule
import time
def daily_standup_job():
"""Run standup for all active boards"""
client = KanbanClient()
# Get all boards
boards = requests.get(f"{client.base}/boards").json()
for board in boards["boards"]:
if board.get("active", True):
result = client.daily_standup(board["id"])
send_notification(result["summary"])python
import schedule
import time
def daily_standup_job():
"""Run standup for all active boards"""
client = KanbanClient()
# Get all boards
boards = requests.get(f"{client.base}/boards").json()
for board in boards["boards"]:
if board.get("active", True):
result = client.daily_standup(board["id"])
send_notification(result["summary"])Schedule daily at 9 AM
Schedule daily at 9 AM
schedule.every().day.at("09:00").do(daily_standup_job)
while True:
schedule.run_pending()
time.sleep(60)
undefinedschedule.every().day.at("09:00").do(daily_standup_job)
while True:
schedule.run_pending()
time.sleep(60)
undefinedTesting
测试
The project includes 105 tests (59 unit, 46 E2E):
bash
undefined该项目包含105个测试用例(59个单元测试,46个端到端测试):
bash
undefinedAll tests
All tests
pytest tests/
pytest tests/
E2E only
E2E only
pytest tests/e2e/
pytest tests/e2e/
Skip slow TUI tests
Skip slow TUI tests
pytest tests/e2e/ -k "not tui"
pytest tests/e2e/ -k "not tui"
Mock API server (no Obsidian required)
Mock API server (no Obsidian required)
python tests/e2e/mock_api_server.py
**Mock API for development:**
```pythonpython tests/e2e/mock_api_server.py
**用于开发的Mock API:**
```pythontests/e2e/mock_api_server.py implements all REST endpoints
tests/e2e/mock_api_server.py implements all REST endpoints
Use for testing without running Obsidian
Use for testing without running Obsidian
import requests
import requests
Start mock server on port 27125
Start mock server on port 27125
response = requests.get("http://localhost:27125/health")
assert response.json()["ok"] == True
undefinedresponse = requests.get("http://localhost:27125/health")
assert response.json()["ok"] == True
undefinedTroubleshooting
故障排除
Connection Refused
连接被拒绝
Symptoms:
curl: Failed to connect to localhost port 27124Solutions:
- Verify plugin is enabled: Settings → Community Plugins → Hermes Kanban Bridge = ON
- Look for notice "Hermes Kanban Bridge started on port 27124"
- Toggle plugin off/on to restart server
- Check port not in use: (Unix) or
lsof -i :27124(Windows)netstat -ano | findstr 27124
症状:
curl: Failed to connect to localhost port 27124解决方案:
- 验证插件已启用:设置 → 社区插件 → Hermes Kanban Bridge = 开启
- 查看提示信息“Hermes Kanban Bridge已在端口27124启动”
- 关闭再重新开启插件以重启服务器
- 检查端口是否被占用:(Unix)或
lsof -i :27124(Windows)netstat -ano | findstr 27124
Board Shows as Markdown List
看板显示为Markdown列表
Symptoms: Board opens as plain text instead of visual kanban
Solution: Add YAML frontmatter to top of file:
markdown
---
kanban-plugin: board
---All API-created boards include this automatically. Manually created boards need it added.
症状: 看板以纯文本形式打开而非可视化看板
解决方案: 在文件顶部添加YAML前置元数据:
markdown
---
kanban-plugin: board
---所有通过API创建的看板会自动包含该元数据。手动创建的看板需要手动添加。
Remote Access Not Working
远程访问无法工作
Symptoms: Can't connect from Hermes on different machine
Solutions:
- Use Obsidian machine's Tailscale/LAN IP instead of
localhost - Verify server binds to not
0.0.0.0:127.0.0.1bashnetstat -ano | findstr 27124 # Should show: TCP 0.0.0.0:27124 LISTENING - Add firewall rule (Windows):
powershell
netsh advfirewall firewall add rule name="Hermes Kanban Bridge" dir=in action=allow protocol=TCP localport=27124 - macOS: System Settings → Network → Firewall → allow Obsidian
症状: 无法从另一台机器上的Hermes连接
解决方案:
- 使用Obsidian所在机器的Tailscale/局域网IP而非
localhost - 验证服务器绑定到而非
0.0.0.0:127.0.0.1bashnetstat -ano | findstr 27124 # 应显示:TCP 0.0.0.0:27124 LISTENING - 添加防火墙规则(Windows):
powershell
netsh advfirewall firewall add rule name="Hermes Kanban Bridge" dir=in action=allow protocol=TCP localport=27124 - macOS:系统设置 → 网络 → 防火墙 → 允许Obsidian
Plugin Not Appearing
插件未显示
Symptoms: Plugin not in Community Plugins list
Solution: Quit Obsidian completely (not just reload), then reopen. Obsidian requires full restart to detect new plugin folders.
症状: 插件未出现在社区插件列表中
解决方案: 完全退出Obsidian(不只是重新加载),然后重新打开。Obsidian需要完全重启才能检测到新的插件文件夹。
Port Conflict
端口冲突
Symptoms: Server fails to start, port already in use
Solution:
- Change port: Settings → Hermes Kanban Bridge → Port → set to 27125 (or other)
- Toggle plugin off/on to apply
- Update Hermes skill configs and to new port
HERMES_KANBAN_URL
症状: 服务器启动失败,端口已被占用
解决方案:
- 修改端口:设置 → Hermes Kanban Bridge → 端口 → 设置为27125(或其他端口)
- 关闭再重新开启插件以应用设置
- 更新Hermes技能配置和以使用新端口
HERMES_KANBAN_URL
Environment Variables
环境变量
bash
undefinedbash
undefinedREST API base URL (default: http://localhost:27124)
REST API base URL (default: http://localhost:27124)
export HERMES_KANBAN_URL="http://192.168.1.100:27124"
export HERMES_KANBAN_URL="http://192.168.1.100:27124"
Hermes profile for skills installation
Hermes profile for skills installation
export HERMES_PROFILE="frodo"
export HERMES_PROFILE="frodo"
Obsidian vault path for scripts
Obsidian vault path for scripts
export VAULT_PATH="/Users/alice/Documents/ObsidianVault"
undefinedexport VAULT_PATH="/Users/alice/Documents/ObsidianVault"
undefinedIntegration with Hermes Agent
与Hermes Agent集成
Once skills are installed (), interact naturally:
~/.hermes/profiles/*/skills/productivity/Voice Commands:
- "Break down the Q3 launch into a Kanban board"
- "Run my daily standup"
- "What cards are blocked?"
- "Move the authentication task to In Progress"
- "Give me a weekly review"
Hermes uses the installed skills to translate commands into REST API calls automatically.
安装技能后(),即可自然交互:
~/.hermes/profiles/*/skills/productivity/语音命令:
- "将Q3启动项目拆解为看板"
- "运行我的每日站会"
- "哪些卡片被阻塞了?"
- "将认证任务移至进行中"
- "给我一份每周回顾"
Hermes会使用已安装的技能自动将命令转换为REST API调用。
Resources
资源
- API Documentation: in repository
docs/API.md - Demo Board: - sample board for testing
docs/demo/Q3-Launch.md - Test Suite: - 105 tests, 55% coverage
tests/ - obsidian-kanban plugin: https://github.com/obsidian-community/obsidian-kanban
- API文档: 仓库中的
docs/API.md - 演示看板: - 用于测试的示例看板
docs/demo/Q3-Launch.md - 测试套件: - 105个测试用例,覆盖率55%
tests/ - obsidian-kanban插件: https://github.com/obsidian-community/obsidian-kanban