Bug Description
hermes_cli/kanban_db.py resolves kanban_db_path() and workspaces_root() through get_hermes_home(), which returns the active profile's HERMES_HOME. When the dispatcher spawns a worker with hermes -p <profile> --skills kanban-worker chat -q "work kanban task <id>", the worker's _apply_profile_override() rewrites HERMES_HOME to ~/.hermes/profiles/<profile> before kanban_db.py is imported, so the worker reads/writes a profile-local kanban.db instead of the shared board the dispatcher claimed against.
This contradicts the public docs (website/docs/user-guide/features/kanban.md: "Hermes Kanban is a durable task board, shared across all your Hermes profiles ... Every task is a row in ~/.hermes/kanban.db") and the kanban_db.py module docstring itself, which says "$HERMES_HOME/kanban.db (profile-agnostic on purpose:".
Steps to Reproduce
- On a host with at least one non-default profile (e.g.
nehemiahkanban).
- Run the gateway with no profile so the dispatcher uses
~/.hermes/kanban.db.
hermes kanban create "smoke" --assignee nehemiahkanban — task lands in ~/.hermes/kanban.db.
- Dispatcher claims the task and spawns
hermes -p nehemiahkanban --skills kanban-worker chat -q "work kanban task <id>".
- Worker process resolves
kanban_db_path() to ~/.hermes/profiles/nehemiahkanban/kanban.db (a different file).
- Worker's
kanban_show <id> returns "task not found"; kanban_complete cannot find the task either; the dispatcher's row stays running and is retried/crashed.
Expected Behavior
Per the kanban docs, the board is shared across all profiles. A worker spawned with hermes -p <profile> must read and write the same kanban.db as the dispatcher that claimed the task. The same applies to workspaces_root() and the per-task log directory (<root>/kanban/logs/<task_id>.log) so kanban tooling and the dispatcher converge on a single set of paths.
Profile-specific config, .env, memory, and session state should remain isolated per profile (no change there).
Actual Behavior
Profile workers operate against a profile-local kanban.db that the dispatcher never wrote to:
- Dispatcher (no profile):
kanban_db_path() == ~/.hermes/kanban.db
- Worker (
-p nehemiahkanban): kanban_db_path() == ~/.hermes/profiles/nehemiahkanban/kanban.db
Reproduced on a Linux VPS with task t_0d214f19. After symlinking ~/.hermes/profiles/nehemiahkanban/kanban.db -> ~/.hermes/kanban.db, a follow-up smoke-test task t_93ef097d ran end-to-end and kanban_complete succeeded. The symlink is the user-side workaround.
Affected Component
CLI (interactive chat), Tools (terminal, file ops, web, code execution, etc.), Agent Core (conversation loop, context compression, memory)
Operating System
Linux (Ubuntu) VPS
Root Cause Analysis
hermes_cli/kanban_db.py:
def kanban_db_path() -> Path:
"""Return the path to ``kanban.db`` inside the active HERMES_HOME."""
from hermes_constants import get_hermes_home
return get_hermes_home() / "kanban.db"
def workspaces_root() -> Path:
"""Return the directory under which ``scratch`` workspaces are created."""
from hermes_constants import get_hermes_home
return get_hermes_home() / "kanban" / "workspaces"
get_hermes_home() returns the active profile's home. The kanban surface is a coordination primitive shared across profiles, so it has to anchor at the parent of <root>/profiles/<name> instead. This is the same architectural pattern as _get_profiles_root() in profile management code, which is intentionally HOME-anchored (see AGENTS.md § "Profiles: Multi-Instance Support" rule 6).
The _default_spawn log directory (get_hermes_home() / "kanban" / "logs") and the kanban log helper (<task_id>.log) have the same defect.
Proposed Fix
Resolve the kanban root through get_default_hermes_root() from hermes_constants.py, which already correctly returns <root> when HERMES_HOME is <root>/profiles/<name> (and falls through to HERMES_HOME for Docker / custom deployments). Add an explicit HERMES_KANBAN_HOME env-var override for tests and unusual deployments. Touch up the misleading docstrings in kanban_db.py and add a one-paragraph clarification to the kanban docs.
A regression test that mocks Path.home() and sets HERMES_HOME to a profile path (per the profile_env fixture in tests/hermes_cli/test_profiles.py) catches this on green.
I'd like to fix this myself and submit a PR.
Bug Description
hermes_cli/kanban_db.pyresolveskanban_db_path()andworkspaces_root()throughget_hermes_home(), which returns the active profile'sHERMES_HOME. When the dispatcher spawns a worker withhermes -p <profile> --skills kanban-worker chat -q "work kanban task <id>", the worker's_apply_profile_override()rewritesHERMES_HOMEto~/.hermes/profiles/<profile>before kanban_db.py is imported, so the worker reads/writes a profile-localkanban.dbinstead of the shared board the dispatcher claimed against.This contradicts the public docs (
website/docs/user-guide/features/kanban.md: "Hermes Kanban is a durable task board, shared across all your Hermes profiles ... Every task is a row in~/.hermes/kanban.db") and the kanban_db.py module docstring itself, which says "$HERMES_HOME/kanban.db (profile-agnostic on purpose:".Steps to Reproduce
nehemiahkanban).~/.hermes/kanban.db.hermes kanban create "smoke" --assignee nehemiahkanban— task lands in~/.hermes/kanban.db.hermes -p nehemiahkanban --skills kanban-worker chat -q "work kanban task <id>".kanban_db_path()to~/.hermes/profiles/nehemiahkanban/kanban.db(a different file).kanban_show <id>returns "task not found";kanban_completecannot find the task either; the dispatcher's row staysrunningand is retried/crashed.Expected Behavior
Per the kanban docs, the board is shared across all profiles. A worker spawned with
hermes -p <profile>must read and write the samekanban.dbas the dispatcher that claimed the task. The same applies toworkspaces_root()and the per-task log directory (<root>/kanban/logs/<task_id>.log) so kanban tooling and the dispatcher converge on a single set of paths.Profile-specific config,
.env, memory, and session state should remain isolated per profile (no change there).Actual Behavior
Profile workers operate against a profile-local
kanban.dbthat the dispatcher never wrote to:kanban_db_path() == ~/.hermes/kanban.db-p nehemiahkanban):kanban_db_path() == ~/.hermes/profiles/nehemiahkanban/kanban.dbReproduced on a Linux VPS with task
t_0d214f19. After symlinking~/.hermes/profiles/nehemiahkanban/kanban.db -> ~/.hermes/kanban.db, a follow-up smoke-test taskt_93ef097dran end-to-end andkanban_completesucceeded. The symlink is the user-side workaround.Affected Component
CLI (interactive chat), Tools (terminal, file ops, web, code execution, etc.), Agent Core (conversation loop, context compression, memory)
Operating System
Linux (Ubuntu) VPS
Root Cause Analysis
hermes_cli/kanban_db.py:get_hermes_home()returns the active profile's home. The kanban surface is a coordination primitive shared across profiles, so it has to anchor at the parent of<root>/profiles/<name>instead. This is the same architectural pattern as_get_profiles_root()in profile management code, which is intentionally HOME-anchored (seeAGENTS.md§ "Profiles: Multi-Instance Support" rule 6).The
_default_spawnlog directory (get_hermes_home() / "kanban" / "logs") and the kanban log helper (<task_id>.log) have the same defect.Proposed Fix
Resolve the kanban root through
get_default_hermes_root()fromhermes_constants.py, which already correctly returns<root>whenHERMES_HOMEis<root>/profiles/<name>(and falls through toHERMES_HOMEfor Docker / custom deployments). Add an explicitHERMES_KANBAN_HOMEenv-var override for tests and unusual deployments. Touch up the misleading docstrings inkanban_db.pyand add a one-paragraph clarification to the kanban docs.A regression test that mocks
Path.home()and setsHERMES_HOMEto a profile path (per theprofile_envfixture intests/hermes_cli/test_profiles.py) catches this on green.I'd like to fix this myself and submit a PR.