hermes-labyrinth-observability

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Hermes Labyrinth

Hermes Labyrinth

Skill by ara.so — Daily 2026 Skills collection.
Hermes Labyrinth is a read-only observability dashboard plugin for Hermes Agent. It turns autonomous agent runs into a navigable map of crossings (prompts, tool calls, tool results, failures, model switches, subagents, approvals, memory hits, redactions, context compression, cron runs) with exportable evidence. It is not a chat UI — it is a black-box recorder for agents moving through unknown work.

ara.so开发的Skill——属于Daily 2026 Skills合集。
Hermes Labyrinth是一款面向Hermes Agent只读可观测性仪表盘插件。它将自主Agent的运行过程转化为可导航的地图,记录各类节点(提示词、工具调用、工具结果、失败记录、模型切换、子Agent、审批操作、内存命中、内容脱敏、上下文压缩、定时任务运行),并支持导出证据。它并非聊天UI,而是用于追踪Agent在未知任务流程中运行情况的黑盒记录工具。

Install

安装

Plugin Directory Install

插件目录安装

bash
mkdir -p ~/.hermes/plugins
git clone https://github.com/stainlu/hermes-labyrinth.git ~/.hermes/plugins/hermes-labyrinth
Start or restart the Hermes dashboard:
bash
hermes dashboard
If the dashboard is already running, rescan plugins without restarting:
bash
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
Open the dashboard in your browser and select the Labyrinth tab.
bash
mkdir -p ~/.hermes/plugins
git clone https://github.com/stainlu/hermes-labyrinth.git ~/.hermes/plugins/hermes-labyrinth
启动或重启Hermes仪表盘:
bash
hermes dashboard
如果仪表盘已在运行,无需重启即可重新扫描插件:
bash
curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
在浏览器中打开仪表盘,选择Labyrinth标签页。

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/

What Labyrinth Tracks

Labyrinth追踪内容

ViewContents
Journey indexRecent CLI, dashboard, gateway, cron, and delegated work
Labyrinth mapOrdered crossings through a selected agent journey
InspectorInput, output, duration, status, evidence, guideposts per crossing
GuidepostsGenerated observations backed by local evidence
Skill atlasBundled, optional, external, and user skill inventory
Cron gateScheduled autonomy, next runs, last failures, workdirs
Model ferryModel/provider transitions across sessions
ReportsRedacted Markdown and JSON exports for one journey

视图内容
旅程索引近期的CLI、仪表盘、网关、定时任务及委托任务
Labyrinth地图所选Agent旅程中的有序节点
检查器每个节点的输入、输出、时长、状态、证据、指引标记
指引标记基于本地证据生成的观测记录
Skill图谱内置、可选、外部及用户自定义Skill清单
定时任务网关计划任务自动化、下次运行时间、最近失败记录、工作目录
模型切换器跨会话的模型/提供商切换记录
报告单旅程的脱敏Markdown和JSON导出文件

API Surface

API接口

All endpoints are read-only. The plugin API is served by Hermes dashboard at:
http://127.0.0.1:9119/api/plugins/hermes-labyrinth/
所有接口均为只读。插件API由Hermes仪表盘提供,地址为:
http://127.0.0.1:9119/api/plugins/hermes-labyrinth/

Endpoints

接口列表

GET /api/plugins/hermes-labyrinth/health
GET /api/plugins/hermes-labyrinth/journeys
GET /api/plugins/hermes-labyrinth/journeys/{journey_id}
GET /api/plugins/hermes-labyrinth/journeys/{journey_id}/crossings
GET /api/plugins/hermes-labyrinth/skills
GET /api/plugins/hermes-labyrinth/cron
GET /api/plugins/hermes-labyrinth/guideposts
GET /api/plugins/hermes-labyrinth/reports/{journey_id}.json
GET /api/plugins/hermes-labyrinth/reports/{journey_id}.md
GET /api/plugins/hermes-labyrinth/health
GET /api/plugins/hermes-labyrinth/journeys
GET /api/plugins/hermes-labyrinth/journeys/{journey_id}
GET /api/plugins/hermes-labyrinth/journeys/{journey_id}/crossings
GET /api/plugins/hermes-labyrinth/skills
GET /api/plugins/hermes-labyrinth/cron
GET /api/plugins/hermes-labyrinth/guideposts
GET /api/plugins/hermes-labyrinth/reports/{journey_id}.json
GET /api/plugins/hermes-labyrinth/reports/{journey_id}.md

Example: Fetch All Journeys

示例:获取所有旅程

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys | jq .
bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys | jq .

Example: Fetch Crossings for a Journey

示例:获取某旅程的节点记录

bash
JOURNEY_ID="your-journey-id"
curl "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/${JOURNEY_ID}/crossings" | jq .
bash
JOURNEY_ID="your-journey-id"
curl "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/journeys/${JOURNEY_ID}/crossings" | jq .

Example: Export a Journey Report as Markdown

示例:导出旅程报告为Markdown格式

bash
JOURNEY_ID="your-journey-id"
curl "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/${JOURNEY_ID}.md" > report.md
bash
JOURNEY_ID="your-journey-id"
curl "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/${JOURNEY_ID}.md" > report.md

Example: Export a Journey Report as JSON

示例:导出旅程报告为JSON格式

bash
JOURNEY_ID="your-journey-id"
curl "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/${JOURNEY_ID}.json" > report.json
bash
JOURNEY_ID="your-journey-id"
curl "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/reports/${JOURNEY_ID}.json" > report.json

Example: Health Check

示例:健康检查

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health

bash
curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health

Python API Client Examples

Python API客户端示例

The plugin backend lives at
dashboard/plugin_api.py
. You can also call the HTTP API from any language. Here are Python examples:
python
import urllib.request
import json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

def get_journeys():
    with urllib.request.urlopen(f"{BASE}/journeys") as r:
        return json.loads(r.read())

def get_crossings(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/journeys/{journey_id}/crossings") as r:
        return json.loads(r.read())

def get_report_json(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/reports/{journey_id}.json") as r:
        return json.loads(r.read())

def get_report_md(journey_id: str) -> str:
    with urllib.request.urlopen(f"{BASE}/reports/{journey_id}.md") as r:
        return r.read().decode("utf-8")
插件后端位于
dashboard/plugin_api.py
。你也可以用任意语言调用HTTP API。以下是Python示例:
python
import urllib.request
import json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

def get_journeys():
    with urllib.request.urlopen(f"{BASE}/journeys") as r:
        return json.loads(r.read())

def get_crossings(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/journeys/{journey_id}/crossings") as r:
        return json.loads(r.read())

def get_report_json(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/reports/{journey_id}.json") as r:
        return json.loads(r.read())

def get_report_md(journey_id: str) -> str:
    with urllib.request.urlopen(f"{BASE}/reports/{journey_id}.md") as r:
        return r.read().decode("utf-8")

Usage

使用示例

journeys = get_journeys() for j in journeys: print(j["id"], j.get("status"), j.get("started_at"))
undefined
journeys = get_journeys() for j in journeys: print(j["id"], j.get("status"), j.get("started_at"))
undefined

Iterate Crossings and Inspect Tool Calls

遍历节点并检查工具调用

python
import urllib.request
import json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

def inspect_tool_crossings(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/journeys/{journey_id}/crossings") as r:
        crossings = json.loads(r.read())

    for crossing in crossings:
        if crossing.get("type") == "tool_call":
            print(f"Tool: {crossing['tool']}")
            print(f"  Status:   {crossing.get('status')}")
            print(f"  Duration: {crossing.get('duration_ms')}ms")
            print(f"  Input:    {json.dumps(crossing.get('input', {}))[:200]}")
            print()

inspect_tool_crossings("your-journey-id")
python
import urllib.request
import json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

def inspect_tool_crossings(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/journeys/{journey_id}/crossings") as r:
        crossings = json.loads(r.read())

    for crossing in crossings:
        if crossing.get("type") == "tool_call":
            print(f"工具: {crossing['tool']}")
            print(f"  状态:   {crossing.get('status')}")
            print(f"  时长: {crossing.get('duration_ms')}ms")
            print(f"  输入:    {json.dumps(crossing.get('input', {}))[:200]}")
            print()

inspect_tool_crossings("your-journey-id")

Download and Save All Reports for Recent Journeys

下载并保存近期旅程的所有报告

python
import urllib.request
import json
import pathlib

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"
OUT = pathlib.Path("./labyrinth-reports")
OUT.mkdir(exist_ok=True)

with urllib.request.urlopen(f"{BASE}/journeys") as r:
    journeys = json.loads(r.read())

for j in journeys[:10]:  # last 10 journeys
    jid = j["id"]
    try:
        with urllib.request.urlopen(f"{BASE}/reports/{jid}.json") as r:
            (OUT / f"{jid}.json").write_bytes(r.read())
        with urllib.request.urlopen(f"{BASE}/reports/{jid}.md") as r:
            (OUT / f"{jid}.md").write_bytes(r.read())
        print(f"Saved reports for {jid}")
    except Exception as e:
        print(f"Failed {jid}: {e}")

python
import urllib.request
import json
import pathlib

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"
OUT = pathlib.Path("./labyrinth-reports")
OUT.mkdir(exist_ok=True)

with urllib.request.urlopen(f"{BASE}/journeys") as r:
    journeys = json.loads(r.read())

for j in journeys[:10]:  # 最近10个旅程
    jid = j["id"]
    try:
        with urllib.request.urlopen(f"{BASE}/reports/{jid}.json") as r:
            (OUT / f"{jid}.json").write_bytes(r.read())
        with urllib.request.urlopen(f"{BASE}/reports/{jid}.md") as r:
            (OUT / f"{jid}.md").write_bytes(r.read())
        print(f"已保存{jid}的报告")
    except Exception as e:
        print(f"{jid}保存失败: {e}")

JavaScript / Frontend API Examples

JavaScript/前端API示例

The frontend plugin bundle lives in
dashboard/dist/
. If you're extending the UI or writing a custom integration:
javascript
const BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth";

async function fetchJourneys() {
  const res = await fetch(`${BASE}/journeys`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

async function fetchCrossings(journeyId) {
  const res = await fetch(`${BASE}/journeys/${journeyId}/crossings`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

async function fetchReportMarkdown(journeyId) {
  const res = await fetch(`${BASE}/reports/${journeyId}.md`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.text();
}

// Example: log all failed crossings in the most recent journey
async function logFailures() {
  const journeys = await fetchJourneys();
  if (!journeys.length) return;
  const crossings = await fetchCrossings(journeys[0].id);
  const failed = crossings.filter(c => c.status === "failure" || c.status === "error");
  console.table(failed.map(c => ({
    type: c.type,
    tool: c.tool ?? "-",
    duration_ms: c.duration_ms,
    error: c.error?.slice(0, 120),
  })));
}

logFailures();

前端插件包位于
dashboard/dist/
。如果你要扩展UI或编写自定义集成:
javascript
const BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth";

async function fetchJourneys() {
  const res = await fetch(`${BASE}/journeys`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

async function fetchCrossings(journeyId) {
  const res = await fetch(`${BASE}/journeys/${journeyId}/crossings`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

async function fetchReportMarkdown(journeyId) {
  const res = await fetch(`${BASE}/reports/${journeyId}.md`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.text();
}

// 示例:记录最近一个旅程中所有失败的节点
async function logFailures() {
  const journeys = await fetchJourneys();
  if (!journeys.length) return;
  const crossings = await fetchCrossings(journeys[0].id);
  const failed = crossings.filter(c => c.status === "failure" || c.status === "error");
  console.table(failed.map(c => ({
    type: c.type,
    tool: c.tool ?? "-",
    duration_ms: c.duration_ms,
    error: c.error?.slice(0, 120),
  })));
}

logFailures();

Build & Development

构建与开发

The frontend is built from
src/parts/*.js
+
src/labyrinth.css
into
dashboard/dist/
. The demo
index.html
is generated with content-hash query strings.
bash
undefined
前端代码从
src/parts/*.js
+
src/labyrinth.css
构建到
dashboard/dist/
。演示用的
index.html
会生成带内容哈希查询字符串的版本。
bash
undefined

Build dashboard/dist and index.html

构建dashboard/dist和index.html

npm run build
npm run build

Run reproducibility and parse checks

运行可复现性和语法检查

npm run check
npm run check

Run browser smoke tests (headless Chrome)

运行浏览器冒烟测试(无头Chrome)

npm run smoke
npm run smoke

Smoke-test the deployed GitHub Pages demo

对部署在GitHub Pages的演示版本进行冒烟测试

npm run smoke:live
npm run smoke:live

Run all tests (build checks, fixture tests, smoke)

运行所有测试(构建检查、测试用例测试、冒烟测试)

npm test
undefined
npm test
undefined

Full Test Suite

完整测试套件

bash
npm test
Runs:
  • Reproducible build checks for
    dashboard/dist
    and
    index.html
  • Frontend JavaScript parse checks
  • Backend Python parse checks
  • API normalization fixture tests (including numeric Hermes timestamps)
  • Packed-artifact and dead-control regressions
  • Headless Chrome smoke coverage for map modes, route changes, search, dataset switching, and threshold filter

bash
npm test
运行以下测试:
  • dashboard/dist
    index.html
    的可复现构建检查
  • 前端JavaScript语法检查
  • 后端Python语法检查
  • API标准化测试用例(包括Hermes的数字时间戳)
  • 打包产物和无效控制流回归测试
  • 无头Chrome冒烟测试,覆盖地图模式、路由切换、搜索、数据集切换和阈值过滤

Repository Layout

仓库结构

.
├── dashboard/
│   ├── manifest.json        # Hermes dashboard plugin manifest
│   ├── plugin_api.py        # Read-only API over local Hermes state
│   └── dist/                # Generated dashboard plugin bundle
├── docs/
│   ├── CONCEPT.md
│   ├── DESIGN_BRIEF.md
│   └── FUNCTIONAL_SPEC.md
├── scripts/
│   ├── build-plugin.mjs     # Builds dashboard/dist and index.html
│   ├── smoke-demo.mjs       # Browser smoke test for public demo
│   ├── test-plugin-api.py   # Fixture tests for API normalization
│   └── verify.mjs           # Local verification checks
├── src/
│   ├── demo/                # GitHub Pages demo source
│   ├── parts/               # Ordered frontend source chunks
│   └── labyrinth.css        # Frontend CSS source
├── theme/
│   └── hermes-labyrinth.yaml
├── index.html               # Generated GitHub Pages demo
└── package.json

.
├── dashboard/
│   ├── manifest.json        # Hermes仪表盘插件清单
│   ├── plugin_api.py        # 基于本地Hermes状态的只读API
│   └── dist/                # 生成的仪表盘插件包
├── docs/
│   ├── CONCEPT.md
│   ├── DESIGN_BRIEF.md
│   └── FUNCTIONAL_SPEC.md
├── scripts/
│   ├── build-plugin.mjs     # 构建dashboard/dist和index.html
│   ├── smoke-demo.mjs       # 公开演示版本的浏览器冒烟测试
│   ├── test-plugin-api.py   # API标准化的测试用例
│   └── verify.mjs           # 本地验证检查
├── src/
│   ├── demo/                # GitHub Pages演示版本源码
│   ├── parts/               # 有序的前端源码片段
│   └── labyrinth.css        # 前端CSS源码
├── theme/
│   └── hermes-labyrinth.yaml
├── index.html               # 生成的GitHub Pages演示页面
└── package.json

Architecture

架构

Hermes local state
  ├─ state.db sessions/messages
  ├─ skills directories
  └─ cron config
dashboard/plugin_api.py
/api/plugins/hermes-labyrinth/*
src/parts/*.js + src/labyrinth.css
        ↓ npm run build
dashboard/dist/*
Hermes dashboard tab: Labyrinth

Hermes本地状态
  ├─ state.db会话/消息
  ├─ skills目录
  └─ cron配置
dashboard/plugin_api.py
/api/plugins/hermes-labyrinth/*
src/parts/*.js + src/labyrinth.css
        ↓ npm run build
dashboard/dist/*
Hermes仪表盘标签页: Labyrinth

Data Policy (Important)

数据政策(重要)

  • Read-only by design: does not start, stop, resume, mutate, or create Hermes sessions.
  • Secret redaction: applied to previews and reports.
  • Unknown fields: stay unknown — not silently dropped.
  • Reports: generated from local Hermes state only.
  • Public demo: uses sample/mocked data — not live telemetry.

  • 设计为只读:不会启动、停止、恢复、修改或创建Hermes会话。
  • 敏感信息脱敏:应用于预览和报告中。
  • 未知字段保留:不会被静默丢弃。
  • 报告生成:仅基于本地Hermes状态生成。
  • 公开演示:使用示例/模拟数据——无实时遥测数据。

Common Patterns

常见模式

Check Plugin Health Before Querying

查询前检查插件健康状态

python
import urllib.request, json

def is_labyrinth_healthy() -> bool:
    try:
        with urllib.request.urlopen(
            "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health",
            timeout=3
        ) as r:
            data = json.loads(r.read())
            return data.get("status") == "ok"
    except Exception:
        return False

if not is_labyrinth_healthy():
    print("Labyrinth plugin not reachable — is `hermes dashboard` running?")
python
import urllib.request, json

def is_labyrinth_healthy() -> bool:
    try:
        with urllib.request.urlopen(
            "http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health",
            timeout=3
        ) as r:
            data = json.loads(r.read())
            return data.get("status") == "ok"
    except Exception:
        return False

if not is_labyrinth_healthy():
    print("无法连接到Labyrinth插件——是否运行了`hermes dashboard`?")

Filter Journeys by Type

按类型过滤旅程

python
import urllib.request, json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

with urllib.request.urlopen(f"{BASE}/journeys") as r:
    journeys = json.loads(r.read())
python
import urllib.request, json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

with urllib.request.urlopen(f"{BASE}/journeys") as r:
    journeys = json.loads(r.read())

Filter to only cron-triggered journeys

过滤仅定时任务触发的旅程

cron_journeys = [j for j in journeys if j.get("origin") == "cron"]
cron_journeys = [j for j in journeys if j.get("origin") == "cron"]

Filter to only failed journeys

过滤仅失败的旅程

failed_journeys = [j for j in journeys if j.get("status") in ("failure", "error")]
undefined
failed_journeys = [j for j in journeys if j.get("status") in ("failure", "error")]
undefined

Summarize Crossing Types in a Journey

汇总某旅程的节点类型

python
from collections import Counter
import urllib.request, json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

def summarize_journey(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/journeys/{journey_id}/crossings") as r:
        crossings = json.loads(r.read())
    counts = Counter(c.get("type", "unknown") for c in crossings)
    total_ms = sum(c.get("duration_ms", 0) for c in crossings)
    print(f"Journey {journey_id}: {len(crossings)} crossings, {total_ms}ms total")
    for ctype, n in counts.most_common():
        print(f"  {ctype}: {n}")

python
from collections import Counter
import urllib.request, json

BASE = "http://127.0.0.1:9119/api/plugins/hermes-labyrinth"

def summarize_journey(journey_id: str):
    with urllib.request.urlopen(f"{BASE}/journeys/{journey_id}/crossings") as r:
        crossings = json.loads(r.read())
    counts = Counter(c.get("type", "unknown") for c in crossings)
    total_ms = sum(c.get("duration_ms", 0) for c in crossings)
    print(f"旅程{journey_id}: {len(crossings)}个节点,总时长{total_ms}ms")
    for ctype, n in counts.most_common():
        print(f"  {ctype}: {n}")

Troubleshooting

故障排除

Plugin tab not appearing in dashboard

插件标签页未在仪表盘中显示

  1. Confirm clone location:
    ls ~/.hermes/plugins/hermes-labyrinth/dashboard/manifest.json
  2. Restart
    hermes dashboard
    or rescan:
    curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
  3. Check
    manifest.json
    is valid JSON.
  1. 确认克隆位置:
    ls ~/.hermes/plugins/hermes-labyrinth/dashboard/manifest.json
  2. 重启
    hermes dashboard
    或重新扫描:
    curl http://127.0.0.1:9119/api/dashboard/plugins/rescan
  3. 检查
    manifest.json
    是否为有效的JSON文件。

API returns 404

API返回404错误

  • Verify the plugin loaded:
    curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health
  • Confirm
    hermes dashboard
    is running on port
    9119
    .
  • 验证插件是否加载:
    curl http://127.0.0.1:9119/api/plugins/hermes-labyrinth/health
  • 确认
    hermes dashboard
    在端口
    9119
    运行。

Build artifacts out of date

构建产物过期

bash
npm run build
bash
npm run build

Then verify reproducibility

然后验证可复现性

npm run check
undefined
npm run check
undefined

Smoke tests fail locally

冒烟测试在本地失败

  • Requires headless Chrome/Chromium available in
    PATH
    .
  • Run
    npm run smoke
    for local,
    npm run smoke:live
    for the deployed Pages demo.
  • 需要在
    PATH
    中提供无头Chrome/Chromium。
  • 运行
    npm run smoke
    进行本地测试,运行
    npm run smoke:live
    测试部署在Pages的演示版本。

Reports contain redacted fields

报告包含脱敏字段

This is expected. Labyrinth applies secret redaction to all previews and exports by design. Raw values are only accessible inside the Hermes process itself.
这是预期行为。Labyrinth设计上会对所有预览和导出内容进行敏感信息脱敏。原始值仅能在Hermes进程内部访问。

Numeric timestamps in API responses

API响应中的数字时间戳

The API normalization layer handles numeric Hermes timestamps automatically (covered by fixture tests in
scripts/test-plugin-api.py
). If you consume the API directly, expect either ISO 8601 strings or Unix epoch integers in timestamp fields.

API标准化层会自动处理Hermes的数字时间戳(由
scripts/test-plugin-api.py
中的测试用例覆盖)。如果直接调用API,时间戳字段可能是ISO 8601字符串或Unix时间戳整数。

Links

链接