guide · computers

Hermes Agent Skills: Authoring, Curating, and the Frontmatter Rules

Where skills live, the SKILL.md frontmatter fields, the cross_profile flag and pinning, when to update vs add a new skill, and how curator catches drift in the weekly sweep.

July 14, 2026 · By Alastair Fraser

A friendly retro robot sitting beside a wooden card-catalog drawer titled SKILLS. One drawer is labeled AUTHOR and is half-open with a quill ready to write; the drawer below is labeled CURATE with a clipboard checklist pinned to it. Warm cream background, ink-outline illustration.

Skills are how Hermes Agent keeps a procedure sharp every time. Most users hit the four-store memory-vs-skills question first (covered in Hermes Agent Memory vs Skills) and stop there. This guide goes the next step: how to author a skill, how to keep SKILL.md frontmatter well-formed, and how the weekly curator sweep catches the skills you forgot.

What a skill is, in one paragraph

A skill is a markdown file with a YAML frontmatter at /opt/data/skills/<category>/<name>/SKILL.md. The agent loads it on demand via skill_view(name="...") and follows the procedural guidance inside. Skills beat memory at procedures (memory holds durable preferences; skills hold reusable workflows). Skills beat prompts (one skill serves every chat; one prompt is one chat). The mental model: skill = a procedure file, memory = a preference file, handoff = a parking lot, fact_store = an entity database. Treat them as different categories of thing, and the rest of this guide reads cleanly.

Where skills live and how they are discovered

/opt/data/skills/ is the canonical store on this VPS. Each top-level directory is a category — devops/, creative/, web/, data-science/, ecommerce/, media/, and so on. Inside each category, every named subdirectory holds one skill’s SKILL.md, with optional references/, templates/, scripts/, and assets/ siblings. A live enumeration on this install shows roughly 68 top-level skill directories and over 100 individual SKILL.md files including nested entries like devops/hermes-image-gen-providers.

Discovery is by file presence plus frontmatter parse. skill_view walks the directory, parses each SKILL.md, and reads the required name and description fields. Skills without valid frontmatter — missing --- close marker, non-YAML content, empty body — are silently dropped. That silent drop is why the next section matters.

The canonical frontmatter

Every peer skill in /opt/data/skills/ uses the same shape. The minimal, validator-passing block:

---
name: my-skill-name
description: "Use when <trigger>. <one-line behavior>."
version: 1.1.0
author: Hermes Agent
license: MIT
metadata:
  hermes:
    tags: [short, descriptive, tags]
    related_skills: [other-skill, another-skill]
---

Field purposes:

  • name — lowercase, hyphens or underscores, ≤64 chars. The argument to skill_view(name=...).
  • description — ≤1024 chars (validator-enforced), single sentence, ideally trigger-first (“Use when…”). The agent’s recall cue.
  • version, author, license — not validator-enforced, but every peer has them. Omit and your skill looks half-finished.
  • metadata.hermes.tags — short, descriptive tags. Used for skills_list filtering.
  • metadata.hermes.related_skills — the loader unions these across trees at load time.

The hard rule: do not edit a deployed skill’s frontmatter casually. Renaming name breaks every memory pointer, every cron prompt that references it, and every related_skills list. A typo is recoverable; a rename is destructive. Use skill_manage(action='patch') for content edits, or write_file to the in-repo tree when the edit ships with a commit.

Truncate frontmatter at the close marker

YAML stops at the first \n---\n it sees. If a description contains three-dash sequences — footnote markers like ---, math notation, an em-dash the editor rendered as literal characters — the parser truncates your frontmatter mid-field. The skill then loads with whatever sits before the spurious ---, your description is cut off, and name may even be missing. Discovery drops the skill.

This bit on 2026-06-29 when a description contained --- the reward function --- mid-sentence. Wrap descriptions in double quotes, escape internal --- runs, and never put raw --- between the opening fence and the closing fence. The in-repo skill hermes-agent-skill-authoring codifies the same rule: read the SKILL.md back through a YAML parser after every edit, and confirm the parsed shape matches what you wrote.

cross_profile and pinning

cross_profile: true makes a skill available across all Hermes profiles (each profile has its own skills tree; default is per-profile). A profile-bound skill loads only when the active profile owns it. A cross-profile skill loads regardless of which profile is active. Most user-local skills stay per-profile; cross-profile is for genuinely shared procedures (the canonical example is hermes-agent-skill-authoring itself).

Pinning is a different idea. When a skill has been regression-tested against specific behavior, you can pin it to a version so that --fix and weekly curator sweeps don’t upgrade it silently. Most skills ship the latest by default. Pin when behavior matters more than recency — a deploy recipe validated against the current Cloudflare API, a parser that handles a known schema. The rule: pin when the cost of surprise exceeds the cost of staying stale.

When to update vs add

Three rules, in priority order:

  1. If a skill exists and covers the new pattern (even obliquely): edit it. A new skill that overlaps an old one makes the agent pick the older one because skill_view resolves by name. The duplicate gets discovered but ignored.
  2. If the new pattern is genuinely new and reusable across sessions: author a fresh skill. Class-level umbrellas earn their overhead at 3+ reusable facts. One fact for one session is a handoff note, a memory line, or a fact_store entry — not a skill.
  3. Never have two skills that overlap. Merge them. skill_manage(action='delete', absorbed_into=<umbrella>) exists exactly so the curator can tell consolidation from pruning.

The boundary I draw in practice: a procedure skill_view will load on more than one task across more than one session is a skill candidate. A procedure used once in one session is a handoff note.

The curator weekly sweep

hermes curator runs against /opt/data/skills/ and reports unused skills, broken frontmatter, missing categories, and absorbed_into edges from past deletions. Output reads roughly like:

Curator sweep — 2026-07-14
Scanned: 187 SKILL.md files in /opt/data/skills/
🔴 Critical: 2 skills with parser-rejected frontmatter
   - devops/foo (missing closing `---`)
   - hermes-cron/bar (non-YAML in description)
🟡 Warning: 4 skills unused for 90+ days
🔵 Info: 12 skills with no `metadata.hermes.tags`
Report: /opt/data/curator-reports/2026-07-14.md

Sorted by severity. 🔴 fires a Telegram ping; 🟡 goes to the weekly report file; 🔵 is silent unless the user asks. --dry-run previews; --fix applies mechanical safe edits. Merging overlapping skills or deleting a duplicate remains a manual call.

Lint pass

hermes lint walks every skill frontmatter and reports. Three checks:

  1. Memory pressure — chars in MEMORY.md and USER.md against the 2,200-char ceiling per profile.
  2. Fact contradictionsfact_store(action='contradict') probes (skipped on this build; tool not registered).
  3. Skill drift — every reference inside every SKILL.md resolved against the live filesystem: file paths via test -e, tool names via tools_help, cross-skill references via test -e <skill_path>/SKILL.md, env vars via grep on both /opt/data/.env and /opt/hermes/.env.

Use --fix to auto-correct YAML truncation and missing optional fields. Use --dry-run to preview. Output carries the threshold tier (🔴/🟡/🔵), the issue count, and a path to the dated report at /opt/data/lint-reports/<date>.md.

What not to do

  • Don’t put secrets in a skill. The file is read into the agent prompt on load.
  • Don’t hand-renumber pin fields across skills. Order is by registration date. Pin by name, not by ordinal.
  • Don’t author two skills that overlap. Merge with absorbed_into.
  • Don’t name a skill after a date (fix-thing-2026-06-29) — that’s a session-specific fact, not a class-level procedure.

Verification checklist

#CommandWhat it proves
1hermes skills list --source localNew skill is visible in the discovery list
2hermes skills browse <my-new-skill>Browse page returns the parsed frontmatter
3hermes curator --dry-runLint passes against the new skill
4hermes chat -q "Load <my-new-skill>" --toolsets skillsskill_view returns the SKILL.md body

Sources

Last verified: 2026-07-14 against Hermes v0.18.2 (2026.7.7.2) and /opt/data/skills/ on this install.

Sources

#hermes#skills#authoring#yaml#playbook#curator

Submit a take

Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.

Your email address will not be published. Required fields are marked.