feat(kanban): default heavy lanes to goal-mode + worker_max_iterations knob - #58
Conversation
…s knob Patch note: ~/.hermes/plans/hermes-patches/kanban-goal-mode-lane-defaults.md Heavy checkable lanes (dev, pr-babysitter, cpe-dev, cpe-research) now default to goal-mode at dispatch so an oversized task auto-continues across judge cycles instead of blocking when one run hits the 90 per-run iteration cap. The judge verdict is the stop condition; the turn budget is the safety ceiling. - kanban_db._resolve_lane_goal_defaults: effective goal_mode/goal_max_turns from task row OR kanban.goal_mode_lanes config (explicit per-task --goal wins). DEFAULT_GOAL_MODE_LANES + DEFAULT_GOAL_MODE_MAX_TURNS=5 built-in defaults. - kanban_db._resolve_worker_max_iterations + _default_spawn: kanban.worker_max_iterations injects HERMES_MAX_ITERATIONS for NON-goal workers only. Goal-mode workers keep the 90 cap (inherited HERMES_MAX_ITERATIONS is dropped); non-goal workers get a deterministic cap from config (inherited value dropped when the knob is unset). - cli.py: in the kanban-worker context (HERMES_KANBAN_TASK set) the injected HERMES_MAX_ITERATIONS now wins over the profile's agent.max_turns default (90), so the knob isn't silently dead. Normal CLI/gateway precedence unchanged. - Judge already reads task title+body (the "Done =" line) as the goal contract; no change, verified. - Docs: website kanban.md goal-mode lanes + worker_max_iterations sections. Tests: tests/hermes_cli/test_kanban_goal_mode.py (lane defaults, precedence, worker_max_iterations injection + goal-mode suppression + inherited-env drop), tests/cli/test_cli_init.py (kanban override beats config default; non-kanban unchanged; CLI arg wins). 76 passed.
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-assignment |
1 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`
✅ Fixed issues (2):
| Rule | Count |
|---|---|
unresolved-attribute |
2 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
run_agent.py:3026: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`
Unchanged: 6086 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
There was a problem hiding this comment.
Code Review
This pull request introduces lane-specific goal-mode defaults and worker iteration cap overrides for Kanban tasks, including environment resolution logic, updated tests, and user documentation. The feedback suggests improving robustness by ensuring that the overridden iteration count in cli.py is validated as a strictly positive integer, and using the existing _positive_int helper in kanban_db.py to safely parse and validate task.goal_max_turns.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Address Gemini review on PR #58: - cli.py: only honor HERMES_MAX_ITERATIONS override when >0, else fall through to config/profile default (0/negative would kill the loop). - kanban_db._resolve_lane_goal_defaults: parse explicit task.goal_max_turns via _positive_int(minimum=1) so a bad --goal-max-turns falls back to the default instead of a nonsensical 0-turn loop. - test: non-positive explicit goal_max_turns falls back to default.
What
Heavy checkable kanban lanes (dev, pr-babysitter, cpe-dev, cpe-research) now default to goal-mode at dispatch, so an oversized task auto-continues across judge cycles instead of blocking when one run hits the 90 per-run iteration cap. The judge verdict is the real stop condition; the turn budget is the safety ceiling. (Eric-approved decision: goal-mode for heavy lanes, NOT a global per-run cap bump.)
Plus a fallback lever —
kanban.worker_max_iterations— for non-goal lanes that genuinely fit in ~130-150 turns but should not loop.Changes
hermes_cli/kanban_db.py_resolve_lane_goal_defaults(task, cfg)-> effective(goal_mode, goal_max_turns). Source:task.goal_modeORkanban.goal_mode_lanes(built-in default[dev, pr-babysitter, cpe-dev, cpe-research]). Explicit per-task--goal/--goal-max-turnsalways win. Budget: task value >kanban.goal_mode_default_max_turns>DEFAULT_GOAL_MODE_MAX_TURNS(5)._resolve_worker_max_iterations(goal_mode, cfg)->kanban.worker_max_iterations, non-goal only._default_spawn: applies both at the dispatch chokepoint (covers tool/CLI/dashboard/webhook/auto-decompose + pre-existing rows). Goal-mode workers keep the 90 cap and drop any inheritedHERMES_MAX_ITERATIONSfrom the dispatcher env; non-goal workers get a deterministic cap from config.cli.py: in the kanban-worker context (HERMES_KANBAN_TASKset), the injectedHERMES_MAX_ITERATIONSnow wins over the profile'sagent.max_turnsdefault (90) — otherwise the knob is silently dead (the default is always present and wins first). Normal CLI/gateway precedence is unchanged.cli.py::_run_kanban_goal_loop_qfeedstask.title + body(the "Done =" line) to the judge. No code change; covered by tests.website/docs/user-guide/features/kanban.md— goal-mode lanes +worker_max_iterations.Verification (runtime, not just code)
HermesCLIinit against a real config withagent.max_turns=90:max_turns=90(config wins, unchanged)HERMES_KANBAN_TASKset,HERMES_MAX_ITERATIONS=150) ->max_turns=150_default_spawnenv (Popen stubbed, real config.yaml with the knob, real task rows, dispatcher env carryingHERMES_MAX_ITERATIONS=200):dev(checkable lane):GOAL_MODE=1, GOAL_MAX_TURNS=5, HERMES_MAX_ITERATIONS=<dropped>keeps 90 capdesigner(non-goal):GOAL_MODE=unset, HERMES_MAX_ITERATIONS=150from knobHERMES_MAX_ITERATIONS; now dropped.tests/hermes_cli/test_kanban_goal_mode.py+tests/cli/test_cli_init.py+tests/hermes_cli/test_kanban_worker_spawn_toolsets.py-> 76 passed. Goal-loop continuation/budget/finalize/block behavior covered by the existing callback-injected loop tests.Notes / scope
goals.run_kanban_goal_loop) runs in the same worker session (re-prompt after each judge verdict), not as separate dispatcher processes — the task body described a fresh-process-per-run shape that differs from the as-implemented loop, but the user-visible outcome (auto-continue past one judge cycle, block on budget exhaustion) is the same.DEFAULT_GOAL_MODE_LANES; config keys are for override/disable. No DB migration.Patch note:
~/.hermes/plans/hermes-patches/kanban-goal-mode-lane-defaults.md