Skip to content

Kanban goal_mode workers never enter the goal loop — dispatcher spawns chat -q but the hook is only wired in the -Q/--quiet path #63396

Description

@MarkWin91

Summary

Cards created with --goal never exercise the Ralph-style goal loop. The dispatcher sets HERMES_KANBAN_GOAL_MODE=1 in the worker env, but the spawned worker command (hermes -p <profile> chat -q "work kanban task <id>") takes the single-query branch of main(), which never reads that env var. The goal hook is only wired in the fully-quiet -Q/--quiet machine-readable branch. Result: goal_mode is stored on the card and silently ignored; any apparent progress comes from the dispatcher's ordinary retry loop, and a worker that leaves the task open (expecting the judge to continue it) is reaped as protocol_violation.

Where the wires cross (0.16.0 line numbers; same structure in 0.18.2)

  • hermes_cli/kanban_db.py:6673-6676 (_default_spawn) — sets HERMES_KANBAN_GOAL_MODE=1 and spawns [hermes, -p, <profile>, --accept-hooks, chat, -q, <prompt>]. The comment says "the worker reads these and wraps its run in the Ralph-style /goal judge loop (see cli.py quiet-mode path)" — but the spawned form never reaches that path.
  • cli.py:16010-16014 — the only reader of HERMES_KANBAN_GOAL_MODE, calling _run_kanban_goal_loop_q(...). It lives in the -Q/--quiet machine-readable branch (the same block that owns the kanban EX_TEMPFAIL exit-code contract).
  • cli.py:16048-16070 — the else branch, explicitly documented "Single-query mode (hermes chat -q "…")": cli.chat(query) + _print_exit_summary(). No goal hook.

Evidence from a live board

Worker logs of a goal_mode card end with the _print_exit_summary() block ("Resume this session with… / Duration / Messages") and never contain the session_id: stderr line of the quiet branch — although _default_spawn merges stderr into the log (stderr=subprocess.STDOUT, kanban_db.py:6768). Three consecutive runs of one goal card each produced exactly one turn in a fresh session, no judge verdict, no continuation; goals.run_kanban_goal_loop itself works when invoked directly (unit-style, mocked cli).

Still present in 0.18.2 (latest)

  • spawn unchanged: kanban_db.py:7794-7796 still ["chat", "-q", prompt]
  • hook unchanged: cli.py:16113 (quiet branch) vs single-query branch 16152-16171

Suggested fix (either side works)

  1. Wire the HERMES_KANBAN_GOAL_MODE check into the single-query branch too (after cli.chat(...) returns the first response), or
  2. Spawn goal-mode workers through the -Q/--quiet path the hook already lives in.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/cronCron scheduler and job managementsweeper:implemented-on-mainSweeper: behavior already present on current maintype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions