hermes-notify

June 28, 2026 · View on GitHub

English | 中文

Snow

Role in the Hermes messaging ecosystem: hermes-notify is the CLI sender layer — two commands (notify-hermes, notify-agent) for injecting messages into the ecosystem. It sends; it does not receive or process. The other two packages in the ecosystem are:

  • hermes-bustransport daemon that routes JSON messages between endpoints via Unix Socket
  • hermes-bus-pluginreceive-side agent plugin that consumes bus messages and routes them to terminal output, LLM context injection, or command execution

Together: notify → bus → plugin. Route rules live in ~/.hermes/bus-rules.yaml.


Hermes Messaging Ecosystem

Hermes Bus Ecosystem Architecture

The ecosystem has four layers:

Layer 1 — CLI / User Space (this package)
  notify-hermes ──→ hermes-bus (Unix Socket)
  notify-agent  ──→ tmux session (send-keys)

Layer 2 — Transport
  hermes-bus daemon — JSON routing, session management

Layer 3 — Agent / Plugin
  hermes-bus-plugin — print · context · command · channel routing

Layer 4 — Gateway / Platform
  Platform adapters — WeChat · Feishu · WeCom · DingTalk → Users
LayerPackageRole
1 — CLIhermes-notify (this package)Send messages into the ecosystem
2 — Transporthermes-busRoute JSON messages between endpoints
3 — Pluginhermes-bus-pluginConsume messages: terminal output, LLM context, commands, channel routing
4 — Gateway(downstream)Platform adapters deliver replies to end users. Zero agent code changes

Install

pip install hermes-notify

Or from source:

git clone https://github.com/mlinquan/hermes-notify.git
cd hermes-notify && pip install -e .

notify-hermes — Send Through the Bus

Sends a JSON message to any bus endpoint via short-lived Unix Socket connection (hermes_bus.client.send_message). The message is routed by the bus daemon to the target endpoint. Route processing (print, context injection, command execution) is handled by hermes-bus-plugin on the receiving end.

Syntax

notify-hermes --to <endpoint> [options] "message text"
notify-hermes --to <endpoint> --body '{"text":"hello","key":"value"}'

Parameters

ArgumentRequiredDefaultDescription
--toyesTarget bus endpoint name (e.g. lead-agent, hermes-bus, worker-alpha)
"message"*Plain text message (positional, last argument). Mutually exclusive with --body
--body*Full JSON body dict as a string. Mutually exclusive with positional message
--typenononeApplication-level message type (see table below)
--channelnononeReply routing token: platform:chat_id or platform (falls back to *_HOME_CHANNEL env var)
--fromnoauto (notify-hermes) / none (notify-agent)Override sender name. notify-hermes: auto-detected from tmux session via role_map. notify-agent: omitted → no sender prefix; provided → role_map lookup
--socketnoautoCustom Unix socket path. Default: $HERMES_BUS_ROOT/hermes-bus.sock
--confignoautoPath to bus-rules.yaml. Default: $HERMES_HOME/bus-rules.yaml

* Either "message" or --body is required, but not both.

--type values

The values below are common conventions — --type accepts any string, bus-rules.yaml matches them exactly.

--typeMeaningReceiver behavior (via bus-rules.yaml)
directiveTask assignment (coordinator → worker)context=true (silent injection)
ackAcknowledgementprint=true (terminal only)
task_startTask startedcontext=true
progressIntermediate progress updatecontext=true
task_doneTask completedprint=true + context=true + command (audio + gateway-forward)
plan_readyPlan ready for reviewprint=true + context=true + command
task_errorError / escalationprint=true + context=true + command
need_decisionDecision neededprint=true + context=true + command

--channel values

ValueResolves to
feishu:oc_abc123Feishu, chat oc_abc123 directly
wecom:ww456WeCom, chat ww456 directly
dingtalk:cid789DingTalk, chat cid789 directly
feishuFeishu, fallback to FEISHU_HOME_CHANNEL env var
wecomWeCom, fallback to WECOM_HOME_CHANNEL env var

The channel token is an opaque routing string. Agents pass it through unmodified. Only the bus-plugin at final delivery acts on it.

Message body assembly

When using "message text" (positional):

{"text": "message text", "type": "task_done", "channel": "feishu:oc_abc123"}

When using --body:

{"text": "hello", "type": "ack", "custom_field": "value"}

--type and --channel are merged into the body dict. --body takes precedence for fields it already defines.

Examples

# Simple acknowledgement
notify-hermes --to lead-agent --type ack "Received, starting work"

# Task completion with channel for reply routing
notify-hermes --to lead-agent --type task_done \
  --channel feishu:oc_abc123 \
  "Auth middleware refactor complete. 5/5 endpoints migrated."

# Progress update (silent — context injection only, no terminal noise)
notify-hermes --to lead-agent --type progress \
  --channel feishu:oc_abc123 \
  "Phase 2 of 4: extracted token validation module"

# Error escalation with channel
notify-hermes --to lead-agent --type task_error \
  --channel wecom_ops \
  "Production outage detected — database connection pool exhausted"

# Full JSON body for custom payloads
notify-hermes --to lead-agent \
  --body '{"text":"Deploy complete","type":"task_done","version":"2.1.0","commit":"abc123"}'

# Custom sender name override
notify-hermes --to lead-agent --type ack --from ci-pipeline "Build #142 passed"

notify-agent — Send to a tmux Session

Sends text directly to a tmux session via send-keys. Does NOT go through the bus. Used for direct inter-agent communication within the same machine.

Syntax

notify-agent [--from SENDER] [--to SESSION] <session> "message text"

Parameters

ArgumentRequiredDescription
--tonoTarget tmux session name (alternative to positional <session>)
--fromnoSender display name. role_map lookup if provided (unmatched → use --from value as-is). Omitted → no sender prefix
<session>yes*Target tmux session name (positional, alternative to --to)
"message"yesPlain text message (positional, last argument)

* Either --to or positional <session> is required.

Message Format

Messages are formatted as ⚕ [{sender}]: {text} where {sender} is resolved through role_map (unmatched → use --from value as-is):

# If role_map has: worker-alpha: {name: "Alpha", ...}
notify-agent --from worker-alpha --to lead-agent "Hello"
# Sends: ⚕ [Alpha]: Hello

# If --from not in role_map
notify-agent --from MyBot --to lead-agent "Hello"
# Sends: ⚕ [MyBot]: Hello

# If --from omitted
notify-agent --to lead-agent "Hello"
# Sends: Hello  (no sender prefix)

Examples

# Start two agent sessions
tmux new-session -d -s lead-agent   'claude'
tmux new-session -d -s worker-alpha 'claude'

# Send a message (auto-detect sender from current session)
notify-agent lead-agent "Task queue is empty, ready for next assignment"

# With explicit sender (resolved through role_map)
notify-agent --from worker-alpha --to lead-agent "Build complete, 3 tests passing"

# Using --to parameter
notify-agent --from worker-alpha --to lead-agent "Direct message via --to"

Important: The target must be a running tmux session. Use notify-hermes for bus-routed messages that can be processed by hermes-bus-plugin.


Configuration

Route rules, role mappings, and sender auto-detection are configured in ~/.hermes/bus-rules.yaml. See hermes-bus-plugin for the full rule format.

Role mapping (for --from auto-detection)

# bus-rules.yaml
role_map:
  lead-agent:   {name: "Lead",    color: "bold_cyan"}
  worker-alpha: {name: "Alpha",   color: "bold_yellow"}
  worker-beta:  {name: "Beta",    color: "bold_magenta"}
  unknown:      {name: "Unknown", color: "white"}

default_sender: notify-agent

When --from is omitted, notify-hermes reads the current tmux session name, looks it up in role_map, and uses the mapped name as the sender.

Skill Registration

When installed as a Hermes plugin, hermes-notify registers the notify-cli skill — agents can discover CLI notification tools (notify-hermes, notify-agent) via snow_search without reading source code or man pages.


Quickstart

# 1. Install all three packages
pip install hermes-bus hermes-notify hermes-bus-plugin

# 2. Start the bus daemon
hermes-busd start

# 3. Start agent sessions
tmux new-session -d -s lead-agent   'claude'
tmux new-session -d -s worker-alpha 'claude'

# 4. Send messages
notify-hermes --to lead-agent --type ack "Hello from worker-alpha"
notify-agent --from worker-alpha lead-agent "Direct message, no bus"

# 5. Check bus status
hermes-busd status

Architecture

notify-hermes ──→ hermes-bus (Unix Socket) ──→ hermes-bus-plugin (agent)
notify-agent  ──→ tmux send-keys ──→ target session terminal

Message routing (print / context injection / command execution)
is handled by hermes-bus-plugin via ~/.hermes/bus-rules.yaml.