feat(kanban): orchestrator-driven auto-decomposition on triage#27572
Merged
Conversation
Closes the core gap in the kanban system: dropping a one-liner into Triage
now decomposes it into a graph of child tasks routed to specialist
profiles by description, matching teknium's original vision ("main
orchestrator splits/creates actual tasks, doles them out to each agent").
The build
---------
- hermes_cli/profiles.py: new `description` + `description_auto` fields
on ProfileInfo, persisted in <profile_dir>/profile.yaml. Helpers
read_profile_meta / write_profile_meta. `create_profile` accepts
optional description.
- hermes_cli/profile_describer.py: new module — auto-generate a 1-2
sentence description from a profile's skills + model + name via the
auxiliary LLM (`auxiliary.profile_describer`).
- hermes_cli/main.py: new `hermes profile create --description ...`
flag; new `hermes profile describe [name] [--text ... | --auto |
--all --auto]` subcommand.
- hermes_cli/kanban_db.py: new `decompose_triage_task` atomic helper —
creates N child tasks, links the root as a child of every leaf
(root waits for the whole graph), flips root `triage -> todo` with
orchestrator assignee, records an audit comment + `decomposed` event
in a single write_txn.
- hermes_cli/kanban_decompose.py: new module — calls the auxiliary LLM
(`auxiliary.kanban_decomposer`) with the profile roster + descriptions
to produce a JSON task graph, then invokes the DB helper. Rewrites
unknown assignees to the configured `kanban.default_assignee` (or
the active default profile) so a task NEVER lands with assignee=None.
Falls back to specify-style single-task promotion when the LLM
returns `fanout: false`.
- hermes_cli/kanban.py: new `hermes kanban decompose [task_id | --all]`
CLI verb.
- hermes_cli/config.py: new DEFAULT_CONFIG keys —
kanban.orchestrator_profile, kanban.default_assignee,
kanban.auto_decompose (default True), kanban.auto_decompose_per_tick
(default 3), auxiliary.kanban_decomposer, auxiliary.profile_describer.
- gateway/run.py: kanban dispatcher watcher now runs auto-decompose
before each `_tick_once`, capped by `auto_decompose_per_tick` so a
bulk-load of triage tasks doesn't burst-spend the aux LLM.
- plugins/kanban/dashboard/plugin_api.py: new endpoints —
GET /profiles (list roster + descriptions),
PATCH /profiles/<name> (set description, user-authored),
POST /profiles/<name>/describe-auto (LLM-generate),
POST /tasks/<id>/decompose (run decomposer),
GET/PUT /orchestration (orchestrator/default-assignee/auto-decompose
pickers, with resolved fallbacks echoed back).
- plugins/kanban/dashboard/dist/index.js: new OrchestrationPanel
collapsible — dropdowns for orchestrator profile and default
assignee, auto-decompose toggle, per-profile description editor with
Save and Auto-generate buttons. New ⚗ Decompose button next to
✨ Specify on triage-column task drawers.
Behavior
--------
- A task in Triage gets fanned out into a small DAG of child tasks.
Children with no internal parents flip to `ready` immediately
(parallel dispatch). Children with sibling parents wait. The root
stays alive as a parent of every child — when the whole graph
finishes, it promotes to `ready` and the orchestrator profile wakes
back up to judge completion (the "adds more tasks until done" part
of the original vision).
- `kanban.orchestrator_profile` unset -> falls back to the default
profile (whichever `hermes` launches with no -p flag).
- `kanban.default_assignee` unset -> same fallback. Tasks NEVER end
up unassigned.
- `kanban.auto_decompose=true` (default) runs the decomposer
automatically on dispatcher ticks; manual `hermes kanban decompose`
is always available.
Tests
-----
- tests/hermes_cli/test_kanban_decompose_db.py — 7 tests for the
atomic DB helper (status transitions, dep graph, audit trail,
validation errors).
- tests/hermes_cli/test_kanban_decompose.py — 6 tests for the
decomposer module (fanout, no-fanout fallback, unknown-assignee
rewrite, malformed-JSON resilience, no-aux-client path).
- tests/hermes_cli/test_profile_describer.py — 10 tests for
profile.yaml r/w + the LLM auto-describer (yaml corrupt tolerance,
user-vs-auto description protection, --overwrite, fallback parsing).
E2E
---
- CLI end-to-end: created profiles with descriptions, dropped a triage
task, mocked the aux LLM with a 3-task graph -> verified all three
children were created with the right assignees, the dependency
edges matched the LLM's graph, root flipped to todo gated by every
child, audit comment + `decomposed` event recorded.
- Dashboard end-to-end: started the dashboard against an isolated
HERMES_HOME, verified all four new endpoints via curl (profile
listing, PATCH for description, PUT for orchestration settings,
POST for decompose). Opened the UI in the browser, confirmed the
OrchestrationPanel renders with all three pickers + the per-profile
description editor, typed a description, clicked Save, verified
~/.hermes/profile.yaml was written. Clicked Decompose on the triage
card and confirmed the inline error message surfaced as designed
("no auxiliary client configured").
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-attribute |
5 |
unresolved-import |
3 |
unused-type-ignore-comment |
3 |
invalid-argument-type |
3 |
First entries
tests/hermes_cli/test_kanban_decompose.py:15: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/hermes_cli/test_kanban_decompose_db.py:67: [unresolved-attribute] unresolved-attribute: Attribute `status` is not defined on `None` in union `Task | None`
tests/hermes_cli/test_kanban_decompose.py:187: [unresolved-attribute] unresolved-attribute: Attribute `assignee` is not defined on `None` in union `Task | None`
tests/hermes_cli/test_kanban_decompose_db.py:68: [unresolved-attribute] unresolved-attribute: Attribute `assignee` is not defined on `None` in union `Task | None`
tests/hermes_cli/test_kanban_decompose.py:144: [unresolved-attribute] unresolved-attribute: Attribute `status` is not defined on `None` in union `Task | None`
hermes_cli/profile_describer.py:214: [unused-type-ignore-comment] unused-type-ignore-comment: Unused blanket `type: ignore` directive
tests/hermes_cli/test_kanban_decompose_db.py:9: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
hermes_cli/main.py:9203: [invalid-argument-type] invalid-argument-type: Argument to function `normalize_profile_name` is incorrect: Expected `str`, found `Any | None`
plugins/kanban/dashboard/plugin_api.py:1593: [unused-type-ignore-comment] unused-type-ignore-comment: Unused blanket `type: ignore` directive
hermes_cli/main.py:9233: [invalid-argument-type] invalid-argument-type: Argument to function `describe_profile` is incorrect: Expected `str`, found `str | Any | None`
hermes_cli/kanban_decompose.py:277: [unused-type-ignore-comment] unused-type-ignore-comment: Unused blanket `type: ignore` directive
tests/hermes_cli/test_kanban_decompose.py:145: [unresolved-attribute] unresolved-attribute: Attribute `title` is not defined on `None` in union `Task | None`
hermes_cli/main.py:9207: [invalid-argument-type] invalid-argument-type: Argument to function `get_profile_dir` is incorrect: Expected `str`, found `Any | None`
tests/hermes_cli/test_profile_describer.py:11: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
✅ Fixed issues: none
Unchanged: 4589 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
| that live directly under ``skills/`` show as bare ``skill_name``. | ||
| """ | ||
| skills_dir = profile_dir / "skills" | ||
| if not skills_dir.is_dir(): |
| if not skills_dir.is_dir(): | ||
| return [] | ||
| names: list[str] = [] | ||
| for md in skills_dir.rglob("SKILL.md"): |
| skill_names = _collect_skills(profile_dir) | ||
| skill_list = "\n".join(f" - {n}" for n in skill_names) or " (no skills installed)" | ||
| skill_count = sum( | ||
| 1 for _ in (profile_dir / "skills").rglob("SKILL.md") |
The auto/manual toggle already existed as kanban.auto_decompose (default true), but it was buried inside the collapsed Orchestration settings panel — users couldn't tell at a glance which mode they were in. This hoists it to a pill at the top of the kanban page so the state is always visible and one click flips it. UX - New "⚗ Decompose: AUTO|MANUAL" pill in the kanban header. Emerald styling when Auto is on (the default), muted/gray when Manual. - Pill is visible both in the collapsed AND expanded Orchestration settings views so context is preserved when the user opens the panel. - Tooltip explains both states + what clicking does. - Renamed the in-panel "Auto-decompose on triage / Enabled" checkbox to "Decompose mode / Auto (default) | Manual" for language parity with the pill. Behavior preserved - Default remains Auto (kanban.auto_decompose=true). - Manual mode restores pre-PR behavior: triage tasks stay in triage until the user clicks ⚗ Decompose on each card (or runs `hermes kanban decompose <id>`). Implementation - plugins/kanban/dashboard/dist/index.js: load /orchestration on mount (not just on expand) so the collapsed pill reflects real state. Render mode pill in both collapsed and expanded headers. Reuses the existing PUT /api/plugins/kanban/orchestration endpoint — no new backend, no new tests required. E2E verified - Pill renders as "⚗ Decompose: AUTO" on page load (default). - One click flips to "⚗ Decompose: MANUAL" with muted styling. - config.yaml on disk shows auto_decompose: false after the flip. - Second click round-trips back to Auto; config.yaml flips to true.
Per Teknium feedback — "Decompose" was too implementation-specific. "Orchestration" is the user-facing concept (the whole pitch is the orchestrator profile routing work), and the pill is the front door to it. - Pill text: "Orchestration: Auto" / "Orchestration: Manual" (title case, no ⚗ prefix, no SHOUTY-CAPS for the mode value) - In-panel checkbox label: "Orchestration mode" (was "Decompose mode") - Tooltips updated to match - No behavior change
… mode
Brings the docs site up to parity with the PR. English build verified
locally (npx docusaurus build --locale en) — clean, no new broken links
or anchors. Pre-existing broken-link warnings (rl-training, llms.txt,
step-by-step-checklist, fallback-model) untouched.
- website/docs/reference/cli-commands.md
+ `hermes kanban decompose` action row in the action table, with
pointer to the Auto vs Manual orchestration section.
- website/docs/reference/profile-commands.md
+ `--description "<text>"` flag on `hermes profile create`.
+ Full `hermes profile describe` section: read, --text, --auto,
--overwrite, --all flags with examples.
- website/docs/user-guide/features/kanban.md (the big one)
+ Triage column intro rewritten around the Auto-decompose default
behavior, with pointer to the new Auto vs Manual section.
+ Status action row updated to mention both ⚗ Decompose and
✨ Specify on triage cards.
+ New "Auto vs Manual orchestration" section explaining the two
modes, how to flip them (pill, config), how routing-by-description
works, the no-None-assignee guarantee, plus a config knob table
(auto_decompose, auto_decompose_per_tick, orchestrator_profile,
default_assignee) and the two new auxiliary slots
(kanban_decomposer, profile_describer).
+ REST surface table gains 6 new endpoint rows: /tasks/:id/decompose,
/profiles (GET), /profiles/:name (PATCH), /profiles/:name/describe-auto,
/orchestration (GET + PUT).
- website/docs/user-guide/features/kanban-tutorial.md
+ Triage column blurb updated for Auto by default + Manual via the
pill, with cross-link to the Auto vs Manual orchestration section.
- website/docs/user-guide/profiles.md
+ Blank-profile flow now mentions --description and points to the
kanban routing model for context.
- website/docs/user-guide/configuration.md
+ `kanban_decomposer` and `profile_describer` added to the
`hermes model -> Configure auxiliary models` menu listing.
qWaitCrypto
added a commit
to qWaitCrypto/hermes-agent
that referenced
this pull request
May 18, 2026
After NousResearch#27572, triage automation defaults to the kanban decomposer path instead of only the specify path. Update the diagnostic to check the active triage automation backend: kanban_decomposer when auto-decompose is enabled, triage_specifier in manual mode.
19 tasks
This was referenced May 18, 2026
teknium1
added a commit
that referenced
this pull request
May 18, 2026
…aware) (#27871) Adds a 'triage_aux_unavailable' diagnostic for tasks stuck in triage when neither the active aux helper slot nor the main-model auto fallback is usable. Auto-decompose aware: - kanban.auto_decompose=True (default): primary is auxiliary.kanban_decomposer, triage_specifier is the fanout=false fallback. - kanban.auto_decompose=False: primary is auxiliary.triage_specifier (manual 'hermes kanban specify' path). Default aux slots use 'provider: auto' which falls back to the main model, so this rule only fires when both the explicit slot config AND the main-model auto fallback are absent. Quiet by default; informative when there is a real config gap. Also adds kd.config_from_runtime_config() that carries kanban + auxiliary + model keys through to diagnostics, and updates CLI/dashboard call sites to use it. config_from_kanban_config() is preserved for back-compat. Reworks the original PR #25640 idea (@qWaitCrypto) to align with the new auto-decompose dispatcher path landed in #27572. The original PR pointed only at auxiliary.triage_specifier, which is now the fallback rather than the primary helper. Co-authored-by: qWaitCrypto <axmaiqiu@gmail.com>
teknium1
added a commit
that referenced
this pull request
May 18, 2026
The dashboard SDK's <Select> is a shadcn-style popup that fires
onValueChange(value), not native onChange({target:{value}}). The file
even has a selectChangeHandler() helper at L213 documenting this:
"Older plugin code calls onChange({target:{value}}) which silently
never fires."
#24547 already fixed the bulk-reassign, workspace-kind, and new-task
parent selects. This patch covers the two OrchestrationPanel selects
introduced later in #27572 that regressed onto the same broken pattern:
- OrchestrationPanel orchestrator_profile picker
- OrchestrationPanel default_assignee picker
Users opened the popup, picked an option, and the popup closed without
firing a PUT to /orchestration — so the orchestrator profile and
default assignee dropdowns appeared totally inert.
Uses the same selectChangeHandler helper as the other working Selects
in the file for consistency.
Reported by Exaario.
teknium1
added a commit
that referenced
this pull request
May 18, 2026
…ts (#27893) The dashboard SDK's <Select> is a shadcn-style popup that fires onValueChange(value), not native onChange({target:{value}}). The file even has a selectChangeHandler() helper at L213 documenting this: "Older plugin code calls onChange({target:{value}}) which silently never fires." #24547 already fixed the bulk-reassign, workspace-kind, and new-task parent selects. This patch covers the two OrchestrationPanel selects introduced later in #27572 that regressed onto the same broken pattern: - OrchestrationPanel orchestrator_profile picker - OrchestrationPanel default_assignee picker Users opened the popup, picked an option, and the popup closed without firing a PUT to /orchestration — so the orchestrator profile and default assignee dropdowns appeared totally inert. Uses the same selectChangeHandler helper as the other working Selects in the file for consistency. Reported by Exaario.
Closed
2 tasks
Lillard01
pushed a commit
to Lillard01/hermes-agent
that referenced
this pull request
May 21, 2026
…aware) (NousResearch#27871) Adds a 'triage_aux_unavailable' diagnostic for tasks stuck in triage when neither the active aux helper slot nor the main-model auto fallback is usable. Auto-decompose aware: - kanban.auto_decompose=True (default): primary is auxiliary.kanban_decomposer, triage_specifier is the fanout=false fallback. - kanban.auto_decompose=False: primary is auxiliary.triage_specifier (manual 'hermes kanban specify' path). Default aux slots use 'provider: auto' which falls back to the main model, so this rule only fires when both the explicit slot config AND the main-model auto fallback are absent. Quiet by default; informative when there is a real config gap. Also adds kd.config_from_runtime_config() that carries kanban + auxiliary + model keys through to diagnostics, and updates CLI/dashboard call sites to use it. config_from_kanban_config() is preserved for back-compat. Reworks the original PR NousResearch#25640 idea (@qWaitCrypto) to align with the new auto-decompose dispatcher path landed in NousResearch#27572. The original PR pointed only at auxiliary.triage_specifier, which is now the fallback rather than the primary helper. Co-authored-by: qWaitCrypto <axmaiqiu@gmail.com>
Lillard01
pushed a commit
to Lillard01/hermes-agent
that referenced
this pull request
May 21, 2026
…ts (NousResearch#27893) The dashboard SDK's <Select> is a shadcn-style popup that fires onValueChange(value), not native onChange({target:{value}}). The file even has a selectChangeHandler() helper at L213 documenting this: "Older plugin code calls onChange({target:{value}}) which silently never fires." NousResearch#24547 already fixed the bulk-reassign, workspace-kind, and new-task parent selects. This patch covers the two OrchestrationPanel selects introduced later in NousResearch#27572 that regressed onto the same broken pattern: - OrchestrationPanel orchestrator_profile picker - OrchestrationPanel default_assignee picker Users opened the popup, picked an option, and the popup closed without firing a PUT to /orchestration — so the orchestrator profile and default assignee dropdowns appeared totally inert. Uses the same selectChangeHandler helper as the other working Selects in the file for consistency. Reported by Exaario.
Mucky010
pushed a commit
to Mucky010/hermes-agent
that referenced
this pull request
May 24, 2026
…ts (NousResearch#27893) The dashboard SDK's <Select> is a shadcn-style popup that fires onValueChange(value), not native onChange({target:{value}}). The file even has a selectChangeHandler() helper at L213 documenting this: "Older plugin code calls onChange({target:{value}}) which silently never fires." NousResearch#24547 already fixed the bulk-reassign, workspace-kind, and new-task parent selects. This patch covers the two OrchestrationPanel selects introduced later in NousResearch#27572 that regressed onto the same broken pattern: - OrchestrationPanel orchestrator_profile picker - OrchestrationPanel default_assignee picker Users opened the popup, picked an option, and the popup closed without firing a PUT to /orchestration — so the orchestrator profile and default assignee dropdowns appeared totally inert. Uses the same selectChangeHandler helper as the other working Selects in the file for consistency. Reported by Exaario.
1 task
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
…esearch#27572) * feat(kanban): orchestrator-driven auto-decomposition on triage Closes the core gap in the kanban system: dropping a one-liner into Triage now decomposes it into a graph of child tasks routed to specialist profiles by description, matching teknium's original vision ("main orchestrator splits/creates actual tasks, doles them out to each agent"). The build --------- - hermes_cli/profiles.py: new `description` + `description_auto` fields on ProfileInfo, persisted in <profile_dir>/profile.yaml. Helpers read_profile_meta / write_profile_meta. `create_profile` accepts optional description. - hermes_cli/profile_describer.py: new module — auto-generate a 1-2 sentence description from a profile's skills + model + name via the auxiliary LLM (`auxiliary.profile_describer`). - hermes_cli/main.py: new `hermes profile create --description ...` flag; new `hermes profile describe [name] [--text ... | --auto | --all --auto]` subcommand. - hermes_cli/kanban_db.py: new `decompose_triage_task` atomic helper — creates N child tasks, links the root as a child of every leaf (root waits for the whole graph), flips root `triage -> todo` with orchestrator assignee, records an audit comment + `decomposed` event in a single write_txn. - hermes_cli/kanban_decompose.py: new module — calls the auxiliary LLM (`auxiliary.kanban_decomposer`) with the profile roster + descriptions to produce a JSON task graph, then invokes the DB helper. Rewrites unknown assignees to the configured `kanban.default_assignee` (or the active default profile) so a task NEVER lands with assignee=None. Falls back to specify-style single-task promotion when the LLM returns `fanout: false`. - hermes_cli/kanban.py: new `hermes kanban decompose [task_id | --all]` CLI verb. - hermes_cli/config.py: new DEFAULT_CONFIG keys — kanban.orchestrator_profile, kanban.default_assignee, kanban.auto_decompose (default True), kanban.auto_decompose_per_tick (default 3), auxiliary.kanban_decomposer, auxiliary.profile_describer. - gateway/run.py: kanban dispatcher watcher now runs auto-decompose before each `_tick_once`, capped by `auto_decompose_per_tick` so a bulk-load of triage tasks doesn't burst-spend the aux LLM. - plugins/kanban/dashboard/plugin_api.py: new endpoints — GET /profiles (list roster + descriptions), PATCH /profiles/<name> (set description, user-authored), POST /profiles/<name>/describe-auto (LLM-generate), POST /tasks/<id>/decompose (run decomposer), GET/PUT /orchestration (orchestrator/default-assignee/auto-decompose pickers, with resolved fallbacks echoed back). - plugins/kanban/dashboard/dist/index.js: new OrchestrationPanel collapsible — dropdowns for orchestrator profile and default assignee, auto-decompose toggle, per-profile description editor with Save and Auto-generate buttons. New ⚗ Decompose button next to ✨ Specify on triage-column task drawers. Behavior -------- - A task in Triage gets fanned out into a small DAG of child tasks. Children with no internal parents flip to `ready` immediately (parallel dispatch). Children with sibling parents wait. The root stays alive as a parent of every child — when the whole graph finishes, it promotes to `ready` and the orchestrator profile wakes back up to judge completion (the "adds more tasks until done" part of the original vision). - `kanban.orchestrator_profile` unset -> falls back to the default profile (whichever `hermes` launches with no -p flag). - `kanban.default_assignee` unset -> same fallback. Tasks NEVER end up unassigned. - `kanban.auto_decompose=true` (default) runs the decomposer automatically on dispatcher ticks; manual `hermes kanban decompose` is always available. Tests ----- - tests/hermes_cli/test_kanban_decompose_db.py — 7 tests for the atomic DB helper (status transitions, dep graph, audit trail, validation errors). - tests/hermes_cli/test_kanban_decompose.py — 6 tests for the decomposer module (fanout, no-fanout fallback, unknown-assignee rewrite, malformed-JSON resilience, no-aux-client path). - tests/hermes_cli/test_profile_describer.py — 10 tests for profile.yaml r/w + the LLM auto-describer (yaml corrupt tolerance, user-vs-auto description protection, --overwrite, fallback parsing). E2E --- - CLI end-to-end: created profiles with descriptions, dropped a triage task, mocked the aux LLM with a 3-task graph -> verified all three children were created with the right assignees, the dependency edges matched the LLM's graph, root flipped to todo gated by every child, audit comment + `decomposed` event recorded. - Dashboard end-to-end: started the dashboard against an isolated HERMES_HOME, verified all four new endpoints via curl (profile listing, PATCH for description, PUT for orchestration settings, POST for decompose). Opened the UI in the browser, confirmed the OrchestrationPanel renders with all three pickers + the per-profile description editor, typed a description, clicked Save, verified ~/.hermes/profile.yaml was written. Clicked Decompose on the triage card and confirmed the inline error message surfaced as designed ("no auxiliary client configured"). * feat(kanban): surface decompose mode (Auto/Manual) as a one-click pill The auto/manual toggle already existed as kanban.auto_decompose (default true), but it was buried inside the collapsed Orchestration settings panel — users couldn't tell at a glance which mode they were in. This hoists it to a pill at the top of the kanban page so the state is always visible and one click flips it. UX - New "⚗ Decompose: AUTO|MANUAL" pill in the kanban header. Emerald styling when Auto is on (the default), muted/gray when Manual. - Pill is visible both in the collapsed AND expanded Orchestration settings views so context is preserved when the user opens the panel. - Tooltip explains both states + what clicking does. - Renamed the in-panel "Auto-decompose on triage / Enabled" checkbox to "Decompose mode / Auto (default) | Manual" for language parity with the pill. Behavior preserved - Default remains Auto (kanban.auto_decompose=true). - Manual mode restores pre-PR behavior: triage tasks stay in triage until the user clicks ⚗ Decompose on each card (or runs `hermes kanban decompose <id>`). Implementation - plugins/kanban/dashboard/dist/index.js: load /orchestration on mount (not just on expand) so the collapsed pill reflects real state. Render mode pill in both collapsed and expanded headers. Reuses the existing PUT /api/plugins/kanban/orchestration endpoint — no new backend, no new tests required. E2E verified - Pill renders as "⚗ Decompose: AUTO" on page load (default). - One click flips to "⚗ Decompose: MANUAL" with muted styling. - config.yaml on disk shows auto_decompose: false after the flip. - Second click round-trips back to Auto; config.yaml flips to true. * feat(kanban): rename mode pill to "Orchestration: Auto/Manual" Per Teknium feedback — "Decompose" was too implementation-specific. "Orchestration" is the user-facing concept (the whole pitch is the orchestrator profile routing work), and the pill is the front door to it. - Pill text: "Orchestration: Auto" / "Orchestration: Manual" (title case, no ⚗ prefix, no SHOUTY-CAPS for the mode value) - In-panel checkbox label: "Orchestration mode" (was "Decompose mode") - Tooltips updated to match - No behavior change * docs(kanban): document decompose, profile descriptions, orchestration mode Brings the docs site up to parity with the PR. English build verified locally (npx docusaurus build --locale en) — clean, no new broken links or anchors. Pre-existing broken-link warnings (rl-training, llms.txt, step-by-step-checklist, fallback-model) untouched. - website/docs/reference/cli-commands.md + `hermes kanban decompose` action row in the action table, with pointer to the Auto vs Manual orchestration section. - website/docs/reference/profile-commands.md + `--description "<text>"` flag on `hermes profile create`. + Full `hermes profile describe` section: read, --text, --auto, --overwrite, --all flags with examples. - website/docs/user-guide/features/kanban.md (the big one) + Triage column intro rewritten around the Auto-decompose default behavior, with pointer to the new Auto vs Manual section. + Status action row updated to mention both ⚗ Decompose and ✨ Specify on triage cards. + New "Auto vs Manual orchestration" section explaining the two modes, how to flip them (pill, config), how routing-by-description works, the no-None-assignee guarantee, plus a config knob table (auto_decompose, auto_decompose_per_tick, orchestrator_profile, default_assignee) and the two new auxiliary slots (kanban_decomposer, profile_describer). + REST surface table gains 6 new endpoint rows: /tasks/:id/decompose, /profiles (GET), /profiles/:name (PATCH), /profiles/:name/describe-auto, /orchestration (GET + PUT). - website/docs/user-guide/features/kanban-tutorial.md + Triage column blurb updated for Auto by default + Manual via the pill, with cross-link to the Auto vs Manual orchestration section. - website/docs/user-guide/profiles.md + Blank-profile flow now mentions --description and points to the kanban routing model for context. - website/docs/user-guide/configuration.md + `kanban_decomposer` and `profile_describer` added to the `hermes model -> Configure auxiliary models` menu listing.
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
…aware) (NousResearch#27871) Adds a 'triage_aux_unavailable' diagnostic for tasks stuck in triage when neither the active aux helper slot nor the main-model auto fallback is usable. Auto-decompose aware: - kanban.auto_decompose=True (default): primary is auxiliary.kanban_decomposer, triage_specifier is the fanout=false fallback. - kanban.auto_decompose=False: primary is auxiliary.triage_specifier (manual 'hermes kanban specify' path). Default aux slots use 'provider: auto' which falls back to the main model, so this rule only fires when both the explicit slot config AND the main-model auto fallback are absent. Quiet by default; informative when there is a real config gap. Also adds kd.config_from_runtime_config() that carries kanban + auxiliary + model keys through to diagnostics, and updates CLI/dashboard call sites to use it. config_from_kanban_config() is preserved for back-compat. Reworks the original PR NousResearch#25640 idea (@qWaitCrypto) to align with the new auto-decompose dispatcher path landed in NousResearch#27572. The original PR pointed only at auxiliary.triage_specifier, which is now the fallback rather than the primary helper. Co-authored-by: qWaitCrypto <axmaiqiu@gmail.com>
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
…ts (NousResearch#27893) The dashboard SDK's <Select> is a shadcn-style popup that fires onValueChange(value), not native onChange({target:{value}}). The file even has a selectChangeHandler() helper at L213 documenting this: "Older plugin code calls onChange({target:{value}}) which silently never fires." NousResearch#24547 already fixed the bulk-reassign, workspace-kind, and new-task parent selects. This patch covers the two OrchestrationPanel selects introduced later in NousResearch#27572 that regressed onto the same broken pattern: - OrchestrationPanel orchestrator_profile picker - OrchestrationPanel default_assignee picker Users opened the popup, picked an option, and the popup closed without firing a PUT to /orchestration — so the orchestrator profile and default assignee dropdowns appeared totally inert. Uses the same selectChangeHandler helper as the other working Selects in the file for consistency. Reported by Exaario.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Drop a one-liner into the Kanban Triage column and an orchestrator profile decomposes it into a graph of child tasks routed to specialist profiles by description — matching the original vision the kanban system was pitched on but never quite delivered on.
This closes priority #1 of the kanban feedback Teknium gathered on 5/11 ("the way I initially envisioned the kanban was this: User puts an issue on triage block, main orchestrator agent then splits/creates actual tasks from it and doles them out to each agent…").
Changes
Profile descriptions (new labeling primitive)
hermes_cli/profiles.py: newdescription+description_autofields onProfileInfo, persisted in<profile_dir>/profile.yaml. Helpersread_profile_meta/write_profile_meta.hermes_cli/profile_describer.py: new module — auto-generate a 1-2 sentence description from skills + model + name viaauxiliary.profile_describer.hermes profile create --description "..."flag.hermes profile describe [name] [--text "..." | --auto | --all --auto]subcommand.Decomposer
hermes_cli/kanban_db.py: newdecompose_triage_taskatomic helper. Creates N child tasks, links the root as a child of every leaf (root waits for the whole graph), flips roottriage → todo, records audit comment +decomposedevent — all in a singlewrite_txn.hermes_cli/kanban_decompose.py: new module — calls the auxiliary LLM with the profile roster + descriptions, parses the JSON task graph, rewrites unknown assignees to the configuredkanban.default_assigneeso a task never lands withassignee=None. Falls back to specify-style single-task promotion when the LLM returnsfanout: false.hermes kanban decompose [task_id | --all]CLI verb.Auto-trigger
gateway/run.py: kanban dispatcher watcher now runs auto-decompose before each_tick_once, capped bykanban.auto_decompose_per_tick(default 3) so a bulk-load of triage tasks doesn't burst-spend the aux LLM.Config
DEFAULT_CONFIGkeys:kanban.orchestrator_profile(default""→ falls back to active default profile)kanban.default_assignee(same fallback)kanban.auto_decompose(defaultTrue)kanban.auto_decompose_per_tick(default3)auxiliary.kanban_decomposerauxiliary.profile_describer_config_versionbump — deep-merge handles new nested keys.Dashboard backend (
plugins/kanban/dashboard/plugin_api.py)GET /profiles— roster with descriptionsPATCH /profiles/<name>— set description (user-authored)POST /profiles/<name>/describe-auto— LLM-generatePOST /tasks/<id>/decompose— run decomposerGET/PUT /orchestration— orchestrator/default-assignee/auto-decompose pickers, with resolved fallbacks echoed backDashboard UI (
plugins/kanban/dashboard/dist/index.js)Behavior
kanban.orchestrator_profile""(active default)kanban.default_assignee""(active default)kanban.auto_decomposeTruekanban.auto_decompose_per_tick3readyand the orchestrator wakes back up to judge completion or add more tasks — the "judges if finished, adds more tasks until done" part of the original vision.assignee=None. Unknown assignees rewrite to the default fallback at decompose time.Tests
Targeted: 23 new tests, all passing.
tests/hermes_cli/test_kanban_decompose_db.py— 7 tests for the atomic DB helper.tests/hermes_cli/test_kanban_decompose.py— 6 tests for the decomposer module (LLM mocked).tests/hermes_cli/test_profile_describer.py— 10 tests for profile.yaml r/w + the LLM auto-describer.Pre-existing test suite (
tests/hermes_cli/): 4560/4569 passing, 9 unrelated failures (test_api_key_providers, test_gateway_service systemd, test_setup_openclaw_migration, test_web_server PTY, test_startup_plugin_gating'ssendsubcommand). None touch kanban/profiles.E2E validation
CLI end-to-end (isolated HERMES_HOME, mocked aux LLM, real DB):
todogated by every child, audit comment +decomposedevent recorded, first child auto-promoted toreadyCLI subprocess (
hermes profile describe):describe <name>(empty) → shows "(no description set)"describe <name> --text "..."→ persists to profile.yamldescribe <name>(read back) → shows the textdescribe ghost→ exits 1 with clear errorkanban decompose <id>(no aux configured) → reports inline failure cleanlyDashboard end-to-end (browser tool):
Files
17 changed (3 new modules + 3 new test files + 8 modified + 1 dashboard JS + 1 dashboard API + 1 dispatcher):