Skip to content

feat(cli): add hermes send to pipe script output to any messaging platform#19631

Closed
teknium1 wants to merge 1 commit into
mainfrom
feat/hermes-send
Closed

feat(cli): add hermes send to pipe script output to any messaging platform#19631
teknium1 wants to merge 1 commit into
mainfrom
feat/hermes-send

Conversation

@teknium1

@teknium1 teknium1 commented May 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a hermes send CLI subcommand that pipes text from shell scripts, cron scripts, CI hooks, and monitoring daemons to any messaging platform Hermes is already configured for. Zero new platform-specific code — it's a thin wrapper over the existing send_message_tool.

This scratches the "I want to ping myself from a bash script" itch without having to re-paste bot tokens into every watchdog or re-implement each platform's REST API.

Examples

hermes send --to telegram "deploy finished"
echo "RAM 92%" | hermes send --to telegram:-1001234567890
hermes send --to discord:#ops --file report.md
hermes send --to slack:#eng --subject "[CI]" --file build.log
hermes send --to telegram:-1001234567890:17585 "threaded reply"
hermes send --list                 # all targets across all platforms
hermes send --list telegram        # filter by platform
hermes send --list --json          # machine-readable

Exit codes follow the classic Unix convention: 0 ok, 1 delivery failure, 2 usage error.

Design

  • hermes_cli/send_cmd.py — single file, ~300 LOC, delegates all real work to tools.send_message_tool.send_message_tool. Supports every platform the tool already does: Telegram, Discord, Slack, Signal, SMS, WhatsApp, Matrix, Feishu, DingTalk, WeCom, Weixin, Email, etc.
  • No running gateway needed for bot-token platforms — the shared tool hits each platform's REST endpoint directly using credentials from ~/.hermes/.env + ~/.hermes/config.yaml. Plugin platforms that rely on a live adapter connection still require the gateway to be running; their error message is forwarded verbatim.
  • Env bootstrap — replicates the minimum of gateway/run.py's startup bridge: load_dotenv(~/.hermes/.env) plus bridging top-level config.yaml scalars into os.environ (without overriding existing env vars). Necessary because TELEGRAM_HOME_CHANNEL and friends are read via os.getenv by the gateway config loader and live in config.yaml when set via hermes config set.
  • Message body precedence: positional arg > --file PATH (or --file -) > piped stdin. When stdin is a TTY with no pipe, the CLI emits a clean usage error instead of blocking on input.
  • Registered via a tiny import in hermes_cli/main.py next to the other messaging subcommands (slack, whatsapp).

Docs

  • New guide: website/docs/guides/pipe-script-output.md — walks through the watchdog pattern, CI notifications, cron piping, and scripting with --json / --quiet. Includes a comparison table vs raw curl, cron delivery, and the send_message agent tool so people land on the right approach for their use case.
  • Cross-links added from:
    • automate-with-cron.md (tip box: "no LLM? use hermes send")
    • developer-guide/gateway-internals.md (delivery-path section)

Tests

tests/hermes_cli/test_send_cmd.py — 20 tests, all green:

  • Happy paths: positional, stdin, --file, --file -, --subject, --json, --quiet
  • Error paths: missing --to, missing body, file not found, tool returns error (exit 1), tool skipped-send (exit 0)
  • --list: human, --json, platform filter, unknown platform
  • Env loader: bridges config.yaml scalars, does not override existing env, handles missing files
  • Registrar contract

Smoke-tested end-to-end against a live Telegram bot before commit — successfully delivered a message from a fresh shell invocation.

Compatibility

  • No changes to existing commands or tools.
  • No new dependencies.
  • No config migration needed.

Test Plan

  • scripts/run_tests.sh tests/hermes_cli/test_send_cmd.py passes (20/20)
  • scripts/run_tests.sh tests/hermes_cli/test_send_cmd.py tests/gateway/test_config.py passes (60/60)
  • hermes send --help renders cleanly
  • hermes send --list prints the shared channel directory
  • Live send to Telegram home channel succeeded

…latform

Introduces a thin CLI wrapper around the existing send_message_tool so
shell scripts, cron scripts, CI hooks, and monitoring daemons can reuse
the gateway's already-configured platform credentials without
reimplementing each platform's REST client.

## What

  hermes send --to telegram "deploy finished"
  echo "RAM 92%" | hermes send --to telegram:-1001234567890
  hermes send --to discord:#ops --file report.md
  hermes send --to slack:#eng --subject "[CI]" --file build.log
  hermes send --list                  # all targets
  hermes send --list telegram         # filter by platform

Supports all platforms the send_message tool already does (Telegram,
Discord, Slack, Signal, SMS, WhatsApp, Matrix, Feishu, DingTalk, WeCom,
Weixin, Email, etc.), including threaded targets and #channel-name
resolution via the channel directory.

## How

hermes_cli/send_cmd.py delegates to tools.send_message_tool.send_message_tool,
which means there is zero new platform-specific code. The subcommand just:

1. Bridges ~/.hermes/.env and top-level ~/.hermes/config.yaml scalars into
   os.environ (same bootstrap the gateway does at startup) — required so
   TELEGRAM_HOME_CHANNEL and friends are visible to load_gateway_config().
2. Resolves the message body from positional arg, --file, or piped stdin.
3. Calls the shared tool and translates its JSON result to exit codes:
   0 success, 1 delivery failure, 2 usage error.

No running gateway is required for bot-token platforms (Telegram, Discord,
Slack, Signal, SMS, WhatsApp) — the tool hits each platform's REST API
directly. Plugin platforms that rely on a live adapter connection still
need the gateway running; the error message is forwarded verbatim.

## Docs

- New guide: website/docs/guides/pipe-script-output.md covering real-world
  patterns (memory watchdogs, CI hooks, cron pipes, long-running task
  completion pings) and the security/gateway notes.
- Cross-links added from automate-with-cron.md ("no LLM? use hermes send")
  and developer-guide/gateway-internals.md (delivery-path section).

## Tests

tests/hermes_cli/test_send_cmd.py (20 tests, all green):

- Happy paths: positional message, stdin, --file, --file -, --subject,
  --json, --quiet.
- Error paths: missing --to, missing body, file not found, tool returns
  error payload (exit 1), tool skipped-send result (exit 0).
- --list: human output, --json output, platform filter, unknown platform.
- Env loader: bridges config.yaml scalars into env, does not override
  existing env vars, gracefully handles missing files.
- Registrar contract: register_send_subparser() returns a working parser.

Smoke-tested end-to-end against a live Telegram bot before commit.
Comment thread hermes_cli/send_cmd.py Dismissed
Comment thread hermes_cli/send_cmd.py Dismissed
Comment thread hermes_cli/send_cmd.py Dismissed
Comment thread hermes_cli/send_cmd.py Dismissed
@teknium1

Copy link
Copy Markdown
Contributor Author

Closing in favor of #27188, which salvages this PR onto current main. One docs conflict resolved by merging both 'no-agent cron' and 'hermes send' tips into a single 'two zero-token options' callout — recurring use cases go to cron, one-shot/external triggers go to hermes send. 20 tests pass, --help renders, home-channel fallback (--to telegram with no chat_id) works as expected via the existing send_message_tool config bridge.

@teknium1 teknium1 closed this May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants