hermes-labyrinth-observability

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hermes Labyrinth Observability Plugin

Hermes Labyrinth 可观测性插件

Skill by ara.so — Hermes Skills collection.
Hermes Labyrinth is a read-only observability plugin for Hermes Agent that provides detailed monitoring of autonomous agent execution. It visualizes agent "journeys" as sequences of "crossings" (prompts, tool calls, results, failures, model switches, subagents) and generates exportable reports with built-in secret redaction.
ara.so开发的Skill —— 属于Hermes Skills集合。
Hermes Labyrinth是一款面向Hermes Agent的只读可观测性插件,可对自主Agent的执行过程进行详细监控。它将Agent的“运行流程”可视化为一系列“节点交互”(提示词、工具调用、结果、失败、模型切换、子Agent),并生成内置敏感信息脱敏功能的可导出报告。

Installation

安装

Install into the Hermes user plugin directory:
bash
mkdir -p ~/.hermes/plugins
git clone https://github.com/stainlu/hermes-labyrinth.git ~/.hermes/plugins/hermes-labyrinth
After installation, restart the Hermes dashboard:
bash
hermes dashboard
The Labyrinth tab will appear in the dashboard UI at
http://127.0.0.1:9119
.
将插件安装到Hermes用户插件目录:
bash
mkdir -p ~/.hermes/plugins
git clone https://github.com/stainlu/hermes-labyrinth.git ~/.hermes/plugins/hermes-labyrinth
安装完成后,重启Hermes仪表盘:
bash
hermes dashboard
仪表盘UI的Labyrinth标签页将在
http://127.0.0.1:9119
地址显示。

Docker Installation

Docker 安装

For Docker-based Hermes installations, mount the plugin directory:
bash
mkdir -p ~/.hermes/plugins
git clone https://github.com/stainlu/hermes-labyrinth.git ~/.hermes/plugins/hermes-labyrinth
cd ~/.hermes/plugins/hermes-labyrinth
git checkout v0.1.3  # Pin to reviewed version
Mount the Hermes home directory into your container and restart the dashboard.
对于基于Docker的Hermes安装,需挂载插件目录:
bash
mkdir -p ~/.hermes/plugins
git clone https://github.com/stainlu/hermes-labyrinth.git ~/.hermes/plugins/hermes-labyrinth
cd ~/.hermes/plugins/hermes-labyrinth
git checkout v0.1.3  # 固定到已审核版本
将Hermes主目录挂载到容器中,然后重启仪表盘。

Plugin Management

插件管理

Rescan Plugins (Frontend Only)

重新扫描插件(仅前端)

Refresh discovered frontend manifests without full restart:
bash
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
Note: Backend API changes require a full dashboard restart.
无需完全重启即可刷新已发现的前端清单:
bash
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
注意: 后端API变更需要完全重启仪表盘。

Disable/Remove Plugin

禁用/移除插件

bash
hermes plugins disable hermes-labyrinth
rm -rf ~/.hermes/plugins/hermes-labyrinth
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
bash
hermes plugins disable hermes-labyrinth
rm -rf ~/.hermes/plugins/hermes-labyrinth
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan

API Reference

API 参考

All endpoints are read-only and include automatic secret redaction.
所有端点均为只读,并包含自动敏感信息脱敏功能。

Health Check

健康检查

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health
Returns plugin status and Hermes state accessibility.
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health
返回插件状态及Hermes状态的可访问性。

List Journeys

列出运行流程

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys
Returns recent CLI, dashboard, gateway, cron, and delegated agent sessions.
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys
返回近期的CLI、仪表盘、网关、定时任务及委托Agent会话。

Get Journey Details

获取运行流程详情

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/{journey_id}
Returns metadata for a specific journey including start time, status, and model usage.
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/{journey_id}
返回特定运行流程的元数据,包括开始时间、状态和模型使用情况。

Get Journey Crossings

获取运行流程节点交互

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/{journey_id}/crossings
Returns ordered sequence of crossings (messages, tool calls, results) for a journey.
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/{journey_id}/crossings
返回运行流程的节点交互有序序列(消息、工具调用、结果)。

Get Skills Inventory

获取Skill清单

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/skills
Returns:
  • skills
    : effective skills loaded
  • shadowed
    : expected user-over-bundled overrides
  • duplicates
    : true duplicate diagnostics
  • errors
    : skill scan errors
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/skills
返回:
  • skills
    : 已加载的有效Skill
  • shadowed
    : 用户覆盖内置Skill的预期情况
  • duplicates
    : 重复项诊断结果
  • errors
    : Skill扫描错误

Get Cron Configuration

获取定时任务配置

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/cron
Returns scheduled autonomy jobs, next run times, last failures, and working directories.
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/cron
返回已调度的自主任务、下次运行时间、最近失败记录及工作目录。

Get Guideposts

获取观测要点

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/guideposts
Returns generated observations backed by local evidence across journeys.
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/guideposts
返回基于各运行流程本地证据生成的观测结果。

Export Reports

导出报告

JSON format:
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/{journey_id}.json > journey.json
Markdown format:
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/{journey_id}.md > journey.md
Both formats include automatic secret redaction.
JSON格式:
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/{journey_id}.json > journey.json
Markdown格式:
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/{journey_id}.md > journey.md
两种格式均包含自动敏感信息脱敏功能。

Python Plugin API Extension

Python 插件API扩展

Hermes Labyrinth extends the dashboard with custom backend routes. The core implementation is in
dashboard/plugin_api.py
.
Hermes Labyrinth通过自定义后端路由扩展仪表盘功能。核心实现位于
dashboard/plugin_api.py

Example: Custom API Route

示例:自定义API路由

python
from fastapi import APIRouter, HTTPException
from typing import Dict, Any
import os

router = APIRouter(prefix="/api/plugins/hermes-labyrinth")

@router.get("/custom-endpoint")
async def custom_endpoint() -> Dict[str, Any]:
    """Example custom endpoint for plugin."""
    hermes_home = os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes"))
    
    # Read-only access to Hermes state
    state_db = os.path.join(hermes_home, "state.db")
    
    if not os.path.exists(state_db):
        raise HTTPException(status_code=503, detail="Hermes state unavailable")
    
    return {
        "status": "ok",
        "hermes_home": hermes_home
    }
python
from fastapi import APIRouter, HTTPException
from typing import Dict, Any
import os

router = APIRouter(prefix="/api/plugins/hermes-labyrinth")

@router.get("/custom-endpoint")
async def custom_endpoint() -> Dict[str, Any]:
    """Example custom endpoint for plugin."""
    hermes_home = os.environ.get("HERMES_HOME", os.path.expanduser("~/.hermes"))
    
    # Read-only access to Hermes state
    state_db = os.path.join(hermes_home, "state.db")
    
    if not os.path.exists(state_db):
        raise HTTPException(status_code=503, detail="Hermes state unavailable")
    
    return {
        "status": "ok",
        "hermes_home": hermes_home
    }

Accessing Hermes State

访问Hermes状态

The plugin reads from:
  • ~/.hermes/state.db
    : Sessions and messages (SQLite)
  • ~/.hermes/skills/
    : User and bundled skills
  • ~/.hermes/cron/
    : Scheduled job configurations
python
import sqlite3
import os

def query_journeys(hermes_home: str):
    """Query recent sessions from Hermes state.db"""
    state_db = os.path.join(hermes_home, "state.db")
    
    conn = sqlite3.connect(state_db)
    conn.row_factory = sqlite3.Row
    
    cursor = conn.cursor()
    cursor.execute("""
        SELECT session_id, created_at, updated_at, status, model
        FROM sessions
        ORDER BY updated_at DESC
        LIMIT 100
    """)
    
    sessions = [dict(row) for row in cursor.fetchall()]
    conn.close()
    
    return sessions
插件读取以下位置的信息:
  • ~/.hermes/state.db
    : 会话和消息(SQLite)
  • ~/.hermes/skills/
    : 用户及内置Skill
  • ~/.hermes/cron/
    : 调度任务配置
python
import sqlite3
import os

def query_journeys(hermes_home: str):
    """Query recent sessions from Hermes state.db"""
    state_db = os.path.join(hermes_home, "state.db")
    
    conn = sqlite3.connect(state_db)
    conn.row_factory = sqlite3.Row
    
    cursor = conn.cursor()
    cursor.execute("""
        SELECT session_id, created_at, updated_at, status, model
        FROM sessions
        ORDER BY updated_at DESC
        LIMIT 100
    """)
    
    sessions = [dict(row) for row in cursor.fetchall()]
    conn.close()
    
    return sessions

Frontend Development

前端开发

The dashboard UI is built from modular JavaScript components.
仪表盘UI由模块化JavaScript组件构建。

Build Process

构建流程

bash
npm run build
Generates:
  • dashboard/dist/labyrinth-bundle.js
    : Combined JS from
    src/parts/*.js
  • dashboard/dist/labyrinth.css
    : Copied from
    src/labyrinth.css
  • index.html
    : GitHub Pages demo with content hashes
bash
npm run build
生成:
  • dashboard/dist/labyrinth-bundle.js
    : 来自
    src/parts/*.js
    的合并JS文件
  • dashboard/dist/labyrinth.css
    : 复制自
    src/labyrinth.css
  • index.html
    : 带有内容哈希的GitHub Pages演示页面

Development Workflow

开发工作流

bash
undefined
bash
undefined

Build and verify

构建并验证

npm run build npm run check
npm run build npm run check

Run smoke tests

运行冒烟测试

npm run smoke
npm run smoke

Test live demo

测试在线演示

npm run smoke:live
undefined
npm run smoke:live
undefined

Frontend Structure

前端结构

javascript
// src/parts/01-state.js - Global state management
const LabyrinthState = {
  journeys: [],
  selectedJourney: null,
  crossings: [],
  mode: 'chronological'
};

// src/parts/02-api.js - API client
async function fetchJourneys() {
  const response = await fetch('/api/plugins/hermes-labyrinth/journeys');
  return response.json();
}

// src/parts/03-components.js - UI components
function renderJourneyCard(journey) {
  return `
    <div class="journey-card" data-id="${journey.id}">
      <h3>${escapeHtml(journey.title)}</h3>
      <time>${new Date(journey.created_at * 1000).toLocaleString()}</time>
    </div>
  `;
}
javascript
// src/parts/01-state.js - 全局状态管理
const LabyrinthState = {
  journeys: [],
  selectedJourney: null,
  crossings: [],
  mode: 'chronological'
};

// src/parts/02-api.js - API客户端
async function fetchJourneys() {
  const response = await fetch('/api/plugins/hermes-labyrinth/journeys');
  return response.json();
}

// src/parts/03-components.js - UI组件
function renderJourneyCard(journey) {
  return `
    <div class="journey-card" data-id="${journey.id}">
      <h3>${escapeHtml(journey.title)}</h3>
      <time>${new Date(journey.created_at * 1000).toLocaleString()}</time>
    </div>
  `;
}

Configuration

配置

Optional Theme

可选主题

bash
mkdir -p ~/.hermes/dashboard-themes
cp ~/.hermes/plugins/hermes-labyrinth/theme/hermes-labyrinth.yaml ~/.hermes/dashboard-themes/
bash
mkdir -p ~/.hermes/dashboard-themes
cp ~/.hermes/plugins/hermes-labyrinth/theme/hermes-labyrinth.yaml ~/.hermes/dashboard-themes/

Plugin Manifest

插件清单

Located at
dashboard/manifest.json
:
json
{
  "name": "hermes-labyrinth",
  "version": "0.1.3",
  "title": "Labyrinth",
  "description": "Agent journey observability",
  "entry_js": "dist/labyrinth-bundle.js",
  "entry_css": "dist/labyrinth.css",
  "api_module": "plugin_api"
}
位于
dashboard/manifest.json
json
{
  "name": "hermes-labyrinth",
  "version": "0.1.3",
  "title": "Labyrinth",
  "description": "Agent journey observability",
  "entry_js": "dist/labyrinth-bundle.js",
  "entry_css": "dist/labyrinth.css",
  "api_module": "plugin_api"
}

Common Patterns

常见用法

Filtering Journeys by Status

按状态过滤运行流程

bash
undefined
bash
undefined

Get all journeys and filter with jq

获取所有运行流程并使用jq过滤

curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys |
jq '.journeys[] | select(.status == "completed")'
undefined
curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys |
jq '.journeys[] | select(.status == "completed")'
undefined

Analyzing Tool Call Patterns

分析工具调用模式

bash
undefined
bash
undefined

Get crossings and count tool types

获取节点交互并统计工具类型

curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/{journey_id}/crossings |
jq '.crossings[] | select(.type == "tool_call") | .tool_name' |
sort | uniq -c
undefined
curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/{journey_id}/crossings |
jq '.crossings[] | select(.type == "tool_call") | .tool_name' |
sort | uniq -c
undefined

Exporting Multiple Journeys

导出多个运行流程

bash
undefined
bash
undefined

Export last 10 journeys as JSON

导出最近10个运行流程为JSON格式

curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys |
jq -r '.journeys[].id' | head -10 | while read id; do curl -s "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/$id.json" > "journey_$id.json" done
undefined
curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys |
jq -r '.journeys[].id' | head -10 | while read id; do curl -s "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/$id.json" > "journey_$id.json" done
undefined

Monitoring Agent Failures

监控Agent失败情况

bash
undefined
bash
undefined

List failed journeys with error details

列出失败的运行流程及错误详情

curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys |
jq '.journeys[] | select(.status == "failed") | {id, error, updated_at}'
undefined
curl -s http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys |
jq '.journeys[] | select(.status == "failed") | {id, error, updated_at}'
undefined

Security and Redaction

安全与脱敏

Labyrinth applies Hermes core secret redaction to all outputs:
python
from hermes.redactor import redact_secrets

def safe_export(content: str) -> str:
    """Apply redaction before export."""
    try:
        return redact_secrets(content)
    except Exception:
        # Fail closed if redactor unavailable
        return "[redaction unavailable]"
Labyrinth对所有输出应用Hermes核心敏感信息脱敏功能:
python
from hermes.redactor import redact_secrets

def safe_export(content: str) -> str:
    """Apply redaction before export."""
    try:
        return redact_secrets(content)
    except Exception:
        # 若脱敏工具不可用则关闭导出
        return "[redaction unavailable]"

Verification Before Production

生产环境前验证

Test redaction with dummy secrets:
bash
undefined
使用模拟敏感信息测试脱敏功能:
bash
undefined

Create test journey with dummy API keys in prompts/outputs

创建测试运行流程,在提示词/输出中包含模拟API密钥

hermes chat "Test: sk-dummy-key-12345"
hermes chat "Test: sk-dummy-key-12345"

Verify redaction in UI and exports

在UI和导出内容中验证脱敏效果

Should return nothing if redaction works

若脱敏生效则无返回结果

Should return nothing if redaction works

若脱敏生效则无返回结果

undefined
undefined

Testing

测试

Run Full Test Suite

运行完整测试套件

bash
npm test
Includes:
  • Build reproducibility checks
  • JavaScript/Python parse validation
  • API normalization fixture tests
  • Headless Chrome smoke tests
bash
npm test
包括:
  • 构建可重复性检查
  • JavaScript/Python解析验证
  • API标准化 fixture测试
  • 无头Chrome冒烟测试

Backend API Tests

后端API测试

bash
python3 scripts/test-plugin-api.py
Tests timestamp normalization, redaction, and data structure handling.
bash
python3 scripts/test-plugin-api.py
测试时间戳标准化、脱敏及数据结构处理。

Manual Smoke Test

手动冒烟测试

bash
npm run smoke
Runs headless Chrome against built demo:
  • Map mode switching
  • Route navigation
  • Search functionality
  • Dataset switching
  • Threshold filtering
bash
npm run smoke
针对构建好的演示页面运行无头Chrome测试:
  • 地图模式切换
  • 路由导航
  • 搜索功能
  • 数据集切换
  • 阈值过滤

Troubleshooting

故障排查

Plugin Not Appearing in Dashboard

插件未在仪表盘显示

  1. Verify installation path:
bash
ls -la ~/.hermes/plugins/hermes-labyrinth/dashboard/manifest.json
  1. Restart dashboard (rescan doesn't mount new Python routes):
bash
undefined
  1. 验证安装路径:
bash
ls -la ~/.hermes/plugins/hermes-labyrinth/dashboard/manifest.json
  1. 重启仪表盘(重新扫描不会挂载新的Python路由):
bash
undefined

Stop dashboard

停止仪表盘

hermes dashboard stop
hermes dashboard stop

Start dashboard

启动仪表盘

hermes dashboard

3. Check dashboard logs for plugin API import errors.
hermes dashboard

3. 检查仪表盘日志中的插件API导入错误。

Backend/API Diagnostic in UI

UI中显示后端/API诊断

This means the Python API routes failed to load:
  1. Restart dashboard completely (not just rescan)
  2. Check Python imports:
bash
python3 -c "import sys; sys.path.insert(0, '$HOME/.hermes/plugins/hermes-labyrinth/dashboard'); import plugin_api"
  1. Verify Hermes home exists:
bash
ls -la ~/.hermes/state.db
这表示Python API路由加载失败:
  1. 完全重启仪表盘(不仅仅是重新扫描)
  2. 检查Python导入:
bash
python3 -c "import sys; sys.path.insert(0, '$HOME/.hermes/plugins/hermes-labyrinth/dashboard'); import plugin_api"
  1. 验证Hermes主目录存在:
bash
ls -la ~/.hermes/state.db

Redaction Unavailable Error

脱敏不可用错误

If reports show
[redaction unavailable]
:
  1. Verify Hermes core is installed properly
  2. Check redactor import:
python
from hermes.redactor import redact_secrets
  1. This is a fail-closed safety mechanism — plugin won't export unredacted content
若报告显示
[redaction unavailable]
  1. 验证Hermes核心组件已正确安装
  2. 检查脱敏工具导入:
python
from hermes.redactor import redact_secrets
  1. 这是一个安全关闭机制——插件不会导出未脱敏的内容

Empty Journeys List

运行流程列表为空

  1. Verify agent sessions exist:
bash
sqlite3 ~/.hermes/state.db "SELECT COUNT(*) FROM sessions;"
  1. Check file permissions:
bash
ls -la ~/.hermes/state.db
  1. Run health check:
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health
  1. 验证Agent会话存在:
bash
sqlite3 ~/.hermes/state.db "SELECT COUNT(*) FROM sessions;"
  1. 检查文件权限:
bash
ls -la ~/.hermes/state.db
  1. 运行健康检查:
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health

Build Failures

构建失败

bash
undefined
bash
undefined

Clean and rebuild

清理并重新构建

rm -rf dashboard/dist index.html npm run build npm run check
undefined
rm -rf dashboard/dist index.html npm run build npm run check
undefined

Development References

开发参考