NousResearch/hermes-agent

Kanban board env variable not inherited by subprocesses

Cluster 20074 · environments. Data as of

1 open item. Fix merged in #20186 on 5 May 2026. Check it covers your case.

The short answer

0open issues
1open PR
5items grouped
Known?
Yes. 5 related items grouped here, 1 issue already closed.
Fix event
A fix was merged to main in PR #20186. Check it covers your case. No release data is tracked.
Tracker
The maintainers' tracker marks this resolved, deciding PR #20186. That is separate from the fix event.
Still open
0 issues and 1 PR.

A bug where HERMES_KANBAN_BOARD is not correctly pinned or propagated to subprocess environments, causing board mis-routing during agent/chat sessions. Multiple fix attempts address environment variable inheritance at CLI and terminal levels.

Open issues0

No open issues.

Open PRs1

  • PR#142272fix(skills): kanban env gate misreads chat-boot BOARD pin as worker identity

Fixes on record

Merged to main. A stamp counts the issues a fix is linked to.

  • #20186 fix(cli): pin HERMES_KANBAN_BOARD at chat boot to stop subprocess board drift (salvages #20094)

    merged to main

    files: hermes_cli/main.py, tests/hermes_cli/test_pin_kanban_board_env.py

    Show the diff
    • hermes_cli/main.py
      @@ -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),
    • tests/hermes_cli/test_pin_kanban_board_env.py
      @@ -0,0 +1,75 @@
      +"""Tests for `_pin_kanban_board_env` helper invoked by `cmd_chat`.
      +
      +Regression coverage for #20074: a chat session must export the active kanban
      +board into `HERMES_KANBAN_BOARD` at boot so subprocess shell-outs (e.g.
      +`hermes kanban …`) inherit the same board the in-process kanban tools resolve.
      +Without this, a concurrent `hermes kanban boards switch` from another session
      +can flip the global current-board file mid-turn and silently divert the
      +shell calls to a different DB.
      +"""
      +import importlib
      +import os
      +
      +import pytest
      +
      +
      [redacted:email](autouse=True)
      +def _isolate_kanban_board_env():
      +    """Snapshot `HERMES_KANBAN_BOARD` and restore it after the test.
      +
      +    `_pin_kanban_board_env()` writes to ``os.environ`` directly, bypassing
      +    any ``monkeypatch.setenv`` tracking. Without this fixture the mutation
      +    leaks into subsequent tests and breaks anything that resolves a kanban
      +    path from the env (e.g. ``TestSharedBoardPaths`` in test_kanban_db.py).
      +    """
      +    prev = os.environ.get("HERMES_KANBAN_BOARD")
      +    os.environ.pop("HERMES_KANBAN_BOARD", None)
      +    try:
      +        yield
      +    finally:
      +        if prev is None:
      +            os.environ.pop("HERMES_KANBAN_BOARD", None)
      +        else:
      +            os.environ["HERMES_KANBAN_BOARD"] = prev
      +
      +
      +def test_pin_writes_resolved_board_when_env_unset(monkeypatch):
      +    main_mod = importlib.import_module("hermes_cli.main")
      +
      +    import hermes_cli.kanban_db as kdb
      +    monkeypatch.setattr(kdb, "get_current_board", lambda: "space")
      +
      +    main_mod._pin_kanban_board_env()
      +
      +    assert main_mod.os.environ.get("HERMES_KANBAN_BOARD") == "space"
      +
      +
      +def test_pin_does_not_overwrite_existing_env(monkeypatch):
      +    monkeypatch.setenv("HERMES_KANBAN_BOARD", "preset")
      +    main_mod = importlib.import_module("hermes_cli.main")
      +
      +    import hermes_cli.kanban_db as kdb
      +
      +    def _explode():
      +        raise AssertionError("get_current_board must not be called when env is set")
      +
      +    monkeypatch.setattr(kdb, "get_current_board", _explode)
      +
      +    main_mod._pin_kanban_board_env()
      +
      +    assert main_mod.os.environ.get("HERMES_KANBAN_BOARD") == "preset"
      +
      +
      +def test_pin_swallows_resolution_failures(monkeypatch):
      +    main_mod = importlib.import_module("hermes_cli.main")
      +
      +    import hermes_cli.kanban_db as kdb
      +
      +    def _boom():
      +        raise RuntimeError("disk gone")
      +
      +    monkeypatch.setattr(kdb, "get_current_board", _boom)
      +
      +    main_mod._pin_kanban_board_env()
      +
      +    assert "HERMES_KANBAN_BOARD" not in main_mod.os.environ

2 PRs closed without merging

From the close comments: done elsewhere 1 · merged via another change 1

  • #20094 fix(cli): pin HERMES_KANBAN_BOARD at chat boot to stop subprocess board drift · merged via another change → #20186
  • #36742 fix(terminal): propagate HERMES_KANBAN_BOARD to subprocess env to prevent board mis-routing · done elsewhere → b22b3f5
Closed issues · 1
  • Closed#20074[Bug]: harness kanban CLI invoked from agent session ignores active-board pin, races current file with concurrent boards switch
How this cluster was grouped
  • Link evidence (structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
  • Pairwise link density 0.40: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. 1.00 means every pair is linked.

Pick up a Lab task

Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.

Open the Lab

At a glance

Subsystem
environments
Merged PRs
#20186
Closed issues
1
Attempts
2 PRs closed without merging
Fix link checked
5 May 2026

For your agent

The same facts, typed.