hermes - 💡(How to fix) Fix Cron jobs created from a profile-scoped agent session go to a jobs.json the gateway never reads (silent orphan)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When cronjob action=create is invoked from inside an agent session running under a non-default Hermes profile (e.g. hermes -p corpusiq-agent chat), the job is written to the profile-local cron/jobs.json (~/.hermes/profiles/<profile>/cron/jobs.json).

However, the gateway scheduler — when started without a profile (hermes gateway run) — reads only the root ~/.hermes/cron/jobs.json. Result: jobs created via the in-session cronjob tool are silently orphaned. They have a next_run_at, look healthy in cronjob action=list from the same profile, but never fire.

This is a quiet failure mode. The agent reports success on create, the user assumes scheduling works, and the job dies on the floor.

Error Message

  1. Explicit error on mismatch. If the gateway is running under HERMES_HOME=A and the cronjob tool is writing under HERMES_HOME=B, surface a warning at create time: "Job created in B but gateway is ticking A — this job will not fire."

Root Cause

cronjob action=list from inside the agent session reports the orphan as scheduled (because it reads the same profile-local file), making this even harder to spot. The user sees "scheduled" and "next run at T" and trusts it.

Fix Action

Fix / Workaround

Workaround used

Code Example

# Terminal 1 — gateway running as root profile (default Hermes home)
hermes gateway run --replace

# Terminal 2 — agent under a named profile
hermes -p myprofile chat
> /cronjob create ... (or have the agent call the cronjob tool)
RAW_BUFFERClick to expand / collapse

Summary

When cronjob action=create is invoked from inside an agent session running under a non-default Hermes profile (e.g. hermes -p corpusiq-agent chat), the job is written to the profile-local cron/jobs.json (~/.hermes/profiles/<profile>/cron/jobs.json).

However, the gateway scheduler — when started without a profile (hermes gateway run) — reads only the root ~/.hermes/cron/jobs.json. Result: jobs created via the in-session cronjob tool are silently orphaned. They have a next_run_at, look healthy in cronjob action=list from the same profile, but never fire.

This is a quiet failure mode. The agent reports success on create, the user assumes scheduling works, and the job dies on the floor.

Reproduction

# Terminal 1 — gateway running as root profile (default Hermes home)
hermes gateway run --replace

# Terminal 2 — agent under a named profile
hermes -p myprofile chat
> /cronjob create ... (or have the agent call the cronjob tool)

The job is created in ~/.hermes/profiles/myprofile/cron/jobs.json. The gateway only ticks jobs in ~/.hermes/cron/jobs.json. last_run_at stays null forever.

cronjob action=list from inside the agent session reports the orphan as scheduled (because it reads the same profile-local file), making this even harder to spot. The user sees "scheduled" and "next run at T" and trusts it.

Observed in the wild

Three jobs created over ~28h on corpusiq-agent profile (daily audit, support reply monitor, support inbox monitor). None fired. last_run_at: null on all three; profile-local store was the only place they existed. Manually relocated them to the root store with profile: corpusiq-agent set on each job — they fired correctly on next tick.

A separate job (dev@ inbox triage) that had been created earlier when the agent was started under a different env state ended up in the root store and ticked normally. The mismatch was non-obvious from the agent's perspective.

Expected behavior

One of:

  1. Single source of truth. The cronjob tool should always write to the same jobs.json the gateway reads, regardless of which profile the agent is running under. The profile field on the job is already the right mechanism to scope execution context — the storage location shouldn't also be profile-scoped.
  2. Scheduler reads union. The gateway should iterate ~/.hermes/cron/jobs.json plus every ~/.hermes/profiles/*/cron/jobs.json. More invasive, but preserves the current write semantics.
  3. Explicit error on mismatch. If the gateway is running under HERMES_HOME=A and the cronjob tool is writing under HERMES_HOME=B, surface a warning at create time: "Job created in B but gateway is ticking A — this job will not fire."

Option 1 is the cleanest from a principle-of-least-surprise angle.

Workaround used

Manually moved jobs from ~/.hermes/profiles/corpusiq-agent/cron/jobs.json into ~/.hermes/cron/jobs.json, preserving the profile: corpusiq-agent field so they still execute under the right environment. Scheduler picked them up on next tick.

Environment

  • Profile in use: corpusiq-agent
  • Gateway invocation: hermes gateway run --replace, launched without -p, so HERMES_HOME=~/.hermes
  • Agent invocation: hermes -p corpusiq-agent chat, so HERMES_HOME=~/.hermes/profiles/corpusiq-agent

Notes

cronjob action=list reads the same profile-scoped file as cronjob action=create, so the lookup is self-consistent from the agent's POV. The break only shows up at fire time, and there's no "job hasn't run despite being due" alarm anywhere. A health check that flags jobs with next_run_at < now - 10min and last_run_at: null would be a useful canary even without fixing the underlying routing.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

One of:

  1. Single source of truth. The cronjob tool should always write to the same jobs.json the gateway reads, regardless of which profile the agent is running under. The profile field on the job is already the right mechanism to scope execution context — the storage location shouldn't also be profile-scoped.
  2. Scheduler reads union. The gateway should iterate ~/.hermes/cron/jobs.json plus every ~/.hermes/profiles/*/cron/jobs.json. More invasive, but preserves the current write semantics.
  3. Explicit error on mismatch. If the gateway is running under HERMES_HOME=A and the cronjob tool is writing under HERMES_HOME=B, surface a warning at create time: "Job created in B but gateway is ticking A — this job will not fire."

Option 1 is the cleanest from a principle-of-least-surprise angle.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING