feat(webhook): cron jobs can fire from app events, not just the clock (ChatGPT Work-inspired) - #95262
Open
teknium1 wants to merge 1 commit into
Open
feat(webhook): cron jobs can fire from app events, not just the clock (ChatGPT Work-inspired)#95262teknium1 wants to merge 1 commit into
teknium1 wants to merge 1 commit into
Conversation
ChatGPT Work's Aug 25 2026 release lets scheduled tasks fire from app events (new Gmail message, Slack activity, GitHub PR feedback) instead of polling on a cadence. This ports the pattern by composing two existing Hermes subsystems: a webhook route can now set cron_job to fire an existing cron job on each inbound event. - gateway/platforms/webhook.py: cron_job route mode — after the same HMAC auth / rate limit / filters / script / idempotency as agent routes, the rendered prompt becomes transient per-run context and the job fires through execute_job_for_event on a worker thread (202 Accepted immediately). Startup validation rejects cron_job + deliver_only. - tools/cronjob_tools.py: execute_job_for_event() — public wrapper over the shared claimed-run body (_execute_job_now), so event fires share at-most-once claiming, in-flight dedupe, delivery, and [SILENT] handling with scheduler and manual runs. - hermes webhook subscribe --cron-job: creates event-trigger subscriptions; job ref validated (and canonicalized to the job ID) at create time. - Docs: webhooks.md route table + Event-Triggered Cron Jobs section, cron.md capability list, zh-Hans mirrors. - Tests: tests/gateway/test_webhook_cron_trigger.py (adapter + unit), CLI tests in test_webhook_cli.py.
Contributor
૮ >ﻌ< ა ci reviewran on 1efa74e — Inspired by ChatGPT Work: event-triggered cron jobs via webh
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A webhook route can now fire an existing cron job the moment an external event arrives — turning any scheduled job into an event-triggered task instead of a polling loop.
Inspired by ChatGPT Work's August 25, 2026 release (OpenAI release notes, learn.chatgpt.com what's new): scheduled tasks there can now respond to app events (new Gmail message, Slack channel activity, GitHub PR feedback) via webhooks "without polling on a fixed cadence." Hermes already had both halves — the webhook adapter and the cron subsystem — this PR composes them with a single route key.
How ChatGPT Work does it vs. how this adapts it
ChatGPT Work binds a scheduled task to a first-party app event (Gmail/Slack/GitHub connectors) and pauses approval-requiring actions. Hermes is self-hosted, so the adaptation is provider-agnostic: anything that can POST (GitHub, GitLab, Stripe, Supabase, a monitoring stack, another agent) can fire a job, protected by the webhook adapter's existing HMAC auth, rate limiting,
events/filters/scriptfiltering, and idempotency. The job keeps its own prompt, skills, model pin, and delivery target; the rendered routepromptis injected as transient per-run context on the exact same rail ascronjob(action='run', prompt=...)— the stored job is never mutated, and the fire goes through the scheduler's at-most-once claim so a webhook burst can't double-fire a running job.Changes
gateway/platforms/webhook.py:cron_jobroute mode — fires the referenced job in the background (202 Accepted), after all existing route protections; connect-time validation rejectscron_job+deliver_only(mutually exclusive)tools/cronjob_tools.py:execute_job_for_event()— public wrapper over the shared claimed-run body (_execute_job_now), so event fires share claiming, in-flight dedupe, delivery, and[SILENT]handling with scheduler/manual runshermes_cli/webhook.py+hermes_cli/subcommands/webhook.py:hermes webhook subscribe --cron-job <id|name>with create-time job-ref validation (canonicalized to the job ID); list/subscribe output shows the trigger modewebhooks.mdroute table + new "Event-Triggered Cron Jobs" section,cron.mdcapability list; zh-Hans mirrors for bothtests/gateway/test_webhook_cron_trigger.py(6), CLI tests intest_webhook_cli.py(3)Validation
no_agentscript job created in a temp HERMES_HOME, real HTTP POST to the real adapterlast_status: okNot applied to any prior PR — dupe sweep found no open/closed PR covering webhook→cron triggering (nearest: #491 webhook-triggered sessions, which the existing agent-mode routes already cover; this adds the existing-job trigger half).
Infographic