fix(cli): pin HERMES_KANBAN_BOARD at chat boot to stop subprocess board drift

Without an explicit pin, in-process kanban tools and shelled-out
`hermes kanban …` subprocesses resolve the active board on different
paths: the env var when set, otherwise the global `<root>/kanban/current`
file. When a concurrent session toggles the current-board pointer
mid-turn, the same chat ends up routing tool calls to board A while its
shell calls hit board B, surfacing as phantom "no such task" errors.

Pin the resolved board into env once at `cmd_chat` boot when
HERMES_KANBAN_BOARD isn't already set. Mirrors what the dispatcher does
for spawned workers (kanban_db.py:2622-2623). Idempotent and a no-op
when the env is already pinned by the caller.

Closes #20074
This commit is contained in:
0xDevNinja 2026-05-05 12:23:43 +05:30 committed by Teknium
parent d472d697cd
commit b22b3f506a
2 changed files with 76 additions and 0 deletions

View file

@ -1216,6 +1216,26 @@ def _launch_tui(
sys.exit(code)
def _pin_kanban_board_env() -> None:
"""Pin the active kanban board into ``HERMES_KANBAN_BOARD`` for the chat session.
Without this, in-process tools (``kanban_*``) and shelled-out CLI calls
(``hermes kanban ``) resolve the board on different paths: the env-pin if
set, otherwise the global ``<root>/kanban/current`` file. A concurrent
``hermes kanban boards switch`` from another session can flip the file
mid-turn, so the same chat sees its tool calls hit board A while its shell
calls hit board B (#20074). Pinning at chat boot mirrors what the
dispatcher already does for spawned workers.
"""
if os.environ.get("HERMES_KANBAN_BOARD"):
return
try:
from hermes_cli.kanban_db import get_current_board
os.environ["HERMES_KANBAN_BOARD"] = get_current_board()
except Exception:
pass
def cmd_chat(args):
"""Run interactive chat CLI."""
use_tui = getattr(args, "tui", False) or os.environ.get("HERMES_TUI") == "1"
@ -1324,6 +1344,8 @@ def cmd_chat(args):
if getattr(args, "source", None):
os.environ["HERMES_SESSION_SOURCE"] = args.source
_pin_kanban_board_env()
if use_tui:
_launch_tui(
getattr(args, "resume", None),