All plugins

hermes-autonomous

Proactive follow-ups: reads the recent conversation, finds things worth returning to (care / utility / risk / curiosity) and comes back at the right moment — a check on the weather before a trip, the price of something bought yesterday, or just "did your throat get better?". Event-driven rather than a daily digest: a cheap no-LLM gate runs on the cron tick and only wakes the agent when something is actually due. Sending goes through followups.py send, which enforces the 90-minute cooldown, the 23:00–08:00 quiet window, muted categories, at most three items and six lines per message, and records the receipt immediately. Disclosure — it reads the Hermes session database (~/.hermes/state.db) read-only: only sessions owned by the configured owner, DMs by default, with group/thread/forum/channel sessions (including other members' messages) only after setup --include-groups; it reads the cron job store (~/.hermes/cron/jobs.json) read-only when doctor or setup runs, and writes only its own plugin-data directory (mode 0600). The install step copies two helper scripts into ~/.hermes/scripts/; doctor --fix edits only this plugin's own cron job via hermes cron edit and never creates or deletes jobs. During a review the agent runs the plugin's helper through its terminal tool, and followups.py send delivers the DM with hermes send; the optional offline scripts/decide.py calls hermes -z. No credentials are read and there is no telemetry.

xiaokAutomationv0.7.1Updated 1 hour ago

About

Proactive follow-ups: reads the recent conversation, finds things worth returning to (care / utility / risk / curiosity) and comes back at the right moment — a check on the weather before a trip, the price of something bought yesterday, or just "did your throat get better?". Event-driven rather than a daily digest: a cheap no-LLM gate runs on the cron tick and only wakes the agent when something is actually due. Sending goes through followups.py send, which enforces the 90-minute cooldown, the 23:00–08:00 quiet window, muted categories, at most three items and six lines per message, and records the receipt immediately. Disclosure — it reads the Hermes session database (~/.hermes/state.db) read-only: only sessions owned by the configured owner, DMs by default, with group/thread/forum/channel sessions (including other members' messages) only after setup --include-groups; it reads the cron job store (~/.hermes/cron/jobs.json) read-only when doctor or setup runs, and writes only its own plugin-data directory (mode 0600). The install step copies two helper scripts into ~/.hermes/scripts/; doctor --fix edits only this plugin's own cron job via hermes cron edit and never creates or deletes jobs. During a review the agent runs the plugin's helper through its terminal tool, and followups.py send delivers the DM with hermes send; the optional offline scripts/decide.py calls hermes -z. No credentials are read and there is no telemetry.

hermes-autonomous

Your agent should remember to check on you.

Most assistants wait. You ask, it answers, the thread closes — and the thing you mentioned on Tuesday
(you were sick, you had a meeting, you bought something) never comes back.

hermes-autonomous is a proactivity layer for Hermes Agent:
it quietly reads your past conversations, notices what is worth returning to, and comes back at the
right moment — sometimes with a useful check (weather, price, a deadline), sometimes with nothing more
than "did your throat get better?"

It is not a digest. It is not a task list. It does not require you to configure what it should watch.

中文说明


Install

You don't install anything. Just tell your agent:

Install the plugin xiaok/hermes-autonomous, enable it, configure it for this chat, and create the
review cron job.

It installs the plugin, writes your local settings, copies the cron helpers and schedules the loop.
Nothing identifying lives in this repo — your ids end up in
~/.hermes/plugin-data/hermes-autonomous/settings.json (mode 0600), on your machine only.

hermes plugins install xiaok/hermes-autonomous --enable
PLUGIN=~/.hermes/plugins/hermes-autonomous
python3 $PLUGIN/scripts/followups.py setup --owner-id <id> --dm-target telegram:<id>
cp $PLUGIN/cron/*.py ~/.hermes/scripts/
hermes cron create "*/15 * * * *" "Read $PLUGIN/prompts/review.md and follow it" \
  --name "proactive follow-ups" --monitor-script followup-wake.py \
  --script followup-digest.py --deliver local --failure-deliver origin
  • --monitor-script is required. It is the wake gate; leave it out and the agent runs
    unconditionally every 15 minutes.
  • --deliver local keeps normal runs from posting anything to your chat — you only hear from the
    job if it fails (--failure-deliver origin). The follow-ups themselves already reach you as DMs
    via hermes send.
  • Optional debug switch: followups.py setup --dev-log makes each run reply with a short developer
    log (off by default; --no-dev-log turns it back off).

Don't know your Telegram id? Message @userinfobot, or ask Hermes — it can
read the id of the conversation it is in.

git clone https://github.com/xiaok/hermes-autonomous.git ~/opt/hermes-autonomous
ln -s ~/opt/hermes-autonomous ~/.hermes/plugins/hermes-autonomous
hermes plugins enable hermes-autonomous
python3 ~/opt/hermes-autonomous/scripts/followups.py setup --owner-id … --dm-target …

Upgrade

hermes plugins update hermes-autonomous
PLUGIN=~/.hermes/plugins/hermes-autonomous
python3 $PLUGIN/scripts/followups.py doctor --fix

Jobs created by older versions may lack --monitor-script (the agent then runs every 15 minutes no
matter what) or use --deliver origin (every run posts its final reply to your chat). doctor --fix
corrects the job in place with hermes cron edit — it never deletes or recreates it. If there is no
job at all, it prints the commands to create one. Without --fix it only reports.


What it actually does

every 15 min   a cheap script asks "is anything worth waking up for?"      ~0 tokens
when yes       read the last hours of conversation, update the board
               check the weather / price / page / calendar
               decide: stay silent · act and report · ask first
               at most one message, at most three items

Four things have to be true before it speaks:

| Gate | Rule |
|---|---|
| Due | that specific thing is worth revisiting now — not a fixed 9am digest |
| New | something changed since you last talked about it; a repeat is not a follow-up |
| Sourced | it can quote what you actually said; no source, no message |
| Rationed | ≤3 items and ≤6 lines per message, 90-minute cooldown, silence 23:00–08:00 |

The first three are judgment calls the agent makes against the rubric. The last one is enforced in
code: every DM goes out through followups.py send, which refuses at night, during the cooldown,
for more than 3 items or more than 6 lines. A refused message is not sent and not shortened — that
run simply ends without one. The cooldown also means one message per wake at most.

And the reason it does not become noise: your reactions are written back. At the start of each
review the agent records how you reacted to what it sent in the last 48 hours (accepted,
ignored, annoyed, useless). Within 30 days, one annoyed or three ignored on sent items mute
that whole category (care / utility / risk / curiosity): its due items no longer wake a
review, the digest marks them held, and send refuses them. Muting only happens once those outcomes
have been recorded; followups.py why shows what is muted.

Two kinds of value (the part most assistants miss)

  • Utility — the meeting is tomorrow: here is the weather and when to leave.
  • Care — you said your throat hurt. Two days later: "better?" No action value at all, and still
    the most important message it can send.

That is why the decision runs on two separate scoring lines. Judging only by "is this actionable"
silently deletes every caring message.

Why this shape

We read the post-mortems so you don't have to. ChatGPT Pulse was retired nine months after launch:
its own limitation note admitted it kept suggesting work you had already finished, and v1 shipped with
no off switch. The pattern behind every dead proactive assistant is the same — fixed schedules, no
completion write-back, configuration pushed onto the user.

This one binds to events, writes every outcome back, and asks for nothing but a yes/no answer in chat.
The full teardown and the research numbers (the best models score ~66% F1 on "should I speak", with
35–48% precision) are in docs/RESEARCH.md (Chinese) and
docs/teardown.md (Chinese).

How it decides

  • prompts/decide.md — the rubric: what counts as worth returning to, the two
    scoring lines, the three action tiers.
  • scripts/decide.py — run any scenario offline and see the exact judgment:
    python3 scripts/decide.py --scenario scenarios/01-throat.json
  • docs/DECIDER.md (Chinese) — inputs, gates, output schema.

The conversations in scenarios/ are made-up examples; they do not belong to any real user.

Your data

  • Only sessions that belong to your user id are read, and by default only your DM with Hermes:
    your messages there and Hermes' replies. Group chats, threads, forum topics and channels
    (Discord/Slack threads, Telegram forum-group topics — i.e. any session Hermes records as
    chat_type='group', 'thread', 'forum' or 'channel'; a Telegram private-chat topic stays
    'dm') are off unless you run
    followups.py setup --include-groups — and once on, everything in those sessions is read,
    including what other members wrote there.
  • State lives in ~/.hermes/plugin-data/hermes-autonomous/ (SQLite + settings, mode 0600), never in
    the repo.
  • The repo ships with no ids, names, chats or personal scenarios — you configure them locally.

What it touches (disclosure)

  • Reads the Hermes session database ~/.hermes/state.db — read-only, only sessions owned by your
    user id: user and assistant turns in your DM; group, thread, forum and channel sessions (all
    members' messages) only with include_groups.
  • Reads Hermes' cron job store ~/.hermes/cron/jobs.json (read-only) when doctor runs — also
    once at the end of setup — to find this plugin's job. If the store can't be read it falls back to
    hermes cron list. Besides that it reads only its own settings.
  • Writes its own data directory ~/.hermes/plugin-data/hermes-autonomous/
    (SQLite board + settings.json, mode 0600; plus a send.lock file).
  • Copies the two cron helpers (cron/followup-wake.py, cron/followup-digest.py) into
    ~/.hermes/scripts/ at install time — your agent does this, or you do with the cp above. That is
    where the job's --script / --monitor-script names are looked up.
  • Modifies its own cron job with doctor --fix: hermes cron edit <id> --monitor-script … --deliver local --failure-deliver origin on the job it recognises as this plugin's. Never another job, never
    delete or recreate; without --fix it only reports.
  • Network: the plugin code makes no requests. During a review your agent may look things up
    (weather, prices, news) using Hermes' own tools — that traffic belongs to Hermes, not to this plugin.
  • Shell: /followups runs one local Python helper (scripts/followups.py) with
    sys.executable; the cron helpers are plain Python. followups.py starts hermes in two places:
    doctor (hermes cron list as the fallback above, hermes cron edit with --fix) and
    followups.py send, which runs hermes send to deliver the DM after its gates pass. During a review
    the agent itself uses its terminal tool to run this plugin's helpers (followups.py digest,
    followups.py send, followups.py apply, …). The offline tool scripts/decide.py calls hermes -z
    for one tool-less model call — only when you run it yourself. No hook, no background thread, no
    approval bypass.
  • Credentials: none. Your Telegram ids live in the plugin's own settings.json (0600) — not in
    .env, auth.json or any keychain.
  • No telemetry, no analytics.

Docs

中文说明 · Design (Chinese) ·
Research (Chinese) · Decider (Chinese) ·
Teardown (Chinese)

Tested with Hermes Agent 0.22.2 (requires_hermes: ">=0.22.2").

MIT.

README from the reviewed commit 431c5fa; it updates when the author re-pins.