Hermes Workflows
Agent-owned workflow graphs for Hermes Agent.
Your agent authors a JSON graph of agent nodes, fan-outs and gates; a background
runner executes it outside the caller process tree and hands results back through the same
workflow tool it launched from. Hermes Desktop draws the live DAG.

What you get
| Capability | In one line |
|---|---|
| Graph runs | Agent nodes with goal, after edges, per-node model/provider/reasoning, and max_turns/timeout/run_budget caps |
| Fan-out | One node → N live children from fanout.items or items_from:"<node>.items"; per-item liveness, quorum |
| Human + machine gates | A gate holds on a question until release; gate.wait holds for a timer or an argv probe; when predicates branch on upstream output; on_skip:"prune" kills the losing arm |
| Fingerprint resume | Every finished node records an effective fingerprint. Crash, restart, or amend the graph — only what actually changed re-runs |
| Cooperative steer | steer queues text; a running child pulls it at its next seam via the tool's inbox action |
| Typed failures | Every node.failed event carries error_class + attempts (timeout, cap_exhausted, provider_400, schema, cancelled, fatal_quota, route_unavailable, …) — the parent never infers a cause from prose |
| Route integrity | A node that pins an explicit model is fail-closed by default (require_route): a dead or fallback-surprised pin refuses the launch instead of silently billing another model; an alive-proved pin bakes the door-only route_verified and the runner holds the served model to it |
| Compact status | Mid-run status/wait return output pointers; detail:"full" opts into everything; terminal payloads are always full |
| Desktop DAG view | Live graph, fan-out stacks, timeline, and a ::workflow{id="…"} inline card in any reply; the live-run strip mounts below the composer dock (composer.underside, core ≥ v2026.7.30 — falls back to above-it composer.top on older shells) |
| Library | save a proven graph (description + tags), library lists it richly, run with from: replays it; a hand-rolled graph the library missed goes to submit with a why_not_library receipt — quarantined for study, never auto-saved; inbox lists them |
| Authoring skill | Bundled workflow skill with grammar, operations, and measured per-shape budget recipes |
Install
hermes plugins install hermes-workflows # from the catalog (pinned SHA)
hermes plugins enable hermes-workflows
Restart the backend (hermes serve) so the tool and dashboard routes mount.
Before disabling or removing the plugin, stop live runs: use workflow {"action":"list"}
to find their run IDs, then workflow {"action":"stop","run_id":"<id>"} for each.
Detached runners can outlive a session, gateway restart, or plugin disable until a
boundary; disabling alone does not stop them. Desktop gate answers use the SDK to
send a visible resume turn to the run owner's chat; older Desktop builds insert
text for you to send, or ask you to type workflow wait in that owner chat.
If Hermes Desktop runs on a different machine than the backend, copy
desktop/plugin.js to that machine's ~/.hermes/desktop-plugins/hermes-workflows/plugin.js
— the app hot-loads it. Manual/zip install and removal: INSTALL.md.
Then ask your agent for a workflow. The bundled skill teaches it the grammar; the smallest graph is one node:
{ "name": "check",
"nodes": [{ "id": "inspect", "type": "agent",
"goal": "Inspect the target. Return one fenced JSON object." }] }
workflow { "action": "run", "graph": <the object above> } → run_id
workflow { "action": "wait", "run_id": "<run_id>" } → repeat until terminal
Two builds, one codebase
The plugin needs no patched Hermes. Every child spawn rides the stock quiet one-shot CLI contract, and every install runs the same code. Exactly one field differs, and it is optional:
| stock Hermes (catalog install) | with the optional core patch | |
|---|---|---|
| graphs, fan-out, gates, steer, resume, desktop view, cards | ✓ | ✓ |
a child that dies on its max_turns cap |
error_class: unknown + preserved partial/log |
typed error_class: cap_exhausted + reason |
| how | nothing to do | one sha-stamped patch — docs/patched-core.md |
The tier is self-reported: after a failed child, status shows
turn_report: typed or untyped, so you always know which build you're on.
When upstream PR #121041
lands, the branch collapses and that doc deletes itself.
Requirements
- Hermes Agent ≥ v2026.9.21 (package version 0.21.4) (measured
stock
-QCLI and quiet turn-report contract; see docs/catalog/pr-body.md). Older 0.21.3 deployments are below this declared floor and will skip plugin admission. - Python 3 (stdlib only — the plugin imports nothing outside Hermes)
- Node for the desktop half's tests only; the app loads
plugin.jsuncompiled
For agents and contributors
AGENTS.md is the front door: repo map, install/operate/contribute
procedures, the test contract, and the rules that keep the tree publishable.
Changes are gated by the serial suite (python3 scripts/suite.py . ci-out) and
hermes plugins validate . — both run in CI.
The repo ships a graphify knowledge
graph (graphify-out/, deterministic AST — no LLM in the build). graphify query "<question>" returns a scoped subgraph instead of a grep
dump; graphify-out/GRAPH_REPORT.md is the architecture overview. CI fails if the
committed graph drifts from the tree.
License
MIT — see LICENSE.

