From ae1cd746cb0174396eb446c656b33df4f96566bc Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Fri, 17 Jul 2026 15:35:57 -0700 Subject: [PATCH] docs(kanban): explain why an unblocked task can later land in triage The reported confusion was an unblocked task 'unpredictably' ending up in triage. unblock itself only ever routes to ready/todo; a subsequent same-cause re-block hitting BLOCK_RECURRENCE_LIMIT is what escalates to triage. Document this deterministic loop-breaker at the human-facing lifecycle level so users stop reading it as an LLM decision. --- website/docs/user-guide/features/kanban.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/docs/user-guide/features/kanban.md b/website/docs/user-guide/features/kanban.md index ae5bbde1fb8a..2b68409249c0 100644 --- a/website/docs/user-guide/features/kanban.md +++ b/website/docs/user-guide/features/kanban.md @@ -265,6 +265,25 @@ hermes kanban unblock t_abc t_def hermes kanban block t_abc "need input" --ids t_def t_hij ``` +:::note Where an unblocked task lands +`unblock` itself only ever moves a task to **`ready`** (all parents `done`) or +**`todo`** (a parent is still open — the task is dependency-gated and the +dispatcher auto-promotes it once the parent finishes). It never routes to +`triage`. + +If you unblock a task and it later shows up in **`triage`**, the unblock is not +what put it there. A subsequent *re-block for the same reason* did: after a task +is blocked → unblocked → re-blocked for the same cause `BLOCK_RECURRENCE_LIMIT` +times (default `2`), the unblock-loop breaker stops sending it back to `blocked` +— where a cron would just keep unblocking it — and routes it to `triage` for a +human decision. This is a deterministic DB guard, not an LLM judgment call, and +a task's body text cannot opt out of it: the recurrence counter deliberately +survives each unblock (it resets only on a successful `complete`). To keep an +unblocked task in the work pool, resolve *why it keeps re-blocking* (unfinished +parent, missing input, unmet capability) before unblocking, or raise +`BLOCK_RECURRENCE_LIMIT` if the loop is expected. +::: + ## How workers interact with the board **Workers do not shell out to `hermes kanban`.** When the dispatcher spawns a worker it sets `HERMES_KANBAN_TASK=t_abcd` in the child's env, and that env var flips on a dedicated **kanban toolset** in the model's schema. The same toolset is also available to orchestrator profiles that enable `kanban` in their toolsets config. These tools read and mutate the board directly via the Python `kanban_db` layer, same as the CLI does. A running worker calls these like any other tool; it never sees or needs the `hermes kanban` CLI.