Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Hermes Labyrinth Observability

ASecurity

Read-only observability dashboard plugin for Hermes Agent — journeys, crossings, guideposts, and reports.

81 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentjavascriptpythonjavabashgitapifrontendbackend

Works with

cliapi

Security Analysis

A96/100
mediumUses curl or wget to download content

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add reason-machines/trending-skills --skill hermes-labyrinth-observability --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hermes Labyrinth Observability?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Hermes Labyrinth Observability
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/reason-machines-hermes-labyrinth-observability/badge)](https://www.skillsdirectory.com/skills/reason-machines-hermes-labyrinth-observability)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: hermes-labyrinth-observability
description: Read-only observability dashboard plugin for Hermes Agent — journeys, crossings, guideposts, and reports.
triggers:
  - add hermes labyrinth to my agent setup
  - how do I observe my hermes agent runs
  - install hermes labyrinth plugin
  - view agent journey crossings dashboard
  - export hermes agent report
  - debug autonomous agent with labyrinth
  - set up hermes observability plugin
  - how do I read hermes labyrinth API
---

# Hermes Labyrinth

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

Hermes Labyrinth is a **read-only observability dashboard plugin** for [Hermes Agent](https://github.com/NousResearch/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.

---

## 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.

### Optional Theme

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

---

## What Labyrinth Tracks

| View | Contents |
|---|---|
| **Journey index** | Recent CLI, dashboard, gateway, cron, and delegated work |
| **Labyrinth map** | Ordered crossings through a selected agent journey |
| **Inspector** | Input, output, duration, status, evidence, guideposts per crossing |
| **Guideposts** | Generated observations backed by local evidence |
| **Skill atlas** | Bundled, optional, external, and user skill inventory |
| **Cron gate** | Scheduled autonomy, next runs, last failures, workdirs |
| **Model ferry** | Model/provider transitions across sessions |
| **Reports** | Redacted Markdown and JSON exports for one journey |

---

## API Surface

All endpoints are read-only. The plugin API is served by Hermes dashboard at:

```
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
```

### Example: Fetch All Journeys

```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 .
```

### Example: Export a Journey Report as Markdown

```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

```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
```

---

## Python API Client Examples

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")

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

### 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")
```

### 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}")
```

---

## JavaScript / Frontend API Examples

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();
```

---

## 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
# Build dashboard/dist and index.html
npm run build

# Run reproducibility and parse checks
npm run check

# Run browser smoke tests (headless Chrome)
npm run smoke

# Smoke-test the deployed GitHub Pages demo
npm run smoke:live

# Run all tests (build checks, fixture tests, smoke)
npm test
```

### 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

---

## 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
```

---

## 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
```

---

## 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.

---

## 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?")
```

### 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())

# Filter to only cron-triggered journeys
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")]
```

### 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}")
```

---

## 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.

### API returns 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`.

### Build artifacts out of date

```bash
npm run build
# Then verify reproducibility
npm run check
```

### 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.

### 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.

### Numeric timestamps in API responses

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.

---

## Links

- **Live demo**: https://stainlu.github.io/hermes-labyrinth/
- **Hermes Agent**: https://github.com/NousResearch/hermes-agent
- **Release v0.1.0**: https://github.com/stainlu/hermes-labyrinth/releases/tag/v0.1.0
- **License**: MIT

Attribution

reason-machinesreason-machines
View sourceMore from reason-machines →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →