Skip to content

feat(kanban): default heavy lanes to goal-mode + worker_max_iterations knob - #58

Merged
exiao merged 2 commits into
live-configfrom
feat/kanban-goal-mode-lane-defaults
Jun 29, 2026
Merged

feat(kanban): default heavy lanes to goal-mode + worker_max_iterations knob#58
exiao merged 2 commits into
live-configfrom
feat/kanban-goal-mode-lane-defaults

Conversation

@exiao

@exiao exiao commented Jun 28, 2026

Copy link
Copy Markdown
Owner

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_mode OR kanban.goal_mode_lanes (built-in default [dev, pr-babysitter, cpe-dev, cpe-research]). Explicit per-task --goal/--goal-max-turns always 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 inherited HERMES_MAX_ITERATIONS from the dispatcher env; non-goal workers get a deterministic cap from config.
  • 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) — otherwise the knob is silently dead (the default is always present and wins first). Normal CLI/gateway precedence is unchanged.
  • Judge done-criteria (task fix(signal): drop empty metadata events and surface reactions #4): already satisfied — cli.py::_run_kanban_goal_loop_q feeds task.title + body (the "Done =" line) to the judge. No code change; covered by tests.
  • Docs: website/docs/user-guide/features/kanban.md — goal-mode lanes + worker_max_iterations.

Verification (runtime, not just code)

  • Runtime probe — worker_max_iterations beats config default: real HermesCLI init against a real config with agent.max_turns=90:
    • non-kanban context -> max_turns=90 (config wins, unchanged)
    • kanban-worker context (HERMES_KANBAN_TASK set, HERMES_MAX_ITERATIONS=150) -> max_turns=150
  • Runtime probe — real _default_spawn env (Popen stubbed, real config.yaml with the knob, real task rows, dispatcher env carrying HERMES_MAX_ITERATIONS=200):
    • dev (checkable lane): GOAL_MODE=1, GOAL_MAX_TURNS=5, HERMES_MAX_ITERATIONS=<dropped> keeps 90 cap
    • designer (non-goal): GOAL_MODE=unset, HERMES_MAX_ITERATIONS=150 from knob
    • This probe caught a real bug — goal-mode workers were inheriting the dispatcher's ambient HERMES_MAX_ITERATIONS; now dropped.
  • Tests: 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

  • The kanban goal loop (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.
  • Behavior change activates on merge via the built-in 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

…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.
@github-actions

github-actions Bot commented Jun 28, 2026

Copy link
Copy Markdown

🔎 Lint report: feat/kanban-goal-mode-lane-defaults vs origin/live-config

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11577 on HEAD, 11579 on base (✅ -2)

🆕 New issues (1):

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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread cli.py
Comment thread hermes_cli/kanban_db.py Outdated
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.
@exiao
exiao merged commit 9f71183 into live-config Jun 29, 2026
36 checks passed
@exiao
exiao deleted the feat/kanban-goal-mode-lane-defaults branch June 29, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant