Hermes AgentAI agentsautomationTelegramPythonlead generation

Hermes Agent on a Schedule: A Daily Lead Finder That Posts to Telegram

·9 min read

Hermes Agent is one of the fastest-rising AI searches in India this year. Most posts about it show the chat side: talk to it on Telegram, let it write skills, let it remember you. This one shows the boring side, which is where I got the most value: a scheduled job that runs every morning at 9:00 IST, finds people asking for SEO help, drafts a reply, and sends me a Telegram digest I can act on from my phone.


It has been running daily since 15 October 2026. In its first week it collected 276 posts, threw away 245 as not a real buyer, and drafted replies for 31. I approve every message by hand.


Last checked: 22 October 2026, on Hermes Agent v0.21.4.


What Hermes Agent is (in one paragraph)


Hermes Agent is an open-source (MIT) agent from Nous Research. You install it on your laptop or a VPS, and one gateway process connects it to Telegram, Discord, Slack, WhatsApp and the CLI. It has memory, skills, plugins and a built-in cron scheduler that delivers results to any of those chats. If you've read my OpenClaw self-hosting guide, it's the same category of tool.


The pipeline



09:00 IST  Hermes cron (no-agent mode)
   │
   ├─ Reddit search (12 subs + 7 queries)     ┐
   ├─ Hacker News (Algolia API, last 3 days)  │  ~300 posts/day
   ├─ X live search (3 queries)               │
   └─ LinkedIn contract / part-time SEO jobs  ┘
   │
   ▼  regex filter: SEO words AND buying words, NOT "for hire" / "my agency"
SQLite (leads.db, url = unique key, so nothing is seen twice)
   │
   ▼  PageSpeed Insights audit if the post links a site (free, no key)
Groq gpt-oss-120b: score 1–10, fit yes/no, draft first reply
   │
   ▼  stdout
Telegram digest: top 6 leads + /send /edit /skip /email

All of it is one Python file using only the standard library: about 330 lines, with no requests and no LangChain.


Step 1: a no-agent cron job


This is the feature that makes Hermes useful for automation. A normal cron job wakes the agent up, gives it a prompt and lets the LLM decide what to do. A no-agent job just runs a script and sends its stdout to the chat word for word. No model and no tokens are involved.



# script lives in ~/.hermes/scripts/
hermes cron create "0 9 * * *" \
  --no-agent \
  --script seo_leads.py \
  --deliver telegram \
  --name seo-leads-daily

The rules that matter, from the Hermes cron docs:


  • Empty stdout = silent tick. No leads means no message, so I'm not spammed.
  • Non-zero exit = error alert delivered to Telegram. A broken job can't fail quietly.
  • Missed runs catch up. My Mac is often asleep at 9:00. When the gateway starts at login, the job runs once, late, instead of being skipped. Hermes logs it as "kind": "late". This morning's ran 54 minutes late, and that's fine.

  • Step 2: collect from four sources


    Each source is a Python generator that yields the same dict shape: url, source, author, title, body.


    
    def hackernews():
        since = int(time.time()) - 3 * 86400
        url = "https://hn.algolia.com/api/v1/search_by_date?" + urllib.parse.urlencode(
            {"query": "SEO", "tags": "(story,comment)",
             "numericFilters": f"created_at_i>{since}", "hitsPerPage": 100})
        for h in json.loads(get(url))["hits"]:
            yield {"url": f"https://news.ycombinator.com/item?id={h['objectID']}",
                   "source": "hackernews", "author": h.get("author") or "",
                   "title": h.get("title") or h.get("story_title") or "",
                   "body": strip_html(h.get("comment_text") or h.get("story_text") or "")}
    

  • Hacker News: the public Algolia API. No key, and it's the most reliable source.
  • Reddit, X and LinkedIn: through OpenCLI, which drives my own logged-in browser and returns JSON. Reddit falls back to a single multi-subreddit RSS request when the browser is closed, because Reddit returns 429 if you hit each sub's RSS separately.
  • LinkedIn has no post search, so I search contract and part-time SEO jobs from the last week instead.

  • Every source is wrapped so that one failure can't sink the run. Errors go into a list that is printed at the bottom of the digest:


    
    ⚠️ reddit 'need SEO help': exitCode: 69
    

    That warning is real. Reddit search through the browser failed on 20 and 22 October, and the digest told me so the same morning.


    Step 3: a cheap filter before any LLM


    Most posts that mention SEO come from sellers, not buyers. Three regexes remove most of them for free:


    
    INTENT = re.compile(r"\b(hiring|hire|looking for|need(ed)?|seeking|recommend|help with|budget|paid|freelancer|agency)\b", re.I)
    SEO = re.compile(r"\b(seo|search console|google rank|organic traffic|core web vitals|indexing|indexed|serp)\b", re.I)
    NOT_BUYER = re.compile(r"\bfor hire\b|\bi am an seo\b|\bmy seo agency\b|\boffering\b", re.I)
    

    A post must match SEO and buying intent, and must not look like an agency ad. Reddit posts on user profiles are dropped too (that's almost always self-promotion). Whatever survives goes into SQLite with insert or ignore on the URL, so a post is processed once, ever.


    Step 4: Groq qualifies and drafts


    New leads go to Groq's openai/gpt-oss-120b in batches of 4. The system prompt is not hard-coded. It's sections 1–5 of a PLAYBOOK.md file, read at runtime. To change how replies sound, I edit the markdown, and the next morning's drafts follow it.


    The rules that made drafts worth sending:


  • Answer their question first, using details from their own post. Give a real fix they can check today.
  • No pitch, no price, no links in a first message. End with "happy to take a look".
  • Never invent problems on their site. Write "if X, check Y" unless the audit shows it.
  • Never claim past clients or results. Offer a free Loom review of their site as proof instead.
  • Return strict JSON: {"id", "fit", "score", "why", "draft"}.

  • Two things I learned the hard way:


    1. reasoning_effort: "low" made things up. It invented broken sitemaps and past clients. "medium" stopped that.

    2. The free tier has a tokens-per-minute cap. With the playbook, one call is about 4k tokens, so the script sleeps 35 seconds between batches and retries 429s. If a batch fails, those leads stay new and are retried tomorrow.


    If you don't have a Groq key, any OpenAI-compatible endpoint works. I compare the free options in Free LLM APIs in 2026.


    Step 5: the Telegram digest and slash commands


    The script prints the top 6 leads by score, each with the post title, a one-line "why", the PageSpeed audit if there was a site, the draft and the link. Here is a real one from the first week (lead #27, r/smallbusiness, scored 8/10: "Help on website developed in Claude Code"). The model's first draft was:


    Since you'll be adding blog posts weekly, setting up a proper XML sitemap and automating its updates will ensure Google crawls new content fast. I can implement a Next.js-compatible sitemap generator... Does that sound useful?

    It's generic, it pitches, and it doesn't answer the question. I rewrote it like this:


    One thing to check with Claude Code sites: if it built a client-side React/Vite app, Google sees a nearly empty page until JavaScript runs, and new blog posts can take weeks to get indexed. Quick test: right-click → View Page Source (not Inspect). If your blog text isn't in there, that's the issue, and prerendering fixes it. Happy to look at the URL if you want a second pair of eyes.

    Then I pasted both versions into the playbook as a "weak vs strong" example. Every later draft is written with that example in front of the model, and no code changed. The digest ends with the commands:


    
    /send ID · /edit ID what to change · /skip ID · /email ID addr · /leads
    

    Those commands come from a small Hermes plugin: a plugin.yaml and an __init__.py that calls ctx.register_command() for each one. Each handler runs the same script with a subcommand, so no LLM is involved except for /edit:


    
    def register(ctx):
        for name, (prefix, usage, desc) in COMMANDS.items():
            ctx.register_command(name, handler=_cmd(*prefix, usage=usage), description=desc)
        for status in ("skip", "won", "lost", "replied", "call"):
            ...  # each one runs: seo_leads.py mark ID 
    

  • /send 27 prints the final text and marks the lead contacted. I post it myself. No auto-DMs.
  • /edit 27 shorter, mention Next.js rewrites the draft with Groq.
  • /email 27 founder@site.com sends it from my own domain through a Cloudflare Worker mail API.
  • /replied, /call, /won and /lost turn the same SQLite table into a tiny CRM.

  • Why I switched the agent's LLM off


    My first version was a normal Hermes cron job: "find SEO leads and draft replies", with the agent choosing tools. It failed for three reasons:


    1. Prompt size. Hermes's agent system prompt (tools, memory, skills) was about 18k tokens. Groq's free tier allows roughly 8k tokens a minute for this model, so every run hit 429 before doing anything.

    2. API mismatch. Hermes sent a reasoning_effort value that Groq rejected.

    3. Cost and reliability. Free models on aggregator routers expired or rate-limited from one week to the next.


    The fix was to let the script make all the decisions and use the LLM only for the one thing it's good at: reading a post and writing a reply. Hermes still does what it's best at: scheduling, catching up missed runs, delivering to Telegram and hosting the commands.


    That's my general rule for agents now: if you can write the steps down, write them as code, and call the model only for judgment. I wrote about the same trade-off for my infrastructure agent.


    Results after one week


    Count
    Posts collected (15–22 Oct) 276
    Auto-skipped (sellers, spam, not a fit) 245
    Drafted for review 31
    Biggest skip source X (55), r/AISEOInsider (25)
    Best drafted source r/jobboardsearch, X, r/SaaS
    Cost ₹0 (free Groq tier, free APIs, my own laptop)

    Daily cost is zero because it runs on hardware I already own. On a VPS, it fits next to n8n on a ₹400–700/month server (cost breakdown).


    Build your own


    The same shape works for any "watch the internet for X" job: job posts, tenders, mentions of your product, competitor launches.


  • [ ] Install Hermes Agent and connect Telegram
  • [ ] Write one script: collect → filter → SQLite → (optional) LLM → print
  • [ ] Print nothing when there's nothing to say
  • [ ] Put the LLM's instructions in a markdown file, not in code
  • [ ] hermes cron create ... --no-agent --script your_script.py --deliver telegram
  • [ ] Add a plugin with slash commands for the actions you take from your phone
  • [ ] Keep a human approval step before anything is sent to a stranger

  • Want a scheduled agent like this for your own leads, alerts or reports? Get in touch.

    Built something similar or want to talk through the architecture? Get in touch.