Skip to content

feat(cron): user-owned model pins + cron.model fleet default - #73532

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-a0ab6ed2
Jul 28, 2026
Merged

feat(cron): user-owned model pins + cron.model fleet default#73532
teknium1 merged 1 commit into
mainfrom
hermes/hermes-a0ab6ed2

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Cron per-job model pins are now user-owned, and a new cron.model config key gives the cron fleet its own default model — switching your chat model with /model or hermes model never touches unattended cron spend again.

Root cause of the pain (#59031, fastfinge's "hundreds of jobs break on every model switch"): unpinned jobs followed the global chat model, so the #44585 fail-closed drift guard tripped fleet-wide on every deliberate switch, with no way to route cron independently.

Changes

  • tools/cronjob_tools.py — the agent-facing cronjob tool schema no longer exposes model/provider/base_url, and the registered handler ignores them even if a model hallucinates the old parameters. Per-job inference pins are user-owned: dashboard, hermes cron create/edit --model/--provider, or jobs.json. Existing pins are grandfathered untouched; the programmatic cronjob() function keeps its parameters for the dashboard/CLI callers. Removes the now-dead _resolve_model_override.
  • hermes_cli/config.py — new cron.model / cron.model_provider keys (cron-fleet inference default, distinct from the cron.provider scheduler axis). The switch-time drift warning (Warn before model config changes trip cron drift guard #59177) stays quiet for an axis covered by the fleet default.
  • cron/scheduler.py — fire-time resolution: per-job pin → cron.modelHERMES_MODELmodel.default; provider: per-job pin → cron.model_provider → global resolution. Drift guard skips any axis covered by the explicit fleet default — deliberate routing is not drift. Uncovered axes still fail closed.
  • cron/jobs.py — snapshot resolution mirrors the new precedence so create-time snapshots stay consistent.
  • hermes_cli/subcommands/cron.py + hermes_cli/cron.py--model / --provider on hermes cron create and hermes cron edit (empty string clears a pin on edit).
  • website/docs/user-guide/features/cron.md — model-resolution tip rewritten around the three-tier order.

Validation

Check Result
tests/cron/ + cronjob tool + config tests (targeted, CI-parity runner) 962 passed, 0 failed
E2E (temp HERMES_HOME, real registry dispatch + jobs store) agent-supplied model args ignored; user pins stick through agent updates; cron.model snapshot honored
ruff on all touched files clean

Infographic

Cron model ownership

Per-job cron inference pins are now user-owned: the agent-facing cronjob
tool schema no longer exposes model/provider/base_url, and the registered
handler ignores them even if a model hallucinates the old parameters.
Users set pins via the dashboard, hermes cron create/edit --model/--provider,
or jobs.json directly — and once set, a pin sticks until the user changes it.
Existing agent-era pins are grandfathered untouched.

New cron.model / cron.model_provider config keys give the cron fleet its
own default model, independent of the chat model. Fire-time resolution:
per-job pin > cron.model > HERMES_MODEL > model.default. An axis covered
by the explicit cron-fleet default is deliberate routing, not drift, so
the #44585 fail-closed guard skips it — switching your chat model with
/model or hermes model no longer breaks unpinned cron fleets.

- tools/cronjob_tools.py: drop model param from agent schema + handler;
  remove now-dead _resolve_model_override
- cron/scheduler.py: cron.model/model_provider resolution + per-axis
  drift-guard skip
- cron/jobs.py: snapshot resolution mirrors the new precedence
- hermes_cli/subcommands/cron.py + hermes_cli/cron.py: --model/--provider
  on hermes cron create/edit
- hermes_cli/config.py: cron.model / cron.model_provider defaults
- docs: cron.md model-resolution tip rewritten
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 0fa395a

ℹ️ Info

Desktop E2E visual evidence · View test artifacts · View job

1 visual diff.

inline evidence upload failed.

Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso)

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cron Cron scheduler and job management comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles area/billing Account usage, credit usage, billing (cross-cutting) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 28, 2026
@teknium1
teknium1 merged commit d464ae3 into main Jul 28, 2026
76 of 79 checks passed
@teknium1
teknium1 deleted the hermes/hermes-a0ab6ed2 branch July 28, 2026 18:52
jackulau added a commit to jackulau/hermes-agent that referenced this pull request Aug 19, 2026
The NousResearch#44585 drift guard fails an unpinned cron job closed when the global
provider/model moves under it, and every message it emits offers exactly one
remedy: pin this job. That is correct for one job and wrong for a fleet.
NousResearch#59031 was 34 jobs breaking on a single global switch, i.e. 34 per-job edits
for one config change, and NousResearch#89242 is the same complaint arriving again with a
proposed fix that would disarm the guard entirely.

The fleet-wide remedy already exists. NousResearch#73532 added `cron.model` /
`cron.model_provider`, and `_cron_fleet_default_covers_axis` makes the guard
skip any axis they cover, so one command decouples the whole unpinned fleet
from the chat model without giving up spend protection on the axes it does not
cover. The cron guide has documented this since NousResearch#73532; none of the runtime
messages did, so the only operators who find it are the ones who read docs
after being told to make N edits.

Teach all three surfaces to name it alongside the pin:

- the scheduler's skip log and alert blob, on both the recurring and the
  NousResearch#72056 finite-one-shot path, naming `cron.model_provider` for the provider
  axis rather than interpolating the axis name into a key that does not exist
- the chat delivery line, which is the surface an operator reads unprompted
  rather than after something sent them to a log; kept to one terse sentence
  so the notification stays one line
- the `hermes config set model.default` warning, which fires before any job
  has failed and is therefore the cheapest place to have omitted it

No behaviour change: the guard engages in exactly the cases it engaged in
before, and the per-job and one-shot remedies are unchanged. The warning is
still suppressed for an axis the fleet default already covers, so an operator
who has taken the advice is never given it.

Tests parse the config key back out of each emitted message and feed it to
`_cron_fleet_default_covers_axis`, so the advice cannot go stale against the
mechanism the way it just did.

Fixes NousResearch#89242
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/billing Account usage, credit usage, billing (cross-cutting) area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants