Skip to content

feat(cron): per-job max_turns override (CLI-only, mirrors reasoning_effort) - #99145

Open
dkswhale wants to merge 1 commit into
NousResearch:mainfrom
dkswhale:fix/cron-per-job-max-turns-upstream
Open

dkswhale wants to merge 1 commit into
NousResearch:mainfrom
dkswhale:fix/cron-per-job-max-turns-upstream

Conversation

@dkswhale

Copy link
Copy Markdown

Summary

Let a cron job carry its own agent turn budget: hermes cron create/edit --max-turns N.

Long multi-phase jobs (browse → plan → generate → QA) legitimately need more turns than the shared agent.max_turns default. Today the only lever is the global value, which spends the same budget on every other job and on every interactive session. This mirrors the existing per-job reasoning_effort override end to end.

Changes

  • cron/jobs.py_normalize_job_max_turns validates at the store choke point: positive int stored; 0/empty clears; anything else raises before the merge so nothing invalid persists. create_job(max_turns=) persists the key only when set, so pre-feature records stay byte-identical.
  • cron/scheduler.py_resolve_job_turn_limit(job, config_limit): the job's value wins over the config-resolved limit and is logged (Job 'x': per-job max_turns override -> N) so an operator can verify it applied from the run log. A garbage value in a hand-edited store warns and follows config instead of killing the tick.
  • CLI--max-turns on cron create and cron edit (0 clears on edit); Max turns: shown in the create/edit summaries.
  • tools/cronjob_tools.py — plumbed through cronjob() for the CLI, but deliberately absent from CRONJOB_SCHEMA: same CLI-only lane as reasoning_effort — a turn budget is a spend decision, so the model never sets it.
  • tests/cron/test_cron_job_max_turns.py — store contract + scheduler precedence (21 cases).

Motivation (real incident)

A three-phase daily content pipeline ran under max_turns: 160/110/200 set directly in jobs.json (a local patch). After an update dropped the patch, every phase silently ran at the global 60 and the planner phase stopped mid-write two days in a row with reached the iteration limit. Raising the global to 200 works but is the wrong tool — it changes every job and every chat session.

Test plan

  • pytest tests/cron/test_cron_job_max_turns.py tests/cron/test_scheduler.py tests/cron/test_jobs.py tests/cron/test_cron_reasoning_effort.py tests/tools/test_cronjob_tools.py → all pass (375).
  • hermes cron create --help shows --max-turns.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HQ7VR1qRcF6jQjQ7h6jsd1

…_effort)

A cron job may now carry its own agent turn budget. Long multi-phase jobs
(browse → plan → generate → QA) legitimately need more turns than the shared
`agent.max_turns` default, and raising the global value to suit them spends
the same budget on every other job — and on every interactive session.

- cron/jobs.py: `_normalize_job_max_turns` validates at the store choke
  point (positive int stored; 0/empty clears; garbage raises before the
  merge so nothing invalid persists). `create_job(max_turns=)` persists the
  key only when set, so pre-feature records stay byte-identical.
- cron/scheduler.py: `_resolve_job_turn_limit` — the job's value wins over
  the config-resolved limit and is logged (`per-job max_turns override ->
  N`) so an operator can verify it applied; a garbage value in a hand-edited
  store warns and follows config instead of killing the tick.
- CLI: `hermes cron create/edit --max-turns N` (0 clears on edit). Same
  CLI-only lane as `--reasoning-effort`: a turn budget is a spend decision,
  so it is deliberately absent from CRONJOB_SCHEMA and the model never sets it.
- tests/cron/test_cron_job_max_turns.py: store contract + scheduler
  precedence (21 cases).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HQ7VR1qRcF6jQjQ7h6jsd1
@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/billing Account usage, credit usage, billing (cross-cutting) sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 31, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Related: #45809 and #57285 also implement per-job cron turn budgets. This PR deliberately keeps the setting CLI-only and omits the wall-clock timeout path, so it is a narrower competing design rather than a duplicate.

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) 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